[aarch64-port-dev ] Request review of fix for forward_exception_handler
Andrew Dinn
adinn at redhat.com
Fri Aug 9 09:38:58 PDT 2013
The following patch to StubGenerator::generate_forward_exception()
appears to be necessary to make exception forwarding work.
diff -r 0d89d051c190 src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
--- a/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Fri Aug 09 16:25:29
2013 +0100
+++ b/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Fri Aug 09 16:26:08
2013 +0100
@@ -504,6 +504,8 @@
__ call_VM_leaf(CAST_FROM_FN_PTR(address,
SharedRuntime::exception_handler_for_return_address),
rthread, c_rarg1);
+ // restore lr
+ __ mov(lr, r19);
// setup r0 & r3 & clear pending exception
__ mov(r3, r19);
__ mov(r19, r0);
The reason for this is less than obvious so I'll explain where it goes
wrong under C2 -- n.b. I think the fact that we are entering this
routine is itself an error but I am not thereby convinced that the patch
is unnecesaary.
I am seeing an exception return from a call to native method
java/security/AccessController.doPrivileged(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;
The native wrapper method checks for a pending exception when the native
code returns and punts to Stub::forward exception when it finds it is
not null. Before doing so it calls leave(). simcputrace shows it
executing this:
0x00007fffed1708d0: mov sp, xfp
0x00007fffed1708d4: ldp xfp, xlr, [sp],#16
0x00007fffed1708d8: ldr xscratch1, [xthread,#8]
0x00007fffed1708dc: cbnz xscratch1, 0x00007fffed1708e4
0x00007fffed1708e4: b Stub::forward exception ; {runtime_call}
So, when we enter the exception forwarding code we have no frame and the
return address into the caller of AccessController.doPrivileged is in
register lr.
The exception forwarder calls into the runtime to find the relevant
handler passing the thread and return address. It loads the exception
from the thread into r0, clearing the thread field and jumps to the
returned address
0x00007fffed07a5a0: ldr xscratch1, [xthread,#8]
0x00007fffed07a5a4: cbnz xscratch1, Stub::forward exception+120
0x0x7fffed07a618
0x00007fffed07a618: mov x1, xlr
0x00007fffed07a61c: mov x19, xlr
0x00007fffed07a620: mov x0, xthread
0x00007fffed07a624: stp xscratch1, xmethod, [sp,#-16]!
0x00007fffed07a628: movz xscratch1, #0xcc92
0x00007fffed07a62c: movk xscratch1, #0xf74b, lsl #16
0x00007fffed07a630: movk xscratch1, #0x7fff, lsl #32
0x00007fffed07a634: brx86 xscratch1, #3, #0, #1
0x00007fffed07a638: ldp xscratch1, xmethod, [sp],#16
0x00007fffed07a63c: mov x3, x19
0x00007fffed07a640: mov x19, x0
0x00007fffed07a644: ldr x0, [xthread,#8]
0x00007fffed07a648: str xzr, [xthread,#8]
0x00007fffed07a64c: cbnz x0, Stub::forward exception+288 0x0x7fffed07a6c0
0x00007fffed07a6c0: br x19
n.b. 0x7ffff74bcc92 is
SharedRuntime::exception_handler_for_return_address(JavaThread*,
unsigned char*).
Note that the exception forward handler saves xlr in x19 as well as
passing it into the native call via x1 so it can restore it into r3
after the call -- the handler expects an oop in r0 and a return address
in r3. On x86 this pair of moves is not needed because the call to leave
has still left the return address on the stack. Instead the x86 code
pops the top of the stack into rdx after the branch into the runtime.
The important thing to note here is that on AArch64 the brx86 call
trashes lr, leaving it containing the address after the brx86 call.
Whereas on x86 the return address passed in rdx is for the caller of the
native wrapper. This is the thing I believe to be wrong. Her eis how it
continues to calamity.
In the case I am looking at exception_handler_for_return_address uses
the value passed in x1 to identify the correct caller continuation (it
is at the end of method
java/net/URLClassLoader.findClass(Ljava/lang/String;)Ljava/lang/Class;)
0x00007fffed07a6c0: br x19
[Exception Handler]
0x00007fffed1b8750: b 0x00007fffed07f060 ; {runtime_call}
As you can see it immediately punts to the opto handling method
OptoRuntime::handle_exception_Java:
0x00007fffed07f060: stp xfp, xlr, [sp,#-16]!
0x00007fffed07f064: str x0, [xthread,#704]
0x00007fffed07f068: str x3, [xthread,#712]
0x00007fffed07f06c: adr xscratch1, 0x00007fffed07f06c
0x00007fffed07f070: str xscratch1, [xthread,#512]
0x00007fffed07f074: mov xscratch1, sp
0x00007fffed07f078: str xscratch1, [xthread,#504]
0x00007fffed07f07c: str xfp, [xthread,#520]
0x00007fffed07f080: mov x0, xthread
;; 0x7FFFF74B3018
0x00007fffed07f084: movz xscratch1, #0x3018
0x00007fffed07f088: movk xscratch1, #0xf74b, lsl #16
0x00007fffed07f08c: movk xscratch1, #0x7fff, lsl #32
0x00007fffed07f090: movk xscratch1, #0x0, lsl #48
0x00007fffed07f094: brx86 xscratch1, #1, #0, #1
OptoRuntime::handle_exception_Java sets up details of the current java
sp/fp/pc in the thread and then calls OptoRuntime::handle_exception_C.
Note that it creates a frame for itself at entry. Unfortunately, the
value in xlr is not the address in URLClassLoader.findClass where the
exception occurred but the address in forward_exception just following
the brx86. OptoRuntime::handle_exception_C looks 2 frames up to find
this address and asserts that it belongs to a nmethod. Only it doesn't!
So, my fix makes the exception forwarder code copy r19 back to xlr after
the brx86 call as well as copying it into r1.
I think this analysis is correct. It certainly allows the code to
continue further albeit only to the point where the uncaught exception
(an NPE) pops out of main. Can anyone see any problems with this?
regards,
Andrew Dinn
-----------
More information about the aarch64-port-dev
mailing list