The right locks for frame rewriting / Exceptions

Tom Rodriguez Thomas.Rodriguez at Sun.COM
Tue Oct 23 18:23:09 PDT 2007


> I guess I found that in sharedRuntime_i486.cpp -
> SharedRuntime::generate_deopt_blob(). I could see the
> "save_live_registers" and the work thereafter. I assume a safepoint
> is circumvented by calling the C function directly, without going
> through callVM, and JRT_ENTRY, which would cause a ThreadInVMfromJava
> to be allocated.

That's right.  That's what's generically called a leaf call and it's 
used in quite a few places like exception dispatch and for various 
helper functions which are implemented in C but aren't allowed to safepoint.

> Well thats exactly my problem :-)   I wanted to something like:
> 
> [..jumping here from a return of a interpreter / compiled frame...]
> otherThread = thisThread.otherThreadReference;
> if(otherThread != NULL){
>   adjustSP(-16);  // 2 words,  plus double word from XMM0
>   save_RAX_into_Stack();
>   save_RDX_into_Stack();
>   save_XMM0_into_Stack();
>   seen = Atomic::cmpxchg(1, otherThread.syncReq, 0);
>   if(seen == 0){
>      this.monitor.wait();  // here, the returnPC could be changed in 
> between...
>      restore_XMM0_from_Stack();
>      restore_RDX_from_Stack();
>      restore_RAX_from_Stack();
>   }
>   adjustSP(+16);
> }
> 
> What happens if I am having an object reference as return value, and the 
> GC decides to move just that object around, while my monitor is sleeping 
> ? As opposed to deopt, I cannot just run through this unsafe passage...

I'm a little confused by your code and I can't quite make out what you 
are trying to accomplish.  Is this piece of code part of every return or 
are you only jumping into this code sometimes?  Are you expecting all 
C++ code or some mix?  I think it would have to a mix.  You cannot do 
anything that blocks from within generated assembly.  You always have to 
call into C++ code in the runtime if you want to perform a blocking 
operation.

One important point to keep in mind is that you can rarely do tricky 
stuff the same way in both interpreted and compiled code.  In the 
interpeter if you want to call some special piece of code as part of the 
execution of a return bytecode then you don't really need to tell the GC 
anything special for it to find the return value since you should be at 
a return bytecode with the value on the top of stack.  You just need to 
flush the frame state and call into the VM and block.

For compiled code it's more tricky and you need something like the 
SafepointBlob to handle the state saving.  It not safe for the VM to 
stop on the actual return instruction of compiled code since this 
creates various unpleasant states we don't want to deal with.  The way 
this works for safepointing is that there's a poll right before the 
return and if we stop there then we pop that frame off and then call 
into the runtime so it looks like we're stopped at the call in the 
caller frame.  GC of the return value is handled specially since it 
doesn't really belong to any frame at this point.  Look at the code in 
safepoint.cpp in the method handle_polling_page_exception, in particular 
the code guarded by is_at_poll_return.

Are you expecting to check otherThreadReference for every return 
bytecode?  That seems very expensive...  Also because of inlining in 
compiled code you would only be checking it on return from the whole 
compile unless you modify the compiler to emit checks for every inlined 
return.

Can you give me the 10 second explanation of what you are trying to do?

> I am still a bit confused when it comes to that magic RegisterMap / GC 
> thing ... If I assume that my return value is a reference to a GC-able 
> object, and I am saving it in the stack, how do I tell this to the frame 
> walker? 

If you are referencing oops from generated code this is usually 
accomplished by describing it in an OopMap or by saving it in special 
fields in the JavaThread named _vm_result and _vm_result2. 
sharedRuntime_<arch> and c1_Runtime1_<arch> have examples of this. 
call_VM allows you to pass in registers which should be saved and 
restored for the GC in the special fields.  The complexity in your case 
is that if you use one stub for all return types you don't know 
statically whether the return value is an oop or not so it's impossible 
to know whether it's ok to store them as oops.  That's why the safepoint 
blob works the way it does.

tom



More information about the hotspot-runtime-dev mailing list