Mercurial > hg > graal-jvmci-8
comparison src/cpu/sparc/vm/vtableStubs_sparc.cpp @ 623:9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
Summary: Code in vtableStubs and templateTable moved into MacroAssembler.
Reviewed-by: kvn
author | jrose |
---|---|
date | Fri, 06 Mar 2009 21:36:50 -0800 |
parents | d1605aabd0a1 |
children | 660978a2a31a |
comparison
equal
deleted
inserted
replaced
622:56aae7be60d4 | 623:9adddb8c0fc8 |
---|---|
104 __ JMP(G3_scratch, 0); | 104 __ JMP(G3_scratch, 0); |
105 // load methodOop (in case we call c2iadapter) | 105 // load methodOop (in case we call c2iadapter) |
106 __ delayed()->nop(); | 106 __ delayed()->nop(); |
107 | 107 |
108 masm->flush(); | 108 masm->flush(); |
109 | |
110 if (PrintMiscellaneous && (WizardMode || Verbose)) { | |
111 tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d", | |
112 vtable_index, s->entry_point(), | |
113 (int)(s->code_end() - s->entry_point()), | |
114 (int)(s->code_end() - __ pc())); | |
115 } | |
116 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); | |
117 | |
109 s->set_exception_points(npe_addr, ame_addr); | 118 s->set_exception_points(npe_addr, ame_addr); |
110 return s; | 119 return s; |
111 } | 120 } |
112 | 121 |
113 | 122 |
114 // NOTE: %%%% if any change is made to this stub make sure that the function | 123 // NOTE: %%%% if any change is made to this stub make sure that the function |
115 // pd_code_size_limit is changed to ensure the correct size for VtableStub | 124 // pd_code_size_limit is changed to ensure the correct size for VtableStub |
116 VtableStub* VtableStubs::create_itable_stub(int vtable_index) { | 125 VtableStub* VtableStubs::create_itable_stub(int itable_index) { |
117 const int sparc_code_length = VtableStub::pd_code_size_limit(false); | 126 const int sparc_code_length = VtableStub::pd_code_size_limit(false); |
118 VtableStub* s = new(sparc_code_length) VtableStub(false, vtable_index); | 127 VtableStub* s = new(sparc_code_length) VtableStub(false, itable_index); |
119 ResourceMark rm; | 128 ResourceMark rm; |
120 CodeBuffer cb(s->entry_point(), sparc_code_length); | 129 CodeBuffer cb(s->entry_point(), sparc_code_length); |
121 MacroAssembler* masm = new MacroAssembler(&cb); | 130 MacroAssembler* masm = new MacroAssembler(&cb); |
122 | 131 |
123 Register G3_klassOop = G3_scratch; | 132 Register G3_klassOop = G3_scratch; |
137 // Push a new window to get some temp registers. This chops the head of all | 146 // Push a new window to get some temp registers. This chops the head of all |
138 // my 64-bit %o registers in the LION build, but this is OK because no longs | 147 // my 64-bit %o registers in the LION build, but this is OK because no longs |
139 // are passed in the %o registers. Instead, longs are passed in G1 and G4 | 148 // are passed in the %o registers. Instead, longs are passed in G1 and G4 |
140 // and so those registers are not available here. | 149 // and so those registers are not available here. |
141 __ save(SP,-frame::register_save_words*wordSize,SP); | 150 __ save(SP,-frame::register_save_words*wordSize,SP); |
142 Register I0_receiver = I0; // Location of receiver after save | |
143 | 151 |
144 #ifndef PRODUCT | 152 #ifndef PRODUCT |
145 if (CountCompiledCalls) { | 153 if (CountCompiledCalls) { |
146 Address ctr(L0, SharedRuntime::nof_megamorphic_calls_addr()); | 154 Address ctr(L0, SharedRuntime::nof_megamorphic_calls_addr()); |
147 __ sethi(ctr); | 155 __ sethi(ctr); |
149 __ inc(L1); | 157 __ inc(L1); |
150 __ st(L1, ctr); | 158 __ st(L1, ctr); |
151 } | 159 } |
152 #endif /* PRODUCT */ | 160 #endif /* PRODUCT */ |
153 | 161 |
154 // load start of itable entries into L0 register | |
155 const int base = instanceKlass::vtable_start_offset() * wordSize; | |
156 __ ld(Address(G3_klassOop, 0, instanceKlass::vtable_length_offset() * wordSize), L0); | |
157 | |
158 // %%% Could store the aligned, prescaled offset in the klassoop. | |
159 __ sll(L0, exact_log2(vtableEntry::size() * wordSize), L0); | |
160 // see code for instanceKlass::start_of_itable! | |
161 const int vtable_alignment = align_object_offset(1); | |
162 assert(vtable_alignment == 1 || vtable_alignment == 2, ""); | |
163 const int odd_bit = vtableEntry::size() * wordSize; | |
164 if (vtable_alignment == 2) { | |
165 __ and3(L0, odd_bit, L1); // isolate the odd bit | |
166 } | |
167 __ add(G3_klassOop, L0, L0); | |
168 if (vtable_alignment == 2) { | |
169 __ add(L0, L1, L0); // double the odd bit, to align up | |
170 } | |
171 | |
172 // Loop over all itable entries until desired interfaceOop (G5_interface) found | |
173 __ bind(search); | |
174 | |
175 // %%%% Could load both offset and interface in one ldx, if they were | |
176 // in the opposite order. This would save a load. | |
177 __ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1); | |
178 | |
179 // If the entry is NULL then we've reached the end of the table | |
180 // without finding the expected interface, so throw an exception | |
181 Label throw_icce; | 162 Label throw_icce; |
182 __ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce); | 163 |
183 __ delayed()->cmp(G5_interface, L1); | 164 Register L5_method = L5; |
184 __ brx(Assembler::notEqual, true, Assembler::pn, search); | 165 __ lookup_interface_method(// inputs: rec. class, interface, itable index |
185 __ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0); | 166 G3_klassOop, G5_interface, itable_index, |
186 | 167 // outputs: method, scan temp. reg |
187 // entry found and L0 points to it, move offset of vtable for interface into L0 | 168 L5_method, L2, L3, |
188 __ ld(L0, base + itableOffsetEntry::offset_offset_in_bytes(), L0); | 169 throw_icce); |
189 | |
190 // Compute itableMethodEntry and get methodOop(G5_method) and entrypoint(L0) for compiler | |
191 const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes(); | |
192 __ add(G3_klassOop, L0, L1); | |
193 __ ld_ptr(L1, method_offset, G5_method); | |
194 | 170 |
195 #ifndef PRODUCT | 171 #ifndef PRODUCT |
196 if (DebugVtables) { | 172 if (DebugVtables) { |
197 Label L01; | 173 Label L01; |
198 __ ld_ptr(L1, method_offset, G5_method); | 174 __ bpr(Assembler::rc_nz, false, Assembler::pt, L5_method, L01); |
199 __ bpr(Assembler::rc_nz, false, Assembler::pt, G5_method, L01); | |
200 __ delayed()->nop(); | 175 __ delayed()->nop(); |
201 __ stop("methodOop is null"); | 176 __ stop("methodOop is null"); |
202 __ bind(L01); | 177 __ bind(L01); |
203 __ verify_oop(G5_method); | 178 __ verify_oop(L5_method); |
204 } | 179 } |
205 #endif | 180 #endif |
206 | 181 |
207 // If the following load is through a NULL pointer, we'll take an OS | 182 // If the following load is through a NULL pointer, we'll take an OS |
208 // exception that should translate into an AbstractMethodError. We need the | 183 // exception that should translate into an AbstractMethodError. We need the |
209 // window count to be correct at that time. | 184 // window count to be correct at that time. |
210 __ restore(); // Restore registers BEFORE the AME point | 185 __ restore(L5_method, 0, G5_method); |
186 // Restore registers *before* the AME point. | |
211 | 187 |
212 address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract | 188 address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract |
213 __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch); | 189 __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch); |
214 | 190 |
215 // G5_method: methodOop | 191 // G5_method: methodOop |
223 __ jump_to(icce, 0); | 199 __ jump_to(icce, 0); |
224 __ delayed()->restore(); | 200 __ delayed()->restore(); |
225 | 201 |
226 masm->flush(); | 202 masm->flush(); |
227 | 203 |
204 if (PrintMiscellaneous && (WizardMode || Verbose)) { | |
205 tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d", | |
206 itable_index, s->entry_point(), | |
207 (int)(s->code_end() - s->entry_point()), | |
208 (int)(s->code_end() - __ pc())); | |
209 } | |
228 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); | 210 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); |
229 | 211 |
230 s->set_exception_points(npe_addr, ame_addr); | 212 s->set_exception_points(npe_addr, ame_addr); |
231 return s; | 213 return s; |
232 } | 214 } |
241 const int basic = 5*BytesPerInstWord + | 223 const int basic = 5*BytesPerInstWord + |
242 // shift;add for load_klass | 224 // shift;add for load_klass |
243 (UseCompressedOops ? 2*BytesPerInstWord : 0); | 225 (UseCompressedOops ? 2*BytesPerInstWord : 0); |
244 return basic + slop; | 226 return basic + slop; |
245 } else { | 227 } else { |
246 // save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore, sethi, jmpl, restore | 228 const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + |
247 const int basic = (20 LP64_ONLY(+ 6)) * BytesPerInstWord + | |
248 // shift;add for load_klass | 229 // shift;add for load_klass |
249 (UseCompressedOops ? 2*BytesPerInstWord : 0); | 230 (UseCompressedOops ? 2*BytesPerInstWord : 0); |
250 return (basic + slop); | 231 return (basic + slop); |
251 } | 232 } |
252 } | 233 } |