Table of Contents | ||||
---|---|---|---|---|
|
Excerpt |
---|
JSR 292 introduces a flexible |
Sub-topics
Children Display | ||||||
---|---|---|---|---|---|---|
|
Method handle fundamentals
...
Here is an example of an adapter method, taken from an actual application:
No Format |
---|
LambdaForm(a0:D,a1:L,a2:L)=>{
t3:L=Invokers.getCallSiteTarget(a2:L);
t4:L=MethodHandle.invokeBasic(t3:L,a0:D,a1:L);
t4:L}
|
...
The body of the lambda form extracts a method handle target from the appendix using the subroutine Invokers.getCallSiteTarget
. The method handle is bound to t3
, and then immediately invoked on the two leading arguments, a0
adnd and a1
.
As may be seen by inspecting the Java code, getCallSiteTarget
expects to get a non-null CallSite
argument. If this were to fail, it would mean that the trusted Java code has a bug in it, since the trusted code is responsible for returning to the JVM a consistent pair of adapter and appendix.
The special non-public routine MethodHandle.invokeBasic
is an unchecked version of MethodHandle.invokeExact
. It differs in two ways from invokeExact
. First, it does not check that its callee has a type which (exactly) matches the types at the call site. (For better or worse, it will never throw WrongMethodTypeException
.)
Second, it allows loose typing of its arguments and return value, according to the basic type scheme used in the JSR 292 runtime. (See above.), it allows loose typing of its arguments and return value, according to the basic type scheme used in the JSR 292 runtime. (See above.)
Example execution sequence for invokedynamic
The target of the invokedynamic instruction's call site can be any method handle. In the simplest case it could be a direct method handle connecting the method containing the invokedynamic instruction to some other Java language method.
Here is an example of the sequence of events and stack frames that would make such a connection, from a method IndyUser.m1 to a target method LibraryCls.m2:
(indyUser.m1) | (LF adapter for indy) | (LF method for DMH) | LibraryCls.m2) |
---|---|---|---|
1.2D "3" > invokedynamic foo(DL)L | |||
1.2D "3" push CPC.appendix | |||
1.2D "3" (CS) > jump to CPC.method | |||
... | a0:1.2D a1:"3" a2: (CS) (CS) > invokestatic Invokers.getCallSiteTarget | ||
... | a0:1.2D a1:"3" a2: (CS) t3: (CS.target) (CS.target) 1.2D "3" > invokevirtual MH.invokeBasic(DL) | ||
... | ... | a0: (CS.target) a1:1.2D as:"3" (CS.target) > invokestatic DMH.internalMemberName | |
... | ... | a0: (CS.target) a1:1.2D as:"3" t3: (MN) 1.2D "3" (MN) > invokestatic MH.linkToStatic(DL+L)L | |
... | ... | 1.2D "3" (MN) > pop MN | |
... | ... | 1.2D "3" > jump to MN.method | |
... | ... | ... | 10:1.3D l1:"3" code for LibraryCls.m2(DL)L |
There are two internal stack frames, one for the adapter bound to the invokedynamic call site, and one which handles invocations for the target method handle.
The special methods internalMemberName and linkToStatic are explained on the page about direct method handles.
Method handle invocation
Internally to HotSpot (in rewriter.cpp
) method handle invocations are rewritten to use a special instruction called invokehandle
. This instruction in many ways is parallel to invokedynamic
. It resolves to an adapter method pointer and an appendix. The appendix (if not null) is pushed after the explicit arguments to invoke
or invokeExact
.
...
Here is an example:
No Format |
---|
LambdaForm(a0:L,a1:L,a2:L)=>{
t3:V=Invokers.checkExactType(a0:L,a2:L);
t4:L=MethodHandle.invokeBasic(a0:L,a1:L);
t4:L}
|
...
Here is an example:
No Format |
---|
LambdaForm(a0:L,a1:L,a2:I,a3:L)=>{
t4:L=Invokers.checkGenericType(a0:L,a3:L);
t5:I=MethodHandle.invokeBasic(t4:L,a3:L,a0:L,a1:L,a2:I);
t5:I}
|
...