9

I am trying to figure out the bytecode size of a method because I want to be sure that it will be small enough to be inlined by compiler optimizations.

I saw that the default max size for inlining methods is 35, so if the method is larger than that I will revise the code or break it into multiple methods.

I have a method that generates the bytecode below (disassembled via the ASM Bytecode Outline plugin for IntelliJ IDEA).

How can I tell the bytecode size of that method? the LINENUMBERs seem to reference the line numbers of the original source code.

public static mergeNativeArrays([Ljava/lang/Object;[Ljava/lang/Object;IZ)[Ljava/lang/Object;
 L0
  LINENUMBER 865 L0
  ALOAD 0
  ASTORE 4
 L1
  LINENUMBER 867 L1
  ILOAD 2
  IFGE L2
 L3
  LINENUMBER 868 L3
  ALOAD 0
  ARRAYLENGTH
  ISTORE 2
 L2
  LINENUMBER 870 L2
 FRAME APPEND [[Ljava/lang/Object;]
  ILOAD 2
  ALOAD 1
  ARRAYLENGTH
  IADD
  ISTORE 5
 L4
  LINENUMBER 872 L4
  ALOAD 4
  ARRAYLENGTH
  ILOAD 5
  IF_ICMPGE L5
 L6
  LINENUMBER 874 L6
  ILOAD 3
  IFEQ L7
 L8
  LINENUMBER 875 L8
  ILOAD 5
  INVOKESTATIC railo/commons/math/MathUtil.nextPowerOf2 (I)I
  ISTORE 5
 L7
  LINENUMBER 877 L7
 FRAME APPEND [I]
  ILOAD 5
  ANEWARRAY java/lang/Object
  ASTORE 4
 L9
  LINENUMBER 878 L9
  ALOAD 0
  ICONST_0
  ALOAD 4
  ICONST_0
  ALOAD 0
  ARRAYLENGTH
  INVOKESTATIC java/lang/System.arraycopy (Ljava/lang/Object;ILjava/lang/Object;II)V
 L5
  LINENUMBER 881 L5
 FRAME SAME
  ALOAD 1
  ICONST_0
  ALOAD 4
  ILOAD 2
  ALOAD 1
  ARRAYLENGTH
  INVOKESTATIC java/lang/System.arraycopy (Ljava/lang/Object;ILjava/lang/Object;II)V
 L10
  LINENUMBER 883 L10
  ALOAD 4
  ARETURN
 L11
  LOCALVARIABLE dst [Ljava/lang/Object; L0 L11 0
  LOCALVARIABLE src [Ljava/lang/Object; L0 L11 1
  LOCALVARIABLE dstPosition I L0 L11 2
  LOCALVARIABLE doPowerOf2 Z L0 L11 3
  LOCALVARIABLE result [Ljava/lang/Object; L1 L11 4
  LOCALVARIABLE newSize I L4 L11 5
  MAXSTACK = 5
  MAXLOCALS = 6
isapir
  • 21,295
  • 13
  • 115
  • 116
  • It would probably be easier to just check if the method gets compiled or not... – assylias Jan 25 '14 at 23:35
  • not sure what you mean? of course it gets compiled. – isapir Jan 25 '14 at 23:36
  • 2
    Sorry I meant inlined. You can use the -`XX:+PrintInlining` flag. – assylias Jan 25 '14 at 23:37
  • 2
    35 bytes is the default max for infrequent methods, if you call the methods often enough, much larger methods can be inlined (the default for frequent methods is JVM dependant). You can always increase this number to see it it improves your code's performance. – Peter Lawrey Jan 25 '14 at 23:39
  • What kind of workflow are you looking for? Finding the size is easy, but if you want to do it programatically, you're best off with ASM. – Antimony Jan 25 '14 at 23:57
  • @assylias - it looks promising, I am reading more about it, but I still would like to be able to count the bytes, or add them up with javap which failed to find the class even though I specified the -classpath pointing to the jar it is in. – isapir Jan 26 '14 at 01:21
  • @PeterLawrey - this code is used by other developers so it's hard to tell how they will use it, thus I am trying to generate the most optimized code that I can. – isapir Jan 26 '14 at 01:22
  • @Antimony - workflow is simple. for the sake of this exercise it is not required at runtime, so counting the bytes manually or using javap (if I could get it to work on that class) would be sufficient. – isapir Jan 26 '14 at 01:24
  • 1
    I'd recommend using javap then. – Antimony Jan 26 '14 at 02:29
  • 3
    Making sure the code is warmed up will improve performance by 10-100x, much more than inlining alone. If you can't be sure the code is warmed up, I would take step to ensure critical code is called enough so that it is. – Peter Lawrey Jan 26 '14 at 08:13
  • @PeterLawrey - I agree, but this code goes into an application server's function, and it is impossible to know if the developer will use that function or not, so I am trying to do whatever I can to make it efficient. I ended up splitting the 64-byte method into two methods of less than 35-bytes each. thank you for your insight - I upvoted all of the useful comments. – isapir Jan 26 '14 at 16:22
  • 1
    Is there a point in making code which is never called more efficient. Unless you have a clear idea of what you are trying to optimise and metrics which show the changes you are making are helping you are lost. You are just as likely to make things worse, and more complicated. – Peter Lawrey Jan 26 '14 at 16:44
  • I did not say it is "never called". all the developers that use the app server use this code as it is used in one of the built-in data types of the app server - some use it casually, others use it extensively. I noticed inefficiencies in some very old code while fixing a bug there, so I decided to improve those while I'm at it. – isapir Jan 26 '14 at 16:59

1 Answers1

8

How can I tell the bytecode size of that method?

One way is to just add them up :-)

Each bytecode instruction consists of 1 byte for the primary instruction plus a fixed number of operand bytes.


A more practical way is to dump the classfile containing the bytecodes using javap -c. The output includes byte offsets for each instruction.

Reference: http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javap.html


1) I can add ALOAD 0 ASTORE 4 as 4 bytes, but what do I do with with ARRAYLENGTH or INVOKESTATIC method-name?

The instructions are listed in Section 6.5 of the JVM spec - http://docs.oracle.com/javase/specs/jvms/se7/html/index.html

  1. Scroll down to the relevant part of the index.
  2. Click on the link for the instruction.
  3. Read the "format" and "description" to figure out how many bytes are used.

Following this procedure, I deduced that ARRAYLENGTH is 1 byte, and INVOKESTATIC is 3 bytes.

2) I tried to use javap but for some reason I get class not found (it's inside a jar and I passed -classpath filename.jar to javap but it didn't work).

Read the javap manual entry again. It does work if you use it correctly. (Perhaps you didn't supply the fully-qualified classname in the correct format.)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • that's what I was trying to do, but 1) I can add ALOAD 0 ASTORE 4 as 4 bytes, but what do I do with with ARRAYLENGTH or INVOKESTATIC method-name? and 2) I tried to use javap but for some reason I get class not found (it's inside a jar and I passed -classpath filename.jar to javap but it didn't work) – isapir Jan 26 '14 at 01:19
  • you're right, I forgot that the class is packaged in a way that makes it "invisible" to the jar in order to allow for updates at runtime. I javap to work and the method shows [64: areturn] so I guess that means it is 65 bytes long? – isapir Jan 26 '14 at 02:55
  • That sounds right. If you don't trust the answer, cross-check by calculating the method size manually. – Stephen C Jan 26 '14 at 03:04
  • I'm not sure that I can add them manually as [ALOAD 0] suggests 2 bytes, while the real instruction is [aload_0] which is 1 byte. I do trust the javap output though, and to correct my previous comment -- the javap "position" output is 0-based, so when it shows [64: areturn] it actually is 64 bytes including the [areturn] instruction. thank you for your insight. – isapir Jan 26 '14 at 03:19