1

JVM has two instructions: bipush (operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE.) and sipush (operand value should be between Short.MIN_VALUE and Short.MAX_VALUE). Correspondingly, the MethodVisitor in the ASM provide the API to manipulate these two instructions:

      public void visitIntInsn(int opcode, int operand)

Therefore, how to visit other non-byte(short) primitives in the ASM? For example, the primitive long, double, int, boolean, and float data? It looks strange these data are wrapped as Long, Double, Integer.

Seki
  • 11,135
  • 7
  • 46
  • 70
shijie xu
  • 1,975
  • 21
  • 52

1 Answers1

5

Booleans are just ints at the JVM level. Push 0 for false and 1 for true. You don't need bipush for that, you can just use iconst_0 and iconst_1.

Bytes, shorts, chars, and ints are all also just ints at the JVM level. There is no concept of short primitive types in bytecode, only truncatation functions (i2c and co).

If you want to push the int value 111, you would use bipush 111. If you want to push 1111, you would use sipush 1111. If you want to push 111111, you would use ldc 111111. They're all just ints at the bytecode level.

For floats, doubles, and longs, you'll have to in most cases use the ldc* family of instructions. For the special case of 0 or 1 constants, you can instead use lconst_0, dconst_1, etc.

You can create ldc instructions in ASM using the aptly named MethodVisitor.visitLdcInsn.

Note that ldc requires space in the constant pool, which is limited to 65534 slots. However, it's big enough that you'll never run out under practical circumstances. If you really want to, you can push larger primitive values without using the constant pool by using math to construct the values.

For example, int 111111 can be generated by iconst_3 bipush 15 ishl sipush 12807 iadd. Enjarify has code to do this for every primative type, even doubles, though they usually take many more instructions to represent for obvious reasons. However, if you're using ASM, you're probably not doing anything unusual and complicated enough to require this approach.

Antimony
  • 37,781
  • 10
  • 100
  • 107
  • 1
    Note that in ASM, `push(0)` or `push(false)` will automatically generate an `iconst_0` instruction rather than `bipush 0` , so you're working at a slightly higher level of abstraction. – Michael Kay Oct 18 '15 at 08:54
  • I wouldn’t use that complicated instruction sequence for `111111`, especially as it isn’t shorter than the space required in the constant pool. However, using something like `iconst_5, i2l` for pushing the `long` constant `5L` is reasonable, imho. – Holger Oct 19 '15 at 12:37
  • @Holger, it's specifically for the case where you've exhausted space in the constant pool. Like I said, it's not a normal occurence. – Antimony Oct 19 '15 at 16:06
  • I suppose, if you’ve exhausted the max number of constant pool items you are likely to hit other limits, e.g. max code size or max number of methods, as well. But on the other hand, expanding int constants to long or double is reasonable, as `iconst_n; i2l` or `iconst_n; i2d` does not only save nine bytes in the constant pool, but even one byte in the actual method’s code. Even using `bipush n, i2…`, has the same code size as the equivalent `ldc2_w` instruction (while still saving the nine bytes in the pool)… – Holger Oct 19 '15 at 18:13