-
-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a reflective name fixer, used for various calls in Class and Meth…
…odHandles.Lookup This currently handles class names with mixed mappings, so doing: Class.forName(ServerPlayerEntity.class.getName() + "$2"); now works correctly even if the inner class has been mapped differently. This also supports field and method lookups using Class.get[Declared](Field/Method), as well as the MethodHandle.Lookup methods find[Static](Getter/Setter/VarHandle), and find(Static/Virtual/Special) This only works if the mappings are present for it - using proper names will never work outside of a development environment. In addition, we still encourage developers to use the MappingResolver to be sure the names will always be mapped correctly. This commit also adds a somewhat unrelated change: - Fixed InternalsHiderTransform always adding one to the maximum stack size of every single method. (I hadn't checked the order that visitMaxs is called in - and since it must be called last, just before visitEnd, we can wait and see if we've needed to emit code that requires an additional stack element, whereas I previously thought it was called first)
- Loading branch information
Showing
10 changed files
with
1,037 additions
and
9 deletions.
There are no files selected for viewing
88 changes: 88 additions & 0 deletions
88
minecraft/minecraft-test/src/main/java/net/fabricmc/minecraft/test/FabricEntrypointTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,98 @@ | ||
package net.fabricmc.minecraft.test; | ||
|
||
import java.lang.invoke.MethodHandle; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.MethodHandles.Lookup; | ||
import java.lang.invoke.MethodType; | ||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
|
||
import org.jetbrains.annotations.Nullable; | ||
import org.quiltmc.loader.api.MappingResolver; | ||
import org.quiltmc.loader.api.QuiltLoader; | ||
import org.quiltmc.loader.impl.launch.common.QuiltLauncherBase; | ||
|
||
import net.fabricmc.api.ModInitializer; | ||
import net.fabricmc.mappingio.tree.MappingTreeView; | ||
import net.fabricmc.mappingio.tree.MappingTreeView.MethodMappingView; | ||
|
||
import net.minecraft.entity.Entity; | ||
import net.minecraft.item.CompassItem; | ||
import net.minecraft.item.DyeItem; | ||
import net.minecraft.item.Item; | ||
import net.minecraft.item.ItemStack; | ||
import net.minecraft.server.network.ServerPlayerEntity; | ||
import net.minecraft.world.World; | ||
|
||
public class FabricEntrypointTest implements ModInitializer { | ||
@Override | ||
public void onInitialize() { | ||
System.out.println("testmod initialized!"); | ||
|
||
System.out.println("Testing ReflectiveFixer"); | ||
try { | ||
String clnom = ServerPlayerEntity.class.getName() + "$2"; // An anonymous inner class | ||
Class<?> cls = Class.forName(clnom, true, FabricEntrypointTest.class.getClassLoader()); | ||
MappingResolver mappings = QuiltLoader.getMappingResolver(); | ||
MappingTreeView mappingsView = QuiltLauncherBase.getLauncher().getMappingConfiguration().getMappings(); | ||
String currentNamespace = mappings.getCurrentRuntimeNamespace(); | ||
|
||
for (String namespace : mappings.getNamespaces()) { | ||
String name = mappings.unmapClassName(namespace, cls.getName()); | ||
System.out.println( | ||
"[" + (currentNamespace.equals(namespace) ? "x" : " ") + "] " + namespace + " = " + name | ||
); | ||
} | ||
|
||
System.out.println(cls.getName()); | ||
System.out.println(Arrays.toString(cls.getInterfaces())); | ||
System.out.println(cls.getDeclaredField("field_29183")); | ||
System.out.println(cls.getField("field_29183")); | ||
MethodHandle getter = MethodHandles.privateLookupIn(cls, MethodHandles.lookup()).findGetter( | ||
cls, "field_29183", ServerPlayerEntity.class | ||
); | ||
int h = 0; | ||
for (int i = 0; i < 100_000; i++) { | ||
MethodHandle handle = MethodHandles.privateLookupIn(cls, MethodHandles.lookup()).findGetter( | ||
cls, "field_29183", ServerPlayerEntity.class | ||
); | ||
h = h + 1 * handle.hashCode(); | ||
} | ||
System.out.println(h); | ||
System.out.println("Obtained getter " + getter + " as " + getter.type().toMethodDescriptorString()); | ||
|
||
// inventoryTick (ItemStack stack, World world, Entity entity, int slot, boolean selected)V | ||
MethodType type = MethodType.methodType(void.class, ItemStack.class, World.class, Entity.class, int.class, boolean.class); | ||
String intermediaryName = null; | ||
for (Method m : Item.class.getDeclaredMethods()) { | ||
if (m.getReturnType() != type.returnType() || !Arrays.equals(type.parameterArray(), m.getParameterTypes())) { | ||
continue; | ||
} | ||
System.out.println(m.getName()); | ||
// Should we publish this as API? | ||
int i = mappingsView.getNamespaceId("named"); | ||
MethodMappingView method = mappingsView.getMethod(Item.class.getName().replace('.', '/'), "inventoryTick", type.descriptorString(), i); | ||
if (method != null) { | ||
System.out.println(method.getName("official")); | ||
System.out.println(intermediaryName = method.getName("intermediary")); | ||
System.out.println(method.getName("named")); | ||
break; | ||
} | ||
} | ||
System.out.println("Method Name = " + intermediaryName); | ||
System.out.println("Method (Virtual) = " + MethodHandles.lookup().findVirtual(CompassItem.class, intermediaryName, type)); | ||
Lookup privateInItem = MethodHandles.privateLookupIn(Item.class, MethodHandles.lookup()); | ||
System.out.println("Method (Special) = " + privateInItem.findSpecial(Item.class, intermediaryName, type, Item.class)); | ||
|
||
System.out.println("Method (Declared) = " + Item.class.getDeclaredMethod(intermediaryName, type.parameterArray())); | ||
System.out.println("Method (Any) = " + CompassItem.class.getMethod(intermediaryName, type.parameterArray())); | ||
|
||
int namespace = mappingsView.getNamespaceId("named"); | ||
MethodMappingView method = mappingsView.getMethod(CompassItem.class.getName().replace('.', '/'), "getSpawnPosition", null, namespace); | ||
System.out.println("getSpawnPosition = " + method); | ||
|
||
} catch (ReflectiveOperationException e) { | ||
throw new Error(e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.