Migrate to access-widener library (#294)
parent
62e89395f9
commit
d1281be741
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue