Migrate to access-widener library (#294)
This commit is contained in:
		
							parent
							
								
									62e89395f9
								
							
						
					
					
						commit
						d1281be741
					
				
					 7 changed files with 27 additions and 648 deletions
				
			
		|  | @ -50,6 +50,8 @@ dependencies { | |||
| 	implementation ('net.fabricmc:tiny-remapper:0.3.0.70') | ||||
| 	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') { | ||||
| 		transitive = false | ||||
| 	} | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ package net.fabricmc.loom.util; | |||
| import java.util.List; | ||||
| 
 | ||||
| import com.google.common.collect.ImmutableList; | ||||
| import org.objectweb.asm.Opcodes; | ||||
| 
 | ||||
| public class Constants { | ||||
| 	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 int ASM_VERSION = Opcodes.ASM9; | ||||
| 
 | ||||
| 	public static final List<RemappedConfigurationEntry> MOD_COMPILE_ENTRIES = ImmutableList.of( | ||||
| 			new RemappedConfigurationEntry("modCompile", "compile", 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.Label; | ||||
| import org.objectweb.asm.MethodVisitor; | ||||
| import org.objectweb.asm.Opcodes; | ||||
| 
 | ||||
| import net.fabricmc.loom.util.progress.ProgressLogger; | ||||
| 
 | ||||
|  | @ -124,7 +123,7 @@ public class LineNumberRemapper { | |||
| 							ClassReader reader = new ClassReader(is); | ||||
| 							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()); | ||||
| 						} | ||||
| 					} | ||||
|  |  | |||
|  | @ -51,11 +51,13 @@ import org.zeroturnaround.zip.ZipUtil; | |||
| import org.zeroturnaround.zip.transform.StringZipEntryTransformer; | ||||
| 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.providers.MappingsProvider; | ||||
| 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.tinyremapper.TinyRemapper; | ||||
| import net.fabricmc.tinyremapper.InputTag; | ||||
|  | @ -109,13 +111,15 @@ public class ModProcessor { | |||
| 	private static byte[] remapAccessWidener(byte[] input, Remapper remapper) { | ||||
| 		try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) { | ||||
| 			AccessWidener accessWidener = new AccessWidener(); | ||||
| 			accessWidener.read(bufferedReader); | ||||
| 			AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener); | ||||
| 			accessWidenerReader.read(bufferedReader); | ||||
| 
 | ||||
| 			AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, "named"); | ||||
| 			AccessWidener remapped = accessWidenerRemapper.remap(); | ||||
| 			AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped); | ||||
| 
 | ||||
| 			try (StringWriter writer = new StringWriter()) { | ||||
| 				remapped.write(writer); | ||||
| 				accessWidenerWriter.write(writer); | ||||
| 				return writer.toString().getBytes(StandardCharsets.UTF_8); | ||||
| 			} | ||||
| 		} 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.ClassVisitor; | ||||
| 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.zeroturnaround.zip.ZipUtil; | ||||
| import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer; | ||||
| import org.zeroturnaround.zip.transform.ZipEntryTransformer; | ||||
| 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.processors.JarProcessor; | ||||
| import net.fabricmc.loom.util.Constants; | ||||
| import net.fabricmc.loom.util.Checksum; | ||||
| import net.fabricmc.mappings.EntryTriple; | ||||
| import net.fabricmc.tinyremapper.TinyRemapper; | ||||
| 
 | ||||
| public class AccessWidenerJarProcessor implements JarProcessor { | ||||
| 	private AccessWidener accessWidener = new AccessWidener(); | ||||
| 	private AccessWidenerReader accessWidenerReader = new AccessWidenerReader(accessWidener); | ||||
| 	private final Project project; | ||||
| 	private byte[] inputHash; | ||||
| 
 | ||||
|  | @ -76,13 +79,13 @@ public class AccessWidenerJarProcessor implements JarProcessor { | |||
| 		inputHash = Checksum.sha256(loomGradleExtension.accessWidener); | ||||
| 
 | ||||
| 		try (BufferedReader reader = new BufferedReader(new FileReader(loomGradleExtension.accessWidener))) { | ||||
| 			accessWidener.read(reader); | ||||
| 			accessWidenerReader.read(reader); | ||||
| 		} catch (IOException e) { | ||||
| 			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 | ||||
| 		if (!accessWidener.namespace.equals("named")) { | ||||
| 		if (!accessWidener.getNamespace().equals("named")) { | ||||
| 			try { | ||||
| 				TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper("official", "named"); | ||||
| 				tinyRemapper.readClassPath(loomGradleExtension.getMinecraftMappedProvider().getRemapClasspath()); | ||||
|  | @ -116,10 +119,11 @@ public class AccessWidenerJarProcessor implements JarProcessor { | |||
| 			protected byte[] transform(ZipEntry zipEntry, byte[] input) { | ||||
| 				ClassReader reader = new ClassReader(input); | ||||
| 				ClassWriter writer = new ClassWriter(0); | ||||
| 				ClassVisitor classVisitor = AccessWidenerVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener); | ||||
| 
 | ||||
| 				project.getLogger().lifecycle("Applying access widener to " + className); | ||||
| 
 | ||||
| 				reader.accept(new AccessTransformer(writer), 0); | ||||
| 				reader.accept(classVisitor, 0); | ||||
| 				return writer.toByteArray(); | ||||
| 			} | ||||
| 		}; | ||||
|  | @ -145,9 +149,10 @@ public class AccessWidenerJarProcessor implements JarProcessor { | |||
| 	public byte[] getRemappedAccessWidener(Remapper asmRemapper) throws IOException { | ||||
| 		AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, "intermediary"); | ||||
| 		AccessWidener remapped = remapper.remap(); | ||||
| 		AccessWidenerWriter accessWidenerWriter = new AccessWidenerWriter(remapped); | ||||
| 
 | ||||
| 		try (StringWriter writer = new StringWriter()) { | ||||
| 			remapped.write(writer); | ||||
| 			accessWidenerWriter.write(writer); | ||||
| 			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? | ||||
| 	} | ||||
| 
 | ||||
| 	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 a new issue