Explanation on the anatomy of a JNI call and return

David Holmes david.holmes at oracle.com
Thu Jan 24 21:28:26 PST 2013


On 25/01/2013 4:01 AM, Fiterau Paul wrote:
> Hello guys. Sorry for the intrusion. Looked everywhere for this information, no luck. Browsed the code, very difficult to get an idea from it. 20 hours of search with no result. Also posted on StackOverflow, http://stackoverflow.com/questions/14497754/the-jni-call-its-effect-on-the-two-stacks, got no response. If someone could explain to me the evolution of the native and the java stack during a JNI call invocation, I'd be very appreciative.
>
> What I could find over the internet is this: http://weblogs.java.net/blog/mlam/archive/2006/12/a_tale_of_two_s.html . But this is not Hotspot. Plus, I'm doubtful on whether the information is accurate, since, in a native to native call, you'd get a recurse in executeJava, the interpreter (like shown bellow) and I suspect the interpreter does not have the lightest of stack frames.
> 	* native stack: executeJava ->  mNa ->  executeJava ->  mNb
>
> 	* Java stack:  mNa ->  mNb
> My question is, what's the anatomy of a java to native, native to native call and native to java in terms of stack frames. The purpose is, for a School project I have involving static analysis, where I should infer a very conservative upper bound for both the Java stack and the native stack. Right now there's a tool inferring the upper bound for the Java stack, but it doesn't take into account that some methods might already be compiled. I can use that measure in my inference.

Not a simple question to answer as the details are very complex.

The Java stack and the native stack are quite distinct and the details 
depend on whether you are running in interpreted code or compiled code. 
The Java stack is a logical stack of linked frames. The native stack 
frames need to be linked to the Java stack frames by some mechanism so 
that we can do stack walking.

When you hit an invocation bytecode for a native method you call into a 
stub routine that prepares the Java stack and native stack so that the 
native method can be called directly. This involves marshalling 
arguments and performing thread-state transitions to mark the thread as 
executing native code. When the native method returns it marshalls any 
return value, cleans up the stack and returns to the point where you can 
execute the next bytecode.

If your native method wants to call a Java method then it needs to use 
the JNI API, so that adds further marshalling etc and prepares the 
thread to recommence executing bytecodes.

> I'm especially interested in what would be the worst case with regards to stack consumption in a call chain. Let's say A calls B which calls C which calls D.
> Would it be more stack consuming if  B, C and D were all native or it's more consuming if they are interleaved (one native one not).
>  From what tests I made, it seems that having all of them native does seem to yield the highest consumption. On the Native stack and on the java stack.

I'm not completely clear on what you mean with the interleaving. Once 
you are in a native method then you can call another native method 
directly - not via JNI - so that yields minimum stack usage. Going back 
and forth between Java and native would consume the most stack as you 
have a lot of "management" code around the transitions.

There is some information here:

https://wikis.oracle.com/display/HotSpotInternals/Home

but unfortunately most of the CallingSequence information is missing.

David Holmes
------------

> Thanks for any input! And sorry for the not really dev oriented post.
> Paul.


More information about the hotspot-dev mailing list