address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) { assert(vtable_index >= 0, "must be positive"); VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL; if (s == NULL) { if (is_vtable_stub) { s = create_vtable_stub(vtable_index); } else { s = create_itable_stub(vtable_index); } // Creation of vtable or itable can fail if there is not enough free space in the code cache. if (s == NULL) { return NULL; } enter(is_vtable_stub, vtable_index, s); if (PrintAdapterHandlers) { tty->print_cr("Decoding VtableStub %s[%d]@%d", is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location()); Disassembler::decode(s->code_begin(), s->code_end()); } // Notify JVMTI about this stub. The event will be recorded by the enclosing // JvmtiDynamicCodeEventCollector and posted when this thread has released // all locks. if (JvmtiExport::should_post_dynamic_code_generated()) { JvmtiExport::post_dynamic_code_generated_while_holding_locks(is_vtable_stub? "vtable stub": "itable stub", s->code_begin(), s->code_end()); } } return s->entry_point(); }
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new(code_length) VtableStub(true, vtable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); assert(VtableStub::receiver_location() == R0->as_VMReg(), "receiver expected in R0"); const Register tmp = Rtemp; // Rtemp OK, should be free at call sites address npe_addr = __ pc(); __ load_klass(tmp, R0); { int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index * vtableEntry::size_in_bytes(); int method_offset = vtableEntry::method_offset_in_bytes() + entry_offset; assert ((method_offset & (wordSize - 1)) == 0, "offset should be aligned"); int offset_mask = AARCH64_ONLY(0xfff << LogBytesPerWord) NOT_AARCH64(0xfff); if (method_offset & ~offset_mask) { __ add(tmp, tmp, method_offset & ~offset_mask); } __ ldr(Rmethod, Address(tmp, method_offset & offset_mask)); } address ame_addr = __ pc(); #ifdef AARCH64 __ ldr(tmp, Address(Rmethod, Method::from_compiled_offset())); __ br(tmp); #else __ ldr(PC, Address(Rmethod, Method::from_compiled_offset())); #endif // AARCH64 masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", vtable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // FIXME ARM: need correct 'slop' - below is x86 code // shut the door on sizing bugs //int slop = 8; // 32-bit offset is this much larger than a 13-bit one //assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); s->set_exception_points(npe_addr, ame_addr); return s; }
address VtableStubs::create_stub(bool is_vtable_stub, int vtable_index, methodOop method) { assert(vtable_index >= 0, "must be positive"); VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL; if (s == NULL) { if (is_vtable_stub) { s = create_vtable_stub(vtable_index); } else { s = create_itable_stub(vtable_index); } enter(is_vtable_stub, vtable_index, s); if (PrintAdapterHandlers) { tty->print_cr("Decoding VtableStub %s[%d]@%d", is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location()); Disassembler::decode(s->code_begin(), s->code_end()); } } return s->entry_point(); }
// These stubs are used by the compiler only. // Argument registers, which must be preserved: // rcx - receiver (always first argument) // rdx - second argument (if any) // Other registers that might be usable: // rax - inline cache register (is interface for itable stub) // rbx - method (used when calling out to interpreter) // Available now, but may become callee-save at some point: // rsi, rdi // Note that rax and rdx are also used for return values. // VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int i486_code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new(i486_code_length) VtableStub(true, vtable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), i486_code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); } #endif /* PRODUCT */ // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx"); // get receiver klass address npe_addr = __ pc(); __ movptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes())); #ifndef PRODUCT if (DebugVtables) { Label L; // check offset vs vtable length __ cmpl(Address(rax, InstanceKlass::vtable_length_offset()*wordSize), vtable_index*vtableEntry::size()); __ jcc(Assembler::greater, L); __ movl(rbx, vtable_index); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), rcx, rbx); __ bind(L); } #endif // PRODUCT const Register method = rbx; // load Method* and target address __ lookup_virtual_method(rax, vtable_index, method); if (DebugVtables) { Label L; __ cmpptr(method, (int32_t)NULL_WORD); __ jcc(Assembler::equal, L); __ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD); __ jcc(Assembler::notZero, L); __ stop("Vtable entry is NULL"); __ bind(L); } // rax,: receiver klass // method (rbx): Method* // rcx: receiver address ame_addr = __ pc(); __ jmp( Address(method, Method::from_compiled_offset())); masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d", vtable_index, s->entry_point(), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 3; // 32-bit offset is this much larger than an 8-bit one assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { // Note well: pd_code_size_limit is the absolute minimum we can get away with. If you // add code here, bump the code stub size returned by pd_code_size_limit! const int i486_code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(i486_code_length) VtableStub(false, itable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), i486_code_length); MacroAssembler* masm = new MacroAssembler(&cb); // Entry arguments: // rax,: Interface // rcx: Receiver #ifndef PRODUCT if (CountCompiledCalls) { __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); } #endif /* PRODUCT */ // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx"); // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); __ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes())); // Most registers are in use; we'll use rax, rbx, rsi, rdi // (If we need to make rsi, rdi callee-save, do a push/pop here.) const Register method = rbx; Label throw_icce; // Get Method* and entrypoint for compiler __ lookup_interface_method(// inputs: rec. class, interface, itable index rsi, rax, itable_index, // outputs: method, scan temp. reg method, rdi, throw_icce); // method (rbx): Method* // rcx: receiver #ifdef ASSERT if (DebugVtables) { Label L1; __ cmpptr(method, (int32_t)NULL_WORD); __ jcc(Assembler::equal, L1); __ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD); __ jcc(Assembler::notZero, L1); __ stop("Method* is null"); __ bind(L1); } #endif // ASSERT address ame_addr = __ pc(); __ jmp(Address(method, Method::from_compiled_offset())); __ bind(throw_icce); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", itable_index, s->entry_point(), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 3; // 32-bit offset is this much larger than an 8-bit one assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { // Note well: pd_code_size_limit is the absolute minimum we can get // away with. If you add code here, bump the code stub size // returned by pd_code_size_limit! const int amd64_code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(amd64_code_length) VtableStub(false, itable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), amd64_code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); } #endif // Entry arguments: // rax: Interface // j_rarg0: Receiver // Free registers (non-args) are rax (interface), rbx // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); // Most registers are in use; we'll use rax, rbx, r10, r11 // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) __ load_klass(r10, j_rarg0); // If we take a trap while this arg is on the stack we will not // be able to walk the stack properly. This is not an issue except // when there are mistakes in this assembly code that could generate // a spurious fault. Ask me how I know... const Register method = rbx; Label throw_icce; // Get methodOop and entrypoint for compiler __ lookup_interface_method(// inputs: rec. class, interface, itable index r10, rax, itable_index, // outputs: method, scan temp. reg method, r11, throw_icce); // method (rbx): methodOop // j_rarg0: receiver #ifdef ASSERT if (DebugVtables) { Label L2; __ cmpptr(method, (int32_t)NULL_WORD); __ jcc(Assembler::equal, L2); __ cmpptr(Address(method, methodOopDesc::from_compiled_offset()), (int32_t)NULL_WORD); __ jcc(Assembler::notZero, L2); __ stop("compiler entrypoint is null"); __ bind(L2); } #endif // ASSERT // rbx: methodOop // j_rarg0: receiver address ame_addr = __ pc(); __ jmp(Address(method, methodOopDesc::from_compiled_offset())); __ bind(throw_icce); __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", itable_index, s->entry_point(), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 3; // 32-bit offset is this much larger than an 8-bit one assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); s->set_exception_points(npe_addr, ame_addr); return s; }
// Used by compiler only; may use only caller saved, non-argument registers // NOTE: %%%% if any change is made to this stub make sure that the function // pd_code_size_limit is changed to ensure the correct size for VtableStub VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int sparc_code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new(sparc_code_length) VtableStub(true, vtable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), sparc_code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), G5, G3_scratch); } #endif /* PRODUCT */ assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); // get receiver klass address npe_addr = __ pc(); __ load_klass(O0, G3_scratch); // set Method* (in case of interpreted method), and destination address #ifndef PRODUCT if (DebugVtables) { Label L; // check offset vs vtable length __ ld(G3_scratch, in_bytes(Klass::vtable_length_offset()), G5); __ cmp_and_br_short(G5, vtable_index*vtableEntry::size(), Assembler::greaterUnsigned, Assembler::pt, L); __ set(vtable_index, O2); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), O0, O2); __ bind(L); } #endif __ lookup_virtual_method(G3_scratch, vtable_index, G5_method); #ifndef PRODUCT if (DebugVtables) { Label L; __ br_notnull_short(G5_method, Assembler::pt, L); __ stop("Vtable entry is ZERO"); __ bind(L); } #endif address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract // NOTE: for vtable dispatches, the vtable entry will never be null. __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); // jump to target (either compiled code or c2iadapter) __ JMP(G3_scratch, 0); // load Method* (in case we call c2iadapter) __ delayed()->nop(); masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", vtable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 2*BytesPerInstWord; // 32-bit offset is this much larger than a 13-bit one assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add"); s->set_exception_points(npe_addr, ame_addr); return s; }
// NOTE: %%%% if any change is made to this stub make sure that the function // pd_code_size_limit is changed to ensure the correct size for VtableStub VtableStub* VtableStubs::create_itable_stub(int itable_index) { const int sparc_code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(sparc_code_length) VtableStub(false, itable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), sparc_code_length); MacroAssembler* masm = new MacroAssembler(&cb); Register G3_Klass = G3_scratch; Register G5_interface = G5; // Passed in as an argument Label search; // Entry arguments: // G5_interface: Interface // O0: Receiver assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); __ load_klass(O0, G3_Klass); // Push a new window to get some temp registers. This chops the head of all // my 64-bit %o registers in the LION build, but this is OK because no longs // are passed in the %o registers. Instead, longs are passed in G1 and G4 // and so those registers are not available here. __ save(SP,-frame::register_save_words*wordSize,SP); #ifndef PRODUCT if (CountCompiledCalls) { __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), L0, L1); } #endif /* PRODUCT */ Label throw_icce; Register L5_method = L5; __ lookup_interface_method(// inputs: rec. class, interface, itable index G3_Klass, G5_interface, itable_index, // outputs: method, scan temp. reg L5_method, L2, L3, throw_icce); #ifndef PRODUCT if (DebugVtables) { Label L01; __ br_notnull_short(L5_method, Assembler::pt, L01); __ stop("Method* is null"); __ bind(L01); } #endif // If the following load is through a NULL pointer, we'll take an OS // exception that should translate into an AbstractMethodError. We need the // window count to be correct at that time. __ restore(L5_method, 0, G5_method); // Restore registers *before* the AME point. address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); // G5_method: Method* // O0: Receiver // G3_scratch: entry point __ JMP(G3_scratch, 0); __ delayed()->nop(); __ bind(throw_icce); AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); __ jump_to(icce, G3_scratch); __ delayed()->restore(); masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", itable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // shut the door on sizing bugs int slop = 2*BytesPerInstWord; // 32-bit offset is this much larger than a 13-bit one assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int aarch64_code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new(aarch64_code_length) VtableStub(true, vtable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), aarch64_code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ lea(r19, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); __ incrementw(Address(r19)); } #endif // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // get receiver klass address npe_addr = __ pc(); __ load_klass(r19, j_rarg0); #ifndef PRODUCT if (DebugVtables) { Label L; // check offset vs vtable length __ ldrw(rscratch1, Address(r19, Klass::vtable_length_offset())); __ cmpw(rscratch1, vtable_index * vtableEntry::size()); __ br(Assembler::GT, L); __ enter(); __ mov(r2, vtable_index); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, r2); __ leave(); __ bind(L); } #endif // PRODUCT __ lookup_virtual_method(r19, vtable_index, rmethod); if (DebugVtables) { Label L; __ cbz(rmethod, L); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ cbnz(rscratch1, L); __ stop("Vtable entry is NULL"); __ bind(L); } // r0: receiver klass // rmethod: Method* // r2: receiver address ame_addr = __ pc(); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ br(rscratch1); __ flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", vtable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { // Note well: pd_code_size_limit is the absolute minimum we can get // away with. If you add code here, bump the code stub size // returned by pd_code_size_limit! const int code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(code_length) VtableStub(false, itable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ lea(r10, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); __ incrementw(Address(r10)); } #endif // Entry arguments: // rscratch2: Interface // j_rarg0: Receiver // Free registers (non-args) are r0 (interface), rmethod // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // get receiver klass (also an implicit null-check) address npe_addr = __ pc(); // Most registers are in use; we'll use r0, rmethod, r10, r11 __ load_klass(r10, j_rarg0); Label throw_icce; // Get Method* and entrypoint for compiler __ lookup_interface_method(// inputs: rec. class, interface, itable index r10, rscratch2, itable_index, // outputs: method, scan temp. reg rmethod, r11, throw_icce); // method (rmethod): Method* // j_rarg0: receiver #ifdef ASSERT if (DebugVtables) { Label L2; __ cbz(rmethod, L2); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ cbnz(rscratch1, L2); __ stop("compiler entrypoint is null"); __ bind(L2); } #endif // ASSERT // rmethod: Method* // j_rarg0: receiver address ame_addr = __ pc(); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ br(rscratch1); __ bind(throw_icce); __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); __ flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", itable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
// Used by compiler only; may use only caller saved, non-argument // registers. VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // PPC port: use fixed size. const int code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new (code_length) VtableStub(true, vtable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true); __ lwz(R12_scratch2, offs, R11_scratch1); __ addi(R12_scratch2, R12_scratch2, 1); __ stw(R12_scratch2, offs, R11_scratch1); } #endif assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1"); // Get receiver klass. const Register rcvr_klass = R11_scratch1; // We might implicit NULL fault here. address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3); // Set method (in case of interpreted method), and destination address. int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); #ifndef PRODUCT if (DebugVtables) { Label L; // Check offset vs vtable length. const Register vtable_len = R12_scratch2; __ lwz(vtable_len, InstanceKlass::vtable_length_offset()*wordSize, rcvr_klass); __ cmpwi(CCR0, vtable_len, vtable_index*vtableEntry::size()); __ bge(CCR0, L); __ li(R12_scratch2, vtable_index); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), R3_ARG1, R12_scratch2, false); __ bind(L); } #endif int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); __ ld(R19_method, v_off, rcvr_klass); #ifndef PRODUCT if (DebugVtables) { Label L; __ cmpdi(CCR0, R19_method, 0); __ bne(CCR0, L); __ stop("Vtable entry is ZERO", 102); __ bind(L); } #endif // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error __ load_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); masm->flush(); guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { // PPC port: use fixed size. const int code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new (code_length) VtableStub(false, itable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); address start_pc; #ifndef PRODUCT if (CountCompiledCalls) { int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true); __ lwz(R12_scratch2, offs, R11_scratch1); __ addi(R12_scratch2, R12_scratch2, 1); __ stw(R12_scratch2, offs, R11_scratch1); } #endif assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1"); // Entry arguments: // R19_method: Interface // R3_ARG1: Receiver Label L_no_such_interface; const Register rcvr_klass = R11_scratch1, interface = R12_scratch2, tmp1 = R21_tmp1, tmp2 = R22_tmp2; address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); // Receiver subtype check against REFC. __ ld(interface, CompiledICHolder::holder_klass_offset(), R19_method); __ lookup_interface_method(rcvr_klass, interface, noreg, R0, tmp1, tmp2, L_no_such_interface, /*return_method=*/ false); // Get Method* and entrypoint for compiler __ ld(interface, CompiledICHolder::holder_metadata_offset(), R19_method); __ lookup_interface_method(rcvr_klass, interface, itable_index, R19_method, tmp1, tmp2, L_no_such_interface, /*return_method=*/ true); #ifndef PRODUCT if (DebugVtables) { Label ok; __ cmpd(CCR0, R19_method, 0); __ bne(CCR0, ok); __ stop("method is null", 103); __ bind(ok); } #endif // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error // Must do an explicit check if implicit checks are disabled. assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity"); if (!ImplicitNullChecks || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { __ trap_null_check(R19_method); } else { __ cmpdi(CCR0, R19_method, 0); __ beq(CCR0, L_no_such_interface); } } __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); // Handle IncompatibleClassChangeError in itable stubs. // More detailed error message. // We force resolving of the call site by jumping to the "handle // wrong method" stub, and so let the interpreter runtime do all the // dirty work. __ bind(L_no_such_interface); __ load_const_optimized(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub(), R12_scratch2); __ mtctr(R11_scratch1); __ bctr(); masm->flush(); guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { const int code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new(code_length) VtableStub(false, itable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); assert(VtableStub::receiver_location() == R0->as_VMReg(), "receiver expected in R0"); // R0-R3 / R0-R7 registers hold the arguments and cannot be spoiled const Register Rclass = AARCH64_ONLY(R9) NOT_AARCH64(R4); const Register Rlength = AARCH64_ONLY(R10) NOT_AARCH64(R5); const Register Rscan = AARCH64_ONLY(R11) NOT_AARCH64(R6); const Register tmp = Rtemp; assert_different_registers(Ricklass, Rclass, Rlength, Rscan, tmp); // Calculate the start of itable (itable goes after vtable) const int scale = exact_log2(vtableEntry::size_in_bytes()); address npe_addr = __ pc(); __ load_klass(Rclass, R0); __ ldr_s32(Rlength, Address(Rclass, Klass::vtable_length_offset())); __ add(Rscan, Rclass, in_bytes(Klass::vtable_start_offset())); __ add(Rscan, Rscan, AsmOperand(Rlength, lsl, scale)); // Search through the itable for an interface equal to incoming Ricklass // itable looks like [intface][offset][intface][offset][intface][offset] const int entry_size = itableOffsetEntry::size() * HeapWordSize; assert(itableOffsetEntry::interface_offset_in_bytes() == 0, "not added for convenience"); Label loop; __ bind(loop); __ ldr(tmp, Address(Rscan, entry_size, post_indexed)); #ifdef AARCH64 Label found; __ cmp(tmp, Ricklass); __ b(found, eq); __ cbnz(tmp, loop); #else __ cmp(tmp, Ricklass); // set ZF and CF if interface is found __ cmn(tmp, 0, ne); // check if tmp == 0 and clear CF if it is __ b(loop, ne); #endif // AARCH64 assert(StubRoutines::throw_IncompatibleClassChangeError_entry() != NULL, "Check initialization order"); #ifdef AARCH64 __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, tmp); __ bind(found); #else // CF == 0 means we reached the end of itable without finding icklass __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, noreg, cc); #endif // !AARCH64 // Interface found at previous position of Rscan, now load the method oop __ ldr_s32(tmp, Address(Rscan, itableOffsetEntry::offset_offset_in_bytes() - entry_size)); { const int method_offset = itableMethodEntry::size() * HeapWordSize * itable_index + itableMethodEntry::method_offset_in_bytes(); __ add_slow(Rmethod, Rclass, method_offset); } __ ldr(Rmethod, Address(Rmethod, tmp)); address ame_addr = __ pc(); #ifdef AARCH64 __ ldr(tmp, Address(Rmethod, Method::from_compiled_offset())); __ br(tmp); #else __ ldr(PC, Address(Rmethod, Method::from_compiled_offset())); #endif // AARCH64 masm->flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", itable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); // FIXME ARM: need correct 'slop' - below is x86 code // shut the door on sizing bugs //int slop = 8; // 32-bit offset is this much larger than a 13-bit one //assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); s->set_exception_points(npe_addr, ame_addr); return s; }