Skip to content

Commit 3933de3

Browse files
committed
make remapping overloaded methods work
1 parent 71f316e commit 3933de3

File tree

2 files changed

+123
-13
lines changed

2 files changed

+123
-13
lines changed

src/main/java/de/blazemcworld/jsscripts/Mappings.java

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@
1010
import java.io.File;
1111
import java.io.FileReader;
1212
import java.io.InputStream;
13+
import java.lang.reflect.Field;
14+
import java.lang.reflect.Method;
1315
import java.net.URI;
1416
import java.net.URL;
1517
import java.net.http.HttpClient;
1618
import java.net.http.HttpRequest;
1719
import java.net.http.HttpResponse;
1820
import java.nio.file.Files;
21+
import java.util.ArrayList;
22+
import java.util.HashSet;
23+
import java.util.List;
24+
import java.util.Set;
1925
import java.util.zip.ZipEntry;
2026
import java.util.zip.ZipInputStream;
2127

@@ -149,6 +155,36 @@ private static MethodDef getMethod(ClassDef classDef, String namespace, String n
149155
return null;
150156
}
151157

158+
private static Set<MethodDef> getOverloadedMethod(ClassDef classDef, String namespace, String name) {
159+
Set<MethodDef> out = new HashSet<>();
160+
for (MethodDef def : classDef.getMethods()) {
161+
if (def.getName(namespace).equals(name)) {
162+
out.add(def);
163+
}
164+
}
165+
166+
try {
167+
Class<?> currentClass = Class.forName(classDef.getName(current()).replace('/', '.'));
168+
Class<?> parent = currentClass.getSuperclass();
169+
if (parent != null) {
170+
ClassDef def = getClass(current(), parent.getName());
171+
if (def != null) {
172+
out.addAll(getOverloadedMethod(def, namespace, name));
173+
}
174+
}
175+
for (Class<?> iface : currentClass.getInterfaces()) {
176+
ClassDef def = getClass(current(), iface.getName());
177+
if (def != null) {
178+
out.addAll(getOverloadedMethod(def, namespace, name));
179+
}
180+
}
181+
} catch (ClassNotFoundException e) {
182+
throw new RuntimeException(e);
183+
}
184+
185+
return out;
186+
}
187+
152188
public static String current() {
153189
return current;
154190
}
@@ -181,6 +217,20 @@ public static String remapMethod(String classNamespace, String className, String
181217
return res;
182218
}
183219

