1 #ifdef USE_PRAGMA_IDENT_SRC 2 #pragma ident "@(#)vtableStubs_sparc.cpp 1.58 07/07/19 12:19:09 JVM" 3 #endif 4 /* 5 * Copyright 1997-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_sparc.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 37 #ifndef PRODUCT 38 extern "C" void bad_compiled_vtable_index(JavaThread* thread, oopDesc* receiver, int index); 39 #endif 40 41 42 // Used by compiler only; may use only caller saved, non-argument registers 43 // NOTE: %%%% if any change is made to this stub make sure that the function 44 // pd_code_size_limit is changed to ensure the correct size for VtableStub 45 VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { 46 const int sparc_code_length = VtableStub::pd_code_size_limit(true); 47 VtableStub* s = new(sparc_code_length) VtableStub(true, vtable_index); 48 ResourceMark rm; 49 CodeBuffer cb(s->entry_point(), sparc_code_length); 50 MacroAssembler* masm = new MacroAssembler(&cb); 51 52 #ifndef PRODUCT 53 if (CountCompiledCalls) { 54 Address ctr(G5, SharedRuntime::nof_megamorphic_calls_addr()); 55 __ sethi(ctr); 56 __ ld(ctr, G3_scratch); 57 __ inc(G3_scratch); 58 __ st(G3_scratch, ctr); 59 } 60 #endif /* PRODUCT */ 61 62 assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); 63 64 // get receiver klass 65 address npe_addr = __ pc(); 66 __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), G3_scratch); 67 68 // set methodOop (in case of interpreted method), and destination address 69 int entry_offset = instanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); 70 #ifndef PRODUCT 71 if (DebugVtables) { 72 Label L; 73 // check offset vs vtable length 74 __ ld(G3_scratch, instanceKlass::vtable_length_offset()*wordSize, G5); 75 __ cmp(G5, vtable_index*vtableEntry::size()); 76 __ br(Assembler::greaterUnsigned, false, Assembler::pt, L); 77 __ delayed()->nop(); 78 __ set(vtable_index, O2); 79 __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), O0, O2); 80 __ bind(L); 81 } 82 #endif 83 int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); 84 if( __ is_simm13(v_off) ) { 85 __ ld_ptr(G3, v_off, G5_method); 86 } else { 87 __ set(v_off,G5); 88 __ ld_ptr(G3, G5, G5_method); 89 } 90 91 #ifndef PRODUCT 92 if (DebugVtables) { 93 Label L; 94 __ br_notnull(G5_method, false, Assembler::pt, L); 95 __ delayed()->nop(); 96 __ stop("Vtable entry is ZERO"); 97 __ bind(L); 98 } 99 #endif 100 101 address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract 102 // NOTE: for vtable dispatches, the vtable entry will never be null. 103 104 __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch); 105 106 // jump to target (either compiled code or c2iadapter) 107 __ JMP(G3_scratch, 0); 108 // load methodOop (in case we call c2iadapter) 109 __ delayed()->nop(); 110 111 masm->flush(); 112 s->set_exception_points(npe_addr, ame_addr); 113 return s; 114 } 115 116 117 // NOTE: %%%% if any change is made to this stub make sure that the function 118 // pd_code_size_limit is changed to ensure the correct size for VtableStub 119 VtableStub* VtableStubs::create_itable_stub(int vtable_index) { 120 const int sparc_code_length = VtableStub::pd_code_size_limit(false); 121 VtableStub* s = new(sparc_code_length) VtableStub(false, vtable_index); 122 ResourceMark rm; 123 CodeBuffer cb(s->entry_point(), sparc_code_length); 124 MacroAssembler* masm = new MacroAssembler(&cb); 125 126 Register G3_klassOop = G3_scratch; 127 Register G5_interface = G5; // Passed in as an argument 128 Label search; 129 130 // Entry arguments: 131 // G5_interface: Interface 132 // O0: Receiver 133 assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); 134 135 // get receiver klass (also an implicit null-check) 136 address npe_addr = __ pc(); 137 __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), G3_klassOop); 138 __ verify_oop(G3_klassOop); 139 140 // Push a new window to get some temp registers. This chops the head of all 141 // my 64-bit %o registers in the LION build, but this is OK because no longs 142 // are passed in the %o registers. Instead, longs are passed in G1 and G4 143 // and so those registers are not available here. 144 __ save(SP,-frame::register_save_words*wordSize,SP); 145 Register I0_receiver = I0; // Location of receiver after save 146 147 #ifndef PRODUCT 148 if (CountCompiledCalls) { 149 Address ctr(L0, SharedRuntime::nof_megamorphic_calls_addr()); 150 __ sethi(ctr); 151 __ ld(ctr, L1); 152 __ inc(L1); 153 __ st(L1, ctr); 154 } 155 #endif /* PRODUCT */ 156 157 // load start of itable entries into L0 register 158 const int base = instanceKlass::vtable_start_offset() * wordSize; 159 __ ld(Address(G3_klassOop, 0, instanceKlass::vtable_length_offset() * wordSize), L0); 160 161 // %%% Could store the aligned, prescaled offset in the klassoop. 162 __ sll(L0, exact_log2(vtableEntry::size() * wordSize), L0); 163 // see code for instanceKlass::start_of_itable! 164 const int vtable_alignment = align_object_offset(1); 165 assert(vtable_alignment == 1 || vtable_alignment == 2, ""); 166 const int odd_bit = vtableEntry::size() * wordSize; 167 if (vtable_alignment == 2) { 168 __ and3(L0, odd_bit, L1); // isolate the odd bit 169 } 170 __ add(G3_klassOop, L0, L0); 171 if (vtable_alignment == 2) { 172 __ add(L0, L1, L0); // double the odd bit, to align up 173 } 174 175 // Loop over all itable entries until desired interfaceOop (G5_interface) found 176 __ bind(search); 177 178 // %%%% Could load both offset and interface in one ldx, if they were 179 // in the opposite order. This would save a load. 180 __ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1); 181 182 // If the entry is NULL then we've reached the end of the table 183 // without finding the expected interface, so throw an exception 184 Label throw_icce; 185 __ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce); 186 __ delayed()->cmp(G5_interface, L1); 187 __ brx(Assembler::notEqual, true, Assembler::pn, search); 188 __ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0); 189 190 // entry found and L0 points to it, move offset of vtable for interface into L0 191 __ ld(L0, base + itableOffsetEntry::offset_offset_in_bytes(), L0); 192 193 // Compute itableMethodEntry and get methodOop(G5_method) and entrypoint(L0) for compiler 194 const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes(); 195 __ add(G3_klassOop, L0, L1); 196 if (__ is_simm13(method_offset)) { 197 __ ld_ptr(L1, method_offset, G5_method); 198 } else { 199 __ set(method_offset, G5_method); 200 __ ld_ptr(L1, G5_method, G5_method); 201 } 202 203 #ifndef PRODUCT 204 if (DebugVtables) { 205 Label L01; 206 __ bpr(Assembler::rc_nz, false, Assembler::pt, G5_method, L01); 207 __ delayed()->nop(); 208 __ stop("methodOop is null"); 209 __ bind(L01); 210 __ verify_oop(G5_method); 211 } 212 #endif 213 214 // If the following load is through a NULL pointer, we'll take an OS 215 // exception that should translate into an AbstractMethodError. We need the 216 // window count to be correct at that time. 217 __ restore(); // Restore registers BEFORE the AME point 218 219 address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract 220 __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch); 221 222 // G5_method: methodOop 223 // O0: Receiver 224 // G3_scratch: entry point 225 __ JMP(G3_scratch, 0); 226 __ delayed()->nop(); 227 228 __ bind(throw_icce); 229 Address icce(G3_scratch, StubRoutines::throw_IncompatibleClassChangeError_entry()); 230 __ jump_to(icce, 0); 231 __ delayed()->restore(); 232 233 masm->flush(); 234 235 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); 236 237 s->set_exception_points(npe_addr, ame_addr); 238 return s; 239 } 240 241 242 int VtableStub::pd_code_size_limit(bool is_vtable_stub) { 243 if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) return 1000; 244 else { 245 const int slop = 2*BytesPerInstWord; // sethi;add (needed for long offsets) 246 if (is_vtable_stub) { 247 const int basic = 5*BytesPerInstWord; // ld;ld;ld,jmp,nop 248 return basic + slop; 249 } else { 250 // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, sethi, add, ld, ld, jmp, restore, sethi, jmpl, restore 251 const int basic = (22 LP64_ONLY(+ 12)) * BytesPerInstWord; // worst case extra 6 bytes for each sethi in 64-bit mode 252 return (basic + slop); 253 } 254 } 255 } 256 257 258 int VtableStub::pd_code_alignment() { 259 // UltraSPARC cache line size is 8 instructions: 260 const unsigned int icache_line_size = 32; 261 return icache_line_size; 262 }