I'm trying to understand 'native code generation and execution' part of Java JITC, but having a hard time visualizing exactly what happens. E.g. say I have the following class:
class Foo
{
private int x;
public void incX()
{
x++;
}
}
javac generates the following byte code for the method:
public void incX();
Code:
Stack=3, Locals=1, Args_size=1
0: aload_0
1: dup
2: getfield #17; //Field x:I
5: iconst_1
6: iadd
7: putfield #17; //Field x:I
10: return
LineNumberTable:
line 33: 0
line 34: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this LFoo;
When JITC converts this into native code, what exactly happens? And how is this native code executed by JVM?
When the method gets called sufficiently often to pass the JVM's compilation threshold, the JIT compiles the bytecode into native code, and sets it up so that calls to the function go directly to the natively compiled method.
Related
I'm trying to figure out exactly how lambdas and closures work in the JVM. To that end, I've tried compiling this simple test case:
import java.util.function.*;
class Adder {
static Function<Float, Float> makeAdder(Float a) {
return b -> a + b;
}
public static void main(String[] args) {
Function<Float, Float> f = makeAdder(1.23f);
System.out.println(f.apply(4.56f));
}
}
Disassembling the resulting byte code is interesting:
static java.util.function.Function<java.lang.Float, java.lang.Float> makeAdder(java.lang.Float);
descriptor: (Ljava/lang/Float;)Ljava/util/function/Function;
flags: (0x0008) ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokedynamic #7, 0 // InvokeDynamic #0:apply:(Ljava/lang/Float;)Ljava/util/function/Function;
6: areturn
LineNumberTable:
line 4: 0
Signature: #48 // (Ljava/lang/Float;)Ljava/util/function/Function<Ljava/lang/Float;Ljava/lang/Float;>;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: ldc #11 // float 1.23f
2: invokestatic #12 // Method java/lang/Float.valueOf:(F)Ljava/lang/Float;
5: invokestatic #18 // Method makeAdder:(Ljava/lang/Float;)Ljava/util/function/Function;
8: astore_1
9: getstatic #23 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_1
13: ldc #29 // float 4.56f
15: invokestatic #12 // Method java/lang/Float.valueOf:(F)Ljava/lang/Float;
18: invokeinterface #30, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
23: invokevirtual #35 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
26: return
LineNumberTable:
line 9: 0
line 10: 9
line 11: 26
private static java.lang.Float lambda$makeAdder$0(java.lang.Float, java.lang.Float);
descriptor: (Ljava/lang/Float;Ljava/lang/Float;)Ljava/lang/Float;
flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: invokevirtual #41 // Method java/lang/Float.floatValue:()F
4: aload_1
5: invokevirtual #41 // Method java/lang/Float.floatValue:()F
8: fadd
9: invokestatic #12 // Method java/lang/Float.valueOf:(F)Ljava/lang/Float;
12: areturn
LineNumberTable:
line 4: 0
Some of the above is clear, some less so. The part I'm most puzzled about right now is the implementation of the lambda function, lambda$makeAdder$0(java.lang.Float, java.lang.Float). That signature suggests the lambda has two parameters even though it was declared with just one.
Well, it's obvious what the extra one is for; it's for the value of a that was bound into the closure. So at one level, that answers the question of how Java closures are supplied with the values of bound variables: they are prepended to the parameter list.
But then, how does the ultimate caller know about this? The disassembled code for main looks isomorphic to the source code, i.e. completely innocent of knowledge about how closures are implemented. It seems to be supplying one argument to makeAdder, then the second argument to the lambda. In other words, supplying just one argument to the lambda.
How is the first argument also supplied to the lambda?
Does it anything to do with the final BootstrapMethods section of the disassembled code?
BootstrapMethods:
0: #56 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#63 (Ljava/lang/Object;)Ljava/lang/Object;
#64 REF_invokeStatic Adder.lambda$makeAdder$0:(Ljava/lang/Float;Ljava/lang/Float;)Ljava/lang/Float;
#67 (Ljava/lang/Float;)Ljava/lang/Float;
InnerClasses:
public static final #74= #70 of #72; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
The relevant aspect is in the output of javap but you didn't include it in your question. At the very end of the javap output: (make sure to run with javap -c -v!)
SourceFile: "Test.java"
BootstrapMethods:
0: #56 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#63 (Ljava/lang/Object;)Ljava/lang/Object;
#64 REF_invokeStatic Adder.lambda$makeAdder$0:(Ljava/lang/Float;Ljava/lang/Float;)Ljava/lang/Float;
#67 (Ljava/lang/Float;)Ljava/lang/Float;
InnerClasses:
public static final #74= #70 of #72; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
This... doesn't really come across as useful, but it is the underlying mechanism that makes all this work.
The relevant call is the invokedynamic bytecode instruction. invokedynamic is, well, dynamic: The first time invokedynamic is encountered the JVM will take a slow path and executes some code that can arbitrarily decide what this invocation is actually going to end up looking like. Any further executions of that same invokedynamic call no longer do that - they 'memoize'. So, an invokedynamic call can result in any kind of actual method invocation you want (here, it'll end up being a partial application of that lambda$makeAdder$0(float, float), of course), and is nevertheless fast.
javap's output isn't all that enlightening. A lot of the crucial moving parts of it all are actually in the java.lang.invoke.LambdaMetaFactory class which is a real class in the JVM whose source is part of the core JDK and thus open.
This baeldung tutorial on invokedynamic is probably something you want to go through top to bottom if you are interested in fully understanding how this works.
Here is a simple question about Java compile optimisation.
Is
final int CONSTANT_NUMBER="Foo Bar".length();
equal to
final int CONSTANT_NUMBER=7;
on compiling code or generally in performance aspect?
No the java compiler doesn't evaluate "Foo Bar".length() at compile time.
Consider these classes
public class ConstantCheck {
final int CONSTANT_NUMBER = "Foo Bar".length();
}
and
public class ConstantCheck {
final int CONSTANT_NUMBER = 7;
}
Using javap -v on the compiled .class file you can see, that the .length() call is kept:
The former results in
...
final int CONSTANT_NUMBER;
descriptor: I
flags: ACC_FINAL
public text.ConstantCheck();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String Foo Bar
7: invokevirtual #3 // Method java/lang/String.length:()I
10: putfield #4 // Field CONSTANT_NUMBER:I
13: return
...
the latter in
...
final int CONSTANT_NUMBER;
descriptor: I
flags: ACC_FINAL
ConstantValue: int 7
public text.ConstantCheck();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 7
7: putfield #2 // Field CONSTANT_NUMBER:I
10: return
....
In the first case the .length call is present
7: invokevirtual #3 // Method java/lang/String.length:()I
in the second case it's just a constant that is written to the field
5: bipush 7
7: putfield #2 // Field CONSTANT_NUMBER:I
From compiling, definitely second is going to be a little faster, as it first has a method call. However, machines these days are way too fast for this to be noticeable or significant.
For performance - Modern compilers should be smart to see that "Foo Bar" is a constant and should replace the expression to length. If however, you change the line to be a variable, then you may be able to fool the compiler to call the method every time, there by making 1st slightly faster if run in a big loop.
I tested this by making them run in a big loop and second method gave slightly better performance. Guess my compiler isn't smart enough to replace the method call with a constant.
So short answer , performance wise, direct int is better than method call on my machine, but it may differ on a different compiler.
Why does Java have an IINC bytecode instruction?
There is already an IADD bytecode instruction that can be used to accomplish the same.
So why does IINC exist?
Only the original designers of Java can answer why they made particular design decisions. However, we can speculate:
IINC does not let you do anything that can't already be accomplished by a ILOAD/SIPUSH/IADD/ISTORE combo. The difference is that IINC is a single instruction, which only takes 3 or 6 bytes, while the 4 instruction sequence is obviously longer. So IINC slightly reduces the size of bytecode that uses it.
Apart from that, early versions of Java used an interpreter, where every instruction has overhead during execution. In this case, using a single IINC instruction could be faster than the equivalent alternative bytecode sequence. Note that JITting has made this largely irrelevant, but IINC dates back to the original version of Java.
As already pointed out a single iinc instruction is shorter than the a iload, sipush, iadd, istore sequence. There is also evidence, that performing a common-case code size reduction was an important motivation.
There are specialized instructions for dealing with the first four local variables, e.g. aload_0 does the same as aload 0 and it will be used often for loading the this reference on the operand stack. There’s an ldc instruction being able to refer to one of the first 255 constant pool items whereas all of them could be handled by ldc_w, branch instructions use two bytes for offsets, so only overly large methods have to resort to goto_w, and iconst_n instructions for -1 to 5 exist despite these all could be handled by bipush which supports values which all also could all be handled by sipush, which could be superseded by ldc.
So asymmetric instructions are the norm. In typical applications, there are a lot of small methods with only a few local variables and smaller numbers are more common than larger numbers. iinc is a direct equivalent to stand-alone i++ or i+=smallConstantNumber expressions (applied to local variables) which often occur within loops. By being able to express common code idioms in more compact code without loosing the ability to express all code, you’ll get great savings in overall code size.
As also already pointed out, there is only a slight opportunity for faster execution in interpreted executions which is irrelevant for compiled/optimized code execution.
Looking at this table, there are a couple important differences.
iinc: increment local variable #index by signed byte const
iinc uses a register instead of the stack.
iinc can only increment by a signed byte value. If you want to add [-128,127] to an integer, then you could use iinc, but as soon as you want to add a number outside that range you would need to use isub, iadd, or multiple iinc instructions.
E1:
TL;DR
I was basically right, except that the limit is signed short values (16 bits [-32768,32767]). There's a wide bytecode instruction which modifies iinc (and a couple other instructions) to use 16 bit numbers instead of 8 bit numbers.
Additionally, consider adding two variables together. If one of the variables is not constant, the compiler will never be able to inline its value to bytecode, so it cannot use iinc; it will have to use iadd.
package SO37056714;
public class IntegerIncrementTest {
public static void main(String[] args) {
int i = 1;
i += 5;
}
}
I'm going to be experimenting with the above piece of code. As it is, is uses iinc, as expected.
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc 1, 5
5: return
}
i += 127 uses iinc as expected.
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc 1, 127
5: return
}
i += 128 does not use iinc anymore, but instead iinc_w:
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc_w 1, 128
8: return
}
i -= 601 also uses iinc_w:
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc_w 1, -601
8: return
}
The _w suffix refers to the wide bytecode, which allows for constants up to 16 bits ([-32768, 32767]).
If we try i += 32768, we will see what I predicted above:
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iload_1
3: ldc #16 // int 32768
5: iadd
6: istore_1
7: return
}
Additionally, consider the case where we are adding another variable to i (i += c). The compiler doesn't know if c is constant or not, so it cannot inline c's value to bytecode. It will use iadd for this case too:
int i = 1;
byte c = 3;
i += c;
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_1
8: return
}
This question already has answers here:
Performance difference between post- and pre- increment operators? [closed]
(2 answers)
Closed 7 years ago.
Is there in JAVA a performance difference between i++; and i--;
I'm not able to evaluate bytecode for this, and I think that simple benchmarks are not reliable because of dependence on a specific algorithm.
im not able to evaluate bytecode
Besides the duplicate which I linked and which shows some general things to consider when asking performance related questions:
Given the following sample code (System.err.println is essentially necessary so that the compiler does not optimize away the unused variable):
public class IncDec {
public static void main(String[] args) {
int i = 5;
i++;
System.err.println(i);
i--;
System.err.println(i);
}
}
Disassembled code:
> javap -c IncDec
Compiled from "IncDec.java"
public class IncDec {
public IncDec();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: istore_1 // int i = 5
2: iinc 1, 1 // i++
5: getstatic #16 // Field java/lang/System.err:Ljava/io/PrintStream;
8: iload_1
9: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
12: iinc 1, -1 // i--
15: getstatic #16 // Field java/lang/System.err:Ljava/io/PrintStream;
18: iload_1
19: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
22: return
}
So, no, there is no performance difference in this particular case on a bytecode level - both statements are compiled to the same bytecode instruction.
The JIT compiler could be free to do any additional optimization though.
In Java, there isn't a difference in speed between the two. At the most basic level, subtraction is simply addition. That is, taking the 2's complement and adding it.
I'm going to make some investigations about dividing large arrays/matrix computations among multiple threads. But I need to know the relative time complexity of Java basic operations.
For instance:
int a = 23498234;
int b = -34234;
int[] array = new int[10000];
int c = a + b; // 1
int c = array[234]; // 2
String 1 (summary of two integers) is 10+ times faster than string 2 (memory access)
or (i & 1) == 0 is 10+ faster than i % 2 == 0.
Question: Can you supppose time relations between next operations:
+, * and / operands (suppose on Integer type)
memory access
starting new thread
For performance timing, there are many confounding factors. Rather than try to get exact timings, it's better to understand what's going on and measure what you can.
The time utility will give you detailed stats on an executable, but keep in mind you're timing the JVM which is running the code, not just your code.
You might try the javap disassembler too -- ultimately you'll want to know how your individual operations break down into java bytecode, and the amount of time it takes to execute certain key bits.
Example source code:
public class T {
public static void main(String [] args) {
int x=2;
int y=3;
int z=x+y;
System.out.println(""+x);
}
}
Compiled, then disassembled:
$ javap -c T
Compiled from "T.java"
public class T {
public T();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_2
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: new #3 // class java/lang/StringBuilder
14: dup
15: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
18: ldc #5 // String
20: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: iload_1
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: return
}
Look at code #6 - that's where the actual addition is happening.
One thing you need to establish is how the operations you're interested in turn into bytecode.
Within the JVM itself, you can use System.getCurrentTimeMillis() as a way of timing, but it won't give you sub-ms resolution. You can also use System.nanoTime(); to get higher precision time, (in the sense that it's sub-ms resolution) but it's less accurate.