220+
public static Set<String> remapOverloadedMethod(String classNamespace, String className, String from, String to, String name) {
221+
ClassDef classDef = Mappings.getClass(classNamespace, className);
222+
if (classDef == null) return new HashSet<>(Set.of(name));
223+
Set<MethodDef> methodDefs = getOverloadedMethod(classDef, from, name);
224+
if (methodDefs.size() == 0) return new HashSet<>(Set.of(name));
225+
Set<String> out = new HashSet<>();
226+
for (MethodDef def : methodDefs) {
227+
String res = def.getName(to);
228+
if (res != null) out.add(res);
229+
}
230+
if (out.size() == 0) return new HashSet<>(Set.of(name));
231+
return out;
232+
}
233+
184234
@SuppressWarnings("unused")
185235
public static String graalRemapClass(String clazz) {
186236
return remapClass("named", current(), clazz);
@@ -192,7 +242,69 @@ public static String graalRemapField(Class<?> clazz, String field) {
192242
}
193243

194244
@SuppressWarnings("unused")
195-
public static String graalRemapMethod(Class<?> clazz, String method) {
196-
return remapMethod(current(), clazz.getName(), "named", current(), method);
245+
public static Object graalRemapOverloadedMethod(Object hostCtx, Class<?> clazz, String searchName, boolean onlyStatic) {
246+
try {
247+
Set<String> names = remapOverloadedMethod(current(), clazz.getName(), "named", current(), searchName);
248+
249+
Class<?> hostClassDescClass = Class.forName("com.oracle.truffle.host.HostClassDesc");
250+
Class<?> hostContextClass = Class.forName("com.oracle.truffle.host.HostContext");
251+
Class<?> overloadedMethodClass = Class.forName("com.oracle.truffle.host.HostMethodDesc$OverloadedMethod");
252+
Class<?> singleMethodClass = Class.forName("com.oracle.truffle.host.HostMethodDesc$SingleMethod");
253+
Class<?> hostMethodDescClass = Class.forName("com.oracle.truffle.host.HostMethodDesc");
254+
Class<?> membersClass = Class.forName("com.oracle.truffle.host.HostClassDesc$Members");
255+
256+
Method forClassMethod = hostClassDescClass.getDeclaredMethod("forClass", hostContextClass, Class.class);
257+
forClassMethod.setAccessible(true);
258+
259+
Object hostClassDesc = forClassMethod.invoke(null, hostCtx, clazz);
260+
261+
List<Object> overloads = new ArrayList<>();
262+
Method lookupMethodMethod = hostClassDescClass.getDeclaredMethod("lookupMethod", String.class, boolean.class);
263+
Method lookupMethodBySignatureMethod = hostClassDescClass.getDeclaredMethod("lookupMethodBySignature", String.class, boolean.class);
264+
Method lookupMethodByJNINameMethod = hostClassDescClass.getDeclaredMethod("lookupMethodByJNIName", String.class, boolean.class);
265+
266+
lookupMethodMethod.setAccessible(true);
267+
lookupMethodBySignatureMethod.setAccessible(true);
268+
lookupMethodByJNINameMethod.setAccessible(true);
269+
270+
Field overloadsField = overloadedMethodClass.getDeclaredField("overloads");
271+
overloadsField.setAccessible(true);
272+
273+
for (String name : names) {
274+
overloads.add(lookupMethodMethod.invoke(hostClassDesc, name, onlyStatic));
275+
overloads.add(lookupMethodBySignatureMethod.invoke(hostClassDesc, name, onlyStatic));
276+
overloads.add(lookupMethodByJNINameMethod.invoke(hostClassDesc, name, onlyStatic));
277+
}
278+
279+
while (overloads.contains(null)) {
280+
overloads.remove(null);
281+
}
282+
283+
List<Object> singleMethods = new ArrayList<>();
284+
285+
for (Object possibleMethod : overloads) {
286+
if (singleMethodClass.isInstance(possibleMethod)) {
287+
singleMethods.add(possibleMethod);
288+
} else {
289+
singleMethods.addAll(List.of((Object[]) overloadsField.get(possibleMethod)));
290+
}
291+
}
292+
293+
if (singleMethods.size() == 0) {
294+
return null;
295+
}
296+
297+
Method mergeMethod = membersClass.getDeclaredMethod("merge", hostMethodDescClass, hostMethodDescClass);
298+
mergeMethod.setAccessible(true);
299+
300+
Object out = singleMethods.get(0);
301+
for (int i = 1; i < singleMethods.size(); i++) {
302+
out = mergeMethod.invoke(null, out, singleMethods.get(i));
303+
}
304+
305+
return out;
306+
} catch (Exception e) {
307+
throw new RuntimeException(e);
308+
}
197309
}
198310
}

src/main/java/de/blazemcworld/jsscripts/ScriptManager.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
import com.google.gson.JsonParser;
66
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
77
import org.objectweb.asm.Opcodes;
8-
import org.objectweb.asm.tree.InsnList;
9-
import org.objectweb.asm.tree.MethodInsnNode;
10-
import org.objectweb.asm.tree.VarInsnNode;
8+
import org.objectweb.asm.tree.*;
119

1210
import java.io.File;
1311
import java.io.IOException;
@@ -239,14 +237,14 @@ private static void injectMappings() {
239237
});
240238
Injector.transformMethod("com.oracle.truffle.host.HostInteropReflect", "findMethod", method -> {
241239
try {
242-
InsnList instructions = new InsnList();
243-
244-
instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
245-
instructions.add(new VarInsnNode(Opcodes.ALOAD, 2));
246-
instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "de/blazemcworld/jsscripts/Mappings", "graalRemapMethod", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/String;"));
247-
instructions.add(new VarInsnNode(Opcodes.ASTORE, 2));
248-
249-
method.instructions.insertBefore(method.instructions.getFirst(), instructions);
240+
method.instructions.clear();
241+
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
242+
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
243+
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2));
244+
method.instructions.add(new VarInsnNode(Opcodes.ILOAD, 3));
245+
method.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "de/blazemcworld/jsscripts/Mappings", "graalRemapOverloadedMethod", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Z)Ljava/lang/Object;"));
246+
method.instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, "com/oracle/truffle/host/HostMethodDesc"));
247+
method.instructions.add(new InsnNode(Opcodes.ARETURN));
250248
} catch (Exception e) {
251249
throw new RuntimeException(e);
252250
}

0 commit comments

Comments
 (0)