duke@435: /* dbuck@8997: * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #include "precompiled.hpp" twisti@4318: #include "asm/macroAssembler.hpp" stefank@2314: #include "code/vtableStubs.hpp" roland@5987: #include "interp_masm_x86.hpp" stefank@2314: #include "memory/resourceArea.hpp" dbuck@8997: #include "oops/compiledICHolder.hpp" stefank@2314: #include "oops/instanceKlass.hpp" stefank@2314: #include "oops/klassVtable.hpp" stefank@2314: #include "runtime/sharedRuntime.hpp" stefank@2314: #include "vmreg_x86.inline.hpp" stefank@2314: #ifdef COMPILER2 stefank@2314: #include "opto/runtime.hpp" stefank@2314: #endif duke@435: drchase@6680: PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC drchase@6680: duke@435: // machine-dependent part of VtableStubs: create VtableStub of correct size and duke@435: // initialize its code duke@435: duke@435: #define __ masm-> duke@435: duke@435: #ifndef PRODUCT duke@435: extern "C" void bad_compiled_vtable_index(JavaThread* thread, duke@435: oop receiver, duke@435: int index); duke@435: #endif duke@435: duke@435: VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { duke@435: const int amd64_code_length = VtableStub::pd_code_size_limit(true); duke@435: VtableStub* s = new(amd64_code_length) VtableStub(true, vtable_index); anoll@5762: // Can be NULL if there is no free space in the code cache. anoll@5762: if (s == NULL) { anoll@5762: return NULL; anoll@5762: } anoll@5762: duke@435: ResourceMark rm; duke@435: CodeBuffer cb(s->entry_point(), amd64_code_length); duke@435: MacroAssembler* masm = new MacroAssembler(&cb); duke@435: duke@435: #ifndef PRODUCT duke@435: if (CountCompiledCalls) { duke@435: __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); duke@435: } duke@435: #endif duke@435: duke@435: // get receiver (need to skip return address on top of stack) duke@435: assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); duke@435: duke@435: // Free registers (non-args) are rax, rbx duke@435: duke@435: // get receiver klass duke@435: address npe_addr = __ pc(); coleenp@548: __ load_klass(rax, j_rarg0); duke@435: duke@435: #ifndef PRODUCT duke@435: if (DebugVtables) { duke@435: Label L; duke@435: // check offset vs vtable length coleenp@4037: __ cmpl(Address(rax, InstanceKlass::vtable_length_offset() * wordSize), duke@435: vtable_index * vtableEntry::size()); duke@435: __ jcc(Assembler::greater, L); duke@435: __ movl(rbx, vtable_index); duke@435: __ call_VM(noreg, duke@435: CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, rbx); duke@435: __ bind(L); duke@435: } duke@435: #endif // PRODUCT duke@435: coleenp@4037: // load Method* and target address duke@435: const Register method = rbx; duke@435: twisti@3969: __ lookup_virtual_method(rax, vtable_index, method); twisti@3969: duke@435: if (DebugVtables) { duke@435: Label L; never@739: __ cmpptr(method, (int32_t)NULL_WORD); duke@435: __ jcc(Assembler::equal, L); coleenp@4037: __ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD); duke@435: __ jcc(Assembler::notZero, L); duke@435: __ stop("Vtable entry is NULL"); duke@435: __ bind(L); duke@435: } duke@435: // rax: receiver klass coleenp@4037: // rbx: Method* duke@435: // rcx: receiver duke@435: address ame_addr = __ pc(); coleenp@4037: __ jmp( Address(rbx, Method::from_compiled_offset())); duke@435: duke@435: __ flush(); jrose@1058: jrose@1058: if (PrintMiscellaneous && (WizardMode || Verbose)) { jrose@1058: tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d", jrose@1058: vtable_index, s->entry_point(), jrose@1058: (int)(s->code_end() - s->entry_point()), jrose@1058: (int)(s->code_end() - __ pc())); jrose@1058: } jrose@1058: guarantee(__ pc() <= s->code_end(), "overflowed buffer"); jrose@1144: // shut the door on sizing bugs jrose@1144: int slop = 3; // 32-bit offset is this much larger than an 8-bit one jrose@1144: assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); jrose@1058: duke@435: s->set_exception_points(npe_addr, ame_addr); duke@435: return s; duke@435: } duke@435: duke@435: jrose@1058: VtableStub* VtableStubs::create_itable_stub(int itable_index) { duke@435: // Note well: pd_code_size_limit is the absolute minimum we can get duke@435: // away with. If you add code here, bump the code stub size duke@435: // returned by pd_code_size_limit! duke@435: const int amd64_code_length = VtableStub::pd_code_size_limit(false); jrose@1058: VtableStub* s = new(amd64_code_length) VtableStub(false, itable_index); anoll@5762: // Can be NULL if there is no free space in the code cache. anoll@5762: if (s == NULL) { anoll@5762: return NULL; anoll@5762: } anoll@5762: duke@435: ResourceMark rm; duke@435: CodeBuffer cb(s->entry_point(), amd64_code_length); duke@435: MacroAssembler* masm = new MacroAssembler(&cb); duke@435: duke@435: #ifndef PRODUCT duke@435: if (CountCompiledCalls) { duke@435: __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); duke@435: } duke@435: #endif duke@435: duke@435: // Entry arguments: dbuck@8997: // rax: CompiledICHolder duke@435: // j_rarg0: Receiver duke@435: jrose@1058: // Most registers are in use; we'll use rax, rbx, r10, r11 jrose@1058: // (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them) dbuck@8997: const Register recv_klass_reg = r10; dbuck@8997: const Register holder_klass_reg = rax; // declaring interface klass (DECC) dbuck@8997: const Register resolved_klass_reg = rbx; // resolved interface klass (REFC) dbuck@8997: const Register temp_reg = r11; dbuck@8997: dbuck@8997: Label L_no_such_interface; dbuck@8997: dbuck@8997: const Register icholder_reg = rax; dbuck@8997: __ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); dbuck@8997: __ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); dbuck@8997: dbuck@8997: // get receiver klass (also an implicit null-check) dbuck@8997: assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); dbuck@8997: address npe_addr = __ pc(); dbuck@8997: __ load_klass(recv_klass_reg, j_rarg0); dbuck@8997: dbuck@8997: // Receiver subtype check against REFC. dbuck@8997: // Destroys recv_klass_reg value. dbuck@8997: __ lookup_interface_method(// inputs: rec. class, interface dbuck@8997: recv_klass_reg, resolved_klass_reg, noreg, dbuck@8997: // outputs: scan temp. reg1, scan temp. reg2 dbuck@8997: recv_klass_reg, temp_reg, dbuck@8997: L_no_such_interface, dbuck@8997: /*return_method=*/false); dbuck@8997: dbuck@8997: // Get selected method from declaring class and itable index dbuck@8997: const Register method = rbx; dbuck@8997: __ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg dbuck@8997: __ lookup_interface_method(// inputs: rec. class, interface, itable index dbuck@8997: recv_klass_reg, holder_klass_reg, itable_index, dbuck@8997: // outputs: method, scan temp. reg dbuck@8997: method, temp_reg, dbuck@8997: L_no_such_interface); duke@435: duke@435: // If we take a trap while this arg is on the stack we will not duke@435: // be able to walk the stack properly. This is not an issue except duke@435: // when there are mistakes in this assembly code that could generate duke@435: // a spurious fault. Ask me how I know... duke@435: coleenp@4037: // method (rbx): Method* duke@435: // j_rarg0: receiver duke@435: duke@435: #ifdef ASSERT dcubed@451: if (DebugVtables) { dcubed@451: Label L2; never@739: __ cmpptr(method, (int32_t)NULL_WORD); dcubed@451: __ jcc(Assembler::equal, L2); coleenp@4037: __ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD); dcubed@451: __ jcc(Assembler::notZero, L2); dcubed@451: __ stop("compiler entrypoint is null"); dcubed@451: __ bind(L2); dcubed@451: } duke@435: #endif // ASSERT duke@435: coleenp@4037: // rbx: Method* dcubed@451: // j_rarg0: receiver dcubed@451: address ame_addr = __ pc(); coleenp@4037: __ jmp(Address(method, Method::from_compiled_offset())); dcubed@451: dbuck@8997: __ bind(L_no_such_interface); dcubed@451: __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); duke@435: duke@435: __ flush(); dcubed@451: jrose@1058: if (PrintMiscellaneous && (WizardMode || Verbose)) { jrose@1058: tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", jrose@1058: itable_index, s->entry_point(), jrose@1058: (int)(s->code_end() - s->entry_point()), jrose@1058: (int)(s->code_end() - __ pc())); jrose@1058: } dcubed@451: guarantee(__ pc() <= s->code_end(), "overflowed buffer"); jrose@1144: // shut the door on sizing bugs jrose@1144: int slop = 3; // 32-bit offset is this much larger than an 8-bit one jrose@1144: assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset"); dcubed@451: duke@435: s->set_exception_points(npe_addr, ame_addr); duke@435: return s; duke@435: } duke@435: duke@435: int VtableStub::pd_code_size_limit(bool is_vtable_stub) { duke@435: if (is_vtable_stub) { duke@435: // Vtable stub size coleenp@548: return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0) + ehelin@5694: (UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); duke@435: } else { duke@435: // Itable stub size dbuck@8997: return (DebugVtables ? 512 : 140) + (CountCompiledCalls ? 13 : 0) + dbuck@8997: (UseCompressedClassPointers ? 2 * MacroAssembler::instr_size_for_decode_klass_not_null() : 0); duke@435: } jrose@1144: // In order to tune these parameters, run the JVM with VM options jrose@1144: // +PrintMiscellaneous and +WizardMode to see information about jrose@1144: // actual itable stubs. Look for lines like this: jrose@1144: // itable #1 at 0x5551212[71] left over: 3 jrose@1144: // Reduce the constants so that the "left over" number is >=3 jrose@1144: // for the common cases. jrose@1144: // Do not aim at a left-over number of zero, because a jrose@1144: // large vtable or itable index (>= 32) will require a 32-bit jrose@1144: // immediate displacement instead of an 8-bit one. jrose@1144: // jrose@1144: // The JVM98 app. _202_jess has a megamorphic interface call. jrose@1144: // The itable code looks like this: jrose@1144: // Decoding VtableStub itbl[1]@12 jrose@1144: // mov 0x8(%rsi),%r10 jrose@1144: // mov 0x198(%r10),%r11d jrose@1144: // lea 0x218(%r10,%r11,8),%r11 jrose@1144: // lea 0x8(%r10),%r10 jrose@1144: // mov (%r11),%rbx jrose@1144: // cmp %rbx,%rax jrose@1144: // je success jrose@1144: // loop: jrose@1144: // test %rbx,%rbx jrose@1144: // je throw_icce jrose@1144: // add $0x10,%r11 jrose@1144: // mov (%r11),%rbx jrose@1144: // cmp %rbx,%rax jrose@1144: // jne loop jrose@1144: // success: jrose@1144: // mov 0x8(%r11),%r11d jrose@1144: // mov (%r10,%r11,1),%rbx jrose@1144: // jmpq *0x60(%rbx) jrose@1144: // throw_icce: jrose@1144: // jmpq throw_ICCE_entry duke@435: } duke@435: duke@435: int VtableStub::pd_code_alignment() { duke@435: return wordSize; duke@435: }