1 /*
   2  * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *
  23  */
  24 
  25 #include "incls/_precompiled.incl"
  26 #include "incls/_vtableStubs_x86_64.cpp.incl"
  27 
  28 // machine-dependent part of VtableStubs: create VtableStub of correct size and
  29 // initialize its code
  30 
  31 #define __ masm->
  32 
  33 #ifndef PRODUCT
  34 extern "C" void bad_compiled_vtable_index(JavaThread* thread,
  35                                           oop receiver,
  36                                           int index);
  37 #endif
  38 
  39 VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
  40   const int amd64_code_length = VtableStub::pd_code_size_limit(true);
  41   VtableStub* s = new(amd64_code_length) VtableStub(true, vtable_index);
  42   ResourceMark rm;
  43   CodeBuffer cb(s->entry_point(), amd64_code_length);
  44   MacroAssembler* masm = new MacroAssembler(&cb);
  45 
  46 #ifndef PRODUCT
  47   if (CountCompiledCalls) {
  48     __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
  49   }
  50 #endif
  51 
  52   // get receiver (need to skip return address on top of stack)
  53   assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
  54 
  55   // Free registers (non-args) are rax, rbx
  56 
  57   // get receiver klass
  58   address npe_addr = __ pc();
  59   __ load_klass(rax, j_rarg0);
  60 
  61   // compute entry offset (in words)
  62   int entry_offset =
  63     instanceKlass::vtable_start_offset() + vtable_index * vtableEntry::size();
  64 
  65 #ifndef PRODUCT
  66   if (DebugVtables) {
  67     Label L;
  68     // check offset vs vtable length
  69     __ cmpl(Address(rax, instanceKlass::vtable_length_offset() * wordSize),
  70             vtable_index * vtableEntry::size());
  71     __ jcc(Assembler::greater, L);
  72     __ movl(rbx, vtable_index);
  73     __ call_VM(noreg,
  74                CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, rbx);
  75     __ bind(L);
  76   }
  77 #endif // PRODUCT
  78 
  79   // load methodOop and target address
  80   const Register method = rbx;
  81 
  82   __ movptr(method, Address(rax,
  83                             entry_offset * wordSize +
  84                             vtableEntry::method_offset_in_bytes()));
  85   if (DebugVtables) {
  86     Label L;
  87     __ cmpptr(method, (int32_t)NULL_WORD);
  88     __ jcc(Assembler::equal, L);
  89     __ cmpptr(Address(method, methodOopDesc::from_compiled_offset()), (int32_t)NULL_WORD);
  90     __ jcc(Assembler::notZero, L);
  91     __ stop("Vtable entry is NULL");
  92     __ bind(L);
  93   }
  94   // rax: receiver klass
  95   // rbx: methodOop
  96   // rcx: receiver
  97   address ame_addr = __ pc();
  98   __ jmp( Address(rbx, methodOopDesc::from_compiled_offset()));
  99 
 100   __ flush();
 101   s->set_exception_points(npe_addr, ame_addr);
 102   return s;
 103 }
 104 
 105 
 106 VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
 107   // Note well: pd_code_size_limit is the absolute minimum we can get
 108   // away with.  If you add code here, bump the code stub size
 109   // returned by pd_code_size_limit!
 110   const int amd64_code_length = VtableStub::pd_code_size_limit(false);
 111   VtableStub* s = new(amd64_code_length) VtableStub(false, vtable_index);
 112   ResourceMark rm;
 113   CodeBuffer cb(s->entry_point(), amd64_code_length);
 114   MacroAssembler* masm = new MacroAssembler(&cb);
 115 
 116 #ifndef PRODUCT
 117   if (CountCompiledCalls) {
 118     __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
 119   }
 120 #endif
 121 
 122   // Entry arguments:
 123   //  rax: Interface
 124   //  j_rarg0: Receiver
 125 
 126   // Free registers (non-args) are rax (interface), rbx
 127 
 128   // get receiver (need to skip return address on top of stack)
 129 
 130   assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
 131   // get receiver klass (also an implicit null-check)
 132   address npe_addr = __ pc();
 133 
 134   __ load_klass(rbx, j_rarg0);
 135 
 136   // If we take a trap while this arg is on the stack we will not
 137   // be able to walk the stack properly. This is not an issue except
 138   // when there are mistakes in this assembly code that could generate
 139   // a spurious fault. Ask me how I know...
 140 
 141   __ push(j_rarg1);     // Most registers are in use, so save one
 142 
 143   // compute itable entry offset (in words)
 144   const int base = instanceKlass::vtable_start_offset() * wordSize;
 145   assert(vtableEntry::size() * wordSize == 8,
 146          "adjust the scaling in the code below");
 147   // Get length of vtable
 148   __ movl(j_rarg1,
 149           Address(rbx, instanceKlass::vtable_length_offset() * wordSize));
 150   __ lea(rbx, Address(rbx, j_rarg1, Address::times_8, base));
 151 
 152   if (HeapWordsPerLong > 1) {
 153     // Round up to align_object_offset boundary
 154     __ round_to(rbx, BytesPerLong);
 155   }
 156   Label hit, next, entry, throw_icce;
 157 
 158   __ jmpb(entry);
 159 
 160   __ bind(next);
 161   __ addptr(rbx, itableOffsetEntry::size() * wordSize);
 162 
 163   __ bind(entry);
 164 
 165   // If the entry is NULL then we've reached the end of the table
 166   // without finding the expected interface, so throw an exception
 167   __ movptr(j_rarg1, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
 168   __ testptr(j_rarg1, j_rarg1);
 169   __ jcc(Assembler::zero, throw_icce);
 170   __ cmpptr(rax, j_rarg1);
 171   __ jccb(Assembler::notEqual, next);
 172 
 173   // We found a hit, move offset into j_rarg1
 174   __ movl(j_rarg1, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
 175 
 176   // Compute itableMethodEntry
 177   const int method_offset =
 178     (itableMethodEntry::size() * wordSize * vtable_index) +
 179     itableMethodEntry::method_offset_in_bytes();
 180 
 181   // Get methodOop and entrypoint for compiler
 182 
 183   // Get klass pointer again
 184   __ load_klass(rax, j_rarg0);
 185 
 186   const Register method = rbx;
 187   __ movptr(method, Address(rax, j_rarg1, Address::times_1, method_offset));
 188 
 189   // Restore saved register, before possible trap.
 190   __ pop(j_rarg1);
 191 
 192   // method (rbx): methodOop
 193   // j_rarg0: receiver
 194 
 195 
 196 #ifdef ASSERT
 197   if (DebugVtables) {
 198     Label L2;
 199     __ cmpptr(method, (int32_t)NULL_WORD);
 200     __ jcc(Assembler::equal, L2);
 201     __ cmpptr(Address(method, methodOopDesc::from_compiled_offset()), (int32_t)NULL_WORD);
 202     __ jcc(Assembler::notZero, L2);
 203     __ stop("compiler entrypoint is null");
 204     __ bind(L2);
 205   }
 206 #endif // ASSERT
 207 
 208   // rbx: methodOop
 209   // j_rarg0: receiver
 210   address ame_addr = __ pc();
 211   __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
 212 
 213   __ bind(throw_icce);
 214   // Restore saved register
 215   __ pop(j_rarg1);
 216   __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
 217 
 218   __ flush();
 219 
 220   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
 221 
 222   s->set_exception_points(npe_addr, ame_addr);
 223   return s;
 224 }
 225 
 226 int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
 227   if (is_vtable_stub) {
 228     // Vtable stub size
 229     return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0) +
 230            (UseCompressedOops ? 16 : 0);  // 1 leaq can be 3 bytes + 1 long
 231   } else {
 232     // Itable stub size
 233     return (DebugVtables ? 636 : 72) + (CountCompiledCalls ? 13 : 0) +
 234            (UseCompressedOops ? 32 : 0);  // 2 leaqs
 235   }
 236 }
 237 
 238 int VtableStub::pd_code_alignment() {
 239   return wordSize;
 240 }