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