Skip to content

Commit 7817963

Browse files
author
Patric Hedlin
committed
8247691: [aarch64] Incorrect handling of VM exceptions in C1 deopt stub/traps
Reviewed-by: eosterlund, aph
1 parent 79904c1 commit 7817963

File tree

3 files changed

+34
-79
lines changed

3 files changed

+34
-79
lines changed

src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -553,84 +553,39 @@ OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) {
553553
__ bind(L);
554554
}
555555
#endif
556-
__ reset_last_Java_frame(true);
557-
__ maybe_isb();
558-
559-
// check for pending exceptions
560-
{ Label L;
561-
__ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
562-
__ cbz(rscratch1, L);
563-
// exception pending => remove activation and forward to exception handler
564-
565-
{ Label L1;
566-
__ cbnz(r0, L1); // have we deoptimized?
567-
__ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id)));
568-
__ bind(L1);
569-
}
570-
571-
// the deopt blob expects exceptions in the special fields of
572-
// JavaThread, so copy and clear pending exception.
573-
574-
// load and clear pending exception
575-
__ ldr(r0, Address(rthread, Thread::pending_exception_offset()));
576-
__ str(zr, Address(rthread, Thread::pending_exception_offset()));
577-
578-
// check that there is really a valid exception
579-
__ verify_not_null_oop(r0);
580556

581-
// load throwing pc: this is the return address of the stub
582-
__ mov(r3, lr);
557+
__ reset_last_Java_frame(true);
583558

584559
#ifdef ASSERT
585-
// check that fields in JavaThread for exception oop and issuing pc are empty
586-
Label oop_empty;
587-
__ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
588-
__ cbz(rscratch1, oop_empty);
589-
__ stop("exception oop must be empty");
590-
__ bind(oop_empty);
591-
592-
Label pc_empty;
593-
__ ldr(rscratch1, Address(rthread, JavaThread::exception_pc_offset()));
594-
__ cbz(rscratch1, pc_empty);
595-
__ stop("exception pc must be empty");
596-
__ bind(pc_empty);
597-
#endif
598-
599-
// store exception oop and throwing pc to JavaThread
600-
__ str(r0, Address(rthread, JavaThread::exception_oop_offset()));
601-
__ str(r3, Address(rthread, JavaThread::exception_pc_offset()));
602-
603-
restore_live_registers(sasm);
604-
605-
__ leave();
606-
607-
// Forward the exception directly to deopt blob. We can blow no
608-
// registers and must leave throwing pc on the stack. A patch may
609-
// have values live in registers so the entry point with the
610-
// exception in tls.
611-
__ far_jump(RuntimeAddress(deopt_blob->unpack_with_exception_in_tls()));
612-
613-
__ bind(L);
614-
}
615-
616-
617-
// Runtime will return true if the nmethod has been deoptimized during
618-
// the patching process. In that case we must do a deopt reexecute instead.
560+
// check that fields in JavaThread for exception oop and issuing pc are empty
561+
Label oop_empty;
562+
__ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
563+
__ cbz(rscratch1, oop_empty);
564+
__ stop("exception oop must be empty");
565+
__ bind(oop_empty);
619566

620-
Label cont;
567+
Label pc_empty;
568+
__ ldr(rscratch1, Address(rthread, JavaThread::exception_pc_offset()));
569+
__ cbz(rscratch1, pc_empty);
570+
__ stop("exception pc must be empty");
571+
__ bind(pc_empty);
572+
#endif
621573

622-
__ cbz(r0, cont); // have we deoptimized?
574+
// Runtime will return true if the nmethod has been deoptimized, this is the
575+
// expected scenario and anything else is an error. Note that we maintain a
576+
// check on the result purely as a defensive measure.
577+
Label no_deopt;
578+
__ cbz(r0, no_deopt); // Have we deoptimized?
623579

624-
// Will reexecute. Proper return address is already on the stack we just restore
625-
// registers, pop all of our frame but the return address and jump to the deopt blob
580+
// Perform a re-execute. The proper return address is already on the stack,
581+
// we just need to restore registers, pop all of our frame but the return
582+
// address and jump to the deopt blob.
626583
restore_live_registers(sasm);
627584
__ leave();
628585
__ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution()));
629586

630-
__ bind(cont);
631-
restore_live_registers(sasm);
632-
__ leave();
633-
__ ret(lr);
587+
__ bind(no_deopt);
588+
__ stop("deopt not performed");
634589

635590
return oop_maps;
636591
}

src/hotspot/share/c1/c1_Runtime1.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,32 +1255,32 @@ JRT_END
12551255

12561256
#else // DEOPTIMIZE_WHEN_PATCHING
12571257

1258-
JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_id ))
1259-
RegisterMap reg_map(thread, false);
1258+
void Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_id) {
1259+
NOT_PRODUCT(_patch_code_slowcase_cnt++);
12601260

1261-
NOT_PRODUCT(_patch_code_slowcase_cnt++;)
12621261
if (TracePatching) {
12631262
tty->print_cr("Deoptimizing because patch is needed");
12641263
}
12651264

1265+
RegisterMap reg_map(thread, false);
1266+
12661267
frame runtime_frame = thread->last_frame();
12671268
frame caller_frame = runtime_frame.sender(&reg_map);
1269+
assert(caller_frame.is_compiled_frame(), "Wrong frame type");
12681270

1269-
// It's possible the nmethod was invalidated in the last
1270-
// safepoint, but if it's still alive then make it not_entrant.
1271+
// Make sure the nmethod is invalidated, i.e. made not entrant.
12711272
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
12721273
if (nm != NULL) {
12731274
nm->make_not_entrant();
12741275
}
12751276

12761277
Deoptimization::deoptimize_frame(thread, caller_frame.id());
1277-
12781278
// Return to the now deoptimized frame.
1279-
JRT_END
1279+
postcond(caller_is_deopted());
1280+
}
12801281

12811282
#endif // DEOPTIMIZE_WHEN_PATCHING
12821283

1283-
//
12841284
// Entry point for compiled code. We want to patch a nmethod.
12851285
// We don't do a normal VM transition here because we want to
12861286
// know after the patching is complete and any safepoint(s) are taken
@@ -1345,7 +1345,7 @@ int Runtime1::move_appendix_patching(JavaThread* thread) {
13451345

13461346
return caller_is_deopted();
13471347
}
1348-
//
1348+
13491349
// Entry point for compiled code. We want to patch a nmethod.
13501350
// We don't do a normal VM transition here because we want to
13511351
// know after the patching is complete and any safepoint(s) are taken
@@ -1354,7 +1354,6 @@ int Runtime1::move_appendix_patching(JavaThread* thread) {
13541354
// completes we can check for deoptimization. This simplifies the
13551355
// assembly code in the cpu directories.
13561356
//
1357-
13581357
int Runtime1::access_field_patching(JavaThread* thread) {
13591358
//
13601359
// NOTE: we are still in Java
@@ -1372,7 +1371,7 @@ int Runtime1::access_field_patching(JavaThread* thread) {
13721371
// Return true if calling code is deoptimized
13731372

13741373
return caller_is_deopted();
1375-
JRT_END
1374+
}
13761375

13771376

13781377
JRT_LEAF(void, Runtime1::trace_block_entry(jint block_id))

src/hotspot/share/runtime/deoptimization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id,
16231623
while (fr.id() != id) {
16241624
fr = fr.sender(&reg_map);
16251625
}
1626+
assert(fr.is_compiled_frame(), "Wrong frame type");
16261627
deoptimize(thread, fr, reason);
16271628
}
16281629

0 commit comments

Comments
 (0)