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