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