J'utilise le ASM library pour modifier le code intermédiaire créé par d'autres. Pour une méthode arbitraire dans une classe arbitraire, je voudrais créer un LdcInsnNode
qui ajoute la classe en cours à la pile.Comment créer un LdcInsnNode ASM qui ajoute statiquement la classe actuelle à la pile?
Par exemple, disons que je suis la transformation d'une classe appelée com.example.ExampleClass
. Je voudrais créer un bytecode équivalent à System.out.println(ExampleClass.class.getName());
.
Cela semble être une tâche relativement simple. Lorsque j'utilise l'Eclipse bytecode plugin Plan, il est dit que le bytecode suivante est équivalente:
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC Lcom/example/ExampleClass;.class
INVOKEVIRTUAL java/lang/Class.getName()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
J'ai essayé le code suivant:
private InsnList printClass() {
InsnList result = new InsnList();
result.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
result.add(new LdcInsnNode("L" + name + ";.class"));
result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false));
result.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false));
return result;
}
Ceci est en cours d'exécution dans une extension de ClassNode
, si name
fait référence au champ ClassNode.name
. Le InsnList
retourné par cette méthode est inséré avant un AbstractInsnNode
existant à l'aide InsnList.insertBefore(AbstractInsnNode, printClass())
. Lorsque ce point est atteint dans le bytecode, je reçois une erreur avec la raison suivante:
Type 'java/lang/String' (current frame, stack[1]) is not assignable to 'java/lang/Class'
Ceci est clairement parce que l'instruction LDC ajoute la chaîne "Lcom/example/ExampleClass;.class"
au lieu de la classe réelle Lcom/example/ExampleClass;.class
.
Y a-t-il une solution de contournement pour cela? Il semble impossible d'ajouter directement l'objet Class
à un LdcInsnNode
car la classe n'existe pas encore. Mais existe-t-il un moyen d'ajouter une instruction qui charge l'objet Class
?
Dans mon cas particulier, appelant la méthode Object.getClass()
n'est pas une option, car elle a besoin de travailler dans un contexte statique.