< prev index next >

src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp

Print this page
rev 53735 : AArch64 support for ValueTypes

*** 24,33 **** --- 24,34 ---- */ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" + #include "classfile/symbolTable.hpp" #include "code/debugInfoRec.hpp" #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp"
*** 287,296 **** --- 288,298 ---- assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); // fall through case T_OBJECT: case T_ARRAY: case T_ADDRESS: + case T_VALUETYPE: if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2;
*** 320,329 **** --- 322,414 ---- } return align_up(stk_args, 2); } + const uint SharedRuntime::java_return_convention_max_int = Argument::n_int_register_parameters_j+1; + const uint SharedRuntime::java_return_convention_max_float = Argument::n_float_register_parameters_j; + + int SharedRuntime::java_return_convention(const BasicType *sig_bt, + VMRegPair *regs, + int total_args_passed) { + + // Create the mapping between argument positions and + // registers. + static const Register INT_ArgReg[java_return_convention_max_int] = { + j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7 + }; + static const FloatRegister FP_ArgReg[java_return_convention_max_float] = { + j_farg0, j_farg1, j_farg2, j_farg3, + j_farg4, j_farg5, j_farg6, j_farg7 + }; + + + uint int_args = 0; + uint fp_args = 0; + + for (int i = 0; i < total_args_passed; i++) { + switch (sig_bt[i]) { + case T_BOOLEAN: + case T_CHAR: + case T_BYTE: + case T_SHORT: + case T_INT: + if (int_args < Argument::n_int_register_parameters_j) { + regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); + int_args ++; + } else { + // Should we have gurantee here? + return -1; + } + break; + case T_VOID: + // halves of T_LONG or T_DOUBLE + assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half"); + regs[i].set_bad(); + break; + case T_LONG: + assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); + // fall through + case T_OBJECT: + case T_ARRAY: + case T_ADDRESS: + // Should T_METADATA be added to java_calling_convention as well ? + case T_METADATA: + case T_VALUETYPE: + if (int_args < Argument::n_int_register_parameters_j) { + regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); + int_args ++; + } else { + return -1; + } + break; + case T_FLOAT: + if (fp_args < Argument::n_float_register_parameters_j) { + regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); + fp_args ++; + } else { + return -1; + } + break; + case T_DOUBLE: + assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); + if (fp_args < Argument::n_float_register_parameters_j) { + regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); + fp_args ++; + } else { + return -1; + } + break; + default: + ShouldNotReachHere(); + break; + } + } + + return int_args + fp_args; + } + // Patch the callers callsite with entry to compiled code if it exists. static void patch_callers_callsite(MacroAssembler *masm) { Label L; __ ldr(rscratch1, Address(rmethod, in_bytes(Method::code_offset()))); __ cbz(rscratch1, L);
*** 350,365 **** // restore sp __ leave(); __ bind(L); } static void gen_c2i_adapter(MacroAssembler *masm, ! int total_args_passed, ! int comp_args_on_stack, ! const BasicType *sig_bt, const VMRegPair *regs, Label& skip_fixup) { // Before we get into the guts of the C2I adapter, see if we should be here // at all. We've come from compiled code and are attempting to jump to the // interpreter, which means the caller made a static call to get here // (vcalls always get a compiled target if there is one). Check for a // compiled target. If there is one, we need to patch the caller's call. --- 435,461 ---- // restore sp __ leave(); __ bind(L); } + // For each value type argument, sig includes the list of fields of + // the value type. This utility function computes the number of + // arguments for the call if value types are passed by reference (the + // calling convention the interpreter expects). + static int compute_total_args_passed_int(const GrowableArray<SigEntry>* sig_extended) { + guarantee(ValueTypePassFieldsAsArgs == false, "Support for ValValueTypePassFieldsAsArgs = true is not implemented"); + + int total_args_passed = 0; + total_args_passed = sig_extended->length(); + return total_args_passed; + } + static void gen_c2i_adapter(MacroAssembler *masm, ! const GrowableArray<SigEntry>* sig_extended, const VMRegPair *regs, Label& skip_fixup) { + // Before we get into the guts of the C2I adapter, see if we should be here // at all. We've come from compiled code and are attempting to jump to the // interpreter, which means the caller made a static call to get here // (vcalls always get a compiled target if there is one). Check for a // compiled target. If there is one, we need to patch the caller's call.
*** 370,393 **** int words_pushed = 0; // Since all args are passed on the stack, total_args_passed * // Interpreter::stackElementSize is the space we need. int extraspace = total_args_passed * Interpreter::stackElementSize; __ mov(r13, sp); // stack is aligned, keep it that way ! extraspace = align_up(extraspace, 2*wordSize); ! if (extraspace) __ sub(sp, sp, extraspace); // Now write the args into the outgoing interpreter space for (int i = 0; i < total_args_passed; i++) { ! if (sig_bt[i] == T_VOID) { ! assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half"); continue; } // offset to start parameters int st_off = (total_args_passed - i - 1) * Interpreter::stackElementSize; --- 466,490 ---- int words_pushed = 0; // Since all args are passed on the stack, total_args_passed * // Interpreter::stackElementSize is the space we need. + int total_args_passed = compute_total_args_passed_int(sig_extended); int extraspace = total_args_passed * Interpreter::stackElementSize; __ mov(r13, sp); // stack is aligned, keep it that way ! extraspace = align_up(extraspace, 2 * wordSize); if (extraspace) __ sub(sp, sp, extraspace); // Now write the args into the outgoing interpreter space for (int i = 0; i < total_args_passed; i++) { ! BasicType bt = sig_extended->at(i)._bt; ! if (bt == T_VOID) { ! //DMS TODO assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half"); continue; } // offset to start parameters int st_off = (total_args_passed - i - 1) * Interpreter::stackElementSize;
*** 412,424 **** assert(!r_2->is_valid(), ""); continue; } if (r_1->is_stack()) { // memory to memory use rscratch1 ! int ld_off = (r_1->reg2stack() * VMRegImpl::stack_slot_size ! + extraspace ! + words_pushed * wordSize); if (!r_2->is_valid()) { // sign extend?? __ ldrw(rscratch1, Address(sp, ld_off)); __ str(rscratch1, Address(sp, st_off)); --- 509,519 ---- assert(!r_2->is_valid(), ""); continue; } if (r_1->is_stack()) { // memory to memory use rscratch1 ! int ld_off = (r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace + words_pushed * wordSize); if (!r_2->is_valid()) { // sign extend?? __ ldrw(rscratch1, Address(sp, ld_off)); __ str(rscratch1, Address(sp, st_off));
*** 426,436 **** __ ldr(rscratch1, Address(sp, ld_off)); // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG // T_DOUBLE and T_LONG use two slots in the interpreter ! if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { // ld_off == LSW, ld_off+wordSize == MSW // st_off == MSW, next_off == LSW __ str(rscratch1, Address(sp, next_off)); #ifdef ASSERT // Overwrite the unused slot with known junk --- 521,531 ---- __ ldr(rscratch1, Address(sp, ld_off)); // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG // T_DOUBLE and T_LONG use two slots in the interpreter ! if ( bt == T_LONG || bt == T_DOUBLE) { // ld_off == LSW, ld_off+wordSize == MSW // st_off == MSW, next_off == LSW __ str(rscratch1, Address(sp, next_off)); #ifdef ASSERT // Overwrite the unused slot with known junk
*** 448,458 **** // why not sign extend?? __ str(r, Address(sp, st_off)); } else { // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG // T_DOUBLE and T_LONG use two slots in the interpreter ! if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { // long/double in gpr #ifdef ASSERT // Overwrite the unused slot with known junk __ mov(rscratch1, 0xdeadffffdeadaaabul); __ str(rscratch1, Address(sp, st_off)); --- 543,553 ---- // why not sign extend?? __ str(r, Address(sp, st_off)); } else { // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG // T_DOUBLE and T_LONG use two slots in the interpreter ! if ( bt == T_LONG || bt == T_DOUBLE) { // long/double in gpr #ifdef ASSERT // Overwrite the unused slot with known junk __ mov(rscratch1, 0xdeadffffdeadaaabul); __ str(rscratch1, Address(sp, st_off));
*** 484,498 **** __ br(rscratch1); } void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, int comp_args_on_stack, ! const BasicType *sig_bt, const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled // code goes non-entrant while we get args ready. // In addition we use r13 to locate all the interpreter args because --- 579,593 ---- __ br(rscratch1); } void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, int comp_args_on_stack, ! const GrowableArray<SigEntry>* sig, const VMRegPair *regs) { + // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled // code goes non-entrant while we get args ready. // In addition we use r13 to locate all the interpreter args because
*** 569,591 **** __ str(zr, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); __ bind(no_alternative_target); } #endif // INCLUDE_JVMCI // Now generate the shuffle code. for (int i = 0; i < total_args_passed; i++) { ! if (sig_bt[i] == T_VOID) { ! assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half"); continue; } // Pick up 0, 1 or 2 words from SP+offset. assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "scrambled load targets?"); // Load in argument order going down. ! int ld_off = (total_args_passed - i - 1)*Interpreter::stackElementSize; // Point to interpreter value (vs. tag) int next_off = ld_off - Interpreter::stackElementSize; // // // --- 664,689 ---- __ str(zr, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); __ bind(no_alternative_target); } #endif // INCLUDE_JVMCI + int total_args_passed = compute_total_args_passed_int(sig); + // Now generate the shuffle code. for (int i = 0; i < total_args_passed; i++) { ! BasicType bt = sig->at(i)._bt; ! if (bt == T_VOID) { ! //DMS TODO: assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half"); continue; } // Pick up 0, 1 or 2 words from SP+offset. assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "scrambled load targets?"); // Load in argument order going down. ! int ld_off = (total_args_passed - i - 1) * Interpreter::stackElementSize; // Point to interpreter value (vs. tag) int next_off = ld_off - Interpreter::stackElementSize; // // //
*** 612,623 **** // // Interpreter local[n] == MSW, local[n+1] == LSW however locals // are accessed as negative so LSW is at LOW address // ld_off is MSW so get LSW ! const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)? ! next_off : ld_off; __ ldr(rscratch2, Address(esp, offset)); // st_off is LSW (i.e. reg.first()) __ str(rscratch2, Address(sp, st_off)); } } else if (r_1->is_Register()) { // Register argument --- 710,720 ---- // // Interpreter local[n] == MSW, local[n+1] == LSW however locals // are accessed as negative so LSW is at LOW address // ld_off is MSW so get LSW ! const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off; __ ldr(rscratch2, Address(esp, offset)); // st_off is LSW (i.e. reg.first()) __ str(rscratch2, Address(sp, st_off)); } } else if (r_1->is_Register()) { // Register argument
*** 628,639 **** // T_ADDRESS, T_LONG, or T_DOUBLE the interpreter allocates // two slots but only uses one for thr T_LONG or T_DOUBLE case // So we must adjust where to pick up the data to match the // interpreter. ! const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)? ! next_off : ld_off; // this can be a misaligned move __ ldr(r, Address(esp, offset)); } else { // sign extend and use a full word? --- 725,735 ---- // T_ADDRESS, T_LONG, or T_DOUBLE the interpreter allocates // two slots but only uses one for thr T_LONG or T_DOUBLE case // So we must adjust where to pick up the data to match the // interpreter. ! const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off; // this can be a misaligned move __ ldr(r, Address(esp, offset)); } else { // sign extend and use a full word?
*** 728,742 **** } #endif // --------------------------------------------------------------- AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, int comp_args_on_stack, ! const BasicType *sig_bt, ! const VMRegPair *regs, ! AdapterFingerPrint* fingerprint) { address i2c_entry = __ pc(); #ifdef BUILTIN_SIM char *name = NULL; AArch64Simulator *sim = NULL; size_t len = 65536; --- 824,841 ---- } #endif // --------------------------------------------------------------- AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, int comp_args_on_stack, ! int comp_args_on_stack_cc, ! const GrowableArray<SigEntry>* sig, ! const VMRegPair* regs, ! const GrowableArray<SigEntry>* sig_cc, ! const VMRegPair* regs_cc, ! AdapterFingerPrint* fingerprint, ! AdapterBlob*& new_adapter) { address i2c_entry = __ pc(); #ifdef BUILTIN_SIM char *name = NULL; AArch64Simulator *sim = NULL; size_t len = 65536;
*** 748,758 **** generate_i2c_adapter_name(name, total_args_passed, sig_bt); sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck); sim->notifyCompile(name, i2c_entry); } #endif ! gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); address c2i_unverified_entry = __ pc(); Label skip_fixup; Label ok; --- 847,857 ---- generate_i2c_adapter_name(name, total_args_passed, sig_bt); sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck); sim->notifyCompile(name, i2c_entry); } #endif ! gen_i2c_adapter(masm, comp_args_on_stack_cc, sig_cc, regs_cc); address c2i_unverified_entry = __ pc(); Label skip_fixup; Label ok;
*** 788,811 **** __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); __ block_comment("} c2i_unverified_entry"); } address c2i_entry = __ pc(); #ifdef BUILTIN_SIM if (name) { name[0] = 'c'; name[2] = 'i'; sim->notifyCompile(name, c2i_entry); FREE_C_HEAP_ARRAY(char, name, mtInternal); } #endif ! gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); __ flush(); ! return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, VMRegPair *regs2, --- 887,921 ---- __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); __ block_comment("} c2i_unverified_entry"); } address c2i_entry = __ pc(); + address c2i_value_entry = c2i_entry; #ifdef BUILTIN_SIM if (name) { name[0] = 'c'; name[2] = 'i'; sim->notifyCompile(name, c2i_entry); FREE_C_HEAP_ARRAY(char, name, mtInternal); } #endif ! gen_c2i_adapter(masm, sig_cc, regs_cc, skip_fixup); __ flush(); ! ! OopMapSet* oop_maps = NULL; ! ! int frame_complete = CodeOffsets::frame_never_safe; ! int frame_size_in_words = 0; ! ! // The c2i adapter might safepoint and trigger a GC. The caller must make sure that ! // the GC knows about the location of oop argument locations passed to the c2i adapter. ! bool caller_must_gc_arguments = (regs != regs_cc); ! new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps, caller_must_gc_arguments); ! return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_value_entry, c2i_unverified_entry); } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, VMRegPair *regs2,
*** 3192,3196 **** --- 3302,3404 ---- // Set exception blob _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); } #endif // COMPILER2_OR_JVMCI + + BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { + BufferBlob* buf = BufferBlob::create("value types pack/unpack", 16 * K); + CodeBuffer buffer(buf); + short buffer_locs[20]; + buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, + sizeof(buffer_locs)/sizeof(relocInfo)); + + MacroAssembler _masm(&buffer); + MacroAssembler* masm = &_masm; + + const Array<SigEntry>* sig_vk = vk->extended_sig(); + const Array<VMRegPair>* regs = vk->return_regs(); + + int pack_fields_off = __ offset(); + + int j = 1; + for (int i = 0; i < sig_vk->length(); i++) { + BasicType bt = sig_vk->at(i)._bt; + if (bt == T_VALUETYPE) { + continue; + } + if (bt == T_VOID) { + if (sig_vk->at(i-1)._bt == T_LONG || + sig_vk->at(i-1)._bt == T_DOUBLE) { + j++; + } + continue; + } + int off = sig_vk->at(i)._offset; + VMRegPair pair = regs->at(j); + VMReg r_1 = pair.first(); + VMReg r_2 = pair.second(); + Address to(r0, off); + if (bt == T_FLOAT) { + __ strs(r_1->as_FloatRegister(), to); + } else if (bt == T_DOUBLE) { + __ strd(r_1->as_FloatRegister(), to); + } else if (bt == T_OBJECT || bt == T_ARRAY) { + __ lea(r_1->as_Register(), to); + } else { + assert(is_java_primitive(bt), "unexpected basic type"); + size_t size_in_bytes = type2aelembytes(bt); + __ store_sized_value(to, r_1->as_Register(), size_in_bytes); + } + j++; + } + assert(j == regs->length(), "missed a field?"); + + __ ret(r0); + + int unpack_fields_off = __ offset(); + + j = 1; + for (int i = 0; i < sig_vk->length(); i++) { + BasicType bt = sig_vk->at(i)._bt; + if (bt == T_VALUETYPE) { + continue; + } + if (bt == T_VOID) { + if (sig_vk->at(i-1)._bt == T_LONG || + sig_vk->at(i-1)._bt == T_DOUBLE) { + j++; + } + continue; + } + int off = sig_vk->at(i)._offset; + VMRegPair pair = regs->at(j); + VMReg r_1 = pair.first(); + VMReg r_2 = pair.second(); + Address from(r0, off); + if (bt == T_FLOAT) { + __ ldrs(r_1->as_FloatRegister(), from); + } else if (bt == T_DOUBLE) { + __ ldrd(r_1->as_FloatRegister(), from); + } else if (bt == T_OBJECT || bt == T_ARRAY) { + __ lea(r_1->as_Register(), from); + } else { + assert(is_java_primitive(bt), "unexpected basic type"); + size_t size_in_bytes = type2aelembytes(bt); + __ load_sized_value(r_1->as_Register(), from, size_in_bytes, bt != T_CHAR && bt != T_BOOLEAN); + } + j++; + } + assert(j == regs->length(), "missed a field?"); + + // DMS CHECK: + if (StressValueTypeReturnedAsFields) { + __ load_klass(r0, r0); + __ orr(r0, r0, 1); + } + + __ ret(r0); + + __ flush(); + + return BufferedValueTypeBlob::create(&buffer, pack_fields_off, unpack_fields_off); + }
< prev index next >