Генерация рабочей инвокединамической инструкции с помощью ASM
Я работаю с байт-кодом Java через ASM и пытаюсь получить простой invokedynamic
пример функционирует нормально. Мне кажется, что я в корне не понимаю, как должна работать invokedynamic. Это то, что я пробовал до сих пор:
В Test2.java
У меня есть статический метод, который я хочу вызвать, и мой метод начальной загрузки:
public static int plus(int a, int b) { // method I want to dynamically invoke
return a + b;
}
public static CallSite bootstrap(MethodHandles.Lookup caller, String name,
MethodType type) throws Exception {
MethodHandle mh = MethodHandles.lookup().findStatic(Test2.class,
"plus", MethodType.methodType(int.class, int.class, int.class));
return new ConstantCallSite(mh);
}
Сейчас в Test.java
Я генерирую файл класса с именем Example.class
в упаковке package1
с ASM:
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",
"([Ljava/lang/String;)V", null, null);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
"Ljava/io/PrintStream;");
mv.visitIntInsn(BIPUSH, 42);
mv.visitIntInsn(BIPUSH, 24);
// mv.visitMethodInsn(INVOKESTATIC, "package1/Test2", "plus", "(II)I");
MethodType mt = MethodType.methodType(CallSite.class,
MethodHandles.Lookup.class, String.class, MethodType.class);
Handle bootstrap = new Handle(Opcodes.INVOKESTATIC, "package1/Test2",
"bootstrap", mt.toMethodDescriptorString());
mv.visitInvokeDynamicInsn("plus", "(II)I", bootstrap, new Object[0]);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(I)V");
mv.visitInsn(RETURN);
Однако, когда я пытаюсь запустить сгенерированный файл класса, я получаю следующее:
Исключение в потоке "main" java.lang.ClassFormatError: Неверный вид дескриптора метода при постоянном индексе пула 23 в файле пакета package1/ Пример в java.lang.ClassLoader.defineClass1(собственный метод) в java.lang.ClassLoader.defineClass(ClassLoader. Java:792) в java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) в java.net.URLClassLoader.defineClass(URLClassLoader.java:449) в java.net.URLClassLoader.access$100(URLClassLo) $ в java.net.URLClassLoader$1.run(URLClassLoader.java:361) в java.net.URLClassLoader$1.run(URLClassLoader.java:355) в java.security.AccessController.doPrivileged(собственный метод) в java.net.URLClassLoader.findClass(URLClassLoader.java:354) в java.lang.ClassLoader.loadClass(ClassLoader.java:424) в sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) в java.lang.ClassLoader.loadClass(ClassLoader.java:357) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
Замена invokedynamic
позвони с обычного invokestatic
Вызов (закомментированная строка выше) дает ожидаемый результат. Из сообщения об ошибке мне кажется, что Handle
представляющий мой метод начальной загрузки (bootstrap
) не сформирован должным образом, но я не могу сказать наверняка. Любая помощь приветствуется. Я использую ASM 4.1.
1 ответ
В качестве типа дескриптора вы передаете код операции, а не тип дескриптора. Поскольку они оба просто целые числа, ошибки типа нет, но вы предоставляете значения мусора, которые вызывают ошибку проверки во время загрузки.
Вы, вероятно, хотели сделать что-то подобное (обратите внимание на префикс H_)
Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, "package1/Test2",
"bootstrap", mt.toMethodDescriptorString());
Смотрите здесь для документации Handle.