--- old/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp 2015-11-09 17:31:07.708288828 +0100 +++ new/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp 2015-11-09 17:31:07.619288760 +0100 @@ -2384,6 +2384,7 @@ } #endif // ASSERT __ mov(c_rarg0, rthread); + __ mov(c_rarg1, rcpool); __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info))); __ blrt(rscratch1, 1, 0, 1); __ bind(retaddr); @@ -2397,6 +2398,7 @@ // Load UnrollBlock* into rdi __ mov(r5, r0); + __ ldrw(rcpool, Address(r5, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); Label noException; __ cmpw(rcpool, Deoptimization::Unpack_exception); // Was exception pending? __ br(Assembler::NE, noException); @@ -2609,6 +2611,7 @@ // n.b. 2 gp args, 0 fp args, integral return type __ mov(c_rarg0, rthread); + __ movw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap); __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); @@ -2628,6 +2631,16 @@ // move UnrollBlock* into r4 __ mov(r4, r0); +#ifdef ASSERT + { Label L; + __ ldrw(rscratch1, Address(r4, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); + __ cmpw(rscratch1, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ br(Assembler::EQ, L); + __ stop("SharedRuntime::generate_deopt_blob: last_Java_fp not cleared"); + __ bind(L); + } +#endif + // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) --- old/src/cpu/ppc/vm/sharedRuntime_ppc.cpp 2015-11-09 17:31:07.883288962 +0100 +++ new/src/cpu/ppc/vm/sharedRuntime_ppc.cpp 2015-11-09 17:31:07.795288895 +0100 @@ -2802,7 +2802,7 @@ __ set_last_Java_frame(R1_SP, noreg); // With EscapeAnalysis turned on, this call may safepoint! - __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), R16_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), R16_thread, exec_mode_reg); address calls_return_pc = __ last_calls_return_pc(); // Set an oopmap for the call site that describes all our saved registers. oop_maps->add_gc_map(calls_return_pc - start, map); @@ -2815,6 +2815,8 @@ // by save_volatile_registers(...). RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes); + // reload the exec mode from the UnrollBlock (it might have changed) + __ lwz(exec_mode_reg, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), unroll_block_reg); // In excp_deopt_mode, restore and clear exception oop which we // stored in the thread during exception entry above. The exception // oop will be the return value of this stub. @@ -2945,8 +2947,9 @@ __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); __ mr(klass_index_reg, R3); + __ li(R5, Deoptimization::Unpack_exception); __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), - R16_thread, klass_index_reg); + R16_thread, klass_index_reg, R5); // Set an oopmap for the call site. oop_maps->add_gc_map(gc_map_pc - start, map); @@ -2966,6 +2969,12 @@ // stack: (caller_of_deoptee, ...). +#ifdef ASSERT + __ lwz(R22_tmp2, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), unroll_block_reg); + __ cmpdi(CCR0, R22_tmp2, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ asm_assert_eq("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap", 0); +#endif + // Allocate new interpreter frame(s) and possibly a c2i adapter // frame. push_skeleton_frames(masm, false/*deopt*/, --- old/src/cpu/sparc/vm/sharedRuntime_sparc.cpp 2015-11-09 17:31:08.040289082 +0100 +++ new/src/cpu/sparc/vm/sharedRuntime_sparc.cpp 2015-11-09 17:31:07.949289013 +0100 @@ -3036,6 +3036,7 @@ __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode); __ mov(G2_thread, O0); + __ mov(L0deopt_mode, O2); __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); __ delayed()->nop(); oop_maps->add_gc_map( __ offset()-start, map->deep_copy()); @@ -3121,6 +3122,7 @@ // do the call by hand so we can get the oopmap __ mov(G2_thread, L7_thread_cache); + __ mov(L0deopt_mode, O1); __ call(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), relocInfo::runtime_call_type); __ delayed()->mov(G2_thread, O0); @@ -3146,6 +3148,7 @@ RegisterSaver::restore_result_registers(masm); + __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), G4deopt_mode); Label noException; __ cmp_and_br_short(G4deopt_mode, Deoptimization::Unpack_exception, Assembler::notEqual, Assembler::pt, noException); @@ -3269,7 +3272,8 @@ __ save_frame(0); __ set_last_Java_frame(SP, noreg); __ mov(I0, O2klass_index); - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), G2_thread, O2klass_index); + __ mov(Deoptimization::Unpack_uncommon_trap, O3); // exec mode + __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), G2_thread, O2klass_index, O3); __ reset_last_Java_frame(); __ mov(O0, O2UnrollBlock->after_save()); __ restore(); @@ -3278,6 +3282,15 @@ __ mov(O2UnrollBlock, O2UnrollBlock->after_save()); __ restore(); +#ifdef ASSERT + { Label L; + __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), O1); + __ cmp_and_br_short(O1, Deoptimization::Unpack_uncommon_trap, Assembler::equal, Assembler::pt, L); + __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + // Allocate new interpreter frame(s) and possible c2i adapter frame make_new_frames(masm, false); --- old/src/cpu/x86/vm/sharedRuntime_x86_32.cpp 2015-11-09 17:31:08.203289207 +0100 +++ new/src/cpu/x86/vm/sharedRuntime_x86_32.cpp 2015-11-09 17:31:08.114289139 +0100 @@ -2575,9 +2575,8 @@ // we are very short of registers Address unpack_kind(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()); - // retrieve the deopt kind from where we left it. - __ pop(rax); - __ movl(unpack_kind, rax); // save the unpack_kind value + // retrieve the deopt kind from the UnrollBlock. + __ movl(rax, unpack_kind); Label noException; __ cmpl(rax, Deoptimization::Unpack_exception); // Was exception pending? @@ -2787,11 +2786,12 @@ enum frame_layout { arg0_off, // thread sp + 0 // Arg location for arg1_off, // unloaded_class_index sp + 1 // calling C + arg2_off, // exec_mode sp + 2 // The frame sender code expects that rbp will be in the "natural" place and // will override any oopMap setting for it. We must therefore force the layout // so that it agrees with the frame sender code. - rbp_off, // callee saved register sp + 2 - return_off, // slot for return address sp + 3 + rbp_off, // callee saved register sp + 3 + return_off, // slot for return address sp + 4 framesize }; @@ -2823,6 +2823,7 @@ __ movptr(Address(rsp, arg0_off*wordSize), rdx); // argument already in ECX __ movl(Address(rsp, arg1_off*wordSize),rcx); + __ movl(Address(rsp, arg2_off*wordSize), Deoptimization::Unpack_uncommon_trap); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); // Set an oopmap for the call site @@ -2839,6 +2840,16 @@ // Load UnrollBlock into EDI __ movptr(rdi, rax); +#ifdef ASSERT + { Label L; + __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()), + (int32_t)Deoptimization::Unpack_uncommon_trap); + __ jcc(Assembler::equal, L); + __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) --- old/src/cpu/x86/vm/sharedRuntime_x86_64.cpp 2015-11-09 17:31:08.357289326 +0100 +++ new/src/cpu/x86/vm/sharedRuntime_x86_64.cpp 2015-11-09 17:31:08.268289257 +0100 @@ -2819,6 +2819,7 @@ __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); __ mov(c_rarg0, r15_thread); + __ movl(c_rarg2, r14); // exec mode __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); @@ -2905,6 +2906,7 @@ } #endif // ASSERT __ mov(c_rarg0, r15_thread); + __ movl(c_rarg1, r14); // exec_mode __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info))); // Need to have an oopmap that tells fetch_unroll_info where to @@ -2922,6 +2924,7 @@ // Load UnrollBlock* into rdi __ mov(rdi, rax); + __ movl(r14, Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); Label noException; __ cmpl(r14, Deoptimization::Unpack_exception); // Was exception pending? __ jcc(Assembler::notEqual, noException); @@ -3140,6 +3143,7 @@ // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); __ mov(c_rarg0, r15_thread); + __ movl(c_rarg2, Deoptimization::Unpack_uncommon_trap); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); // Set an oopmap for the call site @@ -3155,6 +3159,16 @@ // Load UnrollBlock* into rdi __ mov(rdi, rax); +#ifdef ASSERT + { Label L; + __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()), + (int32_t)Deoptimization::Unpack_uncommon_trap); + __ jcc(Assembler::equal, L); + __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) --- old/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java 2015-11-09 17:31:08.515289447 +0100 +++ new/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java 2015-11-09 17:31:08.428289380 +0100 @@ -1677,6 +1677,7 @@ @HotSpotVMField(name = "Deoptimization::UnrollBlock::_caller_adjustment", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockCallerAdjustmentOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_number_of_frames", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockNumberOfFramesOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_total_frame_sizes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockTotalFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_unpack_kind", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockUnpackKindOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_sizes", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFrameSizesOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_pcs", type = "address*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFramePcsOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_initial_info", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockInitialInfoOffset; --- old/src/share/vm/runtime/deoptimization.cpp 2015-11-09 17:31:08.661289558 +0100 +++ new/src/share/vm/runtime/deoptimization.cpp 2015-11-09 17:31:08.572289490 +0100 @@ -68,7 +68,8 @@ int number_of_frames, intptr_t* frame_sizes, address* frame_pcs, - BasicType return_type) { + BasicType return_type, + int exec_mode) { _size_of_deoptimized_frame = size_of_deoptimized_frame; _caller_adjustment = caller_adjustment; _caller_actual_parameters = caller_actual_parameters; @@ -80,10 +81,11 @@ _initial_info = 0; // PD (x86 only) _counter_temp = 0; - _unpack_kind = 0; + _unpack_kind = exec_mode; _sender_sp_temp = 0; _total_frame_sizes = size_of_frames(); + assert(exec_mode >= 0 && exec_mode < Unpack_LIMIT, "Unexpected exec_mode"); } @@ -128,7 +130,7 @@ // ResetNoHandleMark and HandleMark were removed from it. The actual reallocation // of previously eliminated objects occurs in realloc_objects, which is // called from the method fetch_unroll_info_helper below. -JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(JavaThread* thread)) +JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(JavaThread* thread, int exec_mode)) // It is actually ok to allocate handles in a leaf method. It causes no safepoints, // but makes the entry a little slower. There is however a little dance we have to // do in debug mode to get around the NoHandleMark code in the JRT_LEAF macro @@ -142,12 +144,12 @@ } thread->inc_in_deopt_handler(); - return fetch_unroll_info_helper(thread); + return fetch_unroll_info_helper(thread, exec_mode); JRT_END // This is factored, since it is both called from a JRT_LEAF (deoptimization) and a JRT_ENTRY (uncommon_trap) -Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread) { +Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread, int exec_mode) { // Note: there is a safepoint safety issue here. No matter whether we enter // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once @@ -186,6 +188,19 @@ assert(vf->is_compiled_frame(), "Wrong frame type"); chunk->push(compiledVFrame::cast(vf)); + ScopeDesc* trap_scope = chunk->at(0)->scope(); + Handle exceptionObject; + if (trap_scope->rethrow_exception()) { + if (PrintDeoptimizationDetails) { + tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_scope->method()->method_holder()->name()->as_C_string(), trap_scope->method()->name()->as_C_string(), trap_scope->bci()); + } + GrowableArray* expressions = trap_scope->expressions(); + guarantee(expressions != NULL && expressions->length() > 0, "must have exception to throw"); + ScopeValue* topOfStack = expressions->top(); + exceptionObject = StackValue::create_stack_value(&deoptee, &map, topOfStack)->get_obj(); + assert(exceptionObject() != NULL, "exception oop can not be null"); + } + bool realloc_failures = false; #if defined(COMPILER2) || INCLUDE_JVMCI @@ -474,13 +489,21 @@ assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc"); #endif // SHARK +#ifdef INCLUDE_JVMCI + if (exceptionObject() != NULL) { + thread->set_exception_oop(exceptionObject()); + exec_mode = Unpack_exception; + } +#endif + UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord, caller_adjustment * BytesPerWord, caller_was_method_handle ? 0 : callee_parameters, number_of_frames, frame_sizes, frame_pcs, - return_type); + return_type, + exec_mode); // On some platforms, we need a way to pass some platform dependent // information to the unpacking code so the skeletal frames come out // correct (initial fp value, unextended sp, ...) @@ -1495,18 +1518,6 @@ #endif Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); - - if (trap_scope->rethrow_exception()) { - if (PrintDeoptimizationDetails) { - tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_method->method_holder()->name()->as_C_string(), trap_method->name()->as_C_string(), trap_bci); - } - GrowableArray* expressions = trap_scope->expressions(); - guarantee(expressions != NULL, "must have exception to throw"); - ScopeValue* topOfStack = expressions->top(); - Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj(); - THREAD->set_pending_exception(topOfStackObj(), NULL, 0); - } - // Record this event in the histogram. gather_statistics(reason, action, trap_bc); @@ -1985,7 +1996,7 @@ ignore_maybe_prior_recompile); } -Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) { +Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request, jint exec_mode) { if (TraceDeoptimization) { tty->print("Uncommon trap "); } @@ -1994,7 +2005,7 @@ // This enters VM and may safepoint uncommon_trap_inner(thread, trap_request); } - return fetch_unroll_info_helper(thread); + return fetch_unroll_info_helper(thread, exec_mode); } // Local derived constants. --- old/src/share/vm/runtime/deoptimization.hpp 2015-11-09 17:31:08.816289677 +0100 +++ new/src/share/vm/runtime/deoptimization.hpp 2015-11-09 17:31:08.727289609 +0100 @@ -123,7 +123,8 @@ Unpack_deopt = 0, // normal deoptimization, use pc computed in unpack_vframe_on_stack Unpack_exception = 1, // exception is pending Unpack_uncommon_trap = 2, // redo last byte code (C2 only) - Unpack_reexecute = 3 // reexecute bytecode (C1 only) + Unpack_reexecute = 3, // reexecute bytecode (C1 only) + Unpack_LIMIT = 4 }; // Checks all compiled methods. Invalid methods are deleted and @@ -179,13 +180,13 @@ intptr_t _initial_info; // Platform dependent data for the sender frame (was FP on x86) int _caller_actual_parameters; // The number of actual arguments at the // interpreted caller of the deoptimized frame + int _unpack_kind; // exec_mode that can be changed during fetch_unroll_info // The following fields are used as temps during the unpacking phase // (which is tight on registers, especially on x86). They really ought // to be PD variables but that involves moving this class into its own // file to use the pd include mechanism. Maybe in a later cleanup ... intptr_t _counter_temp; // SHOULD BE PD VARIABLE (x86 frame count temp) - intptr_t _unpack_kind; // SHOULD BE PD VARIABLE (x86 unpack kind) intptr_t _sender_sp_temp; // SHOULD BE PD VARIABLE (x86 sender_sp) public: // Constructor @@ -195,7 +196,8 @@ int number_of_frames, intptr_t* frame_sizes, address* frames_pcs, - BasicType return_type); + BasicType return_type, + int unpack_kind); ~UnrollBlock(); // Returns where a register is located. @@ -205,6 +207,7 @@ intptr_t* frame_sizes() const { return _frame_sizes; } int number_of_frames() const { return _number_of_frames; } address* frame_pcs() const { return _frame_pcs ; } + int unpack_kind() const { return _unpack_kind; } // Returns the total size of frames int size_of_frames() const; @@ -237,7 +240,7 @@ // deoptimized frame. // @argument thread. Thread where stub_frame resides. // @see OptoRuntime::deoptimization_fetch_unroll_info_C - static UnrollBlock* fetch_unroll_info(JavaThread* thread); + static UnrollBlock* fetch_unroll_info(JavaThread* thread, int exec_mode); //** Unpacks vframeArray onto execution stack // Called by assembly stub after execution has returned to @@ -262,7 +265,7 @@ //** Performs an uncommon trap for compiled code. // The top most compiler frame is converted into interpreter frames - static UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); + static UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode); // Helper routine that enters the VM and may block static void uncommon_trap_inner(JavaThread* thread, jint unloaded_class_index); @@ -423,7 +426,7 @@ static void load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS); static void load_class_by_index(constantPoolHandle constant_pool, int index); - static UnrollBlock* fetch_unroll_info_helper(JavaThread* thread); + static UnrollBlock* fetch_unroll_info_helper(JavaThread* thread, int exec_mode); static DeoptAction _unloaded_action; // == Action_reinterpret; static const char* _trap_reason_name[]; --- old/src/share/vm/runtime/vmStructs.cpp 2015-11-09 17:31:08.956289784 +0100 +++ new/src/share/vm/runtime/vmStructs.cpp 2015-11-09 17:31:08.865289715 +0100 @@ -968,6 +968,7 @@ nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ nonstatic_field(Deoptimization::UnrollBlock, _register_block, intptr_t*) \ --- old/src/share/vm/shark/sharkRuntime.cpp 2015-11-09 17:31:09.116289907 +0100 +++ new/src/share/vm/shark/sharkRuntime.cpp 2015-11-09 17:31:09.030289841 +0100 @@ -213,8 +213,9 @@ // Initiate the trap thread->set_last_Java_frame(); Deoptimization::UnrollBlock *urb = - Deoptimization::uncommon_trap(thread, trap_request); + Deoptimization::uncommon_trap(thread, trap_request, Deoptimization::Unpack_uncommon_trap); thread->reset_last_Java_frame(); + assert(urb->unpack_kind() == Deoptimization::Unpack_uncommon_trap, "expected Unpack_uncommon_trap"); // Pop our dummy frame and the frame being deoptimized thread->pop_zero_frame();