Mercurial > hg > graal-compiler
annotate src/cpu/sparc/vm/templateTable_sparc.cpp @ 1708:a03ae377b2e8
6930581: G1: assert(ParallelGCThreads > 1 || n_yielded() == _hrrs->occupied(),"Should have yielded all the ..
Summary: During RSet updating, when ParallelGCThreads is zero, references that point into the collection set are added directly the referenced region's RSet. This can cause the sparse table in the RSet to expand. RSet scanning and the "occupied" routine will then operate on different instances of the sparse table causing the assert to trip. This may also cause some cards added post expansion to be missed during RSet scanning. When ParallelGCThreads is non-zero such references are recorded on the "references to be scanned" queue and the card containing the reference is recorded in a dirty card queue for use in the event of an evacuation failure. Employ the parallel code in the serial case to avoid expanding the RSets of regions in the collection set.
Reviewed-by: iveresov, ysr, tonyp
author | johnc |
---|---|
date | Fri, 06 Aug 2010 10:17:21 -0700 |
parents | 136b78722a08 |
children | 126ea7725993 |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 #include "incls/_precompiled.incl" | |
26 #include "incls/_templateTable_sparc.cpp.incl" | |
27 | |
28 #ifndef CC_INTERP | |
29 #define __ _masm-> | |
30 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
31 // Misc helpers |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
32 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
33 // Do an oop store like *(base + index + offset) = val |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
34 // index can be noreg, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
35 static void do_oop_store(InterpreterMacroAssembler* _masm, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
36 Register base, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
37 Register index, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
38 int offset, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
39 Register val, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
40 Register tmp, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
41 BarrierSet::Name barrier, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
42 bool precise) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
43 assert(tmp != val && tmp != base && tmp != index, "register collision"); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
44 assert(index == noreg || offset == 0, "only one offset"); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
45 switch (barrier) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
46 #ifndef SERIALGC |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
47 case BarrierSet::G1SATBCT: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
48 case BarrierSet::G1SATBCTLogging: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
49 { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
50 __ g1_write_barrier_pre( base, index, offset, tmp, /*preserve_o_regs*/true); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
51 if (index == noreg ) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
52 assert(Assembler::is_simm13(offset), "fix this code"); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
53 __ store_heap_oop(val, base, offset); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
54 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
55 __ store_heap_oop(val, base, index); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
56 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
57 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
58 // No need for post barrier if storing NULL |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
59 if (val != G0) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
60 if (precise) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
61 if (index == noreg) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
62 __ add(base, offset, base); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
63 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
64 __ add(base, index, base); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
65 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
66 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
67 __ g1_write_barrier_post(base, val, tmp); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
68 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
69 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
70 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
71 #endif // SERIALGC |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
72 case BarrierSet::CardTableModRef: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
73 case BarrierSet::CardTableExtension: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
74 { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
75 if (index == noreg ) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
76 assert(Assembler::is_simm13(offset), "fix this code"); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
77 __ store_heap_oop(val, base, offset); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
78 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
79 __ store_heap_oop(val, base, index); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
80 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
81 // No need for post barrier if storing NULL |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
82 if (val != G0) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
83 if (precise) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
84 if (index == noreg) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
85 __ add(base, offset, base); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
86 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
87 __ add(base, index, base); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
88 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
89 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
90 __ card_write_barrier_post(base, val, tmp); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
91 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
92 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
93 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
94 case BarrierSet::ModRef: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
95 case BarrierSet::Other: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
96 ShouldNotReachHere(); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
97 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
98 default : |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
99 ShouldNotReachHere(); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
100 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
101 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
102 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
103 |
0 | 104 |
105 //---------------------------------------------------------------------------------------------------- | |
106 // Platform-dependent initialization | |
107 | |
108 void TemplateTable::pd_initialize() { | |
109 // (none) | |
110 } | |
111 | |
112 | |
113 //---------------------------------------------------------------------------------------------------- | |
114 // Condition conversion | |
115 Assembler::Condition ccNot(TemplateTable::Condition cc) { | |
116 switch (cc) { | |
117 case TemplateTable::equal : return Assembler::notEqual; | |
118 case TemplateTable::not_equal : return Assembler::equal; | |
119 case TemplateTable::less : return Assembler::greaterEqual; | |
120 case TemplateTable::less_equal : return Assembler::greater; | |
121 case TemplateTable::greater : return Assembler::lessEqual; | |
122 case TemplateTable::greater_equal: return Assembler::less; | |
123 } | |
124 ShouldNotReachHere(); | |
125 return Assembler::zero; | |
126 } | |
127 | |
128 //---------------------------------------------------------------------------------------------------- | |
129 // Miscelaneous helper routines | |
130 | |
131 | |
132 Address TemplateTable::at_bcp(int offset) { | |
133 assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); | |
727 | 134 return Address(Lbcp, offset); |
0 | 135 } |
136 | |
137 | |
138 void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register Rbyte_code, | |
139 Register Rscratch, | |
140 bool load_bc_into_scratch /*=true*/) { | |
141 // With sharing on, may need to test methodOop flag. | |
142 if (!RewriteBytecodes) return; | |
143 if (load_bc_into_scratch) __ set(bc, Rbyte_code); | |
144 Label patch_done; | |
145 if (JvmtiExport::can_post_breakpoint()) { | |
146 Label fast_patch; | |
147 __ ldub(at_bcp(0), Rscratch); | |
148 __ cmp(Rscratch, Bytecodes::_breakpoint); | |
149 __ br(Assembler::notEqual, false, Assembler::pt, fast_patch); | |
150 __ delayed()->nop(); // don't bother to hoist the stb here | |
151 // perform the quickening, slowly, in the bowels of the breakpoint table | |
152 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), Lmethod, Lbcp, Rbyte_code); | |
153 __ ba(false, patch_done); | |
154 __ delayed()->nop(); | |
155 __ bind(fast_patch); | |
156 } | |
157 #ifdef ASSERT | |
158 Bytecodes::Code orig_bytecode = Bytecodes::java_code(bc); | |
159 Label okay; | |
160 __ ldub(at_bcp(0), Rscratch); | |
161 __ cmp(Rscratch, orig_bytecode); | |
162 __ br(Assembler::equal, false, Assembler::pt, okay); | |
163 __ delayed() ->cmp(Rscratch, Rbyte_code); | |
164 __ br(Assembler::equal, false, Assembler::pt, okay); | |
165 __ delayed()->nop(); | |
166 __ stop("Rewriting wrong bytecode location"); | |
167 __ bind(okay); | |
168 #endif | |
169 __ stb(Rbyte_code, at_bcp(0)); | |
170 __ bind(patch_done); | |
171 } | |
172 | |
173 //---------------------------------------------------------------------------------------------------- | |
174 // Individual instructions | |
175 | |
176 void TemplateTable::nop() { | |
177 transition(vtos, vtos); | |
178 // nothing to do | |
179 } | |
180 | |
181 void TemplateTable::shouldnotreachhere() { | |
182 transition(vtos, vtos); | |
183 __ stop("shouldnotreachhere bytecode"); | |
184 } | |
185 | |
186 void TemplateTable::aconst_null() { | |
187 transition(vtos, atos); | |
188 __ clr(Otos_i); | |
189 } | |
190 | |
191 | |
192 void TemplateTable::iconst(int value) { | |
193 transition(vtos, itos); | |
194 __ set(value, Otos_i); | |
195 } | |
196 | |
197 | |
198 void TemplateTable::lconst(int value) { | |
199 transition(vtos, ltos); | |
200 assert(value >= 0, "check this code"); | |
201 #ifdef _LP64 | |
202 __ set(value, Otos_l); | |
203 #else | |
204 __ set(value, Otos_l2); | |
205 __ clr( Otos_l1); | |
206 #endif | |
207 } | |
208 | |
209 | |
210 void TemplateTable::fconst(int value) { | |
211 transition(vtos, ftos); | |
212 static float zero = 0.0, one = 1.0, two = 2.0; | |
213 float* p; | |
214 switch( value ) { | |
215 default: ShouldNotReachHere(); | |
216 case 0: p = &zero; break; | |
217 case 1: p = &one; break; | |
218 case 2: p = &two; break; | |
219 } | |
727 | 220 AddressLiteral a(p); |
221 __ sethi(a, G3_scratch); | |
222 __ ldf(FloatRegisterImpl::S, G3_scratch, a.low10(), Ftos_f); | |
0 | 223 } |
224 | |
225 | |
226 void TemplateTable::dconst(int value) { | |
227 transition(vtos, dtos); | |
228 static double zero = 0.0, one = 1.0; | |
229 double* p; | |
230 switch( value ) { | |
231 default: ShouldNotReachHere(); | |
232 case 0: p = &zero; break; | |
233 case 1: p = &one; break; | |
234 } | |
727 | 235 AddressLiteral a(p); |
236 __ sethi(a, G3_scratch); | |
237 __ ldf(FloatRegisterImpl::D, G3_scratch, a.low10(), Ftos_d); | |
0 | 238 } |
239 | |
240 | |
241 // %%%%% Should factore most snippet templates across platforms | |
242 | |
243 void TemplateTable::bipush() { | |
244 transition(vtos, itos); | |
245 __ ldsb( at_bcp(1), Otos_i ); | |
246 } | |
247 | |
248 void TemplateTable::sipush() { | |
249 transition(vtos, itos); | |
250 __ get_2_byte_integer_at_bcp(1, G3_scratch, Otos_i, InterpreterMacroAssembler::Signed); | |
251 } | |
252 | |
253 void TemplateTable::ldc(bool wide) { | |
254 transition(vtos, vtos); | |
255 Label call_ldc, notInt, notString, notClass, exit; | |
256 | |
257 if (wide) { | |
258 __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned); | |
259 } else { | |
260 __ ldub(Lbcp, 1, O1); | |
261 } | |
262 __ get_cpool_and_tags(O0, O2); | |
263 | |
264 const int base_offset = constantPoolOopDesc::header_size() * wordSize; | |
265 const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; | |
266 | |
267 // get type from tags | |
268 __ add(O2, tags_offset, O2); | |
269 __ ldub(O2, O1, O2); | |
270 __ cmp(O2, JVM_CONSTANT_UnresolvedString); // unresolved string? If so, must resolve | |
271 __ brx(Assembler::equal, true, Assembler::pt, call_ldc); | |
272 __ delayed()->nop(); | |
273 | |
274 __ cmp(O2, JVM_CONSTANT_UnresolvedClass); // unresolved class? If so, must resolve | |
275 __ brx(Assembler::equal, true, Assembler::pt, call_ldc); | |
276 __ delayed()->nop(); | |
277 | |
278 __ cmp(O2, JVM_CONSTANT_UnresolvedClassInError); // unresolved class in error state | |
279 __ brx(Assembler::equal, true, Assembler::pn, call_ldc); | |
280 __ delayed()->nop(); | |
281 | |
282 __ cmp(O2, JVM_CONSTANT_Class); // need to call vm to get java mirror of the class | |
283 __ brx(Assembler::notEqual, true, Assembler::pt, notClass); | |
284 __ delayed()->add(O0, base_offset, O0); | |
285 | |
286 __ bind(call_ldc); | |
287 __ set(wide, O1); | |
288 call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), O1); | |
289 __ push(atos); | |
290 __ ba(false, exit); | |
291 __ delayed()->nop(); | |
292 | |
293 __ bind(notClass); | |
294 // __ add(O0, base_offset, O0); | |
295 __ sll(O1, LogBytesPerWord, O1); | |
296 __ cmp(O2, JVM_CONSTANT_Integer); | |
297 __ brx(Assembler::notEqual, true, Assembler::pt, notInt); | |
298 __ delayed()->cmp(O2, JVM_CONSTANT_String); | |
299 __ ld(O0, O1, Otos_i); | |
300 __ push(itos); | |
301 __ ba(false, exit); | |
302 __ delayed()->nop(); | |
303 | |
304 __ bind(notInt); | |
305 // __ cmp(O2, JVM_CONSTANT_String); | |
306 __ brx(Assembler::notEqual, true, Assembler::pt, notString); | |
307 __ delayed()->ldf(FloatRegisterImpl::S, O0, O1, Ftos_f); | |
308 __ ld_ptr(O0, O1, Otos_i); | |
309 __ verify_oop(Otos_i); | |
310 __ push(atos); | |
311 __ ba(false, exit); | |
312 __ delayed()->nop(); | |
313 | |
314 __ bind(notString); | |
315 // __ ldf(FloatRegisterImpl::S, O0, O1, Ftos_f); | |
316 __ push(ftos); | |
317 | |
318 __ bind(exit); | |
319 } | |
320 | |
1602 | 321 // Fast path for caching oop constants. |
322 // %%% We should use this to handle Class and String constants also. | |
323 // %%% It will simplify the ldc/primitive path considerably. | |
324 void TemplateTable::fast_aldc(bool wide) { | |
325 transition(vtos, atos); | |
326 | |
327 if (!EnableMethodHandles) { | |
328 // We should not encounter this bytecode if !EnableMethodHandles. | |
329 // The verifier will stop it. However, if we get past the verifier, | |
330 // this will stop the thread in a reasonable way, without crashing the JVM. | |
331 __ call_VM(noreg, CAST_FROM_FN_PTR(address, | |
332 InterpreterRuntime::throw_IncompatibleClassChangeError)); | |
333 // the call_VM checks for exception, so we should never return here. | |
334 __ should_not_reach_here(); | |
335 return; | |
336 } | |
337 | |
338 Register Rcache = G3_scratch; | |
339 Register Rscratch = G4_scratch; | |
340 | |
341 resolve_cache_and_index(f1_oop, Otos_i, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1)); | |
342 | |
343 __ verify_oop(Otos_i); | |
344 } | |
345 | |
0 | 346 void TemplateTable::ldc2_w() { |
347 transition(vtos, vtos); | |
348 Label retry, resolved, Long, exit; | |
349 | |
350 __ bind(retry); | |
351 __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned); | |
352 __ get_cpool_and_tags(O0, O2); | |
353 | |
354 const int base_offset = constantPoolOopDesc::header_size() * wordSize; | |
355 const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; | |
356 // get type from tags | |
357 __ add(O2, tags_offset, O2); | |
358 __ ldub(O2, O1, O2); | |
359 | |
360 __ sll(O1, LogBytesPerWord, O1); | |
361 __ add(O0, O1, G3_scratch); | |
362 | |
363 __ cmp(O2, JVM_CONSTANT_Double); | |
364 __ brx(Assembler::notEqual, false, Assembler::pt, Long); | |
365 __ delayed()->nop(); | |
366 // A double can be placed at word-aligned locations in the constant pool. | |
367 // Check out Conversions.java for an example. | |
368 // Also constantPoolOopDesc::header_size() is 20, which makes it very difficult | |
369 // to double-align double on the constant pool. SG, 11/7/97 | |
370 #ifdef _LP64 | |
371 __ ldf(FloatRegisterImpl::D, G3_scratch, base_offset, Ftos_d); | |
372 #else | |
373 FloatRegister f = Ftos_d; | |
374 __ ldf(FloatRegisterImpl::S, G3_scratch, base_offset, f); | |
375 __ ldf(FloatRegisterImpl::S, G3_scratch, base_offset + sizeof(jdouble)/2, | |
376 f->successor()); | |
377 #endif | |
378 __ push(dtos); | |
379 __ ba(false, exit); | |
380 __ delayed()->nop(); | |
381 | |
382 __ bind(Long); | |
383 #ifdef _LP64 | |
384 __ ldx(G3_scratch, base_offset, Otos_l); | |
385 #else | |
386 __ ld(G3_scratch, base_offset, Otos_l); | |
387 __ ld(G3_scratch, base_offset + sizeof(jlong)/2, Otos_l->successor()); | |
388 #endif | |
389 __ push(ltos); | |
390 | |
391 __ bind(exit); | |
392 } | |
393 | |
394 | |
395 void TemplateTable::locals_index(Register reg, int offset) { | |
396 __ ldub( at_bcp(offset), reg ); | |
397 } | |
398 | |
399 | |
400 void TemplateTable::locals_index_wide(Register reg) { | |
401 // offset is 2, not 1, because Lbcp points to wide prefix code | |
402 __ get_2_byte_integer_at_bcp(2, G4_scratch, reg, InterpreterMacroAssembler::Unsigned); | |
403 } | |
404 | |
405 void TemplateTable::iload() { | |
406 transition(vtos, itos); | |
407 // Rewrite iload,iload pair into fast_iload2 | |
408 // iload,caload pair into fast_icaload | |
409 if (RewriteFrequentPairs) { | |
410 Label rewrite, done; | |
411 | |
412 // get next byte | |
413 __ ldub(at_bcp(Bytecodes::length_for(Bytecodes::_iload)), G3_scratch); | |
414 | |
415 // if _iload, wait to rewrite to iload2. We only want to rewrite the | |
416 // last two iloads in a pair. Comparing against fast_iload means that | |
417 // the next bytecode is neither an iload or a caload, and therefore | |
418 // an iload pair. | |
419 __ cmp(G3_scratch, (int)Bytecodes::_iload); | |
420 __ br(Assembler::equal, false, Assembler::pn, done); | |
421 __ delayed()->nop(); | |
422 | |
423 __ cmp(G3_scratch, (int)Bytecodes::_fast_iload); | |
424 __ br(Assembler::equal, false, Assembler::pn, rewrite); | |
425 __ delayed()->set(Bytecodes::_fast_iload2, G4_scratch); | |
426 | |
427 __ cmp(G3_scratch, (int)Bytecodes::_caload); | |
428 __ br(Assembler::equal, false, Assembler::pn, rewrite); | |
429 __ delayed()->set(Bytecodes::_fast_icaload, G4_scratch); | |
430 | |
431 __ set(Bytecodes::_fast_iload, G4_scratch); // don't check again | |
432 // rewrite | |
433 // G4_scratch: fast bytecode | |
434 __ bind(rewrite); | |
435 patch_bytecode(Bytecodes::_iload, G4_scratch, G3_scratch, false); | |
436 __ bind(done); | |
437 } | |
438 | |
439 // Get the local value into tos | |
440 locals_index(G3_scratch); | |
441 __ access_local_int( G3_scratch, Otos_i ); | |
442 } | |
443 | |
444 void TemplateTable::fast_iload2() { | |
445 transition(vtos, itos); | |
446 locals_index(G3_scratch); | |
447 __ access_local_int( G3_scratch, Otos_i ); | |
448 __ push_i(); | |
449 locals_index(G3_scratch, 3); // get next bytecode's local index. | |
450 __ access_local_int( G3_scratch, Otos_i ); | |
451 } | |
452 | |
453 void TemplateTable::fast_iload() { | |
454 transition(vtos, itos); | |
455 locals_index(G3_scratch); | |
456 __ access_local_int( G3_scratch, Otos_i ); | |
457 } | |
458 | |
459 void TemplateTable::lload() { | |
460 transition(vtos, ltos); | |
461 locals_index(G3_scratch); | |
462 __ access_local_long( G3_scratch, Otos_l ); | |
463 } | |
464 | |
465 | |
466 void TemplateTable::fload() { | |
467 transition(vtos, ftos); | |
468 locals_index(G3_scratch); | |
469 __ access_local_float( G3_scratch, Ftos_f ); | |
470 } | |
471 | |
472 | |
473 void TemplateTable::dload() { | |
474 transition(vtos, dtos); | |
475 locals_index(G3_scratch); | |
476 __ access_local_double( G3_scratch, Ftos_d ); | |
477 } | |
478 | |
479 | |
480 void TemplateTable::aload() { | |
481 transition(vtos, atos); | |
482 locals_index(G3_scratch); | |
483 __ access_local_ptr( G3_scratch, Otos_i); | |
484 } | |
485 | |
486 | |
487 void TemplateTable::wide_iload() { | |
488 transition(vtos, itos); | |
489 locals_index_wide(G3_scratch); | |
490 __ access_local_int( G3_scratch, Otos_i ); | |
491 } | |
492 | |
493 | |
494 void TemplateTable::wide_lload() { | |
495 transition(vtos, ltos); | |
496 locals_index_wide(G3_scratch); | |
497 __ access_local_long( G3_scratch, Otos_l ); | |
498 } | |
499 | |
500 | |
501 void TemplateTable::wide_fload() { | |
502 transition(vtos, ftos); | |
503 locals_index_wide(G3_scratch); | |
504 __ access_local_float( G3_scratch, Ftos_f ); | |
505 } | |
506 | |
507 | |
508 void TemplateTable::wide_dload() { | |
509 transition(vtos, dtos); | |
510 locals_index_wide(G3_scratch); | |
511 __ access_local_double( G3_scratch, Ftos_d ); | |
512 } | |
513 | |
514 | |
515 void TemplateTable::wide_aload() { | |
516 transition(vtos, atos); | |
517 locals_index_wide(G3_scratch); | |
518 __ access_local_ptr( G3_scratch, Otos_i ); | |
519 __ verify_oop(Otos_i); | |
520 } | |
521 | |
522 | |
523 void TemplateTable::iaload() { | |
524 transition(itos, itos); | |
525 // Otos_i: index | |
526 // tos: array | |
527 __ index_check(O2, Otos_i, LogBytesPerInt, G3_scratch, O3); | |
528 __ ld(O3, arrayOopDesc::base_offset_in_bytes(T_INT), Otos_i); | |
529 } | |
530 | |
531 | |
532 void TemplateTable::laload() { | |
533 transition(itos, ltos); | |
534 // Otos_i: index | |
535 // O2: array | |
536 __ index_check(O2, Otos_i, LogBytesPerLong, G3_scratch, O3); | |
537 __ ld_long(O3, arrayOopDesc::base_offset_in_bytes(T_LONG), Otos_l); | |
538 } | |
539 | |
540 | |
541 void TemplateTable::faload() { | |
542 transition(itos, ftos); | |
543 // Otos_i: index | |
544 // O2: array | |
545 __ index_check(O2, Otos_i, LogBytesPerInt, G3_scratch, O3); | |
546 __ ldf(FloatRegisterImpl::S, O3, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Ftos_f); | |
547 } | |
548 | |
549 | |
550 void TemplateTable::daload() { | |
551 transition(itos, dtos); | |
552 // Otos_i: index | |
553 // O2: array | |
554 __ index_check(O2, Otos_i, LogBytesPerLong, G3_scratch, O3); | |
555 __ ldf(FloatRegisterImpl::D, O3, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Ftos_d); | |
556 } | |
557 | |
558 | |
559 void TemplateTable::aaload() { | |
560 transition(itos, atos); | |
561 // Otos_i: index | |
562 // tos: array | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
563 __ index_check(O2, Otos_i, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O3); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
564 __ load_heap_oop(O3, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i); |
0 | 565 __ verify_oop(Otos_i); |
566 } | |
567 | |
568 | |
569 void TemplateTable::baload() { | |
570 transition(itos, itos); | |
571 // Otos_i: index | |
572 // tos: array | |
573 __ index_check(O2, Otos_i, 0, G3_scratch, O3); | |
574 __ ldsb(O3, arrayOopDesc::base_offset_in_bytes(T_BYTE), Otos_i); | |
575 } | |
576 | |
577 | |
578 void TemplateTable::caload() { | |
579 transition(itos, itos); | |
580 // Otos_i: index | |
581 // tos: array | |
582 __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3); | |
583 __ lduh(O3, arrayOopDesc::base_offset_in_bytes(T_CHAR), Otos_i); | |
584 } | |
585 | |
586 void TemplateTable::fast_icaload() { | |
587 transition(vtos, itos); | |
588 // Otos_i: index | |
589 // tos: array | |
590 locals_index(G3_scratch); | |
591 __ access_local_int( G3_scratch, Otos_i ); | |
592 __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3); | |
593 __ lduh(O3, arrayOopDesc::base_offset_in_bytes(T_CHAR), Otos_i); | |
594 } | |
595 | |
596 | |
597 void TemplateTable::saload() { | |
598 transition(itos, itos); | |
599 // Otos_i: index | |
600 // tos: array | |
601 __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3); | |
602 __ ldsh(O3, arrayOopDesc::base_offset_in_bytes(T_SHORT), Otos_i); | |
603 } | |
604 | |
605 | |
606 void TemplateTable::iload(int n) { | |
607 transition(vtos, itos); | |
608 __ ld( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i ); | |
609 } | |
610 | |
611 | |
612 void TemplateTable::lload(int n) { | |
613 transition(vtos, ltos); | |
614 assert(n+1 < Argument::n_register_parameters, "would need more code"); | |
615 __ load_unaligned_long(Llocals, Interpreter::local_offset_in_bytes(n+1), Otos_l); | |
616 } | |
617 | |
618 | |
619 void TemplateTable::fload(int n) { | |
620 transition(vtos, ftos); | |
621 assert(n < Argument::n_register_parameters, "would need more code"); | |
622 __ ldf( FloatRegisterImpl::S, Llocals, Interpreter::local_offset_in_bytes(n), Ftos_f ); | |
623 } | |
624 | |
625 | |
626 void TemplateTable::dload(int n) { | |
627 transition(vtos, dtos); | |
628 FloatRegister dst = Ftos_d; | |
629 __ load_unaligned_double(Llocals, Interpreter::local_offset_in_bytes(n+1), dst); | |
630 } | |
631 | |
632 | |
633 void TemplateTable::aload(int n) { | |
634 transition(vtos, atos); | |
635 __ ld_ptr( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i ); | |
636 } | |
637 | |
638 | |
639 void TemplateTable::aload_0() { | |
640 transition(vtos, atos); | |
641 | |
642 // According to bytecode histograms, the pairs: | |
643 // | |
644 // _aload_0, _fast_igetfield (itos) | |
645 // _aload_0, _fast_agetfield (atos) | |
646 // _aload_0, _fast_fgetfield (ftos) | |
647 // | |
648 // occur frequently. If RewriteFrequentPairs is set, the (slow) _aload_0 | |
649 // bytecode checks the next bytecode and then rewrites the current | |
650 // bytecode into a pair bytecode; otherwise it rewrites the current | |
651 // bytecode into _fast_aload_0 that doesn't do the pair check anymore. | |
652 // | |
653 if (RewriteFrequentPairs) { | |
654 Label rewrite, done; | |
655 | |
656 // get next byte | |
657 __ ldub(at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)), G3_scratch); | |
658 | |
659 // do actual aload_0 | |
660 aload(0); | |
661 | |
662 // if _getfield then wait with rewrite | |
663 __ cmp(G3_scratch, (int)Bytecodes::_getfield); | |
664 __ br(Assembler::equal, false, Assembler::pn, done); | |
665 __ delayed()->nop(); | |
666 | |
667 // if _igetfield then rewrite to _fast_iaccess_0 | |
668 assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); | |
669 __ cmp(G3_scratch, (int)Bytecodes::_fast_igetfield); | |
670 __ br(Assembler::equal, false, Assembler::pn, rewrite); | |
671 __ delayed()->set(Bytecodes::_fast_iaccess_0, G4_scratch); | |
672 | |
673 // if _agetfield then rewrite to _fast_aaccess_0 | |
674 assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); | |
675 __ cmp(G3_scratch, (int)Bytecodes::_fast_agetfield); | |
676 __ br(Assembler::equal, false, Assembler::pn, rewrite); | |
677 __ delayed()->set(Bytecodes::_fast_aaccess_0, G4_scratch); | |
678 | |
679 // if _fgetfield then rewrite to _fast_faccess_0 | |
680 assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); | |
681 __ cmp(G3_scratch, (int)Bytecodes::_fast_fgetfield); | |
682 __ br(Assembler::equal, false, Assembler::pn, rewrite); | |
683 __ delayed()->set(Bytecodes::_fast_faccess_0, G4_scratch); | |
684 | |
685 // else rewrite to _fast_aload0 | |
686 assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); | |
687 __ set(Bytecodes::_fast_aload_0, G4_scratch); | |
688 | |
689 // rewrite | |
690 // G4_scratch: fast bytecode | |
691 __ bind(rewrite); | |
692 patch_bytecode(Bytecodes::_aload_0, G4_scratch, G3_scratch, false); | |
693 __ bind(done); | |
694 } else { | |
695 aload(0); | |
696 } | |
697 } | |
698 | |
699 | |
700 void TemplateTable::istore() { | |
701 transition(itos, vtos); | |
702 locals_index(G3_scratch); | |
703 __ store_local_int( G3_scratch, Otos_i ); | |
704 } | |
705 | |
706 | |
707 void TemplateTable::lstore() { | |
708 transition(ltos, vtos); | |
709 locals_index(G3_scratch); | |
710 __ store_local_long( G3_scratch, Otos_l ); | |
711 } | |
712 | |
713 | |
714 void TemplateTable::fstore() { | |
715 transition(ftos, vtos); | |
716 locals_index(G3_scratch); | |
717 __ store_local_float( G3_scratch, Ftos_f ); | |
718 } | |
719 | |
720 | |
721 void TemplateTable::dstore() { | |
722 transition(dtos, vtos); | |
723 locals_index(G3_scratch); | |
724 __ store_local_double( G3_scratch, Ftos_d ); | |
725 } | |
726 | |
727 | |
728 void TemplateTable::astore() { | |
729 transition(vtos, vtos); | |
1506 | 730 __ load_ptr(0, Otos_i); |
731 __ inc(Lesp, Interpreter::stackElementSize); | |
0 | 732 __ verify_oop_or_return_address(Otos_i, G3_scratch); |
733 locals_index(G3_scratch); | |
1506 | 734 __ store_local_ptr(G3_scratch, Otos_i); |
0 | 735 } |
736 | |
737 | |
738 void TemplateTable::wide_istore() { | |
739 transition(vtos, vtos); | |
740 __ pop_i(); | |
741 locals_index_wide(G3_scratch); | |
742 __ store_local_int( G3_scratch, Otos_i ); | |
743 } | |
744 | |
745 | |
746 void TemplateTable::wide_lstore() { | |
747 transition(vtos, vtos); | |
748 __ pop_l(); | |
749 locals_index_wide(G3_scratch); | |
750 __ store_local_long( G3_scratch, Otos_l ); | |
751 } | |
752 | |
753 | |
754 void TemplateTable::wide_fstore() { | |
755 transition(vtos, vtos); | |
756 __ pop_f(); | |
757 locals_index_wide(G3_scratch); | |
758 __ store_local_float( G3_scratch, Ftos_f ); | |
759 } | |
760 | |
761 | |
762 void TemplateTable::wide_dstore() { | |
763 transition(vtos, vtos); | |
764 __ pop_d(); | |
765 locals_index_wide(G3_scratch); | |
766 __ store_local_double( G3_scratch, Ftos_d ); | |
767 } | |
768 | |
769 | |
770 void TemplateTable::wide_astore() { | |
771 transition(vtos, vtos); | |
1506 | 772 __ load_ptr(0, Otos_i); |
773 __ inc(Lesp, Interpreter::stackElementSize); | |
0 | 774 __ verify_oop_or_return_address(Otos_i, G3_scratch); |
775 locals_index_wide(G3_scratch); | |
1506 | 776 __ store_local_ptr(G3_scratch, Otos_i); |
0 | 777 } |
778 | |
779 | |
780 void TemplateTable::iastore() { | |
781 transition(itos, vtos); | |
782 __ pop_i(O2); // index | |
783 // Otos_i: val | |
784 // O3: array | |
785 __ index_check(O3, O2, LogBytesPerInt, G3_scratch, O2); | |
786 __ st(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_INT)); | |
787 } | |
788 | |
789 | |
790 void TemplateTable::lastore() { | |
791 transition(ltos, vtos); | |
792 __ pop_i(O2); // index | |
793 // Otos_l: val | |
794 // O3: array | |
795 __ index_check(O3, O2, LogBytesPerLong, G3_scratch, O2); | |
796 __ st_long(Otos_l, O2, arrayOopDesc::base_offset_in_bytes(T_LONG)); | |
797 } | |
798 | |
799 | |
800 void TemplateTable::fastore() { | |
801 transition(ftos, vtos); | |
802 __ pop_i(O2); // index | |
803 // Ftos_f: val | |
804 // O3: array | |
805 __ index_check(O3, O2, LogBytesPerInt, G3_scratch, O2); | |
806 __ stf(FloatRegisterImpl::S, Ftos_f, O2, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); | |
807 } | |
808 | |
809 | |
810 void TemplateTable::dastore() { | |
811 transition(dtos, vtos); | |
812 __ pop_i(O2); // index | |
813 // Fos_d: val | |
814 // O3: array | |
815 __ index_check(O3, O2, LogBytesPerLong, G3_scratch, O2); | |
816 __ stf(FloatRegisterImpl::D, Ftos_d, O2, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)); | |
817 } | |
818 | |
819 | |
820 void TemplateTable::aastore() { | |
821 Label store_ok, is_null, done; | |
822 transition(vtos, vtos); | |
823 __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i); | |
824 __ ld(Lesp, Interpreter::expr_offset_in_bytes(1), O2); // get index | |
825 __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(2), O3); // get array | |
826 // Otos_i: val | |
827 // O2: index | |
828 // O3: array | |
829 __ verify_oop(Otos_i); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
830 __ index_check_without_pop(O3, O2, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O1); |
0 | 831 |
832 // do array store check - check for NULL value first | |
833 __ br_null( Otos_i, false, Assembler::pn, is_null ); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
834 __ delayed()->nop(); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
835 |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
836 __ load_klass(O3, O4); // get array klass |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
837 __ load_klass(Otos_i, O5); // get value klass |
0 | 838 |
839 // do fast instanceof cache test | |
840 | |
841 __ ld_ptr(O4, sizeof(oopDesc) + objArrayKlass::element_klass_offset_in_bytes(), O4); | |
842 | |
843 assert(Otos_i == O0, "just checking"); | |
844 | |
845 // Otos_i: value | |
846 // O1: addr - offset | |
847 // O2: index | |
848 // O3: array | |
849 // O4: array element klass | |
850 // O5: value klass | |
851 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
852 // Address element(O1, 0, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
853 |
0 | 854 // Generate a fast subtype check. Branch to store_ok if no |
855 // failure. Throw if failure. | |
856 __ gen_subtype_check( O5, O4, G3_scratch, G4_scratch, G1_scratch, store_ok ); | |
857 | |
858 // Not a subtype; so must throw exception | |
859 __ throw_if_not_x( Assembler::never, Interpreter::_throw_ArrayStoreException_entry, G3_scratch ); | |
860 | |
861 // Store is OK. | |
862 __ bind(store_ok); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
863 do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i, G3_scratch, _bs->kind(), true); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
864 |
0 | 865 __ ba(false,done); |
1506 | 866 __ delayed()->inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value) |
0 | 867 |
868 __ bind(is_null); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
869 do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), G0, G4_scratch, _bs->kind(), true); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
870 |
0 | 871 __ profile_null_seen(G3_scratch); |
1506 | 872 __ inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value) |
0 | 873 __ bind(done); |
874 } | |
875 | |
876 | |
877 void TemplateTable::bastore() { | |
878 transition(itos, vtos); | |
879 __ pop_i(O2); // index | |
880 // Otos_i: val | |
881 // O3: array | |
882 __ index_check(O3, O2, 0, G3_scratch, O2); | |
883 __ stb(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_BYTE)); | |
884 } | |
885 | |
886 | |
887 void TemplateTable::castore() { | |
888 transition(itos, vtos); | |
889 __ pop_i(O2); // index | |
890 // Otos_i: val | |
891 // O3: array | |
892 __ index_check(O3, O2, LogBytesPerShort, G3_scratch, O2); | |
893 __ sth(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_CHAR)); | |
894 } | |
895 | |
896 | |
897 void TemplateTable::sastore() { | |
898 // %%%%% Factor across platform | |
899 castore(); | |
900 } | |
901 | |
902 | |
903 void TemplateTable::istore(int n) { | |
904 transition(itos, vtos); | |
905 __ st(Otos_i, Llocals, Interpreter::local_offset_in_bytes(n)); | |
906 } | |
907 | |
908 | |
909 void TemplateTable::lstore(int n) { | |
910 transition(ltos, vtos); | |
911 assert(n+1 < Argument::n_register_parameters, "only handle register cases"); | |
912 __ store_unaligned_long(Otos_l, Llocals, Interpreter::local_offset_in_bytes(n+1)); | |
913 | |
914 } | |
915 | |
916 | |
917 void TemplateTable::fstore(int n) { | |
918 transition(ftos, vtos); | |
919 assert(n < Argument::n_register_parameters, "only handle register cases"); | |
920 __ stf(FloatRegisterImpl::S, Ftos_f, Llocals, Interpreter::local_offset_in_bytes(n)); | |
921 } | |
922 | |
923 | |
924 void TemplateTable::dstore(int n) { | |
925 transition(dtos, vtos); | |
926 FloatRegister src = Ftos_d; | |
927 __ store_unaligned_double(src, Llocals, Interpreter::local_offset_in_bytes(n+1)); | |
928 } | |
929 | |
930 | |
931 void TemplateTable::astore(int n) { | |
932 transition(vtos, vtos); | |
1506 | 933 __ load_ptr(0, Otos_i); |
934 __ inc(Lesp, Interpreter::stackElementSize); | |
0 | 935 __ verify_oop_or_return_address(Otos_i, G3_scratch); |
1506 | 936 __ store_local_ptr(n, Otos_i); |
0 | 937 } |
938 | |
939 | |
940 void TemplateTable::pop() { | |
941 transition(vtos, vtos); | |
1506 | 942 __ inc(Lesp, Interpreter::stackElementSize); |
0 | 943 } |
944 | |
945 | |
946 void TemplateTable::pop2() { | |
947 transition(vtos, vtos); | |
1506 | 948 __ inc(Lesp, 2 * Interpreter::stackElementSize); |
0 | 949 } |
950 | |
951 | |
952 void TemplateTable::dup() { | |
953 transition(vtos, vtos); | |
954 // stack: ..., a | |
955 // load a and tag | |
1506 | 956 __ load_ptr(0, Otos_i); |
957 __ push_ptr(Otos_i); | |
0 | 958 // stack: ..., a, a |
959 } | |
960 | |
961 | |
962 void TemplateTable::dup_x1() { | |
963 transition(vtos, vtos); | |
964 // stack: ..., a, b | |
1506 | 965 __ load_ptr( 1, G3_scratch); // get a |
966 __ load_ptr( 0, Otos_l1); // get b | |
967 __ store_ptr(1, Otos_l1); // put b | |
968 __ store_ptr(0, G3_scratch); // put a - like swap | |
969 __ push_ptr(Otos_l1); // push b | |
0 | 970 // stack: ..., b, a, b |
971 } | |
972 | |
973 | |
974 void TemplateTable::dup_x2() { | |
975 transition(vtos, vtos); | |
976 // stack: ..., a, b, c | |
977 // get c and push on stack, reuse registers | |
1506 | 978 __ load_ptr( 0, G3_scratch); // get c |
979 __ push_ptr(G3_scratch); // push c with tag | |
0 | 980 // stack: ..., a, b, c, c (c in reg) (Lesp - 4) |
981 // (stack offsets n+1 now) | |
1506 | 982 __ load_ptr( 3, Otos_l1); // get a |
983 __ store_ptr(3, G3_scratch); // put c at 3 | |
0 | 984 // stack: ..., c, b, c, c (a in reg) |
1506 | 985 __ load_ptr( 2, G3_scratch); // get b |
986 __ store_ptr(2, Otos_l1); // put a at 2 | |
0 | 987 // stack: ..., c, a, c, c (b in reg) |
1506 | 988 __ store_ptr(1, G3_scratch); // put b at 1 |
0 | 989 // stack: ..., c, a, b, c |
990 } | |
991 | |
992 | |
993 void TemplateTable::dup2() { | |
994 transition(vtos, vtos); | |
1506 | 995 __ load_ptr(1, G3_scratch); // get a |
996 __ load_ptr(0, Otos_l1); // get b | |
997 __ push_ptr(G3_scratch); // push a | |
998 __ push_ptr(Otos_l1); // push b | |
0 | 999 // stack: ..., a, b, a, b |
1000 } | |
1001 | |
1002 | |
1003 void TemplateTable::dup2_x1() { | |
1004 transition(vtos, vtos); | |
1005 // stack: ..., a, b, c | |
1506 | 1006 __ load_ptr( 1, Lscratch); // get b |
1007 __ load_ptr( 2, Otos_l1); // get a | |
1008 __ store_ptr(2, Lscratch); // put b at a | |
0 | 1009 // stack: ..., b, b, c |
1506 | 1010 __ load_ptr( 0, G3_scratch); // get c |
1011 __ store_ptr(1, G3_scratch); // put c at b | |
0 | 1012 // stack: ..., b, c, c |
1506 | 1013 __ store_ptr(0, Otos_l1); // put a at c |
0 | 1014 // stack: ..., b, c, a |
1506 | 1015 __ push_ptr(Lscratch); // push b |
1016 __ push_ptr(G3_scratch); // push c | |
0 | 1017 // stack: ..., b, c, a, b, c |
1018 } | |
1019 | |
1020 | |
1021 // The spec says that these types can be a mixture of category 1 (1 word) | |
1022 // types and/or category 2 types (long and doubles) | |
1023 void TemplateTable::dup2_x2() { | |
1024 transition(vtos, vtos); | |
1025 // stack: ..., a, b, c, d | |
1506 | 1026 __ load_ptr( 1, Lscratch); // get c |
1027 __ load_ptr( 3, Otos_l1); // get a | |
1028 __ store_ptr(3, Lscratch); // put c at 3 | |
1029 __ store_ptr(1, Otos_l1); // put a at 1 | |
0 | 1030 // stack: ..., c, b, a, d |
1506 | 1031 __ load_ptr( 2, G3_scratch); // get b |
1032 __ load_ptr( 0, Otos_l1); // get d | |
1033 __ store_ptr(0, G3_scratch); // put b at 0 | |
1034 __ store_ptr(2, Otos_l1); // put d at 2 | |
0 | 1035 // stack: ..., c, d, a, b |
1506 | 1036 __ push_ptr(Lscratch); // push c |
1037 __ push_ptr(Otos_l1); // push d | |
0 | 1038 // stack: ..., c, d, a, b, c, d |
1039 } | |
1040 | |
1041 | |
1042 void TemplateTable::swap() { | |
1043 transition(vtos, vtos); | |
1044 // stack: ..., a, b | |
1506 | 1045 __ load_ptr( 1, G3_scratch); // get a |
1046 __ load_ptr( 0, Otos_l1); // get b | |
1047 __ store_ptr(0, G3_scratch); // put b | |
1048 __ store_ptr(1, Otos_l1); // put a | |
0 | 1049 // stack: ..., b, a |
1050 } | |
1051 | |
1052 | |
1053 void TemplateTable::iop2(Operation op) { | |
1054 transition(itos, itos); | |
1055 __ pop_i(O1); | |
1056 switch (op) { | |
1057 case add: __ add(O1, Otos_i, Otos_i); break; | |
1058 case sub: __ sub(O1, Otos_i, Otos_i); break; | |
1059 // %%%%% Mul may not exist: better to call .mul? | |
1060 case mul: __ smul(O1, Otos_i, Otos_i); break; | |
1506 | 1061 case _and: __ and3(O1, Otos_i, Otos_i); break; |
1062 case _or: __ or3(O1, Otos_i, Otos_i); break; | |
1063 case _xor: __ xor3(O1, Otos_i, Otos_i); break; | |
0 | 1064 case shl: __ sll(O1, Otos_i, Otos_i); break; |
1065 case shr: __ sra(O1, Otos_i, Otos_i); break; | |
1066 case ushr: __ srl(O1, Otos_i, Otos_i); break; | |
1067 default: ShouldNotReachHere(); | |
1068 } | |
1069 } | |
1070 | |
1071 | |
1072 void TemplateTable::lop2(Operation op) { | |
1073 transition(ltos, ltos); | |
1074 __ pop_l(O2); | |
1075 switch (op) { | |
1076 #ifdef _LP64 | |
1506 | 1077 case add: __ add(O2, Otos_l, Otos_l); break; |
1078 case sub: __ sub(O2, Otos_l, Otos_l); break; | |
1079 case _and: __ and3(O2, Otos_l, Otos_l); break; | |
1080 case _or: __ or3(O2, Otos_l, Otos_l); break; | |
1081 case _xor: __ xor3(O2, Otos_l, Otos_l); break; | |
0 | 1082 #else |
1083 case add: __ addcc(O3, Otos_l2, Otos_l2); __ addc(O2, Otos_l1, Otos_l1); break; | |
1084 case sub: __ subcc(O3, Otos_l2, Otos_l2); __ subc(O2, Otos_l1, Otos_l1); break; | |
1506 | 1085 case _and: __ and3(O3, Otos_l2, Otos_l2); __ and3(O2, Otos_l1, Otos_l1); break; |
1086 case _or: __ or3(O3, Otos_l2, Otos_l2); __ or3(O2, Otos_l1, Otos_l1); break; | |
1087 case _xor: __ xor3(O3, Otos_l2, Otos_l2); __ xor3(O2, Otos_l1, Otos_l1); break; | |
0 | 1088 #endif |
1089 default: ShouldNotReachHere(); | |
1090 } | |
1091 } | |
1092 | |
1093 | |
1094 void TemplateTable::idiv() { | |
1095 // %%%%% Later: ForSPARC/V7 call .sdiv library routine, | |
1096 // %%%%% Use ldsw...sdivx on pure V9 ABI. 64 bit safe. | |
1097 | |
1098 transition(itos, itos); | |
1099 __ pop_i(O1); // get 1st op | |
1100 | |
1101 // Y contains upper 32 bits of result, set it to 0 or all ones | |
1102 __ wry(G0); | |
1103 __ mov(~0, G3_scratch); | |
1104 | |
1105 __ tst(O1); | |
1106 Label neg; | |
1107 __ br(Assembler::negative, true, Assembler::pn, neg); | |
1108 __ delayed()->wry(G3_scratch); | |
1109 __ bind(neg); | |
1110 | |
1111 Label ok; | |
1112 __ tst(Otos_i); | |
1113 __ throw_if_not_icc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch ); | |
1114 | |
1115 const int min_int = 0x80000000; | |
1116 Label regular; | |
1117 __ cmp(Otos_i, -1); | |
1118 __ br(Assembler::notEqual, false, Assembler::pt, regular); | |
1119 #ifdef _LP64 | |
1120 // Don't put set in delay slot | |
1121 // Set will turn into multiple instructions in 64 bit mode | |
1122 __ delayed()->nop(); | |
1123 __ set(min_int, G4_scratch); | |
1124 #else | |
1125 __ delayed()->set(min_int, G4_scratch); | |
1126 #endif | |
1127 Label done; | |
1128 __ cmp(O1, G4_scratch); | |
1129 __ br(Assembler::equal, true, Assembler::pt, done); | |
1130 __ delayed()->mov(O1, Otos_i); // (mov only executed if branch taken) | |
1131 | |
1132 __ bind(regular); | |
1133 __ sdiv(O1, Otos_i, Otos_i); // note: irem uses O1 after this instruction! | |
1134 __ bind(done); | |
1135 } | |
1136 | |
1137 | |
1138 void TemplateTable::irem() { | |
1139 transition(itos, itos); | |
1140 __ mov(Otos_i, O2); // save divisor | |
1141 idiv(); // %%%% Hack: exploits fact that idiv leaves dividend in O1 | |
1142 __ smul(Otos_i, O2, Otos_i); | |
1143 __ sub(O1, Otos_i, Otos_i); | |
1144 } | |
1145 | |
1146 | |
1147 void TemplateTable::lmul() { | |
1148 transition(ltos, ltos); | |
1149 __ pop_l(O2); | |
1150 #ifdef _LP64 | |
1151 __ mulx(Otos_l, O2, Otos_l); | |
1152 #else | |
1153 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::lmul)); | |
1154 #endif | |
1155 | |
1156 } | |
1157 | |
1158 | |
1159 void TemplateTable::ldiv() { | |
1160 transition(ltos, ltos); | |
1161 | |
1162 // check for zero | |
1163 __ pop_l(O2); | |
1164 #ifdef _LP64 | |
1165 __ tst(Otos_l); | |
1166 __ throw_if_not_xcc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch); | |
1167 __ sdivx(O2, Otos_l, Otos_l); | |
1168 #else | |
1169 __ orcc(Otos_l1, Otos_l2, G0); | |
1170 __ throw_if_not_icc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch); | |
1171 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::ldiv)); | |
1172 #endif | |
1173 } | |
1174 | |
1175 | |
1176 void TemplateTable::lrem() { | |
1177 transition(ltos, ltos); | |
1178 | |
1179 // check for zero | |
1180 __ pop_l(O2); | |
1181 #ifdef _LP64 | |
1182 __ tst(Otos_l); | |
1183 __ throw_if_not_xcc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch); | |
1184 __ sdivx(O2, Otos_l, Otos_l2); | |
1185 __ mulx (Otos_l2, Otos_l, Otos_l2); | |
1186 __ sub (O2, Otos_l2, Otos_l); | |
1187 #else | |
1188 __ orcc(Otos_l1, Otos_l2, G0); | |
1189 __ throw_if_not_icc(Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch); | |
1190 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::lrem)); | |
1191 #endif | |
1192 } | |
1193 | |
1194 | |
1195 void TemplateTable::lshl() { | |
1196 transition(itos, ltos); // %%%% could optimize, fill delay slot or opt for ultra | |
1197 | |
1198 __ pop_l(O2); // shift value in O2, O3 | |
1199 #ifdef _LP64 | |
1200 __ sllx(O2, Otos_i, Otos_l); | |
1201 #else | |
1202 __ lshl(O2, O3, Otos_i, Otos_l1, Otos_l2, O4); | |
1203 #endif | |
1204 } | |
1205 | |
1206 | |
1207 void TemplateTable::lshr() { | |
1208 transition(itos, ltos); // %%%% see lshl comment | |
1209 | |
1210 __ pop_l(O2); // shift value in O2, O3 | |
1211 #ifdef _LP64 | |
1212 __ srax(O2, Otos_i, Otos_l); | |
1213 #else | |
1214 __ lshr(O2, O3, Otos_i, Otos_l1, Otos_l2, O4); | |
1215 #endif | |
1216 } | |
1217 | |
1218 | |
1219 | |
1220 void TemplateTable::lushr() { | |
1221 transition(itos, ltos); // %%%% see lshl comment | |
1222 | |
1223 __ pop_l(O2); // shift value in O2, O3 | |
1224 #ifdef _LP64 | |
1225 __ srlx(O2, Otos_i, Otos_l); | |
1226 #else | |
1227 __ lushr(O2, O3, Otos_i, Otos_l1, Otos_l2, O4); | |
1228 #endif | |
1229 } | |
1230 | |
1231 | |
1232 void TemplateTable::fop2(Operation op) { | |
1233 transition(ftos, ftos); | |
1234 switch (op) { | |
1235 case add: __ pop_f(F4); __ fadd(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; | |
1236 case sub: __ pop_f(F4); __ fsub(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; | |
1237 case mul: __ pop_f(F4); __ fmul(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; | |
1238 case div: __ pop_f(F4); __ fdiv(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; | |
1239 case rem: | |
1240 assert(Ftos_f == F0, "just checking"); | |
1241 #ifdef _LP64 | |
1242 // LP64 calling conventions use F1, F3 for passing 2 floats | |
1243 __ pop_f(F1); | |
1244 __ fmov(FloatRegisterImpl::S, Ftos_f, F3); | |
1245 #else | |
1246 __ pop_i(O0); | |
1247 __ stf(FloatRegisterImpl::S, Ftos_f, __ d_tmp); | |
1248 __ ld( __ d_tmp, O1 ); | |
1249 #endif | |
1250 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::frem)); | |
1251 assert( Ftos_f == F0, "fix this code" ); | |
1252 break; | |
1253 | |
1254 default: ShouldNotReachHere(); | |
1255 } | |
1256 } | |
1257 | |
1258 | |
1259 void TemplateTable::dop2(Operation op) { | |
1260 transition(dtos, dtos); | |
1261 switch (op) { | |
1262 case add: __ pop_d(F4); __ fadd(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; | |
1263 case sub: __ pop_d(F4); __ fsub(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; | |
1264 case mul: __ pop_d(F4); __ fmul(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; | |
1265 case div: __ pop_d(F4); __ fdiv(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; | |
1266 case rem: | |
1267 #ifdef _LP64 | |
1268 // Pass arguments in D0, D2 | |
1269 __ fmov(FloatRegisterImpl::D, Ftos_f, F2 ); | |
1270 __ pop_d( F0 ); | |
1271 #else | |
1272 // Pass arguments in O0O1, O2O3 | |
1273 __ stf(FloatRegisterImpl::D, Ftos_f, __ d_tmp); | |
1274 __ ldd( __ d_tmp, O2 ); | |
1275 __ pop_d(Ftos_f); | |
1276 __ stf(FloatRegisterImpl::D, Ftos_f, __ d_tmp); | |
1277 __ ldd( __ d_tmp, O0 ); | |
1278 #endif | |
1279 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::drem)); | |
1280 assert( Ftos_d == F0, "fix this code" ); | |
1281 break; | |
1282 | |
1283 default: ShouldNotReachHere(); | |
1284 } | |
1285 } | |
1286 | |
1287 | |
1288 void TemplateTable::ineg() { | |
1289 transition(itos, itos); | |
1290 __ neg(Otos_i); | |
1291 } | |
1292 | |
1293 | |
1294 void TemplateTable::lneg() { | |
1295 transition(ltos, ltos); | |
1296 #ifdef _LP64 | |
1297 __ sub(G0, Otos_l, Otos_l); | |
1298 #else | |
1299 __ lneg(Otos_l1, Otos_l2); | |
1300 #endif | |
1301 } | |
1302 | |
1303 | |
1304 void TemplateTable::fneg() { | |
1305 transition(ftos, ftos); | |
1306 __ fneg(FloatRegisterImpl::S, Ftos_f); | |
1307 } | |
1308 | |
1309 | |
1310 void TemplateTable::dneg() { | |
1311 transition(dtos, dtos); | |
1312 // v8 has fnegd if source and dest are the same | |
1313 __ fneg(FloatRegisterImpl::D, Ftos_f); | |
1314 } | |
1315 | |
1316 | |
1317 void TemplateTable::iinc() { | |
1318 transition(vtos, vtos); | |
1319 locals_index(G3_scratch); | |
1320 __ ldsb(Lbcp, 2, O2); // load constant | |
1321 __ access_local_int(G3_scratch, Otos_i); | |
1322 __ add(Otos_i, O2, Otos_i); | |
1506 | 1323 __ st(Otos_i, G3_scratch, 0); // access_local_int puts E.A. in G3_scratch |
0 | 1324 } |
1325 | |
1326 | |
1327 void TemplateTable::wide_iinc() { | |
1328 transition(vtos, vtos); | |
1329 locals_index_wide(G3_scratch); | |
1330 __ get_2_byte_integer_at_bcp( 4, O2, O3, InterpreterMacroAssembler::Signed); | |
1331 __ access_local_int(G3_scratch, Otos_i); | |
1332 __ add(Otos_i, O3, Otos_i); | |
1506 | 1333 __ st(Otos_i, G3_scratch, 0); // access_local_int puts E.A. in G3_scratch |
0 | 1334 } |
1335 | |
1336 | |
1337 void TemplateTable::convert() { | |
1338 // %%%%% Factor this first part accross platforms | |
1339 #ifdef ASSERT | |
1340 TosState tos_in = ilgl; | |
1341 TosState tos_out = ilgl; | |
1342 switch (bytecode()) { | |
1343 case Bytecodes::_i2l: // fall through | |
1344 case Bytecodes::_i2f: // fall through | |
1345 case Bytecodes::_i2d: // fall through | |
1346 case Bytecodes::_i2b: // fall through | |
1347 case Bytecodes::_i2c: // fall through | |
1348 case Bytecodes::_i2s: tos_in = itos; break; | |
1349 case Bytecodes::_l2i: // fall through | |
1350 case Bytecodes::_l2f: // fall through | |
1351 case Bytecodes::_l2d: tos_in = ltos; break; | |
1352 case Bytecodes::_f2i: // fall through | |
1353 case Bytecodes::_f2l: // fall through | |
1354 case Bytecodes::_f2d: tos_in = ftos; break; | |
1355 case Bytecodes::_d2i: // fall through | |
1356 case Bytecodes::_d2l: // fall through | |
1357 case Bytecodes::_d2f: tos_in = dtos; break; | |
1358 default : ShouldNotReachHere(); | |
1359 } | |
1360 switch (bytecode()) { | |
1361 case Bytecodes::_l2i: // fall through | |
1362 case Bytecodes::_f2i: // fall through | |
1363 case Bytecodes::_d2i: // fall through | |
1364 case Bytecodes::_i2b: // fall through | |
1365 case Bytecodes::_i2c: // fall through | |
1366 case Bytecodes::_i2s: tos_out = itos; break; | |
1367 case Bytecodes::_i2l: // fall through | |
1368 case Bytecodes::_f2l: // fall through | |
1369 case Bytecodes::_d2l: tos_out = ltos; break; | |
1370 case Bytecodes::_i2f: // fall through | |
1371 case Bytecodes::_l2f: // fall through | |
1372 case Bytecodes::_d2f: tos_out = ftos; break; | |
1373 case Bytecodes::_i2d: // fall through | |
1374 case Bytecodes::_l2d: // fall through | |
1375 case Bytecodes::_f2d: tos_out = dtos; break; | |
1376 default : ShouldNotReachHere(); | |
1377 } | |
1378 transition(tos_in, tos_out); | |
1379 #endif | |
1380 | |
1381 | |
1382 // Conversion | |
1383 Label done; | |
1384 switch (bytecode()) { | |
1385 case Bytecodes::_i2l: | |
1386 #ifdef _LP64 | |
1387 // Sign extend the 32 bits | |
1388 __ sra ( Otos_i, 0, Otos_l ); | |
1389 #else | |
1390 __ addcc(Otos_i, 0, Otos_l2); | |
1391 __ br(Assembler::greaterEqual, true, Assembler::pt, done); | |
1392 __ delayed()->clr(Otos_l1); | |
1393 __ set(~0, Otos_l1); | |
1394 #endif | |
1395 break; | |
1396 | |
1397 case Bytecodes::_i2f: | |
1398 __ st(Otos_i, __ d_tmp ); | |
1399 __ ldf(FloatRegisterImpl::S, __ d_tmp, F0); | |
1400 __ fitof(FloatRegisterImpl::S, F0, Ftos_f); | |
1401 break; | |
1402 | |
1403 case Bytecodes::_i2d: | |
1404 __ st(Otos_i, __ d_tmp); | |
1405 __ ldf(FloatRegisterImpl::S, __ d_tmp, F0); | |
1406 __ fitof(FloatRegisterImpl::D, F0, Ftos_f); | |
1407 break; | |
1408 | |
1409 case Bytecodes::_i2b: | |
1410 __ sll(Otos_i, 24, Otos_i); | |
1411 __ sra(Otos_i, 24, Otos_i); | |
1412 break; | |
1413 | |
1414 case Bytecodes::_i2c: | |
1415 __ sll(Otos_i, 16, Otos_i); | |
1416 __ srl(Otos_i, 16, Otos_i); | |
1417 break; | |
1418 | |
1419 case Bytecodes::_i2s: | |
1420 __ sll(Otos_i, 16, Otos_i); | |
1421 __ sra(Otos_i, 16, Otos_i); | |
1422 break; | |
1423 | |
1424 case Bytecodes::_l2i: | |
1425 #ifndef _LP64 | |
1426 __ mov(Otos_l2, Otos_i); | |
1427 #else | |
1428 // Sign-extend into the high 32 bits | |
1429 __ sra(Otos_l, 0, Otos_i); | |
1430 #endif | |
1431 break; | |
1432 | |
1433 case Bytecodes::_l2f: | |
1434 case Bytecodes::_l2d: | |
1435 __ st_long(Otos_l, __ d_tmp); | |
1436 __ ldf(FloatRegisterImpl::D, __ d_tmp, Ftos_d); | |
1437 | |
1438 if (VM_Version::v9_instructions_work()) { | |
1439 if (bytecode() == Bytecodes::_l2f) { | |
1440 __ fxtof(FloatRegisterImpl::S, Ftos_d, Ftos_f); | |
1441 } else { | |
1442 __ fxtof(FloatRegisterImpl::D, Ftos_d, Ftos_d); | |
1443 } | |
1444 } else { | |
1445 __ call_VM_leaf( | |
1446 Lscratch, | |
1447 bytecode() == Bytecodes::_l2f | |
1448 ? CAST_FROM_FN_PTR(address, SharedRuntime::l2f) | |
1449 : CAST_FROM_FN_PTR(address, SharedRuntime::l2d) | |
1450 ); | |
1451 } | |
1452 break; | |
1453 | |
1454 case Bytecodes::_f2i: { | |
1455 Label isNaN; | |
1456 // result must be 0 if value is NaN; test by comparing value to itself | |
1457 __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, Ftos_f, Ftos_f); | |
1458 // According to the v8 manual, you have to have a non-fp instruction | |
1459 // between fcmp and fb. | |
1460 if (!VM_Version::v9_instructions_work()) { | |
1461 __ nop(); | |
1462 } | |
1463 __ fb(Assembler::f_unordered, true, Assembler::pn, isNaN); | |
1464 __ delayed()->clr(Otos_i); // NaN | |
1465 __ ftoi(FloatRegisterImpl::S, Ftos_f, F30); | |
1466 __ stf(FloatRegisterImpl::S, F30, __ d_tmp); | |
1467 __ ld(__ d_tmp, Otos_i); | |
1468 __ bind(isNaN); | |
1469 } | |
1470 break; | |
1471 | |
1472 case Bytecodes::_f2l: | |
1473 // must uncache tos | |
1474 __ push_f(); | |
1475 #ifdef _LP64 | |
1476 __ pop_f(F1); | |
1477 #else | |
1478 __ pop_i(O0); | |
1479 #endif | |
1480 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::f2l)); | |
1481 break; | |
1482 | |
1483 case Bytecodes::_f2d: | |
1484 __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, Ftos_f, Ftos_f); | |
1485 break; | |
1486 | |
1487 case Bytecodes::_d2i: | |
1488 case Bytecodes::_d2l: | |
1489 // must uncache tos | |
1490 __ push_d(); | |
1491 #ifdef _LP64 | |
1492 // LP64 calling conventions pass first double arg in D0 | |
1493 __ pop_d( Ftos_d ); | |
1494 #else | |
1495 __ pop_i( O0 ); | |
1496 __ pop_i( O1 ); | |
1497 #endif | |
1498 __ call_VM_leaf(Lscratch, | |
1499 bytecode() == Bytecodes::_d2i | |
1500 ? CAST_FROM_FN_PTR(address, SharedRuntime::d2i) | |
1501 : CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); | |
1502 break; | |
1503 | |
1504 case Bytecodes::_d2f: | |
1505 if (VM_Version::v9_instructions_work()) { | |
1506 __ ftof( FloatRegisterImpl::D, FloatRegisterImpl::S, Ftos_d, Ftos_f); | |
1507 } | |
1508 else { | |
1509 // must uncache tos | |
1510 __ push_d(); | |
1511 __ pop_i(O0); | |
1512 __ pop_i(O1); | |
1513 __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::d2f)); | |
1514 } | |
1515 break; | |
1516 | |
1517 default: ShouldNotReachHere(); | |
1518 } | |
1519 __ bind(done); | |
1520 } | |
1521 | |
1522 | |
1523 void TemplateTable::lcmp() { | |
1524 transition(ltos, itos); | |
1525 | |
1526 #ifdef _LP64 | |
1527 __ pop_l(O1); // pop off value 1, value 2 is in O0 | |
1528 __ lcmp( O1, Otos_l, Otos_i ); | |
1529 #else | |
1530 __ pop_l(O2); // cmp O2,3 to O0,1 | |
1531 __ lcmp( O2, O3, Otos_l1, Otos_l2, Otos_i ); | |
1532 #endif | |
1533 } | |
1534 | |
1535 | |
1536 void TemplateTable::float_cmp(bool is_float, int unordered_result) { | |
1537 | |
1538 if (is_float) __ pop_f(F2); | |
1539 else __ pop_d(F2); | |
1540 | |
1541 assert(Ftos_f == F0 && Ftos_d == F0, "alias checking:"); | |
1542 | |
1543 __ float_cmp( is_float, unordered_result, F2, F0, Otos_i ); | |
1544 } | |
1545 | |
1546 void TemplateTable::branch(bool is_jsr, bool is_wide) { | |
1547 // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also. | |
1548 __ verify_oop(Lmethod); | |
1549 __ verify_thread(); | |
1550 | |
1551 const Register O2_bumped_count = O2; | |
1552 __ profile_taken_branch(G3_scratch, O2_bumped_count); | |
1553 | |
1554 // get (wide) offset to O1_disp | |
1555 const Register O1_disp = O1; | |
1556 if (is_wide) __ get_4_byte_integer_at_bcp( 1, G4_scratch, O1_disp, InterpreterMacroAssembler::set_CC); | |
1557 else __ get_2_byte_integer_at_bcp( 1, G4_scratch, O1_disp, InterpreterMacroAssembler::Signed, InterpreterMacroAssembler::set_CC); | |
1558 | |
1559 // Handle all the JSR stuff here, then exit. | |
1560 // It's much shorter and cleaner than intermingling with the | |
605 | 1561 // non-JSR normal-branch stuff occurring below. |
0 | 1562 if( is_jsr ) { |
1563 // compute return address as bci in Otos_i | |
727 | 1564 __ ld_ptr(Lmethod, methodOopDesc::const_offset(), G3_scratch); |
0 | 1565 __ sub(Lbcp, G3_scratch, G3_scratch); |
1566 __ sub(G3_scratch, in_bytes(constMethodOopDesc::codes_offset()) - (is_wide ? 5 : 3), Otos_i); | |
1567 | |
1568 // Bump Lbcp to target of JSR | |
1569 __ add(Lbcp, O1_disp, Lbcp); | |
1570 // Push returnAddress for "ret" on stack | |
1506 | 1571 __ push_ptr(Otos_i); |
0 | 1572 // And away we go! |
1573 __ dispatch_next(vtos); | |
1574 return; | |
1575 } | |
1576 | |
1577 // Normal (non-jsr) branch handling | |
1578 | |
1579 // Save the current Lbcp | |
1580 const Register O0_cur_bcp = O0; | |
1581 __ mov( Lbcp, O0_cur_bcp ); | |
1582 | |
1583 bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; | |
1584 if ( increment_invocation_counter_for_backward_branches ) { | |
1585 Label Lforward; | |
1586 // check branch direction | |
1587 __ br( Assembler::positive, false, Assembler::pn, Lforward ); | |
1588 // Bump bytecode pointer by displacement (take the branch) | |
1589 __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr | |
1590 | |
1591 // Update Backedge branch separately from invocations | |
1592 const Register G4_invoke_ctr = G4; | |
1593 __ increment_backedge_counter(G4_invoke_ctr, G1_scratch); | |
1594 if (ProfileInterpreter) { | |
1595 __ test_invocation_counter_for_mdp(G4_invoke_ctr, Lbcp, G3_scratch, Lforward); | |
1596 if (UseOnStackReplacement) { | |
1597 __ test_backedge_count_for_osr(O2_bumped_count, O0_cur_bcp, G3_scratch); | |
1598 } | |
1599 } else { | |
1600 if (UseOnStackReplacement) { | |
1601 __ test_backedge_count_for_osr(G4_invoke_ctr, O0_cur_bcp, G3_scratch); | |
1602 } | |
1603 } | |
1604 | |
1605 __ bind(Lforward); | |
1606 } else | |
1607 // Bump bytecode pointer by displacement (take the branch) | |
1608 __ add( O1_disp, Lbcp, Lbcp );// add to bc addr | |
1609 | |
1610 // continue with bytecode @ target | |
1611 // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above, | |
1612 // %%%%% and changing dispatch_next to dispatch_only | |
1613 __ dispatch_next(vtos); | |
1614 } | |
1615 | |
1616 | |
1617 // Note Condition in argument is TemplateTable::Condition | |
1618 // arg scope is within class scope | |
1619 | |
1620 void TemplateTable::if_0cmp(Condition cc) { | |
1621 // no pointers, integer only! | |
1622 transition(itos, vtos); | |
1623 // assume branch is more often taken than not (loops use backward branches) | |
1624 __ cmp( Otos_i, 0); | |
1625 __ if_cmp(ccNot(cc), false); | |
1626 } | |
1627 | |
1628 | |
1629 void TemplateTable::if_icmp(Condition cc) { | |
1630 transition(itos, vtos); | |
1631 __ pop_i(O1); | |
1632 __ cmp(O1, Otos_i); | |
1633 __ if_cmp(ccNot(cc), false); | |
1634 } | |
1635 | |
1636 | |
1637 void TemplateTable::if_nullcmp(Condition cc) { | |
1638 transition(atos, vtos); | |
1639 __ tst(Otos_i); | |
1640 __ if_cmp(ccNot(cc), true); | |
1641 } | |
1642 | |
1643 | |
1644 void TemplateTable::if_acmp(Condition cc) { | |
1645 transition(atos, vtos); | |
1646 __ pop_ptr(O1); | |
1647 __ verify_oop(O1); | |
1648 __ verify_oop(Otos_i); | |
1649 __ cmp(O1, Otos_i); | |
1650 __ if_cmp(ccNot(cc), true); | |
1651 } | |
1652 | |
1653 | |
1654 | |
1655 void TemplateTable::ret() { | |
1656 transition(vtos, vtos); | |
1657 locals_index(G3_scratch); | |
1658 __ access_local_returnAddress(G3_scratch, Otos_i); | |
1659 // Otos_i contains the bci, compute the bcp from that | |
1660 | |
1661 #ifdef _LP64 | |
1662 #ifdef ASSERT | |
1663 // jsr result was labeled as an 'itos' not an 'atos' because we cannot GC | |
1664 // the result. The return address (really a BCI) was stored with an | |
1665 // 'astore' because JVM specs claim it's a pointer-sized thing. Hence in | |
1666 // the 64-bit build the 32-bit BCI is actually in the low bits of a 64-bit | |
1667 // loaded value. | |
1668 { Label zzz ; | |
1669 __ set (65536, G3_scratch) ; | |
1670 __ cmp (Otos_i, G3_scratch) ; | |
1671 __ bp( Assembler::lessEqualUnsigned, false, Assembler::xcc, Assembler::pn, zzz); | |
1672 __ delayed()->nop(); | |
1673 __ stop("BCI is in the wrong register half?"); | |
1674 __ bind (zzz) ; | |
1675 } | |
1676 #endif | |
1677 #endif | |
1678 | |
1679 __ profile_ret(vtos, Otos_i, G4_scratch); | |
1680 | |
727 | 1681 __ ld_ptr(Lmethod, methodOopDesc::const_offset(), G3_scratch); |
0 | 1682 __ add(G3_scratch, Otos_i, G3_scratch); |
1683 __ add(G3_scratch, in_bytes(constMethodOopDesc::codes_offset()), Lbcp); | |
1684 __ dispatch_next(vtos); | |
1685 } | |
1686 | |
1687 | |
1688 void TemplateTable::wide_ret() { | |
1689 transition(vtos, vtos); | |
1690 locals_index_wide(G3_scratch); | |
1691 __ access_local_returnAddress(G3_scratch, Otos_i); | |
1692 // Otos_i contains the bci, compute the bcp from that | |
1693 | |
1694 __ profile_ret(vtos, Otos_i, G4_scratch); | |
1695 | |
727 | 1696 __ ld_ptr(Lmethod, methodOopDesc::const_offset(), G3_scratch); |
0 | 1697 __ add(G3_scratch, Otos_i, G3_scratch); |
1698 __ add(G3_scratch, in_bytes(constMethodOopDesc::codes_offset()), Lbcp); | |
1699 __ dispatch_next(vtos); | |
1700 } | |
1701 | |
1702 | |
1703 void TemplateTable::tableswitch() { | |
1704 transition(itos, vtos); | |
1705 Label default_case, continue_execution; | |
1706 | |
1707 // align bcp | |
1708 __ add(Lbcp, BytesPerInt, O1); | |
1709 __ and3(O1, -BytesPerInt, O1); | |
1710 // load lo, hi | |
1711 __ ld(O1, 1 * BytesPerInt, O2); // Low Byte | |
1712 __ ld(O1, 2 * BytesPerInt, O3); // High Byte | |
1713 #ifdef _LP64 | |
1714 // Sign extend the 32 bits | |
1715 __ sra ( Otos_i, 0, Otos_i ); | |
1716 #endif /* _LP64 */ | |
1717 | |
1718 // check against lo & hi | |
1719 __ cmp( Otos_i, O2); | |
1720 __ br( Assembler::less, false, Assembler::pn, default_case); | |
1721 __ delayed()->cmp( Otos_i, O3 ); | |
1722 __ br( Assembler::greater, false, Assembler::pn, default_case); | |
1723 // lookup dispatch offset | |
1724 __ delayed()->sub(Otos_i, O2, O2); | |
1725 __ profile_switch_case(O2, O3, G3_scratch, G4_scratch); | |
1726 __ sll(O2, LogBytesPerInt, O2); | |
1727 __ add(O2, 3 * BytesPerInt, O2); | |
1728 __ ba(false, continue_execution); | |
1729 __ delayed()->ld(O1, O2, O2); | |
1730 // handle default | |
1731 __ bind(default_case); | |
1732 __ profile_switch_default(O3); | |
1733 __ ld(O1, 0, O2); // get default offset | |
1734 // continue execution | |
1735 __ bind(continue_execution); | |
1736 __ add(Lbcp, O2, Lbcp); | |
1737 __ dispatch_next(vtos); | |
1738 } | |
1739 | |
1740 | |
1741 void TemplateTable::lookupswitch() { | |
1742 transition(itos, itos); | |
1743 __ stop("lookupswitch bytecode should have been rewritten"); | |
1744 } | |
1745 | |
1746 void TemplateTable::fast_linearswitch() { | |
1747 transition(itos, vtos); | |
1748 Label loop_entry, loop, found, continue_execution; | |
1749 // align bcp | |
1750 __ add(Lbcp, BytesPerInt, O1); | |
1751 __ and3(O1, -BytesPerInt, O1); | |
1752 // set counter | |
1753 __ ld(O1, BytesPerInt, O2); | |
1754 __ sll(O2, LogBytesPerInt + 1, O2); // in word-pairs | |
1755 __ add(O1, 2 * BytesPerInt, O3); // set first pair addr | |
1756 __ ba(false, loop_entry); | |
1757 __ delayed()->add(O3, O2, O2); // counter now points past last pair | |
1758 | |
1759 // table search | |
1760 __ bind(loop); | |
1761 __ cmp(O4, Otos_i); | |
1762 __ br(Assembler::equal, true, Assembler::pn, found); | |
1763 __ delayed()->ld(O3, BytesPerInt, O4); // offset -> O4 | |
1764 __ inc(O3, 2 * BytesPerInt); | |
1765 | |
1766 __ bind(loop_entry); | |
1767 __ cmp(O2, O3); | |
1768 __ brx(Assembler::greaterUnsigned, true, Assembler::pt, loop); | |
1769 __ delayed()->ld(O3, 0, O4); | |
1770 | |
1771 // default case | |
1772 __ ld(O1, 0, O4); // get default offset | |
1773 if (ProfileInterpreter) { | |
1774 __ profile_switch_default(O3); | |
1775 __ ba(false, continue_execution); | |
1776 __ delayed()->nop(); | |
1777 } | |
1778 | |
1779 // entry found -> get offset | |
1780 __ bind(found); | |
1781 if (ProfileInterpreter) { | |
1782 __ sub(O3, O1, O3); | |
1783 __ sub(O3, 2*BytesPerInt, O3); | |
1784 __ srl(O3, LogBytesPerInt + 1, O3); // in word-pairs | |
1785 __ profile_switch_case(O3, O1, O2, G3_scratch); | |
1786 | |
1787 __ bind(continue_execution); | |
1788 } | |
1789 __ add(Lbcp, O4, Lbcp); | |
1790 __ dispatch_next(vtos); | |
1791 } | |
1792 | |
1793 | |
1794 void TemplateTable::fast_binaryswitch() { | |
1795 transition(itos, vtos); | |
1796 // Implementation using the following core algorithm: (copied from Intel) | |
1797 // | |
1798 // int binary_search(int key, LookupswitchPair* array, int n) { | |
1799 // // Binary search according to "Methodik des Programmierens" by | |
1800 // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. | |
1801 // int i = 0; | |
1802 // int j = n; | |
1803 // while (i+1 < j) { | |
1804 // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) | |
1805 // // with Q: for all i: 0 <= i < n: key < a[i] | |
1806 // // where a stands for the array and assuming that the (inexisting) | |
1807 // // element a[n] is infinitely big. | |
1808 // int h = (i + j) >> 1; | |
1809 // // i < h < j | |
1810 // if (key < array[h].fast_match()) { | |
1811 // j = h; | |
1812 // } else { | |
1813 // i = h; | |
1814 // } | |
1815 // } | |
1816 // // R: a[i] <= key < a[i+1] or Q | |
1817 // // (i.e., if key is within array, i is the correct index) | |
1818 // return i; | |
1819 // } | |
1820 | |
1821 // register allocation | |
1822 assert(Otos_i == O0, "alias checking"); | |
1823 const Register Rkey = Otos_i; // already set (tosca) | |
1824 const Register Rarray = O1; | |
1825 const Register Ri = O2; | |
1826 const Register Rj = O3; | |
1827 const Register Rh = O4; | |
1828 const Register Rscratch = O5; | |
1829 | |
1830 const int log_entry_size = 3; | |
1831 const int entry_size = 1 << log_entry_size; | |
1832 | |
1833 Label found; | |
1834 // Find Array start | |
1835 __ add(Lbcp, 3 * BytesPerInt, Rarray); | |
1836 __ and3(Rarray, -BytesPerInt, Rarray); | |
1837 // initialize i & j (in delay slot) | |
1838 __ clr( Ri ); | |
1839 | |
1840 // and start | |
1841 Label entry; | |
1842 __ ba(false, entry); | |
1843 __ delayed()->ld( Rarray, -BytesPerInt, Rj); | |
1844 // (Rj is already in the native byte-ordering.) | |
1845 | |
1846 // binary search loop | |
1847 { Label loop; | |
1848 __ bind( loop ); | |
1849 // int h = (i + j) >> 1; | |
1850 __ sra( Rh, 1, Rh ); | |
1851 // if (key < array[h].fast_match()) { | |
1852 // j = h; | |
1853 // } else { | |
1854 // i = h; | |
1855 // } | |
1856 __ sll( Rh, log_entry_size, Rscratch ); | |
1857 __ ld( Rarray, Rscratch, Rscratch ); | |
1858 // (Rscratch is already in the native byte-ordering.) | |
1859 __ cmp( Rkey, Rscratch ); | |
1860 if ( VM_Version::v9_instructions_work() ) { | |
1861 __ movcc( Assembler::less, false, Assembler::icc, Rh, Rj ); // j = h if (key < array[h].fast_match()) | |
1862 __ movcc( Assembler::greaterEqual, false, Assembler::icc, Rh, Ri ); // i = h if (key >= array[h].fast_match()) | |
1863 } | |
1864 else { | |
1865 Label end_of_if; | |
1866 __ br( Assembler::less, true, Assembler::pt, end_of_if ); | |
1867 __ delayed()->mov( Rh, Rj ); // if (<) Rj = Rh | |
1868 __ mov( Rh, Ri ); // else i = h | |
1869 __ bind(end_of_if); // } | |
1870 } | |
1871 | |
1872 // while (i+1 < j) | |
1873 __ bind( entry ); | |
1874 __ add( Ri, 1, Rscratch ); | |
1875 __ cmp(Rscratch, Rj); | |
1876 __ br( Assembler::less, true, Assembler::pt, loop ); | |
1877 __ delayed()->add( Ri, Rj, Rh ); // start h = i + j >> 1; | |
1878 } | |
1879 | |
1880 // end of binary search, result index is i (must check again!) | |
1881 Label default_case; | |
1882 Label continue_execution; | |
1883 if (ProfileInterpreter) { | |
1884 __ mov( Ri, Rh ); // Save index in i for profiling | |
1885 } | |
1886 __ sll( Ri, log_entry_size, Ri ); | |
1887 __ ld( Rarray, Ri, Rscratch ); | |
1888 // (Rscratch is already in the native byte-ordering.) | |
1889 __ cmp( Rkey, Rscratch ); | |
1890 __ br( Assembler::notEqual, true, Assembler::pn, default_case ); | |
1891 __ delayed()->ld( Rarray, -2 * BytesPerInt, Rj ); // load default offset -> j | |
1892 | |
1893 // entry found -> j = offset | |
1894 __ inc( Ri, BytesPerInt ); | |
1895 __ profile_switch_case(Rh, Rj, Rscratch, Rkey); | |
1896 __ ld( Rarray, Ri, Rj ); | |
1897 // (Rj is already in the native byte-ordering.) | |
1898 | |
1899 if (ProfileInterpreter) { | |
1900 __ ba(false, continue_execution); | |
1901 __ delayed()->nop(); | |
1902 } | |
1903 | |
1904 __ bind(default_case); // fall through (if not profiling) | |
1905 __ profile_switch_default(Ri); | |
1906 | |
1907 __ bind(continue_execution); | |
1908 __ add( Lbcp, Rj, Lbcp ); | |
1909 __ dispatch_next( vtos ); | |
1910 } | |
1911 | |
1912 | |
1913 void TemplateTable::_return(TosState state) { | |
1914 transition(state, state); | |
1915 assert(_desc->calls_vm(), "inconsistent calls_vm information"); | |
1916 | |
1917 if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { | |
1918 assert(state == vtos, "only valid state"); | |
1919 __ mov(G0, G3_scratch); | |
1920 __ access_local_ptr(G3_scratch, Otos_i); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
1921 __ load_klass(Otos_i, O2); |
0 | 1922 __ set(JVM_ACC_HAS_FINALIZER, G3); |
1923 __ ld(O2, Klass::access_flags_offset_in_bytes() + sizeof(oopDesc), O2); | |
1924 __ andcc(G3, O2, G0); | |
1925 Label skip_register_finalizer; | |
1926 __ br(Assembler::zero, false, Assembler::pn, skip_register_finalizer); | |
1927 __ delayed()->nop(); | |
1928 | |
1929 // Call out to do finalizer registration | |
1930 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), Otos_i); | |
1931 | |
1932 __ bind(skip_register_finalizer); | |
1933 } | |
1934 | |
1935 __ remove_activation(state, /* throw_monitor_exception */ true); | |
1936 | |
1937 // The caller's SP was adjusted upon method entry to accomodate | |
1938 // the callee's non-argument locals. Undo that adjustment. | |
1939 __ ret(); // return to caller | |
1940 __ delayed()->restore(I5_savedSP, G0, SP); | |
1941 } | |
1942 | |
1943 | |
1944 // ---------------------------------------------------------------------------- | |
1945 // Volatile variables demand their effects be made known to all CPU's in | |
1946 // order. Store buffers on most chips allow reads & writes to reorder; the | |
1947 // JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of | |
1948 // memory barrier (i.e., it's not sufficient that the interpreter does not | |
1949 // reorder volatile references, the hardware also must not reorder them). | |
1950 // | |
1951 // According to the new Java Memory Model (JMM): | |
1952 // (1) All volatiles are serialized wrt to each other. | |
1953 // ALSO reads & writes act as aquire & release, so: | |
1954 // (2) A read cannot let unrelated NON-volatile memory refs that happen after | |
1955 // the read float up to before the read. It's OK for non-volatile memory refs | |
1956 // that happen before the volatile read to float down below it. | |
1957 // (3) Similar a volatile write cannot let unrelated NON-volatile memory refs | |
1958 // that happen BEFORE the write float down to after the write. It's OK for | |
1959 // non-volatile memory refs that happen after the volatile write to float up | |
1960 // before it. | |
1961 // | |
1962 // We only put in barriers around volatile refs (they are expensive), not | |
1963 // _between_ memory refs (that would require us to track the flavor of the | |
1964 // previous memory refs). Requirements (2) and (3) require some barriers | |
1965 // before volatile stores and after volatile loads. These nearly cover | |
1966 // requirement (1) but miss the volatile-store-volatile-load case. This final | |
1967 // case is placed after volatile-stores although it could just as well go | |
1968 // before volatile-loads. | |
1969 void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint) { | |
1970 // Helper function to insert a is-volatile test and memory barrier | |
1971 // All current sparc implementations run in TSO, needing only StoreLoad | |
1972 if ((order_constraint & Assembler::StoreLoad) == 0) return; | |
1973 __ membar( order_constraint ); | |
1974 } | |
1975 | |
1976 // ---------------------------------------------------------------------------- | |
1565 | 1977 void TemplateTable::resolve_cache_and_index(int byte_no, |
1978 Register result, | |
1979 Register Rcache, | |
1980 Register index, | |
1981 size_t index_size) { | |
0 | 1982 // Depends on cpCacheOop layout! |
1983 Label resolved; | |
1984 | |
1565 | 1985 __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); |
1986 if (byte_no == f1_oop) { | |
1987 // We are resolved if the f1 field contains a non-null object (CallSite, etc.) | |
1988 // This kind of CP cache entry does not need to match the flags byte, because | |
1989 // there is a 1-1 relation between bytecode type and CP entry type. | |
1990 assert_different_registers(result, Rcache); | |
1503 | 1991 __ ld_ptr(Rcache, constantPoolCacheOopDesc::base_offset() + |
1565 | 1992 ConstantPoolCacheEntry::f1_offset(), result); |
1993 __ tst(result); | |
1503 | 1994 __ br(Assembler::notEqual, false, Assembler::pt, resolved); |
1995 __ delayed()->set((int)bytecode(), O1); | |
1996 } else { | |
1565 | 1997 assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); |
1998 assert(result == noreg, ""); //else change code for setting result | |
1999 const int shift_count = (1 + byte_no)*BitsPerByte; | |
2000 | |
1503 | 2001 __ ld_ptr(Rcache, constantPoolCacheOopDesc::base_offset() + |
2002 ConstantPoolCacheEntry::indices_offset(), Lbyte_code); | |
2003 | |
2004 __ srl( Lbyte_code, shift_count, Lbyte_code ); | |
2005 __ and3( Lbyte_code, 0xFF, Lbyte_code ); | |
2006 __ cmp( Lbyte_code, (int)bytecode()); | |
2007 __ br( Assembler::equal, false, Assembler::pt, resolved); | |
2008 __ delayed()->set((int)bytecode(), O1); | |
2009 } | |
0 | 2010 |
2011 address entry; | |
2012 switch (bytecode()) { | |
2013 case Bytecodes::_getstatic : // fall through | |
2014 case Bytecodes::_putstatic : // fall through | |
2015 case Bytecodes::_getfield : // fall through | |
2016 case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; | |
2017 case Bytecodes::_invokevirtual : // fall through | |
2018 case Bytecodes::_invokespecial : // fall through | |
2019 case Bytecodes::_invokestatic : // fall through | |
2020 case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; | |
1503 | 2021 case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; |
1602 | 2022 case Bytecodes::_fast_aldc : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; |
2023 case Bytecodes::_fast_aldc_w : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; | |
0 | 2024 default : ShouldNotReachHere(); break; |
2025 } | |
2026 // first time invocation - must resolve first | |
2027 __ call_VM(noreg, entry, O1); | |
2028 // Update registers with resolved info | |
1565 | 2029 __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); |
2030 if (result != noreg) | |
2031 __ ld_ptr(Rcache, constantPoolCacheOopDesc::base_offset() + | |
2032 ConstantPoolCacheEntry::f1_offset(), result); | |
0 | 2033 __ bind(resolved); |
2034 } | |
2035 | |
2036 void TemplateTable::load_invoke_cp_cache_entry(int byte_no, | |
2037 Register Rmethod, | |
2038 Register Ritable_index, | |
2039 Register Rflags, | |
2040 bool is_invokevirtual, | |
1565 | 2041 bool is_invokevfinal, |
2042 bool is_invokedynamic) { | |
0 | 2043 // Uses both G3_scratch and G4_scratch |
2044 Register Rcache = G3_scratch; | |
2045 Register Rscratch = G4_scratch; | |
2046 assert_different_registers(Rcache, Rmethod, Ritable_index); | |
2047 | |
2048 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2049 | |
2050 // determine constant pool cache field offsets | |
2051 const int method_offset = in_bytes( | |
2052 cp_base_offset + | |
2053 (is_invokevirtual | |
2054 ? ConstantPoolCacheEntry::f2_offset() | |
2055 : ConstantPoolCacheEntry::f1_offset() | |
2056 ) | |
2057 ); | |
2058 const int flags_offset = in_bytes(cp_base_offset + | |
2059 ConstantPoolCacheEntry::flags_offset()); | |
2060 // access constant pool cache fields | |
2061 const int index_offset = in_bytes(cp_base_offset + | |
2062 ConstantPoolCacheEntry::f2_offset()); | |
2063 | |
2064 if (is_invokevfinal) { | |
2065 __ get_cache_and_index_at_bcp(Rcache, Rscratch, 1); | |
1565 | 2066 __ ld_ptr(Rcache, method_offset, Rmethod); |
2067 } else if (byte_no == f1_oop) { | |
2068 // Resolved f1_oop goes directly into 'method' register. | |
2069 resolve_cache_and_index(byte_no, Rmethod, Rcache, Rscratch, sizeof(u4)); | |
0 | 2070 } else { |
1565 | 2071 resolve_cache_and_index(byte_no, noreg, Rcache, Rscratch, sizeof(u2)); |
2072 __ ld_ptr(Rcache, method_offset, Rmethod); | |
0 | 2073 } |
2074 | |
2075 if (Ritable_index != noreg) { | |
727 | 2076 __ ld_ptr(Rcache, index_offset, Ritable_index); |
0 | 2077 } |
727 | 2078 __ ld_ptr(Rcache, flags_offset, Rflags); |
0 | 2079 } |
2080 | |
2081 // The Rcache register must be set before call | |
2082 void TemplateTable::load_field_cp_cache_entry(Register Robj, | |
2083 Register Rcache, | |
2084 Register index, | |
2085 Register Roffset, | |
2086 Register Rflags, | |
2087 bool is_static) { | |
2088 assert_different_registers(Rcache, Rflags, Roffset); | |
2089 | |
2090 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2091 | |
727 | 2092 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags); |
2093 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset); | |
0 | 2094 if (is_static) { |
727 | 2095 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset(), Robj); |
0 | 2096 } |
2097 } | |
2098 | |
2099 // The registers Rcache and index expected to be set before call. | |
2100 // Correct values of the Rcache and index registers are preserved. | |
2101 void TemplateTable::jvmti_post_field_access(Register Rcache, | |
2102 Register index, | |
2103 bool is_static, | |
2104 bool has_tos) { | |
2105 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2106 | |
2107 if (JvmtiExport::can_post_field_access()) { | |
2108 // Check to see if a field access watch has been set before we take | |
2109 // the time to call into the VM. | |
2110 Label Label1; | |
2111 assert_different_registers(Rcache, index, G1_scratch); | |
727 | 2112 AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr()); |
0 | 2113 __ load_contents(get_field_access_count_addr, G1_scratch); |
2114 __ tst(G1_scratch); | |
2115 __ br(Assembler::zero, false, Assembler::pt, Label1); | |
2116 __ delayed()->nop(); | |
2117 | |
2118 __ add(Rcache, in_bytes(cp_base_offset), Rcache); | |
2119 | |
2120 if (is_static) { | |
2121 __ clr(Otos_i); | |
2122 } else { | |
2123 if (has_tos) { | |
2124 // save object pointer before call_VM() clobbers it | |
450
b22701a8b88f
6474243: suspicious jvmti code that uses oop unsafely across GC point
coleenp
parents:
356
diff
changeset
|
2125 __ push_ptr(Otos_i); // put object on tos where GC wants it. |
0 | 2126 } else { |
2127 // Load top of stack (do not pop the value off the stack); | |
2128 __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i); | |
2129 } | |
2130 __ verify_oop(Otos_i); | |
2131 } | |
2132 // Otos_i: object pointer or NULL if static | |
2133 // Rcache: cache entry pointer | |
2134 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), | |
2135 Otos_i, Rcache); | |
2136 if (!is_static && has_tos) { | |
450
b22701a8b88f
6474243: suspicious jvmti code that uses oop unsafely across GC point
coleenp
parents:
356
diff
changeset
|
2137 __ pop_ptr(Otos_i); // restore object pointer |
0 | 2138 __ verify_oop(Otos_i); |
2139 } | |
2140 __ get_cache_and_index_at_bcp(Rcache, index, 1); | |
2141 __ bind(Label1); | |
2142 } | |
2143 } | |
2144 | |
2145 void TemplateTable::getfield_or_static(int byte_no, bool is_static) { | |
2146 transition(vtos, vtos); | |
2147 | |
2148 Register Rcache = G3_scratch; | |
2149 Register index = G4_scratch; | |
2150 Register Rclass = Rcache; | |
2151 Register Roffset= G4_scratch; | |
2152 Register Rflags = G1_scratch; | |
2153 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2154 | |
1565 | 2155 resolve_cache_and_index(byte_no, noreg, Rcache, index, sizeof(u2)); |
0 | 2156 jvmti_post_field_access(Rcache, index, is_static, false); |
2157 load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static); | |
2158 | |
2159 if (!is_static) { | |
2160 pop_and_check_object(Rclass); | |
2161 } else { | |
2162 __ verify_oop(Rclass); | |
2163 } | |
2164 | |
2165 Label exit; | |
2166 | |
2167 Assembler::Membar_mask_bits membar_bits = | |
2168 Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore); | |
2169 | |
2170 if (__ membar_has_effect(membar_bits)) { | |
2171 // Get volatile flag | |
2172 __ set((1 << ConstantPoolCacheEntry::volatileField), Lscratch); | |
2173 __ and3(Rflags, Lscratch, Lscratch); | |
2174 } | |
2175 | |
2176 Label checkVolatile; | |
2177 | |
2178 // compute field type | |
2179 Label notByte, notInt, notShort, notChar, notLong, notFloat, notObj; | |
2180 __ srl(Rflags, ConstantPoolCacheEntry::tosBits, Rflags); | |
2181 // Make sure we don't need to mask Rflags for tosBits after the above shift | |
2182 ConstantPoolCacheEntry::verify_tosBits(); | |
2183 | |
2184 // Check atos before itos for getstatic, more likely (in Queens at least) | |
2185 __ cmp(Rflags, atos); | |
2186 __ br(Assembler::notEqual, false, Assembler::pt, notObj); | |
2187 __ delayed() ->cmp(Rflags, itos); | |
2188 | |
2189 // atos | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2190 __ load_heap_oop(Rclass, Roffset, Otos_i); |
0 | 2191 __ verify_oop(Otos_i); |
2192 __ push(atos); | |
2193 if (!is_static) { | |
2194 patch_bytecode(Bytecodes::_fast_agetfield, G3_scratch, G4_scratch); | |
2195 } | |
2196 __ ba(false, checkVolatile); | |
2197 __ delayed()->tst(Lscratch); | |
2198 | |
2199 __ bind(notObj); | |
2200 | |
2201 // cmp(Rflags, itos); | |
2202 __ br(Assembler::notEqual, false, Assembler::pt, notInt); | |
2203 __ delayed() ->cmp(Rflags, ltos); | |
2204 | |
2205 // itos | |
2206 __ ld(Rclass, Roffset, Otos_i); | |
2207 __ push(itos); | |
2208 if (!is_static) { | |
2209 patch_bytecode(Bytecodes::_fast_igetfield, G3_scratch, G4_scratch); | |
2210 } | |
2211 __ ba(false, checkVolatile); | |
2212 __ delayed()->tst(Lscratch); | |
2213 | |
2214 __ bind(notInt); | |
2215 | |
2216 // cmp(Rflags, ltos); | |
2217 __ br(Assembler::notEqual, false, Assembler::pt, notLong); | |
2218 __ delayed() ->cmp(Rflags, btos); | |
2219 | |
2220 // ltos | |
2221 // load must be atomic | |
2222 __ ld_long(Rclass, Roffset, Otos_l); | |
2223 __ push(ltos); | |
2224 if (!is_static) { | |
2225 patch_bytecode(Bytecodes::_fast_lgetfield, G3_scratch, G4_scratch); | |
2226 } | |
2227 __ ba(false, checkVolatile); | |
2228 __ delayed()->tst(Lscratch); | |
2229 | |
2230 __ bind(notLong); | |
2231 | |
2232 // cmp(Rflags, btos); | |
2233 __ br(Assembler::notEqual, false, Assembler::pt, notByte); | |
2234 __ delayed() ->cmp(Rflags, ctos); | |
2235 | |
2236 // btos | |
2237 __ ldsb(Rclass, Roffset, Otos_i); | |
2238 __ push(itos); | |
2239 if (!is_static) { | |
2240 patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch); | |
2241 } | |
2242 __ ba(false, checkVolatile); | |
2243 __ delayed()->tst(Lscratch); | |
2244 | |
2245 __ bind(notByte); | |
2246 | |
2247 // cmp(Rflags, ctos); | |
2248 __ br(Assembler::notEqual, false, Assembler::pt, notChar); | |
2249 __ delayed() ->cmp(Rflags, stos); | |
2250 | |
2251 // ctos | |
2252 __ lduh(Rclass, Roffset, Otos_i); | |
2253 __ push(itos); | |
2254 if (!is_static) { | |
2255 patch_bytecode(Bytecodes::_fast_cgetfield, G3_scratch, G4_scratch); | |
2256 } | |
2257 __ ba(false, checkVolatile); | |
2258 __ delayed()->tst(Lscratch); | |
2259 | |
2260 __ bind(notChar); | |
2261 | |
2262 // cmp(Rflags, stos); | |
2263 __ br(Assembler::notEqual, false, Assembler::pt, notShort); | |
2264 __ delayed() ->cmp(Rflags, ftos); | |
2265 | |
2266 // stos | |
2267 __ ldsh(Rclass, Roffset, Otos_i); | |
2268 __ push(itos); | |
2269 if (!is_static) { | |
2270 patch_bytecode(Bytecodes::_fast_sgetfield, G3_scratch, G4_scratch); | |
2271 } | |
2272 __ ba(false, checkVolatile); | |
2273 __ delayed()->tst(Lscratch); | |
2274 | |
2275 __ bind(notShort); | |
2276 | |
2277 | |
2278 // cmp(Rflags, ftos); | |
2279 __ br(Assembler::notEqual, false, Assembler::pt, notFloat); | |
2280 __ delayed() ->tst(Lscratch); | |
2281 | |
2282 // ftos | |
2283 __ ldf(FloatRegisterImpl::S, Rclass, Roffset, Ftos_f); | |
2284 __ push(ftos); | |
2285 if (!is_static) { | |
2286 patch_bytecode(Bytecodes::_fast_fgetfield, G3_scratch, G4_scratch); | |
2287 } | |
2288 __ ba(false, checkVolatile); | |
2289 __ delayed()->tst(Lscratch); | |
2290 | |
2291 __ bind(notFloat); | |
2292 | |
2293 | |
2294 // dtos | |
2295 __ ldf(FloatRegisterImpl::D, Rclass, Roffset, Ftos_d); | |
2296 __ push(dtos); | |
2297 if (!is_static) { | |
2298 patch_bytecode(Bytecodes::_fast_dgetfield, G3_scratch, G4_scratch); | |
2299 } | |
2300 | |
2301 __ bind(checkVolatile); | |
2302 if (__ membar_has_effect(membar_bits)) { | |
2303 // __ tst(Lscratch); executed in delay slot | |
2304 __ br(Assembler::zero, false, Assembler::pt, exit); | |
2305 __ delayed()->nop(); | |
2306 volatile_barrier(membar_bits); | |
2307 } | |
2308 | |
2309 __ bind(exit); | |
2310 } | |
2311 | |
2312 | |
2313 void TemplateTable::getfield(int byte_no) { | |
2314 getfield_or_static(byte_no, false); | |
2315 } | |
2316 | |
2317 void TemplateTable::getstatic(int byte_no) { | |
2318 getfield_or_static(byte_no, true); | |
2319 } | |
2320 | |
2321 | |
2322 void TemplateTable::fast_accessfield(TosState state) { | |
2323 transition(atos, state); | |
2324 Register Rcache = G3_scratch; | |
2325 Register index = G4_scratch; | |
2326 Register Roffset = G4_scratch; | |
2327 Register Rflags = Rcache; | |
2328 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2329 | |
2330 __ get_cache_and_index_at_bcp(Rcache, index, 1); | |
2331 jvmti_post_field_access(Rcache, index, /*is_static*/false, /*has_tos*/true); | |
2332 | |
727 | 2333 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset); |
0 | 2334 |
2335 __ null_check(Otos_i); | |
2336 __ verify_oop(Otos_i); | |
2337 | |
2338 Label exit; | |
2339 | |
2340 Assembler::Membar_mask_bits membar_bits = | |
2341 Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore); | |
2342 if (__ membar_has_effect(membar_bits)) { | |
2343 // Get volatile flag | |
727 | 2344 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Rflags); |
0 | 2345 __ set((1 << ConstantPoolCacheEntry::volatileField), Lscratch); |
2346 } | |
2347 | |
2348 switch (bytecode()) { | |
2349 case Bytecodes::_fast_bgetfield: | |
2350 __ ldsb(Otos_i, Roffset, Otos_i); | |
2351 break; | |
2352 case Bytecodes::_fast_cgetfield: | |
2353 __ lduh(Otos_i, Roffset, Otos_i); | |
2354 break; | |
2355 case Bytecodes::_fast_sgetfield: | |
2356 __ ldsh(Otos_i, Roffset, Otos_i); | |
2357 break; | |
2358 case Bytecodes::_fast_igetfield: | |
2359 __ ld(Otos_i, Roffset, Otos_i); | |
2360 break; | |
2361 case Bytecodes::_fast_lgetfield: | |
2362 __ ld_long(Otos_i, Roffset, Otos_l); | |
2363 break; | |
2364 case Bytecodes::_fast_fgetfield: | |
2365 __ ldf(FloatRegisterImpl::S, Otos_i, Roffset, Ftos_f); | |
2366 break; | |
2367 case Bytecodes::_fast_dgetfield: | |
2368 __ ldf(FloatRegisterImpl::D, Otos_i, Roffset, Ftos_d); | |
2369 break; | |
2370 case Bytecodes::_fast_agetfield: | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2371 __ load_heap_oop(Otos_i, Roffset, Otos_i); |
0 | 2372 break; |
2373 default: | |
2374 ShouldNotReachHere(); | |
2375 } | |
2376 | |
2377 if (__ membar_has_effect(membar_bits)) { | |
2378 __ btst(Lscratch, Rflags); | |
2379 __ br(Assembler::zero, false, Assembler::pt, exit); | |
2380 __ delayed()->nop(); | |
2381 volatile_barrier(membar_bits); | |
2382 __ bind(exit); | |
2383 } | |
2384 | |
2385 if (state == atos) { | |
2386 __ verify_oop(Otos_i); // does not blow flags! | |
2387 } | |
2388 } | |
2389 | |
2390 void TemplateTable::jvmti_post_fast_field_mod() { | |
2391 if (JvmtiExport::can_post_field_modification()) { | |
2392 // Check to see if a field modification watch has been set before we take | |
2393 // the time to call into the VM. | |
2394 Label done; | |
727 | 2395 AddressLiteral get_field_modification_count_addr(JvmtiExport::get_field_modification_count_addr()); |
0 | 2396 __ load_contents(get_field_modification_count_addr, G4_scratch); |
2397 __ tst(G4_scratch); | |
2398 __ br(Assembler::zero, false, Assembler::pt, done); | |
2399 __ delayed()->nop(); | |
2400 __ pop_ptr(G4_scratch); // copy the object pointer from tos | |
2401 __ verify_oop(G4_scratch); | |
2402 __ push_ptr(G4_scratch); // put the object pointer back on tos | |
2403 __ get_cache_entry_pointer_at_bcp(G1_scratch, G3_scratch, 1); | |
2404 // Save tos values before call_VM() clobbers them. Since we have | |
2405 // to do it for every data type, we use the saved values as the | |
2406 // jvalue object. | |
2407 switch (bytecode()) { // save tos values before call_VM() clobbers them | |
2408 case Bytecodes::_fast_aputfield: __ push_ptr(Otos_i); break; | |
2409 case Bytecodes::_fast_bputfield: // fall through | |
2410 case Bytecodes::_fast_sputfield: // fall through | |
2411 case Bytecodes::_fast_cputfield: // fall through | |
2412 case Bytecodes::_fast_iputfield: __ push_i(Otos_i); break; | |
2413 case Bytecodes::_fast_dputfield: __ push_d(Ftos_d); break; | |
2414 case Bytecodes::_fast_fputfield: __ push_f(Ftos_f); break; | |
2415 // get words in right order for use as jvalue object | |
2416 case Bytecodes::_fast_lputfield: __ push_l(Otos_l); break; | |
2417 } | |
2418 // setup pointer to jvalue object | |
2419 __ mov(Lesp, G3_scratch); __ inc(G3_scratch, wordSize); | |
2420 // G4_scratch: object pointer | |
2421 // G1_scratch: cache entry pointer | |
2422 // G3_scratch: jvalue object on the stack | |
2423 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), G4_scratch, G1_scratch, G3_scratch); | |
2424 switch (bytecode()) { // restore tos values | |
2425 case Bytecodes::_fast_aputfield: __ pop_ptr(Otos_i); break; | |
2426 case Bytecodes::_fast_bputfield: // fall through | |
2427 case Bytecodes::_fast_sputfield: // fall through | |
2428 case Bytecodes::_fast_cputfield: // fall through | |
2429 case Bytecodes::_fast_iputfield: __ pop_i(Otos_i); break; | |
2430 case Bytecodes::_fast_dputfield: __ pop_d(Ftos_d); break; | |
2431 case Bytecodes::_fast_fputfield: __ pop_f(Ftos_f); break; | |
2432 case Bytecodes::_fast_lputfield: __ pop_l(Otos_l); break; | |
2433 } | |
2434 __ bind(done); | |
2435 } | |
2436 } | |
2437 | |
2438 // The registers Rcache and index expected to be set before call. | |
2439 // The function may destroy various registers, just not the Rcache and index registers. | |
2440 void TemplateTable::jvmti_post_field_mod(Register Rcache, Register index, bool is_static) { | |
2441 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2442 | |
2443 if (JvmtiExport::can_post_field_modification()) { | |
2444 // Check to see if a field modification watch has been set before we take | |
2445 // the time to call into the VM. | |
2446 Label Label1; | |
2447 assert_different_registers(Rcache, index, G1_scratch); | |
727 | 2448 AddressLiteral get_field_modification_count_addr(JvmtiExport::get_field_modification_count_addr()); |
0 | 2449 __ load_contents(get_field_modification_count_addr, G1_scratch); |
2450 __ tst(G1_scratch); | |
2451 __ br(Assembler::zero, false, Assembler::pt, Label1); | |
2452 __ delayed()->nop(); | |
2453 | |
2454 // The Rcache and index registers have been already set. | |
2455 // This allows to eliminate this call but the Rcache and index | |
2456 // registers must be correspondingly used after this line. | |
2457 __ get_cache_and_index_at_bcp(G1_scratch, G4_scratch, 1); | |
2458 | |
2459 __ add(G1_scratch, in_bytes(cp_base_offset), G3_scratch); | |
2460 if (is_static) { | |
2461 // Life is simple. Null out the object pointer. | |
2462 __ clr(G4_scratch); | |
2463 } else { | |
2464 Register Rflags = G1_scratch; | |
2465 // Life is harder. The stack holds the value on top, followed by the | |
2466 // object. We don't know the size of the value, though; it could be | |
2467 // one or two words depending on its type. As a result, we must find | |
2468 // the type to determine where the object is. | |
2469 | |
2470 Label two_word, valsizeknown; | |
727 | 2471 __ ld_ptr(G1_scratch, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags); |
0 | 2472 __ mov(Lesp, G4_scratch); |
2473 __ srl(Rflags, ConstantPoolCacheEntry::tosBits, Rflags); | |
2474 // Make sure we don't need to mask Rflags for tosBits after the above shift | |
2475 ConstantPoolCacheEntry::verify_tosBits(); | |
2476 __ cmp(Rflags, ltos); | |
2477 __ br(Assembler::equal, false, Assembler::pt, two_word); | |
2478 __ delayed()->cmp(Rflags, dtos); | |
2479 __ br(Assembler::equal, false, Assembler::pt, two_word); | |
2480 __ delayed()->nop(); | |
2481 __ inc(G4_scratch, Interpreter::expr_offset_in_bytes(1)); | |
2482 __ br(Assembler::always, false, Assembler::pt, valsizeknown); | |
2483 __ delayed()->nop(); | |
2484 __ bind(two_word); | |
2485 | |
2486 __ inc(G4_scratch, Interpreter::expr_offset_in_bytes(2)); | |
2487 | |
2488 __ bind(valsizeknown); | |
2489 // setup object pointer | |
2490 __ ld_ptr(G4_scratch, 0, G4_scratch); | |
2491 __ verify_oop(G4_scratch); | |
2492 } | |
2493 // setup pointer to jvalue object | |
2494 __ mov(Lesp, G1_scratch); __ inc(G1_scratch, wordSize); | |
2495 // G4_scratch: object pointer or NULL if static | |
2496 // G3_scratch: cache entry pointer | |
2497 // G1_scratch: jvalue object on the stack | |
2498 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), | |
2499 G4_scratch, G3_scratch, G1_scratch); | |
2500 __ get_cache_and_index_at_bcp(Rcache, index, 1); | |
2501 __ bind(Label1); | |
2502 } | |
2503 } | |
2504 | |
2505 void TemplateTable::pop_and_check_object(Register r) { | |
2506 __ pop_ptr(r); | |
2507 __ null_check(r); // for field access must check obj. | |
2508 __ verify_oop(r); | |
2509 } | |
2510 | |
2511 void TemplateTable::putfield_or_static(int byte_no, bool is_static) { | |
2512 transition(vtos, vtos); | |
2513 Register Rcache = G3_scratch; | |
2514 Register index = G4_scratch; | |
2515 Register Rclass = Rcache; | |
2516 Register Roffset= G4_scratch; | |
2517 Register Rflags = G1_scratch; | |
2518 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2519 | |
1565 | 2520 resolve_cache_and_index(byte_no, noreg, Rcache, index, sizeof(u2)); |
0 | 2521 jvmti_post_field_mod(Rcache, index, is_static); |
2522 load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static); | |
2523 | |
2524 Assembler::Membar_mask_bits read_bits = | |
2525 Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore); | |
2526 Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad; | |
2527 | |
2528 Label notVolatile, checkVolatile, exit; | |
2529 if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) { | |
2530 __ set((1 << ConstantPoolCacheEntry::volatileField), Lscratch); | |
2531 __ and3(Rflags, Lscratch, Lscratch); | |
2532 | |
2533 if (__ membar_has_effect(read_bits)) { | |
2534 __ tst(Lscratch); | |
2535 __ br(Assembler::zero, false, Assembler::pt, notVolatile); | |
2536 __ delayed()->nop(); | |
2537 volatile_barrier(read_bits); | |
2538 __ bind(notVolatile); | |
2539 } | |
2540 } | |
2541 | |
2542 __ srl(Rflags, ConstantPoolCacheEntry::tosBits, Rflags); | |
2543 // Make sure we don't need to mask Rflags for tosBits after the above shift | |
2544 ConstantPoolCacheEntry::verify_tosBits(); | |
2545 | |
2546 // compute field type | |
2547 Label notInt, notShort, notChar, notObj, notByte, notLong, notFloat; | |
2548 | |
2549 if (is_static) { | |
2550 // putstatic with object type most likely, check that first | |
2551 __ cmp(Rflags, atos ); | |
2552 __ br(Assembler::notEqual, false, Assembler::pt, notObj); | |
2553 __ delayed() ->cmp(Rflags, itos ); | |
2554 | |
2555 // atos | |
2556 __ pop_ptr(); | |
2557 __ verify_oop(Otos_i); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2558 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2559 do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2560 |
0 | 2561 __ ba(false, checkVolatile); |
2562 __ delayed()->tst(Lscratch); | |
2563 | |
2564 __ bind(notObj); | |
2565 | |
2566 // cmp(Rflags, itos ); | |
2567 __ br(Assembler::notEqual, false, Assembler::pt, notInt); | |
2568 __ delayed() ->cmp(Rflags, btos ); | |
2569 | |
2570 // itos | |
2571 __ pop_i(); | |
2572 __ st(Otos_i, Rclass, Roffset); | |
2573 __ ba(false, checkVolatile); | |
2574 __ delayed()->tst(Lscratch); | |
2575 | |
2576 __ bind(notInt); | |
2577 | |
2578 } else { | |
2579 // putfield with int type most likely, check that first | |
2580 __ cmp(Rflags, itos ); | |
2581 __ br(Assembler::notEqual, false, Assembler::pt, notInt); | |
2582 __ delayed() ->cmp(Rflags, atos ); | |
2583 | |
2584 // itos | |
2585 __ pop_i(); | |
2586 pop_and_check_object(Rclass); | |
2587 __ st(Otos_i, Rclass, Roffset); | |
2588 patch_bytecode(Bytecodes::_fast_iputfield, G3_scratch, G4_scratch); | |
2589 __ ba(false, checkVolatile); | |
2590 __ delayed()->tst(Lscratch); | |
2591 | |
2592 __ bind(notInt); | |
2593 // cmp(Rflags, atos ); | |
2594 __ br(Assembler::notEqual, false, Assembler::pt, notObj); | |
2595 __ delayed() ->cmp(Rflags, btos ); | |
2596 | |
2597 // atos | |
2598 __ pop_ptr(); | |
2599 pop_and_check_object(Rclass); | |
2600 __ verify_oop(Otos_i); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2601 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2602 do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2603 |
0 | 2604 patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch); |
2605 __ ba(false, checkVolatile); | |
2606 __ delayed()->tst(Lscratch); | |
2607 | |
2608 __ bind(notObj); | |
2609 } | |
2610 | |
2611 // cmp(Rflags, btos ); | |
2612 __ br(Assembler::notEqual, false, Assembler::pt, notByte); | |
2613 __ delayed() ->cmp(Rflags, ltos ); | |
2614 | |
2615 // btos | |
2616 __ pop_i(); | |
2617 if (!is_static) pop_and_check_object(Rclass); | |
2618 __ stb(Otos_i, Rclass, Roffset); | |
2619 if (!is_static) { | |
2620 patch_bytecode(Bytecodes::_fast_bputfield, G3_scratch, G4_scratch); | |
2621 } | |
2622 __ ba(false, checkVolatile); | |
2623 __ delayed()->tst(Lscratch); | |
2624 | |
2625 __ bind(notByte); | |
2626 | |
2627 // cmp(Rflags, ltos ); | |
2628 __ br(Assembler::notEqual, false, Assembler::pt, notLong); | |
2629 __ delayed() ->cmp(Rflags, ctos ); | |
2630 | |
2631 // ltos | |
2632 __ pop_l(); | |
2633 if (!is_static) pop_and_check_object(Rclass); | |
2634 __ st_long(Otos_l, Rclass, Roffset); | |
2635 if (!is_static) { | |
2636 patch_bytecode(Bytecodes::_fast_lputfield, G3_scratch, G4_scratch); | |
2637 } | |
2638 __ ba(false, checkVolatile); | |
2639 __ delayed()->tst(Lscratch); | |
2640 | |
2641 __ bind(notLong); | |
2642 | |
2643 // cmp(Rflags, ctos ); | |
2644 __ br(Assembler::notEqual, false, Assembler::pt, notChar); | |
2645 __ delayed() ->cmp(Rflags, stos ); | |
2646 | |
2647 // ctos (char) | |
2648 __ pop_i(); | |
2649 if (!is_static) pop_and_check_object(Rclass); | |
2650 __ sth(Otos_i, Rclass, Roffset); | |
2651 if (!is_static) { | |
2652 patch_bytecode(Bytecodes::_fast_cputfield, G3_scratch, G4_scratch); | |
2653 } | |
2654 __ ba(false, checkVolatile); | |
2655 __ delayed()->tst(Lscratch); | |
2656 | |
2657 __ bind(notChar); | |
2658 // cmp(Rflags, stos ); | |
2659 __ br(Assembler::notEqual, false, Assembler::pt, notShort); | |
2660 __ delayed() ->cmp(Rflags, ftos ); | |
2661 | |
2662 // stos (char) | |
2663 __ pop_i(); | |
2664 if (!is_static) pop_and_check_object(Rclass); | |
2665 __ sth(Otos_i, Rclass, Roffset); | |
2666 if (!is_static) { | |
2667 patch_bytecode(Bytecodes::_fast_sputfield, G3_scratch, G4_scratch); | |
2668 } | |
2669 __ ba(false, checkVolatile); | |
2670 __ delayed()->tst(Lscratch); | |
2671 | |
2672 __ bind(notShort); | |
2673 // cmp(Rflags, ftos ); | |
2674 __ br(Assembler::notZero, false, Assembler::pt, notFloat); | |
2675 __ delayed()->nop(); | |
2676 | |
2677 // ftos | |
2678 __ pop_f(); | |
2679 if (!is_static) pop_and_check_object(Rclass); | |
2680 __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset); | |
2681 if (!is_static) { | |
2682 patch_bytecode(Bytecodes::_fast_fputfield, G3_scratch, G4_scratch); | |
2683 } | |
2684 __ ba(false, checkVolatile); | |
2685 __ delayed()->tst(Lscratch); | |
2686 | |
2687 __ bind(notFloat); | |
2688 | |
2689 // dtos | |
2690 __ pop_d(); | |
2691 if (!is_static) pop_and_check_object(Rclass); | |
2692 __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset); | |
2693 if (!is_static) { | |
2694 patch_bytecode(Bytecodes::_fast_dputfield, G3_scratch, G4_scratch); | |
2695 } | |
2696 | |
2697 __ bind(checkVolatile); | |
2698 __ tst(Lscratch); | |
2699 | |
2700 if (__ membar_has_effect(write_bits)) { | |
2701 // __ tst(Lscratch); in delay slot | |
2702 __ br(Assembler::zero, false, Assembler::pt, exit); | |
2703 __ delayed()->nop(); | |
2704 volatile_barrier(Assembler::StoreLoad); | |
2705 __ bind(exit); | |
2706 } | |
2707 } | |
2708 | |
2709 void TemplateTable::fast_storefield(TosState state) { | |
2710 transition(state, vtos); | |
2711 Register Rcache = G3_scratch; | |
2712 Register Rclass = Rcache; | |
2713 Register Roffset= G4_scratch; | |
2714 Register Rflags = G1_scratch; | |
2715 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2716 | |
2717 jvmti_post_fast_field_mod(); | |
2718 | |
2719 __ get_cache_and_index_at_bcp(Rcache, G4_scratch, 1); | |
2720 | |
2721 Assembler::Membar_mask_bits read_bits = | |
2722 Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore); | |
2723 Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad; | |
2724 | |
2725 Label notVolatile, checkVolatile, exit; | |
2726 if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) { | |
727 | 2727 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags); |
0 | 2728 __ set((1 << ConstantPoolCacheEntry::volatileField), Lscratch); |
2729 __ and3(Rflags, Lscratch, Lscratch); | |
2730 if (__ membar_has_effect(read_bits)) { | |
2731 __ tst(Lscratch); | |
2732 __ br(Assembler::zero, false, Assembler::pt, notVolatile); | |
2733 __ delayed()->nop(); | |
2734 volatile_barrier(read_bits); | |
2735 __ bind(notVolatile); | |
2736 } | |
2737 } | |
2738 | |
727 | 2739 __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset); |
0 | 2740 pop_and_check_object(Rclass); |
2741 | |
2742 switch (bytecode()) { | |
2743 case Bytecodes::_fast_bputfield: __ stb(Otos_i, Rclass, Roffset); break; | |
2744 case Bytecodes::_fast_cputfield: /* fall through */ | |
2745 case Bytecodes::_fast_sputfield: __ sth(Otos_i, Rclass, Roffset); break; | |
2746 case Bytecodes::_fast_iputfield: __ st(Otos_i, Rclass, Roffset); break; | |
2747 case Bytecodes::_fast_lputfield: __ st_long(Otos_l, Rclass, Roffset); break; | |
2748 case Bytecodes::_fast_fputfield: | |
2749 __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset); | |
2750 break; | |
2751 case Bytecodes::_fast_dputfield: | |
2752 __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset); | |
2753 break; | |
2754 case Bytecodes::_fast_aputfield: | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2755 do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false); |
0 | 2756 break; |
2757 default: | |
2758 ShouldNotReachHere(); | |
2759 } | |
2760 | |
2761 if (__ membar_has_effect(write_bits)) { | |
2762 __ tst(Lscratch); | |
2763 __ br(Assembler::zero, false, Assembler::pt, exit); | |
2764 __ delayed()->nop(); | |
2765 volatile_barrier(Assembler::StoreLoad); | |
2766 __ bind(exit); | |
2767 } | |
2768 } | |
2769 | |
2770 | |
2771 void TemplateTable::putfield(int byte_no) { | |
2772 putfield_or_static(byte_no, false); | |
2773 } | |
2774 | |
2775 void TemplateTable::putstatic(int byte_no) { | |
2776 putfield_or_static(byte_no, true); | |
2777 } | |
2778 | |
2779 | |
2780 void TemplateTable::fast_xaccess(TosState state) { | |
2781 transition(vtos, state); | |
2782 Register Rcache = G3_scratch; | |
2783 Register Roffset = G4_scratch; | |
2784 Register Rflags = G4_scratch; | |
2785 Register Rreceiver = Lscratch; | |
2786 | |
1506 | 2787 __ ld_ptr(Llocals, 0, Rreceiver); |
0 | 2788 |
2789 // access constant pool cache (is resolved) | |
2790 __ get_cache_and_index_at_bcp(Rcache, G4_scratch, 2); | |
727 | 2791 __ ld_ptr(Rcache, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f2_offset(), Roffset); |
0 | 2792 __ add(Lbcp, 1, Lbcp); // needed to report exception at the correct bcp |
2793 | |
2794 __ verify_oop(Rreceiver); | |
2795 __ null_check(Rreceiver); | |
2796 if (state == atos) { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2797 __ load_heap_oop(Rreceiver, Roffset, Otos_i); |
0 | 2798 } else if (state == itos) { |
2799 __ ld (Rreceiver, Roffset, Otos_i) ; | |
2800 } else if (state == ftos) { | |
2801 __ ldf(FloatRegisterImpl::S, Rreceiver, Roffset, Ftos_f); | |
2802 } else { | |
2803 ShouldNotReachHere(); | |
2804 } | |
2805 | |
2806 Assembler::Membar_mask_bits membar_bits = | |
2807 Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore); | |
2808 if (__ membar_has_effect(membar_bits)) { | |
2809 | |
2810 // Get is_volatile value in Rflags and check if membar is needed | |
727 | 2811 __ ld_ptr(Rcache, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::flags_offset(), Rflags); |
0 | 2812 |
2813 // Test volatile | |
2814 Label notVolatile; | |
2815 __ set((1 << ConstantPoolCacheEntry::volatileField), Lscratch); | |
2816 __ btst(Rflags, Lscratch); | |
2817 __ br(Assembler::zero, false, Assembler::pt, notVolatile); | |
2818 __ delayed()->nop(); | |
2819 volatile_barrier(membar_bits); | |
2820 __ bind(notVolatile); | |
2821 } | |
2822 | |
2823 __ interp_verify_oop(Otos_i, state, __FILE__, __LINE__); | |
2824 __ sub(Lbcp, 1, Lbcp); | |
2825 } | |
2826 | |
2827 //---------------------------------------------------------------------------------------------------- | |
2828 // Calls | |
2829 | |
2830 void TemplateTable::count_calls(Register method, Register temp) { | |
2831 // implemented elsewhere | |
2832 ShouldNotReachHere(); | |
2833 } | |
2834 | |
2835 void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) { | |
2836 Register Rtemp = G4_scratch; | |
2837 Register Rcall = Rindex; | |
2838 assert_different_registers(Rcall, G5_method, Gargs, Rret); | |
2839 | |
2840 // get target methodOop & entry point | |
2841 const int base = instanceKlass::vtable_start_offset() * wordSize; | |
2842 if (vtableEntry::size() % 3 == 0) { | |
2843 // scale the vtable index by 12: | |
2844 int one_third = vtableEntry::size() / 3; | |
2845 __ sll(Rindex, exact_log2(one_third * 1 * wordSize), Rtemp); | |
2846 __ sll(Rindex, exact_log2(one_third * 2 * wordSize), Rindex); | |
2847 __ add(Rindex, Rtemp, Rindex); | |
2848 } else { | |
2849 // scale the vtable index by 8: | |
2850 __ sll(Rindex, exact_log2(vtableEntry::size() * wordSize), Rindex); | |
2851 } | |
2852 | |
2853 __ add(Rrecv, Rindex, Rrecv); | |
2854 __ ld_ptr(Rrecv, base + vtableEntry::method_offset_in_bytes(), G5_method); | |
2855 | |
2856 __ call_from_interpreter(Rcall, Gargs, Rret); | |
2857 } | |
2858 | |
2859 void TemplateTable::invokevirtual(int byte_no) { | |
2860 transition(vtos, vtos); | |
1565 | 2861 assert(byte_no == f2_byte, "use this argument"); |
0 | 2862 |
2863 Register Rscratch = G3_scratch; | |
2864 Register Rtemp = G4_scratch; | |
2865 Register Rret = Lscratch; | |
2866 Register Rrecv = G5_method; | |
2867 Label notFinal; | |
2868 | |
1565 | 2869 load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Rret, true, false, false); |
0 | 2870 __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore |
2871 | |
2872 // Check for vfinal | |
2873 __ set((1 << ConstantPoolCacheEntry::vfinalMethod), G4_scratch); | |
2874 __ btst(Rret, G4_scratch); | |
2875 __ br(Assembler::zero, false, Assembler::pt, notFinal); | |
2876 __ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters | |
2877 | |
2878 patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp); | |
2879 | |
2880 invokevfinal_helper(Rscratch, Rret); | |
2881 | |
2882 __ bind(notFinal); | |
2883 | |
2884 __ mov(G5_method, Rscratch); // better scratch register | |
2885 __ load_receiver(G4_scratch, O0); // gets receiverOop | |
2886 // receiver is in O0 | |
2887 __ verify_oop(O0); | |
2888 | |
2889 // get return address | |
727 | 2890 AddressLiteral table(Interpreter::return_3_addrs_by_index_table()); |
2891 __ set(table, Rtemp); | |
0 | 2892 __ srl(Rret, ConstantPoolCacheEntry::tosBits, Rret); // get return type |
2893 // Make sure we don't need to mask Rret for tosBits after the above shift | |
2894 ConstantPoolCacheEntry::verify_tosBits(); | |
2895 __ sll(Rret, LogBytesPerWord, Rret); | |
2896 __ ld_ptr(Rtemp, Rret, Rret); // get return address | |
2897 | |
2898 // get receiver klass | |
2899 __ null_check(O0, oopDesc::klass_offset_in_bytes()); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
2900 __ load_klass(O0, Rrecv); |
0 | 2901 __ verify_oop(Rrecv); |
2902 | |
2903 __ profile_virtual_call(Rrecv, O4); | |
2904 | |
2905 generate_vtable_call(Rrecv, Rscratch, Rret); | |
2906 } | |
2907 | |
2908 void TemplateTable::fast_invokevfinal(int byte_no) { | |
2909 transition(vtos, vtos); | |
1565 | 2910 assert(byte_no == f2_byte, "use this argument"); |
0 | 2911 |
2912 load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Lscratch, true, | |
1565 | 2913 /*is_invokevfinal*/true, false); |
0 | 2914 __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore |
2915 invokevfinal_helper(G3_scratch, Lscratch); | |
2916 } | |
2917 | |
2918 void TemplateTable::invokevfinal_helper(Register Rscratch, Register Rret) { | |
2919 Register Rtemp = G4_scratch; | |
2920 | |
2921 __ verify_oop(G5_method); | |
2922 | |
2923 // Load receiver from stack slot | |
727 | 2924 __ lduh(G5_method, in_bytes(methodOopDesc::size_of_parameters_offset()), G4_scratch); |
0 | 2925 __ load_receiver(G4_scratch, O0); |
2926 | |
2927 // receiver NULL check | |
2928 __ null_check(O0); | |
2929 | |
2930 __ profile_final_call(O4); | |
2931 | |
2932 // get return address | |
727 | 2933 AddressLiteral table(Interpreter::return_3_addrs_by_index_table()); |
2934 __ set(table, Rtemp); | |
0 | 2935 __ srl(Rret, ConstantPoolCacheEntry::tosBits, Rret); // get return type |
2936 // Make sure we don't need to mask Rret for tosBits after the above shift | |
2937 ConstantPoolCacheEntry::verify_tosBits(); | |
2938 __ sll(Rret, LogBytesPerWord, Rret); | |
2939 __ ld_ptr(Rtemp, Rret, Rret); // get return address | |
2940 | |
2941 | |
2942 // do the call | |
2943 __ call_from_interpreter(Rscratch, Gargs, Rret); | |
2944 } | |
2945 | |
2946 void TemplateTable::invokespecial(int byte_no) { | |
2947 transition(vtos, vtos); | |
1565 | 2948 assert(byte_no == f1_byte, "use this argument"); |
0 | 2949 |
2950 Register Rscratch = G3_scratch; | |
2951 Register Rtemp = G4_scratch; | |
2952 Register Rret = Lscratch; | |
2953 | |
1565 | 2954 load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Rret, /*virtual*/ false, false, false); |
0 | 2955 __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore |
2956 | |
2957 __ verify_oop(G5_method); | |
2958 | |
727 | 2959 __ lduh(G5_method, in_bytes(methodOopDesc::size_of_parameters_offset()), G4_scratch); |
0 | 2960 __ load_receiver(G4_scratch, O0); |
2961 | |
2962 // receiver NULL check | |
2963 __ null_check(O0); | |
2964 | |
2965 __ profile_call(O4); | |
2966 | |
2967 // get return address | |
727 | 2968 AddressLiteral table(Interpreter::return_3_addrs_by_index_table()); |
2969 __ set(table, Rtemp); | |
0 | 2970 __ srl(Rret, ConstantPoolCacheEntry::tosBits, Rret); // get return type |
2971 // Make sure we don't need to mask Rret for tosBits after the above shift | |
2972 ConstantPoolCacheEntry::verify_tosBits(); | |
2973 __ sll(Rret, LogBytesPerWord, Rret); | |
2974 __ ld_ptr(Rtemp, Rret, Rret); // get return address | |
2975 | |
2976 // do the call | |
2977 __ call_from_interpreter(Rscratch, Gargs, Rret); | |
2978 } | |
2979 | |
2980 void TemplateTable::invokestatic(int byte_no) { | |
2981 transition(vtos, vtos); | |
1565 | 2982 assert(byte_no == f1_byte, "use this argument"); |
0 | 2983 |
2984 Register Rscratch = G3_scratch; | |
2985 Register Rtemp = G4_scratch; | |
2986 Register Rret = Lscratch; | |
2987 | |
1565 | 2988 load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Rret, /*virtual*/ false, false, false); |
0 | 2989 __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore |
2990 | |
2991 __ verify_oop(G5_method); | |
2992 | |
2993 __ profile_call(O4); | |
2994 | |
2995 // get return address | |
727 | 2996 AddressLiteral table(Interpreter::return_3_addrs_by_index_table()); |
2997 __ set(table, Rtemp); | |
0 | 2998 __ srl(Rret, ConstantPoolCacheEntry::tosBits, Rret); // get return type |
2999 // Make sure we don't need to mask Rret for tosBits after the above shift | |
3000 ConstantPoolCacheEntry::verify_tosBits(); | |
3001 __ sll(Rret, LogBytesPerWord, Rret); | |
3002 __ ld_ptr(Rtemp, Rret, Rret); // get return address | |
3003 | |
3004 // do the call | |
3005 __ call_from_interpreter(Rscratch, Gargs, Rret); | |
3006 } | |
3007 | |
3008 | |
3009 void TemplateTable::invokeinterface_object_method(Register RklassOop, | |
3010 Register Rcall, | |
3011 Register Rret, | |
3012 Register Rflags) { | |
3013 Register Rscratch = G4_scratch; | |
3014 Register Rindex = Lscratch; | |
3015 | |
3016 assert_different_registers(Rscratch, Rindex, Rret); | |
3017 | |
3018 Label notFinal; | |
3019 | |
3020 // Check for vfinal | |
3021 __ set((1 << ConstantPoolCacheEntry::vfinalMethod), Rscratch); | |
3022 __ btst(Rflags, Rscratch); | |
3023 __ br(Assembler::zero, false, Assembler::pt, notFinal); | |
3024 __ delayed()->nop(); | |
3025 | |
3026 __ profile_final_call(O4); | |
3027 | |
3028 // do the call - the index (f2) contains the methodOop | |
3029 assert_different_registers(G5_method, Gargs, Rcall); | |
3030 __ mov(Rindex, G5_method); | |
3031 __ call_from_interpreter(Rcall, Gargs, Rret); | |
3032 __ bind(notFinal); | |
3033 | |
3034 __ profile_virtual_call(RklassOop, O4); | |
3035 generate_vtable_call(RklassOop, Rindex, Rret); | |
3036 } | |
3037 | |
3038 | |
3039 void TemplateTable::invokeinterface(int byte_no) { | |
3040 transition(vtos, vtos); | |
1565 | 3041 assert(byte_no == f1_byte, "use this argument"); |
0 | 3042 |
3043 Register Rscratch = G4_scratch; | |
3044 Register Rret = G3_scratch; | |
3045 Register Rindex = Lscratch; | |
3046 Register Rinterface = G1_scratch; | |
3047 Register RklassOop = G5_method; | |
3048 Register Rflags = O1; | |
3049 assert_different_registers(Rscratch, G5_method); | |
3050 | |
1565 | 3051 load_invoke_cp_cache_entry(byte_no, Rinterface, Rindex, Rflags, /*virtual*/ false, false, false); |
0 | 3052 __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore |
3053 | |
3054 // get receiver | |
3055 __ and3(Rflags, 0xFF, Rscratch); // gets number of parameters | |
3056 __ load_receiver(Rscratch, O0); | |
3057 __ verify_oop(O0); | |
3058 | |
3059 __ mov(Rflags, Rret); | |
3060 | |
3061 // get return address | |
727 | 3062 AddressLiteral table(Interpreter::return_5_addrs_by_index_table()); |
3063 __ set(table, Rscratch); | |
0 | 3064 __ srl(Rret, ConstantPoolCacheEntry::tosBits, Rret); // get return type |
3065 // Make sure we don't need to mask Rret for tosBits after the above shift | |
3066 ConstantPoolCacheEntry::verify_tosBits(); | |
3067 __ sll(Rret, LogBytesPerWord, Rret); | |
3068 __ ld_ptr(Rscratch, Rret, Rret); // get return address | |
3069 | |
3070 // get receiver klass | |
3071 __ null_check(O0, oopDesc::klass_offset_in_bytes()); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3072 __ load_klass(O0, RklassOop); |
0 | 3073 __ verify_oop(RklassOop); |
3074 | |
3075 // Special case of invokeinterface called for virtual method of | |
3076 // java.lang.Object. See cpCacheOop.cpp for details. | |
3077 // This code isn't produced by javac, but could be produced by | |
3078 // another compliant java compiler. | |
3079 Label notMethod; | |
3080 __ set((1 << ConstantPoolCacheEntry::methodInterface), Rscratch); | |
3081 __ btst(Rflags, Rscratch); | |
3082 __ br(Assembler::zero, false, Assembler::pt, notMethod); | |
3083 __ delayed()->nop(); | |
3084 | |
3085 invokeinterface_object_method(RklassOop, Rinterface, Rret, Rflags); | |
3086 | |
3087 __ bind(notMethod); | |
3088 | |
3089 __ profile_virtual_call(RklassOop, O4); | |
3090 | |
3091 // | |
3092 // find entry point to call | |
3093 // | |
3094 | |
3095 // compute start of first itableOffsetEntry (which is at end of vtable) | |
3096 const int base = instanceKlass::vtable_start_offset() * wordSize; | |
3097 Label search; | |
3098 Register Rtemp = Rflags; | |
3099 | |
727 | 3100 __ ld(RklassOop, instanceKlass::vtable_length_offset() * wordSize, Rtemp); |
0 | 3101 if (align_object_offset(1) > 1) { |
3102 __ round_to(Rtemp, align_object_offset(1)); | |
3103 } | |
3104 __ sll(Rtemp, LogBytesPerWord, Rtemp); // Rscratch *= 4; | |
3105 if (Assembler::is_simm13(base)) { | |
3106 __ add(Rtemp, base, Rtemp); | |
3107 } else { | |
3108 __ set(base, Rscratch); | |
3109 __ add(Rscratch, Rtemp, Rtemp); | |
3110 } | |
3111 __ add(RklassOop, Rtemp, Rscratch); | |
3112 | |
3113 __ bind(search); | |
3114 | |
3115 __ ld_ptr(Rscratch, itableOffsetEntry::interface_offset_in_bytes(), Rtemp); | |
3116 { | |
3117 Label ok; | |
3118 | |
3119 // Check that entry is non-null. Null entries are probably a bytecode | |
605 | 3120 // problem. If the interface isn't implemented by the receiver class, |
0 | 3121 // the VM should throw IncompatibleClassChangeError. linkResolver checks |
3122 // this too but that's only if the entry isn't already resolved, so we | |
3123 // need to check again. | |
3124 __ br_notnull( Rtemp, false, Assembler::pt, ok); | |
3125 __ delayed()->nop(); | |
3126 call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError)); | |
3127 __ should_not_reach_here(); | |
3128 __ bind(ok); | |
3129 __ verify_oop(Rtemp); | |
3130 } | |
3131 | |
3132 __ verify_oop(Rinterface); | |
3133 | |
3134 __ cmp(Rinterface, Rtemp); | |
3135 __ brx(Assembler::notEqual, true, Assembler::pn, search); | |
3136 __ delayed()->add(Rscratch, itableOffsetEntry::size() * wordSize, Rscratch); | |
3137 | |
3138 // entry found and Rscratch points to it | |
3139 __ ld(Rscratch, itableOffsetEntry::offset_offset_in_bytes(), Rscratch); | |
3140 | |
3141 assert(itableMethodEntry::method_offset_in_bytes() == 0, "adjust instruction below"); | |
3142 __ sll(Rindex, exact_log2(itableMethodEntry::size() * wordSize), Rindex); // Rindex *= 8; | |
3143 __ add(Rscratch, Rindex, Rscratch); | |
3144 __ ld_ptr(RklassOop, Rscratch, G5_method); | |
3145 | |
3146 // Check for abstract method error. | |
3147 { | |
3148 Label ok; | |
3149 __ tst(G5_method); | |
3150 __ brx(Assembler::notZero, false, Assembler::pt, ok); | |
3151 __ delayed()->nop(); | |
3152 call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); | |
3153 __ should_not_reach_here(); | |
3154 __ bind(ok); | |
3155 } | |
3156 | |
3157 Register Rcall = Rinterface; | |
3158 assert_different_registers(Rcall, G5_method, Gargs, Rret); | |
3159 | |
3160 __ verify_oop(G5_method); | |
3161 __ call_from_interpreter(Rcall, Gargs, Rret); | |
3162 | |
3163 } | |
3164 | |
3165 | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3166 void TemplateTable::invokedynamic(int byte_no) { |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3167 transition(vtos, vtos); |
1565 | 3168 assert(byte_no == f1_oop, "use this argument"); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3169 |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3170 if (!EnableInvokeDynamic) { |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3171 // We should not encounter this bytecode if !EnableInvokeDynamic. |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3172 // The verifier will stop it. However, if we get past the verifier, |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3173 // this will stop the thread in a reasonable way, without crashing the JVM. |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3174 __ call_VM(noreg, CAST_FROM_FN_PTR(address, |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3175 InterpreterRuntime::throw_IncompatibleClassChangeError)); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3176 // the call_VM checks for exception, so we should never return here. |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3177 __ should_not_reach_here(); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3178 return; |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3179 } |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3180 |
1503 | 3181 // G5: CallSite object (f1) |
3182 // XX: unused (f2) | |
3183 // XX: flags (unused) | |
3184 | |
3185 Register G5_callsite = G5_method; | |
3186 Register Rscratch = G3_scratch; | |
3187 Register Rtemp = G1_scratch; | |
3188 Register Rret = Lscratch; | |
3189 | |
1565 | 3190 load_invoke_cp_cache_entry(byte_no, G5_callsite, noreg, Rret, |
3191 /*virtual*/ false, /*vfinal*/ false, /*indy*/ true); | |
1503 | 3192 __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore |
3193 | |
3194 __ verify_oop(G5_callsite); | |
3195 | |
3196 // profile this call | |
3197 __ profile_call(O4); | |
3198 | |
3199 // get return address | |
3200 AddressLiteral table(Interpreter::return_5_addrs_by_index_table()); | |
3201 __ set(table, Rtemp); | |
3202 __ srl(Rret, ConstantPoolCacheEntry::tosBits, Rret); // get return type | |
3203 // Make sure we don't need to mask Rret for tosBits after the above shift | |
3204 ConstantPoolCacheEntry::verify_tosBits(); | |
3205 __ sll(Rret, LogBytesPerWord, Rret); | |
3206 __ ld_ptr(Rtemp, Rret, Rret); // get return address | |
3207 | |
3208 __ ld_ptr(G5_callsite, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, Rscratch), G3_method_handle); | |
3209 __ null_check(G3_method_handle); | |
3210 | |
3211 // Adjust Rret first so Llast_SP can be same as Rret | |
3212 __ add(Rret, -frame::pc_return_offset, O7); | |
3213 __ add(Lesp, BytesPerWord, Gargs); // setup parameter pointer | |
3214 __ jump_to_method_handle_entry(G3_method_handle, Rtemp, /* emit_delayed_nop */ false); | |
3215 // Record SP so we can remove any stack space allocated by adapter transition | |
3216 __ delayed()->mov(SP, Llast_SP); | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3217 } |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3218 |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
605
diff
changeset
|
3219 |
0 | 3220 //---------------------------------------------------------------------------------------------------- |
3221 // Allocation | |
3222 | |
3223 void TemplateTable::_new() { | |
3224 transition(vtos, atos); | |
3225 | |
3226 Label slow_case; | |
3227 Label done; | |
3228 Label initialize_header; | |
3229 Label initialize_object; // including clearing the fields | |
3230 | |
3231 Register RallocatedObject = Otos_i; | |
3232 Register RinstanceKlass = O1; | |
3233 Register Roffset = O3; | |
3234 Register Rscratch = O4; | |
3235 | |
3236 __ get_2_byte_integer_at_bcp(1, Rscratch, Roffset, InterpreterMacroAssembler::Unsigned); | |
3237 __ get_cpool_and_tags(Rscratch, G3_scratch); | |
3238 // make sure the class we're about to instantiate has been resolved | |
3239 __ add(G3_scratch, typeArrayOopDesc::header_size(T_BYTE) * wordSize, G3_scratch); | |
3240 __ ldub(G3_scratch, Roffset, G3_scratch); | |
3241 __ cmp(G3_scratch, JVM_CONSTANT_Class); | |
3242 __ br(Assembler::notEqual, false, Assembler::pn, slow_case); | |
3243 __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); | |
3244 | |
3245 //__ sll(Roffset, LogBytesPerWord, Roffset); // executed in delay slot | |
3246 __ add(Roffset, sizeof(constantPoolOopDesc), Roffset); | |
3247 __ ld_ptr(Rscratch, Roffset, RinstanceKlass); | |
3248 | |
3249 // make sure klass is fully initialized: | |
3250 __ ld(RinstanceKlass, instanceKlass::init_state_offset_in_bytes() + sizeof(oopDesc), G3_scratch); | |
3251 __ cmp(G3_scratch, instanceKlass::fully_initialized); | |
3252 __ br(Assembler::notEqual, false, Assembler::pn, slow_case); | |
3253 __ delayed()->ld(RinstanceKlass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc), Roffset); | |
3254 | |
3255 // get instance_size in instanceKlass (already aligned) | |
3256 //__ ld(RinstanceKlass, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc), Roffset); | |
3257 | |
3258 // make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class | |
3259 __ btst(Klass::_lh_instance_slow_path_bit, Roffset); | |
3260 __ br(Assembler::notZero, false, Assembler::pn, slow_case); | |
3261 __ delayed()->nop(); | |
3262 | |
3263 // allocate the instance | |
3264 // 1) Try to allocate in the TLAB | |
3265 // 2) if fail, and the TLAB is not full enough to discard, allocate in the shared Eden | |
3266 // 3) if the above fails (or is not applicable), go to a slow case | |
3267 // (creates a new TLAB, etc.) | |
3268 | |
3269 const bool allow_shared_alloc = | |
3270 Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; | |
3271 | |
3272 if(UseTLAB) { | |
3273 Register RoldTopValue = RallocatedObject; | |
3274 Register RtopAddr = G3_scratch, RtlabWasteLimitValue = G3_scratch; | |
3275 Register RnewTopValue = G1_scratch; | |
3276 Register RendValue = Rscratch; | |
3277 Register RfreeValue = RnewTopValue; | |
3278 | |
3279 // check if we can allocate in the TLAB | |
3280 __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), RoldTopValue); // sets up RalocatedObject | |
3281 __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), RendValue); | |
3282 __ add(RoldTopValue, Roffset, RnewTopValue); | |
3283 | |
3284 // if there is enough space, we do not CAS and do not clear | |
3285 __ cmp(RnewTopValue, RendValue); | |
3286 if(ZeroTLAB) { | |
3287 // the fields have already been cleared | |
3288 __ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_header); | |
3289 } else { | |
3290 // initialize both the header and fields | |
3291 __ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_object); | |
3292 } | |
3293 __ delayed()->st_ptr(RnewTopValue, G2_thread, in_bytes(JavaThread::tlab_top_offset())); | |
3294 | |
3295 if (allow_shared_alloc) { | |
3296 // Check if tlab should be discarded (refill_waste_limit >= free) | |
3297 __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), RtlabWasteLimitValue); | |
3298 __ sub(RendValue, RoldTopValue, RfreeValue); | |
3299 #ifdef _LP64 | |
3300 __ srlx(RfreeValue, LogHeapWordSize, RfreeValue); | |
3301 #else | |
3302 __ srl(RfreeValue, LogHeapWordSize, RfreeValue); | |
3303 #endif | |
3304 __ cmp(RtlabWasteLimitValue, RfreeValue); | |
3305 __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, slow_case); // tlab waste is small | |
3306 __ delayed()->nop(); | |
3307 | |
3308 // increment waste limit to prevent getting stuck on this slow path | |
3309 __ add(RtlabWasteLimitValue, ThreadLocalAllocBuffer::refill_waste_limit_increment(), RtlabWasteLimitValue); | |
3310 __ st_ptr(RtlabWasteLimitValue, G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset())); | |
3311 } else { | |
3312 // No allocation in the shared eden. | |
3313 __ br(Assembler::always, false, Assembler::pt, slow_case); | |
3314 __ delayed()->nop(); | |
3315 } | |
3316 } | |
3317 | |
3318 // Allocation in the shared Eden | |
3319 if (allow_shared_alloc) { | |
3320 Register RoldTopValue = G1_scratch; | |
3321 Register RtopAddr = G3_scratch; | |
3322 Register RnewTopValue = RallocatedObject; | |
3323 Register RendValue = Rscratch; | |
3324 | |
3325 __ set((intptr_t)Universe::heap()->top_addr(), RtopAddr); | |
3326 | |
3327 Label retry; | |
3328 __ bind(retry); | |
3329 __ set((intptr_t)Universe::heap()->end_addr(), RendValue); | |
3330 __ ld_ptr(RendValue, 0, RendValue); | |
3331 __ ld_ptr(RtopAddr, 0, RoldTopValue); | |
3332 __ add(RoldTopValue, Roffset, RnewTopValue); | |
3333 | |
3334 // RnewTopValue contains the top address after the new object | |
3335 // has been allocated. | |
3336 __ cmp(RnewTopValue, RendValue); | |
3337 __ brx(Assembler::greaterUnsigned, false, Assembler::pn, slow_case); | |
3338 __ delayed()->nop(); | |
3339 | |
3340 __ casx_under_lock(RtopAddr, RoldTopValue, RnewTopValue, | |
3341 VM_Version::v9_instructions_work() ? NULL : | |
3342 (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr()); | |
3343 | |
3344 // if someone beat us on the allocation, try again, otherwise continue | |
3345 __ cmp(RoldTopValue, RnewTopValue); | |
3346 __ brx(Assembler::notEqual, false, Assembler::pn, retry); | |
3347 __ delayed()->nop(); | |
3348 } | |
3349 | |
3350 if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { | |
3351 // clear object fields | |
3352 __ bind(initialize_object); | |
3353 __ deccc(Roffset, sizeof(oopDesc)); | |
3354 __ br(Assembler::zero, false, Assembler::pt, initialize_header); | |
3355 __ delayed()->add(RallocatedObject, sizeof(oopDesc), G3_scratch); | |
3356 | |
3357 // initialize remaining object fields | |
3358 { Label loop; | |
3359 __ subcc(Roffset, wordSize, Roffset); | |
3360 __ bind(loop); | |
3361 //__ subcc(Roffset, wordSize, Roffset); // executed above loop or in delay slot | |
3362 __ st_ptr(G0, G3_scratch, Roffset); | |
3363 __ br(Assembler::notEqual, false, Assembler::pt, loop); | |
3364 __ delayed()->subcc(Roffset, wordSize, Roffset); | |
3365 } | |
3366 __ br(Assembler::always, false, Assembler::pt, initialize_header); | |
3367 __ delayed()->nop(); | |
3368 } | |
3369 | |
3370 // slow case | |
3371 __ bind(slow_case); | |
3372 __ get_2_byte_integer_at_bcp(1, G3_scratch, O2, InterpreterMacroAssembler::Unsigned); | |
3373 __ get_constant_pool(O1); | |
3374 | |
3375 call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), O1, O2); | |
3376 | |
3377 __ ba(false, done); | |
3378 __ delayed()->nop(); | |
3379 | |
3380 // Initialize the header: mark, klass | |
3381 __ bind(initialize_header); | |
3382 | |
3383 if (UseBiasedLocking) { | |
3384 __ ld_ptr(RinstanceKlass, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), G4_scratch); | |
3385 } else { | |
3386 __ set((intptr_t)markOopDesc::prototype(), G4_scratch); | |
3387 } | |
3388 __ st_ptr(G4_scratch, RallocatedObject, oopDesc::mark_offset_in_bytes()); // mark | |
167
feeb96a45707
6696264: assert("narrow oop can never be zero") for GCBasher & ParNewGC
coleenp
parents:
113
diff
changeset
|
3389 __ store_klass_gap(G0, RallocatedObject); // klass gap if compressed |
feeb96a45707
6696264: assert("narrow oop can never be zero") for GCBasher & ParNewGC
coleenp
parents:
113
diff
changeset
|
3390 __ store_klass(RinstanceKlass, RallocatedObject); // klass (last for cms) |
0 | 3391 |
3392 { | |
3393 SkipIfEqual skip_if( | |
3394 _masm, G4_scratch, &DTraceAllocProbes, Assembler::zero); | |
3395 // Trigger dtrace event | |
3396 __ push(atos); | |
3397 __ call_VM_leaf(noreg, | |
3398 CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), O0); | |
3399 __ pop(atos); | |
3400 } | |
3401 | |
3402 // continue | |
3403 __ bind(done); | |
3404 } | |
3405 | |
3406 | |
3407 | |
3408 void TemplateTable::newarray() { | |
3409 transition(itos, atos); | |
3410 __ ldub(Lbcp, 1, O1); | |
3411 call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), O1, Otos_i); | |
3412 } | |
3413 | |
3414 | |
3415 void TemplateTable::anewarray() { | |
3416 transition(itos, atos); | |
3417 __ get_constant_pool(O1); | |
3418 __ get_2_byte_integer_at_bcp(1, G4_scratch, O2, InterpreterMacroAssembler::Unsigned); | |
3419 call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), O1, O2, Otos_i); | |
3420 } | |
3421 | |
3422 | |
3423 void TemplateTable::arraylength() { | |
3424 transition(atos, itos); | |
3425 Label ok; | |
3426 __ verify_oop(Otos_i); | |
3427 __ tst(Otos_i); | |
3428 __ throw_if_not_1_x( Assembler::notZero, ok ); | |
3429 __ delayed()->ld(Otos_i, arrayOopDesc::length_offset_in_bytes(), Otos_i); | |
3430 __ throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ok); | |
3431 } | |
3432 | |
3433 | |
3434 void TemplateTable::checkcast() { | |
3435 transition(atos, atos); | |
3436 Label done, is_null, quicked, cast_ok, resolved; | |
3437 Register Roffset = G1_scratch; | |
3438 Register RobjKlass = O5; | |
3439 Register RspecifiedKlass = O4; | |
3440 | |
3441 // Check for casting a NULL | |
3442 __ br_null(Otos_i, false, Assembler::pn, is_null); | |
3443 __ delayed()->nop(); | |
3444 | |
3445 // Get value klass in RobjKlass | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3446 __ load_klass(Otos_i, RobjKlass); // get value klass |
0 | 3447 |
3448 // Get constant pool tag | |
3449 __ get_2_byte_integer_at_bcp(1, Lscratch, Roffset, InterpreterMacroAssembler::Unsigned); | |
3450 | |
3451 // See if the checkcast has been quickened | |
3452 __ get_cpool_and_tags(Lscratch, G3_scratch); | |
3453 __ add(G3_scratch, typeArrayOopDesc::header_size(T_BYTE) * wordSize, G3_scratch); | |
3454 __ ldub(G3_scratch, Roffset, G3_scratch); | |
3455 __ cmp(G3_scratch, JVM_CONSTANT_Class); | |
3456 __ br(Assembler::equal, true, Assembler::pt, quicked); | |
3457 __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); | |
3458 | |
3459 __ push_ptr(); // save receiver for result, and for GC | |
3460 call_VM(RspecifiedKlass, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) ); | |
3461 __ pop_ptr(Otos_i, G3_scratch); // restore receiver | |
3462 | |
3463 __ br(Assembler::always, false, Assembler::pt, resolved); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3464 __ delayed()->nop(); |
0 | 3465 |
3466 // Extract target class from constant pool | |
3467 __ bind(quicked); | |
3468 __ add(Roffset, sizeof(constantPoolOopDesc), Roffset); | |
3469 __ ld_ptr(Lscratch, Roffset, RspecifiedKlass); | |
3470 __ bind(resolved); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3471 __ load_klass(Otos_i, RobjKlass); // get value klass |
0 | 3472 |
3473 // Generate a fast subtype check. Branch to cast_ok if no | |
3474 // failure. Throw exception if failure. | |
3475 __ gen_subtype_check( RobjKlass, RspecifiedKlass, G3_scratch, G4_scratch, G1_scratch, cast_ok ); | |
3476 | |
3477 // Not a subtype; so must throw exception | |
3478 __ throw_if_not_x( Assembler::never, Interpreter::_throw_ClassCastException_entry, G3_scratch ); | |
3479 | |
3480 __ bind(cast_ok); | |
3481 | |
3482 if (ProfileInterpreter) { | |
3483 __ ba(false, done); | |
3484 __ delayed()->nop(); | |
3485 } | |
3486 __ bind(is_null); | |
3487 __ profile_null_seen(G3_scratch); | |
3488 __ bind(done); | |
3489 } | |
3490 | |
3491 | |
3492 void TemplateTable::instanceof() { | |
3493 Label done, is_null, quicked, resolved; | |
3494 transition(atos, itos); | |
3495 Register Roffset = G1_scratch; | |
3496 Register RobjKlass = O5; | |
3497 Register RspecifiedKlass = O4; | |
3498 | |
3499 // Check for casting a NULL | |
3500 __ br_null(Otos_i, false, Assembler::pt, is_null); | |
3501 __ delayed()->nop(); | |
3502 | |
3503 // Get value klass in RobjKlass | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3504 __ load_klass(Otos_i, RobjKlass); // get value klass |
0 | 3505 |
3506 // Get constant pool tag | |
3507 __ get_2_byte_integer_at_bcp(1, Lscratch, Roffset, InterpreterMacroAssembler::Unsigned); | |
3508 | |
3509 // See if the checkcast has been quickened | |
3510 __ get_cpool_and_tags(Lscratch, G3_scratch); | |
3511 __ add(G3_scratch, typeArrayOopDesc::header_size(T_BYTE) * wordSize, G3_scratch); | |
3512 __ ldub(G3_scratch, Roffset, G3_scratch); | |
3513 __ cmp(G3_scratch, JVM_CONSTANT_Class); | |
3514 __ br(Assembler::equal, true, Assembler::pt, quicked); | |
3515 __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); | |
3516 | |
3517 __ push_ptr(); // save receiver for result, and for GC | |
3518 call_VM(RspecifiedKlass, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) ); | |
3519 __ pop_ptr(Otos_i, G3_scratch); // restore receiver | |
3520 | |
3521 __ br(Assembler::always, false, Assembler::pt, resolved); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3522 __ delayed()->nop(); |
0 | 3523 |
3524 | |
3525 // Extract target class from constant pool | |
3526 __ bind(quicked); | |
3527 __ add(Roffset, sizeof(constantPoolOopDesc), Roffset); | |
3528 __ get_constant_pool(Lscratch); | |
3529 __ ld_ptr(Lscratch, Roffset, RspecifiedKlass); | |
3530 __ bind(resolved); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
3531 __ load_klass(Otos_i, RobjKlass); // get value klass |
0 | 3532 |
3533 // Generate a fast subtype check. Branch to cast_ok if no | |
3534 // failure. Return 0 if failure. | |
3535 __ or3(G0, 1, Otos_i); // set result assuming quick tests succeed | |
3536 __ gen_subtype_check( RobjKlass, RspecifiedKlass, G3_scratch, G4_scratch, G1_scratch, done ); | |
3537 // Not a subtype; return 0; | |
3538 __ clr( Otos_i ); | |
3539 | |
3540 if (ProfileInterpreter) { | |
3541 __ ba(false, done); | |
3542 __ delayed()->nop(); | |
3543 } | |
3544 __ bind(is_null); | |
3545 __ profile_null_seen(G3_scratch); | |
3546 __ bind(done); | |
3547 } | |
3548 | |
3549 void TemplateTable::_breakpoint() { | |
3550 | |
3551 // Note: We get here even if we are single stepping.. | |
3552 // jbug inists on setting breakpoints at every bytecode | |
3553 // even if we are in single step mode. | |
3554 | |
3555 transition(vtos, vtos); | |
3556 // get the unpatched byte code | |
3557 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), Lmethod, Lbcp); | |
3558 __ mov(O0, Lbyte_code); | |
3559 | |
3560 // post the breakpoint event | |
3561 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), Lmethod, Lbcp); | |
3562 | |
3563 // complete the execution of original bytecode | |
3564 __ dispatch_normal(vtos); | |
3565 } | |
3566 | |
3567 | |
3568 //---------------------------------------------------------------------------------------------------- | |
3569 // Exceptions | |
3570 | |
3571 void TemplateTable::athrow() { | |
3572 transition(atos, vtos); | |
3573 | |
3574 // This works because exception is cached in Otos_i which is same as O0, | |
3575 // which is same as what throw_exception_entry_expects | |
3576 assert(Otos_i == Oexception, "see explanation above"); | |
3577 | |
3578 __ verify_oop(Otos_i); | |
3579 __ null_check(Otos_i); | |
3580 __ throw_if_not_x(Assembler::never, Interpreter::throw_exception_entry(), G3_scratch); | |
3581 } | |
3582 | |
3583 | |
3584 //---------------------------------------------------------------------------------------------------- | |
3585 // Synchronization | |
3586 | |
3587 | |
3588 // See frame_sparc.hpp for monitor block layout. | |
3589 // Monitor elements are dynamically allocated by growing stack as needed. | |
3590 | |
3591 void TemplateTable::monitorenter() { | |
3592 transition(atos, vtos); | |
3593 __ verify_oop(Otos_i); | |
3594 // Try to acquire a lock on the object | |
3595 // Repeat until succeeded (i.e., until | |
3596 // monitorenter returns true). | |
3597 | |
3598 { Label ok; | |
3599 __ tst(Otos_i); | |
3600 __ throw_if_not_1_x( Assembler::notZero, ok); | |
3601 __ delayed()->mov(Otos_i, Lscratch); // save obj | |
3602 __ throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ok); | |
3603 } | |
3604 | |
3605 assert(O0 == Otos_i, "Be sure where the object to lock is"); | |
3606 | |
3607 // find a free slot in the monitor block | |
3608 | |
3609 | |
3610 // initialize entry pointer | |
3611 __ clr(O1); // points to free slot or NULL | |
3612 | |
3613 { | |
3614 Label entry, loop, exit; | |
3615 __ add( __ top_most_monitor(), O2 ); // last one to check | |
3616 __ ba( false, entry ); | |
3617 __ delayed()->mov( Lmonitors, O3 ); // first one to check | |
3618 | |
3619 | |
3620 __ bind( loop ); | |
3621 | |
3622 __ verify_oop(O4); // verify each monitor's oop | |
3623 __ tst(O4); // is this entry unused? | |
3624 if (VM_Version::v9_instructions_work()) | |
3625 __ movcc( Assembler::zero, false, Assembler::ptr_cc, O3, O1); | |
3626 else { | |
3627 Label L; | |
3628 __ br( Assembler::zero, true, Assembler::pn, L ); | |
3629 __ delayed()->mov(O3, O1); // rememeber this one if match | |
3630 __ bind(L); | |
3631 } | |
3632 | |
3633 __ cmp(O4, O0); // check if current entry is for same object | |
3634 __ brx( Assembler::equal, false, Assembler::pn, exit ); | |
3635 __ delayed()->inc( O3, frame::interpreter_frame_monitor_size() * wordSize ); // check next one | |
3636 | |
3637 __ bind( entry ); | |
3638 | |
3639 __ cmp( O3, O2 ); | |
3640 __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, loop ); | |
3641 __ delayed()->ld_ptr(O3, BasicObjectLock::obj_offset_in_bytes(), O4); | |
3642 | |
3643 __ bind( exit ); | |
3644 } | |
3645 | |
3646 { Label allocated; | |
3647 | |
3648 // found free slot? | |
3649 __ br_notnull(O1, false, Assembler::pn, allocated); | |
3650 __ delayed()->nop(); | |
3651 | |
3652 __ add_monitor_to_stack( false, O2, O3 ); | |
3653 __ mov(Lmonitors, O1); | |
3654 | |
3655 __ bind(allocated); | |
3656 } | |
3657 | |
3658 // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly. | |
3659 // The object has already been poped from the stack, so the expression stack looks correct. | |
3660 __ inc(Lbcp); | |
3661 | |
3662 __ st_ptr(O0, O1, BasicObjectLock::obj_offset_in_bytes()); // store object | |
3663 __ lock_object(O1, O0); | |
3664 | |
3665 // check if there's enough space on the stack for the monitors after locking | |
3666 __ generate_stack_overflow_check(0); | |
3667 | |
3668 // The bcp has already been incremented. Just need to dispatch to next instruction. | |
3669 __ dispatch_next(vtos); | |
3670 } | |
3671 | |
3672 | |
3673 void TemplateTable::monitorexit() { | |
3674 transition(atos, vtos); | |
3675 __ verify_oop(Otos_i); | |
3676 __ tst(Otos_i); | |
3677 __ throw_if_not_x( Assembler::notZero, Interpreter::_throw_NullPointerException_entry, G3_scratch ); | |
3678 | |
3679 assert(O0 == Otos_i, "just checking"); | |
3680 | |
3681 { Label entry, loop, found; | |
3682 __ add( __ top_most_monitor(), O2 ); // last one to check | |
3683 __ ba(false, entry ); | |
3684 // use Lscratch to hold monitor elem to check, start with most recent monitor, | |
3685 // By using a local it survives the call to the C routine. | |
3686 __ delayed()->mov( Lmonitors, Lscratch ); | |
3687 | |
3688 __ bind( loop ); | |
3689 | |
3690 __ verify_oop(O4); // verify each monitor's oop | |
3691 __ cmp(O4, O0); // check if current entry is for desired object | |
3692 __ brx( Assembler::equal, true, Assembler::pt, found ); | |
3693 __ delayed()->mov(Lscratch, O1); // pass found entry as argument to monitorexit | |
3694 | |
3695 __ inc( Lscratch, frame::interpreter_frame_monitor_size() * wordSize ); // advance to next | |
3696 | |
3697 __ bind( entry ); | |
3698 | |
3699 __ cmp( Lscratch, O2 ); | |
3700 __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, loop ); | |
3701 __ delayed()->ld_ptr(Lscratch, BasicObjectLock::obj_offset_in_bytes(), O4); | |
3702 | |
3703 call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); | |
3704 __ should_not_reach_here(); | |
3705 | |
3706 __ bind(found); | |
3707 } | |
3708 __ unlock_object(O1); | |
3709 } | |
3710 | |
3711 | |
3712 //---------------------------------------------------------------------------------------------------- | |
3713 // Wide instructions | |
3714 | |
3715 void TemplateTable::wide() { | |
3716 transition(vtos, vtos); | |
3717 __ ldub(Lbcp, 1, G3_scratch);// get next bc | |
3718 __ sll(G3_scratch, LogBytesPerWord, G3_scratch); | |
727 | 3719 AddressLiteral ep(Interpreter::_wentry_point); |
3720 __ set(ep, G4_scratch); | |
3721 __ ld_ptr(G4_scratch, G3_scratch, G3_scratch); | |
0 | 3722 __ jmp(G3_scratch, G0); |
3723 __ delayed()->nop(); | |
3724 // Note: the Lbcp increment step is part of the individual wide bytecode implementations | |
3725 } | |
3726 | |
3727 | |
3728 //---------------------------------------------------------------------------------------------------- | |
3729 // Multi arrays | |
3730 | |
3731 void TemplateTable::multianewarray() { | |
3732 transition(vtos, atos); | |
3733 // put ndims * wordSize into Lscratch | |
3734 __ ldub( Lbcp, 3, Lscratch); | |
1506 | 3735 __ sll( Lscratch, Interpreter::logStackElementSize, Lscratch); |
0 | 3736 // Lesp points past last_dim, so set to O1 to first_dim address |
3737 __ add( Lesp, Lscratch, O1); | |
3738 call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), O1); | |
3739 __ add( Lesp, Lscratch, Lesp); // pop all dimensions off the stack | |
3740 } | |
3741 #endif /* !CC_INTERP */ |