Mercurial > hg > truffle
annotate src/cpu/x86/vm/stubGenerator_x86_32.cpp @ 2007:5ddfcf4b079e
7003554: (tiered) assert(is_null_object() || handle() != NULL) failed: cannot embed null pointer
Summary: C1 with profiling doesn't check whether the MDO has been really allocated, which can silently fail if the perm gen is full. The solution is to check if the allocation failed and bailout out of inlining or compilation.
Reviewed-by: kvn, never
author | iveresov |
---|---|
date | Thu, 02 Dec 2010 17:21:12 -0800 |
parents | f95d63e2154a |
children | 638119ce7cfd |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "asm/assembler.hpp" | |
27 #include "assembler_x86.inline.hpp" | |
28 #include "interpreter/interpreter.hpp" | |
29 #include "nativeInst_x86.hpp" | |
30 #include "oops/instanceOop.hpp" | |
31 #include "oops/methodOop.hpp" | |
32 #include "oops/objArrayKlass.hpp" | |
33 #include "oops/oop.inline.hpp" | |
34 #include "prims/methodHandles.hpp" | |
35 #include "runtime/frame.inline.hpp" | |
36 #include "runtime/handles.inline.hpp" | |
37 #include "runtime/sharedRuntime.hpp" | |
38 #include "runtime/stubCodeGenerator.hpp" | |
39 #include "runtime/stubRoutines.hpp" | |
40 #include "utilities/top.hpp" | |
41 #ifdef TARGET_OS_FAMILY_linux | |
42 # include "thread_linux.inline.hpp" | |
43 #endif | |
44 #ifdef TARGET_OS_FAMILY_solaris | |
45 # include "thread_solaris.inline.hpp" | |
46 #endif | |
47 #ifdef TARGET_OS_FAMILY_windows | |
48 # include "thread_windows.inline.hpp" | |
49 #endif | |
50 #ifdef COMPILER2 | |
51 #include "opto/runtime.hpp" | |
52 #endif | |
0 | 53 |
54 // Declaration and definition of StubGenerator (no .hpp file). | |
55 // For a more detailed description of the stub routine structure | |
56 // see the comment in stubRoutines.hpp | |
57 | |
58 #define __ _masm-> | |
304 | 59 #define a__ ((Assembler*)_masm)-> |
0 | 60 |
61 #ifdef PRODUCT | |
62 #define BLOCK_COMMENT(str) /* nothing */ | |
63 #else | |
64 #define BLOCK_COMMENT(str) __ block_comment(str) | |
65 #endif | |
66 | |
67 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") | |
68 | |
69 const int MXCSR_MASK = 0xFFC0; // Mask out any pending exceptions | |
70 const int FPU_CNTRL_WRD_MASK = 0xFFFF; | |
71 | |
72 // ------------------------------------------------------------------------------------------------------------------------- | |
73 // Stub Code definitions | |
74 | |
75 static address handle_unsafe_access() { | |
76 JavaThread* thread = JavaThread::current(); | |
77 address pc = thread->saved_exception_pc(); | |
78 // pc is the instruction which we must emulate | |
79 // doing a no-op is fine: return garbage from the load | |
80 // therefore, compute npc | |
81 address npc = Assembler::locate_next_instruction(pc); | |
82 | |
83 // request an async exception | |
84 thread->set_pending_unsafe_access_error(); | |
85 | |
86 // return address of next instruction to execute | |
87 return npc; | |
88 } | |
89 | |
90 class StubGenerator: public StubCodeGenerator { | |
91 private: | |
92 | |
93 #ifdef PRODUCT | |
94 #define inc_counter_np(counter) (0) | |
95 #else | |
96 void inc_counter_np_(int& counter) { | |
304 | 97 __ incrementl(ExternalAddress((address)&counter)); |
0 | 98 } |
99 #define inc_counter_np(counter) \ | |
100 BLOCK_COMMENT("inc_counter " #counter); \ | |
101 inc_counter_np_(counter); | |
102 #endif //PRODUCT | |
103 | |
104 void inc_copy_counter_np(BasicType t) { | |
105 #ifndef PRODUCT | |
106 switch (t) { | |
107 case T_BYTE: inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); return; | |
108 case T_SHORT: inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); return; | |
109 case T_INT: inc_counter_np(SharedRuntime::_jint_array_copy_ctr); return; | |
110 case T_LONG: inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); return; | |
111 case T_OBJECT: inc_counter_np(SharedRuntime::_oop_array_copy_ctr); return; | |
112 } | |
113 ShouldNotReachHere(); | |
114 #endif //PRODUCT | |
115 } | |
116 | |
117 //------------------------------------------------------------------------------------------------------------------------ | |
118 // Call stubs are used to call Java from C | |
119 // | |
120 // [ return_from_Java ] <--- rsp | |
121 // [ argument word n ] | |
122 // ... | |
123 // -N [ argument word 1 ] | |
124 // -7 [ Possible padding for stack alignment ] | |
125 // -6 [ Possible padding for stack alignment ] | |
126 // -5 [ Possible padding for stack alignment ] | |
127 // -4 [ mxcsr save ] <--- rsp_after_call | |
128 // -3 [ saved rbx, ] | |
129 // -2 [ saved rsi ] | |
130 // -1 [ saved rdi ] | |
131 // 0 [ saved rbp, ] <--- rbp, | |
132 // 1 [ return address ] | |
133 // 2 [ ptr. to call wrapper ] | |
134 // 3 [ result ] | |
135 // 4 [ result_type ] | |
136 // 5 [ method ] | |
137 // 6 [ entry_point ] | |
138 // 7 [ parameters ] | |
139 // 8 [ parameter_size ] | |
140 // 9 [ thread ] | |
141 | |
142 | |
143 address generate_call_stub(address& return_address) { | |
144 StubCodeMark mark(this, "StubRoutines", "call_stub"); | |
145 address start = __ pc(); | |
146 | |
147 // stub code parameters / addresses | |
148 assert(frame::entry_frame_call_wrapper_offset == 2, "adjust this code"); | |
149 bool sse_save = false; | |
150 const Address rsp_after_call(rbp, -4 * wordSize); // same as in generate_catch_exception()! | |
151 const int locals_count_in_bytes (4*wordSize); | |
152 const Address mxcsr_save (rbp, -4 * wordSize); | |
153 const Address saved_rbx (rbp, -3 * wordSize); | |
154 const Address saved_rsi (rbp, -2 * wordSize); | |
155 const Address saved_rdi (rbp, -1 * wordSize); | |
156 const Address result (rbp, 3 * wordSize); | |
157 const Address result_type (rbp, 4 * wordSize); | |
158 const Address method (rbp, 5 * wordSize); | |
159 const Address entry_point (rbp, 6 * wordSize); | |
160 const Address parameters (rbp, 7 * wordSize); | |
161 const Address parameter_size(rbp, 8 * wordSize); | |
162 const Address thread (rbp, 9 * wordSize); // same as in generate_catch_exception()! | |
163 sse_save = UseSSE > 0; | |
164 | |
165 // stub code | |
166 __ enter(); | |
304 | 167 __ movptr(rcx, parameter_size); // parameter counter |
1506 | 168 __ shlptr(rcx, Interpreter::logStackElementSize); // convert parameter count to bytes |
304 | 169 __ addptr(rcx, locals_count_in_bytes); // reserve space for register saves |
170 __ subptr(rsp, rcx); | |
171 __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack | |
0 | 172 |
173 // save rdi, rsi, & rbx, according to C calling conventions | |
304 | 174 __ movptr(saved_rdi, rdi); |
175 __ movptr(saved_rsi, rsi); | |
176 __ movptr(saved_rbx, rbx); | |
0 | 177 // save and initialize %mxcsr |
178 if (sse_save) { | |
179 Label skip_ldmx; | |
180 __ stmxcsr(mxcsr_save); | |
181 __ movl(rax, mxcsr_save); | |
182 __ andl(rax, MXCSR_MASK); // Only check control and mask bits | |
183 ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std()); | |
184 __ cmp32(rax, mxcsr_std); | |
185 __ jcc(Assembler::equal, skip_ldmx); | |
186 __ ldmxcsr(mxcsr_std); | |
187 __ bind(skip_ldmx); | |
188 } | |
189 | |
190 // make sure the control word is correct. | |
191 __ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); | |
192 | |
193 #ifdef ASSERT | |
194 // make sure we have no pending exceptions | |
195 { Label L; | |
304 | 196 __ movptr(rcx, thread); |
197 __ cmpptr(Address(rcx, Thread::pending_exception_offset()), (int32_t)NULL_WORD); | |
0 | 198 __ jcc(Assembler::equal, L); |
199 __ stop("StubRoutines::call_stub: entered with pending exception"); | |
200 __ bind(L); | |
201 } | |
202 #endif | |
203 | |
204 // pass parameters if any | |
205 BLOCK_COMMENT("pass parameters if any"); | |
206 Label parameters_done; | |
207 __ movl(rcx, parameter_size); // parameter counter | |
208 __ testl(rcx, rcx); | |
209 __ jcc(Assembler::zero, parameters_done); | |
210 | |
211 // parameter passing loop | |
212 | |
213 Label loop; | |
214 // Copy Java parameters in reverse order (receiver last) | |
215 // Note that the argument order is inverted in the process | |
216 // source is rdx[rcx: N-1..0] | |
217 // dest is rsp[rbx: 0..N-1] | |
218 | |
304 | 219 __ movptr(rdx, parameters); // parameter pointer |
220 __ xorptr(rbx, rbx); | |
0 | 221 |
222 __ BIND(loop); | |
223 | |
224 // get parameter | |
304 | 225 __ movptr(rax, Address(rdx, rcx, Interpreter::stackElementScale(), -wordSize)); |
226 __ movptr(Address(rsp, rbx, Interpreter::stackElementScale(), | |
0 | 227 Interpreter::expr_offset_in_bytes(0)), rax); // store parameter |
228 __ increment(rbx); | |
229 __ decrement(rcx); | |
230 __ jcc(Assembler::notZero, loop); | |
231 | |
232 // call Java function | |
233 __ BIND(parameters_done); | |
304 | 234 __ movptr(rbx, method); // get methodOop |
235 __ movptr(rax, entry_point); // get entry_point | |
236 __ mov(rsi, rsp); // set sender sp | |
0 | 237 BLOCK_COMMENT("call Java function"); |
238 __ call(rax); | |
239 | |
240 BLOCK_COMMENT("call_stub_return_address:"); | |
241 return_address = __ pc(); | |
242 | |
243 Label common_return; | |
244 | |
245 __ BIND(common_return); | |
246 | |
247 // store result depending on type | |
248 // (everything that is not T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) | |
304 | 249 __ movptr(rdi, result); |
0 | 250 Label is_long, is_float, is_double, exit; |
251 __ movl(rsi, result_type); | |
252 __ cmpl(rsi, T_LONG); | |
253 __ jcc(Assembler::equal, is_long); | |
254 __ cmpl(rsi, T_FLOAT); | |
255 __ jcc(Assembler::equal, is_float); | |
256 __ cmpl(rsi, T_DOUBLE); | |
257 __ jcc(Assembler::equal, is_double); | |
258 | |
259 // handle T_INT case | |
260 __ movl(Address(rdi, 0), rax); | |
261 __ BIND(exit); | |
262 | |
263 // check that FPU stack is empty | |
264 __ verify_FPU(0, "generate_call_stub"); | |
265 | |
266 // pop parameters | |
304 | 267 __ lea(rsp, rsp_after_call); |
0 | 268 |
269 // restore %mxcsr | |
270 if (sse_save) { | |
271 __ ldmxcsr(mxcsr_save); | |
272 } | |
273 | |
274 // restore rdi, rsi and rbx, | |
304 | 275 __ movptr(rbx, saved_rbx); |
276 __ movptr(rsi, saved_rsi); | |
277 __ movptr(rdi, saved_rdi); | |
278 __ addptr(rsp, 4*wordSize); | |
0 | 279 |
280 // return | |
304 | 281 __ pop(rbp); |
0 | 282 __ ret(0); |
283 | |
284 // handle return types different from T_INT | |
285 __ BIND(is_long); | |
286 __ movl(Address(rdi, 0 * wordSize), rax); | |
287 __ movl(Address(rdi, 1 * wordSize), rdx); | |
288 __ jmp(exit); | |
289 | |
290 __ BIND(is_float); | |
291 // interpreter uses xmm0 for return values | |
292 if (UseSSE >= 1) { | |
293 __ movflt(Address(rdi, 0), xmm0); | |
294 } else { | |
295 __ fstp_s(Address(rdi, 0)); | |
296 } | |
297 __ jmp(exit); | |
298 | |
299 __ BIND(is_double); | |
300 // interpreter uses xmm0 for return values | |
301 if (UseSSE >= 2) { | |
302 __ movdbl(Address(rdi, 0), xmm0); | |
303 } else { | |
304 __ fstp_d(Address(rdi, 0)); | |
305 } | |
306 __ jmp(exit); | |
307 | |
308 // If we call compiled code directly from the call stub we will | |
309 // need to adjust the return back to the call stub to a specialized | |
310 // piece of code that can handle compiled results and cleaning the fpu | |
311 // stack. compiled code will be set to return here instead of the | |
312 // return above that handles interpreter returns. | |
313 | |
314 BLOCK_COMMENT("call_stub_compiled_return:"); | |
304 | 315 StubRoutines::x86::set_call_stub_compiled_return( __ pc()); |
0 | 316 |
317 #ifdef COMPILER2 | |
318 if (UseSSE >= 2) { | |
319 __ verify_FPU(0, "call_stub_compiled_return"); | |
320 } else { | |
321 for (int i = 1; i < 8; i++) { | |
322 __ ffree(i); | |
323 } | |
324 | |
325 // UseSSE <= 1 so double result should be left on TOS | |
326 __ movl(rsi, result_type); | |
327 __ cmpl(rsi, T_DOUBLE); | |
328 __ jcc(Assembler::equal, common_return); | |
329 if (UseSSE == 0) { | |
330 // UseSSE == 0 so float result should be left on TOS | |
331 __ cmpl(rsi, T_FLOAT); | |
332 __ jcc(Assembler::equal, common_return); | |
333 } | |
334 __ ffree(0); | |
335 } | |
336 #endif /* COMPILER2 */ | |
337 __ jmp(common_return); | |
338 | |
339 return start; | |
340 } | |
341 | |
342 | |
343 //------------------------------------------------------------------------------------------------------------------------ | |
344 // Return point for a Java call if there's an exception thrown in Java code. | |
345 // The exception is caught and transformed into a pending exception stored in | |
346 // JavaThread that can be tested from within the VM. | |
347 // | |
348 // Note: Usually the parameters are removed by the callee. In case of an exception | |
349 // crossing an activation frame boundary, that is not the case if the callee | |
350 // is compiled code => need to setup the rsp. | |
351 // | |
352 // rax,: exception oop | |
353 | |
354 address generate_catch_exception() { | |
355 StubCodeMark mark(this, "StubRoutines", "catch_exception"); | |
356 const Address rsp_after_call(rbp, -4 * wordSize); // same as in generate_call_stub()! | |
357 const Address thread (rbp, 9 * wordSize); // same as in generate_call_stub()! | |
358 address start = __ pc(); | |
359 | |
360 // get thread directly | |
304 | 361 __ movptr(rcx, thread); |
0 | 362 #ifdef ASSERT |
363 // verify that threads correspond | |
364 { Label L; | |
365 __ get_thread(rbx); | |
304 | 366 __ cmpptr(rbx, rcx); |
0 | 367 __ jcc(Assembler::equal, L); |
368 __ stop("StubRoutines::catch_exception: threads must correspond"); | |
369 __ bind(L); | |
370 } | |
371 #endif | |
372 // set pending exception | |
373 __ verify_oop(rax); | |
304 | 374 __ movptr(Address(rcx, Thread::pending_exception_offset()), rax ); |
0 | 375 __ lea(Address(rcx, Thread::exception_file_offset ()), |
376 ExternalAddress((address)__FILE__)); | |
377 __ movl(Address(rcx, Thread::exception_line_offset ()), __LINE__ ); | |
378 // complete return to VM | |
379 assert(StubRoutines::_call_stub_return_address != NULL, "_call_stub_return_address must have been generated before"); | |
380 __ jump(RuntimeAddress(StubRoutines::_call_stub_return_address)); | |
381 | |
382 return start; | |
383 } | |
384 | |
385 | |
386 //------------------------------------------------------------------------------------------------------------------------ | |
387 // Continuation point for runtime calls returning with a pending exception. | |
388 // The pending exception check happened in the runtime or native call stub. | |
389 // The pending exception in Thread is converted into a Java-level exception. | |
390 // | |
391 // Contract with Java-level exception handlers: | |
1295 | 392 // rax: exception |
0 | 393 // rdx: throwing pc |
394 // | |
395 // NOTE: At entry of this stub, exception-pc must be on stack !! | |
396 | |
397 address generate_forward_exception() { | |
398 StubCodeMark mark(this, "StubRoutines", "forward exception"); | |
399 address start = __ pc(); | |
1295 | 400 const Register thread = rcx; |
401 | |
402 // other registers used in this stub | |
403 const Register exception_oop = rax; | |
404 const Register handler_addr = rbx; | |
405 const Register exception_pc = rdx; | |
0 | 406 |
407 // Upon entry, the sp points to the return address returning into Java | |
408 // (interpreted or compiled) code; i.e., the return address becomes the | |
409 // throwing pc. | |
410 // | |
411 // Arguments pushed before the runtime call are still on the stack but | |
412 // the exception handler will reset the stack pointer -> ignore them. | |
413 // A potential result in registers can be ignored as well. | |
414 | |
415 #ifdef ASSERT | |
416 // make sure this code is only executed if there is a pending exception | |
417 { Label L; | |
1295 | 418 __ get_thread(thread); |
419 __ cmpptr(Address(thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); | |
0 | 420 __ jcc(Assembler::notEqual, L); |
421 __ stop("StubRoutines::forward exception: no pending exception (1)"); | |
422 __ bind(L); | |
423 } | |
424 #endif | |
425 | |
426 // compute exception handler into rbx, | |
1295 | 427 __ get_thread(thread); |
428 __ movptr(exception_pc, Address(rsp, 0)); | |
0 | 429 BLOCK_COMMENT("call exception_handler_for_return_address"); |
1295 | 430 __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), thread, exception_pc); |
431 __ mov(handler_addr, rax); | |
0 | 432 |
1295 | 433 // setup rax & rdx, remove return address & clear pending exception |
434 __ get_thread(thread); | |
435 __ pop(exception_pc); | |
436 __ movptr(exception_oop, Address(thread, Thread::pending_exception_offset())); | |
437 __ movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); | |
0 | 438 |
439 #ifdef ASSERT | |
440 // make sure exception is set | |
441 { Label L; | |
1295 | 442 __ testptr(exception_oop, exception_oop); |
0 | 443 __ jcc(Assembler::notEqual, L); |
444 __ stop("StubRoutines::forward exception: no pending exception (2)"); | |
445 __ bind(L); | |
446 } | |
447 #endif | |
448 | |
1295 | 449 // Verify that there is really a valid exception in RAX. |
450 __ verify_oop(exception_oop); | |
451 | |
452 // Restore SP from BP if the exception PC is a MethodHandle call site. | |
1368
93767e6a2dfd
6941529: SharedRuntime::raw_exception_handler_for_return_address must reset thread MethodHandle flag
twisti
parents:
1365
diff
changeset
|
453 __ cmpl(Address(thread, JavaThread::is_method_handle_return_offset()), 0); |
1295 | 454 __ cmovptr(Assembler::notEqual, rsp, rbp); |
455 | |
0 | 456 // continue at exception handler (return address removed) |
1295 | 457 // rax: exception |
458 // rbx: exception handler | |
0 | 459 // rdx: throwing pc |
1295 | 460 __ jmp(handler_addr); |
0 | 461 |
462 return start; | |
463 } | |
464 | |
465 | |
466 //---------------------------------------------------------------------------------------------------- | |
467 // Support for jint Atomic::xchg(jint exchange_value, volatile jint* dest) | |
468 // | |
469 // xchg exists as far back as 8086, lock needed for MP only | |
470 // Stack layout immediately after call: | |
471 // | |
472 // 0 [ret addr ] <--- rsp | |
473 // 1 [ ex ] | |
474 // 2 [ dest ] | |
475 // | |
476 // Result: *dest <- ex, return (old *dest) | |
477 // | |
478 // Note: win32 does not currently use this code | |
479 | |
480 address generate_atomic_xchg() { | |
481 StubCodeMark mark(this, "StubRoutines", "atomic_xchg"); | |
482 address start = __ pc(); | |
483 | |
304 | 484 __ push(rdx); |
0 | 485 Address exchange(rsp, 2 * wordSize); |
486 Address dest_addr(rsp, 3 * wordSize); | |
487 __ movl(rax, exchange); | |
304 | 488 __ movptr(rdx, dest_addr); |
489 __ xchgl(rax, Address(rdx, 0)); | |
490 __ pop(rdx); | |
0 | 491 __ ret(0); |
492 | |
493 return start; | |
494 } | |
495 | |
496 //---------------------------------------------------------------------------------------------------- | |
497 // Support for void verify_mxcsr() | |
498 // | |
499 // This routine is used with -Xcheck:jni to verify that native | |
500 // JNI code does not return to Java code without restoring the | |
501 // MXCSR register to our expected state. | |
502 | |
503 | |
504 address generate_verify_mxcsr() { | |
505 StubCodeMark mark(this, "StubRoutines", "verify_mxcsr"); | |
506 address start = __ pc(); | |
507 | |
508 const Address mxcsr_save(rsp, 0); | |
509 | |
510 if (CheckJNICalls && UseSSE > 0 ) { | |
511 Label ok_ret; | |
512 ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std()); | |
304 | 513 __ push(rax); |
514 __ subptr(rsp, wordSize); // allocate a temp location | |
0 | 515 __ stmxcsr(mxcsr_save); |
516 __ movl(rax, mxcsr_save); | |
517 __ andl(rax, MXCSR_MASK); | |
518 __ cmp32(rax, mxcsr_std); | |
519 __ jcc(Assembler::equal, ok_ret); | |
520 | |
521 __ warn("MXCSR changed by native JNI code."); | |
522 | |
523 __ ldmxcsr(mxcsr_std); | |
524 | |
525 __ bind(ok_ret); | |
304 | 526 __ addptr(rsp, wordSize); |
527 __ pop(rax); | |
0 | 528 } |
529 | |
530 __ ret(0); | |
531 | |
532 return start; | |
533 } | |
534 | |
535 | |
536 //--------------------------------------------------------------------------- | |
537 // Support for void verify_fpu_cntrl_wrd() | |
538 // | |
539 // This routine is used with -Xcheck:jni to verify that native | |
540 // JNI code does not return to Java code without restoring the | |
541 // FP control word to our expected state. | |
542 | |
543 address generate_verify_fpu_cntrl_wrd() { | |
544 StubCodeMark mark(this, "StubRoutines", "verify_spcw"); | |
545 address start = __ pc(); | |
546 | |
547 const Address fpu_cntrl_wrd_save(rsp, 0); | |
548 | |
549 if (CheckJNICalls) { | |
550 Label ok_ret; | |
304 | 551 __ push(rax); |
552 __ subptr(rsp, wordSize); // allocate a temp location | |
0 | 553 __ fnstcw(fpu_cntrl_wrd_save); |
554 __ movl(rax, fpu_cntrl_wrd_save); | |
555 __ andl(rax, FPU_CNTRL_WRD_MASK); | |
556 ExternalAddress fpu_std(StubRoutines::addr_fpu_cntrl_wrd_std()); | |
557 __ cmp32(rax, fpu_std); | |
558 __ jcc(Assembler::equal, ok_ret); | |
559 | |
560 __ warn("Floating point control word changed by native JNI code."); | |
561 | |
562 __ fldcw(fpu_std); | |
563 | |
564 __ bind(ok_ret); | |
304 | 565 __ addptr(rsp, wordSize); |
566 __ pop(rax); | |
0 | 567 } |
568 | |
569 __ ret(0); | |
570 | |
571 return start; | |
572 } | |
573 | |
574 //--------------------------------------------------------------------------- | |
575 // Wrapper for slow-case handling of double-to-integer conversion | |
576 // d2i or f2i fast case failed either because it is nan or because | |
577 // of under/overflow. | |
578 // Input: FPU TOS: float value | |
579 // Output: rax, (rdx): integer (long) result | |
580 | |
581 address generate_d2i_wrapper(BasicType t, address fcn) { | |
582 StubCodeMark mark(this, "StubRoutines", "d2i_wrapper"); | |
583 address start = __ pc(); | |
584 | |
585 // Capture info about frame layout | |
586 enum layout { FPUState_off = 0, | |
587 rbp_off = FPUStateSizeInWords, | |
588 rdi_off, | |
589 rsi_off, | |
590 rcx_off, | |
591 rbx_off, | |
592 saved_argument_off, | |
593 saved_argument_off2, // 2nd half of double | |
594 framesize | |
595 }; | |
596 | |
597 assert(FPUStateSizeInWords == 27, "update stack layout"); | |
598 | |
599 // Save outgoing argument to stack across push_FPU_state() | |
304 | 600 __ subptr(rsp, wordSize * 2); |
0 | 601 __ fstp_d(Address(rsp, 0)); |
602 | |
603 // Save CPU & FPU state | |
304 | 604 __ push(rbx); |
605 __ push(rcx); | |
606 __ push(rsi); | |
607 __ push(rdi); | |
608 __ push(rbp); | |
0 | 609 __ push_FPU_state(); |
610 | |
611 // push_FPU_state() resets the FP top of stack | |
612 // Load original double into FP top of stack | |
613 __ fld_d(Address(rsp, saved_argument_off * wordSize)); | |
614 // Store double into stack as outgoing argument | |
304 | 615 __ subptr(rsp, wordSize*2); |
0 | 616 __ fst_d(Address(rsp, 0)); |
617 | |
618 // Prepare FPU for doing math in C-land | |
619 __ empty_FPU_stack(); | |
620 // Call the C code to massage the double. Result in EAX | |
621 if (t == T_INT) | |
622 { BLOCK_COMMENT("SharedRuntime::d2i"); } | |
623 else if (t == T_LONG) | |
624 { BLOCK_COMMENT("SharedRuntime::d2l"); } | |
625 __ call_VM_leaf( fcn, 2 ); | |
626 | |
627 // Restore CPU & FPU state | |
628 __ pop_FPU_state(); | |
304 | 629 __ pop(rbp); |
630 __ pop(rdi); | |
631 __ pop(rsi); | |
632 __ pop(rcx); | |
633 __ pop(rbx); | |
634 __ addptr(rsp, wordSize * 2); | |
0 | 635 |
636 __ ret(0); | |
637 | |
638 return start; | |
639 } | |
640 | |
641 | |
642 //--------------------------------------------------------------------------- | |
643 // The following routine generates a subroutine to throw an asynchronous | |
644 // UnknownError when an unsafe access gets a fault that could not be | |
645 // reasonably prevented by the programmer. (Example: SIGBUS/OBJERR.) | |
646 address generate_handler_for_unsafe_access() { | |
647 StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access"); | |
648 address start = __ pc(); | |
649 | |
304 | 650 __ push(0); // hole for return address-to-be |
651 __ pusha(); // push registers | |
0 | 652 Address next_pc(rsp, RegisterImpl::number_of_registers * BytesPerWord); |
653 BLOCK_COMMENT("call handle_unsafe_access"); | |
654 __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, handle_unsafe_access))); | |
304 | 655 __ movptr(next_pc, rax); // stuff next address |
656 __ popa(); | |
0 | 657 __ ret(0); // jump to next address |
658 | |
659 return start; | |
660 } | |
661 | |
662 | |
663 //---------------------------------------------------------------------------------------------------- | |
664 // Non-destructive plausibility checks for oops | |
665 | |
666 address generate_verify_oop() { | |
667 StubCodeMark mark(this, "StubRoutines", "verify_oop"); | |
668 address start = __ pc(); | |
669 | |
670 // Incoming arguments on stack after saving rax,: | |
671 // | |
672 // [tos ]: saved rdx | |
673 // [tos + 1]: saved EFLAGS | |
674 // [tos + 2]: return address | |
675 // [tos + 3]: char* error message | |
676 // [tos + 4]: oop object to verify | |
677 // [tos + 5]: saved rax, - saved by caller and bashed | |
678 | |
679 Label exit, error; | |
304 | 680 __ pushf(); |
681 __ incrementl(ExternalAddress((address) StubRoutines::verify_oop_count_addr())); | |
682 __ push(rdx); // save rdx | |
0 | 683 // make sure object is 'reasonable' |
304 | 684 __ movptr(rax, Address(rsp, 4 * wordSize)); // get object |
685 __ testptr(rax, rax); | |
0 | 686 __ jcc(Assembler::zero, exit); // if obj is NULL it is ok |
687 | |
688 // Check if the oop is in the right area of memory | |
689 const int oop_mask = Universe::verify_oop_mask(); | |
690 const int oop_bits = Universe::verify_oop_bits(); | |
304 | 691 __ mov(rdx, rax); |
692 __ andptr(rdx, oop_mask); | |
693 __ cmpptr(rdx, oop_bits); | |
0 | 694 __ jcc(Assembler::notZero, error); |
695 | |
696 // make sure klass is 'reasonable' | |
304 | 697 __ movptr(rax, Address(rax, oopDesc::klass_offset_in_bytes())); // get klass |
698 __ testptr(rax, rax); | |
0 | 699 __ jcc(Assembler::zero, error); // if klass is NULL it is broken |
700 | |
701 // Check if the klass is in the right area of memory | |
702 const int klass_mask = Universe::verify_klass_mask(); | |
703 const int klass_bits = Universe::verify_klass_bits(); | |
304 | 704 __ mov(rdx, rax); |
705 __ andptr(rdx, klass_mask); | |
706 __ cmpptr(rdx, klass_bits); | |
0 | 707 __ jcc(Assembler::notZero, error); |
708 | |
709 // make sure klass' klass is 'reasonable' | |
304 | 710 __ movptr(rax, Address(rax, oopDesc::klass_offset_in_bytes())); // get klass' klass |
711 __ testptr(rax, rax); | |
0 | 712 __ jcc(Assembler::zero, error); // if klass' klass is NULL it is broken |
713 | |
304 | 714 __ mov(rdx, rax); |
715 __ andptr(rdx, klass_mask); | |
716 __ cmpptr(rdx, klass_bits); | |
0 | 717 __ jcc(Assembler::notZero, error); // if klass not in right area |
718 // of memory it is broken too. | |
719 | |
720 // return if everything seems ok | |
721 __ bind(exit); | |
304 | 722 __ movptr(rax, Address(rsp, 5 * wordSize)); // get saved rax, back |
723 __ pop(rdx); // restore rdx | |
724 __ popf(); // restore EFLAGS | |
0 | 725 __ ret(3 * wordSize); // pop arguments |
726 | |
727 // handle errors | |
728 __ bind(error); | |
304 | 729 __ movptr(rax, Address(rsp, 5 * wordSize)); // get saved rax, back |
730 __ pop(rdx); // get saved rdx back | |
731 __ popf(); // get saved EFLAGS off stack -- will be ignored | |
732 __ pusha(); // push registers (eip = return address & msg are already pushed) | |
0 | 733 BLOCK_COMMENT("call MacroAssembler::debug"); |
304 | 734 __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug32))); |
735 __ popa(); | |
0 | 736 __ ret(3 * wordSize); // pop arguments |
737 return start; | |
738 } | |
739 | |
740 // | |
741 // Generate pre-barrier for array stores | |
742 // | |
743 // Input: | |
744 // start - starting address | |
845
df6caf649ff7
6700789: G1: Enable use of compressed oops with G1 heaps
ysr
parents:
710
diff
changeset
|
745 // count - element count |
0 | 746 void gen_write_ref_array_pre_barrier(Register start, Register count) { |
747 assert_different_registers(start, count); | |
748 BarrierSet* bs = Universe::heap()->barrier_set(); | |
749 switch (bs->kind()) { | |
750 case BarrierSet::G1SATBCT: | |
751 case BarrierSet::G1SATBCTLogging: | |
752 { | |
304 | 753 __ pusha(); // push registers |
1192
776fb94f33cc
6918006: G1: spill space must be reserved on the stack for barrier calls on Windows x64
apetrusenko
parents:
1174
diff
changeset
|
754 __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), |
776fb94f33cc
6918006: G1: spill space must be reserved on the stack for barrier calls on Windows x64
apetrusenko
parents:
1174
diff
changeset
|
755 start, count); |
304 | 756 __ popa(); |
0 | 757 } |
758 break; | |
759 case BarrierSet::CardTableModRef: | |
760 case BarrierSet::CardTableExtension: | |
761 case BarrierSet::ModRef: | |
762 break; | |
763 default : | |
764 ShouldNotReachHere(); | |
765 | |
766 } | |
767 } | |
768 | |
769 | |
770 // | |
771 // Generate a post-barrier for an array store | |
772 // | |
773 // start - starting address | |
774 // count - element count | |
775 // | |
776 // The two input registers are overwritten. | |
777 // | |
778 void gen_write_ref_array_post_barrier(Register start, Register count) { | |
779 BarrierSet* bs = Universe::heap()->barrier_set(); | |
780 assert_different_registers(start, count); | |
781 switch (bs->kind()) { | |
782 case BarrierSet::G1SATBCT: | |
783 case BarrierSet::G1SATBCTLogging: | |
784 { | |
304 | 785 __ pusha(); // push registers |
1192
776fb94f33cc
6918006: G1: spill space must be reserved on the stack for barrier calls on Windows x64
apetrusenko
parents:
1174
diff
changeset
|
786 __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), |
776fb94f33cc
6918006: G1: spill space must be reserved on the stack for barrier calls on Windows x64
apetrusenko
parents:
1174
diff
changeset
|
787 start, count); |
304 | 788 __ popa(); |
0 | 789 } |
790 break; | |
791 | |
792 case BarrierSet::CardTableModRef: | |
793 case BarrierSet::CardTableExtension: | |
794 { | |
795 CardTableModRefBS* ct = (CardTableModRefBS*)bs; | |
796 assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); | |
797 | |
798 Label L_loop; | |
799 const Register end = count; // elements count; end == start+count-1 | |
800 assert_different_registers(start, end); | |
801 | |
304 | 802 __ lea(end, Address(start, count, Address::times_ptr, -wordSize)); |
803 __ shrptr(start, CardTableModRefBS::card_shift); | |
804 __ shrptr(end, CardTableModRefBS::card_shift); | |
805 __ subptr(end, start); // end --> count | |
0 | 806 __ BIND(L_loop); |
249
910a4cb98e9e
6717457: Internal Error (src/share/vm/code/relocInfo.hpp:1089)
never
parents:
19
diff
changeset
|
807 intptr_t disp = (intptr_t) ct->byte_map_base; |
910a4cb98e9e
6717457: Internal Error (src/share/vm/code/relocInfo.hpp:1089)
never
parents:
19
diff
changeset
|
808 Address cardtable(start, count, Address::times_1, disp); |
910a4cb98e9e
6717457: Internal Error (src/share/vm/code/relocInfo.hpp:1089)
never
parents:
19
diff
changeset
|
809 __ movb(cardtable, 0); |
0 | 810 __ decrement(count); |
811 __ jcc(Assembler::greaterEqual, L_loop); | |
812 } | |
813 break; | |
814 case BarrierSet::ModRef: | |
815 break; | |
816 default : | |
817 ShouldNotReachHere(); | |
818 | |
819 } | |
820 } | |
821 | |
405 | 822 |
823 // Copy 64 bytes chunks | |
824 // | |
825 // Inputs: | |
826 // from - source array address | |
827 // to_from - destination array address - from | |
828 // qword_count - 8-bytes element count, negative | |
829 // | |
830 void xmm_copy_forward(Register from, Register to_from, Register qword_count) { | |
831 assert( UseSSE >= 2, "supported cpu only" ); | |
832 Label L_copy_64_bytes_loop, L_copy_64_bytes, L_copy_8_bytes, L_exit; | |
833 // Copy 64-byte chunks | |
834 __ jmpb(L_copy_64_bytes); | |
1365 | 835 __ align(OptoLoopAlignment); |
405 | 836 __ BIND(L_copy_64_bytes_loop); |
837 | |
838 if(UseUnalignedLoadStores) { | |
839 __ movdqu(xmm0, Address(from, 0)); | |
840 __ movdqu(Address(from, to_from, Address::times_1, 0), xmm0); | |
841 __ movdqu(xmm1, Address(from, 16)); | |
842 __ movdqu(Address(from, to_from, Address::times_1, 16), xmm1); | |
843 __ movdqu(xmm2, Address(from, 32)); | |
844 __ movdqu(Address(from, to_from, Address::times_1, 32), xmm2); | |
845 __ movdqu(xmm3, Address(from, 48)); | |
846 __ movdqu(Address(from, to_from, Address::times_1, 48), xmm3); | |
847 | |
848 } else { | |
849 __ movq(xmm0, Address(from, 0)); | |
850 __ movq(Address(from, to_from, Address::times_1, 0), xmm0); | |
851 __ movq(xmm1, Address(from, 8)); | |
852 __ movq(Address(from, to_from, Address::times_1, 8), xmm1); | |
853 __ movq(xmm2, Address(from, 16)); | |
854 __ movq(Address(from, to_from, Address::times_1, 16), xmm2); | |
855 __ movq(xmm3, Address(from, 24)); | |
856 __ movq(Address(from, to_from, Address::times_1, 24), xmm3); | |
857 __ movq(xmm4, Address(from, 32)); | |
858 __ movq(Address(from, to_from, Address::times_1, 32), xmm4); | |
859 __ movq(xmm5, Address(from, 40)); | |
860 __ movq(Address(from, to_from, Address::times_1, 40), xmm5); | |
861 __ movq(xmm6, Address(from, 48)); | |
862 __ movq(Address(from, to_from, Address::times_1, 48), xmm6); | |
863 __ movq(xmm7, Address(from, 56)); | |
864 __ movq(Address(from, to_from, Address::times_1, 56), xmm7); | |
865 } | |
866 | |
867 __ addl(from, 64); | |
868 __ BIND(L_copy_64_bytes); | |
869 __ subl(qword_count, 8); | |
870 __ jcc(Assembler::greaterEqual, L_copy_64_bytes_loop); | |
871 __ addl(qword_count, 8); | |
872 __ jccb(Assembler::zero, L_exit); | |
873 // | |
874 // length is too short, just copy qwords | |
875 // | |
876 __ BIND(L_copy_8_bytes); | |
877 __ movq(xmm0, Address(from, 0)); | |
878 __ movq(Address(from, to_from, Address::times_1), xmm0); | |
879 __ addl(from, 8); | |
880 __ decrement(qword_count); | |
881 __ jcc(Assembler::greater, L_copy_8_bytes); | |
882 __ BIND(L_exit); | |
883 } | |
884 | |
0 | 885 // Copy 64 bytes chunks |
886 // | |
887 // Inputs: | |
888 // from - source array address | |
889 // to_from - destination array address - from | |
890 // qword_count - 8-bytes element count, negative | |
891 // | |
892 void mmx_copy_forward(Register from, Register to_from, Register qword_count) { | |
405 | 893 assert( VM_Version::supports_mmx(), "supported cpu only" ); |
0 | 894 Label L_copy_64_bytes_loop, L_copy_64_bytes, L_copy_8_bytes, L_exit; |
895 // Copy 64-byte chunks | |
896 __ jmpb(L_copy_64_bytes); | |
1365 | 897 __ align(OptoLoopAlignment); |
0 | 898 __ BIND(L_copy_64_bytes_loop); |
899 __ movq(mmx0, Address(from, 0)); | |
900 __ movq(mmx1, Address(from, 8)); | |
901 __ movq(mmx2, Address(from, 16)); | |
902 __ movq(Address(from, to_from, Address::times_1, 0), mmx0); | |
903 __ movq(mmx3, Address(from, 24)); | |
904 __ movq(Address(from, to_from, Address::times_1, 8), mmx1); | |
905 __ movq(mmx4, Address(from, 32)); | |
906 __ movq(Address(from, to_from, Address::times_1, 16), mmx2); | |
907 __ movq(mmx5, Address(from, 40)); | |
908 __ movq(Address(from, to_from, Address::times_1, 24), mmx3); | |
909 __ movq(mmx6, Address(from, 48)); | |
910 __ movq(Address(from, to_from, Address::times_1, 32), mmx4); | |
911 __ movq(mmx7, Address(from, 56)); | |
912 __ movq(Address(from, to_from, Address::times_1, 40), mmx5); | |
913 __ movq(Address(from, to_from, Address::times_1, 48), mmx6); | |
914 __ movq(Address(from, to_from, Address::times_1, 56), mmx7); | |
304 | 915 __ addptr(from, 64); |
0 | 916 __ BIND(L_copy_64_bytes); |
917 __ subl(qword_count, 8); | |
918 __ jcc(Assembler::greaterEqual, L_copy_64_bytes_loop); | |
919 __ addl(qword_count, 8); | |
920 __ jccb(Assembler::zero, L_exit); | |
921 // | |
922 // length is too short, just copy qwords | |
923 // | |
924 __ BIND(L_copy_8_bytes); | |
925 __ movq(mmx0, Address(from, 0)); | |
926 __ movq(Address(from, to_from, Address::times_1), mmx0); | |
304 | 927 __ addptr(from, 8); |
0 | 928 __ decrement(qword_count); |
929 __ jcc(Assembler::greater, L_copy_8_bytes); | |
930 __ BIND(L_exit); | |
931 __ emms(); | |
932 } | |
933 | |
934 address generate_disjoint_copy(BasicType t, bool aligned, | |
935 Address::ScaleFactor sf, | |
936 address* entry, const char *name) { | |
937 __ align(CodeEntryAlignment); | |
938 StubCodeMark mark(this, "StubRoutines", name); | |
939 address start = __ pc(); | |
940 | |
941 Label L_0_count, L_exit, L_skip_align1, L_skip_align2, L_copy_byte; | |
942 Label L_copy_2_bytes, L_copy_4_bytes, L_copy_64_bytes; | |
943 | |
304 | 944 int shift = Address::times_ptr - sf; |
0 | 945 |
946 const Register from = rsi; // source array address | |
947 const Register to = rdi; // destination array address | |
948 const Register count = rcx; // elements count | |
949 const Register to_from = to; // (to - from) | |
950 const Register saved_to = rdx; // saved destination array address | |
951 | |
952 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
304 | 953 __ push(rsi); |
954 __ push(rdi); | |
955 __ movptr(from , Address(rsp, 12+ 4)); | |
956 __ movptr(to , Address(rsp, 12+ 8)); | |
0 | 957 __ movl(count, Address(rsp, 12+ 12)); |
958 if (t == T_OBJECT) { | |
959 __ testl(count, count); | |
960 __ jcc(Assembler::zero, L_0_count); | |
961 gen_write_ref_array_pre_barrier(to, count); | |
304 | 962 __ mov(saved_to, to); // save 'to' |
0 | 963 } |
964 | |
965 *entry = __ pc(); // Entry point from conjoint arraycopy stub. | |
966 BLOCK_COMMENT("Entry:"); | |
967 | |
304 | 968 __ subptr(to, from); // to --> to_from |
0 | 969 __ cmpl(count, 2<<shift); // Short arrays (< 8 bytes) copy by element |
970 __ jcc(Assembler::below, L_copy_4_bytes); // use unsigned cmp | |
405 | 971 if (!UseUnalignedLoadStores && !aligned && (t == T_BYTE || t == T_SHORT)) { |
0 | 972 // align source address at 4 bytes address boundary |
973 if (t == T_BYTE) { | |
974 // One byte misalignment happens only for byte arrays | |
975 __ testl(from, 1); | |
976 __ jccb(Assembler::zero, L_skip_align1); | |
977 __ movb(rax, Address(from, 0)); | |
978 __ movb(Address(from, to_from, Address::times_1, 0), rax); | |
979 __ increment(from); | |
980 __ decrement(count); | |
981 __ BIND(L_skip_align1); | |
982 } | |
983 // Two bytes misalignment happens only for byte and short (char) arrays | |
984 __ testl(from, 2); | |
985 __ jccb(Assembler::zero, L_skip_align2); | |
986 __ movw(rax, Address(from, 0)); | |
987 __ movw(Address(from, to_from, Address::times_1, 0), rax); | |
304 | 988 __ addptr(from, 2); |
0 | 989 __ subl(count, 1<<(shift-1)); |
990 __ BIND(L_skip_align2); | |
991 } | |
992 if (!VM_Version::supports_mmx()) { | |
304 | 993 __ mov(rax, count); // save 'count' |
994 __ shrl(count, shift); // bytes count | |
995 __ addptr(to_from, from);// restore 'to' | |
996 __ rep_mov(); | |
997 __ subptr(to_from, from);// restore 'to_from' | |
998 __ mov(count, rax); // restore 'count' | |
0 | 999 __ jmpb(L_copy_2_bytes); // all dwords were copied |
1000 } else { | |
405 | 1001 if (!UseUnalignedLoadStores) { |
1002 // align to 8 bytes, we know we are 4 byte aligned to start | |
1003 __ testptr(from, 4); | |
1004 __ jccb(Assembler::zero, L_copy_64_bytes); | |
1005 __ movl(rax, Address(from, 0)); | |
1006 __ movl(Address(from, to_from, Address::times_1, 0), rax); | |
1007 __ addptr(from, 4); | |
1008 __ subl(count, 1<<shift); | |
1009 } | |
0 | 1010 __ BIND(L_copy_64_bytes); |
304 | 1011 __ mov(rax, count); |
0 | 1012 __ shrl(rax, shift+1); // 8 bytes chunk count |
1013 // | |
1014 // Copy 8-byte chunks through MMX registers, 8 per iteration of the loop | |
1015 // | |
405 | 1016 if (UseXMMForArrayCopy) { |
1017 xmm_copy_forward(from, to_from, rax); | |
1018 } else { | |
1019 mmx_copy_forward(from, to_from, rax); | |
1020 } | |
0 | 1021 } |
1022 // copy tailing dword | |
1023 __ BIND(L_copy_4_bytes); | |
1024 __ testl(count, 1<<shift); | |
1025 __ jccb(Assembler::zero, L_copy_2_bytes); | |
1026 __ movl(rax, Address(from, 0)); | |
1027 __ movl(Address(from, to_from, Address::times_1, 0), rax); | |
1028 if (t == T_BYTE || t == T_SHORT) { | |
304 | 1029 __ addptr(from, 4); |
0 | 1030 __ BIND(L_copy_2_bytes); |
1031 // copy tailing word | |
1032 __ testl(count, 1<<(shift-1)); | |
1033 __ jccb(Assembler::zero, L_copy_byte); | |
1034 __ movw(rax, Address(from, 0)); | |
1035 __ movw(Address(from, to_from, Address::times_1, 0), rax); | |
1036 if (t == T_BYTE) { | |
304 | 1037 __ addptr(from, 2); |
0 | 1038 __ BIND(L_copy_byte); |
1039 // copy tailing byte | |
1040 __ testl(count, 1); | |
1041 __ jccb(Assembler::zero, L_exit); | |
1042 __ movb(rax, Address(from, 0)); | |
1043 __ movb(Address(from, to_from, Address::times_1, 0), rax); | |
1044 __ BIND(L_exit); | |
1045 } else { | |
1046 __ BIND(L_copy_byte); | |
1047 } | |
1048 } else { | |
1049 __ BIND(L_copy_2_bytes); | |
1050 } | |
1051 | |
1052 if (t == T_OBJECT) { | |
1053 __ movl(count, Address(rsp, 12+12)); // reread 'count' | |
304 | 1054 __ mov(to, saved_to); // restore 'to' |
0 | 1055 gen_write_ref_array_post_barrier(to, count); |
1056 __ BIND(L_0_count); | |
1057 } | |
1058 inc_copy_counter_np(t); | |
304 | 1059 __ pop(rdi); |
1060 __ pop(rsi); | |
0 | 1061 __ leave(); // required for proper stackwalking of RuntimeStub frame |
304 | 1062 __ xorptr(rax, rax); // return 0 |
0 | 1063 __ ret(0); |
1064 return start; | |
1065 } | |
1066 | |
1067 | |
1763 | 1068 address generate_fill(BasicType t, bool aligned, const char *name) { |
1069 __ align(CodeEntryAlignment); | |
1070 StubCodeMark mark(this, "StubRoutines", name); | |
1071 address start = __ pc(); | |
1072 | |
1073 BLOCK_COMMENT("Entry:"); | |
1074 | |
1075 const Register to = rdi; // source array address | |
1076 const Register value = rdx; // value | |
1077 const Register count = rsi; // elements count | |
1078 | |
1079 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
1080 __ push(rsi); | |
1081 __ push(rdi); | |
1082 __ movptr(to , Address(rsp, 12+ 4)); | |
1083 __ movl(value, Address(rsp, 12+ 8)); | |
1084 __ movl(count, Address(rsp, 12+ 12)); | |
1085 | |
1086 __ generate_fill(t, aligned, to, value, count, rax, xmm0); | |
1087 | |
1088 __ pop(rdi); | |
1089 __ pop(rsi); | |
1090 __ leave(); // required for proper stackwalking of RuntimeStub frame | |
1091 __ ret(0); | |
1092 return start; | |
1093 } | |
1094 | |
0 | 1095 address generate_conjoint_copy(BasicType t, bool aligned, |
1096 Address::ScaleFactor sf, | |
1097 address nooverlap_target, | |
1098 address* entry, const char *name) { | |
1099 __ align(CodeEntryAlignment); | |
1100 StubCodeMark mark(this, "StubRoutines", name); | |
1101 address start = __ pc(); | |
1102 | |
1103 Label L_0_count, L_exit, L_skip_align1, L_skip_align2, L_copy_byte; | |
1104 Label L_copy_2_bytes, L_copy_4_bytes, L_copy_8_bytes, L_copy_8_bytes_loop; | |
1105 | |
304 | 1106 int shift = Address::times_ptr - sf; |
0 | 1107 |
1108 const Register src = rax; // source array address | |
1109 const Register dst = rdx; // destination array address | |
1110 const Register from = rsi; // source array address | |
1111 const Register to = rdi; // destination array address | |
1112 const Register count = rcx; // elements count | |
1113 const Register end = rax; // array end address | |
1114 | |
1115 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1116 __ push(rsi); |
1117 __ push(rdi); | |
1118 __ movptr(src , Address(rsp, 12+ 4)); // from | |
1119 __ movptr(dst , Address(rsp, 12+ 8)); // to | |
1120 __ movl2ptr(count, Address(rsp, 12+12)); // count | |
0 | 1121 if (t == T_OBJECT) { |
1122 gen_write_ref_array_pre_barrier(dst, count); | |
1123 } | |
1124 | |
1125 if (entry != NULL) { | |
1126 *entry = __ pc(); // Entry point from generic arraycopy stub. | |
1127 BLOCK_COMMENT("Entry:"); | |
1128 } | |
1129 | |
1130 if (t == T_OBJECT) { | |
1131 __ testl(count, count); | |
1132 __ jcc(Assembler::zero, L_0_count); | |
1133 } | |
304 | 1134 __ mov(from, src); |
1135 __ mov(to , dst); | |
0 | 1136 |
1137 // arrays overlap test | |
1138 RuntimeAddress nooverlap(nooverlap_target); | |
304 | 1139 __ cmpptr(dst, src); |
1140 __ lea(end, Address(src, count, sf, 0)); // src + count * elem_size | |
0 | 1141 __ jump_cc(Assembler::belowEqual, nooverlap); |
304 | 1142 __ cmpptr(dst, end); |
0 | 1143 __ jump_cc(Assembler::aboveEqual, nooverlap); |
1144 | |
1145 // copy from high to low | |
1146 __ cmpl(count, 2<<shift); // Short arrays (< 8 bytes) copy by element | |
1147 __ jcc(Assembler::below, L_copy_4_bytes); // use unsigned cmp | |
1148 if (t == T_BYTE || t == T_SHORT) { | |
1149 // Align the end of destination array at 4 bytes address boundary | |
304 | 1150 __ lea(end, Address(dst, count, sf, 0)); |
0 | 1151 if (t == T_BYTE) { |
1152 // One byte misalignment happens only for byte arrays | |
1153 __ testl(end, 1); | |
1154 __ jccb(Assembler::zero, L_skip_align1); | |
1155 __ decrement(count); | |
1156 __ movb(rdx, Address(from, count, sf, 0)); | |
1157 __ movb(Address(to, count, sf, 0), rdx); | |
1158 __ BIND(L_skip_align1); | |
1159 } | |
1160 // Two bytes misalignment happens only for byte and short (char) arrays | |
1161 __ testl(end, 2); | |
1162 __ jccb(Assembler::zero, L_skip_align2); | |
304 | 1163 __ subptr(count, 1<<(shift-1)); |
0 | 1164 __ movw(rdx, Address(from, count, sf, 0)); |
1165 __ movw(Address(to, count, sf, 0), rdx); | |
1166 __ BIND(L_skip_align2); | |
1167 __ cmpl(count, 2<<shift); // Short arrays (< 8 bytes) copy by element | |
1168 __ jcc(Assembler::below, L_copy_4_bytes); | |
1169 } | |
1170 | |
1171 if (!VM_Version::supports_mmx()) { | |
1172 __ std(); | |
304 | 1173 __ mov(rax, count); // Save 'count' |
1174 __ mov(rdx, to); // Save 'to' | |
1175 __ lea(rsi, Address(from, count, sf, -4)); | |
1176 __ lea(rdi, Address(to , count, sf, -4)); | |
1177 __ shrptr(count, shift); // bytes count | |
1178 __ rep_mov(); | |
0 | 1179 __ cld(); |
304 | 1180 __ mov(count, rax); // restore 'count' |
0 | 1181 __ andl(count, (1<<shift)-1); // mask the number of rest elements |
304 | 1182 __ movptr(from, Address(rsp, 12+4)); // reread 'from' |
1183 __ mov(to, rdx); // restore 'to' | |
0 | 1184 __ jmpb(L_copy_2_bytes); // all dword were copied |
1185 } else { | |
1186 // Align to 8 bytes the end of array. It is aligned to 4 bytes already. | |
304 | 1187 __ testptr(end, 4); |
0 | 1188 __ jccb(Assembler::zero, L_copy_8_bytes); |
1189 __ subl(count, 1<<shift); | |
1190 __ movl(rdx, Address(from, count, sf, 0)); | |
1191 __ movl(Address(to, count, sf, 0), rdx); | |
1192 __ jmpb(L_copy_8_bytes); | |
1193 | |
1365 | 1194 __ align(OptoLoopAlignment); |
0 | 1195 // Move 8 bytes |
1196 __ BIND(L_copy_8_bytes_loop); | |
405 | 1197 if (UseXMMForArrayCopy) { |
1198 __ movq(xmm0, Address(from, count, sf, 0)); | |
1199 __ movq(Address(to, count, sf, 0), xmm0); | |
1200 } else { | |
1201 __ movq(mmx0, Address(from, count, sf, 0)); | |
1202 __ movq(Address(to, count, sf, 0), mmx0); | |
1203 } | |
0 | 1204 __ BIND(L_copy_8_bytes); |
1205 __ subl(count, 2<<shift); | |
1206 __ jcc(Assembler::greaterEqual, L_copy_8_bytes_loop); | |
1207 __ addl(count, 2<<shift); | |
405 | 1208 if (!UseXMMForArrayCopy) { |
1209 __ emms(); | |
1210 } | |
0 | 1211 } |
1212 __ BIND(L_copy_4_bytes); | |
1213 // copy prefix qword | |
1214 __ testl(count, 1<<shift); | |
1215 __ jccb(Assembler::zero, L_copy_2_bytes); | |
1216 __ movl(rdx, Address(from, count, sf, -4)); | |
1217 __ movl(Address(to, count, sf, -4), rdx); | |
1218 | |
1219 if (t == T_BYTE || t == T_SHORT) { | |
1220 __ subl(count, (1<<shift)); | |
1221 __ BIND(L_copy_2_bytes); | |
1222 // copy prefix dword | |
1223 __ testl(count, 1<<(shift-1)); | |
1224 __ jccb(Assembler::zero, L_copy_byte); | |
1225 __ movw(rdx, Address(from, count, sf, -2)); | |
1226 __ movw(Address(to, count, sf, -2), rdx); | |
1227 if (t == T_BYTE) { | |
1228 __ subl(count, 1<<(shift-1)); | |
1229 __ BIND(L_copy_byte); | |
1230 // copy prefix byte | |
1231 __ testl(count, 1); | |
1232 __ jccb(Assembler::zero, L_exit); | |
1233 __ movb(rdx, Address(from, 0)); | |
1234 __ movb(Address(to, 0), rdx); | |
1235 __ BIND(L_exit); | |
1236 } else { | |
1237 __ BIND(L_copy_byte); | |
1238 } | |
1239 } else { | |
1240 __ BIND(L_copy_2_bytes); | |
1241 } | |
1242 if (t == T_OBJECT) { | |
304 | 1243 __ movl2ptr(count, Address(rsp, 12+12)); // reread count |
0 | 1244 gen_write_ref_array_post_barrier(to, count); |
1245 __ BIND(L_0_count); | |
1246 } | |
1247 inc_copy_counter_np(t); | |
304 | 1248 __ pop(rdi); |
1249 __ pop(rsi); | |
0 | 1250 __ leave(); // required for proper stackwalking of RuntimeStub frame |
304 | 1251 __ xorptr(rax, rax); // return 0 |
0 | 1252 __ ret(0); |
1253 return start; | |
1254 } | |
1255 | |
1256 | |
1257 address generate_disjoint_long_copy(address* entry, const char *name) { | |
1258 __ align(CodeEntryAlignment); | |
1259 StubCodeMark mark(this, "StubRoutines", name); | |
1260 address start = __ pc(); | |
1261 | |
1262 Label L_copy_8_bytes, L_copy_8_bytes_loop; | |
1263 const Register from = rax; // source array address | |
1264 const Register to = rdx; // destination array address | |
1265 const Register count = rcx; // elements count | |
1266 const Register to_from = rdx; // (to - from) | |
1267 | |
1268 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1269 __ movptr(from , Address(rsp, 8+0)); // from |
1270 __ movptr(to , Address(rsp, 8+4)); // to | |
1271 __ movl2ptr(count, Address(rsp, 8+8)); // count | |
0 | 1272 |
1273 *entry = __ pc(); // Entry point from conjoint arraycopy stub. | |
1274 BLOCK_COMMENT("Entry:"); | |
1275 | |
304 | 1276 __ subptr(to, from); // to --> to_from |
0 | 1277 if (VM_Version::supports_mmx()) { |
405 | 1278 if (UseXMMForArrayCopy) { |
1279 xmm_copy_forward(from, to_from, count); | |
1280 } else { | |
1281 mmx_copy_forward(from, to_from, count); | |
1282 } | |
0 | 1283 } else { |
1284 __ jmpb(L_copy_8_bytes); | |
1365 | 1285 __ align(OptoLoopAlignment); |
0 | 1286 __ BIND(L_copy_8_bytes_loop); |
1287 __ fild_d(Address(from, 0)); | |
1288 __ fistp_d(Address(from, to_from, Address::times_1)); | |
304 | 1289 __ addptr(from, 8); |
0 | 1290 __ BIND(L_copy_8_bytes); |
1291 __ decrement(count); | |
1292 __ jcc(Assembler::greaterEqual, L_copy_8_bytes_loop); | |
1293 } | |
1294 inc_copy_counter_np(T_LONG); | |
1295 __ leave(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1296 __ xorptr(rax, rax); // return 0 |
0 | 1297 __ ret(0); |
1298 return start; | |
1299 } | |
1300 | |
1301 address generate_conjoint_long_copy(address nooverlap_target, | |
1302 address* entry, const char *name) { | |
1303 __ align(CodeEntryAlignment); | |
1304 StubCodeMark mark(this, "StubRoutines", name); | |
1305 address start = __ pc(); | |
1306 | |
1307 Label L_copy_8_bytes, L_copy_8_bytes_loop; | |
1308 const Register from = rax; // source array address | |
1309 const Register to = rdx; // destination array address | |
1310 const Register count = rcx; // elements count | |
1311 const Register end_from = rax; // source array end address | |
1312 | |
1313 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1314 __ movptr(from , Address(rsp, 8+0)); // from |
1315 __ movptr(to , Address(rsp, 8+4)); // to | |
1316 __ movl2ptr(count, Address(rsp, 8+8)); // count | |
0 | 1317 |
1318 *entry = __ pc(); // Entry point from generic arraycopy stub. | |
1319 BLOCK_COMMENT("Entry:"); | |
1320 | |
1321 // arrays overlap test | |
304 | 1322 __ cmpptr(to, from); |
0 | 1323 RuntimeAddress nooverlap(nooverlap_target); |
1324 __ jump_cc(Assembler::belowEqual, nooverlap); | |
304 | 1325 __ lea(end_from, Address(from, count, Address::times_8, 0)); |
1326 __ cmpptr(to, end_from); | |
1327 __ movptr(from, Address(rsp, 8)); // from | |
0 | 1328 __ jump_cc(Assembler::aboveEqual, nooverlap); |
1329 | |
1330 __ jmpb(L_copy_8_bytes); | |
1331 | |
1365 | 1332 __ align(OptoLoopAlignment); |
0 | 1333 __ BIND(L_copy_8_bytes_loop); |
1334 if (VM_Version::supports_mmx()) { | |
405 | 1335 if (UseXMMForArrayCopy) { |
1336 __ movq(xmm0, Address(from, count, Address::times_8)); | |
1337 __ movq(Address(to, count, Address::times_8), xmm0); | |
1338 } else { | |
1339 __ movq(mmx0, Address(from, count, Address::times_8)); | |
1340 __ movq(Address(to, count, Address::times_8), mmx0); | |
1341 } | |
0 | 1342 } else { |
1343 __ fild_d(Address(from, count, Address::times_8)); | |
1344 __ fistp_d(Address(to, count, Address::times_8)); | |
1345 } | |
1346 __ BIND(L_copy_8_bytes); | |
1347 __ decrement(count); | |
1348 __ jcc(Assembler::greaterEqual, L_copy_8_bytes_loop); | |
1349 | |
405 | 1350 if (VM_Version::supports_mmx() && !UseXMMForArrayCopy) { |
0 | 1351 __ emms(); |
1352 } | |
1353 inc_copy_counter_np(T_LONG); | |
1354 __ leave(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1355 __ xorptr(rax, rax); // return 0 |
0 | 1356 __ ret(0); |
1357 return start; | |
1358 } | |
1359 | |
1360 | |
1361 // Helper for generating a dynamic type check. | |
1362 // The sub_klass must be one of {rbx, rdx, rsi}. | |
1363 // The temp is killed. | |
1364 void generate_type_check(Register sub_klass, | |
1365 Address& super_check_offset_addr, | |
1366 Address& super_klass_addr, | |
1367 Register temp, | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1368 Label* L_success, Label* L_failure) { |
0 | 1369 BLOCK_COMMENT("type_check:"); |
1370 | |
1371 Label L_fallthrough; | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1372 #define LOCAL_JCC(assembler_con, label_ptr) \ |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1373 if (label_ptr != NULL) __ jcc(assembler_con, *(label_ptr)); \ |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1374 else __ jcc(assembler_con, L_fallthrough) /*omit semi*/ |
0 | 1375 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1376 // The following is a strange variation of the fast path which requires |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1377 // one less register, because needed values are on the argument stack. |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1378 // __ check_klass_subtype_fast_path(sub_klass, *super_klass*, temp, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1379 // L_success, L_failure, NULL); |
0 | 1380 assert_different_registers(sub_klass, temp); |
1381 | |
1382 int sc_offset = (klassOopDesc::header_size() * HeapWordSize + | |
1383 Klass::secondary_super_cache_offset_in_bytes()); | |
1384 | |
1385 // if the pointers are equal, we are done (e.g., String[] elements) | |
304 | 1386 __ cmpptr(sub_klass, super_klass_addr); |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1387 LOCAL_JCC(Assembler::equal, L_success); |
0 | 1388 |
1389 // check the supertype display: | |
304 | 1390 __ movl2ptr(temp, super_check_offset_addr); |
0 | 1391 Address super_check_addr(sub_klass, temp, Address::times_1, 0); |
304 | 1392 __ movptr(temp, super_check_addr); // load displayed supertype |
1393 __ cmpptr(temp, super_klass_addr); // test the super type | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1394 LOCAL_JCC(Assembler::equal, L_success); |
0 | 1395 |
1396 // if it was a primary super, we can just fail immediately | |
1397 __ cmpl(super_check_offset_addr, sc_offset); | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1398 LOCAL_JCC(Assembler::notEqual, L_failure); |
0 | 1399 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1400 // The repne_scan instruction uses fixed registers, which will get spilled. |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1401 // We happen to know this works best when super_klass is in rax. |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1402 Register super_klass = temp; |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1403 __ movptr(super_klass, super_klass_addr); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1404 __ check_klass_subtype_slow_path(sub_klass, super_klass, noreg, noreg, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1405 L_success, L_failure); |
0 | 1406 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1407 __ bind(L_fallthrough); |
0 | 1408 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1409 if (L_success == NULL) { BLOCK_COMMENT("L_success:"); } |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1410 if (L_failure == NULL) { BLOCK_COMMENT("L_failure:"); } |
0 | 1411 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
533
diff
changeset
|
1412 #undef LOCAL_JCC |
0 | 1413 } |
1414 | |
1415 // | |
1416 // Generate checkcasting array copy stub | |
1417 // | |
1418 // Input: | |
1419 // 4(rsp) - source array address | |
1420 // 8(rsp) - destination array address | |
1421 // 12(rsp) - element count, can be zero | |
1422 // 16(rsp) - size_t ckoff (super_check_offset) | |
1423 // 20(rsp) - oop ckval (super_klass) | |
1424 // | |
1425 // Output: | |
1426 // rax, == 0 - success | |
1427 // rax, == -1^K - failure, where K is partial transfer count | |
1428 // | |
1429 address generate_checkcast_copy(const char *name, address* entry) { | |
1430 __ align(CodeEntryAlignment); | |
1431 StubCodeMark mark(this, "StubRoutines", name); | |
1432 address start = __ pc(); | |
1433 | |
1434 Label L_load_element, L_store_element, L_do_card_marks, L_done; | |
1435 | |
1436 // register use: | |
1437 // rax, rdx, rcx -- loop control (end_from, end_to, count) | |
1438 // rdi, rsi -- element access (oop, klass) | |
1439 // rbx, -- temp | |
1440 const Register from = rax; // source array address | |
1441 const Register to = rdx; // destination array address | |
1442 const Register length = rcx; // elements count | |
1443 const Register elem = rdi; // each oop copied | |
1444 const Register elem_klass = rsi; // each elem._klass (sub_klass) | |
1445 const Register temp = rbx; // lone remaining temp | |
1446 | |
1447 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
1448 | |
304 | 1449 __ push(rsi); |
1450 __ push(rdi); | |
1451 __ push(rbx); | |
0 | 1452 |
1453 Address from_arg(rsp, 16+ 4); // from | |
1454 Address to_arg(rsp, 16+ 8); // to | |
1455 Address length_arg(rsp, 16+12); // elements count | |
1456 Address ckoff_arg(rsp, 16+16); // super_check_offset | |
1457 Address ckval_arg(rsp, 16+20); // super_klass | |
1458 | |
1459 // Load up: | |
304 | 1460 __ movptr(from, from_arg); |
1461 __ movptr(to, to_arg); | |
1462 __ movl2ptr(length, length_arg); | |
0 | 1463 |
1464 *entry = __ pc(); // Entry point from generic arraycopy stub. | |
1465 BLOCK_COMMENT("Entry:"); | |
1466 | |
1467 //--------------------------------------------------------------- | |
1468 // Assembler stub will be used for this call to arraycopy | |
1469 // if the two arrays are subtypes of Object[] but the | |
1470 // destination array type is not equal to or a supertype | |
1471 // of the source type. Each element must be separately | |
1472 // checked. | |
1473 | |
1474 // Loop-invariant addresses. They are exclusive end pointers. | |
304 | 1475 Address end_from_addr(from, length, Address::times_ptr, 0); |
1476 Address end_to_addr(to, length, Address::times_ptr, 0); | |
0 | 1477 |
1478 Register end_from = from; // re-use | |
1479 Register end_to = to; // re-use | |
1480 Register count = length; // re-use | |
1481 | |
1482 // Loop-variant addresses. They assume post-incremented count < 0. | |
304 | 1483 Address from_element_addr(end_from, count, Address::times_ptr, 0); |
1484 Address to_element_addr(end_to, count, Address::times_ptr, 0); | |
0 | 1485 Address elem_klass_addr(elem, oopDesc::klass_offset_in_bytes()); |
1486 | |
1487 // Copy from low to high addresses, indexed from the end of each array. | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
19
diff
changeset
|
1488 gen_write_ref_array_pre_barrier(to, count); |
304 | 1489 __ lea(end_from, end_from_addr); |
1490 __ lea(end_to, end_to_addr); | |
0 | 1491 assert(length == count, ""); // else fix next line: |
304 | 1492 __ negptr(count); // negate and test the length |
0 | 1493 __ jccb(Assembler::notZero, L_load_element); |
1494 | |
1495 // Empty array: Nothing to do. | |
304 | 1496 __ xorptr(rax, rax); // return 0 on (trivial) success |
0 | 1497 __ jmp(L_done); |
1498 | |
1499 // ======== begin loop ======== | |
1500 // (Loop is rotated; its entry is L_load_element.) | |
1501 // Loop control: | |
1502 // for (count = -count; count != 0; count++) | |
1503 // Base pointers src, dst are biased by 8*count,to last element. | |
1365 | 1504 __ align(OptoLoopAlignment); |
0 | 1505 |
1506 __ BIND(L_store_element); | |
304 | 1507 __ movptr(to_element_addr, elem); // store the oop |
0 | 1508 __ increment(count); // increment the count toward zero |
1509 __ jccb(Assembler::zero, L_do_card_marks); | |
1510 | |
1511 // ======== loop entry is here ======== | |
1512 __ BIND(L_load_element); | |
304 | 1513 __ movptr(elem, from_element_addr); // load the oop |
1514 __ testptr(elem, elem); | |
0 | 1515 __ jccb(Assembler::zero, L_store_element); |
1516 | |
1517 // (Could do a trick here: Remember last successful non-null | |
1518 // element stored and make a quick oop equality check on it.) | |
1519 | |
304 | 1520 __ movptr(elem_klass, elem_klass_addr); // query the object klass |
0 | 1521 generate_type_check(elem_klass, ckoff_arg, ckval_arg, temp, |
1522 &L_store_element, NULL); | |
1523 // (On fall-through, we have failed the element type check.) | |
1524 // ======== end loop ======== | |
1525 | |
1526 // It was a real error; we must depend on the caller to finish the job. | |
19
a73cc31728fe
6614036: REGRESSION: Java server x86 VM intermittently crash with SIGSEGV (0xb)
rasbold
parents:
16
diff
changeset
|
1527 // Register "count" = -1 * number of *remaining* oops, length_arg = *total* oops. |
a73cc31728fe
6614036: REGRESSION: Java server x86 VM intermittently crash with SIGSEGV (0xb)
rasbold
parents:
16
diff
changeset
|
1528 // Emit GC store barriers for the oops we have copied (length_arg + count), |
0 | 1529 // and report their number to the caller. |
1530 __ addl(count, length_arg); // transfers = (length - remaining) | |
304 | 1531 __ movl2ptr(rax, count); // save the value |
1532 __ notptr(rax); // report (-1^K) to caller | |
1533 __ movptr(to, to_arg); // reload | |
0 | 1534 assert_different_registers(to, count, rax); |
1535 gen_write_ref_array_post_barrier(to, count); | |
1536 __ jmpb(L_done); | |
1537 | |
1538 // Come here on success only. | |
1539 __ BIND(L_do_card_marks); | |
304 | 1540 __ movl2ptr(count, length_arg); |
1541 __ movptr(to, to_arg); // reload | |
0 | 1542 gen_write_ref_array_post_barrier(to, count); |
304 | 1543 __ xorptr(rax, rax); // return 0 on success |
0 | 1544 |
1545 // Common exit point (success or failure). | |
1546 __ BIND(L_done); | |
304 | 1547 __ pop(rbx); |
1548 __ pop(rdi); | |
1549 __ pop(rsi); | |
0 | 1550 inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); |
1551 __ leave(); // required for proper stackwalking of RuntimeStub frame | |
1552 __ ret(0); | |
1553 | |
1554 return start; | |
1555 } | |
1556 | |
1557 // | |
1558 // Generate 'unsafe' array copy stub | |
1559 // Though just as safe as the other stubs, it takes an unscaled | |
1560 // size_t argument instead of an element count. | |
1561 // | |
1562 // Input: | |
1563 // 4(rsp) - source array address | |
1564 // 8(rsp) - destination array address | |
1565 // 12(rsp) - byte count, can be zero | |
1566 // | |
1567 // Output: | |
1568 // rax, == 0 - success | |
1569 // rax, == -1 - need to call System.arraycopy | |
1570 // | |
1571 // Examines the alignment of the operands and dispatches | |
1572 // to a long, int, short, or byte copy loop. | |
1573 // | |
1574 address generate_unsafe_copy(const char *name, | |
1575 address byte_copy_entry, | |
1576 address short_copy_entry, | |
1577 address int_copy_entry, | |
1578 address long_copy_entry) { | |
1579 | |
1580 Label L_long_aligned, L_int_aligned, L_short_aligned; | |
1581 | |
1582 __ align(CodeEntryAlignment); | |
1583 StubCodeMark mark(this, "StubRoutines", name); | |
1584 address start = __ pc(); | |
1585 | |
1586 const Register from = rax; // source array address | |
1587 const Register to = rdx; // destination array address | |
1588 const Register count = rcx; // elements count | |
1589 | |
1590 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1591 __ push(rsi); |
1592 __ push(rdi); | |
0 | 1593 Address from_arg(rsp, 12+ 4); // from |
1594 Address to_arg(rsp, 12+ 8); // to | |
1595 Address count_arg(rsp, 12+12); // byte count | |
1596 | |
1597 // Load up: | |
304 | 1598 __ movptr(from , from_arg); |
1599 __ movptr(to , to_arg); | |
1600 __ movl2ptr(count, count_arg); | |
0 | 1601 |
1602 // bump this on entry, not on exit: | |
1603 inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr); | |
1604 | |
1605 const Register bits = rsi; | |
304 | 1606 __ mov(bits, from); |
1607 __ orptr(bits, to); | |
1608 __ orptr(bits, count); | |
0 | 1609 |
1610 __ testl(bits, BytesPerLong-1); | |
1611 __ jccb(Assembler::zero, L_long_aligned); | |
1612 | |
1613 __ testl(bits, BytesPerInt-1); | |
1614 __ jccb(Assembler::zero, L_int_aligned); | |
1615 | |
1616 __ testl(bits, BytesPerShort-1); | |
1617 __ jump_cc(Assembler::notZero, RuntimeAddress(byte_copy_entry)); | |
1618 | |
1619 __ BIND(L_short_aligned); | |
304 | 1620 __ shrptr(count, LogBytesPerShort); // size => short_count |
0 | 1621 __ movl(count_arg, count); // update 'count' |
1622 __ jump(RuntimeAddress(short_copy_entry)); | |
1623 | |
1624 __ BIND(L_int_aligned); | |
304 | 1625 __ shrptr(count, LogBytesPerInt); // size => int_count |
0 | 1626 __ movl(count_arg, count); // update 'count' |
1627 __ jump(RuntimeAddress(int_copy_entry)); | |
1628 | |
1629 __ BIND(L_long_aligned); | |
304 | 1630 __ shrptr(count, LogBytesPerLong); // size => qword_count |
0 | 1631 __ movl(count_arg, count); // update 'count' |
304 | 1632 __ pop(rdi); // Do pops here since jlong_arraycopy stub does not do it. |
1633 __ pop(rsi); | |
0 | 1634 __ jump(RuntimeAddress(long_copy_entry)); |
1635 | |
1636 return start; | |
1637 } | |
1638 | |
1639 | |
1640 // Perform range checks on the proposed arraycopy. | |
1641 // Smashes src_pos and dst_pos. (Uses them up for temps.) | |
1642 void arraycopy_range_checks(Register src, | |
1643 Register src_pos, | |
1644 Register dst, | |
1645 Register dst_pos, | |
1646 Address& length, | |
1647 Label& L_failed) { | |
1648 BLOCK_COMMENT("arraycopy_range_checks:"); | |
1649 const Register src_end = src_pos; // source array end position | |
1650 const Register dst_end = dst_pos; // destination array end position | |
1651 __ addl(src_end, length); // src_pos + length | |
1652 __ addl(dst_end, length); // dst_pos + length | |
1653 | |
1654 // if (src_pos + length > arrayOop(src)->length() ) FAIL; | |
1655 __ cmpl(src_end, Address(src, arrayOopDesc::length_offset_in_bytes())); | |
1656 __ jcc(Assembler::above, L_failed); | |
1657 | |
1658 // if (dst_pos + length > arrayOop(dst)->length() ) FAIL; | |
1659 __ cmpl(dst_end, Address(dst, arrayOopDesc::length_offset_in_bytes())); | |
1660 __ jcc(Assembler::above, L_failed); | |
1661 | |
1662 BLOCK_COMMENT("arraycopy_range_checks done"); | |
1663 } | |
1664 | |
1665 | |
1666 // | |
1667 // Generate generic array copy stubs | |
1668 // | |
1669 // Input: | |
1670 // 4(rsp) - src oop | |
1671 // 8(rsp) - src_pos | |
1672 // 12(rsp) - dst oop | |
1673 // 16(rsp) - dst_pos | |
1674 // 20(rsp) - element count | |
1675 // | |
1676 // Output: | |
1677 // rax, == 0 - success | |
1678 // rax, == -1^K - failure, where K is partial transfer count | |
1679 // | |
1680 address generate_generic_copy(const char *name, | |
1681 address entry_jbyte_arraycopy, | |
1682 address entry_jshort_arraycopy, | |
1683 address entry_jint_arraycopy, | |
1684 address entry_oop_arraycopy, | |
1685 address entry_jlong_arraycopy, | |
1686 address entry_checkcast_arraycopy) { | |
1687 Label L_failed, L_failed_0, L_objArray; | |
1688 | |
1689 { int modulus = CodeEntryAlignment; | |
1690 int target = modulus - 5; // 5 = sizeof jmp(L_failed) | |
1691 int advance = target - (__ offset() % modulus); | |
1692 if (advance < 0) advance += modulus; | |
1693 if (advance > 0) __ nop(advance); | |
1694 } | |
1695 StubCodeMark mark(this, "StubRoutines", name); | |
1696 | |
1697 // Short-hop target to L_failed. Makes for denser prologue code. | |
1698 __ BIND(L_failed_0); | |
1699 __ jmp(L_failed); | |
1700 assert(__ offset() % CodeEntryAlignment == 0, "no further alignment needed"); | |
1701 | |
1702 __ align(CodeEntryAlignment); | |
1703 address start = __ pc(); | |
1704 | |
1705 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
304 | 1706 __ push(rsi); |
1707 __ push(rdi); | |
0 | 1708 |
1709 // bump this on entry, not on exit: | |
1710 inc_counter_np(SharedRuntime::_generic_array_copy_ctr); | |
1711 | |
1712 // Input values | |
1713 Address SRC (rsp, 12+ 4); | |
1714 Address SRC_POS (rsp, 12+ 8); | |
1715 Address DST (rsp, 12+12); | |
1716 Address DST_POS (rsp, 12+16); | |
1717 Address LENGTH (rsp, 12+20); | |
1718 | |
1719 //----------------------------------------------------------------------- | |
1720 // Assembler stub will be used for this call to arraycopy | |
1721 // if the following conditions are met: | |
1722 // | |
1723 // (1) src and dst must not be null. | |
1724 // (2) src_pos must not be negative. | |
1725 // (3) dst_pos must not be negative. | |
1726 // (4) length must not be negative. | |
1727 // (5) src klass and dst klass should be the same and not NULL. | |
1728 // (6) src and dst should be arrays. | |
1729 // (7) src_pos + length must not exceed length of src. | |
1730 // (8) dst_pos + length must not exceed length of dst. | |
1731 // | |
1732 | |
1733 const Register src = rax; // source array oop | |
1734 const Register src_pos = rsi; | |
1735 const Register dst = rdx; // destination array oop | |
1736 const Register dst_pos = rdi; | |
1737 const Register length = rcx; // transfer count | |
1738 | |
1739 // if (src == NULL) return -1; | |
304 | 1740 __ movptr(src, SRC); // src oop |
1741 __ testptr(src, src); | |
0 | 1742 __ jccb(Assembler::zero, L_failed_0); |
1743 | |
1744 // if (src_pos < 0) return -1; | |
304 | 1745 __ movl2ptr(src_pos, SRC_POS); // src_pos |
0 | 1746 __ testl(src_pos, src_pos); |
1747 __ jccb(Assembler::negative, L_failed_0); | |
1748 | |
1749 // if (dst == NULL) return -1; | |
304 | 1750 __ movptr(dst, DST); // dst oop |
1751 __ testptr(dst, dst); | |
0 | 1752 __ jccb(Assembler::zero, L_failed_0); |
1753 | |
1754 // if (dst_pos < 0) return -1; | |
304 | 1755 __ movl2ptr(dst_pos, DST_POS); // dst_pos |
0 | 1756 __ testl(dst_pos, dst_pos); |
1757 __ jccb(Assembler::negative, L_failed_0); | |
1758 | |
1759 // if (length < 0) return -1; | |
304 | 1760 __ movl2ptr(length, LENGTH); // length |
0 | 1761 __ testl(length, length); |
1762 __ jccb(Assembler::negative, L_failed_0); | |
1763 | |
1764 // if (src->klass() == NULL) return -1; | |
1765 Address src_klass_addr(src, oopDesc::klass_offset_in_bytes()); | |
1766 Address dst_klass_addr(dst, oopDesc::klass_offset_in_bytes()); | |
1767 const Register rcx_src_klass = rcx; // array klass | |
304 | 1768 __ movptr(rcx_src_klass, Address(src, oopDesc::klass_offset_in_bytes())); |
0 | 1769 |
1770 #ifdef ASSERT | |
1771 // assert(src->klass() != NULL); | |
1772 BLOCK_COMMENT("assert klasses not null"); | |
1773 { Label L1, L2; | |
304 | 1774 __ testptr(rcx_src_klass, rcx_src_klass); |
0 | 1775 __ jccb(Assembler::notZero, L2); // it is broken if klass is NULL |
1776 __ bind(L1); | |
1777 __ stop("broken null klass"); | |
1778 __ bind(L2); | |
304 | 1779 __ cmpptr(dst_klass_addr, (int32_t)NULL_WORD); |
0 | 1780 __ jccb(Assembler::equal, L1); // this would be broken also |
1781 BLOCK_COMMENT("assert done"); | |
1782 } | |
1783 #endif //ASSERT | |
1784 | |
1785 // Load layout helper (32-bits) | |
1786 // | |
1787 // |array_tag| | header_size | element_type | |log2_element_size| | |
1788 // 32 30 24 16 8 2 0 | |
1789 // | |
1790 // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 | |
1791 // | |
1792 | |
1793 int lh_offset = klassOopDesc::header_size() * HeapWordSize + | |
1794 Klass::layout_helper_offset_in_bytes(); | |
1795 Address src_klass_lh_addr(rcx_src_klass, lh_offset); | |
1796 | |
1797 // Handle objArrays completely differently... | |
1798 jint objArray_lh = Klass::array_layout_helper(T_OBJECT); | |
1799 __ cmpl(src_klass_lh_addr, objArray_lh); | |
1800 __ jcc(Assembler::equal, L_objArray); | |
1801 | |
1802 // if (src->klass() != dst->klass()) return -1; | |
304 | 1803 __ cmpptr(rcx_src_klass, dst_klass_addr); |
0 | 1804 __ jccb(Assembler::notEqual, L_failed_0); |
1805 | |
1806 const Register rcx_lh = rcx; // layout helper | |
1807 assert(rcx_lh == rcx_src_klass, "known alias"); | |
1808 __ movl(rcx_lh, src_klass_lh_addr); | |
1809 | |
1810 // if (!src->is_Array()) return -1; | |
1811 __ cmpl(rcx_lh, Klass::_lh_neutral_value); | |
1812 __ jcc(Assembler::greaterEqual, L_failed_0); // signed cmp | |
1813 | |
1814 // At this point, it is known to be a typeArray (array_tag 0x3). | |
1815 #ifdef ASSERT | |
1816 { Label L; | |
1817 __ cmpl(rcx_lh, (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift)); | |
1818 __ jcc(Assembler::greaterEqual, L); // signed cmp | |
1819 __ stop("must be a primitive array"); | |
1820 __ bind(L); | |
1821 } | |
1822 #endif | |
1823 | |
1824 assert_different_registers(src, src_pos, dst, dst_pos, rcx_lh); | |
1825 arraycopy_range_checks(src, src_pos, dst, dst_pos, LENGTH, L_failed); | |
1826 | |
1827 // typeArrayKlass | |
1828 // | |
1829 // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); | |
1830 // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); | |
1831 // | |
1832 const Register rsi_offset = rsi; // array offset | |
1833 const Register src_array = src; // src array offset | |
1834 const Register dst_array = dst; // dst array offset | |
1835 const Register rdi_elsize = rdi; // log2 element size | |
1836 | |
304 | 1837 __ mov(rsi_offset, rcx_lh); |
1838 __ shrptr(rsi_offset, Klass::_lh_header_size_shift); | |
1839 __ andptr(rsi_offset, Klass::_lh_header_size_mask); // array_offset | |
1840 __ addptr(src_array, rsi_offset); // src array offset | |
1841 __ addptr(dst_array, rsi_offset); // dst array offset | |
1842 __ andptr(rcx_lh, Klass::_lh_log2_element_size_mask); // log2 elsize | |
0 | 1843 |
1844 // next registers should be set before the jump to corresponding stub | |
1845 const Register from = src; // source array address | |
1846 const Register to = dst; // destination array address | |
1847 const Register count = rcx; // elements count | |
1848 // some of them should be duplicated on stack | |
1849 #define FROM Address(rsp, 12+ 4) | |
1850 #define TO Address(rsp, 12+ 8) // Not used now | |
1851 #define COUNT Address(rsp, 12+12) // Only for oop arraycopy | |
1852 | |
1853 BLOCK_COMMENT("scale indexes to element size"); | |
304 | 1854 __ movl2ptr(rsi, SRC_POS); // src_pos |
1855 __ shlptr(rsi); // src_pos << rcx (log2 elsize) | |
0 | 1856 assert(src_array == from, ""); |
304 | 1857 __ addptr(from, rsi); // from = src_array + SRC_POS << log2 elsize |
1858 __ movl2ptr(rdi, DST_POS); // dst_pos | |
1859 __ shlptr(rdi); // dst_pos << rcx (log2 elsize) | |
0 | 1860 assert(dst_array == to, ""); |
304 | 1861 __ addptr(to, rdi); // to = dst_array + DST_POS << log2 elsize |
1862 __ movptr(FROM, from); // src_addr | |
1863 __ mov(rdi_elsize, rcx_lh); // log2 elsize | |
1864 __ movl2ptr(count, LENGTH); // elements count | |
0 | 1865 |
1866 BLOCK_COMMENT("choose copy loop based on element size"); | |
1867 __ cmpl(rdi_elsize, 0); | |
1868 | |
1869 __ jump_cc(Assembler::equal, RuntimeAddress(entry_jbyte_arraycopy)); | |
1870 __ cmpl(rdi_elsize, LogBytesPerShort); | |
1871 __ jump_cc(Assembler::equal, RuntimeAddress(entry_jshort_arraycopy)); | |
1872 __ cmpl(rdi_elsize, LogBytesPerInt); | |
1873 __ jump_cc(Assembler::equal, RuntimeAddress(entry_jint_arraycopy)); | |
1874 #ifdef ASSERT | |
1875 __ cmpl(rdi_elsize, LogBytesPerLong); | |
1876 __ jccb(Assembler::notEqual, L_failed); | |
1877 #endif | |
304 | 1878 __ pop(rdi); // Do pops here since jlong_arraycopy stub does not do it. |
1879 __ pop(rsi); | |
0 | 1880 __ jump(RuntimeAddress(entry_jlong_arraycopy)); |
1881 | |
1882 __ BIND(L_failed); | |
304 | 1883 __ xorptr(rax, rax); |
1884 __ notptr(rax); // return -1 | |
1885 __ pop(rdi); | |
1886 __ pop(rsi); | |
0 | 1887 __ leave(); // required for proper stackwalking of RuntimeStub frame |
1888 __ ret(0); | |
1889 | |
1890 // objArrayKlass | |
1891 __ BIND(L_objArray); | |
1892 // live at this point: rcx_src_klass, src[_pos], dst[_pos] | |
1893 | |
1894 Label L_plain_copy, L_checkcast_copy; | |
1895 // test array classes for subtyping | |
304 | 1896 __ cmpptr(rcx_src_klass, dst_klass_addr); // usual case is exact equality |
0 | 1897 __ jccb(Assembler::notEqual, L_checkcast_copy); |
1898 | |
1899 // Identically typed arrays can be copied without element-wise checks. | |
1900 assert_different_registers(src, src_pos, dst, dst_pos, rcx_src_klass); | |
1901 arraycopy_range_checks(src, src_pos, dst, dst_pos, LENGTH, L_failed); | |
1902 | |
1903 __ BIND(L_plain_copy); | |
304 | 1904 __ movl2ptr(count, LENGTH); // elements count |
1905 __ movl2ptr(src_pos, SRC_POS); // reload src_pos | |
1906 __ lea(from, Address(src, src_pos, Address::times_ptr, | |
1907 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); // src_addr | |
1908 __ movl2ptr(dst_pos, DST_POS); // reload dst_pos | |
1909 __ lea(to, Address(dst, dst_pos, Address::times_ptr, | |
1910 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); // dst_addr | |
1911 __ movptr(FROM, from); // src_addr | |
1912 __ movptr(TO, to); // dst_addr | |
0 | 1913 __ movl(COUNT, count); // count |
1914 __ jump(RuntimeAddress(entry_oop_arraycopy)); | |
1915 | |
1916 __ BIND(L_checkcast_copy); | |
1917 // live at this point: rcx_src_klass, dst[_pos], src[_pos] | |
1918 { | |
1919 // Handy offsets: | |
1920 int ek_offset = (klassOopDesc::header_size() * HeapWordSize + | |
1921 objArrayKlass::element_klass_offset_in_bytes()); | |
1922 int sco_offset = (klassOopDesc::header_size() * HeapWordSize + | |
1923 Klass::super_check_offset_offset_in_bytes()); | |
1924 | |
1925 Register rsi_dst_klass = rsi; | |
1926 Register rdi_temp = rdi; | |
1927 assert(rsi_dst_klass == src_pos, "expected alias w/ src_pos"); | |
1928 assert(rdi_temp == dst_pos, "expected alias w/ dst_pos"); | |
1929 Address dst_klass_lh_addr(rsi_dst_klass, lh_offset); | |
1930 | |
1931 // Before looking at dst.length, make sure dst is also an objArray. | |
304 | 1932 __ movptr(rsi_dst_klass, dst_klass_addr); |
0 | 1933 __ cmpl(dst_klass_lh_addr, objArray_lh); |
1934 __ jccb(Assembler::notEqual, L_failed); | |
1935 | |
1936 // It is safe to examine both src.length and dst.length. | |
304 | 1937 __ movl2ptr(src_pos, SRC_POS); // reload rsi |
0 | 1938 arraycopy_range_checks(src, src_pos, dst, dst_pos, LENGTH, L_failed); |
1939 // (Now src_pos and dst_pos are killed, but not src and dst.) | |
1940 | |
1941 // We'll need this temp (don't forget to pop it after the type check). | |
304 | 1942 __ push(rbx); |
0 | 1943 Register rbx_src_klass = rbx; |
1944 | |
304 | 1945 __ mov(rbx_src_klass, rcx_src_klass); // spill away from rcx |
1946 __ movptr(rsi_dst_klass, dst_klass_addr); | |
0 | 1947 Address super_check_offset_addr(rsi_dst_klass, sco_offset); |
1948 Label L_fail_array_check; | |
1949 generate_type_check(rbx_src_klass, | |
1950 super_check_offset_addr, dst_klass_addr, | |
1951 rdi_temp, NULL, &L_fail_array_check); | |
1952 // (On fall-through, we have passed the array type check.) | |
304 | 1953 __ pop(rbx); |
0 | 1954 __ jmp(L_plain_copy); |
1955 | |
1956 __ BIND(L_fail_array_check); | |
1957 // Reshuffle arguments so we can call checkcast_arraycopy: | |
1958 | |
1959 // match initial saves for checkcast_arraycopy | |
304 | 1960 // push(rsi); // already done; see above |
1961 // push(rdi); // already done; see above | |
1962 // push(rbx); // already done; see above | |
0 | 1963 |
1964 // Marshal outgoing arguments now, freeing registers. | |
1965 Address from_arg(rsp, 16+ 4); // from | |
1966 Address to_arg(rsp, 16+ 8); // to | |
1967 Address length_arg(rsp, 16+12); // elements count | |
1968 Address ckoff_arg(rsp, 16+16); // super_check_offset | |
1969 Address ckval_arg(rsp, 16+20); // super_klass | |
1970 | |
1971 Address SRC_POS_arg(rsp, 16+ 8); | |
1972 Address DST_POS_arg(rsp, 16+16); | |
1973 Address LENGTH_arg(rsp, 16+20); | |
1974 // push rbx, changed the incoming offsets (why not just use rbp,??) | |
1975 // assert(SRC_POS_arg.disp() == SRC_POS.disp() + 4, ""); | |
1976 | |
304 | 1977 __ movptr(rbx, Address(rsi_dst_klass, ek_offset)); |
1978 __ movl2ptr(length, LENGTH_arg); // reload elements count | |
1979 __ movl2ptr(src_pos, SRC_POS_arg); // reload src_pos | |
1980 __ movl2ptr(dst_pos, DST_POS_arg); // reload dst_pos | |
0 | 1981 |
304 | 1982 __ movptr(ckval_arg, rbx); // destination element type |
0 | 1983 __ movl(rbx, Address(rbx, sco_offset)); |
1984 __ movl(ckoff_arg, rbx); // corresponding class check offset | |
1985 | |
1986 __ movl(length_arg, length); // outgoing length argument | |
1987 | |
304 | 1988 __ lea(from, Address(src, src_pos, Address::times_ptr, |
0 | 1989 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
304 | 1990 __ movptr(from_arg, from); |
0 | 1991 |
304 | 1992 __ lea(to, Address(dst, dst_pos, Address::times_ptr, |
0 | 1993 arrayOopDesc::base_offset_in_bytes(T_OBJECT))); |
304 | 1994 __ movptr(to_arg, to); |
0 | 1995 __ jump(RuntimeAddress(entry_checkcast_arraycopy)); |
1996 } | |
1997 | |
1998 return start; | |
1999 } | |
2000 | |
2001 void generate_arraycopy_stubs() { | |
2002 address entry; | |
2003 address entry_jbyte_arraycopy; | |
2004 address entry_jshort_arraycopy; | |
2005 address entry_jint_arraycopy; | |
2006 address entry_oop_arraycopy; | |
2007 address entry_jlong_arraycopy; | |
2008 address entry_checkcast_arraycopy; | |
2009 | |
2010 StubRoutines::_arrayof_jbyte_disjoint_arraycopy = | |
2011 generate_disjoint_copy(T_BYTE, true, Address::times_1, &entry, | |
2012 "arrayof_jbyte_disjoint_arraycopy"); | |
2013 StubRoutines::_arrayof_jbyte_arraycopy = | |
2014 generate_conjoint_copy(T_BYTE, true, Address::times_1, entry, | |
2015 NULL, "arrayof_jbyte_arraycopy"); | |
2016 StubRoutines::_jbyte_disjoint_arraycopy = | |
2017 generate_disjoint_copy(T_BYTE, false, Address::times_1, &entry, | |
2018 "jbyte_disjoint_arraycopy"); | |
2019 StubRoutines::_jbyte_arraycopy = | |
2020 generate_conjoint_copy(T_BYTE, false, Address::times_1, entry, | |
2021 &entry_jbyte_arraycopy, "jbyte_arraycopy"); | |
2022 | |
2023 StubRoutines::_arrayof_jshort_disjoint_arraycopy = | |
2024 generate_disjoint_copy(T_SHORT, true, Address::times_2, &entry, | |
2025 "arrayof_jshort_disjoint_arraycopy"); | |
2026 StubRoutines::_arrayof_jshort_arraycopy = | |
2027 generate_conjoint_copy(T_SHORT, true, Address::times_2, entry, | |
2028 NULL, "arrayof_jshort_arraycopy"); | |
2029 StubRoutines::_jshort_disjoint_arraycopy = | |
2030 generate_disjoint_copy(T_SHORT, false, Address::times_2, &entry, | |
2031 "jshort_disjoint_arraycopy"); | |
2032 StubRoutines::_jshort_arraycopy = | |
2033 generate_conjoint_copy(T_SHORT, false, Address::times_2, entry, | |
2034 &entry_jshort_arraycopy, "jshort_arraycopy"); | |
2035 | |
2036 // Next arrays are always aligned on 4 bytes at least. | |
2037 StubRoutines::_jint_disjoint_arraycopy = | |
2038 generate_disjoint_copy(T_INT, true, Address::times_4, &entry, | |
2039 "jint_disjoint_arraycopy"); | |
2040 StubRoutines::_jint_arraycopy = | |
2041 generate_conjoint_copy(T_INT, true, Address::times_4, entry, | |
2042 &entry_jint_arraycopy, "jint_arraycopy"); | |
2043 | |
2044 StubRoutines::_oop_disjoint_arraycopy = | |
304 | 2045 generate_disjoint_copy(T_OBJECT, true, Address::times_ptr, &entry, |
0 | 2046 "oop_disjoint_arraycopy"); |
2047 StubRoutines::_oop_arraycopy = | |
304 | 2048 generate_conjoint_copy(T_OBJECT, true, Address::times_ptr, entry, |
0 | 2049 &entry_oop_arraycopy, "oop_arraycopy"); |
2050 | |
2051 StubRoutines::_jlong_disjoint_arraycopy = | |
2052 generate_disjoint_long_copy(&entry, "jlong_disjoint_arraycopy"); | |
2053 StubRoutines::_jlong_arraycopy = | |
2054 generate_conjoint_long_copy(entry, &entry_jlong_arraycopy, | |
2055 "jlong_arraycopy"); | |
2056 | |
1763 | 2057 StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); |
2058 StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); | |
2059 StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); | |
2060 StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); | |
2061 StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); | |
2062 StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); | |
2063 | |
0 | 2064 StubRoutines::_arrayof_jint_disjoint_arraycopy = |
2065 StubRoutines::_jint_disjoint_arraycopy; | |
2066 StubRoutines::_arrayof_oop_disjoint_arraycopy = | |
2067 StubRoutines::_oop_disjoint_arraycopy; | |
2068 StubRoutines::_arrayof_jlong_disjoint_arraycopy = | |
2069 StubRoutines::_jlong_disjoint_arraycopy; | |
2070 | |
2071 StubRoutines::_arrayof_jint_arraycopy = StubRoutines::_jint_arraycopy; | |
2072 StubRoutines::_arrayof_oop_arraycopy = StubRoutines::_oop_arraycopy; | |
2073 StubRoutines::_arrayof_jlong_arraycopy = StubRoutines::_jlong_arraycopy; | |
2074 | |
2075 StubRoutines::_checkcast_arraycopy = | |
2076 generate_checkcast_copy("checkcast_arraycopy", | |
2077 &entry_checkcast_arraycopy); | |
2078 | |
2079 StubRoutines::_unsafe_arraycopy = | |
2080 generate_unsafe_copy("unsafe_arraycopy", | |
2081 entry_jbyte_arraycopy, | |
2082 entry_jshort_arraycopy, | |
2083 entry_jint_arraycopy, | |
2084 entry_jlong_arraycopy); | |
2085 | |
2086 StubRoutines::_generic_arraycopy = | |
2087 generate_generic_copy("generic_arraycopy", | |
2088 entry_jbyte_arraycopy, | |
2089 entry_jshort_arraycopy, | |
2090 entry_jint_arraycopy, | |
2091 entry_oop_arraycopy, | |
2092 entry_jlong_arraycopy, | |
2093 entry_checkcast_arraycopy); | |
2094 } | |
2095 | |
1174
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2096 void generate_math_stubs() { |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2097 { |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2098 StubCodeMark mark(this, "StubRoutines", "log"); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2099 StubRoutines::_intrinsic_log = (double (*)(double)) __ pc(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2100 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2101 __ fld_d(Address(rsp, 4)); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2102 __ flog(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2103 __ ret(0); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2104 } |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2105 { |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2106 StubCodeMark mark(this, "StubRoutines", "log10"); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2107 StubRoutines::_intrinsic_log10 = (double (*)(double)) __ pc(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2108 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2109 __ fld_d(Address(rsp, 4)); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2110 __ flog10(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2111 __ ret(0); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2112 } |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2113 { |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2114 StubCodeMark mark(this, "StubRoutines", "sin"); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2115 StubRoutines::_intrinsic_sin = (double (*)(double)) __ pc(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2116 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2117 __ fld_d(Address(rsp, 4)); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2118 __ trigfunc('s'); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2119 __ ret(0); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2120 } |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2121 { |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2122 StubCodeMark mark(this, "StubRoutines", "cos"); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2123 StubRoutines::_intrinsic_cos = (double (*)(double)) __ pc(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2124 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2125 __ fld_d(Address(rsp, 4)); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2126 __ trigfunc('c'); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2127 __ ret(0); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2128 } |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2129 { |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2130 StubCodeMark mark(this, "StubRoutines", "tan"); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2131 StubRoutines::_intrinsic_tan = (double (*)(double)) __ pc(); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2132 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2133 __ fld_d(Address(rsp, 4)); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2134 __ trigfunc('t'); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2135 __ ret(0); |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2136 } |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2137 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2138 // The intrinsic version of these seem to return the same value as |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2139 // the strict version. |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2140 StubRoutines::_intrinsic_exp = SharedRuntime::dexp; |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2141 StubRoutines::_intrinsic_pow = SharedRuntime::dpow; |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2142 } |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2143 |
0 | 2144 public: |
2145 // Information about frame layout at time of blocking runtime call. | |
2146 // Note that we only have to preserve callee-saved registers since | |
2147 // the compilers are responsible for supplying a continuation point | |
2148 // if they expect all registers to be preserved. | |
2149 enum layout { | |
2150 thread_off, // last_java_sp | |
2151 rbp_off, // callee saved register | |
2152 ret_pc, | |
2153 framesize | |
2154 }; | |
2155 | |
2156 private: | |
2157 | |
2158 #undef __ | |
2159 #define __ masm-> | |
2160 | |
2161 //------------------------------------------------------------------------------------------------------------------------ | |
2162 // Continuation point for throwing of implicit exceptions that are not handled in | |
2163 // the current activation. Fabricates an exception oop and initiates normal | |
2164 // exception dispatching in this frame. | |
2165 // | |
2166 // Previously the compiler (c2) allowed for callee save registers on Java calls. | |
2167 // This is no longer true after adapter frames were removed but could possibly | |
2168 // be brought back in the future if the interpreter code was reworked and it | |
2169 // was deemed worthwhile. The comment below was left to describe what must | |
2170 // happen here if callee saves were resurrected. As it stands now this stub | |
2171 // could actually be a vanilla BufferBlob and have now oopMap at all. | |
2172 // Since it doesn't make much difference we've chosen to leave it the | |
2173 // way it was in the callee save days and keep the comment. | |
2174 | |
2175 // If we need to preserve callee-saved values we need a callee-saved oop map and | |
2176 // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs. | |
2177 // If the compiler needs all registers to be preserved between the fault | |
2178 // point and the exception handler then it must assume responsibility for that in | |
2179 // AbstractCompiler::continuation_for_implicit_null_exception or | |
2180 // continuation_for_implicit_division_by_zero_exception. All other implicit | |
2181 // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are | |
2182 // either at call sites or otherwise assume that stack unwinding will be initiated, | |
2183 // so caller saved registers were assumed volatile in the compiler. | |
2184 address generate_throw_exception(const char* name, address runtime_entry, | |
2185 bool restore_saved_exception_pc) { | |
2186 | |
2187 int insts_size = 256; | |
2188 int locs_size = 32; | |
2189 | |
2190 CodeBuffer code(name, insts_size, locs_size); | |
2191 OopMapSet* oop_maps = new OopMapSet(); | |
2192 MacroAssembler* masm = new MacroAssembler(&code); | |
2193 | |
2194 address start = __ pc(); | |
2195 | |
2196 // This is an inlined and slightly modified version of call_VM | |
2197 // which has the ability to fetch the return PC out of | |
2198 // thread-local storage and also sets up last_Java_sp slightly | |
2199 // differently than the real call_VM | |
2200 Register java_thread = rbx; | |
2201 __ get_thread(java_thread); | |
2202 if (restore_saved_exception_pc) { | |
304 | 2203 __ movptr(rax, Address(java_thread, in_bytes(JavaThread::saved_exception_pc_offset()))); |
2204 __ push(rax); | |
0 | 2205 } |
2206 | |
2207 __ enter(); // required for proper stackwalking of RuntimeStub frame | |
2208 | |
2209 // pc and rbp, already pushed | |
304 | 2210 __ subptr(rsp, (framesize-2) * wordSize); // prolog |
0 | 2211 |
2212 // Frame is now completed as far as size and linkage. | |
2213 | |
2214 int frame_complete = __ pc() - start; | |
2215 | |
2216 // push java thread (becomes first argument of C function) | |
304 | 2217 __ movptr(Address(rsp, thread_off * wordSize), java_thread); |
0 | 2218 |
2219 // Set up last_Java_sp and last_Java_fp | |
2220 __ set_last_Java_frame(java_thread, rsp, rbp, NULL); | |
2221 | |
2222 // Call runtime | |
2223 BLOCK_COMMENT("call runtime_entry"); | |
2224 __ call(RuntimeAddress(runtime_entry)); | |
2225 // Generate oop map | |
2226 OopMap* map = new OopMap(framesize, 0); | |
2227 oop_maps->add_gc_map(__ pc() - start, map); | |
2228 | |
2229 // restore the thread (cannot use the pushed argument since arguments | |
2230 // may be overwritten by C code generated by an optimizing compiler); | |
2231 // however can use the register value directly if it is callee saved. | |
2232 __ get_thread(java_thread); | |
2233 | |
2234 __ reset_last_Java_frame(java_thread, true, false); | |
2235 | |
2236 __ leave(); // required for proper stackwalking of RuntimeStub frame | |
2237 | |
2238 // check for pending exceptions | |
2239 #ifdef ASSERT | |
2240 Label L; | |
304 | 2241 __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); |
0 | 2242 __ jcc(Assembler::notEqual, L); |
2243 __ should_not_reach_here(); | |
2244 __ bind(L); | |
2245 #endif /* ASSERT */ | |
2246 __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); | |
2247 | |
2248 | |
2249 RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false); | |
2250 return stub->entry_point(); | |
2251 } | |
2252 | |
2253 | |
2254 void create_control_words() { | |
2255 // Round to nearest, 53-bit mode, exceptions masked | |
2256 StubRoutines::_fpu_cntrl_wrd_std = 0x027F; | |
2257 // Round to zero, 53-bit mode, exception mased | |
2258 StubRoutines::_fpu_cntrl_wrd_trunc = 0x0D7F; | |
2259 // Round to nearest, 24-bit mode, exceptions masked | |
2260 StubRoutines::_fpu_cntrl_wrd_24 = 0x007F; | |
2261 // Round to nearest, 64-bit mode, exceptions masked | |
2262 StubRoutines::_fpu_cntrl_wrd_64 = 0x037F; | |
2263 // Round to nearest, 64-bit mode, exceptions masked | |
2264 StubRoutines::_mxcsr_std = 0x1F80; | |
2265 // Note: the following two constants are 80-bit values | |
2266 // layout is critical for correct loading by FPU. | |
2267 // Bias for strict fp multiply/divide | |
2268 StubRoutines::_fpu_subnormal_bias1[0]= 0x00000000; // 2^(-15360) == 0x03ff 8000 0000 0000 0000 | |
2269 StubRoutines::_fpu_subnormal_bias1[1]= 0x80000000; | |
2270 StubRoutines::_fpu_subnormal_bias1[2]= 0x03ff; | |
2271 // Un-Bias for strict fp multiply/divide | |
2272 StubRoutines::_fpu_subnormal_bias2[0]= 0x00000000; // 2^(+15360) == 0x7bff 8000 0000 0000 0000 | |
2273 StubRoutines::_fpu_subnormal_bias2[1]= 0x80000000; | |
2274 StubRoutines::_fpu_subnormal_bias2[2]= 0x7bff; | |
2275 } | |
2276 | |
2277 //--------------------------------------------------------------------------- | |
2278 // Initialization | |
2279 | |
2280 void generate_initial() { | |
2281 // Generates all stubs and initializes the entry points | |
2282 | |
2283 //------------------------------------------------------------------------------------------------------------------------ | |
2284 // entry points that exist in all platforms | |
2285 // Note: This is code that could be shared among different platforms - however the benefit seems to be smaller than | |
2286 // the disadvantage of having a much more complicated generator structure. See also comment in stubRoutines.hpp. | |
2287 StubRoutines::_forward_exception_entry = generate_forward_exception(); | |
2288 | |
2289 StubRoutines::_call_stub_entry = | |
2290 generate_call_stub(StubRoutines::_call_stub_return_address); | |
2291 // is referenced by megamorphic call | |
2292 StubRoutines::_catch_exception_entry = generate_catch_exception(); | |
2293 | |
2294 // These are currently used by Solaris/Intel | |
2295 StubRoutines::_atomic_xchg_entry = generate_atomic_xchg(); | |
2296 | |
2297 StubRoutines::_handler_for_unsafe_access_entry = | |
2298 generate_handler_for_unsafe_access(); | |
2299 | |
2300 // platform dependent | |
2301 create_control_words(); | |
2302 | |
304 | 2303 StubRoutines::x86::_verify_mxcsr_entry = generate_verify_mxcsr(); |
2304 StubRoutines::x86::_verify_fpu_cntrl_wrd_entry = generate_verify_fpu_cntrl_wrd(); | |
0 | 2305 StubRoutines::_d2i_wrapper = generate_d2i_wrapper(T_INT, |
2306 CAST_FROM_FN_PTR(address, SharedRuntime::d2i)); | |
2307 StubRoutines::_d2l_wrapper = generate_d2i_wrapper(T_LONG, | |
2308 CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); | |
2309 } | |
2310 | |
2311 | |
2312 void generate_all() { | |
2313 // Generates all stubs and initializes the entry points | |
2314 | |
2315 // These entry points require SharedInfo::stack0 to be set up in non-core builds | |
2316 // and need to be relocatable, so they each fabricate a RuntimeStub internally. | |
2317 StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); | |
16
f8236e79048a
6664627: Merge changes made only in hotspot 11 forward to jdk 7
dcubed
parents:
0
diff
changeset
|
2318 StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); |
0 | 2319 StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_ArithmeticException), true); |
2320 StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true); | |
2321 StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); | |
2322 StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); | |
2323 | |
2324 //------------------------------------------------------------------------------------------------------------------------ | |
2325 // entry points that are platform specific | |
2326 | |
2327 // support for verify_oop (must happen after universe_init) | |
2328 StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); | |
2329 | |
2330 // arraycopy stubs used by compilers | |
2331 generate_arraycopy_stubs(); | |
710 | 2332 |
1174
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
845
diff
changeset
|
2333 generate_math_stubs(); |
0 | 2334 } |
2335 | |
2336 | |
2337 public: | |
2338 StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { | |
2339 if (all) { | |
2340 generate_all(); | |
2341 } else { | |
2342 generate_initial(); | |
2343 } | |
2344 } | |
2345 }; // end class declaration | |
2346 | |
2347 | |
2348 void StubGenerator_generate(CodeBuffer* code, bool all) { | |
2349 StubGenerator g(code, all); | |
2350 } |