static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) { assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words), "mismatch in calculation"); __ save_frame_c1(frame_size_in_bytes); // Record volatile registers as callee-save values in an OopMap so their save locations will be // propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for // deoptimization; see compiledVFrame::create_stack_value). The caller's I, L and O registers // are saved in register windows - I's and L's in the caller's frame and O's in the stub frame // (as the stub's I's) when the runtime routine called by the stub creates its frame. // OopMap frame sizes are in c2 stack slot sizes (sizeof(jint)) int i; for (i = 0; i < FrameMap::nof_cpu_regs; i++) { Register r = as_Register(i); if (r == G1 || r == G3 || r == G4 || r == G5) { int sp_offset = cpu_reg_save_offsets[i]; __ st_ptr(r, SP, (sp_offset * BytesPerWord) + STACK_BIAS); } } if (save_fpu_registers) { for (i = 0; i < FrameMap::nof_fpu_regs; i++) { FloatRegister r = as_FloatRegister(i); int sp_offset = fpu_reg_save_offsets[i]; __ stf(FloatRegisterImpl::S, r, SP, (sp_offset * BytesPerWord) + STACK_BIAS); } } return generate_oop_map(sasm, save_fpu_registers); }
static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words), "mismatch in calculation"); sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); OopMap* oop_map = new OopMap(frame_size_in_slots, 0); int i; for (i = 0; i < FrameMap::nof_cpu_regs; i++) { Register r = as_Register(i); if (r == G1 || r == G3 || r == G4 || r == G5) { int sp_offset = cpu_reg_save_offsets[i]; oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), r->as_VMReg()); } } if (save_fpu_registers) { for (i = 0; i < FrameMap::nof_fpu_regs; i++) { FloatRegister r = as_FloatRegister(i); int sp_offset = fpu_reg_save_offsets[i]; oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), r->as_VMReg()); } } return oop_map; }
// Reg2 unused. LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { assert(as_FloatRegister(reg2) == fnoreg, "Not used on this platform"); return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | (reg1 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); }
void InterpreterRuntime::SignatureHandlerGenerator::pass_double() { const Address src(from(), -(offset() + 1) * wordSize); #ifdef _WIN64 if (_num_args < Argument::n_float_register_parameters-1) { __ movlpd(as_FloatRegister(++_num_args), src); } else { __ movq(rax, src); __ movq(Address(to(), _stack_offset), rax); _stack_offset += wordSize; } #else if (_num_fp_args < 8) { __ movlpd(as_FloatRegister(_num_fp_args++), src); } else { __ movq(rax, src); __ movq(Address(to(), _stack_offset), rax); _stack_offset += wordSize; } #endif }
static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { Register r = as_Register(i); if (r == G1 || r == G3 || r == G4 || r == G5) { __ ld_ptr(SP, (cpu_reg_save_offsets[i] * BytesPerWord) + STACK_BIAS, r); } } if (restore_fpu_registers) { for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { FloatRegister r = as_FloatRegister(i); __ ldf(FloatRegisterImpl::S, SP, (fpu_reg_save_offsets[i] * BytesPerWord) + STACK_BIAS, r); } } }
// convert JVMCI register indices (as used in oop maps) to HotSpot registers VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { // JVMCI Registers are numbered as follows: // 0..31: Thirty-two General Purpose registers (CPU Registers) // 32..63: Thirty-two single precision float registers // 64..95: Thirty-two double precision float registers // 96..111: Sixteen quad precision float registers if (jvmci_reg < 32) { return as_Register(jvmci_reg)->as_VMReg(); } else { jint floatRegisterNumber; if(jvmci_reg < 64) { // Single precision floatRegisterNumber = jvmci_reg - 32; } else if(jvmci_reg < 96) { floatRegisterNumber = 2 * (jvmci_reg - 64); } else if(jvmci_reg < 112) { floatRegisterNumber = 4 * (jvmci_reg - 96); } else { JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg); } return as_FloatRegister(floatRegisterNumber)->as_VMReg(); } }
address AbstractInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); __ andr(esp, esp, -16); __ mov(c_rarg3, esp); // rmethod // rlocals // c_rarg3: first stack arg - wordSize // adjust sp __ sub(sp, c_rarg3, 18 * wordSize); __ str(lr, Address(__ pre(sp, -2 * wordSize))); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), rmethod, rlocals, c_rarg3); // r0: result handler // Stack layout: // rsp: return address <- sp // 1 garbage // 8 integer args (if static first is unused) // 1 float/double identifiers // 8 double args // stack args <- esp // garbage // expression stack bottom // bcp (NULL) // ... // Restore LR __ ldr(lr, Address(__ post(sp, 2 * wordSize))); // Do FP first so we can use c_rarg3 as temp __ ldrw(c_rarg3, Address(sp, 9 * wordSize)); // float/double identifiers for (int i = 0; i < Argument::n_float_register_parameters_c; i++) { const FloatRegister r = as_FloatRegister(i); Label d, done; __ tbnz(c_rarg3, i, d); __ ldrs(r, Address(sp, (10 + i) * wordSize)); __ b(done); __ bind(d); __ ldrd(r, Address(sp, (10 + i) * wordSize)); __ bind(done); } // c_rarg0 contains the result from the call of // InterpreterRuntime::slow_signature_handler so we don't touch it // here. It will be loaded with the JNIEnv* later. __ ldr(c_rarg1, Address(sp, 1 * wordSize)); for (int i = c_rarg2->encoding(); i <= c_rarg7->encoding(); i += 2) { Register rm = as_Register(i), rn = as_Register(i+1); __ ldp(rm, rn, Address(sp, i * wordSize)); } __ add(sp, sp, 18 * wordSize); __ ret(lr); return entry; }
// derived registers, offsets, and addresses FloatRegister successor() const { return as_FloatRegister(encoding() + 1); }
void InterpreterRuntime::SignatureHandlerGenerator::pass_prev(int slot_offset) { Argument jni_arg(_prev_jni_offset); Argument::Sig sig = _prev_sig; if (sig == Argument::no_sig) { return; } slot_offset += BytesPerWord; if (Argument::is_integral(sig)) { // Integral argument // Load either the output register or a very-local temp from the java stack // Bump java stack offset address if requested. const Register tmp = jni_arg.is_register() ? jni_arg.as_register() : GR2_SCRATCH; if (slot_offset == 0) { __ ld8(tmp, GR_I0); } else { __ ld8(tmp, GR_I0, -slot_offset); } if (Argument::is_4byte(sig)) { __ sxt4(tmp, tmp); } if (Argument::is_obj(sig)) { // Object, box if not null const PredicateRegister box = PR15_SCRATCH; __ cmp(box, PR0, 0, tmp, Assembler::notEqual); __ add(box, tmp, GR_I0, slot_offset); } if (!jni_arg.is_register()) { // Store into native memory parameter list __ add(GR3_SCRATCH, SP, jni_arg.jni_offset_in_frame()); __ st8(GR3_SCRATCH, tmp); } } else { // Floating point argument const FloatRegister tmp = jni_arg.is_register() ? as_FloatRegister(FR_I0->encoding() + _prev_float_reg_offset) : FR6; if (jni_arg.is_register()) { if (Argument::is_4byte(sig)) { // Single precision float if (slot_offset == 0) { __ ldfs(tmp, GR_I0); } else { __ ldfs(tmp, GR_I0, -slot_offset); } } else { // Double precision float if (slot_offset == 0) { __ ldfd(tmp, GR_I0); } else { __ ldfd(tmp, GR_I0, -slot_offset); } } } else { if (slot_offset == 0) { __ ld8(GR2_SCRATCH, GR_I0); } else { __ ld8(GR2_SCRATCH, GR_I0, -slot_offset); } __ add(GR3_SCRATCH, SP, jni_arg.jni_offset_in_frame()); __ st8(GR3_SCRATCH, GR2_SCRATCH); } } }
VMReg FrameMap::fpu_regname (int n) { // Return the OptoReg name for the fpu stack slot "n" // A spilled fpu stack slot comprises to two single-word OptoReg's. return as_FloatRegister(n)->as_VMReg(); }