void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { // At this point we know that marking is in progress. // If do_load() is true then we have to emit the // load of the previous value; otherwise it has already // been loaded into _pre_val. __ bind(_entry); assert(pre_val()->is_register(), "Precondition."); Register pre_val_reg = pre_val()->as_register(); if (do_load()) { ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); } if (__ is_in_wdisp16_range(_continuation)) { __ br_null(pre_val_reg, /*annul*/false, Assembler::pt, _continuation); } else { __ cmp(pre_val_reg, G0); __ brx(Assembler::equal, false, Assembler::pn, _continuation); } __ delayed()->nop(); __ call(Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id)); __ delayed()->mov(pre_val_reg, G4); __ br(Assembler::always, false, Assembler::pt, _continuation); __ delayed()->nop(); }
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); assert(addr()->is_register(), "Precondition."); assert(new_val()->is_register(), "Precondition."); Register addr_reg = addr()->as_pointer_register(); Register new_val_reg = new_val()->as_register(); if (__ is_in_wdisp16_range(_continuation)) { __ br_null(new_val_reg, /*annul*/false, Assembler::pt, _continuation); } else { __ cmp(new_val_reg, G0); __ brx(Assembler::equal, false, Assembler::pn, _continuation); } __ delayed()->nop(); __ call(Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id)); __ delayed()->mov(addr_reg, G4); __ br(Assembler::always, false, Assembler::pt, _continuation); __ delayed()->nop(); }
void G1UnsafeGetObjSATBBarrierStub::emit_code(LIR_Assembler* ce) { // At this point we know that offset == referent_offset. // // So we might have to emit: // if (src == null) goto continuation. // // and we definitely have to emit: // if (klass(src).reference_type == REF_NONE) goto continuation // if (!marking_active) goto continuation // if (pre_val == null) goto continuation // call pre_barrier(pre_val) // goto continuation // __ bind(_entry); assert(src()->is_register(), "sanity"); Register src_reg = src()->as_register(); if (gen_src_check()) { // The original src operand was not a constant. // Generate src == null? if (__ is_in_wdisp16_range(_continuation)) { __ br_null(src_reg, /*annul*/false, Assembler::pt, _continuation); } else { __ cmp(src_reg, G0); __ brx(Assembler::equal, false, Assembler::pt, _continuation); } __ delayed()->nop(); } // Generate src->_klass->_reference_type() == REF_NONE)? assert(tmp()->is_register(), "sanity"); Register tmp_reg = tmp()->as_register(); __ load_klass(src_reg, tmp_reg); Address ref_type_adr(tmp_reg, instanceKlass::reference_type_offset()); __ ldub(ref_type_adr, tmp_reg); // _reference_type field is of type ReferenceType (enum) assert(REF_NONE == 0, "check this code"); __ cmp_zero_and_br(Assembler::equal, tmp_reg, _continuation, /*annul*/false, Assembler::pt); __ delayed()->nop(); // Is marking active? assert(thread()->is_register(), "precondition"); Register thread_reg = thread()->as_pointer_register(); Address in_progress(thread_reg, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active())); if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { __ ld(in_progress, tmp_reg); } else { assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); __ ldsb(in_progress, tmp_reg); } __ cmp_zero_and_br(Assembler::equal, tmp_reg, _continuation, /*annul*/false, Assembler::pt); __ delayed()->nop(); // val == null? assert(val()->is_register(), "Precondition."); Register val_reg = val()->as_register(); if (__ is_in_wdisp16_range(_continuation)) { __ br_null(val_reg, /*annul*/false, Assembler::pt, _continuation); } else { __ cmp(val_reg, G0); __ brx(Assembler::equal, false, Assembler::pt, _continuation); } __ delayed()->nop(); __ call(Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id)); __ delayed()->mov(val_reg, G4); __ br(Assembler::always, false, Assembler::pt, _continuation); __ delayed()->nop(); }
int StubAssembler::call_RT(Register oop_result1, Register oop_result2, address entry_point, int number_of_arguments) { // for sparc changing the number of arguments doesn't change // anything about the frame size so we'll always lie and claim that // we are only passing 1 argument. set_num_rt_args(1); assert_not_delayed(); // bang stack before going to runtime set(-os::vm_page_size() + STACK_BIAS, G3_scratch); st(G0, SP, G3_scratch); // debugging support assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); set_last_Java_frame(SP, noreg); if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early save_thread(L7_thread_cache); // do the call call(entry_point, relocInfo::runtime_call_type); if (!VerifyThread) { delayed()->mov(G2_thread, O0); // pass thread as first argument } else { delayed()->nop(); // (thread already passed) } int call_offset = offset(); // offset of return address restore_thread(L7_thread_cache); reset_last_Java_frame(); // check for pending exceptions { Label L; Address exception_addr(G2_thread, Thread::pending_exception_offset()); ld_ptr(exception_addr, Gtemp); br_null(Gtemp, false, pt, L); delayed()->nop(); Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); st_ptr(G0, vm_result_addr); Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); st_ptr(G0, vm_result_addr_2); if (frame_size() == no_frame_size) { // we use O7 linkage so that forward_exception_entry has the issuing PC call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); delayed()->restore(); } else if (_stub_id == Runtime1::forward_exception_id) { should_not_reach_here(); } else { AddressLiteral exc(Runtime1::entry_for(Runtime1::forward_exception_id)); jump_to(exc, G4); delayed()->nop(); } bind(L); } // get oop result if there is one and reset the value in the thread if (oop_result1->is_valid()) { // get oop result if there is one and reset it in the thread get_vm_result (oop_result1); } else { // be a little paranoid and clear the result Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); st_ptr(G0, vm_result_addr); } if (oop_result2->is_valid()) { get_vm_result_2(oop_result2); } else { // be a little paranoid and clear the result Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); st_ptr(G0, vm_result_addr_2); } return call_offset; }
OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) { __ block_comment("generate_handle_exception"); // Save registers, if required. OopMapSet* oop_maps = new OopMapSet(); OopMap* oop_map = NULL; switch (id) { case forward_exception_id: // We're handling an exception in the context of a compiled frame. // The registers have been saved in the standard places. Perform // an exception lookup in the caller and dispatch to the handler // if found. Otherwise unwind and dispatch to the callers // exception handler. oop_map = generate_oop_map(sasm, true); // transfer the pending exception to the exception_oop __ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception); __ ld_ptr(Oexception, 0, G0); __ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset())); __ add(I7, frame::pc_return_offset, Oissuing_pc); break; case handle_exception_id: // At this point all registers MAY be live. oop_map = save_live_registers(sasm); __ mov(Oexception->after_save(), Oexception); __ mov(Oissuing_pc->after_save(), Oissuing_pc); break; case handle_exception_from_callee_id: // At this point all registers except exception oop (Oexception) // and exception pc (Oissuing_pc) are dead. oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); __ save_frame_c1(frame_size_in_bytes); __ mov(Oexception->after_save(), Oexception); __ mov(Oissuing_pc->after_save(), Oissuing_pc); break; default: ShouldNotReachHere(); } __ verify_not_null_oop(Oexception); #ifdef ASSERT // check that fields in JavaThread for exception oop and issuing pc are // empty before writing to them Label oop_empty; Register scratch = I7; // We can use I7 here because it's overwritten later anyway. __ ld_ptr(Address(G2_thread, JavaThread::exception_oop_offset()), scratch); __ br_null(scratch, false, Assembler::pt, oop_empty); __ delayed()->nop(); __ stop("exception oop already set"); __ bind(oop_empty); Label pc_empty; __ ld_ptr(Address(G2_thread, JavaThread::exception_pc_offset()), scratch); __ br_null(scratch, false, Assembler::pt, pc_empty); __ delayed()->nop(); __ stop("exception pc already set"); __ bind(pc_empty); #endif // save the exception and issuing pc in the thread __ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset())); __ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset())); // use the throwing pc as the return address to lookup (has bci & oop map) __ mov(Oissuing_pc, I7); __ sub(I7, frame::pc_return_offset, I7); int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); oop_maps->add_gc_map(call_offset, oop_map); // Note: if nmethod has been deoptimized then regardless of // whether it had a handler or not we will deoptimize // by entering the deopt blob with a pending exception. // Restore the registers that were saved at the beginning, remove // the frame and jump to the exception handler. switch (id) { case forward_exception_id: case handle_exception_id: restore_live_registers(sasm); __ jmp(O0, 0); __ delayed()->restore(); break; case handle_exception_from_callee_id: // Restore SP from L7 if the exception PC is a method handle call site. __ mov(O0, G5); // Save the target address. __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0); __ tst(L0); // Condition codes are preserved over the restore. __ restore(); __ jmp(G5, 0); // jump to the exception handler __ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required. break; default: ShouldNotReachHere(); } return oop_maps; }