DSL of Groovy never made me bored. I am working on some bytecode transformation and having a number of tests to run.
Testing low-level transformation means dealing with JVM instructions. For example,
ILOAD 0
INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
LDC 0
INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter
.compareLessThan(Ljava/lang/Object;Ljava/lang/Object;)Z
IFEQ L2
There is class MethodNode in the tree package of ASM. The class has the field instructions of class InsnList, which contains its method body. In the following, I have InsnList insn = methodNode.instructions; to perform some optimisation over it.
Before making AsmNodeBuilder, I had to create
a test data using Asm's Tree Nodes. Something looks like:
insn.add(new VarInsnNode(ILOAD, 0))
With Groovy and AsmNodeBuilder, now I can write:
insn.append {
iload 0
}
When comparing results, I had to do:
assert insn.get(0).opcode == ILOAD
assert insn.get(0).var == 0
Now, it becomes:
assertEquals asm { iload 0 }, insn[0]
Of course, I can also do:
assertEquals asm {
iload 0
invokestatic Integer,"valueOf",[int],Integer
}, insn
to assert all instructions in the list.
Look fun? Convinced? There are two classes you may use:
- InsnListHelper.groovy
- AsmNodeBuilder.java (generated from gen_asm_builder.groovy)
Here's how to
Testing low-level transformation means dealing with JVM instructions. For example,
ILOAD 0
INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
LDC 0
INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;
INVOKESTATIC org/codehaus/groovy/runtime/ScriptBytecodeAdapter
.compareLessThan(Ljava/lang/Object;Ljava/lang/Object;)Z
IFEQ L2
There is class MethodNode in the tree package of ASM. The class has the field instructions of class InsnList, which contains its method body. In the following, I have InsnList insn = methodNode.instructions; to perform some optimisation over it.
Before making AsmNodeBuilder, I had to create
a test data using Asm's Tree Nodes. Something looks like:
insn.add(new VarInsnNode(ILOAD, 0))
With Groovy and AsmNodeBuilder, now I can write:
insn.append {
iload 0
}
When comparing results, I had to do:
assert insn.get(0).opcode == ILOAD
assert insn.get(0).var == 0
Now, it becomes:
assertEquals asm { iload 0 }, insn[0]
Of course, I can also do:
assertEquals asm {
iload 0
invokestatic Integer,"valueOf",[int],Integer
}, insn
to assert all instructions in the list.
Look fun? Convinced? There are two classes you may use:
- InsnListHelper.groovy
- AsmNodeBuilder.java (generated from gen_asm_builder.groovy)
Here's how to
- call InsnListHelper.install() in the very beginning of your Groovy test case.
- Write a test case.
- use <InsnList>.append { ... } to create a method body.
- do your transformation.
- assert the result against an asm { ... } block. Note that Groovy's power assertion won't work with the block for some reasons, use assertEquals instead.