Mercurial > hg > truffle
annotate src/cpu/x86/vm/templateTable_x86_32.cpp @ 2007:5ddfcf4b079e
7003554: (tiered) assert(is_null_object() || handle() != NULL) failed: cannot embed null pointer
Summary: C1 with profiling doesn't check whether the MDO has been really allocated, which can silently fail if the perm gen is full. The solution is to check if the allocation failed and bailout out of inlining or compilation.
Reviewed-by: kvn, never
author | iveresov |
---|---|
date | Thu, 02 Dec 2010 17:21:12 -0800 |
parents | f95d63e2154a |
children | b1a2afa37ec4 dd031b2226de |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
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 | |
41 //---------------------------------------------------------------------------------------------------- | |
42 // Platform-dependent initialization | |
43 | |
44 void TemplateTable::pd_initialize() { | |
45 // No i486 specific initialization | |
46 } | |
47 | |
48 //---------------------------------------------------------------------------------------------------- | |
49 // Address computation | |
50 | |
51 // local variables | |
52 static inline Address iaddress(int n) { | |
53 return Address(rdi, Interpreter::local_offset_in_bytes(n)); | |
54 } | |
55 | |
56 static inline Address laddress(int n) { return iaddress(n + 1); } | |
57 static inline Address haddress(int n) { return iaddress(n + 0); } | |
58 static inline Address faddress(int n) { return iaddress(n); } | |
59 static inline Address daddress(int n) { return laddress(n); } | |
60 static inline Address aaddress(int n) { return iaddress(n); } | |
61 | |
62 static inline Address iaddress(Register r) { | |
1506 | 63 return Address(rdi, r, Interpreter::stackElementScale()); |
0 | 64 } |
65 static inline Address laddress(Register r) { | |
66 return Address(rdi, r, Interpreter::stackElementScale(), Interpreter::local_offset_in_bytes(1)); | |
67 } | |
68 static inline Address haddress(Register r) { | |
69 return Address(rdi, r, Interpreter::stackElementScale(), Interpreter::local_offset_in_bytes(0)); | |
70 } | |
71 | |
1506 | 72 static inline Address faddress(Register r) { return iaddress(r); } |
73 static inline Address daddress(Register r) { return laddress(r); } | |
74 static inline Address aaddress(Register r) { return iaddress(r); } | |
0 | 75 |
76 // expression stack | |
77 // (Note: Must not use symmetric equivalents at_rsp_m1/2 since they store | |
78 // data beyond the rsp which is potentially unsafe in an MT environment; | |
79 // an interrupt may overwrite that data.) | |
80 static inline Address at_rsp () { | |
81 return Address(rsp, 0); | |
82 } | |
83 | |
84 // At top of Java expression stack which may be different than rsp(). It | |
85 // isn't for category 1 objects. | |
86 static inline Address at_tos () { | |
87 Address tos = Address(rsp, Interpreter::expr_offset_in_bytes(0)); | |
88 return tos; | |
89 } | |
90 | |
91 static inline Address at_tos_p1() { | |
92 return Address(rsp, Interpreter::expr_offset_in_bytes(1)); | |
93 } | |
94 | |
95 static inline Address at_tos_p2() { | |
96 return Address(rsp, Interpreter::expr_offset_in_bytes(2)); | |
97 } | |
98 | |
99 // Condition conversion | |
100 static Assembler::Condition j_not(TemplateTable::Condition cc) { | |
101 switch (cc) { | |
102 case TemplateTable::equal : return Assembler::notEqual; | |
103 case TemplateTable::not_equal : return Assembler::equal; | |
104 case TemplateTable::less : return Assembler::greaterEqual; | |
105 case TemplateTable::less_equal : return Assembler::greater; | |
106 case TemplateTable::greater : return Assembler::lessEqual; | |
107 case TemplateTable::greater_equal: return Assembler::less; | |
108 } | |
109 ShouldNotReachHere(); | |
110 return Assembler::zero; | |
111 } | |
112 | |
113 | |
114 //---------------------------------------------------------------------------------------------------- | |
115 // Miscelaneous helper routines | |
116 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
117 // Store an oop (or NULL) at the address described by obj. |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
118 // If val == noreg this means store a NULL |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
119 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
120 static void do_oop_store(InterpreterMacroAssembler* _masm, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
121 Address obj, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
122 Register val, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
123 BarrierSet::Name barrier, |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
124 bool precise) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
125 assert(val == noreg || val == rax, "parameter is just for looks"); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
126 switch (barrier) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
127 #ifndef SERIALGC |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
128 case BarrierSet::G1SATBCT: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
129 case BarrierSet::G1SATBCTLogging: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
130 { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
131 // flatten object address if needed |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
132 // We do it regardless of precise because we need the registers |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
133 if (obj.index() == noreg && obj.disp() == 0) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
134 if (obj.base() != rdx) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
135 __ movl(rdx, obj.base()); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
136 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
137 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
138 __ leal(rdx, obj); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
139 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
140 __ get_thread(rcx); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
141 __ save_bcp(); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
142 __ g1_write_barrier_pre(rdx, rcx, rsi, rbx, val != noreg); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
143 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
144 // Do the actual store |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
145 // noreg means NULL |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
146 if (val == noreg) { |
533
dc3ad84615cf
6795913: A few remaining wrong casts need to be fixed for building hotspot successfully on Mac OS.
xlu
parents:
512
diff
changeset
|
147 __ movptr(Address(rdx, 0), NULL_WORD); |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
148 // No post barrier for NULL |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
149 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
150 __ movl(Address(rdx, 0), val); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
151 __ g1_write_barrier_post(rdx, rax, rcx, rbx, rsi); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
152 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
153 __ restore_bcp(); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
154 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
155 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
156 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
157 #endif // SERIALGC |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
158 case BarrierSet::CardTableModRef: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
159 case BarrierSet::CardTableExtension: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
160 { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
161 if (val == noreg) { |
533
dc3ad84615cf
6795913: A few remaining wrong casts need to be fixed for building hotspot successfully on Mac OS.
xlu
parents:
512
diff
changeset
|
162 __ movptr(obj, NULL_WORD); |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
163 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
164 __ movl(obj, val); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
165 // flatten object address if needed |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
166 if (!precise || (obj.index() == noreg && obj.disp() == 0)) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
167 __ store_check(obj.base()); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
168 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
169 __ leal(rdx, obj); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
170 __ store_check(rdx); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
171 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
172 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
173 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
174 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
175 case BarrierSet::ModRef: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
176 case BarrierSet::Other: |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
177 if (val == noreg) { |
533
dc3ad84615cf
6795913: A few remaining wrong casts need to be fixed for building hotspot successfully on Mac OS.
xlu
parents:
512
diff
changeset
|
178 __ movptr(obj, NULL_WORD); |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
179 } else { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
180 __ movl(obj, val); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
181 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
182 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
183 default : |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
184 ShouldNotReachHere(); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
185 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
186 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
187 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
188 |
0 | 189 Address TemplateTable::at_bcp(int offset) { |
190 assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); | |
191 return Address(rsi, offset); | |
192 } | |
193 | |
194 | |
195 void TemplateTable::patch_bytecode(Bytecodes::Code bytecode, Register bc, | |
196 Register scratch, | |
197 bool load_bc_into_scratch/*=true*/) { | |
198 | |
199 if (!RewriteBytecodes) return; | |
200 // the pair bytecodes have already done the load. | |
304 | 201 if (load_bc_into_scratch) { |
202 __ movl(bc, bytecode); | |
203 } | |
0 | 204 Label patch_done; |
205 if (JvmtiExport::can_post_breakpoint()) { | |
206 Label fast_patch; | |
207 // if a breakpoint is present we can't rewrite the stream directly | |
304 | 208 __ movzbl(scratch, at_bcp(0)); |
0 | 209 __ cmpl(scratch, Bytecodes::_breakpoint); |
210 __ jcc(Assembler::notEqual, fast_patch); | |
211 __ get_method(scratch); | |
212 // Let breakpoint table handling rewrite to quicker bytecode | |
213 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), scratch, rsi, bc); | |
214 #ifndef ASSERT | |
215 __ jmpb(patch_done); | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
216 #else |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
217 __ jmp(patch_done); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
218 #endif |
0 | 219 __ bind(fast_patch); |
220 } | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
221 #ifdef ASSERT |
0 | 222 Label okay; |
223 __ load_unsigned_byte(scratch, at_bcp(0)); | |
224 __ cmpl(scratch, (int)Bytecodes::java_code(bytecode)); | |
225 __ jccb(Assembler::equal, okay); | |
226 __ cmpl(scratch, bc); | |
227 __ jcc(Assembler::equal, okay); | |
228 __ stop("patching the wrong bytecode"); | |
229 __ bind(okay); | |
230 #endif | |
231 // patch bytecode | |
232 __ movb(at_bcp(0), bc); | |
233 __ bind(patch_done); | |
234 } | |
235 | |
236 //---------------------------------------------------------------------------------------------------- | |
237 // Individual instructions | |
238 | |
239 void TemplateTable::nop() { | |
240 transition(vtos, vtos); | |
241 // nothing to do | |
242 } | |
243 | |
244 void TemplateTable::shouldnotreachhere() { | |
245 transition(vtos, vtos); | |
246 __ stop("shouldnotreachhere bytecode"); | |
247 } | |
248 | |
249 | |
250 | |
251 void TemplateTable::aconst_null() { | |
252 transition(vtos, atos); | |
304 | 253 __ xorptr(rax, rax); |
0 | 254 } |
255 | |
256 | |
257 void TemplateTable::iconst(int value) { | |
258 transition(vtos, itos); | |
259 if (value == 0) { | |
304 | 260 __ xorptr(rax, rax); |
0 | 261 } else { |
304 | 262 __ movptr(rax, value); |
0 | 263 } |
264 } | |
265 | |
266 | |
267 void TemplateTable::lconst(int value) { | |
268 transition(vtos, ltos); | |
269 if (value == 0) { | |
304 | 270 __ xorptr(rax, rax); |
0 | 271 } else { |
304 | 272 __ movptr(rax, value); |
0 | 273 } |
274 assert(value >= 0, "check this code"); | |
304 | 275 __ xorptr(rdx, rdx); |
0 | 276 } |
277 | |
278 | |
279 void TemplateTable::fconst(int value) { | |
280 transition(vtos, ftos); | |
281 if (value == 0) { __ fldz(); | |
282 } else if (value == 1) { __ fld1(); | |
283 } else if (value == 2) { __ fld1(); __ fld1(); __ faddp(); // should do a better solution here | |
284 } else { ShouldNotReachHere(); | |
285 } | |
286 } | |
287 | |
288 | |
289 void TemplateTable::dconst(int value) { | |
290 transition(vtos, dtos); | |
291 if (value == 0) { __ fldz(); | |
292 } else if (value == 1) { __ fld1(); | |
293 } else { ShouldNotReachHere(); | |
294 } | |
295 } | |
296 | |
297 | |
298 void TemplateTable::bipush() { | |
299 transition(vtos, itos); | |
300 __ load_signed_byte(rax, at_bcp(1)); | |
301 } | |
302 | |
303 | |
304 void TemplateTable::sipush() { | |
305 transition(vtos, itos); | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
306 __ load_unsigned_short(rax, at_bcp(1)); |
304 | 307 __ bswapl(rax); |
0 | 308 __ sarl(rax, 16); |
309 } | |
310 | |
311 void TemplateTable::ldc(bool wide) { | |
312 transition(vtos, vtos); | |
313 Label call_ldc, notFloat, notClass, Done; | |
314 | |
315 if (wide) { | |
316 __ get_unsigned_2_byte_index_at_bcp(rbx, 1); | |
317 } else { | |
318 __ load_unsigned_byte(rbx, at_bcp(1)); | |
319 } | |
320 __ get_cpool_and_tags(rcx, rax); | |
321 const int base_offset = constantPoolOopDesc::header_size() * wordSize; | |
322 const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; | |
323 | |
324 // get type | |
304 | 325 __ xorptr(rdx, rdx); |
0 | 326 __ movb(rdx, Address(rax, rbx, Address::times_1, tags_offset)); |
327 | |
328 // unresolved string - get the resolved string | |
329 __ cmpl(rdx, JVM_CONSTANT_UnresolvedString); | |
330 __ jccb(Assembler::equal, call_ldc); | |
331 | |
332 // unresolved class - get the resolved class | |
333 __ cmpl(rdx, JVM_CONSTANT_UnresolvedClass); | |
334 __ jccb(Assembler::equal, call_ldc); | |
335 | |
336 // unresolved class in error (resolution failed) - call into runtime | |
337 // so that the same error from first resolution attempt is thrown. | |
338 __ cmpl(rdx, JVM_CONSTANT_UnresolvedClassInError); | |
339 __ jccb(Assembler::equal, call_ldc); | |
340 | |
341 // resolved class - need to call vm to get java mirror of the class | |
342 __ cmpl(rdx, JVM_CONSTANT_Class); | |
343 __ jcc(Assembler::notEqual, notClass); | |
344 | |
345 __ bind(call_ldc); | |
346 __ movl(rcx, wide); | |
347 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), rcx); | |
348 __ push(atos); | |
349 __ jmp(Done); | |
350 | |
351 __ bind(notClass); | |
352 __ cmpl(rdx, JVM_CONSTANT_Float); | |
353 __ jccb(Assembler::notEqual, notFloat); | |
354 // ftos | |
304 | 355 __ fld_s( Address(rcx, rbx, Address::times_ptr, base_offset)); |
0 | 356 __ push(ftos); |
357 __ jmp(Done); | |
358 | |
359 __ bind(notFloat); | |
360 #ifdef ASSERT | |
361 { Label L; | |
362 __ cmpl(rdx, JVM_CONSTANT_Integer); | |
363 __ jcc(Assembler::equal, L); | |
364 __ cmpl(rdx, JVM_CONSTANT_String); | |
365 __ jcc(Assembler::equal, L); | |
366 __ stop("unexpected tag type in ldc"); | |
367 __ bind(L); | |
368 } | |
369 #endif | |
370 Label isOop; | |
371 // atos and itos | |
372 // String is only oop type we will see here | |
373 __ cmpl(rdx, JVM_CONSTANT_String); | |
374 __ jccb(Assembler::equal, isOop); | |
304 | 375 __ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset)); |
0 | 376 __ push(itos); |
377 __ jmp(Done); | |
378 __ bind(isOop); | |
304 | 379 __ movptr(rax, Address(rcx, rbx, Address::times_ptr, base_offset)); |
0 | 380 __ push(atos); |
381 | |
382 if (VerifyOops) { | |
383 __ verify_oop(rax); | |
384 } | |
385 __ bind(Done); | |
386 } | |
387 | |
1602 | 388 // Fast path for caching oop constants. |
389 // %%% We should use this to handle Class and String constants also. | |
390 // %%% It will simplify the ldc/primitive path considerably. | |
391 void TemplateTable::fast_aldc(bool wide) { | |
392 transition(vtos, atos); | |
393 | |
394 if (!EnableMethodHandles) { | |
395 // We should not encounter this bytecode if !EnableMethodHandles. | |
396 // The verifier will stop it. However, if we get past the verifier, | |
397 // this will stop the thread in a reasonable way, without crashing the JVM. | |
398 __ call_VM(noreg, CAST_FROM_FN_PTR(address, | |
399 InterpreterRuntime::throw_IncompatibleClassChangeError)); | |
400 // the call_VM checks for exception, so we should never return here. | |
401 __ should_not_reach_here(); | |
402 return; | |
403 } | |
404 | |
405 const Register cache = rcx; | |
406 const Register index = rdx; | |
407 | |
408 resolve_cache_and_index(f1_oop, rax, cache, index, wide ? sizeof(u2) : sizeof(u1)); | |
409 if (VerifyOops) { | |
410 __ verify_oop(rax); | |
411 } | |
1913
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
412 |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
413 Label L_done, L_throw_exception; |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
414 const Register con_klass_temp = rcx; // same as Rcache |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
415 __ movptr(con_klass_temp, Address(rax, oopDesc::klass_offset_in_bytes())); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
416 __ cmpptr(con_klass_temp, ExternalAddress((address)Universe::systemObjArrayKlassObj_addr())); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
417 __ jcc(Assembler::notEqual, L_done); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
418 __ cmpl(Address(rax, arrayOopDesc::length_offset_in_bytes()), 0); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
419 __ jcc(Assembler::notEqual, L_throw_exception); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
420 __ xorptr(rax, rax); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
421 __ jmp(L_done); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
422 |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
423 // Load the exception from the system-array which wraps it: |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
424 __ bind(L_throw_exception); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
425 __ movptr(rax, Address(rax, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
426 __ jump(ExternalAddress(Interpreter::throw_exception_entry())); |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
427 |
3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
jrose
parents:
1846
diff
changeset
|
428 __ bind(L_done); |
1602 | 429 } |
430 | |
0 | 431 void TemplateTable::ldc2_w() { |
432 transition(vtos, vtos); | |
433 Label Long, Done; | |
434 __ get_unsigned_2_byte_index_at_bcp(rbx, 1); | |
435 | |
436 __ get_cpool_and_tags(rcx, rax); | |
437 const int base_offset = constantPoolOopDesc::header_size() * wordSize; | |
438 const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; | |
439 | |
440 // get type | |
441 __ cmpb(Address(rax, rbx, Address::times_1, tags_offset), JVM_CONSTANT_Double); | |
442 __ jccb(Assembler::notEqual, Long); | |
443 // dtos | |
304 | 444 __ fld_d( Address(rcx, rbx, Address::times_ptr, base_offset)); |
0 | 445 __ push(dtos); |
446 __ jmpb(Done); | |
447 | |
448 __ bind(Long); | |
449 // ltos | |
304 | 450 __ movptr(rax, Address(rcx, rbx, Address::times_ptr, base_offset + 0 * wordSize)); |
451 NOT_LP64(__ movptr(rdx, Address(rcx, rbx, Address::times_ptr, base_offset + 1 * wordSize))); | |
0 | 452 |
453 __ push(ltos); | |
454 | |
455 __ bind(Done); | |
456 } | |
457 | |
458 | |
459 void TemplateTable::locals_index(Register reg, int offset) { | |
460 __ load_unsigned_byte(reg, at_bcp(offset)); | |
304 | 461 __ negptr(reg); |
0 | 462 } |
463 | |
464 | |
465 void TemplateTable::iload() { | |
466 transition(vtos, itos); | |
467 if (RewriteFrequentPairs) { | |
468 Label rewrite, done; | |
469 | |
470 // get next byte | |
471 __ load_unsigned_byte(rbx, at_bcp(Bytecodes::length_for(Bytecodes::_iload))); | |
472 // if _iload, wait to rewrite to iload2. We only want to rewrite the | |
473 // last two iloads in a pair. Comparing against fast_iload means that | |
474 // the next bytecode is neither an iload or a caload, and therefore | |
475 // an iload pair. | |
476 __ cmpl(rbx, Bytecodes::_iload); | |
477 __ jcc(Assembler::equal, done); | |
478 | |
479 __ cmpl(rbx, Bytecodes::_fast_iload); | |
480 __ movl(rcx, Bytecodes::_fast_iload2); | |
481 __ jccb(Assembler::equal, rewrite); | |
482 | |
483 // if _caload, rewrite to fast_icaload | |
484 __ cmpl(rbx, Bytecodes::_caload); | |
485 __ movl(rcx, Bytecodes::_fast_icaload); | |
486 __ jccb(Assembler::equal, rewrite); | |
487 | |
488 // rewrite so iload doesn't check again. | |
489 __ movl(rcx, Bytecodes::_fast_iload); | |
490 | |
491 // rewrite | |
492 // rcx: fast bytecode | |
493 __ bind(rewrite); | |
494 patch_bytecode(Bytecodes::_iload, rcx, rbx, false); | |
495 __ bind(done); | |
496 } | |
497 | |
498 // Get the local value into tos | |
499 locals_index(rbx); | |
500 __ movl(rax, iaddress(rbx)); | |
501 } | |
502 | |
503 | |
504 void TemplateTable::fast_iload2() { | |
505 transition(vtos, itos); | |
506 locals_index(rbx); | |
507 __ movl(rax, iaddress(rbx)); | |
508 __ push(itos); | |
509 locals_index(rbx, 3); | |
510 __ movl(rax, iaddress(rbx)); | |
511 } | |
512 | |
513 void TemplateTable::fast_iload() { | |
514 transition(vtos, itos); | |
515 locals_index(rbx); | |
516 __ movl(rax, iaddress(rbx)); | |
517 } | |
518 | |
519 | |
520 void TemplateTable::lload() { | |
521 transition(vtos, ltos); | |
522 locals_index(rbx); | |
304 | 523 __ movptr(rax, laddress(rbx)); |
524 NOT_LP64(__ movl(rdx, haddress(rbx))); | |
0 | 525 } |
526 | |
527 | |
528 void TemplateTable::fload() { | |
529 transition(vtos, ftos); | |
530 locals_index(rbx); | |
531 __ fld_s(faddress(rbx)); | |
532 } | |
533 | |
534 | |
535 void TemplateTable::dload() { | |
536 transition(vtos, dtos); | |
537 locals_index(rbx); | |
1506 | 538 __ fld_d(daddress(rbx)); |
0 | 539 } |
540 | |
541 | |
542 void TemplateTable::aload() { | |
543 transition(vtos, atos); | |
544 locals_index(rbx); | |
304 | 545 __ movptr(rax, aaddress(rbx)); |
0 | 546 } |
547 | |
548 | |
549 void TemplateTable::locals_index_wide(Register reg) { | |
550 __ movl(reg, at_bcp(2)); | |
304 | 551 __ bswapl(reg); |
0 | 552 __ shrl(reg, 16); |
304 | 553 __ negptr(reg); |
0 | 554 } |
555 | |
556 | |
557 void TemplateTable::wide_iload() { | |
558 transition(vtos, itos); | |
559 locals_index_wide(rbx); | |
560 __ movl(rax, iaddress(rbx)); | |
561 } | |
562 | |
563 | |
564 void TemplateTable::wide_lload() { | |
565 transition(vtos, ltos); | |
566 locals_index_wide(rbx); | |
304 | 567 __ movptr(rax, laddress(rbx)); |
568 NOT_LP64(__ movl(rdx, haddress(rbx))); | |
0 | 569 } |
570 | |
571 | |
572 void TemplateTable::wide_fload() { | |
573 transition(vtos, ftos); | |
574 locals_index_wide(rbx); | |
575 __ fld_s(faddress(rbx)); | |
576 } | |
577 | |
578 | |
579 void TemplateTable::wide_dload() { | |
580 transition(vtos, dtos); | |
581 locals_index_wide(rbx); | |
1506 | 582 __ fld_d(daddress(rbx)); |
0 | 583 } |
584 | |
585 | |
586 void TemplateTable::wide_aload() { | |
587 transition(vtos, atos); | |
588 locals_index_wide(rbx); | |
304 | 589 __ movptr(rax, aaddress(rbx)); |
0 | 590 } |
591 | |
592 void TemplateTable::index_check(Register array, Register index) { | |
593 // Pop ptr into array | |
594 __ pop_ptr(array); | |
595 index_check_without_pop(array, index); | |
596 } | |
597 | |
598 void TemplateTable::index_check_without_pop(Register array, Register index) { | |
599 // destroys rbx, | |
600 // check array | |
601 __ null_check(array, arrayOopDesc::length_offset_in_bytes()); | |
304 | 602 LP64_ONLY(__ movslq(index, index)); |
0 | 603 // check index |
604 __ cmpl(index, Address(array, arrayOopDesc::length_offset_in_bytes())); | |
605 if (index != rbx) { | |
606 // ??? convention: move aberrant index into rbx, for exception message | |
607 assert(rbx != array, "different registers"); | |
304 | 608 __ mov(rbx, index); |
0 | 609 } |
610 __ jump_cc(Assembler::aboveEqual, | |
611 ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry)); | |
612 } | |
613 | |
614 | |
615 void TemplateTable::iaload() { | |
616 transition(itos, itos); | |
617 // rdx: array | |
618 index_check(rdx, rax); // kills rbx, | |
619 // rax,: index | |
620 __ movl(rax, Address(rdx, rax, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_INT))); | |
621 } | |
622 | |
623 | |
624 void TemplateTable::laload() { | |
625 transition(itos, ltos); | |
626 // rax,: index | |
627 // rdx: array | |
628 index_check(rdx, rax); | |
304 | 629 __ mov(rbx, rax); |
0 | 630 // rbx,: index |
304 | 631 __ movptr(rax, Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG) + 0 * wordSize)); |
632 NOT_LP64(__ movl(rdx, Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG) + 1 * wordSize))); | |
0 | 633 } |
634 | |
635 | |
636 void TemplateTable::faload() { | |
637 transition(itos, ftos); | |
638 // rdx: array | |
639 index_check(rdx, rax); // kills rbx, | |
640 // rax,: index | |
641 __ fld_s(Address(rdx, rax, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT))); | |
642 } | |
643 | |
644 | |
645 void TemplateTable::daload() { | |
646 transition(itos, dtos); | |
647 // rdx: array | |
648 index_check(rdx, rax); // kills rbx, | |
649 // rax,: index | |
650 __ fld_d(Address(rdx, rax, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE))); | |
651 } | |
652 | |
653 | |
654 void TemplateTable::aaload() { | |
655 transition(itos, atos); | |
656 // rdx: array | |
657 index_check(rdx, rax); // kills rbx, | |
658 // rax,: index | |
304 | 659 __ movptr(rax, Address(rdx, rax, Address::times_ptr, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
0 | 660 } |
661 | |
662 | |
663 void TemplateTable::baload() { | |
664 transition(itos, itos); | |
665 // rdx: array | |
666 index_check(rdx, rax); // kills rbx, | |
667 // rax,: index | |
668 // can do better code for P5 - fix this at some point | |
669 __ load_signed_byte(rbx, Address(rdx, rax, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE))); | |
304 | 670 __ mov(rax, rbx); |
0 | 671 } |
672 | |
673 | |
674 void TemplateTable::caload() { | |
675 transition(itos, itos); | |
676 // rdx: array | |
677 index_check(rdx, rax); // kills rbx, | |
678 // rax,: index | |
679 // can do better code for P5 - may want to improve this at some point | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
680 __ load_unsigned_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); |
304 | 681 __ mov(rax, rbx); |
0 | 682 } |
683 | |
684 // iload followed by caload frequent pair | |
685 void TemplateTable::fast_icaload() { | |
686 transition(vtos, itos); | |
687 // load index out of locals | |
688 locals_index(rbx); | |
689 __ movl(rax, iaddress(rbx)); | |
690 | |
691 // rdx: array | |
692 index_check(rdx, rax); | |
693 // rax,: index | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
694 __ load_unsigned_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR))); |
304 | 695 __ mov(rax, rbx); |
0 | 696 } |
697 | |
698 void TemplateTable::saload() { | |
699 transition(itos, itos); | |
700 // rdx: array | |
701 index_check(rdx, rax); // kills rbx, | |
702 // rax,: index | |
703 // can do better code for P5 - may want to improve this at some point | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
704 __ load_signed_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT))); |
304 | 705 __ mov(rax, rbx); |
0 | 706 } |
707 | |
708 | |
709 void TemplateTable::iload(int n) { | |
710 transition(vtos, itos); | |
711 __ movl(rax, iaddress(n)); | |
712 } | |
713 | |
714 | |
715 void TemplateTable::lload(int n) { | |
716 transition(vtos, ltos); | |
304 | 717 __ movptr(rax, laddress(n)); |
718 NOT_LP64(__ movptr(rdx, haddress(n))); | |
0 | 719 } |
720 | |
721 | |
722 void TemplateTable::fload(int n) { | |
723 transition(vtos, ftos); | |
724 __ fld_s(faddress(n)); | |
725 } | |
726 | |
727 | |
728 void TemplateTable::dload(int n) { | |
729 transition(vtos, dtos); | |
1506 | 730 __ fld_d(daddress(n)); |
0 | 731 } |
732 | |
733 | |
734 void TemplateTable::aload(int n) { | |
735 transition(vtos, atos); | |
304 | 736 __ movptr(rax, aaddress(n)); |
0 | 737 } |
738 | |
739 | |
740 void TemplateTable::aload_0() { | |
741 transition(vtos, atos); | |
742 // According to bytecode histograms, the pairs: | |
743 // | |
744 // _aload_0, _fast_igetfield | |
745 // _aload_0, _fast_agetfield | |
746 // _aload_0, _fast_fgetfield | |
747 // | |
748 // occur frequently. If RewriteFrequentPairs is set, the (slow) _aload_0 | |
749 // bytecode checks if the next bytecode is either _fast_igetfield, | |
750 // _fast_agetfield or _fast_fgetfield and then rewrites the | |
751 // current bytecode into a pair bytecode; otherwise it rewrites the current | |
752 // bytecode into _fast_aload_0 that doesn't do the pair check anymore. | |
753 // | |
754 // Note: If the next bytecode is _getfield, the rewrite must be delayed, | |
755 // otherwise we may miss an opportunity for a pair. | |
756 // | |
757 // Also rewrite frequent pairs | |
758 // aload_0, aload_1 | |
759 // aload_0, iload_1 | |
760 // These bytecodes with a small amount of code are most profitable to rewrite | |
761 if (RewriteFrequentPairs) { | |
762 Label rewrite, done; | |
763 // get next byte | |
764 __ load_unsigned_byte(rbx, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0))); | |
765 | |
766 // do actual aload_0 | |
767 aload(0); | |
768 | |
769 // if _getfield then wait with rewrite | |
770 __ cmpl(rbx, Bytecodes::_getfield); | |
771 __ jcc(Assembler::equal, done); | |
772 | |
773 // if _igetfield then reqrite to _fast_iaccess_0 | |
774 assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); | |
775 __ cmpl(rbx, Bytecodes::_fast_igetfield); | |
776 __ movl(rcx, Bytecodes::_fast_iaccess_0); | |
777 __ jccb(Assembler::equal, rewrite); | |
778 | |
779 // if _agetfield then reqrite to _fast_aaccess_0 | |
780 assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); | |
781 __ cmpl(rbx, Bytecodes::_fast_agetfield); | |
782 __ movl(rcx, Bytecodes::_fast_aaccess_0); | |
783 __ jccb(Assembler::equal, rewrite); | |
784 | |
785 // if _fgetfield then reqrite to _fast_faccess_0 | |
786 assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); | |
787 __ cmpl(rbx, Bytecodes::_fast_fgetfield); | |
788 __ movl(rcx, Bytecodes::_fast_faccess_0); | |
789 __ jccb(Assembler::equal, rewrite); | |
790 | |
791 // else rewrite to _fast_aload0 | |
792 assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "fix bytecode definition"); | |
793 __ movl(rcx, Bytecodes::_fast_aload_0); | |
794 | |
795 // rewrite | |
796 // rcx: fast bytecode | |
797 __ bind(rewrite); | |
798 patch_bytecode(Bytecodes::_aload_0, rcx, rbx, false); | |
799 | |
800 __ bind(done); | |
801 } else { | |
802 aload(0); | |
803 } | |
804 } | |
805 | |
806 void TemplateTable::istore() { | |
807 transition(itos, vtos); | |
808 locals_index(rbx); | |
809 __ movl(iaddress(rbx), rax); | |
810 } | |
811 | |
812 | |
813 void TemplateTable::lstore() { | |
814 transition(ltos, vtos); | |
815 locals_index(rbx); | |
304 | 816 __ movptr(laddress(rbx), rax); |
817 NOT_LP64(__ movptr(haddress(rbx), rdx)); | |
0 | 818 } |
819 | |
820 | |
821 void TemplateTable::fstore() { | |
822 transition(ftos, vtos); | |
823 locals_index(rbx); | |
824 __ fstp_s(faddress(rbx)); | |
825 } | |
826 | |
827 | |
828 void TemplateTable::dstore() { | |
829 transition(dtos, vtos); | |
830 locals_index(rbx); | |
1506 | 831 __ fstp_d(daddress(rbx)); |
0 | 832 } |
833 | |
834 | |
835 void TemplateTable::astore() { | |
836 transition(vtos, vtos); | |
1506 | 837 __ pop_ptr(rax); |
0 | 838 locals_index(rbx); |
304 | 839 __ movptr(aaddress(rbx), rax); |
0 | 840 } |
841 | |
842 | |
843 void TemplateTable::wide_istore() { | |
844 transition(vtos, vtos); | |
845 __ pop_i(rax); | |
846 locals_index_wide(rbx); | |
847 __ movl(iaddress(rbx), rax); | |
848 } | |
849 | |
850 | |
851 void TemplateTable::wide_lstore() { | |
852 transition(vtos, vtos); | |
853 __ pop_l(rax, rdx); | |
854 locals_index_wide(rbx); | |
304 | 855 __ movptr(laddress(rbx), rax); |
856 NOT_LP64(__ movl(haddress(rbx), rdx)); | |
0 | 857 } |
858 | |
859 | |
860 void TemplateTable::wide_fstore() { | |
861 wide_istore(); | |
862 } | |
863 | |
864 | |
865 void TemplateTable::wide_dstore() { | |
866 wide_lstore(); | |
867 } | |
868 | |
869 | |
870 void TemplateTable::wide_astore() { | |
871 transition(vtos, vtos); | |
1506 | 872 __ pop_ptr(rax); |
0 | 873 locals_index_wide(rbx); |
304 | 874 __ movptr(aaddress(rbx), rax); |
0 | 875 } |
876 | |
877 | |
878 void TemplateTable::iastore() { | |
879 transition(itos, vtos); | |
880 __ pop_i(rbx); | |
881 // rax,: value | |
882 // rdx: array | |
883 index_check(rdx, rbx); // prefer index in rbx, | |
884 // rbx,: index | |
885 __ movl(Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_INT)), rax); | |
886 } | |
887 | |
888 | |
889 void TemplateTable::lastore() { | |
890 transition(ltos, vtos); | |
891 __ pop_i(rbx); | |
892 // rax,: low(value) | |
893 // rcx: array | |
894 // rdx: high(value) | |
895 index_check(rcx, rbx); // prefer index in rbx, | |
896 // rbx,: index | |
304 | 897 __ movptr(Address(rcx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG) + 0 * wordSize), rax); |
898 NOT_LP64(__ movl(Address(rcx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG) + 1 * wordSize), rdx)); | |
0 | 899 } |
900 | |
901 | |
902 void TemplateTable::fastore() { | |
903 transition(ftos, vtos); | |
904 __ pop_i(rbx); | |
905 // rdx: array | |
906 // st0: value | |
907 index_check(rdx, rbx); // prefer index in rbx, | |
908 // rbx,: index | |
909 __ fstp_s(Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT))); | |
910 } | |
911 | |
912 | |
913 void TemplateTable::dastore() { | |
914 transition(dtos, vtos); | |
915 __ pop_i(rbx); | |
916 // rdx: array | |
917 // st0: value | |
918 index_check(rdx, rbx); // prefer index in rbx, | |
919 // rbx,: index | |
920 __ fstp_d(Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE))); | |
921 } | |
922 | |
923 | |
924 void TemplateTable::aastore() { | |
925 Label is_null, ok_is_subtype, done; | |
926 transition(vtos, vtos); | |
927 // stack: ..., array, index, value | |
304 | 928 __ movptr(rax, at_tos()); // Value |
0 | 929 __ movl(rcx, at_tos_p1()); // Index |
304 | 930 __ movptr(rdx, at_tos_p2()); // Array |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
931 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
932 Address element_address(rdx, rcx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); |
0 | 933 index_check_without_pop(rdx, rcx); // kills rbx, |
934 // do array store check - check for NULL value first | |
304 | 935 __ testptr(rax, rax); |
0 | 936 __ jcc(Assembler::zero, is_null); |
937 | |
938 // Move subklass into EBX | |
304 | 939 __ movptr(rbx, Address(rax, oopDesc::klass_offset_in_bytes())); |
0 | 940 // Move superklass into EAX |
304 | 941 __ movptr(rax, Address(rdx, oopDesc::klass_offset_in_bytes())); |
942 __ movptr(rax, Address(rax, sizeof(oopDesc) + objArrayKlass::element_klass_offset_in_bytes())); | |
943 // Compress array+index*wordSize+12 into a single register. Frees ECX. | |
362 | 944 __ lea(rdx, element_address); |
0 | 945 |
946 // Generate subtype check. Blows ECX. Resets EDI to locals. | |
947 // Superklass in EAX. Subklass in EBX. | |
948 __ gen_subtype_check( rbx, ok_is_subtype ); | |
949 | |
950 // Come here on failure | |
951 // object is at TOS | |
952 __ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry)); | |
953 | |
954 // Come here on success | |
955 __ bind(ok_is_subtype); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
956 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
957 // Get the value to store |
362 | 958 __ movptr(rax, at_rsp()); |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
959 // and store it with appropriate barrier |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
960 do_oop_store(_masm, Address(rdx, 0), rax, _bs->kind(), true); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
961 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
962 __ jmp(done); |
0 | 963 |
964 // Have a NULL in EAX, EDX=array, ECX=index. Store NULL at ary[idx] | |
965 __ bind(is_null); | |
966 __ profile_null_seen(rbx); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
967 |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
968 // Store NULL, (noreg means NULL to do_oop_store) |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
969 do_oop_store(_masm, element_address, noreg, _bs->kind(), true); |
0 | 970 |
971 // Pop stack arguments | |
972 __ bind(done); | |
1506 | 973 __ addptr(rsp, 3 * Interpreter::stackElementSize); |
0 | 974 } |
975 | |
976 | |
977 void TemplateTable::bastore() { | |
978 transition(itos, vtos); | |
979 __ pop_i(rbx); | |
980 // rax,: value | |
981 // rdx: array | |
982 index_check(rdx, rbx); // prefer index in rbx, | |
983 // rbx,: index | |
984 __ movb(Address(rdx, rbx, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), rax); | |
985 } | |
986 | |
987 | |
988 void TemplateTable::castore() { | |
989 transition(itos, vtos); | |
990 __ pop_i(rbx); | |
991 // rax,: value | |
992 // rdx: array | |
993 index_check(rdx, rbx); // prefer index in rbx, | |
994 // rbx,: index | |
995 __ movw(Address(rdx, rbx, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), rax); | |
996 } | |
997 | |
998 | |
999 void TemplateTable::sastore() { | |
1000 castore(); | |
1001 } | |
1002 | |
1003 | |
1004 void TemplateTable::istore(int n) { | |
1005 transition(itos, vtos); | |
1006 __ movl(iaddress(n), rax); | |
1007 } | |
1008 | |
1009 | |
1010 void TemplateTable::lstore(int n) { | |
1011 transition(ltos, vtos); | |
304 | 1012 __ movptr(laddress(n), rax); |
1013 NOT_LP64(__ movptr(haddress(n), rdx)); | |
0 | 1014 } |
1015 | |
1016 | |
1017 void TemplateTable::fstore(int n) { | |
1018 transition(ftos, vtos); | |
1019 __ fstp_s(faddress(n)); | |
1020 } | |
1021 | |
1022 | |
1023 void TemplateTable::dstore(int n) { | |
1024 transition(dtos, vtos); | |
1506 | 1025 __ fstp_d(daddress(n)); |
0 | 1026 } |
1027 | |
1028 | |
1029 void TemplateTable::astore(int n) { | |
1030 transition(vtos, vtos); | |
1506 | 1031 __ pop_ptr(rax); |
304 | 1032 __ movptr(aaddress(n), rax); |
0 | 1033 } |
1034 | |
1035 | |
1036 void TemplateTable::pop() { | |
1037 transition(vtos, vtos); | |
1506 | 1038 __ addptr(rsp, Interpreter::stackElementSize); |
0 | 1039 } |
1040 | |
1041 | |
1042 void TemplateTable::pop2() { | |
1043 transition(vtos, vtos); | |
1506 | 1044 __ addptr(rsp, 2*Interpreter::stackElementSize); |
0 | 1045 } |
1046 | |
1047 | |
1048 void TemplateTable::dup() { | |
1049 transition(vtos, vtos); | |
1050 // stack: ..., a | |
1506 | 1051 __ load_ptr(0, rax); |
1052 __ push_ptr(rax); | |
0 | 1053 // stack: ..., a, a |
1054 } | |
1055 | |
1056 | |
1057 void TemplateTable::dup_x1() { | |
1058 transition(vtos, vtos); | |
1059 // stack: ..., a, b | |
1506 | 1060 __ load_ptr( 0, rax); // load b |
1061 __ load_ptr( 1, rcx); // load a | |
1062 __ store_ptr(1, rax); // store b | |
1063 __ store_ptr(0, rcx); // store a | |
1064 __ push_ptr(rax); // push b | |
0 | 1065 // stack: ..., b, a, b |
1066 } | |
1067 | |
1068 | |
1069 void TemplateTable::dup_x2() { | |
1070 transition(vtos, vtos); | |
1071 // stack: ..., a, b, c | |
1506 | 1072 __ load_ptr( 0, rax); // load c |
1073 __ load_ptr( 2, rcx); // load a | |
1074 __ store_ptr(2, rax); // store c in a | |
1075 __ push_ptr(rax); // push c | |
0 | 1076 // stack: ..., c, b, c, c |
1506 | 1077 __ load_ptr( 2, rax); // load b |
1078 __ store_ptr(2, rcx); // store a in b | |
0 | 1079 // stack: ..., c, a, c, c |
1506 | 1080 __ store_ptr(1, rax); // store b in c |
0 | 1081 // stack: ..., c, a, b, c |
1082 } | |
1083 | |
1084 | |
1085 void TemplateTable::dup2() { | |
1086 transition(vtos, vtos); | |
1087 // stack: ..., a, b | |
1506 | 1088 __ load_ptr(1, rax); // load a |
1089 __ push_ptr(rax); // push a | |
1090 __ load_ptr(1, rax); // load b | |
1091 __ push_ptr(rax); // push b | |
0 | 1092 // stack: ..., a, b, a, b |
1093 } | |
1094 | |
1095 | |
1096 void TemplateTable::dup2_x1() { | |
1097 transition(vtos, vtos); | |
1098 // stack: ..., a, b, c | |
1506 | 1099 __ load_ptr( 0, rcx); // load c |
1100 __ load_ptr( 1, rax); // load b | |
1101 __ push_ptr(rax); // push b | |
1102 __ push_ptr(rcx); // push c | |
0 | 1103 // stack: ..., a, b, c, b, c |
1506 | 1104 __ store_ptr(3, rcx); // store c in b |
0 | 1105 // stack: ..., a, c, c, b, c |
1506 | 1106 __ load_ptr( 4, rcx); // load a |
1107 __ store_ptr(2, rcx); // store a in 2nd c | |
0 | 1108 // stack: ..., a, c, a, b, c |
1506 | 1109 __ store_ptr(4, rax); // store b in a |
0 | 1110 // stack: ..., b, c, a, b, c |
1111 // stack: ..., b, c, a, b, c | |
1112 } | |
1113 | |
1114 | |
1115 void TemplateTable::dup2_x2() { | |
1116 transition(vtos, vtos); | |
1117 // stack: ..., a, b, c, d | |
1506 | 1118 __ load_ptr( 0, rcx); // load d |
1119 __ load_ptr( 1, rax); // load c | |
1120 __ push_ptr(rax); // push c | |
1121 __ push_ptr(rcx); // push d | |
0 | 1122 // stack: ..., a, b, c, d, c, d |
1506 | 1123 __ load_ptr( 4, rax); // load b |
1124 __ store_ptr(2, rax); // store b in d | |
1125 __ store_ptr(4, rcx); // store d in b | |
0 | 1126 // stack: ..., a, d, c, b, c, d |
1506 | 1127 __ load_ptr( 5, rcx); // load a |
1128 __ load_ptr( 3, rax); // load c | |
1129 __ store_ptr(3, rcx); // store a in c | |
1130 __ store_ptr(5, rax); // store c in a | |
0 | 1131 // stack: ..., c, d, a, b, c, d |
1132 // stack: ..., c, d, a, b, c, d | |
1133 } | |
1134 | |
1135 | |
1136 void TemplateTable::swap() { | |
1137 transition(vtos, vtos); | |
1138 // stack: ..., a, b | |
1506 | 1139 __ load_ptr( 1, rcx); // load a |
1140 __ load_ptr( 0, rax); // load b | |
1141 __ store_ptr(0, rcx); // store a in b | |
1142 __ store_ptr(1, rax); // store b in a | |
0 | 1143 // stack: ..., b, a |
1144 } | |
1145 | |
1146 | |
1147 void TemplateTable::iop2(Operation op) { | |
1148 transition(itos, itos); | |
1149 switch (op) { | |
1506 | 1150 case add : __ pop_i(rdx); __ addl (rax, rdx); break; |
304 | 1151 case sub : __ mov(rdx, rax); __ pop_i(rax); __ subl (rax, rdx); break; |
1506 | 1152 case mul : __ pop_i(rdx); __ imull(rax, rdx); break; |
1153 case _and : __ pop_i(rdx); __ andl (rax, rdx); break; | |
1154 case _or : __ pop_i(rdx); __ orl (rax, rdx); break; | |
1155 case _xor : __ pop_i(rdx); __ xorl (rax, rdx); break; | |
304 | 1156 case shl : __ mov(rcx, rax); __ pop_i(rax); __ shll (rax); break; // implicit masking of lower 5 bits by Intel shift instr. |
1157 case shr : __ mov(rcx, rax); __ pop_i(rax); __ sarl (rax); break; // implicit masking of lower 5 bits by Intel shift instr. | |
1158 case ushr : __ mov(rcx, rax); __ pop_i(rax); __ shrl (rax); break; // implicit masking of lower 5 bits by Intel shift instr. | |
0 | 1159 default : ShouldNotReachHere(); |
1160 } | |
1161 } | |
1162 | |
1163 | |
1164 void TemplateTable::lop2(Operation op) { | |
1165 transition(ltos, ltos); | |
1166 __ pop_l(rbx, rcx); | |
1167 switch (op) { | |
1506 | 1168 case add : __ addl(rax, rbx); __ adcl(rdx, rcx); break; |
1169 case sub : __ subl(rbx, rax); __ sbbl(rcx, rdx); | |
1170 __ mov (rax, rbx); __ mov (rdx, rcx); break; | |
1171 case _and : __ andl(rax, rbx); __ andl(rdx, rcx); break; | |
1172 case _or : __ orl (rax, rbx); __ orl (rdx, rcx); break; | |
1173 case _xor : __ xorl(rax, rbx); __ xorl(rdx, rcx); break; | |
1174 default : ShouldNotReachHere(); | |
0 | 1175 } |
1176 } | |
1177 | |
1178 | |
1179 void TemplateTable::idiv() { | |
1180 transition(itos, itos); | |
304 | 1181 __ mov(rcx, rax); |
0 | 1182 __ pop_i(rax); |
1183 // Note: could xor rax, and rcx and compare with (-1 ^ min_int). If | |
1184 // they are not equal, one could do a normal division (no correction | |
1185 // needed), which may speed up this implementation for the common case. | |
1186 // (see also JVM spec., p.243 & p.271) | |
1187 __ corrected_idivl(rcx); | |
1188 } | |
1189 | |
1190 | |
1191 void TemplateTable::irem() { | |
1192 transition(itos, itos); | |
304 | 1193 __ mov(rcx, rax); |
0 | 1194 __ pop_i(rax); |
1195 // Note: could xor rax, and rcx and compare with (-1 ^ min_int). If | |
1196 // they are not equal, one could do a normal division (no correction | |
1197 // needed), which may speed up this implementation for the common case. | |
1198 // (see also JVM spec., p.243 & p.271) | |
1199 __ corrected_idivl(rcx); | |
304 | 1200 __ mov(rax, rdx); |
0 | 1201 } |
1202 | |
1203 | |
1204 void TemplateTable::lmul() { | |
1205 transition(ltos, ltos); | |
1206 __ pop_l(rbx, rcx); | |
304 | 1207 __ push(rcx); __ push(rbx); |
1208 __ push(rdx); __ push(rax); | |
0 | 1209 __ lmul(2 * wordSize, 0); |
304 | 1210 __ addptr(rsp, 4 * wordSize); // take off temporaries |
0 | 1211 } |
1212 | |
1213 | |
1214 void TemplateTable::ldiv() { | |
1215 transition(ltos, ltos); | |
1216 __ pop_l(rbx, rcx); | |
304 | 1217 __ push(rcx); __ push(rbx); |
1218 __ push(rdx); __ push(rax); | |
0 | 1219 // check if y = 0 |
1220 __ orl(rax, rdx); | |
1221 __ jump_cc(Assembler::zero, | |
1222 ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); | |
1223 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv)); | |
304 | 1224 __ addptr(rsp, 4 * wordSize); // take off temporaries |
0 | 1225 } |
1226 | |
1227 | |
1228 void TemplateTable::lrem() { | |
1229 transition(ltos, ltos); | |
1230 __ pop_l(rbx, rcx); | |
304 | 1231 __ push(rcx); __ push(rbx); |
1232 __ push(rdx); __ push(rax); | |
0 | 1233 // check if y = 0 |
1234 __ orl(rax, rdx); | |
1235 __ jump_cc(Assembler::zero, | |
1236 ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); | |
1237 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem)); | |
304 | 1238 __ addptr(rsp, 4 * wordSize); |
0 | 1239 } |
1240 | |
1241 | |
1242 void TemplateTable::lshl() { | |
1243 transition(itos, ltos); | |
1244 __ movl(rcx, rax); // get shift count | |
1245 __ pop_l(rax, rdx); // get shift value | |
1246 __ lshl(rdx, rax); | |
1247 } | |
1248 | |
1249 | |
1250 void TemplateTable::lshr() { | |
1251 transition(itos, ltos); | |
304 | 1252 __ mov(rcx, rax); // get shift count |
0 | 1253 __ pop_l(rax, rdx); // get shift value |
1254 __ lshr(rdx, rax, true); | |
1255 } | |
1256 | |
1257 | |
1258 void TemplateTable::lushr() { | |
1259 transition(itos, ltos); | |
304 | 1260 __ mov(rcx, rax); // get shift count |
0 | 1261 __ pop_l(rax, rdx); // get shift value |
1262 __ lshr(rdx, rax); | |
1263 } | |
1264 | |
1265 | |
1266 void TemplateTable::fop2(Operation op) { | |
1267 transition(ftos, ftos); | |
1268 switch (op) { | |
1269 case add: __ fadd_s (at_rsp()); break; | |
1270 case sub: __ fsubr_s(at_rsp()); break; | |
1271 case mul: __ fmul_s (at_rsp()); break; | |
1272 case div: __ fdivr_s(at_rsp()); break; | |
1273 case rem: __ fld_s (at_rsp()); __ fremr(rax); break; | |
1274 default : ShouldNotReachHere(); | |
1275 } | |
1276 __ f2ieee(); | |
304 | 1277 __ pop(rax); // pop float thing off |
0 | 1278 } |
1279 | |
1280 | |
1281 void TemplateTable::dop2(Operation op) { | |
1282 transition(dtos, dtos); | |
1283 | |
1284 switch (op) { | |
1285 case add: __ fadd_d (at_rsp()); break; | |
1286 case sub: __ fsubr_d(at_rsp()); break; | |
1287 case mul: { | |
1288 Label L_strict; | |
1289 Label L_join; | |
1290 const Address access_flags (rcx, methodOopDesc::access_flags_offset()); | |
1291 __ get_method(rcx); | |
1292 __ movl(rcx, access_flags); | |
1293 __ testl(rcx, JVM_ACC_STRICT); | |
1294 __ jccb(Assembler::notZero, L_strict); | |
1295 __ fmul_d (at_rsp()); | |
1296 __ jmpb(L_join); | |
1297 __ bind(L_strict); | |
1298 __ fld_x(ExternalAddress(StubRoutines::addr_fpu_subnormal_bias1())); | |
1299 __ fmulp(); | |
1300 __ fmul_d (at_rsp()); | |
1301 __ fld_x(ExternalAddress(StubRoutines::addr_fpu_subnormal_bias2())); | |
1302 __ fmulp(); | |
1303 __ bind(L_join); | |
1304 break; | |
1305 } | |
1306 case div: { | |
1307 Label L_strict; | |
1308 Label L_join; | |
1309 const Address access_flags (rcx, methodOopDesc::access_flags_offset()); | |
1310 __ get_method(rcx); | |
1311 __ movl(rcx, access_flags); | |
1312 __ testl(rcx, JVM_ACC_STRICT); | |
1313 __ jccb(Assembler::notZero, L_strict); | |
1314 __ fdivr_d(at_rsp()); | |
1315 __ jmp(L_join); | |
1316 __ bind(L_strict); | |
1317 __ fld_x(ExternalAddress(StubRoutines::addr_fpu_subnormal_bias1())); | |
1318 __ fmul_d (at_rsp()); | |
1319 __ fdivrp(); | |
1320 __ fld_x(ExternalAddress(StubRoutines::addr_fpu_subnormal_bias2())); | |
1321 __ fmulp(); | |
1322 __ bind(L_join); | |
1323 break; | |
1324 } | |
1325 case rem: __ fld_d (at_rsp()); __ fremr(rax); break; | |
1326 default : ShouldNotReachHere(); | |
1327 } | |
1328 __ d2ieee(); | |
1329 // Pop double precision number from rsp. | |
304 | 1330 __ pop(rax); |
1331 __ pop(rdx); | |
0 | 1332 } |
1333 | |
1334 | |
1335 void TemplateTable::ineg() { | |
1336 transition(itos, itos); | |
1337 __ negl(rax); | |
1338 } | |
1339 | |
1340 | |
1341 void TemplateTable::lneg() { | |
1342 transition(ltos, ltos); | |
1343 __ lneg(rdx, rax); | |
1344 } | |
1345 | |
1346 | |
1347 void TemplateTable::fneg() { | |
1348 transition(ftos, ftos); | |
1349 __ fchs(); | |
1350 } | |
1351 | |
1352 | |
1353 void TemplateTable::dneg() { | |
1354 transition(dtos, dtos); | |
1355 __ fchs(); | |
1356 } | |
1357 | |
1358 | |
1359 void TemplateTable::iinc() { | |
1360 transition(vtos, vtos); | |
1361 __ load_signed_byte(rdx, at_bcp(2)); // get constant | |
1362 locals_index(rbx); | |
1363 __ addl(iaddress(rbx), rdx); | |
1364 } | |
1365 | |
1366 | |
1367 void TemplateTable::wide_iinc() { | |
1368 transition(vtos, vtos); | |
1369 __ movl(rdx, at_bcp(4)); // get constant | |
1370 locals_index_wide(rbx); | |
304 | 1371 __ bswapl(rdx); // swap bytes & sign-extend constant |
0 | 1372 __ sarl(rdx, 16); |
1373 __ addl(iaddress(rbx), rdx); | |
1374 // Note: should probably use only one movl to get both | |
1375 // the index and the constant -> fix this | |
1376 } | |
1377 | |
1378 | |
1379 void TemplateTable::convert() { | |
1380 // Checking | |
1381 #ifdef ASSERT | |
1382 { TosState tos_in = ilgl; | |
1383 TosState tos_out = ilgl; | |
1384 switch (bytecode()) { | |
1385 case Bytecodes::_i2l: // fall through | |
1386 case Bytecodes::_i2f: // fall through | |
1387 case Bytecodes::_i2d: // fall through | |
1388 case Bytecodes::_i2b: // fall through | |
1389 case Bytecodes::_i2c: // fall through | |
1390 case Bytecodes::_i2s: tos_in = itos; break; | |
1391 case Bytecodes::_l2i: // fall through | |
1392 case Bytecodes::_l2f: // fall through | |
1393 case Bytecodes::_l2d: tos_in = ltos; break; | |
1394 case Bytecodes::_f2i: // fall through | |
1395 case Bytecodes::_f2l: // fall through | |
1396 case Bytecodes::_f2d: tos_in = ftos; break; | |
1397 case Bytecodes::_d2i: // fall through | |
1398 case Bytecodes::_d2l: // fall through | |
1399 case Bytecodes::_d2f: tos_in = dtos; break; | |
1400 default : ShouldNotReachHere(); | |
1401 } | |
1402 switch (bytecode()) { | |
1403 case Bytecodes::_l2i: // fall through | |
1404 case Bytecodes::_f2i: // fall through | |
1405 case Bytecodes::_d2i: // fall through | |
1406 case Bytecodes::_i2b: // fall through | |
1407 case Bytecodes::_i2c: // fall through | |
1408 case Bytecodes::_i2s: tos_out = itos; break; | |
1409 case Bytecodes::_i2l: // fall through | |
1410 case Bytecodes::_f2l: // fall through | |
1411 case Bytecodes::_d2l: tos_out = ltos; break; | |
1412 case Bytecodes::_i2f: // fall through | |
1413 case Bytecodes::_l2f: // fall through | |
1414 case Bytecodes::_d2f: tos_out = ftos; break; | |
1415 case Bytecodes::_i2d: // fall through | |
1416 case Bytecodes::_l2d: // fall through | |
1417 case Bytecodes::_f2d: tos_out = dtos; break; | |
1418 default : ShouldNotReachHere(); | |
1419 } | |
1420 transition(tos_in, tos_out); | |
1421 } | |
1422 #endif // ASSERT | |
1423 | |
1424 // Conversion | |
304 | 1425 // (Note: use push(rcx)/pop(rcx) for 1/2-word stack-ptr manipulation) |
0 | 1426 switch (bytecode()) { |
1427 case Bytecodes::_i2l: | |
1428 __ extend_sign(rdx, rax); | |
1429 break; | |
1430 case Bytecodes::_i2f: | |
304 | 1431 __ push(rax); // store int on tos |
0 | 1432 __ fild_s(at_rsp()); // load int to ST0 |
1433 __ f2ieee(); // truncate to float size | |
304 | 1434 __ pop(rcx); // adjust rsp |
0 | 1435 break; |
1436 case Bytecodes::_i2d: | |
304 | 1437 __ push(rax); // add one slot for d2ieee() |
1438 __ push(rax); // store int on tos | |
0 | 1439 __ fild_s(at_rsp()); // load int to ST0 |
1440 __ d2ieee(); // truncate to double size | |
304 | 1441 __ pop(rcx); // adjust rsp |
1442 __ pop(rcx); | |
0 | 1443 break; |
1444 case Bytecodes::_i2b: | |
1445 __ shll(rax, 24); // truncate upper 24 bits | |
1446 __ sarl(rax, 24); // and sign-extend byte | |
304 | 1447 LP64_ONLY(__ movsbl(rax, rax)); |
0 | 1448 break; |
1449 case Bytecodes::_i2c: | |
1450 __ andl(rax, 0xFFFF); // truncate upper 16 bits | |
304 | 1451 LP64_ONLY(__ movzwl(rax, rax)); |
0 | 1452 break; |
1453 case Bytecodes::_i2s: | |
1454 __ shll(rax, 16); // truncate upper 16 bits | |
1455 __ sarl(rax, 16); // and sign-extend short | |
304 | 1456 LP64_ONLY(__ movswl(rax, rax)); |
0 | 1457 break; |
1458 case Bytecodes::_l2i: | |
1459 /* nothing to do */ | |
1460 break; | |
1461 case Bytecodes::_l2f: | |
304 | 1462 __ push(rdx); // store long on tos |
1463 __ push(rax); | |
0 | 1464 __ fild_d(at_rsp()); // load long to ST0 |
1465 __ f2ieee(); // truncate to float size | |
304 | 1466 __ pop(rcx); // adjust rsp |
1467 __ pop(rcx); | |
0 | 1468 break; |
1469 case Bytecodes::_l2d: | |
304 | 1470 __ push(rdx); // store long on tos |
1471 __ push(rax); | |
0 | 1472 __ fild_d(at_rsp()); // load long to ST0 |
1473 __ d2ieee(); // truncate to double size | |
304 | 1474 __ pop(rcx); // adjust rsp |
1475 __ pop(rcx); | |
0 | 1476 break; |
1477 case Bytecodes::_f2i: | |
304 | 1478 __ push(rcx); // reserve space for argument |
0 | 1479 __ fstp_s(at_rsp()); // pass float argument on stack |
1480 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2i), 1); | |
1481 break; | |
1482 case Bytecodes::_f2l: | |
304 | 1483 __ push(rcx); // reserve space for argument |
0 | 1484 __ fstp_s(at_rsp()); // pass float argument on stack |
1485 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2l), 1); | |
1486 break; | |
1487 case Bytecodes::_f2d: | |
1488 /* nothing to do */ | |
1489 break; | |
1490 case Bytecodes::_d2i: | |
304 | 1491 __ push(rcx); // reserve space for argument |
1492 __ push(rcx); | |
0 | 1493 __ fstp_d(at_rsp()); // pass double argument on stack |
1494 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2i), 2); | |
1495 break; | |
1496 case Bytecodes::_d2l: | |
304 | 1497 __ push(rcx); // reserve space for argument |
1498 __ push(rcx); | |
0 | 1499 __ fstp_d(at_rsp()); // pass double argument on stack |
1500 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2l), 2); | |
1501 break; | |
1502 case Bytecodes::_d2f: | |
304 | 1503 __ push(rcx); // reserve space for f2ieee() |
0 | 1504 __ f2ieee(); // truncate to float size |
304 | 1505 __ pop(rcx); // adjust rsp |
0 | 1506 break; |
1507 default : | |
1508 ShouldNotReachHere(); | |
1509 } | |
1510 } | |
1511 | |
1512 | |
1513 void TemplateTable::lcmp() { | |
1514 transition(ltos, itos); | |
1515 // y = rdx:rax | |
1516 __ pop_l(rbx, rcx); // get x = rcx:rbx | |
1517 __ lcmp2int(rcx, rbx, rdx, rax);// rcx := cmp(x, y) | |
304 | 1518 __ mov(rax, rcx); |
0 | 1519 } |
1520 | |
1521 | |
1522 void TemplateTable::float_cmp(bool is_float, int unordered_result) { | |
1523 if (is_float) { | |
1524 __ fld_s(at_rsp()); | |
1525 } else { | |
1526 __ fld_d(at_rsp()); | |
304 | 1527 __ pop(rdx); |
0 | 1528 } |
304 | 1529 __ pop(rcx); |
0 | 1530 __ fcmp2int(rax, unordered_result < 0); |
1531 } | |
1532 | |
1533 | |
1534 void TemplateTable::branch(bool is_jsr, bool is_wide) { | |
1535 __ get_method(rcx); // ECX holds method | |
1536 __ profile_taken_branch(rax,rbx); // EAX holds updated MDP, EBX holds bumped taken count | |
1537 | |
1538 const ByteSize be_offset = methodOopDesc::backedge_counter_offset() + InvocationCounter::counter_offset(); | |
1539 const ByteSize inv_offset = methodOopDesc::invocation_counter_offset() + InvocationCounter::counter_offset(); | |
1540 const int method_offset = frame::interpreter_frame_method_offset * wordSize; | |
1541 | |
1542 // Load up EDX with the branch displacement | |
1543 __ movl(rdx, at_bcp(1)); | |
304 | 1544 __ bswapl(rdx); |
0 | 1545 if (!is_wide) __ sarl(rdx, 16); |
304 | 1546 LP64_ONLY(__ movslq(rdx, rdx)); |
1547 | |
0 | 1548 |
1549 // Handle all the JSR stuff here, then exit. | |
1550 // It's much shorter and cleaner than intermingling with the | |
605 | 1551 // non-JSR normal-branch stuff occurring below. |
0 | 1552 if (is_jsr) { |
1553 // Pre-load the next target bytecode into EBX | |
1554 __ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1, 0)); | |
1555 | |
1556 // compute return address as bci in rax, | |
304 | 1557 __ lea(rax, at_bcp((is_wide ? 5 : 3) - in_bytes(constMethodOopDesc::codes_offset()))); |
1558 __ subptr(rax, Address(rcx, methodOopDesc::const_offset())); | |
362 | 1559 // Adjust the bcp in RSI by the displacement in EDX |
304 | 1560 __ addptr(rsi, rdx); |
0 | 1561 // Push return address |
1562 __ push_i(rax); | |
1563 // jsr returns vtos | |
1564 __ dispatch_only_noverify(vtos); | |
1565 return; | |
1566 } | |
1567 | |
1568 // Normal (non-jsr) branch handling | |
1569 | |
362 | 1570 // Adjust the bcp in RSI by the displacement in EDX |
304 | 1571 __ addptr(rsi, rdx); |
0 | 1572 |
1573 assert(UseLoopCounter || !UseOnStackReplacement, "on-stack-replacement requires loop counters"); | |
1574 Label backedge_counter_overflow; | |
1575 Label profile_method; | |
1576 Label dispatch; | |
1577 if (UseLoopCounter) { | |
1578 // increment backedge counter for backward branches | |
1579 // rax,: MDO | |
1580 // rbx,: MDO bumped taken-count | |
1581 // rcx: method | |
1582 // rdx: target offset | |
1583 // rsi: target bcp | |
1584 // rdi: locals pointer | |
1585 __ testl(rdx, rdx); // check if forward or backward branch | |
1586 __ jcc(Assembler::positive, dispatch); // count only if backward branch | |
1587 | |
1783 | 1588 if (TieredCompilation) { |
1589 Label no_mdo; | |
1590 int increment = InvocationCounter::count_increment; | |
1591 int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; | |
1592 if (ProfileInterpreter) { | |
1593 // Are we profiling? | |
1594 __ movptr(rbx, Address(rcx, in_bytes(methodOopDesc::method_data_offset()))); | |
1595 __ testptr(rbx, rbx); | |
1596 __ jccb(Assembler::zero, no_mdo); | |
1597 // Increment the MDO backedge counter | |
1598 const Address mdo_backedge_counter(rbx, in_bytes(methodDataOopDesc::backedge_counter_offset()) + | |
1599 in_bytes(InvocationCounter::counter_offset())); | |
1600 __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, | |
1601 rax, false, Assembler::zero, &backedge_counter_overflow); | |
1602 __ jmp(dispatch); | |
0 | 1603 } |
1783 | 1604 __ bind(no_mdo); |
1605 // Increment backedge counter in methodOop | |
1606 __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, | |
1607 rax, false, Assembler::zero, &backedge_counter_overflow); | |
0 | 1608 } else { |
1783 | 1609 // increment counter |
1610 __ movl(rax, Address(rcx, be_offset)); // load backedge counter | |
1611 __ incrementl(rax, InvocationCounter::count_increment); // increment counter | |
1612 __ movl(Address(rcx, be_offset), rax); // store counter | |
1613 | |
1614 __ movl(rax, Address(rcx, inv_offset)); // load invocation counter | |
1615 __ andl(rax, InvocationCounter::count_mask_value); // and the status bits | |
1616 __ addl(rax, Address(rcx, be_offset)); // add both counters | |
1617 | |
1618 if (ProfileInterpreter) { | |
1619 // Test to see if we should create a method data oop | |
0 | 1620 __ cmp32(rax, |
1783 | 1621 ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); |
1622 __ jcc(Assembler::less, dispatch); | |
1623 | |
1624 // if no method data exists, go to profile method | |
1625 __ test_method_data_pointer(rax, profile_method); | |
1626 | |
1627 if (UseOnStackReplacement) { | |
1628 // check for overflow against rbx, which is the MDO taken count | |
1629 __ cmp32(rbx, | |
1630 ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); | |
1631 __ jcc(Assembler::below, dispatch); | |
1632 | |
1633 // When ProfileInterpreter is on, the backedge_count comes from the | |
1634 // methodDataOop, which value does not get reset on the call to | |
1635 // frequency_counter_overflow(). To avoid excessive calls to the overflow | |
1636 // routine while the method is being compiled, add a second test to make | |
1637 // sure the overflow function is called only once every overflow_frequency. | |
1638 const int overflow_frequency = 1024; | |
1639 __ andptr(rbx, overflow_frequency-1); | |
1640 __ jcc(Assembler::zero, backedge_counter_overflow); | |
1641 } | |
1642 } else { | |
1643 if (UseOnStackReplacement) { | |
1644 // check for overflow against rax, which is the sum of the counters | |
1645 __ cmp32(rax, | |
1646 ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); | |
1647 __ jcc(Assembler::aboveEqual, backedge_counter_overflow); | |
1648 | |
1649 } | |
0 | 1650 } |
1651 } | |
1652 __ bind(dispatch); | |
1653 } | |
1654 | |
1655 // Pre-load the next target bytecode into EBX | |
1656 __ load_unsigned_byte(rbx, Address(rsi, 0)); | |
1657 | |
1658 // continue with the bytecode @ target | |
1659 // rax,: return bci for jsr's, unused otherwise | |
1660 // rbx,: target bytecode | |
1661 // rsi: target bcp | |
1662 __ dispatch_only(vtos); | |
1663 | |
1664 if (UseLoopCounter) { | |
1665 if (ProfileInterpreter) { | |
1666 // Out-of-line code to allocate method data oop. | |
1667 __ bind(profile_method); | |
1668 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method), rsi); | |
1669 __ load_unsigned_byte(rbx, Address(rsi, 0)); // restore target bytecode | |
304 | 1670 __ movptr(rcx, Address(rbp, method_offset)); |
1671 __ movptr(rcx, Address(rcx, in_bytes(methodOopDesc::method_data_offset()))); | |
1672 __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rcx); | |
0 | 1673 __ test_method_data_pointer(rcx, dispatch); |
1674 // offset non-null mdp by MDO::data_offset() + IR::profile_method() | |
304 | 1675 __ addptr(rcx, in_bytes(methodDataOopDesc::data_offset())); |
1676 __ addptr(rcx, rax); | |
1677 __ movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), rcx); | |
0 | 1678 __ jmp(dispatch); |
1679 } | |
1680 | |
1681 if (UseOnStackReplacement) { | |
1682 | |
1683 // invocation counter overflow | |
1684 __ bind(backedge_counter_overflow); | |
304 | 1685 __ negptr(rdx); |
1686 __ addptr(rdx, rsi); // branch bcp | |
0 | 1687 call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), rdx); |
1688 __ load_unsigned_byte(rbx, Address(rsi, 0)); // restore target bytecode | |
1689 | |
1690 // rax,: osr nmethod (osr ok) or NULL (osr not possible) | |
1691 // rbx,: target bytecode | |
1692 // rdx: scratch | |
1693 // rdi: locals pointer | |
1694 // rsi: bcp | |
304 | 1695 __ testptr(rax, rax); // test result |
0 | 1696 __ jcc(Assembler::zero, dispatch); // no osr if null |
1697 // nmethod may have been invalidated (VM may block upon call_VM return) | |
1698 __ movl(rcx, Address(rax, nmethod::entry_bci_offset())); | |
1699 __ cmpl(rcx, InvalidOSREntryBci); | |
1700 __ jcc(Assembler::equal, dispatch); | |
1701 | |
1702 // We have the address of an on stack replacement routine in rax, | |
1703 // We need to prepare to execute the OSR method. First we must | |
1704 // migrate the locals and monitors off of the stack. | |
1705 | |
304 | 1706 __ mov(rbx, rax); // save the nmethod |
0 | 1707 |
1708 const Register thread = rcx; | |
1709 __ get_thread(thread); | |
1710 call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); | |
1711 // rax, is OSR buffer, move it to expected parameter location | |
304 | 1712 __ mov(rcx, rax); |
0 | 1713 |
1714 // pop the interpreter frame | |
304 | 1715 __ movptr(rdx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp |
0 | 1716 __ leave(); // remove frame anchor |
304 | 1717 __ pop(rdi); // get return address |
1718 __ mov(rsp, rdx); // set sp to sender sp | |
0 | 1719 |
1720 | |
1721 Label skip; | |
1722 Label chkint; | |
1723 | |
1724 // The interpreter frame we have removed may be returning to | |
1725 // either the callstub or the interpreter. Since we will | |
1726 // now be returning from a compiled (OSR) nmethod we must | |
1727 // adjust the return to the return were it can handler compiled | |
1728 // results and clean the fpu stack. This is very similar to | |
1729 // what a i2c adapter must do. | |
1730 | |
1731 // Are we returning to the call stub? | |
1732 | |
1733 __ cmp32(rdi, ExternalAddress(StubRoutines::_call_stub_return_address)); | |
1734 __ jcc(Assembler::notEqual, chkint); | |
1735 | |
1736 // yes adjust to the specialized call stub return. | |
304 | 1737 assert(StubRoutines::x86::get_call_stub_compiled_return() != NULL, "must be set"); |
1738 __ lea(rdi, ExternalAddress(StubRoutines::x86::get_call_stub_compiled_return())); | |
0 | 1739 __ jmp(skip); |
1740 | |
1741 __ bind(chkint); | |
1742 | |
1743 // Are we returning to the interpreter? Look for sentinel | |
1744 | |
304 | 1745 __ cmpl(Address(rdi, -2*wordSize), Interpreter::return_sentinel); |
0 | 1746 __ jcc(Assembler::notEqual, skip); |
1747 | |
1748 // Adjust to compiled return back to interpreter | |
1749 | |
304 | 1750 __ movptr(rdi, Address(rdi, -wordSize)); |
0 | 1751 __ bind(skip); |
1752 | |
1753 // Align stack pointer for compiled code (note that caller is | |
1754 // responsible for undoing this fixup by remembering the old SP | |
1755 // in an rbp,-relative location) | |
304 | 1756 __ andptr(rsp, -(StackAlignmentInBytes)); |
0 | 1757 |
1758 // push the (possibly adjusted) return address | |
304 | 1759 __ push(rdi); |
0 | 1760 |
1761 // and begin the OSR nmethod | |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
1762 __ jmp(Address(rbx, nmethod::osr_entry_point_offset())); |
0 | 1763 } |
1764 } | |
1765 } | |
1766 | |
1767 | |
1768 void TemplateTable::if_0cmp(Condition cc) { | |
1769 transition(itos, vtos); | |
1770 // assume branch is more often taken than not (loops use backward branches) | |
1771 Label not_taken; | |
1772 __ testl(rax, rax); | |
1773 __ jcc(j_not(cc), not_taken); | |
1774 branch(false, false); | |
1775 __ bind(not_taken); | |
1776 __ profile_not_taken_branch(rax); | |
1777 } | |
1778 | |
1779 | |
1780 void TemplateTable::if_icmp(Condition cc) { | |
1781 transition(itos, vtos); | |
1782 // assume branch is more often taken than not (loops use backward branches) | |
1783 Label not_taken; | |
1784 __ pop_i(rdx); | |
1785 __ cmpl(rdx, rax); | |
1786 __ jcc(j_not(cc), not_taken); | |
1787 branch(false, false); | |
1788 __ bind(not_taken); | |
1789 __ profile_not_taken_branch(rax); | |
1790 } | |
1791 | |
1792 | |
1793 void TemplateTable::if_nullcmp(Condition cc) { | |
1794 transition(atos, vtos); | |
1795 // assume branch is more often taken than not (loops use backward branches) | |
1796 Label not_taken; | |
304 | 1797 __ testptr(rax, rax); |
0 | 1798 __ jcc(j_not(cc), not_taken); |
1799 branch(false, false); | |
1800 __ bind(not_taken); | |
1801 __ profile_not_taken_branch(rax); | |
1802 } | |
1803 | |
1804 | |
1805 void TemplateTable::if_acmp(Condition cc) { | |
1806 transition(atos, vtos); | |
1807 // assume branch is more often taken than not (loops use backward branches) | |
1808 Label not_taken; | |
1809 __ pop_ptr(rdx); | |
304 | 1810 __ cmpptr(rdx, rax); |
0 | 1811 __ jcc(j_not(cc), not_taken); |
1812 branch(false, false); | |
1813 __ bind(not_taken); | |
1814 __ profile_not_taken_branch(rax); | |
1815 } | |
1816 | |
1817 | |
1818 void TemplateTable::ret() { | |
1819 transition(vtos, vtos); | |
1820 locals_index(rbx); | |
304 | 1821 __ movptr(rbx, iaddress(rbx)); // get return bci, compute return bcp |
0 | 1822 __ profile_ret(rbx, rcx); |
1823 __ get_method(rax); | |
304 | 1824 __ movptr(rsi, Address(rax, methodOopDesc::const_offset())); |
1825 __ lea(rsi, Address(rsi, rbx, Address::times_1, | |
1826 constMethodOopDesc::codes_offset())); | |
0 | 1827 __ dispatch_next(vtos); |
1828 } | |
1829 | |
1830 | |
1831 void TemplateTable::wide_ret() { | |
1832 transition(vtos, vtos); | |
1833 locals_index_wide(rbx); | |
304 | 1834 __ movptr(rbx, iaddress(rbx)); // get return bci, compute return bcp |
0 | 1835 __ profile_ret(rbx, rcx); |
1836 __ get_method(rax); | |
304 | 1837 __ movptr(rsi, Address(rax, methodOopDesc::const_offset())); |
1838 __ lea(rsi, Address(rsi, rbx, Address::times_1, constMethodOopDesc::codes_offset())); | |
0 | 1839 __ dispatch_next(vtos); |
1840 } | |
1841 | |
1842 | |
1843 void TemplateTable::tableswitch() { | |
1844 Label default_case, continue_execution; | |
1845 transition(itos, vtos); | |
1846 // align rsi | |
304 | 1847 __ lea(rbx, at_bcp(wordSize)); |
1848 __ andptr(rbx, -wordSize); | |
0 | 1849 // load lo & hi |
1850 __ movl(rcx, Address(rbx, 1 * wordSize)); | |
1851 __ movl(rdx, Address(rbx, 2 * wordSize)); | |
304 | 1852 __ bswapl(rcx); |
1853 __ bswapl(rdx); | |
0 | 1854 // check against lo & hi |
1855 __ cmpl(rax, rcx); | |
1856 __ jccb(Assembler::less, default_case); | |
1857 __ cmpl(rax, rdx); | |
1858 __ jccb(Assembler::greater, default_case); | |
1859 // lookup dispatch offset | |
1860 __ subl(rax, rcx); | |
304 | 1861 __ movl(rdx, Address(rbx, rax, Address::times_4, 3 * BytesPerInt)); |
0 | 1862 __ profile_switch_case(rax, rbx, rcx); |
1863 // continue execution | |
1864 __ bind(continue_execution); | |
304 | 1865 __ bswapl(rdx); |
0 | 1866 __ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1)); |
304 | 1867 __ addptr(rsi, rdx); |
0 | 1868 __ dispatch_only(vtos); |
1869 // handle default | |
1870 __ bind(default_case); | |
1871 __ profile_switch_default(rax); | |
1872 __ movl(rdx, Address(rbx, 0)); | |
1873 __ jmp(continue_execution); | |
1874 } | |
1875 | |
1876 | |
1877 void TemplateTable::lookupswitch() { | |
1878 transition(itos, itos); | |
1879 __ stop("lookupswitch bytecode should have been rewritten"); | |
1880 } | |
1881 | |
1882 | |
1883 void TemplateTable::fast_linearswitch() { | |
1884 transition(itos, vtos); | |
1885 Label loop_entry, loop, found, continue_execution; | |
304 | 1886 // bswapl rax, so we can avoid bswapping the table entries |
1887 __ bswapl(rax); | |
0 | 1888 // align rsi |
304 | 1889 __ lea(rbx, at_bcp(wordSize)); // btw: should be able to get rid of this instruction (change offsets below) |
1890 __ andptr(rbx, -wordSize); | |
0 | 1891 // set counter |
1892 __ movl(rcx, Address(rbx, wordSize)); | |
304 | 1893 __ bswapl(rcx); |
0 | 1894 __ jmpb(loop_entry); |
1895 // table search | |
1896 __ bind(loop); | |
1897 __ cmpl(rax, Address(rbx, rcx, Address::times_8, 2 * wordSize)); | |
1898 __ jccb(Assembler::equal, found); | |
1899 __ bind(loop_entry); | |
304 | 1900 __ decrementl(rcx); |
0 | 1901 __ jcc(Assembler::greaterEqual, loop); |
1902 // default case | |
1903 __ profile_switch_default(rax); | |
1904 __ movl(rdx, Address(rbx, 0)); | |
1905 __ jmpb(continue_execution); | |
1906 // entry found -> get offset | |
1907 __ bind(found); | |
1908 __ movl(rdx, Address(rbx, rcx, Address::times_8, 3 * wordSize)); | |
1909 __ profile_switch_case(rcx, rax, rbx); | |
1910 // continue execution | |
1911 __ bind(continue_execution); | |
304 | 1912 __ bswapl(rdx); |
0 | 1913 __ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1)); |
304 | 1914 __ addptr(rsi, rdx); |
0 | 1915 __ dispatch_only(vtos); |
1916 } | |
1917 | |
1918 | |
1919 void TemplateTable::fast_binaryswitch() { | |
1920 transition(itos, vtos); | |
1921 // Implementation using the following core algorithm: | |
1922 // | |
1923 // int binary_search(int key, LookupswitchPair* array, int n) { | |
1924 // // Binary search according to "Methodik des Programmierens" by | |
1925 // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. | |
1926 // int i = 0; | |
1927 // int j = n; | |
1928 // while (i+1 < j) { | |
1929 // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) | |
1930 // // with Q: for all i: 0 <= i < n: key < a[i] | |
1931 // // where a stands for the array and assuming that the (inexisting) | |
1932 // // element a[n] is infinitely big. | |
1933 // int h = (i + j) >> 1; | |
1934 // // i < h < j | |
1935 // if (key < array[h].fast_match()) { | |
1936 // j = h; | |
1937 // } else { | |
1938 // i = h; | |
1939 // } | |
1940 // } | |
1941 // // R: a[i] <= key < a[i+1] or Q | |
1942 // // (i.e., if key is within array, i is the correct index) | |
1943 // return i; | |
1944 // } | |
1945 | |
1946 // register allocation | |
1947 const Register key = rax; // already set (tosca) | |
1948 const Register array = rbx; | |
1949 const Register i = rcx; | |
1950 const Register j = rdx; | |
1951 const Register h = rdi; // needs to be restored | |
1952 const Register temp = rsi; | |
1953 // setup array | |
1954 __ save_bcp(); | |
1955 | |
304 | 1956 __ lea(array, at_bcp(3*wordSize)); // btw: should be able to get rid of this instruction (change offsets below) |
1957 __ andptr(array, -wordSize); | |
0 | 1958 // initialize i & j |
1959 __ xorl(i, i); // i = 0; | |
1960 __ movl(j, Address(array, -wordSize)); // j = length(array); | |
1961 // Convert j into native byteordering | |
304 | 1962 __ bswapl(j); |
0 | 1963 // and start |
1964 Label entry; | |
1965 __ jmp(entry); | |
1966 | |
1967 // binary search loop | |
1968 { Label loop; | |
1969 __ bind(loop); | |
1970 // int h = (i + j) >> 1; | |
1971 __ leal(h, Address(i, j, Address::times_1)); // h = i + j; | |
1972 __ sarl(h, 1); // h = (i + j) >> 1; | |
1973 // if (key < array[h].fast_match()) { | |
1974 // j = h; | |
1975 // } else { | |
1976 // i = h; | |
1977 // } | |
1978 // Convert array[h].match to native byte-ordering before compare | |
1979 __ movl(temp, Address(array, h, Address::times_8, 0*wordSize)); | |
304 | 1980 __ bswapl(temp); |
0 | 1981 __ cmpl(key, temp); |
1982 if (VM_Version::supports_cmov()) { | |
1983 __ cmovl(Assembler::less , j, h); // j = h if (key < array[h].fast_match()) | |
1984 __ cmovl(Assembler::greaterEqual, i, h); // i = h if (key >= array[h].fast_match()) | |
1985 } else { | |
1986 Label set_i, end_of_if; | |
304 | 1987 __ jccb(Assembler::greaterEqual, set_i); // { |
1988 __ mov(j, h); // j = h; | |
1989 __ jmp(end_of_if); // } | |
1990 __ bind(set_i); // else { | |
1991 __ mov(i, h); // i = h; | |
1992 __ bind(end_of_if); // } | |
0 | 1993 } |
1994 // while (i+1 < j) | |
1995 __ bind(entry); | |
1996 __ leal(h, Address(i, 1)); // i+1 | |
1997 __ cmpl(h, j); // i+1 < j | |
1998 __ jcc(Assembler::less, loop); | |
1999 } | |
2000 | |
2001 // end of binary search, result index is i (must check again!) | |
2002 Label default_case; | |
2003 // Convert array[i].match to native byte-ordering before compare | |
2004 __ movl(temp, Address(array, i, Address::times_8, 0*wordSize)); | |
304 | 2005 __ bswapl(temp); |
0 | 2006 __ cmpl(key, temp); |
2007 __ jcc(Assembler::notEqual, default_case); | |
2008 | |
2009 // entry found -> j = offset | |
2010 __ movl(j , Address(array, i, Address::times_8, 1*wordSize)); | |
2011 __ profile_switch_case(i, key, array); | |
304 | 2012 __ bswapl(j); |
2013 LP64_ONLY(__ movslq(j, j)); | |
0 | 2014 __ restore_bcp(); |
2015 __ restore_locals(); // restore rdi | |
2016 __ load_unsigned_byte(rbx, Address(rsi, j, Address::times_1)); | |
2017 | |
304 | 2018 __ addptr(rsi, j); |
0 | 2019 __ dispatch_only(vtos); |
2020 | |
2021 // default case -> j = default offset | |
2022 __ bind(default_case); | |
2023 __ profile_switch_default(i); | |
2024 __ movl(j, Address(array, -2*wordSize)); | |
304 | 2025 __ bswapl(j); |
2026 LP64_ONLY(__ movslq(j, j)); | |
0 | 2027 __ restore_bcp(); |
2028 __ restore_locals(); // restore rdi | |
2029 __ load_unsigned_byte(rbx, Address(rsi, j, Address::times_1)); | |
304 | 2030 __ addptr(rsi, j); |
0 | 2031 __ dispatch_only(vtos); |
2032 } | |
2033 | |
2034 | |
2035 void TemplateTable::_return(TosState state) { | |
2036 transition(state, state); | |
2037 assert(_desc->calls_vm(), "inconsistent calls_vm information"); // call in remove_activation | |
2038 | |
2039 if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { | |
2040 assert(state == vtos, "only valid state"); | |
304 | 2041 __ movptr(rax, aaddress(0)); |
2042 __ movptr(rdi, Address(rax, oopDesc::klass_offset_in_bytes())); | |
0 | 2043 __ movl(rdi, Address(rdi, Klass::access_flags_offset_in_bytes() + sizeof(oopDesc))); |
2044 __ testl(rdi, JVM_ACC_HAS_FINALIZER); | |
2045 Label skip_register_finalizer; | |
2046 __ jcc(Assembler::zero, skip_register_finalizer); | |
2047 | |
2048 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), rax); | |
2049 | |
2050 __ bind(skip_register_finalizer); | |
2051 } | |
2052 | |
2053 __ remove_activation(state, rsi); | |
2054 __ jmp(rsi); | |
2055 } | |
2056 | |
2057 | |
2058 // ---------------------------------------------------------------------------- | |
2059 // Volatile variables demand their effects be made known to all CPU's in | |
2060 // order. Store buffers on most chips allow reads & writes to reorder; the | |
2061 // JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of | |
2062 // memory barrier (i.e., it's not sufficient that the interpreter does not | |
2063 // reorder volatile references, the hardware also must not reorder them). | |
2064 // | |
2065 // According to the new Java Memory Model (JMM): | |
2066 // (1) All volatiles are serialized wrt to each other. | |
2067 // ALSO reads & writes act as aquire & release, so: | |
2068 // (2) A read cannot let unrelated NON-volatile memory refs that happen after | |
2069 // the read float up to before the read. It's OK for non-volatile memory refs | |
2070 // that happen before the volatile read to float down below it. | |
2071 // (3) Similar a volatile write cannot let unrelated NON-volatile memory refs | |
2072 // that happen BEFORE the write float down to after the write. It's OK for | |
2073 // non-volatile memory refs that happen after the volatile write to float up | |
2074 // before it. | |
2075 // | |
2076 // We only put in barriers around volatile refs (they are expensive), not | |
2077 // _between_ memory refs (that would require us to track the flavor of the | |
2078 // previous memory refs). Requirements (2) and (3) require some barriers | |
2079 // before volatile stores and after volatile loads. These nearly cover | |
2080 // requirement (1) but miss the volatile-store-volatile-load case. This final | |
2081 // case is placed after volatile-stores although it could just as well go | |
2082 // before volatile-loads. | |
304 | 2083 void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint ) { |
0 | 2084 // Helper function to insert a is-volatile test and memory barrier |
2085 if( !os::is_MP() ) return; // Not needed on single CPU | |
304 | 2086 __ membar(order_constraint); |
0 | 2087 } |
2088 | |
1565 | 2089 void TemplateTable::resolve_cache_and_index(int byte_no, |
2090 Register result, | |
2091 Register Rcache, | |
2092 Register index, | |
2093 size_t index_size) { | |
0 | 2094 Register temp = rbx; |
2095 | |
1565 | 2096 assert_different_registers(result, Rcache, index, temp); |
2097 | |
0 | 2098 Label resolved; |
1565 | 2099 __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); |
2100 if (byte_no == f1_oop) { | |
2101 // We are resolved if the f1 field contains a non-null object (CallSite, etc.) | |
2102 // This kind of CP cache entry does not need to match the flags byte, because | |
2103 // there is a 1-1 relation between bytecode type and CP entry type. | |
2104 assert(result != noreg, ""); //else do cmpptr(Address(...), (int32_t) NULL_WORD) | |
2105 __ movptr(result, Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset())); | |
2106 __ testptr(result, result); | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2107 __ jcc(Assembler::notEqual, resolved); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2108 } else { |
1565 | 2109 assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); |
2110 assert(result == noreg, ""); //else change code for setting result | |
2111 const int shift_count = (1 + byte_no)*BitsPerByte; | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2112 __ movl(temp, Address(Rcache, index, Address::times_4, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset())); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2113 __ shrl(temp, shift_count); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2114 // have we resolved this bytecode? |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2115 __ andl(temp, 0xFF); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2116 __ cmpl(temp, (int)bytecode()); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2117 __ jcc(Assembler::equal, resolved); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2118 } |
0 | 2119 |
2120 // resolve first time through | |
2121 address entry; | |
2122 switch (bytecode()) { | |
2123 case Bytecodes::_getstatic : // fall through | |
2124 case Bytecodes::_putstatic : // fall through | |
2125 case Bytecodes::_getfield : // fall through | |
2126 case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break; | |
2127 case Bytecodes::_invokevirtual : // fall through | |
2128 case Bytecodes::_invokespecial : // fall through | |
2129 case Bytecodes::_invokestatic : // fall through | |
2130 case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break; | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2131 case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break; |
1602 | 2132 case Bytecodes::_fast_aldc : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; |
2133 case Bytecodes::_fast_aldc_w : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); break; | |
0 | 2134 default : ShouldNotReachHere(); break; |
2135 } | |
2136 __ movl(temp, (int)bytecode()); | |
2137 __ call_VM(noreg, entry, temp); | |
2138 // Update registers with resolved info | |
1565 | 2139 __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); |
2140 if (result != noreg) | |
2141 __ movptr(result, Address(Rcache, index, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f1_offset())); | |
0 | 2142 __ bind(resolved); |
2143 } | |
2144 | |
2145 | |
2146 // The cache and index registers must be set before call | |
2147 void TemplateTable::load_field_cp_cache_entry(Register obj, | |
2148 Register cache, | |
2149 Register index, | |
2150 Register off, | |
2151 Register flags, | |
2152 bool is_static = false) { | |
2153 assert_different_registers(cache, index, flags, off); | |
2154 | |
2155 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2156 // Field offset | |
304 | 2157 __ movptr(off, Address(cache, index, Address::times_ptr, |
2158 in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset()))); | |
0 | 2159 // Flags |
304 | 2160 __ movl(flags, Address(cache, index, Address::times_ptr, |
0 | 2161 in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset()))); |
2162 | |
2163 // klass overwrite register | |
2164 if (is_static) { | |
304 | 2165 __ movptr(obj, Address(cache, index, Address::times_ptr, |
2166 in_bytes(cp_base_offset + ConstantPoolCacheEntry::f1_offset()))); | |
0 | 2167 } |
2168 } | |
2169 | |
2170 void TemplateTable::load_invoke_cp_cache_entry(int byte_no, | |
2171 Register method, | |
2172 Register itable_index, | |
2173 Register flags, | |
2174 bool is_invokevirtual, | |
1565 | 2175 bool is_invokevfinal /*unused*/, |
2176 bool is_invokedynamic) { | |
0 | 2177 // setup registers |
2178 const Register cache = rcx; | |
2179 const Register index = rdx; | |
2180 assert_different_registers(method, flags); | |
2181 assert_different_registers(method, cache, index); | |
2182 assert_different_registers(itable_index, flags); | |
2183 assert_different_registers(itable_index, cache, index); | |
2184 // determine constant pool cache field offsets | |
2185 const int method_offset = in_bytes( | |
2186 constantPoolCacheOopDesc::base_offset() + | |
2187 (is_invokevirtual | |
2188 ? ConstantPoolCacheEntry::f2_offset() | |
2189 : ConstantPoolCacheEntry::f1_offset() | |
2190 ) | |
2191 ); | |
2192 const int flags_offset = in_bytes(constantPoolCacheOopDesc::base_offset() + | |
2193 ConstantPoolCacheEntry::flags_offset()); | |
2194 // access constant pool cache fields | |
2195 const int index_offset = in_bytes(constantPoolCacheOopDesc::base_offset() + | |
2196 ConstantPoolCacheEntry::f2_offset()); | |
2197 | |
1565 | 2198 if (byte_no == f1_oop) { |
2199 // Resolved f1_oop goes directly into 'method' register. | |
2200 assert(is_invokedynamic, ""); | |
2201 resolve_cache_and_index(byte_no, method, cache, index, sizeof(u4)); | |
2202 } else { | |
2203 resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); | |
2204 __ movptr(method, Address(cache, index, Address::times_ptr, method_offset)); | |
2205 } | |
0 | 2206 if (itable_index != noreg) { |
304 | 2207 __ movptr(itable_index, Address(cache, index, Address::times_ptr, index_offset)); |
0 | 2208 } |
1565 | 2209 __ movl(flags, Address(cache, index, Address::times_ptr, flags_offset)); |
0 | 2210 } |
2211 | |
2212 | |
2213 // The registers cache and index expected to be set before call. | |
2214 // Correct values of the cache and index registers are preserved. | |
2215 void TemplateTable::jvmti_post_field_access(Register cache, | |
2216 Register index, | |
2217 bool is_static, | |
2218 bool has_tos) { | |
2219 if (JvmtiExport::can_post_field_access()) { | |
2220 // Check to see if a field access watch has been set before we take | |
2221 // the time to call into the VM. | |
2222 Label L1; | |
2223 assert_different_registers(cache, index, rax); | |
2224 __ mov32(rax, ExternalAddress((address) JvmtiExport::get_field_access_count_addr())); | |
2225 __ testl(rax,rax); | |
2226 __ jcc(Assembler::zero, L1); | |
2227 | |
2228 // cache entry pointer | |
304 | 2229 __ addptr(cache, in_bytes(constantPoolCacheOopDesc::base_offset())); |
0 | 2230 __ shll(index, LogBytesPerWord); |
304 | 2231 __ addptr(cache, index); |
0 | 2232 if (is_static) { |
304 | 2233 __ xorptr(rax, rax); // NULL object reference |
0 | 2234 } else { |
2235 __ pop(atos); // Get the object | |
2236 __ verify_oop(rax); | |
2237 __ push(atos); // Restore stack state | |
2238 } | |
2239 // rax,: object pointer or NULL | |
2240 // cache: cache entry pointer | |
2241 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), | |
2242 rax, cache); | |
2243 __ get_cache_and_index_at_bcp(cache, index, 1); | |
2244 __ bind(L1); | |
2245 } | |
2246 } | |
2247 | |
2248 void TemplateTable::pop_and_check_object(Register r) { | |
2249 __ pop_ptr(r); | |
2250 __ null_check(r); // for field access must check obj. | |
2251 __ verify_oop(r); | |
2252 } | |
2253 | |
2254 void TemplateTable::getfield_or_static(int byte_no, bool is_static) { | |
2255 transition(vtos, vtos); | |
2256 | |
2257 const Register cache = rcx; | |
2258 const Register index = rdx; | |
2259 const Register obj = rcx; | |
2260 const Register off = rbx; | |
2261 const Register flags = rax; | |
2262 | |
1565 | 2263 resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); |
0 | 2264 jvmti_post_field_access(cache, index, is_static, false); |
2265 load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); | |
2266 | |
2267 if (!is_static) pop_and_check_object(obj); | |
2268 | |
2269 const Address lo(obj, off, Address::times_1, 0*wordSize); | |
2270 const Address hi(obj, off, Address::times_1, 1*wordSize); | |
2271 | |
2272 Label Done, notByte, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; | |
2273 | |
2274 __ shrl(flags, ConstantPoolCacheEntry::tosBits); | |
2275 assert(btos == 0, "change code, btos != 0"); | |
2276 // btos | |
304 | 2277 __ andptr(flags, 0x0f); |
0 | 2278 __ jcc(Assembler::notZero, notByte); |
2279 | |
2280 __ load_signed_byte(rax, lo ); | |
2281 __ push(btos); | |
2282 // Rewrite bytecode to be faster | |
2283 if (!is_static) { | |
2284 patch_bytecode(Bytecodes::_fast_bgetfield, rcx, rbx); | |
2285 } | |
2286 __ jmp(Done); | |
2287 | |
2288 __ bind(notByte); | |
2289 // itos | |
2290 __ cmpl(flags, itos ); | |
2291 __ jcc(Assembler::notEqual, notInt); | |
2292 | |
2293 __ movl(rax, lo ); | |
2294 __ push(itos); | |
2295 // Rewrite bytecode to be faster | |
2296 if (!is_static) { | |
2297 patch_bytecode(Bytecodes::_fast_igetfield, rcx, rbx); | |
2298 } | |
2299 __ jmp(Done); | |
2300 | |
2301 __ bind(notInt); | |
2302 // atos | |
2303 __ cmpl(flags, atos ); | |
2304 __ jcc(Assembler::notEqual, notObj); | |
2305 | |
2306 __ movl(rax, lo ); | |
2307 __ push(atos); | |
2308 if (!is_static) { | |
2309 patch_bytecode(Bytecodes::_fast_agetfield, rcx, rbx); | |
2310 } | |
2311 __ jmp(Done); | |
2312 | |
2313 __ bind(notObj); | |
2314 // ctos | |
2315 __ cmpl(flags, ctos ); | |
2316 __ jcc(Assembler::notEqual, notChar); | |
2317 | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
2318 __ load_unsigned_short(rax, lo ); |
0 | 2319 __ push(ctos); |
2320 if (!is_static) { | |
2321 patch_bytecode(Bytecodes::_fast_cgetfield, rcx, rbx); | |
2322 } | |
2323 __ jmp(Done); | |
2324 | |
2325 __ bind(notChar); | |
2326 // stos | |
2327 __ cmpl(flags, stos ); | |
2328 __ jcc(Assembler::notEqual, notShort); | |
2329 | |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
2330 __ load_signed_short(rax, lo ); |
0 | 2331 __ push(stos); |
2332 if (!is_static) { | |
2333 patch_bytecode(Bytecodes::_fast_sgetfield, rcx, rbx); | |
2334 } | |
2335 __ jmp(Done); | |
2336 | |
2337 __ bind(notShort); | |
2338 // ltos | |
2339 __ cmpl(flags, ltos ); | |
2340 __ jcc(Assembler::notEqual, notLong); | |
2341 | |
2342 // Generate code as if volatile. There just aren't enough registers to | |
2343 // save that information and this code is faster than the test. | |
2344 __ fild_d(lo); // Must load atomically | |
304 | 2345 __ subptr(rsp,2*wordSize); // Make space for store |
0 | 2346 __ fistp_d(Address(rsp,0)); |
304 | 2347 __ pop(rax); |
2348 __ pop(rdx); | |
0 | 2349 |
2350 __ push(ltos); | |
2351 // Don't rewrite to _fast_lgetfield for potential volatile case. | |
2352 __ jmp(Done); | |
2353 | |
2354 __ bind(notLong); | |
2355 // ftos | |
2356 __ cmpl(flags, ftos ); | |
2357 __ jcc(Assembler::notEqual, notFloat); | |
2358 | |
2359 __ fld_s(lo); | |
2360 __ push(ftos); | |
2361 if (!is_static) { | |
2362 patch_bytecode(Bytecodes::_fast_fgetfield, rcx, rbx); | |
2363 } | |
2364 __ jmp(Done); | |
2365 | |
2366 __ bind(notFloat); | |
2367 // dtos | |
2368 __ cmpl(flags, dtos ); | |
2369 __ jcc(Assembler::notEqual, notDouble); | |
2370 | |
2371 __ fld_d(lo); | |
2372 __ push(dtos); | |
2373 if (!is_static) { | |
2374 patch_bytecode(Bytecodes::_fast_dgetfield, rcx, rbx); | |
2375 } | |
2376 __ jmpb(Done); | |
2377 | |
2378 __ bind(notDouble); | |
2379 | |
2380 __ stop("Bad state"); | |
2381 | |
2382 __ bind(Done); | |
2383 // Doug Lea believes this is not needed with current Sparcs (TSO) and Intel (PSO). | |
2384 // volatile_barrier( ); | |
2385 } | |
2386 | |
2387 | |
2388 void TemplateTable::getfield(int byte_no) { | |
2389 getfield_or_static(byte_no, false); | |
2390 } | |
2391 | |
2392 | |
2393 void TemplateTable::getstatic(int byte_no) { | |
2394 getfield_or_static(byte_no, true); | |
2395 } | |
2396 | |
2397 // The registers cache and index expected to be set before call. | |
2398 // The function may destroy various registers, just not the cache and index registers. | |
2399 void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { | |
2400 | |
2401 ByteSize cp_base_offset = constantPoolCacheOopDesc::base_offset(); | |
2402 | |
2403 if (JvmtiExport::can_post_field_modification()) { | |
2404 // Check to see if a field modification watch has been set before we take | |
2405 // the time to call into the VM. | |
2406 Label L1; | |
2407 assert_different_registers(cache, index, rax); | |
2408 __ mov32(rax, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr())); | |
2409 __ testl(rax, rax); | |
2410 __ jcc(Assembler::zero, L1); | |
2411 | |
2412 // The cache and index registers have been already set. | |
2413 // This allows to eliminate this call but the cache and index | |
2414 // registers have to be correspondingly used after this line. | |
2415 __ get_cache_and_index_at_bcp(rax, rdx, 1); | |
2416 | |
2417 if (is_static) { | |
2418 // Life is simple. Null out the object pointer. | |
304 | 2419 __ xorptr(rbx, rbx); |
0 | 2420 } else { |
2421 // Life is harder. The stack holds the value on top, followed by the object. | |
2422 // We don't know the size of the value, though; it could be one or two words | |
2423 // depending on its type. As a result, we must find the type to determine where | |
2424 // the object is. | |
2425 Label two_word, valsize_known; | |
304 | 2426 __ movl(rcx, Address(rax, rdx, Address::times_ptr, in_bytes(cp_base_offset + |
0 | 2427 ConstantPoolCacheEntry::flags_offset()))); |
304 | 2428 __ mov(rbx, rsp); |
0 | 2429 __ shrl(rcx, ConstantPoolCacheEntry::tosBits); |
2430 // Make sure we don't need to mask rcx for tosBits after the above shift | |
2431 ConstantPoolCacheEntry::verify_tosBits(); | |
2432 __ cmpl(rcx, ltos); | |
2433 __ jccb(Assembler::equal, two_word); | |
2434 __ cmpl(rcx, dtos); | |
2435 __ jccb(Assembler::equal, two_word); | |
304 | 2436 __ addptr(rbx, Interpreter::expr_offset_in_bytes(1)); // one word jvalue (not ltos, dtos) |
0 | 2437 __ jmpb(valsize_known); |
2438 | |
2439 __ bind(two_word); | |
304 | 2440 __ addptr(rbx, Interpreter::expr_offset_in_bytes(2)); // two words jvalue |
0 | 2441 |
2442 __ bind(valsize_known); | |
2443 // setup object pointer | |
304 | 2444 __ movptr(rbx, Address(rbx, 0)); |
0 | 2445 } |
2446 // cache entry pointer | |
304 | 2447 __ addptr(rax, in_bytes(cp_base_offset)); |
0 | 2448 __ shll(rdx, LogBytesPerWord); |
304 | 2449 __ addptr(rax, rdx); |
0 | 2450 // object (tos) |
304 | 2451 __ mov(rcx, rsp); |
0 | 2452 // rbx,: object pointer set up above (NULL if static) |
2453 // rax,: cache entry pointer | |
2454 // rcx: jvalue object on the stack | |
2455 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), | |
2456 rbx, rax, rcx); | |
2457 __ get_cache_and_index_at_bcp(cache, index, 1); | |
2458 __ bind(L1); | |
2459 } | |
2460 } | |
2461 | |
2462 | |
2463 void TemplateTable::putfield_or_static(int byte_no, bool is_static) { | |
2464 transition(vtos, vtos); | |
2465 | |
2466 const Register cache = rcx; | |
2467 const Register index = rdx; | |
2468 const Register obj = rcx; | |
2469 const Register off = rbx; | |
2470 const Register flags = rax; | |
2471 | |
1565 | 2472 resolve_cache_and_index(byte_no, noreg, cache, index, sizeof(u2)); |
0 | 2473 jvmti_post_field_mod(cache, index, is_static); |
2474 load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); | |
2475 | |
2476 // Doug Lea believes this is not needed with current Sparcs (TSO) and Intel (PSO). | |
2477 // volatile_barrier( ); | |
2478 | |
2479 Label notVolatile, Done; | |
2480 __ movl(rdx, flags); | |
2481 __ shrl(rdx, ConstantPoolCacheEntry::volatileField); | |
2482 __ andl(rdx, 0x1); | |
2483 | |
2484 // field addresses | |
2485 const Address lo(obj, off, Address::times_1, 0*wordSize); | |
2486 const Address hi(obj, off, Address::times_1, 1*wordSize); | |
2487 | |
2488 Label notByte, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble; | |
2489 | |
2490 __ shrl(flags, ConstantPoolCacheEntry::tosBits); | |
2491 assert(btos == 0, "change code, btos != 0"); | |
2492 // btos | |
2493 __ andl(flags, 0x0f); | |
2494 __ jcc(Assembler::notZero, notByte); | |
2495 | |
2496 __ pop(btos); | |
2497 if (!is_static) pop_and_check_object(obj); | |
2498 __ movb(lo, rax ); | |
2499 if (!is_static) { | |
2500 patch_bytecode(Bytecodes::_fast_bputfield, rcx, rbx); | |
2501 } | |
2502 __ jmp(Done); | |
2503 | |
2504 __ bind(notByte); | |
2505 // itos | |
2506 __ cmpl(flags, itos ); | |
2507 __ jcc(Assembler::notEqual, notInt); | |
2508 | |
2509 __ pop(itos); | |
2510 if (!is_static) pop_and_check_object(obj); | |
2511 | |
2512 __ movl(lo, rax ); | |
2513 if (!is_static) { | |
2514 patch_bytecode(Bytecodes::_fast_iputfield, rcx, rbx); | |
2515 } | |
2516 __ jmp(Done); | |
2517 | |
2518 __ bind(notInt); | |
2519 // atos | |
2520 __ cmpl(flags, atos ); | |
2521 __ jcc(Assembler::notEqual, notObj); | |
2522 | |
2523 __ pop(atos); | |
2524 if (!is_static) pop_and_check_object(obj); | |
2525 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2526 do_oop_store(_masm, lo, rax, _bs->kind(), false); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2527 |
0 | 2528 if (!is_static) { |
2529 patch_bytecode(Bytecodes::_fast_aputfield, rcx, rbx); | |
2530 } | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2531 |
0 | 2532 __ jmp(Done); |
2533 | |
2534 __ bind(notObj); | |
2535 // ctos | |
2536 __ cmpl(flags, ctos ); | |
2537 __ jcc(Assembler::notEqual, notChar); | |
2538 | |
2539 __ pop(ctos); | |
2540 if (!is_static) pop_and_check_object(obj); | |
2541 __ movw(lo, rax ); | |
2542 if (!is_static) { | |
2543 patch_bytecode(Bytecodes::_fast_cputfield, rcx, rbx); | |
2544 } | |
2545 __ jmp(Done); | |
2546 | |
2547 __ bind(notChar); | |
2548 // stos | |
2549 __ cmpl(flags, stos ); | |
2550 __ jcc(Assembler::notEqual, notShort); | |
2551 | |
2552 __ pop(stos); | |
2553 if (!is_static) pop_and_check_object(obj); | |
2554 __ movw(lo, rax ); | |
2555 if (!is_static) { | |
2556 patch_bytecode(Bytecodes::_fast_sputfield, rcx, rbx); | |
2557 } | |
2558 __ jmp(Done); | |
2559 | |
2560 __ bind(notShort); | |
2561 // ltos | |
2562 __ cmpl(flags, ltos ); | |
2563 __ jcc(Assembler::notEqual, notLong); | |
2564 | |
2565 Label notVolatileLong; | |
2566 __ testl(rdx, rdx); | |
2567 __ jcc(Assembler::zero, notVolatileLong); | |
2568 | |
2569 __ pop(ltos); // overwrites rdx, do this after testing volatile. | |
2570 if (!is_static) pop_and_check_object(obj); | |
2571 | |
2572 // Replace with real volatile test | |
304 | 2573 __ push(rdx); |
2574 __ push(rax); // Must update atomically with FIST | |
0 | 2575 __ fild_d(Address(rsp,0)); // So load into FPU register |
2576 __ fistp_d(lo); // and put into memory atomically | |
304 | 2577 __ addptr(rsp, 2*wordSize); |
2578 // volatile_barrier(); | |
2579 volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad | | |
2580 Assembler::StoreStore)); | |
0 | 2581 // Don't rewrite volatile version |
2582 __ jmp(notVolatile); | |
2583 | |
2584 __ bind(notVolatileLong); | |
2585 | |
2586 __ pop(ltos); // overwrites rdx | |
2587 if (!is_static) pop_and_check_object(obj); | |
304 | 2588 NOT_LP64(__ movptr(hi, rdx)); |
2589 __ movptr(lo, rax); | |
0 | 2590 if (!is_static) { |
2591 patch_bytecode(Bytecodes::_fast_lputfield, rcx, rbx); | |
2592 } | |
2593 __ jmp(notVolatile); | |
2594 | |
2595 __ bind(notLong); | |
2596 // ftos | |
2597 __ cmpl(flags, ftos ); | |
2598 __ jcc(Assembler::notEqual, notFloat); | |
2599 | |
2600 __ pop(ftos); | |
2601 if (!is_static) pop_and_check_object(obj); | |
2602 __ fstp_s(lo); | |
2603 if (!is_static) { | |
2604 patch_bytecode(Bytecodes::_fast_fputfield, rcx, rbx); | |
2605 } | |
2606 __ jmp(Done); | |
2607 | |
2608 __ bind(notFloat); | |
2609 // dtos | |
2610 __ cmpl(flags, dtos ); | |
2611 __ jcc(Assembler::notEqual, notDouble); | |
2612 | |
2613 __ pop(dtos); | |
2614 if (!is_static) pop_and_check_object(obj); | |
2615 __ fstp_d(lo); | |
2616 if (!is_static) { | |
2617 patch_bytecode(Bytecodes::_fast_dputfield, rcx, rbx); | |
2618 } | |
2619 __ jmp(Done); | |
2620 | |
2621 __ bind(notDouble); | |
2622 | |
2623 __ stop("Bad state"); | |
2624 | |
2625 __ bind(Done); | |
2626 | |
2627 // Check for volatile store | |
2628 __ testl(rdx, rdx); | |
2629 __ jcc(Assembler::zero, notVolatile); | |
304 | 2630 volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad | |
2631 Assembler::StoreStore)); | |
0 | 2632 __ bind(notVolatile); |
2633 } | |
2634 | |
2635 | |
2636 void TemplateTable::putfield(int byte_no) { | |
2637 putfield_or_static(byte_no, false); | |
2638 } | |
2639 | |
2640 | |
2641 void TemplateTable::putstatic(int byte_no) { | |
2642 putfield_or_static(byte_no, true); | |
2643 } | |
2644 | |
2645 void TemplateTable::jvmti_post_fast_field_mod() { | |
2646 if (JvmtiExport::can_post_field_modification()) { | |
2647 // Check to see if a field modification watch has been set before we take | |
2648 // the time to call into the VM. | |
2649 Label L2; | |
2650 __ mov32(rcx, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr())); | |
2651 __ testl(rcx,rcx); | |
2652 __ jcc(Assembler::zero, L2); | |
2653 __ pop_ptr(rbx); // copy the object pointer from tos | |
2654 __ verify_oop(rbx); | |
2655 __ push_ptr(rbx); // put the object pointer back on tos | |
304 | 2656 __ subptr(rsp, sizeof(jvalue)); // add space for a jvalue object |
2657 __ mov(rcx, rsp); | |
0 | 2658 __ push_ptr(rbx); // save object pointer so we can steal rbx, |
304 | 2659 __ xorptr(rbx, rbx); |
0 | 2660 const Address lo_value(rcx, rbx, Address::times_1, 0*wordSize); |
2661 const Address hi_value(rcx, rbx, Address::times_1, 1*wordSize); | |
2662 switch (bytecode()) { // load values into the jvalue object | |
2663 case Bytecodes::_fast_bputfield: __ movb(lo_value, rax); break; | |
2664 case Bytecodes::_fast_sputfield: __ movw(lo_value, rax); break; | |
2665 case Bytecodes::_fast_cputfield: __ movw(lo_value, rax); break; | |
2666 case Bytecodes::_fast_iputfield: __ movl(lo_value, rax); break; | |
304 | 2667 case Bytecodes::_fast_lputfield: |
2668 NOT_LP64(__ movptr(hi_value, rdx)); | |
2669 __ movptr(lo_value, rax); | |
2670 break; | |
2671 | |
0 | 2672 // need to call fld_s() after fstp_s() to restore the value for below |
2673 case Bytecodes::_fast_fputfield: __ fstp_s(lo_value); __ fld_s(lo_value); break; | |
304 | 2674 |
0 | 2675 // need to call fld_d() after fstp_d() to restore the value for below |
2676 case Bytecodes::_fast_dputfield: __ fstp_d(lo_value); __ fld_d(lo_value); break; | |
304 | 2677 |
0 | 2678 // since rcx is not an object we don't call store_check() here |
304 | 2679 case Bytecodes::_fast_aputfield: __ movptr(lo_value, rax); break; |
2680 | |
0 | 2681 default: ShouldNotReachHere(); |
2682 } | |
2683 __ pop_ptr(rbx); // restore copy of object pointer | |
2684 | |
2685 // Save rax, and sometimes rdx because call_VM() will clobber them, | |
2686 // then use them for JVM/DI purposes | |
304 | 2687 __ push(rax); |
2688 if (bytecode() == Bytecodes::_fast_lputfield) __ push(rdx); | |
0 | 2689 // access constant pool cache entry |
2690 __ get_cache_entry_pointer_at_bcp(rax, rdx, 1); | |
2691 __ verify_oop(rbx); | |
2692 // rbx,: object pointer copied above | |
2693 // rax,: cache entry pointer | |
2694 // rcx: jvalue object on the stack | |
2695 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, rax, rcx); | |
304 | 2696 if (bytecode() == Bytecodes::_fast_lputfield) __ pop(rdx); // restore high value |
2697 __ pop(rax); // restore lower value | |
2698 __ addptr(rsp, sizeof(jvalue)); // release jvalue object space | |
0 | 2699 __ bind(L2); |
2700 } | |
2701 } | |
2702 | |
2703 void TemplateTable::fast_storefield(TosState state) { | |
2704 transition(state, vtos); | |
2705 | |
2706 ByteSize base = constantPoolCacheOopDesc::base_offset(); | |
2707 | |
2708 jvmti_post_fast_field_mod(); | |
2709 | |
2710 // access constant pool cache | |
2711 __ get_cache_and_index_at_bcp(rcx, rbx, 1); | |
2712 | |
2713 // test for volatile with rdx but rdx is tos register for lputfield. | |
304 | 2714 if (bytecode() == Bytecodes::_fast_lputfield) __ push(rdx); |
2715 __ movl(rdx, Address(rcx, rbx, Address::times_ptr, in_bytes(base + | |
0 | 2716 ConstantPoolCacheEntry::flags_offset()))); |
2717 | |
2718 // replace index with field offset from cache entry | |
304 | 2719 __ movptr(rbx, Address(rcx, rbx, Address::times_ptr, in_bytes(base + ConstantPoolCacheEntry::f2_offset()))); |
0 | 2720 |
2721 // Doug Lea believes this is not needed with current Sparcs (TSO) and Intel (PSO). | |
2722 // volatile_barrier( ); | |
2723 | |
2724 Label notVolatile, Done; | |
2725 __ shrl(rdx, ConstantPoolCacheEntry::volatileField); | |
2726 __ andl(rdx, 0x1); | |
2727 // Check for volatile store | |
2728 __ testl(rdx, rdx); | |
2729 __ jcc(Assembler::zero, notVolatile); | |
2730 | |
304 | 2731 if (bytecode() == Bytecodes::_fast_lputfield) __ pop(rdx); |
0 | 2732 |
2733 // Get object from stack | |
2734 pop_and_check_object(rcx); | |
2735 | |
2736 // field addresses | |
2737 const Address lo(rcx, rbx, Address::times_1, 0*wordSize); | |
2738 const Address hi(rcx, rbx, Address::times_1, 1*wordSize); | |
2739 | |
2740 // access field | |
2741 switch (bytecode()) { | |
2742 case Bytecodes::_fast_bputfield: __ movb(lo, rax); break; | |
2743 case Bytecodes::_fast_sputfield: // fall through | |
2744 case Bytecodes::_fast_cputfield: __ movw(lo, rax); break; | |
2745 case Bytecodes::_fast_iputfield: __ movl(lo, rax); break; | |
304 | 2746 case Bytecodes::_fast_lputfield: |
2747 NOT_LP64(__ movptr(hi, rdx)); | |
2748 __ movptr(lo, rax); | |
2749 break; | |
0 | 2750 case Bytecodes::_fast_fputfield: __ fstp_s(lo); break; |
2751 case Bytecodes::_fast_dputfield: __ fstp_d(lo); break; | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2752 case Bytecodes::_fast_aputfield: { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2753 do_oop_store(_masm, lo, rax, _bs->kind(), false); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2754 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2755 } |
0 | 2756 default: |
2757 ShouldNotReachHere(); | |
2758 } | |
2759 | |
2760 Label done; | |
304 | 2761 volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad | |
2762 Assembler::StoreStore)); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2763 // Barriers are so large that short branch doesn't reach! |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2764 __ jmp(done); |
0 | 2765 |
2766 // Same code as above, but don't need rdx to test for volatile. | |
2767 __ bind(notVolatile); | |
2768 | |
304 | 2769 if (bytecode() == Bytecodes::_fast_lputfield) __ pop(rdx); |
0 | 2770 |
2771 // Get object from stack | |
2772 pop_and_check_object(rcx); | |
2773 | |
2774 // access field | |
2775 switch (bytecode()) { | |
2776 case Bytecodes::_fast_bputfield: __ movb(lo, rax); break; | |
2777 case Bytecodes::_fast_sputfield: // fall through | |
2778 case Bytecodes::_fast_cputfield: __ movw(lo, rax); break; | |
2779 case Bytecodes::_fast_iputfield: __ movl(lo, rax); break; | |
304 | 2780 case Bytecodes::_fast_lputfield: |
2781 NOT_LP64(__ movptr(hi, rdx)); | |
2782 __ movptr(lo, rax); | |
2783 break; | |
0 | 2784 case Bytecodes::_fast_fputfield: __ fstp_s(lo); break; |
2785 case Bytecodes::_fast_dputfield: __ fstp_d(lo); break; | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2786 case Bytecodes::_fast_aputfield: { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2787 do_oop_store(_masm, lo, rax, _bs->kind(), false); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2788 break; |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
2789 } |
0 | 2790 default: |
2791 ShouldNotReachHere(); | |
2792 } | |
2793 __ bind(done); | |
2794 } | |
2795 | |
2796 | |
2797 void TemplateTable::fast_accessfield(TosState state) { | |
2798 transition(atos, state); | |
2799 | |
2800 // do the JVMTI work here to avoid disturbing the register state below | |
2801 if (JvmtiExport::can_post_field_access()) { | |
2802 // Check to see if a field access watch has been set before we take | |
2803 // the time to call into the VM. | |
2804 Label L1; | |
2805 __ mov32(rcx, ExternalAddress((address) JvmtiExport::get_field_access_count_addr())); | |
2806 __ testl(rcx,rcx); | |
2807 __ jcc(Assembler::zero, L1); | |
2808 // access constant pool cache entry | |
2809 __ get_cache_entry_pointer_at_bcp(rcx, rdx, 1); | |
2810 __ push_ptr(rax); // save object pointer before call_VM() clobbers it | |
2811 __ verify_oop(rax); | |
2812 // rax,: object pointer copied above | |
2813 // rcx: cache entry pointer | |
2814 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), rax, rcx); | |
2815 __ pop_ptr(rax); // restore object pointer | |
2816 __ bind(L1); | |
2817 } | |
2818 | |
2819 // access constant pool cache | |
2820 __ get_cache_and_index_at_bcp(rcx, rbx, 1); | |
2821 // replace index with field offset from cache entry | |
304 | 2822 __ movptr(rbx, Address(rcx, |
2823 rbx, | |
2824 Address::times_ptr, | |
2825 in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f2_offset()))); | |
0 | 2826 |
2827 | |
2828 // rax,: object | |
2829 __ verify_oop(rax); | |
2830 __ null_check(rax); | |
2831 // field addresses | |
2832 const Address lo = Address(rax, rbx, Address::times_1, 0*wordSize); | |
2833 const Address hi = Address(rax, rbx, Address::times_1, 1*wordSize); | |
2834 | |
2835 // access field | |
2836 switch (bytecode()) { | |
304 | 2837 case Bytecodes::_fast_bgetfield: __ movsbl(rax, lo ); break; |
622
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
2838 case Bytecodes::_fast_sgetfield: __ load_signed_short(rax, lo ); break; |
56aae7be60d4
6812678: macro assembler needs delayed binding of a few constants (for 6655638)
jrose
parents:
605
diff
changeset
|
2839 case Bytecodes::_fast_cgetfield: __ load_unsigned_short(rax, lo ); break; |
0 | 2840 case Bytecodes::_fast_igetfield: __ movl(rax, lo); break; |
2841 case Bytecodes::_fast_lgetfield: __ stop("should not be rewritten"); break; | |
2842 case Bytecodes::_fast_fgetfield: __ fld_s(lo); break; | |
2843 case Bytecodes::_fast_dgetfield: __ fld_d(lo); break; | |
304 | 2844 case Bytecodes::_fast_agetfield: __ movptr(rax, lo); __ verify_oop(rax); break; |
0 | 2845 default: |
2846 ShouldNotReachHere(); | |
2847 } | |
2848 | |
2849 // Doug Lea believes this is not needed with current Sparcs(TSO) and Intel(PSO) | |
2850 // volatile_barrier( ); | |
2851 } | |
2852 | |
2853 void TemplateTable::fast_xaccess(TosState state) { | |
2854 transition(vtos, state); | |
2855 // get receiver | |
304 | 2856 __ movptr(rax, aaddress(0)); |
0 | 2857 // access constant pool cache |
2858 __ get_cache_and_index_at_bcp(rcx, rdx, 2); | |
304 | 2859 __ movptr(rbx, Address(rcx, |
2860 rdx, | |
2861 Address::times_ptr, | |
2862 in_bytes(constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f2_offset()))); | |
0 | 2863 // make sure exception is reported in correct bcp range (getfield is next instruction) |
2864 __ increment(rsi); | |
2865 __ null_check(rax); | |
2866 const Address lo = Address(rax, rbx, Address::times_1, 0*wordSize); | |
2867 if (state == itos) { | |
2868 __ movl(rax, lo); | |
2869 } else if (state == atos) { | |
304 | 2870 __ movptr(rax, lo); |
0 | 2871 __ verify_oop(rax); |
2872 } else if (state == ftos) { | |
2873 __ fld_s(lo); | |
2874 } else { | |
2875 ShouldNotReachHere(); | |
2876 } | |
2877 __ decrement(rsi); | |
2878 } | |
2879 | |
2880 | |
2881 | |
2882 //---------------------------------------------------------------------------------------------------- | |
2883 // Calls | |
2884 | |
2885 void TemplateTable::count_calls(Register method, Register temp) { | |
2886 // implemented elsewhere | |
2887 ShouldNotReachHere(); | |
2888 } | |
2889 | |
2890 | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2891 void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) { |
0 | 2892 // determine flags |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2893 Bytecodes::Code code = bytecode(); |
0 | 2894 const bool is_invokeinterface = code == Bytecodes::_invokeinterface; |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2895 const bool is_invokedynamic = code == Bytecodes::_invokedynamic; |
0 | 2896 const bool is_invokevirtual = code == Bytecodes::_invokevirtual; |
2897 const bool is_invokespecial = code == Bytecodes::_invokespecial; | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2898 const bool load_receiver = (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic); |
0 | 2899 const bool receiver_null_check = is_invokespecial; |
2900 const bool save_flags = is_invokeinterface || is_invokevirtual; | |
2901 // setup registers & access constant pool cache | |
2902 const Register recv = rcx; | |
2903 const Register flags = rdx; | |
2904 assert_different_registers(method, index, recv, flags); | |
2905 | |
2906 // save 'interpreter return address' | |
2907 __ save_bcp(); | |
2908 | |
1565 | 2909 load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic); |
0 | 2910 |
2911 // load receiver if needed (note: no return address pushed yet) | |
2912 if (load_receiver) { | |
1565 | 2913 assert(!is_invokedynamic, ""); |
0 | 2914 __ movl(recv, flags); |
2915 __ andl(recv, 0xFF); | |
2916 // recv count is 0 based? | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2917 Address recv_addr(rsp, recv, Interpreter::stackElementScale(), -Interpreter::expr_offset_in_bytes(1)); |
1304 | 2918 __ movptr(recv, recv_addr); |
2919 __ verify_oop(recv); | |
0 | 2920 } |
2921 | |
2922 // do null check if needed | |
2923 if (receiver_null_check) { | |
2924 __ null_check(recv); | |
2925 } | |
2926 | |
2927 if (save_flags) { | |
304 | 2928 __ mov(rsi, flags); |
0 | 2929 } |
2930 | |
2931 // compute return type | |
2932 __ shrl(flags, ConstantPoolCacheEntry::tosBits); | |
2933 // Make sure we don't need to mask flags for tosBits after the above shift | |
2934 ConstantPoolCacheEntry::verify_tosBits(); | |
2935 // load return address | |
304 | 2936 { |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2937 address table_addr; |
1059
389049f3f393
6858164: invokedynamic code needs some cleanup (post-6655638)
jrose
parents:
726
diff
changeset
|
2938 if (is_invokeinterface || is_invokedynamic) |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2939 table_addr = (address)Interpreter::return_5_addrs_by_index_table(); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2940 else |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2941 table_addr = (address)Interpreter::return_3_addrs_by_index_table(); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
2942 ExternalAddress table(table_addr); |
304 | 2943 __ movptr(flags, ArrayAddress(table, Address(noreg, flags, Address::times_ptr))); |
0 | 2944 } |
2945 | |
2946 // push return address | |
304 | 2947 __ push(flags); |
0 | 2948 |
2949 // Restore flag value from the constant pool cache, and restore rsi | |
2950 // for later null checks. rsi is the bytecode pointer | |
2951 if (save_flags) { | |
304 | 2952 __ mov(flags, rsi); |
0 | 2953 __ restore_bcp(); |
2954 } | |
2955 } | |
2956 | |
2957 | |
2958 void TemplateTable::invokevirtual_helper(Register index, Register recv, | |
2959 Register flags) { | |
2960 | |
2961 // Uses temporary registers rax, rdx | |
2962 assert_different_registers(index, recv, rax, rdx); | |
2963 | |
2964 // Test for an invoke of a final method | |
2965 Label notFinal; | |
2966 __ movl(rax, flags); | |
2967 __ andl(rax, (1 << ConstantPoolCacheEntry::vfinalMethod)); | |
2968 __ jcc(Assembler::zero, notFinal); | |
2969 | |
2970 Register method = index; // method must be rbx, | |
2971 assert(method == rbx, "methodOop must be rbx, for interpreter calling convention"); | |
2972 | |
2973 // do the call - the index is actually the method to call | |
2974 __ verify_oop(method); | |
2975 | |
2976 // It's final, need a null check here! | |
2977 __ null_check(recv); | |
2978 | |
2979 // profile this call | |
2980 __ profile_final_call(rax); | |
2981 | |
2982 __ jump_from_interpreted(method, rax); | |
2983 | |
2984 __ bind(notFinal); | |
2985 | |
2986 // get receiver klass | |
2987 __ null_check(recv, oopDesc::klass_offset_in_bytes()); | |
2988 // Keep recv in rcx for callee expects it there | |
304 | 2989 __ movptr(rax, Address(recv, oopDesc::klass_offset_in_bytes())); |
0 | 2990 __ verify_oop(rax); |
2991 | |
2992 // profile this call | |
2993 __ profile_virtual_call(rax, rdi, rdx); | |
2994 | |
2995 // get target methodOop & entry point | |
2996 const int base = instanceKlass::vtable_start_offset() * wordSize; | |
2997 assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below"); | |
304 | 2998 __ movptr(method, Address(rax, index, Address::times_ptr, base + vtableEntry::method_offset_in_bytes())); |
0 | 2999 __ jump_from_interpreted(method, rdx); |
3000 } | |
3001 | |
3002 | |
3003 void TemplateTable::invokevirtual(int byte_no) { | |
3004 transition(vtos, vtos); | |
1565 | 3005 assert(byte_no == f2_byte, "use this argument"); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3006 prepare_invoke(rbx, noreg, byte_no); |
0 | 3007 |
3008 // rbx,: index | |
3009 // rcx: receiver | |
3010 // rdx: flags | |
3011 | |
3012 invokevirtual_helper(rbx, rcx, rdx); | |
3013 } | |
3014 | |
3015 | |
3016 void TemplateTable::invokespecial(int byte_no) { | |
3017 transition(vtos, vtos); | |
1565 | 3018 assert(byte_no == f1_byte, "use this argument"); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3019 prepare_invoke(rbx, noreg, byte_no); |
0 | 3020 // do the call |
3021 __ verify_oop(rbx); | |
3022 __ profile_call(rax); | |
3023 __ jump_from_interpreted(rbx, rax); | |
3024 } | |
3025 | |
3026 | |
3027 void TemplateTable::invokestatic(int byte_no) { | |
3028 transition(vtos, vtos); | |
1565 | 3029 assert(byte_no == f1_byte, "use this argument"); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3030 prepare_invoke(rbx, noreg, byte_no); |
0 | 3031 // do the call |
3032 __ verify_oop(rbx); | |
3033 __ profile_call(rax); | |
3034 __ jump_from_interpreted(rbx, rax); | |
3035 } | |
3036 | |
3037 | |
3038 void TemplateTable::fast_invokevfinal(int byte_no) { | |
3039 transition(vtos, vtos); | |
1565 | 3040 assert(byte_no == f2_byte, "use this argument"); |
0 | 3041 __ stop("fast_invokevfinal not used on x86"); |
3042 } | |
3043 | |
3044 | |
3045 void TemplateTable::invokeinterface(int byte_no) { | |
3046 transition(vtos, vtos); | |
1565 | 3047 assert(byte_no == f1_byte, "use this argument"); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3048 prepare_invoke(rax, rbx, byte_no); |
0 | 3049 |
3050 // rax,: Interface | |
3051 // rbx,: index | |
3052 // rcx: receiver | |
3053 // rdx: flags | |
3054 | |
3055 // Special case of invokeinterface called for virtual method of | |
3056 // java.lang.Object. See cpCacheOop.cpp for details. | |
3057 // This code isn't produced by javac, but could be produced by | |
3058 // another compliant java compiler. | |
3059 Label notMethod; | |
3060 __ movl(rdi, rdx); | |
3061 __ andl(rdi, (1 << ConstantPoolCacheEntry::methodInterface)); | |
3062 __ jcc(Assembler::zero, notMethod); | |
3063 | |
3064 invokevirtual_helper(rbx, rcx, rdx); | |
3065 __ bind(notMethod); | |
3066 | |
3067 // Get receiver klass into rdx - also a null check | |
3068 __ restore_locals(); // restore rdi | |
304 | 3069 __ movptr(rdx, Address(rcx, oopDesc::klass_offset_in_bytes())); |
0 | 3070 __ verify_oop(rdx); |
3071 | |
3072 // profile this call | |
3073 __ profile_virtual_call(rdx, rsi, rdi); | |
3074 | |
623
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3075 Label no_such_interface, no_such_method; |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3076 |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3077 __ lookup_interface_method(// inputs: rec. class, interface, itable index |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3078 rdx, rax, rbx, |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3079 // outputs: method, scan temp. reg |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3080 rbx, rsi, |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3081 no_such_interface); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3082 |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3083 // rbx,: methodOop to call |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3084 // rcx: receiver |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3085 // Check for abstract method error |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3086 // Note: This should be done more efficiently via a throw_abstract_method_error |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3087 // interpreter entry point and a conditional jump to it in case of a null |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3088 // method. |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3089 __ testptr(rbx, rbx); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3090 __ jcc(Assembler::zero, no_such_method); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3091 |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3092 // do the call |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3093 // rcx: receiver |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3094 // rbx,: methodOop |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3095 __ jump_from_interpreted(rbx, rdx); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3096 __ should_not_reach_here(); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3097 |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3098 // exception handling code follows... |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3099 // note: must restore interpreter registers to canonical |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3100 // state for exception handling to work correctly! |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3101 |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3102 __ bind(no_such_method); |
0 | 3103 // throw exception |
623
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3104 __ pop(rbx); // pop return address (pushed by prepare_invoke) |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3105 __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3106 __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3107 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError)); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3108 // the call_VM checks for exception, so we should never return here. |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3109 __ should_not_reach_here(); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3110 |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3111 __ bind(no_such_interface); |
9adddb8c0fc8
6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638)
jrose
parents:
622
diff
changeset
|
3112 // throw exception |
304 | 3113 __ pop(rbx); // pop return address (pushed by prepare_invoke) |
0 | 3114 __ restore_bcp(); // rsi must be correct for exception handler (was destroyed) |
3115 __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) | |
3116 __ call_VM(noreg, CAST_FROM_FN_PTR(address, | |
3117 InterpreterRuntime::throw_IncompatibleClassChangeError)); | |
3118 // the call_VM checks for exception, so we should never return here. | |
3119 __ should_not_reach_here(); | |
3120 } | |
3121 | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3122 void TemplateTable::invokedynamic(int byte_no) { |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3123 transition(vtos, vtos); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3124 |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3125 if (!EnableInvokeDynamic) { |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3126 // We should not encounter this bytecode if !EnableInvokeDynamic. |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3127 // The verifier will stop it. However, if we get past the verifier, |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3128 // this will stop the thread in a reasonable way, without crashing the JVM. |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3129 __ call_VM(noreg, CAST_FROM_FN_PTR(address, |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3130 InterpreterRuntime::throw_IncompatibleClassChangeError)); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3131 // the call_VM checks for exception, so we should never return here. |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3132 __ should_not_reach_here(); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3133 return; |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3134 } |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3135 |
1565 | 3136 assert(byte_no == f1_oop, "use this argument"); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3137 prepare_invoke(rax, rbx, byte_no); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3138 |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3139 // rax: CallSite object (f1) |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3140 // rbx: unused (f2) |
1846 | 3141 // rcx: receiver address |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3142 // rdx: flags (unused) |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3143 |
1846 | 3144 Register rax_callsite = rax; |
3145 Register rcx_method_handle = rcx; | |
3146 | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3147 if (ProfileInterpreter) { |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3148 // %%% should make a type profile for any invokedynamic that takes a ref argument |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3149 // profile this call |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3150 __ profile_call(rsi); |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3151 } |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3152 |
1846 | 3153 __ movptr(rcx_method_handle, Address(rax_callsite, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, rcx))); |
3154 __ null_check(rcx_method_handle); | |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3155 __ prepare_to_jump_from_interpreted(); |
1846 | 3156 __ jump_to_method_handle_entry(rcx_method_handle, rdx); |
726
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3157 } |
be93aad57795
6655646: dynamic languages need dynamically linked call sites
jrose
parents:
628
diff
changeset
|
3158 |
0 | 3159 //---------------------------------------------------------------------------------------------------- |
3160 // Allocation | |
3161 | |
3162 void TemplateTable::_new() { | |
3163 transition(vtos, atos); | |
3164 __ get_unsigned_2_byte_index_at_bcp(rdx, 1); | |
3165 Label slow_case; | |
1681
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3166 Label slow_case_no_pop; |
0 | 3167 Label done; |
3168 Label initialize_header; | |
3169 Label initialize_object; // including clearing the fields | |
3170 Label allocate_shared; | |
3171 | |
3172 __ get_cpool_and_tags(rcx, rax); | |
1681
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3173 |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3174 // Make sure the class we're about to instantiate has been resolved. |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3175 // 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
|
3176 // how Constant Pool is updated (see constantPoolOopDesc::klass_at_put) |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3177 const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3178 __ cmpb(Address(rax, rdx, Address::times_1, tags_offset), JVM_CONSTANT_Class); |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3179 __ jcc(Assembler::notEqual, slow_case_no_pop); |
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3180 |
0 | 3181 // get instanceKlass |
304 | 3182 __ movptr(rcx, Address(rcx, rdx, Address::times_ptr, sizeof(constantPoolOopDesc))); |
3183 __ push(rcx); // save the contexts of klass for initializing the header | |
0 | 3184 |
3185 // make sure klass is initialized & doesn't have finalizer | |
3186 // make sure klass is fully initialized | |
3187 __ cmpl(Address(rcx, instanceKlass::init_state_offset_in_bytes() + sizeof(oopDesc)), instanceKlass::fully_initialized); | |
3188 __ jcc(Assembler::notEqual, slow_case); | |
3189 | |
3190 // get instance_size in instanceKlass (scaled to a count of bytes) | |
3191 __ movl(rdx, Address(rcx, Klass::layout_helper_offset_in_bytes() + sizeof(oopDesc))); | |
3192 // test to see if it has a finalizer or is malformed in some way | |
3193 __ testl(rdx, Klass::_lh_instance_slow_path_bit); | |
3194 __ jcc(Assembler::notZero, slow_case); | |
3195 | |
3196 // | |
3197 // Allocate the instance | |
3198 // 1) Try to allocate in the TLAB | |
3199 // 2) if fail and the object is large allocate in the shared Eden | |
3200 // 3) if the above fails (or is not applicable), go to a slow case | |
3201 // (creates a new TLAB, etc.) | |
3202 | |
3203 const bool allow_shared_alloc = | |
3204 Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; | |
3205 | |
3206 if (UseTLAB) { | |
3207 const Register thread = rcx; | |
3208 | |
3209 __ get_thread(thread); | |
304 | 3210 __ movptr(rax, Address(thread, in_bytes(JavaThread::tlab_top_offset()))); |
3211 __ lea(rbx, Address(rax, rdx, Address::times_1)); | |
3212 __ cmpptr(rbx, Address(thread, in_bytes(JavaThread::tlab_end_offset()))); | |
0 | 3213 __ jcc(Assembler::above, allow_shared_alloc ? allocate_shared : slow_case); |
304 | 3214 __ movptr(Address(thread, in_bytes(JavaThread::tlab_top_offset())), rbx); |
0 | 3215 if (ZeroTLAB) { |
3216 // the fields have been already cleared | |
3217 __ jmp(initialize_header); | |
3218 } else { | |
3219 // initialize both the header and fields | |
3220 __ jmp(initialize_object); | |
3221 } | |
3222 } | |
3223 | |
3224 // Allocation in the shared Eden, if allowed. | |
3225 // | |
3226 // rdx: instance size in bytes | |
3227 if (allow_shared_alloc) { | |
3228 __ bind(allocate_shared); | |
3229 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
3230 ExternalAddress heap_top((address)Universe::heap()->top_addr()); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
107
diff
changeset
|
3231 |
0 | 3232 Label retry; |
3233 __ bind(retry); | |
304 | 3234 __ movptr(rax, heap_top); |
3235 __ lea(rbx, Address(rax, rdx, Address::times_1)); | |
3236 __ cmpptr(rbx, ExternalAddress((address)Universe::heap()->end_addr())); | |
0 | 3237 __ jcc(Assembler::above, slow_case); |
3238 | |
3239 // Compare rax, with the top addr, and if still equal, store the new | |
3240 // top addr in rbx, at the address of the top addr pointer. Sets ZF if was | |
3241 // equal, and clears it otherwise. Use lock prefix for atomicity on MPs. | |
3242 // | |
3243 // rax,: object begin | |
3244 // rbx,: object end | |
3245 // rdx: instance size in bytes | |
304 | 3246 __ locked_cmpxchgptr(rbx, heap_top); |
0 | 3247 |
3248 // if someone beat us on the allocation, try again, otherwise continue | |
3249 __ jcc(Assembler::notEqual, retry); | |
3250 } | |
3251 | |
3252 if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) { | |
3253 // The object is initialized before the header. If the object size is | |
3254 // zero, go directly to the header initialization. | |
3255 __ bind(initialize_object); | |
3256 __ decrement(rdx, sizeof(oopDesc)); | |
3257 __ jcc(Assembler::zero, initialize_header); | |
3258 | |
3259 // Initialize topmost object field, divide rdx by 8, check if odd and | |
3260 // test if zero. | |
3261 __ xorl(rcx, rcx); // use zero reg to clear memory (shorter code) | |
3262 __ shrl(rdx, LogBytesPerLong); // divide by 2*oopSize and set carry flag if odd | |
3263 | |
3264 // rdx must have been multiple of 8 | |
3265 #ifdef ASSERT | |
3266 // make sure rdx was multiple of 8 | |
3267 Label L; | |
3268 // Ignore partial flag stall after shrl() since it is debug VM | |
3269 __ jccb(Assembler::carryClear, L); | |
3270 __ stop("object size is not multiple of 2 - adjust this code"); | |
3271 __ bind(L); | |
3272 // rdx must be > 0, no extra check needed here | |
3273 #endif | |
3274 | |
3275 // initialize remaining object fields: rdx was a multiple of 8 | |
3276 { Label loop; | |
3277 __ bind(loop); | |
304 | 3278 __ movptr(Address(rax, rdx, Address::times_8, sizeof(oopDesc) - 1*oopSize), rcx); |
3279 NOT_LP64(__ movptr(Address(rax, rdx, Address::times_8, sizeof(oopDesc) - 2*oopSize), rcx)); | |
0 | 3280 __ decrement(rdx); |
3281 __ jcc(Assembler::notZero, loop); | |
3282 } | |
3283 | |
3284 // initialize object header only. | |
3285 __ bind(initialize_header); | |
3286 if (UseBiasedLocking) { | |
304 | 3287 __ pop(rcx); // get saved klass back in the register. |
3288 __ movptr(rbx, Address(rcx, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes())); | |
3289 __ movptr(Address(rax, oopDesc::mark_offset_in_bytes ()), rbx); | |
0 | 3290 } else { |
304 | 3291 __ movptr(Address(rax, oopDesc::mark_offset_in_bytes ()), |
3292 (int32_t)markOopDesc::prototype()); // header | |
3293 __ pop(rcx); // get saved klass back in the register. | |
0 | 3294 } |
304 | 3295 __ movptr(Address(rax, oopDesc::klass_offset_in_bytes()), rcx); // klass |
0 | 3296 |
3297 { | |
3298 SkipIfEqual skip_if(_masm, &DTraceAllocProbes, 0); | |
3299 // Trigger dtrace event for fastpath | |
3300 __ push(atos); | |
3301 __ call_VM_leaf( | |
3302 CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax); | |
3303 __ pop(atos); | |
3304 } | |
3305 | |
3306 __ jmp(done); | |
3307 } | |
3308 | |
3309 // slow case | |
3310 __ bind(slow_case); | |
304 | 3311 __ pop(rcx); // restore stack pointer to what it was when we came in. |
1681
126ea7725993
6953477: Increase portability and flexibility of building Hotspot
bobv
parents:
1602
diff
changeset
|
3312 __ bind(slow_case_no_pop); |
0 | 3313 __ get_constant_pool(rax); |
3314 __ get_unsigned_2_byte_index_at_bcp(rdx, 1); | |
3315 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), rax, rdx); | |
3316 | |
3317 // continue | |
3318 __ bind(done); | |
3319 } | |
3320 | |
3321 | |
3322 void TemplateTable::newarray() { | |
3323 transition(itos, atos); | |
3324 __ push_i(rax); // make sure everything is on the stack | |
3325 __ load_unsigned_byte(rdx, at_bcp(1)); | |
3326 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), rdx, rax); | |
3327 __ pop_i(rdx); // discard size | |
3328 } | |
3329 | |
3330 | |
3331 void TemplateTable::anewarray() { | |
3332 transition(itos, atos); | |
3333 __ get_unsigned_2_byte_index_at_bcp(rdx, 1); | |
3334 __ get_constant_pool(rcx); | |
3335 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), rcx, rdx, rax); | |
3336 } | |
3337 | |
3338 | |
3339 void TemplateTable::arraylength() { | |
3340 transition(atos, itos); | |
3341 __ null_check(rax, arrayOopDesc::length_offset_in_bytes()); | |
3342 __ movl(rax, Address(rax, arrayOopDesc::length_offset_in_bytes())); | |
3343 } | |
3344 | |
3345 | |
3346 void TemplateTable::checkcast() { | |
3347 transition(atos, atos); | |
3348 Label done, is_null, ok_is_subtype, quicked, resolved; | |
304 | 3349 __ testptr(rax, rax); // Object is in EAX |
0 | 3350 __ jcc(Assembler::zero, is_null); |
3351 | |
3352 // Get cpool & tags index | |
3353 __ get_cpool_and_tags(rcx, rdx); // ECX=cpool, EDX=tags array | |
3354 __ get_unsigned_2_byte_index_at_bcp(rbx, 1); // EBX=index | |
3355 // See if bytecode has already been quicked | |
3356 __ cmpb(Address(rdx, rbx, Address::times_1, typeArrayOopDesc::header_size(T_BYTE) * wordSize), JVM_CONSTANT_Class); | |
3357 __ jcc(Assembler::equal, quicked); | |
3358 | |
3359 __ push(atos); | |
3360 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) ); | |
3361 __ pop_ptr(rdx); | |
3362 __ jmpb(resolved); | |
3363 | |
3364 // Get superklass in EAX and subklass in EBX | |
3365 __ bind(quicked); | |
304 | 3366 __ mov(rdx, rax); // Save object in EDX; EAX needed for subtype check |
3367 __ movptr(rax, Address(rcx, rbx, Address::times_ptr, sizeof(constantPoolOopDesc))); | |
0 | 3368 |
3369 __ bind(resolved); | |
304 | 3370 __ movptr(rbx, Address(rdx, oopDesc::klass_offset_in_bytes())); |
0 | 3371 |
3372 // Generate subtype check. Blows ECX. Resets EDI. Object in EDX. | |
3373 // Superklass in EAX. Subklass in EBX. | |
3374 __ gen_subtype_check( rbx, ok_is_subtype ); | |
3375 | |
3376 // Come here on failure | |
304 | 3377 __ push(rdx); |
0 | 3378 // object is at TOS |
3379 __ jump(ExternalAddress(Interpreter::_throw_ClassCastException_entry)); | |
3380 | |
3381 // Come here on success | |
3382 __ bind(ok_is_subtype); | |
304 | 3383 __ mov(rax,rdx); // Restore object in EDX |
0 | 3384 |
3385 // Collect counts on whether this check-cast sees NULLs a lot or not. | |
3386 if (ProfileInterpreter) { | |
3387 __ jmp(done); | |
3388 __ bind(is_null); | |
3389 __ profile_null_seen(rcx); | |
3390 } else { | |
3391 __ bind(is_null); // same as 'done' | |
3392 } | |
3393 __ bind(done); | |
3394 } | |
3395 | |
3396 | |
3397 void TemplateTable::instanceof() { | |
3398 transition(atos, itos); | |
3399 Label done, is_null, ok_is_subtype, quicked, resolved; | |
304 | 3400 __ testptr(rax, rax); |
0 | 3401 __ jcc(Assembler::zero, is_null); |
3402 | |
3403 // Get cpool & tags index | |
3404 __ get_cpool_and_tags(rcx, rdx); // ECX=cpool, EDX=tags array | |
3405 __ get_unsigned_2_byte_index_at_bcp(rbx, 1); // EBX=index | |
3406 // See if bytecode has already been quicked | |
3407 __ cmpb(Address(rdx, rbx, Address::times_1, typeArrayOopDesc::header_size(T_BYTE) * wordSize), JVM_CONSTANT_Class); | |
3408 __ jcc(Assembler::equal, quicked); | |
3409 | |
3410 __ push(atos); | |
3411 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) ); | |
3412 __ pop_ptr(rdx); | |
304 | 3413 __ movptr(rdx, Address(rdx, oopDesc::klass_offset_in_bytes())); |
0 | 3414 __ jmp(resolved); |
3415 | |
3416 // Get superklass in EAX and subklass in EDX | |
3417 __ bind(quicked); | |
304 | 3418 __ movptr(rdx, Address(rax, oopDesc::klass_offset_in_bytes())); |
3419 __ movptr(rax, Address(rcx, rbx, Address::times_ptr, sizeof(constantPoolOopDesc))); | |
0 | 3420 |
3421 __ bind(resolved); | |
3422 | |
3423 // Generate subtype check. Blows ECX. Resets EDI. | |
3424 // Superklass in EAX. Subklass in EDX. | |
3425 __ gen_subtype_check( rdx, ok_is_subtype ); | |
3426 | |
3427 // Come here on failure | |
3428 __ xorl(rax,rax); | |
3429 __ jmpb(done); | |
3430 // Come here on success | |
3431 __ bind(ok_is_subtype); | |
3432 __ movl(rax, 1); | |
3433 | |
3434 // Collect counts on whether this test sees NULLs a lot or not. | |
3435 if (ProfileInterpreter) { | |
3436 __ jmp(done); | |
3437 __ bind(is_null); | |
3438 __ profile_null_seen(rcx); | |
3439 } else { | |
3440 __ bind(is_null); // same as 'done' | |
3441 } | |
3442 __ bind(done); | |
3443 // rax, = 0: obj == NULL or obj is not an instanceof the specified klass | |
3444 // rax, = 1: obj != NULL and obj is an instanceof the specified klass | |
3445 } | |
3446 | |
3447 | |
3448 //---------------------------------------------------------------------------------------------------- | |
3449 // Breakpoints | |
3450 void TemplateTable::_breakpoint() { | |
3451 | |
3452 // Note: We get here even if we are single stepping.. | |
3453 // jbug inists on setting breakpoints at every bytecode | |
3454 // even if we are in single step mode. | |
3455 | |
3456 transition(vtos, vtos); | |
3457 | |
3458 // get the unpatched byte code | |
3459 __ get_method(rcx); | |
3460 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), rcx, rsi); | |
304 | 3461 __ mov(rbx, rax); |
0 | 3462 |
3463 // post the breakpoint event | |
3464 __ get_method(rcx); | |
3465 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), rcx, rsi); | |
3466 | |
3467 // complete the execution of original bytecode | |
3468 __ dispatch_only_normal(vtos); | |
3469 } | |
3470 | |
3471 | |
3472 //---------------------------------------------------------------------------------------------------- | |
3473 // Exceptions | |
3474 | |
3475 void TemplateTable::athrow() { | |
3476 transition(atos, vtos); | |
3477 __ null_check(rax); | |
3478 __ jump(ExternalAddress(Interpreter::throw_exception_entry())); | |
3479 } | |
3480 | |
3481 | |
3482 //---------------------------------------------------------------------------------------------------- | |
3483 // Synchronization | |
3484 // | |
3485 // Note: monitorenter & exit are symmetric routines; which is reflected | |
3486 // in the assembly code structure as well | |
3487 // | |
3488 // Stack layout: | |
3489 // | |
3490 // [expressions ] <--- rsp = expression stack top | |
3491 // .. | |
3492 // [expressions ] | |
3493 // [monitor entry] <--- monitor block top = expression stack bot | |
3494 // .. | |
3495 // [monitor entry] | |
3496 // [frame data ] <--- monitor block bot | |
3497 // ... | |
3498 // [saved rbp, ] <--- rbp, | |
3499 | |
3500 | |
3501 void TemplateTable::monitorenter() { | |
3502 transition(atos, vtos); | |
3503 | |
3504 // check for NULL object | |
3505 __ null_check(rax); | |
3506 | |
3507 const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); | |
3508 const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize); | |
3509 const int entry_size = ( frame::interpreter_frame_monitor_size() * wordSize); | |
3510 Label allocated; | |
3511 | |
3512 // initialize entry pointer | |
3513 __ xorl(rdx, rdx); // points to free slot or NULL | |
3514 | |
3515 // find a free slot in the monitor block (result in rdx) | |
3516 { Label entry, loop, exit; | |
304 | 3517 __ movptr(rcx, monitor_block_top); // points to current entry, starting with top-most entry |
3518 __ lea(rbx, monitor_block_bot); // points to word before bottom of monitor block | |
0 | 3519 __ jmpb(entry); |
3520 | |
3521 __ bind(loop); | |
304 | 3522 __ cmpptr(Address(rcx, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); // check if current entry is used |
0 | 3523 |
3524 // TODO - need new func here - kbt | |
3525 if (VM_Version::supports_cmov()) { | |
304 | 3526 __ cmov(Assembler::equal, rdx, rcx); // if not used then remember entry in rdx |
0 | 3527 } else { |
3528 Label L; | |
3529 __ jccb(Assembler::notEqual, L); | |
304 | 3530 __ mov(rdx, rcx); // if not used then remember entry in rdx |
0 | 3531 __ bind(L); |
3532 } | |
304 | 3533 __ cmpptr(rax, Address(rcx, BasicObjectLock::obj_offset_in_bytes())); // check if current entry is for same object |
3534 __ jccb(Assembler::equal, exit); // if same object then stop searching | |
3535 __ addptr(rcx, entry_size); // otherwise advance to next entry | |
0 | 3536 __ bind(entry); |
304 | 3537 __ cmpptr(rcx, rbx); // check if bottom reached |
0 | 3538 __ jcc(Assembler::notEqual, loop); // if not at bottom then check this entry |
3539 __ bind(exit); | |
3540 } | |
3541 | |
304 | 3542 __ testptr(rdx, rdx); // check if a slot has been found |
3543 __ jccb(Assembler::notZero, allocated); // if found, continue with that one | |
0 | 3544 |
3545 // allocate one if there's no free slot | |
3546 { Label entry, loop; | |
3547 // 1. compute new pointers // rsp: old expression stack top | |
304 | 3548 __ movptr(rdx, monitor_block_bot); // rdx: old expression stack bottom |
3549 __ subptr(rsp, entry_size); // move expression stack top | |
3550 __ subptr(rdx, entry_size); // move expression stack bottom | |
3551 __ mov(rcx, rsp); // set start value for copy loop | |
3552 __ movptr(monitor_block_bot, rdx); // set new monitor block top | |
0 | 3553 __ jmp(entry); |
3554 // 2. move expression stack contents | |
3555 __ bind(loop); | |
304 | 3556 __ movptr(rbx, Address(rcx, entry_size)); // load expression stack word from old location |
3557 __ movptr(Address(rcx, 0), rbx); // and store it at new location | |
3558 __ addptr(rcx, wordSize); // advance to next word | |
0 | 3559 __ bind(entry); |
304 | 3560 __ cmpptr(rcx, rdx); // check if bottom reached |
0 | 3561 __ jcc(Assembler::notEqual, loop); // if not at bottom then copy next word |
3562 } | |
3563 | |
3564 // call run-time routine | |
3565 // rdx: points to monitor entry | |
3566 __ bind(allocated); | |
3567 | |
3568 // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly. | |
3569 // The object has already been poped from the stack, so the expression stack looks correct. | |
3570 __ increment(rsi); | |
3571 | |
304 | 3572 __ movptr(Address(rdx, BasicObjectLock::obj_offset_in_bytes()), rax); // store object |
0 | 3573 __ lock_object(rdx); |
3574 | |
3575 // check to make sure this monitor doesn't cause stack overflow after locking | |
3576 __ save_bcp(); // in case of exception | |
3577 __ generate_stack_overflow_check(0); | |
3578 | |
3579 // The bcp has already been incremented. Just need to dispatch to next instruction. | |
3580 __ dispatch_next(vtos); | |
3581 } | |
3582 | |
3583 | |
3584 void TemplateTable::monitorexit() { | |
3585 transition(atos, vtos); | |
3586 | |
3587 // check for NULL object | |
3588 __ null_check(rax); | |
3589 | |
3590 const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); | |
3591 const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize); | |
3592 const int entry_size = ( frame::interpreter_frame_monitor_size() * wordSize); | |
3593 Label found; | |
3594 | |
3595 // find matching slot | |
3596 { Label entry, loop; | |
304 | 3597 __ movptr(rdx, monitor_block_top); // points to current entry, starting with top-most entry |
3598 __ lea(rbx, monitor_block_bot); // points to word before bottom of monitor block | |
0 | 3599 __ jmpb(entry); |
3600 | |
3601 __ bind(loop); | |
304 | 3602 __ cmpptr(rax, Address(rdx, BasicObjectLock::obj_offset_in_bytes())); // check if current entry is for same object |
0 | 3603 __ jcc(Assembler::equal, found); // if same object then stop searching |
304 | 3604 __ addptr(rdx, entry_size); // otherwise advance to next entry |
0 | 3605 __ bind(entry); |
304 | 3606 __ cmpptr(rdx, rbx); // check if bottom reached |
0 | 3607 __ jcc(Assembler::notEqual, loop); // if not at bottom then check this entry |
3608 } | |
3609 | |
3610 // error handling. Unlocking was not block-structured | |
3611 Label end; | |
3612 __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); | |
3613 __ should_not_reach_here(); | |
3614 | |
3615 // call run-time routine | |
3616 // rcx: points to monitor entry | |
3617 __ bind(found); | |
3618 __ push_ptr(rax); // make sure object is on stack (contract with oopMaps) | |
3619 __ unlock_object(rdx); | |
3620 __ pop_ptr(rax); // discard object | |
3621 __ bind(end); | |
3622 } | |
3623 | |
3624 | |
3625 //---------------------------------------------------------------------------------------------------- | |
3626 // Wide instructions | |
3627 | |
3628 void TemplateTable::wide() { | |
3629 transition(vtos, vtos); | |
3630 __ load_unsigned_byte(rbx, at_bcp(1)); | |
304 | 3631 ExternalAddress wtable((address)Interpreter::_wentry_point); |
3632 __ jump(ArrayAddress(wtable, Address(noreg, rbx, Address::times_ptr))); | |
0 | 3633 // Note: the rsi increment step is part of the individual wide bytecode implementations |
3634 } | |
3635 | |
3636 | |
3637 //---------------------------------------------------------------------------------------------------- | |
3638 // Multi arrays | |
3639 | |
3640 void TemplateTable::multianewarray() { | |
3641 transition(vtos, atos); | |
3642 __ load_unsigned_byte(rax, at_bcp(3)); // get number of dimensions | |
3643 // last dim is on top of stack; we want address of first one: | |
3644 // first_addr = last_addr + (ndims - 1) * stackElementSize - 1*wordsize | |
3645 // the latter wordSize to point to the beginning of the array. | |
304 | 3646 __ lea( rax, Address(rsp, rax, Interpreter::stackElementScale(), -wordSize)); |
0 | 3647 call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), rax); // pass in rax, |
3648 __ load_unsigned_byte(rbx, at_bcp(3)); | |
304 | 3649 __ lea(rsp, Address(rsp, rbx, Interpreter::stackElementScale())); // get rid of counts |
0 | 3650 } |
3651 | |
3652 #endif /* !CC_INTERP */ |