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