2015-12-31 1 views
2

J'écris un programme dans ASM qui utilise l'API Tree pour ajouter du bytecode à certaines méthodes. Je l'ai utilisé ASMifier pour générer le code nécessaire pour créer une méthode spécifique, mais je vais avoir des problèmes avec la ligne suivante:ASM Tree API: utilisation de LDC pour charger une classe <?>

mv.visitLdcInsn(Type.getType('L' + targetClassName + ';')); 

J'ai simplement initialisés mv à un new MethodNode, mais au lieu de charger la Class, la ligne ci-dessus apparaît en bytecode comme:

ldc Lsome/test/TestClass; (org.objectweb.asm.Type) 

Comment puis-je faire charger ASM la constante java/lang/Class au lieu d'une constante org.objectweb.asm.Type?

Si elle est liée, la ligne suivante de bytecode serait invokevirtual java/lang/Class getClassLoader(()Ljava/lang/ClassLoader;);

+0

Il semble un peu étrange que vous utilisiez l'API Tree * et * 'visitLdcInsn'. Avec 'MethodNode', je m'attendrais à ce que de nouvelles instructions soient insérées dans [' InsnList'] (http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/tree/InsnList.html). – dejvuth

+0

J'utilise ASMifier, puis je remplace simplement le '' '' MethodVisitor''' par un '' '' MethodNode''', parce que cela semble être le moyen le plus simple de convertir une méthode générée en quelque chose qui peut être utilisé dans le API de l'arbre Pour autant que je sache, le '' '' LdcInsnNode''' est simplement ajouté à '' '' 'InsnList''' dans l'implémentation de visitLdcInsn. – konsolas

+1

Vous avez une erreur dans le processus de conversion. Sinon, cela semble correct. –

Répondre

3

Votre code est correct, mais pas la solution canonique. Vous pouvez simplifier comme

mv.visitLdcInsn(Type.getObjectType(targetClassName)); 

(En ASM, « Type d'objet », un type de référence, voir aussi Type.getObjectType(…) et the Type.OBJECT sort). Cependant, le résultat est le même. La raison, pourquoi la sortie de démontage ressemble

ldc Lsome/test/TestClass; (org.objectweb.asm.Type) 

réside dans le désassembleur. Si vous regardez it’s code for converting an LDC instruction to a String:

protected String printLdcInsnNode(LdcInsnNode ldc, ListIterator<?> it) { 
    if (ldc.cst instanceof String) 
     return nameOpcode(ldc.opcode()) + " \"" + StringEscapeUtils.escapeJava(ldc.cst.toString()) + "\" (" + ldc.cst.getClass().getCanonicalName() + ")"; 

    return nameOpcode(ldc.opcode()) + " " + StringEscapeUtils.escapeJava(ldc.cst.toString()) + " (" + ldc.cst.getClass().getCanonicalName() + ")"; 
} 

vous verrez qu'il imprime le type de l'instance d'objet stocké dans la LdcInsnNode plutôt que ce que le code finira par produire lors de l'exécution. Pour un String, cela suffit comme étant le même type, et pour les primitives, il imprimera le type wrapper correspondant, mais pour Type ou Handle objets, ce désassembleur vous montrera ces classes spécifiques ASM au lieu des classes d'exécution correspondantes java.lang.Class, java.lang.invoke.MethodType ou java.lang.invoke.MethodHandle, que l'instruction ldc va réellement pousser vers la pile d'opérandes.

+0

Bien, merci. J'ai vérifié avec un autre désassembleur, et j'obtiens la constante java/lang/Class correcte. Merci :) – konsolas

0

Je suis venu avec une solution temporaire pour l'instant.

mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false); 
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "lookupClass", "()Ljava/lang/Class;", false); 
+0

Il semble n'y avoir aucun lien avec le problème ci-dessus. Il semble que le texte ci-dessus n'était pas votre vrai problème ... – CoronA

+0

L'objectif était de charger une constante de classe sur la pile. J'ai d'abord essayé d'utiliser LDC, c'est une autre méthode de faire la même chose. – konsolas