Migrate to access-widener library (#294)

dev/0.11
modmuss50 2020-11-15 16:15:02 +00:00 committed by GitHub
parent 62e89395f9
commit d1281be741
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 27 additions and 648 deletions

View File

@ -50,6 +50,8 @@ dependencies {
implementation ('net.fabricmc:tiny-remapper:0.3.0.70') implementation ('net.fabricmc:tiny-remapper:0.3.0.70')
implementation ('net.fabricmc:tiny-mappings-parser:0.2.2.14') implementation ('net.fabricmc:tiny-mappings-parser:0.2.2.14')
implementation 'net.fabricmc:access-widener:1.0.0'
implementation ('net.fabricmc:lorenz-tiny:2.0.0+build.2') { implementation ('net.fabricmc:lorenz-tiny:2.0.0+build.2') {
transitive = false transitive = false
} }

View File

@ -27,6 +27,7 @@ package net.fabricmc.loom.util;
import java.util.List; import java.util.List;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.objectweb.asm.Opcodes;
public class Constants { public class Constants {
public static final String LIBRARIES_BASE = "https://libraries.minecraft.net/"; public static final String LIBRARIES_BASE = "https://libraries.minecraft.net/";
@ -35,6 +36,8 @@ public class Constants {
public static final String SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32"; public static final String SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32";
public static final int ASM_VERSION = Opcodes.ASM9;
public static final List<RemappedConfigurationEntry> MOD_COMPILE_ENTRIES = ImmutableList.of( public static final List<RemappedConfigurationEntry> MOD_COMPILE_ENTRIES = ImmutableList.of(
new RemappedConfigurationEntry("modCompile", "compile", true, "compile"), new RemappedConfigurationEntry("modCompile", "compile", true, "compile"),
new RemappedConfigurationEntry("modApi", "api", true, "compile"), new RemappedConfigurationEntry("modApi", "api", true, "compile"),

View File

@ -45,7 +45,6 @@ import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import net.fabricmc.loom.util.progress.ProgressLogger; import net.fabricmc.loom.util.progress.ProgressLogger;
@ -124,7 +123,7 @@ public class LineNumberRemapper {
ClassReader reader = new ClassReader(is); ClassReader reader = new ClassReader(is);
ClassWriter writer = new ClassWriter(0); ClassWriter writer = new ClassWriter(0);
reader.accept(new LineNumberVisitor(Opcodes.ASM7, writer, lineMap.get(idx)), 0); reader.accept(new LineNumberVisitor(Constants.ASM_VERSION, writer, lineMap.get(idx)), 0);
Files.write(dst, writer.toByteArray()); Files.write(dst, writer.toByteArray());
} }
} }

View File

@ -51,11 +51,13 @@ import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.transform.StringZipEntryTransformer; import org.zeroturnaround.zip.transform.StringZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
import net.fabricmc.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerWriter;
import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.providers.MappingsProvider; import net.fabricmc.loom.providers.MappingsProvider;
import net.fabricmc.loom.providers.MinecraftMappedProvider; import net.fabricmc.loom.providers.MinecraftMappedProvider;
import net.fabricmc.loom.util.accesswidener.AccessWidener;
import net.fabricmc.loom.util.accesswidener.AccessWidenerRemapper;
import net.fabricmc.loom.processors.dependency.ModDependencyInfo; import net.fabricmc.loom.processors.dependency.ModDependencyInfo;
import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.InputTag; import net.fabricmc.tinyremapper.InputTag;
@ -109,13 +111,15 @@ public class ModProcessor {
private static byte[] remapAccessWidener(byte[] input, Remapper remapper) { private static byte[] remapAccessWidener(byte[] input, Remapper remapper) {
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) { try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) {
AccessWidener accessWidener = new AccessWidener(); AccessWidener accessWidener = new AccessWidener();
accessWidener.read(bufferedReader); AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener);
accessWidenerReader.read(bufferedReader);
AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, "named"); AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, "named");
AccessWidener remapped = accessWidenerRemapper.remap(); AccessWidener remapped = accessWidenerRemapper.remap();
AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped);
try (StringWriter writer = new StringWriter()) { try (StringWriter writer = new StringWriter()) {
remapped.write(writer); accessWidenerWriter.write(writer);
return writer.toString().getBytes(StandardCharsets.UTF_8); return writer.toString().getBytes(StandardCharsets.UTF_8);
} }
} catch (IOException e) { } catch (IOException e) {

View File

@ -1,477 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.util.accesswidener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import net.fabricmc.mappings.EntryTriple;
public class AccessWidener {
public String namespace;
public Map<String, Access> classAccess = new HashMap<>();
public Map<EntryTriple, Access> methodAccess = new HashMap<>();
public Map<EntryTriple, Access> fieldAccess = new HashMap<>();
private final Set<String> classes = new LinkedHashSet<>();
public void read(BufferedReader reader) throws IOException {
String headerStr = reader.readLine();
if (headerStr == null) {
throw new RuntimeException("Cannot read empty or invalid access widener");
}
String[] header = headerStr.split("\\s+");
if (header.length != 3 || !header[0].equals("accessWidener")) {
throw new UnsupportedOperationException("Invalid access access widener header");
}
if (!header[1].equals("v1")) {
throw new RuntimeException(String.format("Unsupported access widener format (%s)", header[1]));
}
if (namespace != null) {
if (!namespace.equals(header[2])) {
throw new RuntimeException(String.format("Namespace mismatch, expected %s got %s", namespace, header[2]));
}
}
namespace = header[2];
String line;
Set<String> targets = new LinkedHashSet<>();
while ((line = reader.readLine()) != null) {
// Comment handling
int commentPos = line.indexOf('#');
if (commentPos >= 0) {
line = line.substring(0, commentPos).trim();
}
if (line.isEmpty()) continue;
String[] split = line.split("\\s+");
if (split.length != 3 && split.length != 5) {
throw new RuntimeException(String.format("Invalid line (%s)", line));
}
String access = split[0];
targets.add(split[2].replaceAll("/", "."));
switch (split[1]) {
case "class":
if (split.length != 3) {
throw new RuntimeException(String.format("Expected (<access>\tclass\t<className>) got (%s)", line));
}
classAccess.put(split[2], applyAccess(access, classAccess.getOrDefault(split[2], ClassAccess.DEFAULT), null));
break;
case "field":
if (split.length != 5) {
throw new RuntimeException(String.format("Expected (<access>\tfield\t<className>\t<fieldName>\t<fieldDesc>) got (%s)", line));
}
addOrMerge(fieldAccess, new EntryTriple(split[2], split[3], split[4]), access, FieldAccess.DEFAULT);
break;
case "method":
if (split.length != 5) {
throw new RuntimeException(String.format("Expected (<access>\tmethod\t<className>\t<methodName>\t<methodDesc>) got (%s)", line));
}
addOrMerge(methodAccess, new EntryTriple(split[2], split[3], split[4]), access, MethodAccess.DEFAULT);
break;
default:
throw new UnsupportedOperationException("Unsupported type " + split[1]);
}
}
Set<String> parentClasses = new LinkedHashSet<>();
//Also transform all parent classes
for (String clazz : targets) {
while (clazz.contains("$")) {
clazz = clazz.substring(0, clazz.lastIndexOf("$"));
parentClasses.add(clazz);
}
}
classes.addAll(targets);
classes.addAll(parentClasses);
}
// Could possibly be cleaner but should do its job for now
public void write(StringWriter writer) {
writer.write("accessWidener\tv1\t");
writer.write(namespace);
writer.write("\n");
for (Map.Entry<String, Access> entry : classAccess.entrySet()) {
for (String s : getAccesses(entry.getValue())) {
writer.write(s);
writer.write("\tclass\t");
writer.write(entry.getKey());
writer.write("\n");
}
}
for (Map.Entry<EntryTriple, Access> entry : methodAccess.entrySet()) {
writeEntry(writer, "method", entry.getKey(), entry.getValue());
}
for (Map.Entry<EntryTriple, Access> entry : fieldAccess.entrySet()) {
writeEntry(writer, "field", entry.getKey(), entry.getValue());
}
}
private void writeEntry(StringWriter writer, String type, EntryTriple entryTriple, Access access) {
for (String s : getAccesses(access)) {
writer.write(s);
writer.write("\t");
writer.write(type);
writer.write("\t");
writer.write(entryTriple.getOwner());
writer.write("\t");
writer.write(entryTriple.getName());
writer.write("\t");
writer.write(entryTriple.getDesc());
writer.write("\n");
}
}
private List<String> getAccesses(Access access) {
List<String> accesses = new ArrayList<>();
if (access == ClassAccess.ACCESSIBLE || access == MethodAccess.ACCESSIBLE || access == FieldAccess.ACCESSIBLE || access == MethodAccess.ACCESSIBLE_EXTENDABLE || access == ClassAccess.ACCESSIBLE_EXTENDABLE || access == FieldAccess.ACCESSIBLE_MUTABLE) {
accesses.add("accessible");
}
if (access == ClassAccess.EXTENDABLE || access == MethodAccess.EXTENDABLE || access == MethodAccess.ACCESSIBLE_EXTENDABLE || access == ClassAccess.ACCESSIBLE_EXTENDABLE) {
accesses.add("extendable");
}
if (access == FieldAccess.MUTABLE || access == FieldAccess.ACCESSIBLE_MUTABLE) {
accesses.add("mutable");
}
return accesses;
}
void addOrMerge(Map<EntryTriple, Access> map, EntryTriple entry, Access access) {
if (entry == null || access == null) {
throw new RuntimeException("Input entry or access is null");
}
Access merged = null;
if (access instanceof ClassAccess) {
merged = ClassAccess.DEFAULT;
} else if (access instanceof MethodAccess) {
merged = MethodAccess.DEFAULT;
} else if (access instanceof FieldAccess) {
merged = FieldAccess.DEFAULT;
}
merged = mergeAccess(merged, access);
map.put(entry, merged);
}
void addOrMerge(Map<EntryTriple, Access> map, EntryTriple entry, String access, Access defaultAccess) {
if (entry == null || access == null) {
throw new RuntimeException("Input entry or access is null");
}
map.put(entry, applyAccess(access, map.getOrDefault(entry, defaultAccess), entry));
}
public void merge(AccessWidener other) {
if (namespace == null) {
namespace = other.namespace;
} else if (!namespace.equals(other.namespace)) {
throw new RuntimeException("Namespace mismatch");
}
for (Map.Entry<String, Access> entry : other.classAccess.entrySet()) {
if (classAccess.containsKey(entry.getKey())) {
classAccess.replace(entry.getKey(), mergeAccess(classAccess.get(entry.getKey()), entry.getValue()));
} else {
classAccess.put(entry.getKey(), entry.getValue());
}
}
for (Map.Entry<EntryTriple, Access> entry : other.methodAccess.entrySet()) {
addOrMerge(methodAccess, entry.getKey(), entry.getValue());
}
for (Map.Entry<EntryTriple, Access> entry : other.fieldAccess.entrySet()) {
addOrMerge(fieldAccess, entry.getKey(), entry.getValue());
}
}
private Access applyAccess(String input, Access access, EntryTriple entryTriple) {
switch (input.toLowerCase(Locale.ROOT)) {
case "accessible":
makeClassAccessible(entryTriple);
return access.makeAccessible();
case "extendable":
makeClassExtendable(entryTriple);
return access.makeExtendable();
case "mutable":
return access.makeMutable();
default:
throw new UnsupportedOperationException("Unknown access type:" + input);
}
}
private void makeClassAccessible(EntryTriple entryTriple) {
if (entryTriple == null) return;
classAccess.put(entryTriple.getOwner(), applyAccess("accessible", classAccess.getOrDefault(entryTriple.getOwner(), ClassAccess.DEFAULT), null));
}
private void makeClassExtendable(EntryTriple entryTriple) {
if (entryTriple == null) return;
classAccess.put(entryTriple.getOwner(), applyAccess("extendable", classAccess.getOrDefault(entryTriple.getOwner(), ClassAccess.DEFAULT), null));
}
private static Access mergeAccess(Access a, Access b) {
Access access = a;
if (b == ClassAccess.ACCESSIBLE || b == MethodAccess.ACCESSIBLE || b == FieldAccess.ACCESSIBLE || b == MethodAccess.ACCESSIBLE_EXTENDABLE || b == ClassAccess.ACCESSIBLE_EXTENDABLE || b == FieldAccess.ACCESSIBLE_MUTABLE) {
access = access.makeAccessible();
}
if (b == ClassAccess.EXTENDABLE || b == MethodAccess.EXTENDABLE || b == MethodAccess.ACCESSIBLE_EXTENDABLE || b == ClassAccess.ACCESSIBLE_EXTENDABLE) {
access = access.makeExtendable();
}
if (b == FieldAccess.MUTABLE || b == FieldAccess.ACCESSIBLE_MUTABLE) {
access = access.makeMutable();
}
return access;
}
public Access getClassAccess(String className) {
return classAccess.getOrDefault(className, ClassAccess.DEFAULT);
}
public Access getFieldAccess(EntryTriple entryTriple) {
return fieldAccess.getOrDefault(entryTriple, FieldAccess.DEFAULT);
}
public Access getMethodAccess(EntryTriple entryTriple) {
return methodAccess.getOrDefault(entryTriple, MethodAccess.DEFAULT);
}
public Set<String> getTargets() {
return classes;
}
private static int makePublic(int i) {
return (i & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;
}
private static int makeProtected(int i) {
if ((i & Opcodes.ACC_PUBLIC) != 0) {
// Return i if public
return i;
}
return (i & ~(Opcodes.ACC_PRIVATE)) | Opcodes.ACC_PROTECTED;
}
private static int makeFinalIfPrivate(int access, String name, int ownerAccess) {
// Dont make constructors final
if (name.equals("<init>")) {
return access;
}
// Skip interface and static methods
if ((ownerAccess & Opcodes.ACC_INTERFACE) != 0 || (access & Opcodes.ACC_STATIC) != 0) {
return access;
}
if ((access & Opcodes.ACC_PRIVATE) != 0) {
return access | Opcodes.ACC_FINAL;
}
return access;
}
private static int removeFinal(int i) {
return i & ~Opcodes.ACC_FINAL;
}
public interface Access extends AccessOperator {
Access makeAccessible();
Access makeExtendable();
Access makeMutable();
}
public enum ClassAccess implements Access {
DEFAULT((access, name, ownerAccess) -> access),
ACCESSIBLE((access, name, ownerAccess) -> makePublic(access)),
EXTENDABLE((access, name, ownerAccess) -> makePublic(removeFinal(access))),
ACCESSIBLE_EXTENDABLE((access, name, ownerAccess) -> makePublic(removeFinal(access)));
private final AccessOperator operator;
ClassAccess(AccessOperator operator) {
this.operator = operator;
}
@Override
public Access makeAccessible() {
if (this == EXTENDABLE || this == ACCESSIBLE_EXTENDABLE) {
return ACCESSIBLE_EXTENDABLE;
}
return ACCESSIBLE;
}
@Override
public Access makeExtendable() {
if (this == ACCESSIBLE || this == ACCESSIBLE_EXTENDABLE) {
return ACCESSIBLE_EXTENDABLE;
}
return EXTENDABLE;
}
@Override
public Access makeMutable() {
throw new UnsupportedOperationException("Classes cannot be made mutable");
}
@Override
public int apply(int access, String targetName, int ownerAccess) {
return operator.apply(access, targetName, ownerAccess);
}
}
public enum MethodAccess implements Access {
DEFAULT((access, name, ownerAccess) -> access),
ACCESSIBLE((access, name, ownerAccess) -> makePublic(makeFinalIfPrivate(access, name, ownerAccess))),
EXTENDABLE((access, name, ownerAccess) -> makeProtected(removeFinal(access))),
ACCESSIBLE_EXTENDABLE((access, name, owner) -> makePublic(removeFinal(access)));
private final AccessOperator operator;
MethodAccess(AccessOperator operator) {
this.operator = operator;
}
@Override
public Access makeAccessible() {
if (this == EXTENDABLE || this == ACCESSIBLE_EXTENDABLE) {
return ACCESSIBLE_EXTENDABLE;
}
return ACCESSIBLE;
}
@Override
public Access makeExtendable() {
if (this == ACCESSIBLE || this == ACCESSIBLE_EXTENDABLE) {
return ACCESSIBLE_EXTENDABLE;
}
return EXTENDABLE;
}
@Override
public Access makeMutable() {
throw new UnsupportedOperationException("Methods cannot be made mutable");
}
@Override
public int apply(int access, String targetName, int ownerAccess) {
return operator.apply(access, targetName, ownerAccess);
}
}
public enum FieldAccess implements Access {
DEFAULT((access, name, ownerAccess) -> access),
ACCESSIBLE((access, name, ownerAccess) -> makePublic(access)),
MUTABLE((access, name, ownerAccess) -> removeFinal(access)),
ACCESSIBLE_MUTABLE((access, name, ownerAccess) -> makePublic(removeFinal(access)));
private final AccessOperator operator;
FieldAccess(AccessOperator operator) {
this.operator = operator;
}
@Override
public Access makeAccessible() {
if (this == MUTABLE || this == ACCESSIBLE_MUTABLE) {
return ACCESSIBLE_MUTABLE;
}
return ACCESSIBLE;
}
@Override
public Access makeExtendable() {
throw new UnsupportedOperationException("Fields cannot be made extendable");
}
@Override
public Access makeMutable() {
if (this == ACCESSIBLE || this == ACCESSIBLE_MUTABLE) {
return ACCESSIBLE_MUTABLE;
}
return MUTABLE;
}
@Override
public int apply(int access, String targetName, int ownerAccess) {
return operator.apply(access, targetName, ownerAccess);
}
}
@FunctionalInterface
public interface AccessOperator {
int apply(int access, String targetName, int ownerAccess);
}
}

View File

@ -41,23 +41,26 @@ import org.gradle.api.Project;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.Remapper;
import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer; import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformer; import org.zeroturnaround.zip.transform.ZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
import net.fabricmc.accesswidener.AccessWidener;
import net.fabricmc.accesswidener.AccessWidenerRemapper;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.accesswidener.AccessWidenerWriter;
import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.processors.JarProcessor; import net.fabricmc.loom.processors.JarProcessor;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.Checksum; import net.fabricmc.loom.util.Checksum;
import net.fabricmc.mappings.EntryTriple;
import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.TinyRemapper;
public class AccessWidenerJarProcessor implements JarProcessor { public class AccessWidenerJarProcessor implements JarProcessor {
private AccessWidener accessWidener = new AccessWidener(); private AccessWidener accessWidener = new AccessWidener();
private AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener);
private final Project project; private final Project project;
private byte[] inputHash; private byte[] inputHash;
@ -76,13 +79,13 @@ public class AccessWidenerJarProcessor implements JarProcessor {
inputHash = Checksum.sha256(loomGradleExtension.accessWidener); inputHash = Checksum.sha256(loomGradleExtension.accessWidener);
try (BufferedReader reader = new BufferedReader(new FileReader(loomGradleExtension.accessWidener))) { try (BufferedReader reader = new BufferedReader(new FileReader(loomGradleExtension.accessWidener))) {
accessWidener.read(reader); accessWidenerReader.read(reader);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to read project access widener file"); throw new RuntimeException("Failed to read project access widener file");
} }
//Remap accessWidener if its not named, allows for AE's to be written in intermediary //Remap accessWidener if its not named, allows for AE's to be written in intermediary
if (!accessWidener.namespace.equals("named")) { if (!accessWidener.getNamespace().equals("named")) {
try { try {
TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper("official", "named"); TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper("official", "named");
tinyRemapper.readClassPath(loomGradleExtension.getMinecraftMappedProvider().getRemapClasspath()); tinyRemapper.readClassPath(loomGradleExtension.getMinecraftMappedProvider().getRemapClasspath());
@ -116,10 +119,11 @@ public class AccessWidenerJarProcessor implements JarProcessor {
protected byte[] transform(ZipEntry zipEntry, byte[] input) { protected byte[] transform(ZipEntry zipEntry, byte[] input) {
ClassReader reader = new ClassReader(input); ClassReader reader = new ClassReader(input);
ClassWriter writer = new ClassWriter(0); ClassWriter writer = new ClassWriter(0);
ClassVisitor classVisitor = AccessWidenerVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener);
project.getLogger().lifecycle("Applying access widener to " + className); project.getLogger().lifecycle("Applying access widener to " + className);
reader.accept(new AccessTransformer(writer), 0); reader.accept(classVisitor, 0);
return writer.toByteArray(); return writer.toByteArray();
} }
}; };
@ -145,9 +149,10 @@ public class AccessWidenerJarProcessor implements JarProcessor {
public byte[] getRemappedAccessWidener(Remapper asmRemapper) throws IOException { public byte[] getRemappedAccessWidener(Remapper asmRemapper) throws IOException {
AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, "intermediary"); AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, "intermediary");
AccessWidener remapped = remapper.remap(); AccessWidener remapped = remapper.remap();
AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped);
try (StringWriter writer = new StringWriter()) { try (StringWriter writer = new StringWriter()) {
remapped.write(writer); accessWidenerWriter.write(writer);
return writer.toString().getBytes(); return writer.toString().getBytes();
} }
} }
@ -178,78 +183,4 @@ public class AccessWidenerJarProcessor implements JarProcessor {
return !Arrays.equals(inputHash, hash); // TODO how do we know if the current jar as the correct access applied? save the hash of the input? return !Arrays.equals(inputHash, hash); // TODO how do we know if the current jar as the correct access applied? save the hash of the input?
} }
private class AccessTransformer extends ClassVisitor {
private String className;
private int classAccess;
private AccessTransformer(ClassVisitor classVisitor) {
super(Opcodes.ASM7, classVisitor);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
className = name;
classAccess = access;
super.visit(
version,
accessWidener.getClassAccess(name).apply(access, name, classAccess),
name,
signature,
superName,
interfaces
);
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
super.visitInnerClass(
name,
outerName,
innerName,
accessWidener.getClassAccess(name).apply(access, name, classAccess)
);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
return super.visitField(
accessWidener.getFieldAccess(new EntryTriple(className, name, descriptor)).apply(access, name, classAccess),
name,
descriptor,
signature,
value
);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
return new AccessWidenerMethodVisitor(super.visitMethod(
accessWidener.getMethodAccess(new EntryTriple(className, name, descriptor)).apply(access, name, classAccess),
name,
descriptor,
signature,
exceptions
));
}
private class AccessWidenerMethodVisitor extends MethodVisitor {
AccessWidenerMethodVisitor(MethodVisitor methodVisitor) {
super(Opcodes.ASM7, methodVisitor);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
if (opcode == Opcodes.INVOKESPECIAL && owner.equals(className) && !name.equals("<init>")) {
AccessWidener.Access methodAccess = accessWidener.getMethodAccess(new EntryTriple(owner, name, descriptor));
if (methodAccess != AccessWidener.MethodAccess.DEFAULT) {
opcode = Opcodes.INVOKEVIRTUAL;
}
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}
}
} }

View File

@ -1,83 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.util.accesswidener;
import java.util.Map;
import org.objectweb.asm.commons.Remapper;
import net.fabricmc.mappings.EntryTriple;
public class AccessWidenerRemapper {
private final AccessWidener input;
private final String to;
private final Remapper remapper;
public AccessWidenerRemapper(AccessWidener input, Remapper remapper, String to) {
this.input = input;
this.to = to;
this.remapper = remapper;
}
public AccessWidener remap() {
// Dont remap if we dont need to
if (input.namespace.equals(to)) {
return input;
}
AccessWidener remapped = new AccessWidener();
remapped.namespace = to;
for (Map.Entry<String, AccessWidener.Access> entry : input.classAccess.entrySet()) {
remapped.classAccess.put(remapper.map(entry.getKey()), entry.getValue());
}
for (Map.Entry<EntryTriple, AccessWidener.Access> entry : input.methodAccess.entrySet()) {
remapped.addOrMerge(remapped.methodAccess, remapMethod(entry.getKey()), entry.getValue());
}
for (Map.Entry<EntryTriple, AccessWidener.Access> entry : input.fieldAccess.entrySet()) {
remapped.addOrMerge(remapped.fieldAccess, remapField(entry.getKey()), entry.getValue());
}
return remapped;
}
private EntryTriple remapMethod(EntryTriple entryTriple) {
return new EntryTriple(
remapper.map(entryTriple.getOwner()),
remapper.mapMethodName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()),
remapper.mapDesc(entryTriple.getDesc())
);
}
private EntryTriple remapField(EntryTriple entryTriple) {
return new EntryTriple(
remapper.map(entryTriple.getOwner()),
remapper.mapFieldName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()),
remapper.mapDesc(entryTriple.getDesc())
);
}
}