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.
Related
I have reading JVM documetion about invokevirtual.
I have see it will pop the entry form stack, and then no one push into stack.
Operand Stack
..., objectref, [arg1, [arg2 ...]] →
...
Is this only true if you call a method that has no return value?
————————————————————————————————
public static void main(String[] args){
System.out.println("Hello JVM!");
Integer integer = 1;
}
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello JVM!
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: invokestatic #5 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
12: astore_1
13: return
LineNumberTable:
line 6: 0
line 7: 8
line 8: 13
In the code above:
8: iconst_1 push the int into stack
9: invokestatic pop the int form stack // stack is empty now
12: astore_1
Does invokestatic put the return value on the stack when the method has a return value?
Well, technically not, but effectively yes.
invokestatic only pushed the return value on the operand stack if the invoked method is native (which in this case confusingly means non-Java code).
For non-native methods (i.e. all "normal" methods written in Java) that job is done by the *return opcodes, which will be the last instruction executed (assuming normal termination of the method). For example areturn:
If no exception is thrown, objectref is popped from the operand stack of the current frame [...] and pushed onto the operand stack of the frame of the invoker.
Since regular returns only happen via the *return opcodes a successful invokestatic of a non-void method is guaranteed to have the return value popped onto the operand stack.
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.
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.
I was curious about how the JVM works. Does the JVM acknowledge method accesibility rules like 'private' protected or is that only done at compile time?
For example, is it possible at around line37 to do some bytecode manipulation and call a protected method, say test3? Normally the compiler would not let me call that method because it is declared protected. But I was curious if that protected rule is enforced at runtime?
u.test1();
// Is it possible at runtime, to call 'test3' through bytecode manipulation
// #line37
package org.berlin.algo.basic.test;
public class RunX {
private String zzz = "rrrrr";
public void test1() {
// Note: I am intentionally use 'new' here as part of my test, not a
// good practice I know but allowed by the language.
Object x = new String("Test1 -----[1.1] " + zzz);
x = new String("Test1 --- [1.2]" + x.toString());
System.out.println(x);
this.test2();
this.test3();
}
/**
* Here, I noticed that the compiler removed my 'test2' code block.
* Does that always happen?
*/
private void test2() {
Object x = new String("Test2#line21--->>> [2.1]");
System.out.println(x);
}
protected void test3() {
Object x = new String("Test3#line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]");
x = new String("Test3#line28--->>> [3.2]");
System.out.println(x);
}
public static void main(final String [] args) {
System.out.println("Running");
RunX u = new RunX();
u.test1();
// Is it possible at runtime, to call 'test3' through bytecode manipulation
// #line37
System.out.println("Done");
}
} // End of the Class //
/*
JVM bytecode: javap -v RunX
Compiled from "RunX.java"
public class org.berlin.algo.basic.test.RunX extends java.lang.Object
SourceFile: "RunX.java"
minor version: 0
major version: 50
Constant pool:
const #1 = class #2; // org/berlin/algo/basic/test/RunX
const #2 = Asciz org/berlin/algo/basic/test/RunX;
...
...
const #84 = Asciz SourceFile;
const #85 = Asciz RunX.java;
{
public org.berlin.algo.basic.test.RunX();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #12; //String rrrrr
7: putfield #14; //Field zzz:Ljava/lang/String;
10: return
LineNumberTable:
line 3: 0
line 5: 4
line 3: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lorg/berlin/algo/basic/test/RunX;
public void test1();
Code:
Stack=5, Locals=2, Args_size=1
0: new #21; //class java/lang/String
3: dup
4: new #23; //class java/lang/StringBuilder
7: dup
8: ldc #25; //String Test1 -----[1.1]
10: invokespecial #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
13: aload_0
14: getfield #14; //Field zzz:Ljava/lang/String;
17: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
23: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
26: astore_1
27: new #21; //class java/lang/String
30: dup
31: new #23; //class java/lang/StringBuilder
34: dup
35: ldc #39; //String Test1 --- [1.2]
37: invokespecial #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
40: aload_1
41: invokevirtual #41; //Method java/lang/Object.toString:()Ljava/lang/String;
44: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
47: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
50: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
53: astore_1
54: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
57: aload_1
58: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
61: aload_0
62: invokespecial #54; //Method test2:()V
65: aload_0
66: invokevirtual #57; //Method test3:()V
69: return
LocalVariableTable:
Start Length Slot Name Signature
0 70 0 this Lorg/berlin/algo/basic/test/RunX;
27 43 1 x Ljava/lang/Object;
protected void test3();
Code:
Stack=3, Locals=2, Args_size=1
0: new #21; //class java/lang/String
3: dup
4: ldc #66; //String Test3#line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]
6: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: new #21; //class java/lang/String
13: dup
14: ldc #68; //String Test3#line28--->>> [3.2]
16: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
19: astore_1
20: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
LocalVariableTable:
Start Length Slot Name Signature
0 28 0 this Lorg/berlin/algo/basic/test/RunX;
10 18 1 x Ljava/lang/Object;
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=2, Args_size=1
0: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #72; //String Running
5: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: new #1; //class org/berlin/algo/basic/test/RunX
11: dup
12: invokespecial #76; //Method "<init>":()V
15: astore_1
16: aload_1
17: invokevirtual #77; //Method test1:()V
20: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #79; //String Done
25: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
LocalVariableTable:
Start Length Slot Name Signature
0 29 0 args [Ljava/lang/String;
16 13 1 u Lorg/berlin/algo/basic/test/RunX;
}
*/
To the JLS!
15.12.4 Runtime Evaluation of Method Invocation
At run time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. Third, the accessibility of the method to be invoked is checked. Fourth, the actual code for the method to be executed is located. Fifth, a new activation frame is created, synchronization is performed if necessary, and control is transferred to the method code.
The wording of the JLS indicates that the accessibility would be checked at runtime.
The JVM does acknowledge these. They can be overridden, by calling setAccessible(true) as Prashant Bhate does, but by default they are enforced. (See http://download.oracle.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible%28boolean%29.)
By the way, you write that "the compiler doesn't encode type method visibility rules into the Java bytecde file"; but it does. In addition to the above, it has to encode these, for a number of reasons. For example:
you can compile a class A that references class B even if you only have the compiled version of class B.
you can inspect a method's visibility via reflection (the getModifiers() method).
private methods aren't virtual -slash- can't be overridden by subclasses.
If you want to call this method from outside current class you could call private & protected methods using reflection.
Method m = RunX.class.getDeclaredMethod("test3");
m.setAccesible(true);
m.invoke(u);
however you can call this protected (and also private) method directly from main() without any issues.
Oli mentioned it rightly that ultimately you can do anything if you come to extent of byte code manipulation (if done correctly !!!).
Although I will like answer your question of accessibility honor at runtime in Java. If you have any doubts then please go ahead and use reflection to call the private method of one class from other class and you will get your answer. Java creates the function table of class at runtime when loading it and allow the refererence to the functions in limit of accessibility rule. However Java provides facility where you can call the private methods via reflection using setAccessible(true) on the method reference before invoking it.
Are there any optimizations, such as dead code elimination, involved when translating java source files to bytecodes?
The standard Java compilers do few optimizations on the emitted bytecodes. I think that the reasoning is that unoptimized bytecodes will be easier for the HotSpot JIT compiler to optimize.
The links that #Mitch Wheat provided in comments above (particularly the 2nd one) date from the days when HotSpot JIT was new technology.
While searching all source code optimization, i came across this question and though I am answering after long time this question asked.
After jdk1.7, String concatenation using plus [+] operator converted to StringBuilder append e.g
public static void main(String[] args) {
String s = new String("");
s = s+"new";
}
Converted to StringBuilder append as shown in bytecode
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // String
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: new #5 // class java/lang/StringBuilder
13: dup
14: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
17: aload_1
18: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: ldc #8 // String new
23: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
26: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: astore_1
30: return
LineNumberTable:
line 13: 0
line 14: 10
line 15: 30
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 args [Ljava/lang/String;
10 21 1 s Ljava/lang/String;
}