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