Mercurial > hg > graal-jvmci-8
annotate src/cpu/sparc/vm/stubGenerator_sparc.cpp @ 2368:dde920245681
6896099: Integrate CMS heap ergo with default heap sizing ergo
6627787: CMS: JVM refuses to start up with -Xms16m -Xmx16m
7000125: CMS: Anti-monotone young gen sizing with respect to maximum whole heap size specification
7027529: CMS: retire CMSUseOldDefaults flag
Summary: Simplify CMS heap sizing code, relying on ergonomic initial sizing consistent with other collectors for the most part, controlling only young gen sizing to rein in pause times. Make CMS young gen sizing default statically cpu-dependant. Remove inconsistencies wrt generation sizing and policy code, allowing for the fixing for 6627787 and 7000125. For 7027529, retire the flag CMSUseOldDefaults which had been introduced as a bridge from JDK 5 to JDK 6 a number of years ago.
Reviewed-by: brutisso, poonam
author | ysr |
---|---|
date | Wed, 16 Mar 2011 10:37:08 -0700 |
parents | f95d63e2154a |
children | d89a22843c62 |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1506
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "asm/assembler.hpp" | |
27 #include "assembler_sparc.inline.hpp" | |
28 #include "interpreter/interpreter.hpp" | |
29 #include "nativeInst_sparc.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 COMPILER2 | |
48 #include "opto/runtime.hpp" | |
49 #endif | |
0 | 50 |
51 // Declaration and definition of StubGenerator (no .hpp file). | |
52 // For a more detailed description of the stub routine structure | |
53 // see the comment in stubRoutines.hpp. | |
54 | |
55 #define __ _masm-> | |
56 | |
57 #ifdef PRODUCT | |
58 #define BLOCK_COMMENT(str) /* nothing */ | |
59 #else | |
60 #define BLOCK_COMMENT(str) __ block_comment(str) | |
61 #endif | |
62 | |
63 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") | |
64 | |
65 // Note: The register L7 is used as L7_thread_cache, and may not be used | |
66 // any other way within this module. | |
67 | |
68 | |
69 static const Register& Lstub_temp = L2; | |
70 | |
71 // ------------------------------------------------------------------------------------------------------------------------- | |
72 // Stub Code definitions | |
73 | |
74 static address handle_unsafe_access() { | |
75 JavaThread* thread = JavaThread::current(); | |
76 address pc = thread->saved_exception_pc(); | |
77 address npc = thread->saved_exception_npc(); | |
78 // pc is the instruction which we must emulate | |
79 // doing a no-op is fine: return garbage from the load | |
80 | |
81 // request an async exception | |
82 thread->set_pending_unsafe_access_error(); | |
83 | |
84 // return address of next instruction to execute | |
85 return npc; | |
86 } | |
87 | |
88 class StubGenerator: public StubCodeGenerator { | |
89 private: | |
90 | |
91 #ifdef PRODUCT | |
92 #define inc_counter_np(a,b,c) (0) | |
93 #else | |
94 #define inc_counter_np(counter, t1, t2) \ | |
95 BLOCK_COMMENT("inc_counter " #counter); \ | |
727 | 96 __ inc_counter(&counter, t1, t2); |
0 | 97 #endif |
98 | |
99 //---------------------------------------------------------------------------------------------------- | |
100 // Call stubs are used to call Java from C | |
101 | |
102 address generate_call_stub(address& return_pc) { | |
103 StubCodeMark mark(this, "StubRoutines", "call_stub"); | |
104 address start = __ pc(); | |
105 | |
106 // Incoming arguments: | |
107 // | |
108 // o0 : call wrapper address | |
109 // o1 : result (address) | |
110 // o2 : result type | |
111 // o3 : method | |
112 // o4 : (interpreter) entry point | |
113 // o5 : parameters (address) | |
114 // [sp + 0x5c]: parameter size (in words) | |
115 // [sp + 0x60]: thread | |
116 // | |
117 // +---------------+ <--- sp + 0 | |
118 // | | | |
119 // . reg save area . | |
120 // | | | |
121 // +---------------+ <--- sp + 0x40 | |
122 // | | | |
123 // . extra 7 slots . | |
124 // | | | |
125 // +---------------+ <--- sp + 0x5c | |
126 // | param. size | | |
127 // +---------------+ <--- sp + 0x60 | |
128 // | thread | | |
129 // +---------------+ | |
130 // | | | |
131 | |
132 // note: if the link argument position changes, adjust | |
133 // the code in frame::entry_frame_call_wrapper() | |
134 | |
135 const Argument link = Argument(0, false); // used only for GC | |
136 const Argument result = Argument(1, false); | |
137 const Argument result_type = Argument(2, false); | |
138 const Argument method = Argument(3, false); | |
139 const Argument entry_point = Argument(4, false); | |
140 const Argument parameters = Argument(5, false); | |
141 const Argument parameter_size = Argument(6, false); | |
142 const Argument thread = Argument(7, false); | |
143 | |
144 // setup thread register | |
145 __ ld_ptr(thread.as_address(), G2_thread); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
146 __ reinit_heapbase(); |
0 | 147 |
148 #ifdef ASSERT | |
149 // make sure we have no pending exceptions | |
150 { const Register t = G3_scratch; | |
151 Label L; | |
152 __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), t); | |
153 __ br_null(t, false, Assembler::pt, L); | |
154 __ delayed()->nop(); | |
155 __ stop("StubRoutines::call_stub: entered with pending exception"); | |
156 __ bind(L); | |
157 } | |
158 #endif | |
159 | |
160 // create activation frame & allocate space for parameters | |
161 { const Register t = G3_scratch; | |
162 __ ld_ptr(parameter_size.as_address(), t); // get parameter size (in words) | |
163 __ add(t, frame::memory_parameter_word_sp_offset, t); // add space for save area (in words) | |
164 __ round_to(t, WordsPerLong); // make sure it is multiple of 2 (in words) | |
1506 | 165 __ sll(t, Interpreter::logStackElementSize, t); // compute number of bytes |
0 | 166 __ neg(t); // negate so it can be used with save |
167 __ save(SP, t, SP); // setup new frame | |
168 } | |
169 | |
170 // +---------------+ <--- sp + 0 | |
171 // | | | |
172 // . reg save area . | |
173 // | | | |
174 // +---------------+ <--- sp + 0x40 | |
175 // | | | |
176 // . extra 7 slots . | |
177 // | | | |
178 // +---------------+ <--- sp + 0x5c | |
179 // | empty slot | (only if parameter size is even) | |
180 // +---------------+ | |
181 // | | | |
182 // . parameters . | |
183 // | | | |
184 // +---------------+ <--- fp + 0 | |
185 // | | | |
186 // . reg save area . | |
187 // | | | |
188 // +---------------+ <--- fp + 0x40 | |
189 // | | | |
190 // . extra 7 slots . | |
191 // | | | |
192 // +---------------+ <--- fp + 0x5c | |
193 // | param. size | | |
194 // +---------------+ <--- fp + 0x60 | |
195 // | thread | | |
196 // +---------------+ | |
197 // | | | |
198 | |
199 // pass parameters if any | |
200 BLOCK_COMMENT("pass parameters if any"); | |
201 { const Register src = parameters.as_in().as_register(); | |
202 const Register dst = Lentry_args; | |
203 const Register tmp = G3_scratch; | |
204 const Register cnt = G4_scratch; | |
205 | |
206 // test if any parameters & setup of Lentry_args | |
207 Label exit; | |
208 __ ld_ptr(parameter_size.as_in().as_address(), cnt); // parameter counter | |
209 __ add( FP, STACK_BIAS, dst ); | |
210 __ tst(cnt); | |
211 __ br(Assembler::zero, false, Assembler::pn, exit); | |
212 __ delayed()->sub(dst, BytesPerWord, dst); // setup Lentry_args | |
213 | |
214 // copy parameters if any | |
215 Label loop; | |
216 __ BIND(loop); | |
217 // Store parameter value | |
218 __ ld_ptr(src, 0, tmp); | |
219 __ add(src, BytesPerWord, src); | |
1506 | 220 __ st_ptr(tmp, dst, 0); |
0 | 221 __ deccc(cnt); |
222 __ br(Assembler::greater, false, Assembler::pt, loop); | |
1506 | 223 __ delayed()->sub(dst, Interpreter::stackElementSize, dst); |
0 | 224 |
225 // done | |
226 __ BIND(exit); | |
227 } | |
228 | |
229 // setup parameters, method & call Java function | |
230 #ifdef ASSERT | |
231 // layout_activation_impl checks it's notion of saved SP against | |
232 // this register, so if this changes update it as well. | |
233 const Register saved_SP = Lscratch; | |
234 __ mov(SP, saved_SP); // keep track of SP before call | |
235 #endif | |
236 | |
237 // setup parameters | |
238 const Register t = G3_scratch; | |
239 __ ld_ptr(parameter_size.as_in().as_address(), t); // get parameter size (in words) | |
1506 | 240 __ sll(t, Interpreter::logStackElementSize, t); // compute number of bytes |
0 | 241 __ sub(FP, t, Gargs); // setup parameter pointer |
242 #ifdef _LP64 | |
243 __ add( Gargs, STACK_BIAS, Gargs ); // Account for LP64 stack bias | |
244 #endif | |
245 __ mov(SP, O5_savedSP); | |
246 | |
247 | |
248 // do the call | |
249 // | |
250 // the following register must be setup: | |
251 // | |
252 // G2_thread | |
253 // G5_method | |
254 // Gargs | |
255 BLOCK_COMMENT("call Java function"); | |
256 __ jmpl(entry_point.as_in().as_register(), G0, O7); | |
257 __ delayed()->mov(method.as_in().as_register(), G5_method); // setup method | |
258 | |
259 BLOCK_COMMENT("call_stub_return_address:"); | |
260 return_pc = __ pc(); | |
261 | |
262 // The callee, if it wasn't interpreted, can return with SP changed so | |
263 // we can no longer assert of change of SP. | |
264 | |
265 // store result depending on type | |
266 // (everything that is not T_OBJECT, T_LONG, T_FLOAT, or T_DOUBLE | |
267 // is treated as T_INT) | |
268 { const Register addr = result .as_in().as_register(); | |
269 const Register type = result_type.as_in().as_register(); | |
270 Label is_long, is_float, is_double, is_object, exit; | |
271 __ cmp(type, T_OBJECT); __ br(Assembler::equal, false, Assembler::pn, is_object); | |
272 __ delayed()->cmp(type, T_FLOAT); __ br(Assembler::equal, false, Assembler::pn, is_float); | |
273 __ delayed()->cmp(type, T_DOUBLE); __ br(Assembler::equal, false, Assembler::pn, is_double); | |
274 __ delayed()->cmp(type, T_LONG); __ br(Assembler::equal, false, Assembler::pn, is_long); | |
275 __ delayed()->nop(); | |
276 | |
277 // store int result | |
278 __ st(O0, addr, G0); | |
279 | |
280 __ BIND(exit); | |
281 __ ret(); | |
282 __ delayed()->restore(); | |
283 | |
284 __ BIND(is_object); | |
285 __ ba(false, exit); | |
286 __ delayed()->st_ptr(O0, addr, G0); | |
287 | |
288 __ BIND(is_float); | |
289 __ ba(false, exit); | |
290 __ delayed()->stf(FloatRegisterImpl::S, F0, addr, G0); | |
291 | |
292 __ BIND(is_double); | |
293 __ ba(false, exit); | |
294 __ delayed()->stf(FloatRegisterImpl::D, F0, addr, G0); | |
295 | |
296 __ BIND(is_long); | |
297 #ifdef _LP64 | |
298 __ ba(false, exit); | |
299 __ delayed()->st_long(O0, addr, G0); // store entire long | |
300 #else | |
301 #if defined(COMPILER2) | |
302 // All return values are where we want them, except for Longs. C2 returns | |
303 // longs in G1 in the 32-bit build whereas the interpreter wants them in O0/O1. | |
304 // Since the interpreter will return longs in G1 and O0/O1 in the 32bit | |
305 // build we simply always use G1. | |
306 // Note: I tried to make c2 return longs in O0/O1 and G1 so we wouldn't have to | |
307 // do this here. Unfortunately if we did a rethrow we'd see an machepilog node | |
308 // first which would move g1 -> O0/O1 and destroy the exception we were throwing. | |
309 | |
310 __ ba(false, exit); | |
311 __ delayed()->stx(G1, addr, G0); // store entire long | |
312 #else | |
313 __ st(O1, addr, BytesPerInt); | |
314 __ ba(false, exit); | |
315 __ delayed()->st(O0, addr, G0); | |
316 #endif /* COMPILER2 */ | |
317 #endif /* _LP64 */ | |
318 } | |
319 return start; | |
320 } | |
321 | |
322 | |
323 //---------------------------------------------------------------------------------------------------- | |
324 // Return point for a Java call if there's an exception thrown in Java code. | |
325 // The exception is caught and transformed into a pending exception stored in | |
326 // JavaThread that can be tested from within the VM. | |
327 // | |
328 // Oexception: exception oop | |
329 | |
330 address generate_catch_exception() { | |
331 StubCodeMark mark(this, "StubRoutines", "catch_exception"); | |
332 | |
333 address start = __ pc(); | |
334 // verify that thread corresponds | |
335 __ verify_thread(); | |
336 | |
337 const Register& temp_reg = Gtemp; | |
727 | 338 Address pending_exception_addr (G2_thread, Thread::pending_exception_offset()); |
339 Address exception_file_offset_addr(G2_thread, Thread::exception_file_offset ()); | |
340 Address exception_line_offset_addr(G2_thread, Thread::exception_line_offset ()); | |
0 | 341 |
342 // set pending exception | |
343 __ verify_oop(Oexception); | |
344 __ st_ptr(Oexception, pending_exception_addr); | |
345 __ set((intptr_t)__FILE__, temp_reg); | |
346 __ st_ptr(temp_reg, exception_file_offset_addr); | |
347 __ set((intptr_t)__LINE__, temp_reg); | |
348 __ st(temp_reg, exception_line_offset_addr); | |
349 | |
350 // complete return to VM | |
351 assert(StubRoutines::_call_stub_return_address != NULL, "must have been generated before"); | |
352 | |
727 | 353 AddressLiteral stub_ret(StubRoutines::_call_stub_return_address); |
354 __ jump_to(stub_ret, temp_reg); | |
0 | 355 __ delayed()->nop(); |
356 | |
357 return start; | |
358 } | |
359 | |
360 | |
361 //---------------------------------------------------------------------------------------------------- | |
362 // Continuation point for runtime calls returning with a pending exception | |
363 // The pending exception check happened in the runtime or native call stub | |
364 // The pending exception in Thread is converted into a Java-level exception | |
365 // | |
366 // Contract with Java-level exception handler: O0 = exception | |
367 // O1 = throwing pc | |
368 | |
369 address generate_forward_exception() { | |
370 StubCodeMark mark(this, "StubRoutines", "forward_exception"); | |
371 address start = __ pc(); | |
372 | |
373 // Upon entry, O7 has the return address returning into Java | |
374 // (interpreted or compiled) code; i.e. the return address | |
375 // becomes the throwing pc. | |
376 | |
377 const Register& handler_reg = Gtemp; | |
378 | |
727 | 379 Address exception_addr(G2_thread, Thread::pending_exception_offset()); |
0 | 380 |
381 #ifdef ASSERT | |
382 // make sure that this code is only executed if there is a pending exception | |
383 { Label L; | |
384 __ ld_ptr(exception_addr, Gtemp); | |
385 __ br_notnull(Gtemp, false, Assembler::pt, L); | |
386 __ delayed()->nop(); | |
387 __ stop("StubRoutines::forward exception: no pending exception (1)"); | |
388 __ bind(L); | |
389 } | |
390 #endif | |
391 | |
392 // compute exception handler into handler_reg | |
393 __ get_thread(); | |
394 __ ld_ptr(exception_addr, Oexception); | |
395 __ verify_oop(Oexception); | |
396 __ save_frame(0); // compensates for compiler weakness | |
397 __ add(O7->after_save(), frame::pc_return_offset, Lscratch); // save the issuing PC | |
398 BLOCK_COMMENT("call exception_handler_for_return_address"); | |
1295 | 399 __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), G2_thread, Lscratch); |
0 | 400 __ mov(O0, handler_reg); |
401 __ restore(); // compensates for compiler weakness | |
402 | |
403 __ ld_ptr(exception_addr, Oexception); | |
404 __ add(O7, frame::pc_return_offset, Oissuing_pc); // save the issuing PC | |
405 | |
406 #ifdef ASSERT | |
407 // make sure exception is set | |
408 { Label L; | |
409 __ br_notnull(Oexception, false, Assembler::pt, L); | |
410 __ delayed()->nop(); | |
411 __ stop("StubRoutines::forward exception: no pending exception (2)"); | |
412 __ bind(L); | |
413 } | |
414 #endif | |
415 // jump to exception handler | |
416 __ jmp(handler_reg, 0); | |
417 // clear pending exception | |
418 __ delayed()->st_ptr(G0, exception_addr); | |
419 | |
420 return start; | |
421 } | |
422 | |
423 | |
424 //------------------------------------------------------------------------------------------------------------------------ | |
425 // Continuation point for throwing of implicit exceptions that are not handled in | |
426 // the current activation. Fabricates an exception oop and initiates normal | |
427 // exception dispatching in this frame. Only callee-saved registers are preserved | |
428 // (through the normal register window / RegisterMap handling). | |
429 // If the compiler needs all registers to be preserved between the fault | |
430 // point and the exception handler then it must assume responsibility for that in | |
431 // AbstractCompiler::continuation_for_implicit_null_exception or | |
432 // continuation_for_implicit_division_by_zero_exception. All other implicit | |
433 // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are | |
434 // either at call sites or otherwise assume that stack unwinding will be initiated, | |
435 // so caller saved registers were assumed volatile in the compiler. | |
436 | |
437 // Note that we generate only this stub into a RuntimeStub, because it needs to be | |
438 // properly traversed and ignored during GC, so we change the meaning of the "__" | |
439 // macro within this method. | |
440 #undef __ | |
441 #define __ masm-> | |
442 | |
443 address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc) { | |
444 #ifdef ASSERT | |
445 int insts_size = VerifyThread ? 1 * K : 600; | |
446 #else | |
447 int insts_size = VerifyThread ? 1 * K : 256; | |
448 #endif /* ASSERT */ | |
449 int locs_size = 32; | |
450 | |
451 CodeBuffer code(name, insts_size, locs_size); | |
452 MacroAssembler* masm = new MacroAssembler(&code); | |
453 | |
454 __ verify_thread(); | |
455 | |
456 // This is an inlined and slightly modified version of call_VM | |
457 // which has the ability to fetch the return PC out of thread-local storage | |
458 __ assert_not_delayed(); | |
459 | |
460 // Note that we always push a frame because on the SPARC | |
461 // architecture, for all of our implicit exception kinds at call | |
462 // sites, the implicit exception is taken before the callee frame | |
463 // is pushed. | |
464 __ save_frame(0); | |
465 | |
466 int frame_complete = __ offset(); | |
467 | |
468 if (restore_saved_exception_pc) { | |
727 | 469 __ ld_ptr(G2_thread, JavaThread::saved_exception_pc_offset(), I7); |
0 | 470 __ sub(I7, frame::pc_return_offset, I7); |
471 } | |
472 | |
473 // Note that we always have a runtime stub frame on the top of stack by this point | |
474 Register last_java_sp = SP; | |
475 // 64-bit last_java_sp is biased! | |
476 __ set_last_Java_frame(last_java_sp, G0); | |
477 if (VerifyThread) __ mov(G2_thread, O0); // about to be smashed; pass early | |
478 __ save_thread(noreg); | |
479 // do the call | |
480 BLOCK_COMMENT("call runtime_entry"); | |
481 __ call(runtime_entry, relocInfo::runtime_call_type); | |
482 if (!VerifyThread) | |
483 __ delayed()->mov(G2_thread, O0); // pass thread as first argument | |
484 else | |
485 __ delayed()->nop(); // (thread already passed) | |
486 __ restore_thread(noreg); | |
487 __ reset_last_Java_frame(); | |
488 | |
489 // check for pending exceptions. use Gtemp as scratch register. | |
490 #ifdef ASSERT | |
491 Label L; | |
492 | |
727 | 493 Address exception_addr(G2_thread, Thread::pending_exception_offset()); |
0 | 494 Register scratch_reg = Gtemp; |
495 __ ld_ptr(exception_addr, scratch_reg); | |
496 __ br_notnull(scratch_reg, false, Assembler::pt, L); | |
497 __ delayed()->nop(); | |
498 __ should_not_reach_here(); | |
499 __ bind(L); | |
500 #endif // ASSERT | |
501 BLOCK_COMMENT("call forward_exception_entry"); | |
502 __ call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); | |
503 // we use O7 linkage so that forward_exception_entry has the issuing PC | |
504 __ delayed()->restore(); | |
505 | |
506 RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, masm->total_frame_size_in_bytes(0), NULL, false); | |
507 return stub->entry_point(); | |
508 } | |
509 | |
510 #undef __ | |
511 #define __ _masm-> | |
512 | |
513 | |
514 // Generate a routine that sets all the registers so we | |
515 // can tell if the stop routine prints them correctly. | |
516 address generate_test_stop() { | |
517 StubCodeMark mark(this, "StubRoutines", "test_stop"); | |
518 address start = __ pc(); | |
519 | |
520 int i; | |
521 | |
522 __ save_frame(0); | |
523 | |
524 static jfloat zero = 0.0, one = 1.0; | |
525 | |
526 // put addr in L0, then load through L0 to F0 | |
527 __ set((intptr_t)&zero, L0); __ ldf( FloatRegisterImpl::S, L0, 0, F0); | |
528 __ set((intptr_t)&one, L0); __ ldf( FloatRegisterImpl::S, L0, 0, F1); // 1.0 to F1 | |
529 | |
530 // use add to put 2..18 in F2..F18 | |
531 for ( i = 2; i <= 18; ++i ) { | |
532 __ fadd( FloatRegisterImpl::S, F1, as_FloatRegister(i-1), as_FloatRegister(i)); | |
533 } | |
534 | |
535 // Now put double 2 in F16, double 18 in F18 | |
536 __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, F2, F16 ); | |
537 __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, F18, F18 ); | |
538 | |
539 // use add to put 20..32 in F20..F32 | |
540 for (i = 20; i < 32; i += 2) { | |
541 __ fadd( FloatRegisterImpl::D, F16, as_FloatRegister(i-2), as_FloatRegister(i)); | |
542 } | |
543 | |
544 // put 0..7 in i's, 8..15 in l's, 16..23 in o's, 24..31 in g's | |
545 for ( i = 0; i < 8; ++i ) { | |
546 if (i < 6) { | |
547 __ set( i, as_iRegister(i)); | |
548 __ set(16 + i, as_oRegister(i)); | |
549 __ set(24 + i, as_gRegister(i)); | |
550 } | |
551 __ set( 8 + i, as_lRegister(i)); | |
552 } | |
553 | |
554 __ stop("testing stop"); | |
555 | |
556 | |
557 __ ret(); | |
558 __ delayed()->restore(); | |
559 | |
560 return start; | |
561 } | |
562 | |
563 | |
564 address generate_stop_subroutine() { | |
565 StubCodeMark mark(this, "StubRoutines", "stop_subroutine"); | |
566 address start = __ pc(); | |
567 | |
568 __ stop_subroutine(); | |
569 | |
570 return start; | |
571 } | |
572 | |
573 address generate_flush_callers_register_windows() { | |
574 StubCodeMark mark(this, "StubRoutines", "flush_callers_register_windows"); | |
575 address start = __ pc(); | |
576 | |
577 __ flush_windows(); | |
578 __ retl(false); | |
579 __ delayed()->add( FP, STACK_BIAS, O0 ); | |
580 // The returned value must be a stack pointer whose register save area | |
581 // is flushed, and will stay flushed while the caller executes. | |
582 | |
583 return start; | |
584 } | |
585 | |
586 // Helper functions for v8 atomic operations. | |
587 // | |
588 void get_v8_oop_lock_ptr(Register lock_ptr_reg, Register mark_oop_reg, Register scratch_reg) { | |
589 if (mark_oop_reg == noreg) { | |
590 address lock_ptr = (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr(); | |
591 __ set((intptr_t)lock_ptr, lock_ptr_reg); | |
592 } else { | |
593 assert(scratch_reg != noreg, "just checking"); | |
594 address lock_ptr = (address)StubRoutines::Sparc::_v8_oop_lock_cache; | |
595 __ set((intptr_t)lock_ptr, lock_ptr_reg); | |
596 __ and3(mark_oop_reg, StubRoutines::Sparc::v8_oop_lock_mask_in_place, scratch_reg); | |
597 __ add(lock_ptr_reg, scratch_reg, lock_ptr_reg); | |
598 } | |
599 } | |
600 | |
601 void generate_v8_lock_prologue(Register lock_reg, Register lock_ptr_reg, Register yield_reg, Label& retry, Label& dontyield, Register mark_oop_reg = noreg, Register scratch_reg = noreg) { | |
602 | |
603 get_v8_oop_lock_ptr(lock_ptr_reg, mark_oop_reg, scratch_reg); | |
604 __ set(StubRoutines::Sparc::locked, lock_reg); | |
605 // Initialize yield counter | |
606 __ mov(G0,yield_reg); | |
607 | |
608 __ BIND(retry); | |
609 __ cmp(yield_reg, V8AtomicOperationUnderLockSpinCount); | |
610 __ br(Assembler::less, false, Assembler::pt, dontyield); | |
611 __ delayed()->nop(); | |
612 | |
613 // This code can only be called from inside the VM, this | |
614 // stub is only invoked from Atomic::add(). We do not | |
615 // want to use call_VM, because _last_java_sp and such | |
616 // must already be set. | |
617 // | |
618 // Save the regs and make space for a C call | |
619 __ save(SP, -96, SP); | |
620 __ save_all_globals_into_locals(); | |
621 BLOCK_COMMENT("call os::naked_sleep"); | |
622 __ call(CAST_FROM_FN_PTR(address, os::naked_sleep)); | |
623 __ delayed()->nop(); | |
624 __ restore_globals_from_locals(); | |
625 __ restore(); | |
626 // reset the counter | |
627 __ mov(G0,yield_reg); | |
628 | |
629 __ BIND(dontyield); | |
630 | |
631 // try to get lock | |
632 __ swap(lock_ptr_reg, 0, lock_reg); | |
633 | |
634 // did we get the lock? | |
635 __ cmp(lock_reg, StubRoutines::Sparc::unlocked); | |
636 __ br(Assembler::notEqual, true, Assembler::pn, retry); | |
637 __ delayed()->add(yield_reg,1,yield_reg); | |
638 | |
639 // yes, got lock. do the operation here. | |
640 } | |
641 | |
642 void generate_v8_lock_epilogue(Register lock_reg, Register lock_ptr_reg, Register yield_reg, Label& retry, Label& dontyield, Register mark_oop_reg = noreg, Register scratch_reg = noreg) { | |
643 __ st(lock_reg, lock_ptr_reg, 0); // unlock | |
644 } | |
645 | |
646 // Support for jint Atomic::xchg(jint exchange_value, volatile jint* dest). | |
647 // | |
648 // Arguments : | |
649 // | |
650 // exchange_value: O0 | |
651 // dest: O1 | |
652 // | |
653 // Results: | |
654 // | |
655 // O0: the value previously stored in dest | |
656 // | |
657 address generate_atomic_xchg() { | |
658 StubCodeMark mark(this, "StubRoutines", "atomic_xchg"); | |
659 address start = __ pc(); | |
660 | |
661 if (UseCASForSwap) { | |
662 // Use CAS instead of swap, just in case the MP hardware | |
663 // prefers to work with just one kind of synch. instruction. | |
664 Label retry; | |
665 __ BIND(retry); | |
666 __ mov(O0, O3); // scratch copy of exchange value | |
667 __ ld(O1, 0, O2); // observe the previous value | |
668 // try to replace O2 with O3 | |
669 __ cas_under_lock(O1, O2, O3, | |
670 (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr(),false); | |
671 __ cmp(O2, O3); | |
672 __ br(Assembler::notEqual, false, Assembler::pn, retry); | |
673 __ delayed()->nop(); | |
674 | |
675 __ retl(false); | |
676 __ delayed()->mov(O2, O0); // report previous value to caller | |
677 | |
678 } else { | |
679 if (VM_Version::v9_instructions_work()) { | |
680 __ retl(false); | |
681 __ delayed()->swap(O1, 0, O0); | |
682 } else { | |
683 const Register& lock_reg = O2; | |
684 const Register& lock_ptr_reg = O3; | |
685 const Register& yield_reg = O4; | |
686 | |
687 Label retry; | |
688 Label dontyield; | |
689 | |
690 generate_v8_lock_prologue(lock_reg, lock_ptr_reg, yield_reg, retry, dontyield); | |
691 // got the lock, do the swap | |
692 __ swap(O1, 0, O0); | |
693 | |
694 generate_v8_lock_epilogue(lock_reg, lock_ptr_reg, yield_reg, retry, dontyield); | |
695 __ retl(false); | |
696 __ delayed()->nop(); | |
697 } | |
698 } | |
699 | |
700 return start; | |
701 } | |
702 | |
703 | |
704 // Support for jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) | |
705 // | |
706 // Arguments : | |
707 // | |
708 // exchange_value: O0 | |
709 // dest: O1 | |
710 // compare_value: O2 | |
711 // | |
712 // Results: | |
713 // | |
714 // O0: the value previously stored in dest | |
715 // | |
716 // Overwrites (v8): O3,O4,O5 | |
717 // | |
718 address generate_atomic_cmpxchg() { | |
719 StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg"); | |
720 address start = __ pc(); | |
721 | |
722 // cmpxchg(dest, compare_value, exchange_value) | |
723 __ cas_under_lock(O1, O2, O0, | |
724 (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr(),false); | |
725 __ retl(false); | |
726 __ delayed()->nop(); | |
727 | |
728 return start; | |
729 } | |
730 | |
731 // Support for jlong Atomic::cmpxchg(jlong exchange_value, volatile jlong *dest, jlong compare_value) | |
732 // | |
733 // Arguments : | |
734 // | |
735 // exchange_value: O1:O0 | |
736 // dest: O2 | |
737 // compare_value: O4:O3 | |
738 // | |
739 // Results: | |
740 // | |
741 // O1:O0: the value previously stored in dest | |
742 // | |
743 // This only works on V9, on V8 we don't generate any | |
744 // code and just return NULL. | |
745 // | |
746 // Overwrites: G1,G2,G3 | |
747 // | |
748 address generate_atomic_cmpxchg_long() { | |
749 StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg_long"); | |
750 address start = __ pc(); | |
751 | |
752 if (!VM_Version::supports_cx8()) | |
753 return NULL;; | |
754 __ sllx(O0, 32, O0); | |
755 __ srl(O1, 0, O1); | |
756 __ or3(O0,O1,O0); // O0 holds 64-bit value from compare_value | |
757 __ sllx(O3, 32, O3); | |
758 __ srl(O4, 0, O4); | |
759 __ or3(O3,O4,O3); // O3 holds 64-bit value from exchange_value | |
760 __ casx(O2, O3, O0); | |
761 __ srl(O0, 0, O1); // unpacked return value in O1:O0 | |
762 __ retl(false); | |
763 __ delayed()->srlx(O0, 32, O0); | |
764 | |
765 return start; | |
766 } | |
767 | |
768 | |
769 // Support for jint Atomic::add(jint add_value, volatile jint* dest). | |
770 // | |
771 // Arguments : | |
772 // | |
773 // add_value: O0 (e.g., +1 or -1) | |
774 // dest: O1 | |
775 // | |
776 // Results: | |
777 // | |
778 // O0: the new value stored in dest | |
779 // | |
780 // Overwrites (v9): O3 | |
781 // Overwrites (v8): O3,O4,O5 | |
782 // | |
783 address generate_atomic_add() { | |
784 StubCodeMark mark(this, "StubRoutines", "atomic_add"); | |
785 address start = __ pc(); | |
786 __ BIND(_atomic_add_stub); | |
787 | |
788 if (VM_Version::v9_instructions_work()) { | |
789 Label(retry); | |
790 __ BIND(retry); | |
791 | |
792 __ lduw(O1, 0, O2); | |
793 __ add(O0, O2, O3); | |
794 __ cas(O1, O2, O3); | |
795 __ cmp( O2, O3); | |
796 __ br(Assembler::notEqual, false, Assembler::pn, retry); | |
797 __ delayed()->nop(); | |
798 __ retl(false); | |
799 __ delayed()->add(O0, O2, O0); // note that cas made O2==O3 | |
800 } else { | |
801 const Register& lock_reg = O2; | |
802 const Register& lock_ptr_reg = O3; | |
803 const Register& value_reg = O4; | |
804 const Register& yield_reg = O5; | |
805 | |
806 Label(retry); | |
807 Label(dontyield); | |
808 | |
809 generate_v8_lock_prologue(lock_reg, lock_ptr_reg, yield_reg, retry, dontyield); | |
810 // got lock, do the increment | |
811 __ ld(O1, 0, value_reg); | |
812 __ add(O0, value_reg, value_reg); | |
813 __ st(value_reg, O1, 0); | |
814 | |
815 // %%% only for RMO and PSO | |
816 __ membar(Assembler::StoreStore); | |
817 | |
818 generate_v8_lock_epilogue(lock_reg, lock_ptr_reg, yield_reg, retry, dontyield); | |
819 | |
820 __ retl(false); | |
821 __ delayed()->mov(value_reg, O0); | |
822 } | |
823 | |
824 return start; | |
825 } | |
826 Label _atomic_add_stub; // called from other stubs | |
827 | |
828 | |
829 //------------------------------------------------------------------------------------------------------------------------ | |
830 // The following routine generates a subroutine to throw an asynchronous | |
831 // UnknownError when an unsafe access gets a fault that could not be | |
832 // reasonably prevented by the programmer. (Example: SIGBUS/OBJERR.) | |
833 // | |
834 // Arguments : | |
835 // | |
836 // trapping PC: O7 | |
837 // | |
838 // Results: | |
839 // posts an asynchronous exception, skips the trapping instruction | |
840 // | |
841 | |
842 address generate_handler_for_unsafe_access() { | |
843 StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access"); | |
844 address start = __ pc(); | |
845 | |
846 const int preserve_register_words = (64 * 2); | |
727 | 847 Address preserve_addr(FP, (-preserve_register_words * wordSize) + STACK_BIAS); |
0 | 848 |
849 Register Lthread = L7_thread_cache; | |
850 int i; | |
851 | |
852 __ save_frame(0); | |
853 __ mov(G1, L1); | |
854 __ mov(G2, L2); | |
855 __ mov(G3, L3); | |
856 __ mov(G4, L4); | |
857 __ mov(G5, L5); | |
858 for (i = 0; i < (VM_Version::v9_instructions_work() ? 64 : 32); i += 2) { | |
859 __ stf(FloatRegisterImpl::D, as_FloatRegister(i), preserve_addr, i * wordSize); | |
860 } | |
861 | |
862 address entry_point = CAST_FROM_FN_PTR(address, handle_unsafe_access); | |
863 BLOCK_COMMENT("call handle_unsafe_access"); | |
864 __ call(entry_point, relocInfo::runtime_call_type); | |
865 __ delayed()->nop(); | |
866 | |
867 __ mov(L1, G1); | |
868 __ mov(L2, G2); | |
869 __ mov(L3, G3); | |
870 __ mov(L4, G4); | |
871 __ mov(L5, G5); | |
872 for (i = 0; i < (VM_Version::v9_instructions_work() ? 64 : 32); i += 2) { | |
873 __ ldf(FloatRegisterImpl::D, preserve_addr, as_FloatRegister(i), i * wordSize); | |
874 } | |
875 | |
876 __ verify_thread(); | |
877 | |
878 __ jmp(O0, 0); | |
879 __ delayed()->restore(); | |
880 | |
881 return start; | |
882 } | |
883 | |
884 | |
885 // Support for uint StubRoutine::Sparc::partial_subtype_check( Klass sub, Klass super ); | |
886 // Arguments : | |
887 // | |
888 // ret : O0, returned | |
889 // icc/xcc: set as O0 (depending on wordSize) | |
890 // sub : O1, argument, not changed | |
891 // super: O2, argument, not changed | |
892 // raddr: O7, blown by call | |
893 address generate_partial_subtype_check() { | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
894 __ align(CodeEntryAlignment); |
0 | 895 StubCodeMark mark(this, "StubRoutines", "partial_subtype_check"); |
896 address start = __ pc(); | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
897 Label miss; |
0 | 898 |
899 #if defined(COMPILER2) && !defined(_LP64) | |
900 // Do not use a 'save' because it blows the 64-bit O registers. | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
901 __ add(SP,-4*wordSize,SP); // Make space for 4 temps (stack must be 2 words aligned) |
0 | 902 __ st_ptr(L0,SP,(frame::register_save_words+0)*wordSize); |
903 __ st_ptr(L1,SP,(frame::register_save_words+1)*wordSize); | |
904 __ st_ptr(L2,SP,(frame::register_save_words+2)*wordSize); | |
905 __ st_ptr(L3,SP,(frame::register_save_words+3)*wordSize); | |
906 Register Rret = O0; | |
907 Register Rsub = O1; | |
908 Register Rsuper = O2; | |
909 #else | |
910 __ save_frame(0); | |
911 Register Rret = I0; | |
912 Register Rsub = I1; | |
913 Register Rsuper = I2; | |
914 #endif | |
915 | |
916 Register L0_ary_len = L0; | |
917 Register L1_ary_ptr = L1; | |
918 Register L2_super = L2; | |
919 Register L3_index = L3; | |
920 | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
921 __ check_klass_subtype_slow_path(Rsub, Rsuper, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
922 L0, L1, L2, L3, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
923 NULL, &miss); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
924 |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
925 // Match falls through here. |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
926 __ addcc(G0,0,Rret); // set Z flags, Z result |
0 | 927 |
928 #if defined(COMPILER2) && !defined(_LP64) | |
929 __ ld_ptr(SP,(frame::register_save_words+0)*wordSize,L0); | |
930 __ ld_ptr(SP,(frame::register_save_words+1)*wordSize,L1); | |
931 __ ld_ptr(SP,(frame::register_save_words+2)*wordSize,L2); | |
932 __ ld_ptr(SP,(frame::register_save_words+3)*wordSize,L3); | |
933 __ retl(); // Result in Rret is zero; flags set to Z | |
934 __ delayed()->add(SP,4*wordSize,SP); | |
935 #else | |
936 __ ret(); // Result in Rret is zero; flags set to Z | |
937 __ delayed()->restore(); | |
938 #endif | |
939 | |
940 __ BIND(miss); | |
941 __ addcc(G0,1,Rret); // set NZ flags, NZ result | |
942 | |
943 #if defined(COMPILER2) && !defined(_LP64) | |
944 __ ld_ptr(SP,(frame::register_save_words+0)*wordSize,L0); | |
945 __ ld_ptr(SP,(frame::register_save_words+1)*wordSize,L1); | |
946 __ ld_ptr(SP,(frame::register_save_words+2)*wordSize,L2); | |
947 __ ld_ptr(SP,(frame::register_save_words+3)*wordSize,L3); | |
948 __ retl(); // Result in Rret is != 0; flags set to NZ | |
949 __ delayed()->add(SP,4*wordSize,SP); | |
950 #else | |
951 __ ret(); // Result in Rret is != 0; flags set to NZ | |
952 __ delayed()->restore(); | |
953 #endif | |
954 | |
955 return start; | |
956 } | |
957 | |
958 | |
959 // Called from MacroAssembler::verify_oop | |
960 // | |
961 address generate_verify_oop_subroutine() { | |
962 StubCodeMark mark(this, "StubRoutines", "verify_oop_stub"); | |
963 | |
964 address start = __ pc(); | |
965 | |
966 __ verify_oop_subroutine(); | |
967 | |
968 return start; | |
969 } | |
970 | |
971 static address disjoint_byte_copy_entry; | |
972 static address disjoint_short_copy_entry; | |
973 static address disjoint_int_copy_entry; | |
974 static address disjoint_long_copy_entry; | |
975 static address disjoint_oop_copy_entry; | |
976 | |
977 static address byte_copy_entry; | |
978 static address short_copy_entry; | |
979 static address int_copy_entry; | |
980 static address long_copy_entry; | |
981 static address oop_copy_entry; | |
982 | |
983 static address checkcast_copy_entry; | |
984 | |
985 // | |
986 // Verify that a register contains clean 32-bits positive value | |
987 // (high 32-bits are 0) so it could be used in 64-bits shifts (sllx, srax). | |
988 // | |
989 // Input: | |
990 // Rint - 32-bits value | |
991 // Rtmp - scratch | |
992 // | |
993 void assert_clean_int(Register Rint, Register Rtmp) { | |
994 #if defined(ASSERT) && defined(_LP64) | |
995 __ signx(Rint, Rtmp); | |
996 __ cmp(Rint, Rtmp); | |
997 __ breakpoint_trap(Assembler::notEqual, Assembler::xcc); | |
998 #endif | |
999 } | |
1000 | |
1001 // | |
1002 // Generate overlap test for array copy stubs | |
1003 // | |
1004 // Input: | |
1005 // O0 - array1 | |
1006 // O1 - array2 | |
1007 // O2 - element count | |
1008 // | |
1009 // Kills temps: O3, O4 | |
1010 // | |
1011 void array_overlap_test(address no_overlap_target, int log2_elem_size) { | |
1012 assert(no_overlap_target != NULL, "must be generated"); | |
1013 array_overlap_test(no_overlap_target, NULL, log2_elem_size); | |
1014 } | |
1015 void array_overlap_test(Label& L_no_overlap, int log2_elem_size) { | |
1016 array_overlap_test(NULL, &L_no_overlap, log2_elem_size); | |
1017 } | |
1018 void array_overlap_test(address no_overlap_target, Label* NOLp, int log2_elem_size) { | |
1019 const Register from = O0; | |
1020 const Register to = O1; | |
1021 const Register count = O2; | |
1022 const Register to_from = O3; // to - from | |
1023 const Register byte_count = O4; // count << log2_elem_size | |
1024 | |
1025 __ subcc(to, from, to_from); | |
1026 __ sll_ptr(count, log2_elem_size, byte_count); | |
1027 if (NOLp == NULL) | |
1028 __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, no_overlap_target); | |
1029 else | |
1030 __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, (*NOLp)); | |
1031 __ delayed()->cmp(to_from, byte_count); | |
1032 if (NOLp == NULL) | |
1655
e7ec8cd4dd8a
6962569: assembler_sparc.cpp:1969: assert(false) failed: error
tonyp
parents:
1579
diff
changeset
|
1033 __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, no_overlap_target); |
0 | 1034 else |
1655
e7ec8cd4dd8a
6962569: assembler_sparc.cpp:1969: assert(false) failed: error
tonyp
parents:
1579
diff
changeset
|
1035 __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, (*NOLp)); |
0 | 1036 __ delayed()->nop(); |
1037 } | |
1038 | |
1039 // | |
1040 // Generate pre-write barrier for array. | |
1041 // | |
1042 // Input: | |
1043 // addr - register containing starting address | |
1044 // count - register containing element count | |
1045 // tmp - scratch register | |
1046 // | |
1047 // The input registers are overwritten. | |
1048 // | |
1049 void gen_write_ref_array_pre_barrier(Register addr, Register count) { | |
1050 BarrierSet* bs = Universe::heap()->barrier_set(); | |
1051 if (bs->has_write_ref_pre_barrier()) { | |
1052 assert(bs->has_write_ref_array_pre_opt(), | |
1053 "Else unsupported barrier set."); | |
1054 | |
1055 __ save_frame(0); | |
1056 // Save the necessary global regs... will be used after. | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1057 if (addr->is_global()) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1058 __ mov(addr, L0); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1059 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1060 if (count->is_global()) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1061 __ mov(count, L1); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1062 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1063 __ mov(addr->after_save(), O0); |
0 | 1064 // Get the count into O1 |
1065 __ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre)); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1066 __ delayed()->mov(count->after_save(), O1); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1067 if (addr->is_global()) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1068 __ mov(L0, addr); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1069 } |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1070 if (count->is_global()) { |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1071 __ mov(L1, count); |
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1072 } |
0 | 1073 __ restore(); |
1074 } | |
1075 } | |
1076 // | |
1077 // Generate post-write barrier for array. | |
1078 // | |
1079 // Input: | |
1080 // addr - register containing starting address | |
1081 // count - register containing element count | |
1082 // tmp - scratch register | |
1083 // | |
1084 // The input registers are overwritten. | |
1085 // | |
1086 void gen_write_ref_array_post_barrier(Register addr, Register count, | |
1087 Register tmp) { | |
1088 BarrierSet* bs = Universe::heap()->barrier_set(); | |
1089 | |
1090 switch (bs->kind()) { | |
1091 case BarrierSet::G1SATBCT: | |
1092 case BarrierSet::G1SATBCTLogging: | |
1093 { | |
1094 // Get some new fresh output registers. | |
1095 __ save_frame(0); | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1096 __ mov(addr->after_save(), O0); |
0 | 1097 __ call(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post)); |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
1098 __ delayed()->mov(count->after_save(), O1); |
0 | 1099 __ restore(); |
1100 } | |
1101 break; | |
1102 case BarrierSet::CardTableModRef: | |
1103 case BarrierSet::CardTableExtension: | |
1104 { | |
1105 CardTableModRefBS* ct = (CardTableModRefBS*)bs; | |
1106 assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); | |
1107 assert_different_registers(addr, count, tmp); | |
1108 | |
1109 Label L_loop; | |
1110 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
1111 __ sll_ptr(count, LogBytesPerHeapOop, count); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
1112 __ sub(count, BytesPerHeapOop, count); |
0 | 1113 __ add(count, addr, count); |
1114 // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.) | |
1115 __ srl_ptr(addr, CardTableModRefBS::card_shift, addr); | |
1116 __ srl_ptr(count, CardTableModRefBS::card_shift, count); | |
1117 __ sub(count, addr, count); | |
727 | 1118 AddressLiteral rs(ct->byte_map_base); |
1119 __ set(rs, tmp); | |
0 | 1120 __ BIND(L_loop); |
727 | 1121 __ stb(G0, tmp, addr); |
0 | 1122 __ subcc(count, 1, count); |
1123 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); | |
1124 __ delayed()->add(addr, 1, addr); | |
727 | 1125 } |
0 | 1126 break; |
1127 case BarrierSet::ModRef: | |
1128 break; | |
727 | 1129 default: |
0 | 1130 ShouldNotReachHere(); |
1131 } | |
1132 } | |
1133 | |
1134 | |
1135 // Copy big chunks forward with shift | |
1136 // | |
1137 // Inputs: | |
1138 // from - source arrays | |
1139 // to - destination array aligned to 8-bytes | |
1140 // count - elements count to copy >= the count equivalent to 16 bytes | |
1141 // count_dec - elements count's decrement equivalent to 16 bytes | |
1142 // L_copy_bytes - copy exit label | |
1143 // | |
1144 void copy_16_bytes_forward_with_shift(Register from, Register to, | |
1145 Register count, int count_dec, Label& L_copy_bytes) { | |
1146 Label L_loop, L_aligned_copy, L_copy_last_bytes; | |
1147 | |
1148 // if both arrays have the same alignment mod 8, do 8 bytes aligned copy | |
1149 __ andcc(from, 7, G1); // misaligned bytes | |
1150 __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); | |
1151 __ delayed()->nop(); | |
1152 | |
1153 const Register left_shift = G1; // left shift bit counter | |
1154 const Register right_shift = G5; // right shift bit counter | |
1155 | |
1156 __ sll(G1, LogBitsPerByte, left_shift); | |
1157 __ mov(64, right_shift); | |
1158 __ sub(right_shift, left_shift, right_shift); | |
1159 | |
1160 // | |
1161 // Load 2 aligned 8-bytes chunks and use one from previous iteration | |
1162 // to form 2 aligned 8-bytes chunks to store. | |
1163 // | |
1164 __ deccc(count, count_dec); // Pre-decrement 'count' | |
1165 __ andn(from, 7, from); // Align address | |
1166 __ ldx(from, 0, O3); | |
1167 __ inc(from, 8); | |
1365 | 1168 __ align(OptoLoopAlignment); |
0 | 1169 __ BIND(L_loop); |
1170 __ ldx(from, 0, O4); | |
1171 __ deccc(count, count_dec); // Can we do next iteration after this one? | |
1172 __ ldx(from, 8, G4); | |
1173 __ inc(to, 16); | |
1174 __ inc(from, 16); | |
1175 __ sllx(O3, left_shift, O3); | |
1176 __ srlx(O4, right_shift, G3); | |
1177 __ bset(G3, O3); | |
1178 __ stx(O3, to, -16); | |
1179 __ sllx(O4, left_shift, O4); | |
1180 __ srlx(G4, right_shift, G3); | |
1181 __ bset(G3, O4); | |
1182 __ stx(O4, to, -8); | |
1183 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); | |
1184 __ delayed()->mov(G4, O3); | |
1185 | |
1186 __ inccc(count, count_dec>>1 ); // + 8 bytes | |
1187 __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes); | |
1188 __ delayed()->inc(count, count_dec>>1); // restore 'count' | |
1189 | |
1190 // copy 8 bytes, part of them already loaded in O3 | |
1191 __ ldx(from, 0, O4); | |
1192 __ inc(to, 8); | |
1193 __ inc(from, 8); | |
1194 __ sllx(O3, left_shift, O3); | |
1195 __ srlx(O4, right_shift, G3); | |
1196 __ bset(O3, G3); | |
1197 __ stx(G3, to, -8); | |
1198 | |
1199 __ BIND(L_copy_last_bytes); | |
1200 __ srl(right_shift, LogBitsPerByte, right_shift); // misaligned bytes | |
1201 __ br(Assembler::always, false, Assembler::pt, L_copy_bytes); | |
1202 __ delayed()->sub(from, right_shift, from); // restore address | |
1203 | |
1204 __ BIND(L_aligned_copy); | |
1205 } | |
1206 | |
1207 // Copy big chunks backward with shift | |
1208 // | |
1209 // Inputs: | |
1210 // end_from - source arrays end address | |
1211 // end_to - destination array end address aligned to 8-bytes | |
1212 // count - elements count to copy >= the count equivalent to 16 bytes | |
1213 // count_dec - elements count's decrement equivalent to 16 bytes | |
1214 // L_aligned_copy - aligned copy exit label | |
1215 // L_copy_bytes - copy exit label | |
1216 // | |
1217 void copy_16_bytes_backward_with_shift(Register end_from, Register end_to, | |
1218 Register count, int count_dec, | |
1219 Label& L_aligned_copy, Label& L_copy_bytes) { | |
1220 Label L_loop, L_copy_last_bytes; | |
1221 | |
1222 // if both arrays have the same alignment mod 8, do 8 bytes aligned copy | |
1223 __ andcc(end_from, 7, G1); // misaligned bytes | |
1224 __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); | |
1225 __ delayed()->deccc(count, count_dec); // Pre-decrement 'count' | |
1226 | |
1227 const Register left_shift = G1; // left shift bit counter | |
1228 const Register right_shift = G5; // right shift bit counter | |
1229 | |
1230 __ sll(G1, LogBitsPerByte, left_shift); | |
1231 __ mov(64, right_shift); | |
1232 __ sub(right_shift, left_shift, right_shift); | |
1233 | |
1234 // | |
1235 // Load 2 aligned 8-bytes chunks and use one from previous iteration | |
1236 // to form 2 aligned 8-bytes chunks to store. | |
1237 // | |
1238 __ andn(end_from, 7, end_from); // Align address | |
1239 __ ldx(end_from, 0, O3); | |
1365 | 1240 __ align(OptoLoopAlignment); |
0 | 1241 __ BIND(L_loop); |
1242 __ ldx(end_from, -8, O4); | |
1243 __ deccc(count, count_dec); // Can we do next iteration after this one? | |
1244 __ ldx(end_from, -16, G4); | |
1245 __ dec(end_to, 16); | |
1246 __ dec(end_from, 16); | |
1247 __ srlx(O3, right_shift, O3); | |
1248 __ sllx(O4, left_shift, G3); | |
1249 __ bset(G3, O3); | |
1250 __ stx(O3, end_to, 8); | |
1251 __ srlx(O4, right_shift, O4); | |
1252 __ sllx(G4, left_shift, G3); | |
1253 __ bset(G3, O4); | |
1254 __ stx(O4, end_to, 0); | |
1255 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); | |
1256 __ delayed()->mov(G4, O3); | |
1257 | |
1258 __ inccc(count, count_dec>>1 ); // + 8 bytes | |
1259 __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes); | |
1260 __ delayed()->inc(count, count_dec>>1); // restore 'count' | |
1261 | |
1262 // copy 8 bytes, part of them already loaded in O3 | |
1263 __ ldx(end_from, -8, O4); | |
1264 __ dec(end_to, 8); | |
1265 __ dec(end_from, 8); | |
1266 __ srlx(O3, right_shift, O3); | |
1267 __ sllx(O4, left_shift, G3); | |
1268 __ bset(O3, G3); | |
1269 __ stx(G3, end_to, 0); | |
1270 | |
1271 __ BIND(L_copy_last_bytes); | |
1272 __ srl(left_shift, LogBitsPerByte, left_shift); // misaligned bytes | |
1273 __ br(Assembler::always, false, Assembler::pt, L_copy_bytes); | |
1274 __ delayed()->add(end_from, left_shift, end_from); // restore address | |
1275 } | |
1276 | |
1277 // | |
1278 // Generate stub for disjoint byte copy. If "aligned" is true, the | |
1279 // "from" and "to" addresses are assumed to be heapword aligned. | |
1280 // | |
1281 // Arguments for generated stub: | |
1282 // from: O0 | |
1283 // to: O1 | |
1284 // count: O2 treated as signed | |
1285 // | |
1286 address generate_disjoint_byte_copy(bool aligned, const char * name) { | |
1287 __ align(CodeEntryAlignment); | |
1288 StubCodeMark mark(this, "StubRoutines", name); | |
1289 address start = __ pc(); | |
1290 | |
1291 Label L_skip_alignment, L_align; | |
1292 Label L_copy_byte, L_copy_byte_loop, L_exit; | |
1293 | |
1294 const Register from = O0; // source array address | |
1295 const Register to = O1; // destination array address | |
1296 const Register count = O2; // elements count | |
1297 const Register offset = O5; // offset from start of arrays | |
1298 // O3, O4, G3, G4 are used as temp registers | |
1299 | |
1300 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
1301 | |
1302 if (!aligned) disjoint_byte_copy_entry = __ pc(); | |
1303 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
1304 if (!aligned) BLOCK_COMMENT("Entry:"); | |
1305 | |
1306 // for short arrays, just do single element copy | |
1307 __ cmp(count, 23); // 16 + 7 | |
1308 __ brx(Assembler::less, false, Assembler::pn, L_copy_byte); | |
1309 __ delayed()->mov(G0, offset); | |
1310 | |
1311 if (aligned) { | |
1312 // 'aligned' == true when it is known statically during compilation | |
1313 // of this arraycopy call site that both 'from' and 'to' addresses | |
1314 // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()). | |
1315 // | |
1316 // Aligned arrays have 4 bytes alignment in 32-bits VM | |
1317 // and 8 bytes - in 64-bits VM. So we do it only for 32-bits VM | |
1318 // | |
1319 #ifndef _LP64 | |
1320 // copy a 4-bytes word if necessary to align 'to' to 8 bytes | |
1321 __ andcc(to, 7, G0); | |
1322 __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment); | |
1323 __ delayed()->ld(from, 0, O3); | |
1324 __ inc(from, 4); | |
1325 __ inc(to, 4); | |
1326 __ dec(count, 4); | |
1327 __ st(O3, to, -4); | |
1328 __ BIND(L_skip_alignment); | |
1329 #endif | |
1330 } else { | |
1331 // copy bytes to align 'to' on 8 byte boundary | |
1332 __ andcc(to, 7, G1); // misaligned bytes | |
1333 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
1334 __ delayed()->neg(G1); | |
1335 __ inc(G1, 8); // bytes need to copy to next 8-bytes alignment | |
1336 __ sub(count, G1, count); | |
1337 __ BIND(L_align); | |
1338 __ ldub(from, 0, O3); | |
1339 __ deccc(G1); | |
1340 __ inc(from); | |
1341 __ stb(O3, to, 0); | |
1342 __ br(Assembler::notZero, false, Assembler::pt, L_align); | |
1343 __ delayed()->inc(to); | |
1344 __ BIND(L_skip_alignment); | |
1345 } | |
1346 #ifdef _LP64 | |
1347 if (!aligned) | |
1348 #endif | |
1349 { | |
1350 // Copy with shift 16 bytes per iteration if arrays do not have | |
1351 // the same alignment mod 8, otherwise fall through to the next | |
1352 // code for aligned copy. | |
1353 // The compare above (count >= 23) guarantes 'count' >= 16 bytes. | |
1354 // Also jump over aligned copy after the copy with shift completed. | |
1355 | |
1356 copy_16_bytes_forward_with_shift(from, to, count, 16, L_copy_byte); | |
1357 } | |
1358 | |
1359 // Both array are 8 bytes aligned, copy 16 bytes at a time | |
1360 __ and3(count, 7, G4); // Save count | |
1361 __ srl(count, 3, count); | |
1362 generate_disjoint_long_copy_core(aligned); | |
1363 __ mov(G4, count); // Restore count | |
1364 | |
1365 // copy tailing bytes | |
1366 __ BIND(L_copy_byte); | |
1367 __ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit); | |
1368 __ delayed()->nop(); | |
1365 | 1369 __ align(OptoLoopAlignment); |
0 | 1370 __ BIND(L_copy_byte_loop); |
1371 __ ldub(from, offset, O3); | |
1372 __ deccc(count); | |
1373 __ stb(O3, to, offset); | |
1374 __ brx(Assembler::notZero, false, Assembler::pt, L_copy_byte_loop); | |
1375 __ delayed()->inc(offset); | |
1376 | |
1377 __ BIND(L_exit); | |
1378 // O3, O4 are used as temp registers | |
1379 inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr, O3, O4); | |
1380 __ retl(); | |
1381 __ delayed()->mov(G0, O0); // return 0 | |
1382 return start; | |
1383 } | |
1384 | |
1385 // | |
1386 // Generate stub for conjoint byte copy. If "aligned" is true, the | |
1387 // "from" and "to" addresses are assumed to be heapword aligned. | |
1388 // | |
1389 // Arguments for generated stub: | |
1390 // from: O0 | |
1391 // to: O1 | |
1392 // count: O2 treated as signed | |
1393 // | |
1394 address generate_conjoint_byte_copy(bool aligned, const char * name) { | |
1395 // Do reverse copy. | |
1396 | |
1397 __ align(CodeEntryAlignment); | |
1398 StubCodeMark mark(this, "StubRoutines", name); | |
1399 address start = __ pc(); | |
1400 address nooverlap_target = aligned ? | |
1401 StubRoutines::arrayof_jbyte_disjoint_arraycopy() : | |
1402 disjoint_byte_copy_entry; | |
1403 | |
1404 Label L_skip_alignment, L_align, L_aligned_copy; | |
1405 Label L_copy_byte, L_copy_byte_loop, L_exit; | |
1406 | |
1407 const Register from = O0; // source array address | |
1408 const Register to = O1; // destination array address | |
1409 const Register count = O2; // elements count | |
1410 const Register end_from = from; // source array end address | |
1411 const Register end_to = to; // destination array end address | |
1412 | |
1413 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
1414 | |
1415 if (!aligned) byte_copy_entry = __ pc(); | |
1416 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
1417 if (!aligned) BLOCK_COMMENT("Entry:"); | |
1418 | |
1419 array_overlap_test(nooverlap_target, 0); | |
1420 | |
1421 __ add(to, count, end_to); // offset after last copied element | |
1422 | |
1423 // for short arrays, just do single element copy | |
1424 __ cmp(count, 23); // 16 + 7 | |
1425 __ brx(Assembler::less, false, Assembler::pn, L_copy_byte); | |
1426 __ delayed()->add(from, count, end_from); | |
1427 | |
1428 { | |
1429 // Align end of arrays since they could be not aligned even | |
1430 // when arrays itself are aligned. | |
1431 | |
1432 // copy bytes to align 'end_to' on 8 byte boundary | |
1433 __ andcc(end_to, 7, G1); // misaligned bytes | |
1434 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
1435 __ delayed()->nop(); | |
1436 __ sub(count, G1, count); | |
1437 __ BIND(L_align); | |
1438 __ dec(end_from); | |
1439 __ dec(end_to); | |
1440 __ ldub(end_from, 0, O3); | |
1441 __ deccc(G1); | |
1442 __ brx(Assembler::notZero, false, Assembler::pt, L_align); | |
1443 __ delayed()->stb(O3, end_to, 0); | |
1444 __ BIND(L_skip_alignment); | |
1445 } | |
1446 #ifdef _LP64 | |
1447 if (aligned) { | |
1448 // Both arrays are aligned to 8-bytes in 64-bits VM. | |
1449 // The 'count' is decremented in copy_16_bytes_backward_with_shift() | |
1450 // in unaligned case. | |
1451 __ dec(count, 16); | |
1452 } else | |
1453 #endif | |
1454 { | |
1455 // Copy with shift 16 bytes per iteration if arrays do not have | |
1456 // the same alignment mod 8, otherwise jump to the next | |
1457 // code for aligned copy (and substracting 16 from 'count' before jump). | |
1458 // The compare above (count >= 11) guarantes 'count' >= 16 bytes. | |
1459 // Also jump over aligned copy after the copy with shift completed. | |
1460 | |
1461 copy_16_bytes_backward_with_shift(end_from, end_to, count, 16, | |
1462 L_aligned_copy, L_copy_byte); | |
1463 } | |
1464 // copy 4 elements (16 bytes) at a time | |
1365 | 1465 __ align(OptoLoopAlignment); |
0 | 1466 __ BIND(L_aligned_copy); |
1467 __ dec(end_from, 16); | |
1468 __ ldx(end_from, 8, O3); | |
1469 __ ldx(end_from, 0, O4); | |
1470 __ dec(end_to, 16); | |
1471 __ deccc(count, 16); | |
1472 __ stx(O3, end_to, 8); | |
1473 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy); | |
1474 __ delayed()->stx(O4, end_to, 0); | |
1475 __ inc(count, 16); | |
1476 | |
1477 // copy 1 element (2 bytes) at a time | |
1478 __ BIND(L_copy_byte); | |
1479 __ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit); | |
1480 __ delayed()->nop(); | |
1365 | 1481 __ align(OptoLoopAlignment); |
0 | 1482 __ BIND(L_copy_byte_loop); |
1483 __ dec(end_from); | |
1484 __ dec(end_to); | |
1485 __ ldub(end_from, 0, O4); | |
1486 __ deccc(count); | |
1487 __ brx(Assembler::greater, false, Assembler::pt, L_copy_byte_loop); | |
1488 __ delayed()->stb(O4, end_to, 0); | |
1489 | |
1490 __ BIND(L_exit); | |
1491 // O3, O4 are used as temp registers | |
1492 inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr, O3, O4); | |
1493 __ retl(); | |
1494 __ delayed()->mov(G0, O0); // return 0 | |
1495 return start; | |
1496 } | |
1497 | |
1498 // | |
1499 // Generate stub for disjoint short copy. If "aligned" is true, the | |
1500 // "from" and "to" addresses are assumed to be heapword aligned. | |
1501 // | |
1502 // Arguments for generated stub: | |
1503 // from: O0 | |
1504 // to: O1 | |
1505 // count: O2 treated as signed | |
1506 // | |
1507 address generate_disjoint_short_copy(bool aligned, const char * name) { | |
1508 __ align(CodeEntryAlignment); | |
1509 StubCodeMark mark(this, "StubRoutines", name); | |
1510 address start = __ pc(); | |
1511 | |
1512 Label L_skip_alignment, L_skip_alignment2; | |
1513 Label L_copy_2_bytes, L_copy_2_bytes_loop, L_exit; | |
1514 | |
1515 const Register from = O0; // source array address | |
1516 const Register to = O1; // destination array address | |
1517 const Register count = O2; // elements count | |
1518 const Register offset = O5; // offset from start of arrays | |
1519 // O3, O4, G3, G4 are used as temp registers | |
1520 | |
1521 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
1522 | |
1523 if (!aligned) disjoint_short_copy_entry = __ pc(); | |
1524 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
1525 if (!aligned) BLOCK_COMMENT("Entry:"); | |
1526 | |
1527 // for short arrays, just do single element copy | |
1528 __ cmp(count, 11); // 8 + 3 (22 bytes) | |
1529 __ brx(Assembler::less, false, Assembler::pn, L_copy_2_bytes); | |
1530 __ delayed()->mov(G0, offset); | |
1531 | |
1532 if (aligned) { | |
1533 // 'aligned' == true when it is known statically during compilation | |
1534 // of this arraycopy call site that both 'from' and 'to' addresses | |
1535 // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()). | |
1536 // | |
1537 // Aligned arrays have 4 bytes alignment in 32-bits VM | |
1538 // and 8 bytes - in 64-bits VM. | |
1539 // | |
1540 #ifndef _LP64 | |
1541 // copy a 2-elements word if necessary to align 'to' to 8 bytes | |
1542 __ andcc(to, 7, G0); | |
1543 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
1544 __ delayed()->ld(from, 0, O3); | |
1545 __ inc(from, 4); | |
1546 __ inc(to, 4); | |
1547 __ dec(count, 2); | |
1548 __ st(O3, to, -4); | |
1549 __ BIND(L_skip_alignment); | |
1550 #endif | |
1551 } else { | |
1552 // copy 1 element if necessary to align 'to' on an 4 bytes | |
1553 __ andcc(to, 3, G0); | |
1554 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
1555 __ delayed()->lduh(from, 0, O3); | |
1556 __ inc(from, 2); | |
1557 __ inc(to, 2); | |
1558 __ dec(count); | |
1559 __ sth(O3, to, -2); | |
1560 __ BIND(L_skip_alignment); | |
1561 | |
1562 // copy 2 elements to align 'to' on an 8 byte boundary | |
1563 __ andcc(to, 7, G0); | |
1564 __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment2); | |
1565 __ delayed()->lduh(from, 0, O3); | |
1566 __ dec(count, 2); | |
1567 __ lduh(from, 2, O4); | |
1568 __ inc(from, 4); | |
1569 __ inc(to, 4); | |
1570 __ sth(O3, to, -4); | |
1571 __ sth(O4, to, -2); | |
1572 __ BIND(L_skip_alignment2); | |
1573 } | |
1574 #ifdef _LP64 | |
1575 if (!aligned) | |
1576 #endif | |
1577 { | |
1578 // Copy with shift 16 bytes per iteration if arrays do not have | |
1579 // the same alignment mod 8, otherwise fall through to the next | |
1580 // code for aligned copy. | |
1581 // The compare above (count >= 11) guarantes 'count' >= 16 bytes. | |
1582 // Also jump over aligned copy after the copy with shift completed. | |
1583 | |
1584 copy_16_bytes_forward_with_shift(from, to, count, 8, L_copy_2_bytes); | |
1585 } | |
1586 | |
1587 // Both array are 8 bytes aligned, copy 16 bytes at a time | |
1588 __ and3(count, 3, G4); // Save | |
1589 __ srl(count, 2, count); | |
1590 generate_disjoint_long_copy_core(aligned); | |
1591 __ mov(G4, count); // restore | |
1592 | |
1593 // copy 1 element at a time | |
1594 __ BIND(L_copy_2_bytes); | |
1595 __ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit); | |
1596 __ delayed()->nop(); | |
1365 | 1597 __ align(OptoLoopAlignment); |
0 | 1598 __ BIND(L_copy_2_bytes_loop); |
1599 __ lduh(from, offset, O3); | |
1600 __ deccc(count); | |
1601 __ sth(O3, to, offset); | |
1602 __ brx(Assembler::notZero, false, Assembler::pt, L_copy_2_bytes_loop); | |
1603 __ delayed()->inc(offset, 2); | |
1604 | |
1605 __ BIND(L_exit); | |
1606 // O3, O4 are used as temp registers | |
1607 inc_counter_np(SharedRuntime::_jshort_array_copy_ctr, O3, O4); | |
1608 __ retl(); | |
1609 __ delayed()->mov(G0, O0); // return 0 | |
1610 return start; | |
1611 } | |
1612 | |
1613 // | |
1763 | 1614 // Generate stub for disjoint short fill. If "aligned" is true, the |
1615 // "to" address is assumed to be heapword aligned. | |
1616 // | |
1617 // Arguments for generated stub: | |
1618 // to: O0 | |
1619 // value: O1 | |
1620 // count: O2 treated as signed | |
1621 // | |
1622 address generate_fill(BasicType t, bool aligned, const char* name) { | |
1623 __ align(CodeEntryAlignment); | |
1624 StubCodeMark mark(this, "StubRoutines", name); | |
1625 address start = __ pc(); | |
1626 | |
1627 const Register to = O0; // source array address | |
1628 const Register value = O1; // fill value | |
1629 const Register count = O2; // elements count | |
1630 // O3 is used as a temp register | |
1631 | |
1632 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
1633 | |
1634 Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte; | |
1794 | 1635 Label L_fill_2_bytes, L_fill_elements, L_fill_32_bytes; |
1763 | 1636 |
1637 int shift = -1; | |
1638 switch (t) { | |
1639 case T_BYTE: | |
1640 shift = 2; | |
1641 break; | |
1642 case T_SHORT: | |
1643 shift = 1; | |
1644 break; | |
1645 case T_INT: | |
1646 shift = 0; | |
1647 break; | |
1648 default: ShouldNotReachHere(); | |
1649 } | |
1650 | |
1651 BLOCK_COMMENT("Entry:"); | |
1652 | |
1653 if (t == T_BYTE) { | |
1654 // Zero extend value | |
1655 __ and3(value, 0xff, value); | |
1656 __ sllx(value, 8, O3); | |
1657 __ or3(value, O3, value); | |
1658 } | |
1659 if (t == T_SHORT) { | |
1660 // Zero extend value | |
1794 | 1661 __ sllx(value, 48, value); |
1662 __ srlx(value, 48, value); | |
1763 | 1663 } |
1664 if (t == T_BYTE || t == T_SHORT) { | |
1665 __ sllx(value, 16, O3); | |
1666 __ or3(value, O3, value); | |
1667 } | |
1668 | |
1669 __ cmp(count, 2<<shift); // Short arrays (< 8 bytes) fill by element | |
1794 | 1670 __ brx(Assembler::lessUnsigned, false, Assembler::pn, L_fill_elements); // use unsigned cmp |
1671 __ delayed()->andcc(count, 1, G0); | |
1763 | 1672 |
1673 if (!aligned && (t == T_BYTE || t == T_SHORT)) { | |
1674 // align source address at 4 bytes address boundary | |
1675 if (t == T_BYTE) { | |
1676 // One byte misalignment happens only for byte arrays | |
1677 __ andcc(to, 1, G0); | |
1678 __ br(Assembler::zero, false, Assembler::pt, L_skip_align1); | |
1679 __ delayed()->nop(); | |
1680 __ stb(value, to, 0); | |
1681 __ inc(to, 1); | |
1682 __ dec(count, 1); | |
1683 __ BIND(L_skip_align1); | |
1684 } | |
1685 // Two bytes misalignment happens only for byte and short (char) arrays | |
1686 __ andcc(to, 2, G0); | |
1687 __ br(Assembler::zero, false, Assembler::pt, L_skip_align2); | |
1688 __ delayed()->nop(); | |
1689 __ sth(value, to, 0); | |
1690 __ inc(to, 2); | |
1691 __ dec(count, 1 << (shift - 1)); | |
1692 __ BIND(L_skip_align2); | |
1693 } | |
1694 #ifdef _LP64 | |
1695 if (!aligned) { | |
1696 #endif | |
1697 // align to 8 bytes, we know we are 4 byte aligned to start | |
1698 __ andcc(to, 7, G0); | |
1699 __ br(Assembler::zero, false, Assembler::pt, L_fill_32_bytes); | |
1700 __ delayed()->nop(); | |
1701 __ stw(value, to, 0); | |
1702 __ inc(to, 4); | |
1703 __ dec(count, 1 << shift); | |
1704 __ BIND(L_fill_32_bytes); | |
1705 #ifdef _LP64 | |
1706 } | |
1707 #endif | |
1708 | |
1709 if (t == T_INT) { | |
1710 // Zero extend value | |
1711 __ srl(value, 0, value); | |
1712 } | |
1713 if (t == T_BYTE || t == T_SHORT || t == T_INT) { | |
1714 __ sllx(value, 32, O3); | |
1715 __ or3(value, O3, value); | |
1716 } | |
1717 | |
1782 | 1718 Label L_check_fill_8_bytes; |
1719 // Fill 32-byte chunks | |
1720 __ subcc(count, 8 << shift, count); | |
1721 __ brx(Assembler::less, false, Assembler::pt, L_check_fill_8_bytes); | |
1722 __ delayed()->nop(); | |
1723 | |
1794 | 1724 Label L_fill_32_bytes_loop, L_fill_4_bytes; |
1763 | 1725 __ align(16); |
1726 __ BIND(L_fill_32_bytes_loop); | |
1727 | |
1728 __ stx(value, to, 0); | |
1729 __ stx(value, to, 8); | |
1730 __ stx(value, to, 16); | |
1731 __ stx(value, to, 24); | |
1732 | |
1733 __ subcc(count, 8 << shift, count); | |
1734 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_fill_32_bytes_loop); | |
1735 __ delayed()->add(to, 32, to); | |
1736 | |
1737 __ BIND(L_check_fill_8_bytes); | |
1738 __ addcc(count, 8 << shift, count); | |
1739 __ brx(Assembler::zero, false, Assembler::pn, L_exit); | |
1740 __ delayed()->subcc(count, 1 << (shift + 1), count); | |
1741 __ brx(Assembler::less, false, Assembler::pn, L_fill_4_bytes); | |
1742 __ delayed()->andcc(count, 1<<shift, G0); | |
1743 | |
1744 // | |
1745 // length is too short, just fill 8 bytes at a time | |
1746 // | |
1747 Label L_fill_8_bytes_loop; | |
1748 __ BIND(L_fill_8_bytes_loop); | |
1749 __ stx(value, to, 0); | |
1750 __ subcc(count, 1 << (shift + 1), count); | |
1751 __ brx(Assembler::greaterEqual, false, Assembler::pn, L_fill_8_bytes_loop); | |
1752 __ delayed()->add(to, 8, to); | |
1753 | |
1754 // fill trailing 4 bytes | |
1755 __ andcc(count, 1<<shift, G0); // in delay slot of branches | |
1794 | 1756 if (t == T_INT) { |
1757 __ BIND(L_fill_elements); | |
1758 } | |
1763 | 1759 __ BIND(L_fill_4_bytes); |
1760 __ brx(Assembler::zero, false, Assembler::pt, L_fill_2_bytes); | |
1761 if (t == T_BYTE || t == T_SHORT) { | |
1762 __ delayed()->andcc(count, 1<<(shift-1), G0); | |
1763 } else { | |
1764 __ delayed()->nop(); | |
1765 } | |
1766 __ stw(value, to, 0); | |
1767 if (t == T_BYTE || t == T_SHORT) { | |
1768 __ inc(to, 4); | |
1769 // fill trailing 2 bytes | |
1770 __ andcc(count, 1<<(shift-1), G0); // in delay slot of branches | |
1771 __ BIND(L_fill_2_bytes); | |
1772 __ brx(Assembler::zero, false, Assembler::pt, L_fill_byte); | |
1773 __ delayed()->andcc(count, 1, count); | |
1774 __ sth(value, to, 0); | |
1775 if (t == T_BYTE) { | |
1776 __ inc(to, 2); | |
1777 // fill trailing byte | |
1778 __ andcc(count, 1, count); // in delay slot of branches | |
1779 __ BIND(L_fill_byte); | |
1780 __ brx(Assembler::zero, false, Assembler::pt, L_exit); | |
1781 __ delayed()->nop(); | |
1782 __ stb(value, to, 0); | |
1783 } else { | |
1784 __ BIND(L_fill_byte); | |
1785 } | |
1786 } else { | |
1787 __ BIND(L_fill_2_bytes); | |
1788 } | |
1789 __ BIND(L_exit); | |
1790 __ retl(); | |
1794 | 1791 __ delayed()->nop(); |
1792 | |
1793 // Handle copies less than 8 bytes. Int is handled elsewhere. | |
1794 if (t == T_BYTE) { | |
1795 __ BIND(L_fill_elements); | |
1796 Label L_fill_2, L_fill_4; | |
1797 // in delay slot __ andcc(count, 1, G0); | |
1798 __ brx(Assembler::zero, false, Assembler::pt, L_fill_2); | |
1799 __ delayed()->andcc(count, 2, G0); | |
1800 __ stb(value, to, 0); | |
1801 __ inc(to, 1); | |
1802 __ BIND(L_fill_2); | |
1803 __ brx(Assembler::zero, false, Assembler::pt, L_fill_4); | |
1804 __ delayed()->andcc(count, 4, G0); | |
1805 __ stb(value, to, 0); | |
1806 __ stb(value, to, 1); | |
1807 __ inc(to, 2); | |
1808 __ BIND(L_fill_4); | |
1809 __ brx(Assembler::zero, false, Assembler::pt, L_exit); | |
1810 __ delayed()->nop(); | |
1811 __ stb(value, to, 0); | |
1812 __ stb(value, to, 1); | |
1813 __ stb(value, to, 2); | |
1814 __ retl(); | |
1815 __ delayed()->stb(value, to, 3); | |
1816 } | |
1817 | |
1818 if (t == T_SHORT) { | |
1819 Label L_fill_2; | |
1820 __ BIND(L_fill_elements); | |
1821 // in delay slot __ andcc(count, 1, G0); | |
1822 __ brx(Assembler::zero, false, Assembler::pt, L_fill_2); | |
1823 __ delayed()->andcc(count, 2, G0); | |
1824 __ sth(value, to, 0); | |
1825 __ inc(to, 2); | |
1826 __ BIND(L_fill_2); | |
1827 __ brx(Assembler::zero, false, Assembler::pt, L_exit); | |
1828 __ delayed()->nop(); | |
1829 __ sth(value, to, 0); | |
1830 __ retl(); | |
1831 __ delayed()->sth(value, to, 2); | |
1832 } | |
1763 | 1833 return start; |
1834 } | |
1835 | |
1836 // | |
0 | 1837 // Generate stub for conjoint short copy. If "aligned" is true, the |
1838 // "from" and "to" addresses are assumed to be heapword aligned. | |
1839 // | |
1840 // Arguments for generated stub: | |
1841 // from: O0 | |
1842 // to: O1 | |
1843 // count: O2 treated as signed | |
1844 // | |
1845 address generate_conjoint_short_copy(bool aligned, const char * name) { | |
1846 // Do reverse copy. | |
1847 | |
1848 __ align(CodeEntryAlignment); | |
1849 StubCodeMark mark(this, "StubRoutines", name); | |
1850 address start = __ pc(); | |
1851 address nooverlap_target = aligned ? | |
1852 StubRoutines::arrayof_jshort_disjoint_arraycopy() : | |
1853 disjoint_short_copy_entry; | |
1854 | |
1855 Label L_skip_alignment, L_skip_alignment2, L_aligned_copy; | |
1856 Label L_copy_2_bytes, L_copy_2_bytes_loop, L_exit; | |
1857 | |
1858 const Register from = O0; // source array address | |
1859 const Register to = O1; // destination array address | |
1860 const Register count = O2; // elements count | |
1861 const Register end_from = from; // source array end address | |
1862 const Register end_to = to; // destination array end address | |
1863 | |
1864 const Register byte_count = O3; // bytes count to copy | |
1865 | |
1866 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
1867 | |
1868 if (!aligned) short_copy_entry = __ pc(); | |
1869 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
1870 if (!aligned) BLOCK_COMMENT("Entry:"); | |
1871 | |
1872 array_overlap_test(nooverlap_target, 1); | |
1873 | |
1874 __ sllx(count, LogBytesPerShort, byte_count); | |
1875 __ add(to, byte_count, end_to); // offset after last copied element | |
1876 | |
1877 // for short arrays, just do single element copy | |
1878 __ cmp(count, 11); // 8 + 3 (22 bytes) | |
1879 __ brx(Assembler::less, false, Assembler::pn, L_copy_2_bytes); | |
1880 __ delayed()->add(from, byte_count, end_from); | |
1881 | |
1882 { | |
1883 // Align end of arrays since they could be not aligned even | |
1884 // when arrays itself are aligned. | |
1885 | |
1886 // copy 1 element if necessary to align 'end_to' on an 4 bytes | |
1887 __ andcc(end_to, 3, G0); | |
1888 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
1889 __ delayed()->lduh(end_from, -2, O3); | |
1890 __ dec(end_from, 2); | |
1891 __ dec(end_to, 2); | |
1892 __ dec(count); | |
1893 __ sth(O3, end_to, 0); | |
1894 __ BIND(L_skip_alignment); | |
1895 | |
1896 // copy 2 elements to align 'end_to' on an 8 byte boundary | |
1897 __ andcc(end_to, 7, G0); | |
1898 __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment2); | |
1899 __ delayed()->lduh(end_from, -2, O3); | |
1900 __ dec(count, 2); | |
1901 __ lduh(end_from, -4, O4); | |
1902 __ dec(end_from, 4); | |
1903 __ dec(end_to, 4); | |
1904 __ sth(O3, end_to, 2); | |
1905 __ sth(O4, end_to, 0); | |
1906 __ BIND(L_skip_alignment2); | |
1907 } | |
1908 #ifdef _LP64 | |
1909 if (aligned) { | |
1910 // Both arrays are aligned to 8-bytes in 64-bits VM. | |
1911 // The 'count' is decremented in copy_16_bytes_backward_with_shift() | |
1912 // in unaligned case. | |
1913 __ dec(count, 8); | |
1914 } else | |
1915 #endif | |
1916 { | |
1917 // Copy with shift 16 bytes per iteration if arrays do not have | |
1918 // the same alignment mod 8, otherwise jump to the next | |
1919 // code for aligned copy (and substracting 8 from 'count' before jump). | |
1920 // The compare above (count >= 11) guarantes 'count' >= 16 bytes. | |
1921 // Also jump over aligned copy after the copy with shift completed. | |
1922 | |
1923 copy_16_bytes_backward_with_shift(end_from, end_to, count, 8, | |
1924 L_aligned_copy, L_copy_2_bytes); | |
1925 } | |
1926 // copy 4 elements (16 bytes) at a time | |
1365 | 1927 __ align(OptoLoopAlignment); |
0 | 1928 __ BIND(L_aligned_copy); |
1929 __ dec(end_from, 16); | |
1930 __ ldx(end_from, 8, O3); | |
1931 __ ldx(end_from, 0, O4); | |
1932 __ dec(end_to, 16); | |
1933 __ deccc(count, 8); | |
1934 __ stx(O3, end_to, 8); | |
1935 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy); | |
1936 __ delayed()->stx(O4, end_to, 0); | |
1937 __ inc(count, 8); | |
1938 | |
1939 // copy 1 element (2 bytes) at a time | |
1940 __ BIND(L_copy_2_bytes); | |
1941 __ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit); | |
1942 __ delayed()->nop(); | |
1943 __ BIND(L_copy_2_bytes_loop); | |
1944 __ dec(end_from, 2); | |
1945 __ dec(end_to, 2); | |
1946 __ lduh(end_from, 0, O4); | |
1947 __ deccc(count); | |
1948 __ brx(Assembler::greater, false, Assembler::pt, L_copy_2_bytes_loop); | |
1949 __ delayed()->sth(O4, end_to, 0); | |
1950 | |
1951 __ BIND(L_exit); | |
1952 // O3, O4 are used as temp registers | |
1953 inc_counter_np(SharedRuntime::_jshort_array_copy_ctr, O3, O4); | |
1954 __ retl(); | |
1955 __ delayed()->mov(G0, O0); // return 0 | |
1956 return start; | |
1957 } | |
1958 | |
1959 // | |
1960 // Generate core code for disjoint int copy (and oop copy on 32-bit). | |
1961 // If "aligned" is true, the "from" and "to" addresses are assumed | |
1962 // to be heapword aligned. | |
1963 // | |
1964 // Arguments: | |
1965 // from: O0 | |
1966 // to: O1 | |
1967 // count: O2 treated as signed | |
1968 // | |
1969 void generate_disjoint_int_copy_core(bool aligned) { | |
1970 | |
1971 Label L_skip_alignment, L_aligned_copy; | |
1972 Label L_copy_16_bytes, L_copy_4_bytes, L_copy_4_bytes_loop, L_exit; | |
1973 | |
1974 const Register from = O0; // source array address | |
1975 const Register to = O1; // destination array address | |
1976 const Register count = O2; // elements count | |
1977 const Register offset = O5; // offset from start of arrays | |
1978 // O3, O4, G3, G4 are used as temp registers | |
1979 | |
1980 // 'aligned' == true when it is known statically during compilation | |
1981 // of this arraycopy call site that both 'from' and 'to' addresses | |
1982 // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()). | |
1983 // | |
1984 // Aligned arrays have 4 bytes alignment in 32-bits VM | |
1985 // and 8 bytes - in 64-bits VM. | |
1986 // | |
1987 #ifdef _LP64 | |
1988 if (!aligned) | |
1989 #endif | |
1990 { | |
1991 // The next check could be put under 'ifndef' since the code in | |
1992 // generate_disjoint_long_copy_core() has own checks and set 'offset'. | |
1993 | |
1994 // for short arrays, just do single element copy | |
1995 __ cmp(count, 5); // 4 + 1 (20 bytes) | |
1996 __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_4_bytes); | |
1997 __ delayed()->mov(G0, offset); | |
1998 | |
1999 // copy 1 element to align 'to' on an 8 byte boundary | |
2000 __ andcc(to, 7, G0); | |
2001 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
2002 __ delayed()->ld(from, 0, O3); | |
2003 __ inc(from, 4); | |
2004 __ inc(to, 4); | |
2005 __ dec(count); | |
2006 __ st(O3, to, -4); | |
2007 __ BIND(L_skip_alignment); | |
2008 | |
2009 // if arrays have same alignment mod 8, do 4 elements copy | |
2010 __ andcc(from, 7, G0); | |
2011 __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); | |
2012 __ delayed()->ld(from, 0, O3); | |
2013 | |
2014 // | |
2015 // Load 2 aligned 8-bytes chunks and use one from previous iteration | |
2016 // to form 2 aligned 8-bytes chunks to store. | |
2017 // | |
2018 // copy_16_bytes_forward_with_shift() is not used here since this | |
2019 // code is more optimal. | |
2020 | |
2021 // copy with shift 4 elements (16 bytes) at a time | |
2022 __ dec(count, 4); // The cmp at the beginning guaranty count >= 4 | |
2023 | |
1365 | 2024 __ align(OptoLoopAlignment); |
0 | 2025 __ BIND(L_copy_16_bytes); |
2026 __ ldx(from, 4, O4); | |
2027 __ deccc(count, 4); // Can we do next iteration after this one? | |
2028 __ ldx(from, 12, G4); | |
2029 __ inc(to, 16); | |
2030 __ inc(from, 16); | |
2031 __ sllx(O3, 32, O3); | |
2032 __ srlx(O4, 32, G3); | |
2033 __ bset(G3, O3); | |
2034 __ stx(O3, to, -16); | |
2035 __ sllx(O4, 32, O4); | |
2036 __ srlx(G4, 32, G3); | |
2037 __ bset(G3, O4); | |
2038 __ stx(O4, to, -8); | |
2039 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes); | |
2040 __ delayed()->mov(G4, O3); | |
2041 | |
2042 __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes); | |
2043 __ delayed()->inc(count, 4); // restore 'count' | |
2044 | |
2045 __ BIND(L_aligned_copy); | |
2046 } | |
2047 // copy 4 elements (16 bytes) at a time | |
2048 __ and3(count, 1, G4); // Save | |
2049 __ srl(count, 1, count); | |
2050 generate_disjoint_long_copy_core(aligned); | |
2051 __ mov(G4, count); // Restore | |
2052 | |
2053 // copy 1 element at a time | |
2054 __ BIND(L_copy_4_bytes); | |
2055 __ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit); | |
2056 __ delayed()->nop(); | |
2057 __ BIND(L_copy_4_bytes_loop); | |
2058 __ ld(from, offset, O3); | |
2059 __ deccc(count); | |
2060 __ st(O3, to, offset); | |
2061 __ brx(Assembler::notZero, false, Assembler::pt, L_copy_4_bytes_loop); | |
2062 __ delayed()->inc(offset, 4); | |
2063 __ BIND(L_exit); | |
2064 } | |
2065 | |
2066 // | |
2067 // Generate stub for disjoint int copy. If "aligned" is true, the | |
2068 // "from" and "to" addresses are assumed to be heapword aligned. | |
2069 // | |
2070 // Arguments for generated stub: | |
2071 // from: O0 | |
2072 // to: O1 | |
2073 // count: O2 treated as signed | |
2074 // | |
2075 address generate_disjoint_int_copy(bool aligned, const char * name) { | |
2076 __ align(CodeEntryAlignment); | |
2077 StubCodeMark mark(this, "StubRoutines", name); | |
2078 address start = __ pc(); | |
2079 | |
2080 const Register count = O2; | |
2081 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
2082 | |
2083 if (!aligned) disjoint_int_copy_entry = __ pc(); | |
2084 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
2085 if (!aligned) BLOCK_COMMENT("Entry:"); | |
2086 | |
2087 generate_disjoint_int_copy_core(aligned); | |
2088 | |
2089 // O3, O4 are used as temp registers | |
2090 inc_counter_np(SharedRuntime::_jint_array_copy_ctr, O3, O4); | |
2091 __ retl(); | |
2092 __ delayed()->mov(G0, O0); // return 0 | |
2093 return start; | |
2094 } | |
2095 | |
2096 // | |
2097 // Generate core code for conjoint int copy (and oop copy on 32-bit). | |
2098 // If "aligned" is true, the "from" and "to" addresses are assumed | |
2099 // to be heapword aligned. | |
2100 // | |
2101 // Arguments: | |
2102 // from: O0 | |
2103 // to: O1 | |
2104 // count: O2 treated as signed | |
2105 // | |
2106 void generate_conjoint_int_copy_core(bool aligned) { | |
2107 // Do reverse copy. | |
2108 | |
2109 Label L_skip_alignment, L_aligned_copy; | |
2110 Label L_copy_16_bytes, L_copy_4_bytes, L_copy_4_bytes_loop, L_exit; | |
2111 | |
2112 const Register from = O0; // source array address | |
2113 const Register to = O1; // destination array address | |
2114 const Register count = O2; // elements count | |
2115 const Register end_from = from; // source array end address | |
2116 const Register end_to = to; // destination array end address | |
2117 // O3, O4, O5, G3 are used as temp registers | |
2118 | |
2119 const Register byte_count = O3; // bytes count to copy | |
2120 | |
2121 __ sllx(count, LogBytesPerInt, byte_count); | |
2122 __ add(to, byte_count, end_to); // offset after last copied element | |
2123 | |
2124 __ cmp(count, 5); // for short arrays, just do single element copy | |
2125 __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_4_bytes); | |
2126 __ delayed()->add(from, byte_count, end_from); | |
2127 | |
2128 // copy 1 element to align 'to' on an 8 byte boundary | |
2129 __ andcc(end_to, 7, G0); | |
2130 __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); | |
2131 __ delayed()->nop(); | |
2132 __ dec(count); | |
2133 __ dec(end_from, 4); | |
2134 __ dec(end_to, 4); | |
2135 __ ld(end_from, 0, O4); | |
2136 __ st(O4, end_to, 0); | |
2137 __ BIND(L_skip_alignment); | |
2138 | |
2139 // Check if 'end_from' and 'end_to' has the same alignment. | |
2140 __ andcc(end_from, 7, G0); | |
2141 __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); | |
2142 __ delayed()->dec(count, 4); // The cmp at the start guaranty cnt >= 4 | |
2143 | |
2144 // copy with shift 4 elements (16 bytes) at a time | |
2145 // | |
2146 // Load 2 aligned 8-bytes chunks and use one from previous iteration | |
2147 // to form 2 aligned 8-bytes chunks to store. | |
2148 // | |
2149 __ ldx(end_from, -4, O3); | |
1365 | 2150 __ align(OptoLoopAlignment); |
0 | 2151 __ BIND(L_copy_16_bytes); |
2152 __ ldx(end_from, -12, O4); | |
2153 __ deccc(count, 4); | |
2154 __ ldx(end_from, -20, O5); | |
2155 __ dec(end_to, 16); | |
2156 __ dec(end_from, 16); | |
2157 __ srlx(O3, 32, O3); | |
2158 __ sllx(O4, 32, G3); | |
2159 __ bset(G3, O3); | |
2160 __ stx(O3, end_to, 8); | |
2161 __ srlx(O4, 32, O4); | |
2162 __ sllx(O5, 32, G3); | |
2163 __ bset(O4, G3); | |
2164 __ stx(G3, end_to, 0); | |
2165 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes); | |
2166 __ delayed()->mov(O5, O3); | |
2167 | |
2168 __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes); | |
2169 __ delayed()->inc(count, 4); | |
2170 | |
2171 // copy 4 elements (16 bytes) at a time | |
1365 | 2172 __ align(OptoLoopAlignment); |
0 | 2173 __ BIND(L_aligned_copy); |
2174 __ dec(end_from, 16); | |
2175 __ ldx(end_from, 8, O3); | |
2176 __ ldx(end_from, 0, O4); | |
2177 __ dec(end_to, 16); | |
2178 __ deccc(count, 4); | |
2179 __ stx(O3, end_to, 8); | |
2180 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy); | |
2181 __ delayed()->stx(O4, end_to, 0); | |
2182 __ inc(count, 4); | |
2183 | |
2184 // copy 1 element (4 bytes) at a time | |
2185 __ BIND(L_copy_4_bytes); | |
2186 __ br_zero(Assembler::zero, false, Assembler::pt, count, L_exit); | |
2187 __ delayed()->nop(); | |
2188 __ BIND(L_copy_4_bytes_loop); | |
2189 __ dec(end_from, 4); | |
2190 __ dec(end_to, 4); | |
2191 __ ld(end_from, 0, O4); | |
2192 __ deccc(count); | |
2193 __ brx(Assembler::greater, false, Assembler::pt, L_copy_4_bytes_loop); | |
2194 __ delayed()->st(O4, end_to, 0); | |
2195 __ BIND(L_exit); | |
2196 } | |
2197 | |
2198 // | |
2199 // Generate stub for conjoint int copy. If "aligned" is true, the | |
2200 // "from" and "to" addresses are assumed to be heapword aligned. | |
2201 // | |
2202 // Arguments for generated stub: | |
2203 // from: O0 | |
2204 // to: O1 | |
2205 // count: O2 treated as signed | |
2206 // | |
2207 address generate_conjoint_int_copy(bool aligned, const char * name) { | |
2208 __ align(CodeEntryAlignment); | |
2209 StubCodeMark mark(this, "StubRoutines", name); | |
2210 address start = __ pc(); | |
2211 | |
2212 address nooverlap_target = aligned ? | |
2213 StubRoutines::arrayof_jint_disjoint_arraycopy() : | |
2214 disjoint_int_copy_entry; | |
2215 | |
2216 assert_clean_int(O2, O3); // Make sure 'count' is clean int. | |
2217 | |
2218 if (!aligned) int_copy_entry = __ pc(); | |
2219 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
2220 if (!aligned) BLOCK_COMMENT("Entry:"); | |
2221 | |
2222 array_overlap_test(nooverlap_target, 2); | |
2223 | |
2224 generate_conjoint_int_copy_core(aligned); | |
2225 | |
2226 // O3, O4 are used as temp registers | |
2227 inc_counter_np(SharedRuntime::_jint_array_copy_ctr, O3, O4); | |
2228 __ retl(); | |
2229 __ delayed()->mov(G0, O0); // return 0 | |
2230 return start; | |
2231 } | |
2232 | |
2233 // | |
2234 // Generate core code for disjoint long copy (and oop copy on 64-bit). | |
2235 // "aligned" is ignored, because we must make the stronger | |
2236 // assumption that both addresses are always 64-bit aligned. | |
2237 // | |
2238 // Arguments: | |
2239 // from: O0 | |
2240 // to: O1 | |
2241 // count: O2 treated as signed | |
2242 // | |
1364
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2243 // count -= 2; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2244 // if ( count >= 0 ) { // >= 2 elements |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2245 // if ( count > 6) { // >= 8 elements |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2246 // count -= 6; // original count - 8 |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2247 // do { |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2248 // copy_8_elements; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2249 // count -= 8; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2250 // } while ( count >= 0 ); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2251 // count += 6; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2252 // } |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2253 // if ( count >= 0 ) { // >= 2 elements |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2254 // do { |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2255 // copy_2_elements; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2256 // } while ( (count=count-2) >= 0 ); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2257 // } |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2258 // } |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2259 // count += 2; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2260 // if ( count != 0 ) { // 1 element left |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2261 // copy_1_element; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2262 // } |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2263 // |
0 | 2264 void generate_disjoint_long_copy_core(bool aligned) { |
2265 Label L_copy_8_bytes, L_copy_16_bytes, L_exit; | |
2266 const Register from = O0; // source array address | |
2267 const Register to = O1; // destination array address | |
2268 const Register count = O2; // elements count | |
2269 const Register offset0 = O4; // element offset | |
2270 const Register offset8 = O5; // next element offset | |
2271 | |
2272 __ deccc(count, 2); | |
2273 __ mov(G0, offset0); // offset from start of arrays (0) | |
2274 __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes ); | |
2275 __ delayed()->add(offset0, 8, offset8); | |
1364
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2276 |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2277 // Copy by 64 bytes chunks |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2278 Label L_copy_64_bytes; |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2279 const Register from64 = O3; // source address |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2280 const Register to64 = G3; // destination address |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2281 __ subcc(count, 6, O3); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2282 __ brx(Assembler::negative, false, Assembler::pt, L_copy_16_bytes ); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2283 __ delayed()->mov(to, to64); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2284 // Now we can use O4(offset0), O5(offset8) as temps |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2285 __ mov(O3, count); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2286 __ mov(from, from64); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2287 |
1365 | 2288 __ align(OptoLoopAlignment); |
1364
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2289 __ BIND(L_copy_64_bytes); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2290 for( int off = 0; off < 64; off += 16 ) { |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2291 __ ldx(from64, off+0, O4); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2292 __ ldx(from64, off+8, O5); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2293 __ stx(O4, to64, off+0); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2294 __ stx(O5, to64, off+8); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2295 } |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2296 __ deccc(count, 8); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2297 __ inc(from64, 64); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2298 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_64_bytes); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2299 __ delayed()->inc(to64, 64); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2300 |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2301 // Restore O4(offset0), O5(offset8) |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2302 __ sub(from64, from, offset0); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2303 __ inccc(count, 6); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2304 __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes ); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2305 __ delayed()->add(offset0, 8, offset8); |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2306 |
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2307 // Copy by 16 bytes chunks |
1365 | 2308 __ align(OptoLoopAlignment); |
0 | 2309 __ BIND(L_copy_16_bytes); |
2310 __ ldx(from, offset0, O3); | |
2311 __ ldx(from, offset8, G3); | |
2312 __ deccc(count, 2); | |
2313 __ stx(O3, to, offset0); | |
2314 __ inc(offset0, 16); | |
2315 __ stx(G3, to, offset8); | |
2316 __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes); | |
2317 __ delayed()->inc(offset8, 16); | |
2318 | |
1364
0dc88ad3244e
6940677: Use 64 bytes chunk copy for arraycopy on Sparc
kvn
parents:
1295
diff
changeset
|
2319 // Copy last 8 bytes |
0 | 2320 __ BIND(L_copy_8_bytes); |
2321 __ inccc(count, 2); | |
2322 __ brx(Assembler::zero, true, Assembler::pn, L_exit ); | |
2323 __ delayed()->mov(offset0, offset8); // Set O5 used by other stubs | |
2324 __ ldx(from, offset0, O3); | |
2325 __ stx(O3, to, offset0); | |
2326 __ BIND(L_exit); | |
2327 } | |
2328 | |
2329 // | |
2330 // Generate stub for disjoint long copy. | |
2331 // "aligned" is ignored, because we must make the stronger | |
2332 // assumption that both addresses are always 64-bit aligned. | |
2333 // | |
2334 // Arguments for generated stub: | |
2335 // from: O0 | |
2336 // to: O1 | |
2337 // count: O2 treated as signed | |
2338 // | |
2339 address generate_disjoint_long_copy(bool aligned, const char * name) { | |
2340 __ align(CodeEntryAlignment); | |
2341 StubCodeMark mark(this, "StubRoutines", name); | |
2342 address start = __ pc(); | |
2343 | |
2344 assert_clean_int(O2, O3); // Make sure 'count' is clean int. | |
2345 | |
2346 if (!aligned) disjoint_long_copy_entry = __ pc(); | |
2347 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
2348 if (!aligned) BLOCK_COMMENT("Entry:"); | |
2349 | |
2350 generate_disjoint_long_copy_core(aligned); | |
2351 | |
2352 // O3, O4 are used as temp registers | |
2353 inc_counter_np(SharedRuntime::_jlong_array_copy_ctr, O3, O4); | |
2354 __ retl(); | |
2355 __ delayed()->mov(G0, O0); // return 0 | |
2356 return start; | |
2357 } | |
2358 | |
2359 // | |
2360 // Generate core code for conjoint long copy (and oop copy on 64-bit). | |
2361 // "aligned" is ignored, because we must make the stronger | |
2362 // assumption that both addresses are always 64-bit aligned. | |
2363 // | |
2364 // Arguments: | |
2365 // from: O0 | |
2366 // to: O1 | |
2367 // count: O2 treated as signed | |
2368 // | |
2369 void generate_conjoint_long_copy_core(bool aligned) { | |
2370 // Do reverse copy. | |
2371 Label L_copy_8_bytes, L_copy_16_bytes, L_exit; | |
2372 const Register from = O0; // source array address | |
2373 const Register to = O1; // destination array address | |
2374 const Register count = O2; // elements count | |
2375 const Register offset8 = O4; // element offset | |
2376 const Register offset0 = O5; // previous element offset | |
2377 | |
2378 __ subcc(count, 1, count); | |
2379 __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_8_bytes ); | |
2380 __ delayed()->sllx(count, LogBytesPerLong, offset8); | |
2381 __ sub(offset8, 8, offset0); | |
1365 | 2382 __ align(OptoLoopAlignment); |
0 | 2383 __ BIND(L_copy_16_bytes); |
2384 __ ldx(from, offset8, O2); | |
2385 __ ldx(from, offset0, O3); | |
2386 __ stx(O2, to, offset8); | |
2387 __ deccc(offset8, 16); // use offset8 as counter | |
2388 __ stx(O3, to, offset0); | |
2389 __ brx(Assembler::greater, false, Assembler::pt, L_copy_16_bytes); | |
2390 __ delayed()->dec(offset0, 16); | |
2391 | |
2392 __ BIND(L_copy_8_bytes); | |
2393 __ brx(Assembler::negative, false, Assembler::pn, L_exit ); | |
2394 __ delayed()->nop(); | |
2395 __ ldx(from, 0, O3); | |
2396 __ stx(O3, to, 0); | |
2397 __ BIND(L_exit); | |
2398 } | |
2399 | |
2400 // Generate stub for conjoint long copy. | |
2401 // "aligned" is ignored, because we must make the stronger | |
2402 // assumption that both addresses are always 64-bit aligned. | |
2403 // | |
2404 // Arguments for generated stub: | |
2405 // from: O0 | |
2406 // to: O1 | |
2407 // count: O2 treated as signed | |
2408 // | |
2409 address generate_conjoint_long_copy(bool aligned, const char * name) { | |
2410 __ align(CodeEntryAlignment); | |
2411 StubCodeMark mark(this, "StubRoutines", name); | |
2412 address start = __ pc(); | |
2413 | |
2414 assert(!aligned, "usage"); | |
2415 address nooverlap_target = disjoint_long_copy_entry; | |
2416 | |
2417 assert_clean_int(O2, O3); // Make sure 'count' is clean int. | |
2418 | |
2419 if (!aligned) long_copy_entry = __ pc(); | |
2420 // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) | |
2421 if (!aligned) BLOCK_COMMENT("Entry:"); | |
2422 | |
2423 array_overlap_test(nooverlap_target, 3); | |
2424 | |
2425 generate_conjoint_long_copy_core(aligned); | |
2426 | |
2427 // O3, O4 are used as temp registers | |
2428 inc_counter_np(SharedRuntime::_jlong_array_copy_ctr, O3, O4); | |
2429 __ retl(); | |
2430 __ delayed()->mov(G0, O0); // return 0 | |
2431 return start; | |
2432 } | |
2433 | |
2434 // Generate stub for disjoint oop copy. If "aligned" is true, the | |
2435 // "from" and "to" addresses are assumed to be heapword aligned. | |
2436 // | |
2437 // Arguments for generated stub: | |
2438 // from: O0 | |
2439 // to: O1 | |
2440 // count: O2 treated as signed | |
2441 // | |
2442 address generate_disjoint_oop_copy(bool aligned, const char * name) { | |
2443 | |
2444 const Register from = O0; // source array address | |
2445 const Register to = O1; // destination array address | |
2446 const Register count = O2; // elements count | |
2447 | |
2448 __ align(CodeEntryAlignment); | |
2449 StubCodeMark mark(this, "StubRoutines", name); | |
2450 address start = __ pc(); | |
2451 | |
2452 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
2453 | |
2454 if (!aligned) disjoint_oop_copy_entry = __ pc(); | |
2455 // caller can pass a 64-bit byte count here | |
2456 if (!aligned) BLOCK_COMMENT("Entry:"); | |
2457 | |
2458 // save arguments for barrier generation | |
2459 __ mov(to, G1); | |
2460 __ mov(count, G5); | |
2461 gen_write_ref_array_pre_barrier(G1, G5); | |
2462 #ifdef _LP64 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2463 assert_clean_int(count, O3); // Make sure 'count' is clean int. |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2464 if (UseCompressedOops) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2465 generate_disjoint_int_copy_core(aligned); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2466 } else { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2467 generate_disjoint_long_copy_core(aligned); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2468 } |
0 | 2469 #else |
2470 generate_disjoint_int_copy_core(aligned); | |
2471 #endif | |
2472 // O0 is used as temp register | |
2473 gen_write_ref_array_post_barrier(G1, G5, O0); | |
2474 | |
2475 // O3, O4 are used as temp registers | |
2476 inc_counter_np(SharedRuntime::_oop_array_copy_ctr, O3, O4); | |
2477 __ retl(); | |
2478 __ delayed()->mov(G0, O0); // return 0 | |
2479 return start; | |
2480 } | |
2481 | |
2482 // Generate stub for conjoint oop copy. If "aligned" is true, the | |
2483 // "from" and "to" addresses are assumed to be heapword aligned. | |
2484 // | |
2485 // Arguments for generated stub: | |
2486 // from: O0 | |
2487 // to: O1 | |
2488 // count: O2 treated as signed | |
2489 // | |
2490 address generate_conjoint_oop_copy(bool aligned, const char * name) { | |
2491 | |
2492 const Register from = O0; // source array address | |
2493 const Register to = O1; // destination array address | |
2494 const Register count = O2; // elements count | |
2495 | |
2496 __ align(CodeEntryAlignment); | |
2497 StubCodeMark mark(this, "StubRoutines", name); | |
2498 address start = __ pc(); | |
2499 | |
2500 assert_clean_int(count, O3); // Make sure 'count' is clean int. | |
2501 | |
2502 if (!aligned) oop_copy_entry = __ pc(); | |
2503 // caller can pass a 64-bit byte count here | |
2504 if (!aligned) BLOCK_COMMENT("Entry:"); | |
2505 | |
2506 // save arguments for barrier generation | |
2507 __ mov(to, G1); | |
2508 __ mov(count, G5); | |
2509 | |
2510 gen_write_ref_array_pre_barrier(G1, G5); | |
2511 | |
2512 address nooverlap_target = aligned ? | |
2513 StubRoutines::arrayof_oop_disjoint_arraycopy() : | |
2514 disjoint_oop_copy_entry; | |
2515 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2516 array_overlap_test(nooverlap_target, LogBytesPerHeapOop); |
0 | 2517 |
2518 #ifdef _LP64 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2519 if (UseCompressedOops) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2520 generate_conjoint_int_copy_core(aligned); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2521 } else { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2522 generate_conjoint_long_copy_core(aligned); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2523 } |
0 | 2524 #else |
2525 generate_conjoint_int_copy_core(aligned); | |
2526 #endif | |
2527 | |
2528 // O0 is used as temp register | |
2529 gen_write_ref_array_post_barrier(G1, G5, O0); | |
2530 | |
2531 // O3, O4 are used as temp registers | |
2532 inc_counter_np(SharedRuntime::_oop_array_copy_ctr, O3, O4); | |
2533 __ retl(); | |
2534 __ delayed()->mov(G0, O0); // return 0 | |
2535 return start; | |
2536 } | |
2537 | |
2538 | |
2539 // Helper for generating a dynamic type check. | |
2540 // Smashes only the given temp registers. | |
2541 void generate_type_check(Register sub_klass, | |
2542 Register super_check_offset, | |
2543 Register super_klass, | |
2544 Register temp, | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2545 Label& L_success) { |
0 | 2546 assert_different_registers(sub_klass, super_check_offset, super_klass, temp); |
2547 | |
2548 BLOCK_COMMENT("type_check:"); | |
2549 | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2550 Label L_miss, L_pop_to_miss; |
0 | 2551 |
2552 assert_clean_int(super_check_offset, temp); | |
2553 | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2554 __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, noreg, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2555 &L_success, &L_miss, NULL, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2556 super_check_offset); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2557 |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2558 BLOCK_COMMENT("type_check_slow_path:"); |
0 | 2559 __ save_frame(0); |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2560 __ check_klass_subtype_slow_path(sub_klass->after_save(), |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2561 super_klass->after_save(), |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2562 L0, L1, L2, L4, |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2563 NULL, &L_pop_to_miss); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2564 __ ba(false, L_success); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2565 __ delayed()->restore(); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2566 |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2567 __ bind(L_pop_to_miss); |
0 | 2568 __ restore(); |
2569 | |
2570 // Fall through on failure! | |
2571 __ BIND(L_miss); | |
2572 } | |
2573 | |
2574 | |
2575 // Generate stub for checked oop copy. | |
2576 // | |
2577 // Arguments for generated stub: | |
2578 // from: O0 | |
2579 // to: O1 | |
2580 // count: O2 treated as signed | |
2581 // ckoff: O3 (super_check_offset) | |
2582 // ckval: O4 (super_klass) | |
2583 // ret: O0 zero for success; (-1^K) where K is partial transfer count | |
2584 // | |
2585 address generate_checkcast_copy(const char* name) { | |
2586 | |
2587 const Register O0_from = O0; // source array address | |
2588 const Register O1_to = O1; // destination array address | |
2589 const Register O2_count = O2; // elements count | |
2590 const Register O3_ckoff = O3; // super_check_offset | |
2591 const Register O4_ckval = O4; // super_klass | |
2592 | |
2593 const Register O5_offset = O5; // loop var, with stride wordSize | |
2594 const Register G1_remain = G1; // loop var, with stride -1 | |
2595 const Register G3_oop = G3; // actual oop copied | |
2596 const Register G4_klass = G4; // oop._klass | |
2597 const Register G5_super = G5; // oop._klass._primary_supers[ckval] | |
2598 | |
2599 __ align(CodeEntryAlignment); | |
2600 StubCodeMark mark(this, "StubRoutines", name); | |
2601 address start = __ pc(); | |
2602 | |
342
37f87013dfd8
6711316: Open source the Garbage-First garbage collector
ysr
parents:
113
diff
changeset
|
2603 gen_write_ref_array_pre_barrier(O1, O2); |
0 | 2604 |
2605 #ifdef ASSERT | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2606 // We sometimes save a frame (see generate_type_check below). |
0 | 2607 // If this will cause trouble, let's fail now instead of later. |
2608 __ save_frame(0); | |
2609 __ restore(); | |
2610 #endif | |
2611 | |
1844
75588558f1bf
6980792: Crash "exception happened outside interpreter, nmethods and vtable stubs (1)"
never
parents:
1794
diff
changeset
|
2612 assert_clean_int(O2_count, G1); // Make sure 'count' is clean int. |
75588558f1bf
6980792: Crash "exception happened outside interpreter, nmethods and vtable stubs (1)"
never
parents:
1794
diff
changeset
|
2613 |
0 | 2614 #ifdef ASSERT |
2615 // caller guarantees that the arrays really are different | |
2616 // otherwise, we would have to make conjoint checks | |
2617 { Label L; | |
2618 __ mov(O3, G1); // spill: overlap test smashes O3 | |
2619 __ mov(O4, G4); // spill: overlap test smashes O4 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2620 array_overlap_test(L, LogBytesPerHeapOop); |
0 | 2621 __ stop("checkcast_copy within a single array"); |
2622 __ bind(L); | |
2623 __ mov(G1, O3); | |
2624 __ mov(G4, O4); | |
2625 } | |
2626 #endif //ASSERT | |
2627 | |
2628 checkcast_copy_entry = __ pc(); | |
2629 // caller can pass a 64-bit byte count here (from generic stub) | |
2630 BLOCK_COMMENT("Entry:"); | |
2631 | |
2632 Label load_element, store_element, do_card_marks, fail, done; | |
2633 __ addcc(O2_count, 0, G1_remain); // initialize loop index, and test it | |
2634 __ brx(Assembler::notZero, false, Assembler::pt, load_element); | |
2635 __ delayed()->mov(G0, O5_offset); // offset from start of arrays | |
2636 | |
2637 // Empty array: Nothing to do. | |
2638 inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4); | |
2639 __ retl(); | |
2640 __ delayed()->set(0, O0); // return 0 on (trivial) success | |
2641 | |
2642 // ======== begin loop ======== | |
2643 // (Loop is rotated; its entry is load_element.) | |
2644 // Loop variables: | |
2645 // (O5 = 0; ; O5 += wordSize) --- offset from src, dest arrays | |
2646 // (O2 = len; O2 != 0; O2--) --- number of oops *remaining* | |
2647 // G3, G4, G5 --- current oop, oop.klass, oop.klass.super | |
1365 | 2648 __ align(OptoLoopAlignment); |
0 | 2649 |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2650 __ BIND(store_element); |
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2651 __ deccc(G1_remain); // decrement the count |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2652 __ store_heap_oop(G3_oop, O1_to, O5_offset); // store the oop |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2653 __ inc(O5_offset, heapOopSize); // step to next offset |
0 | 2654 __ brx(Assembler::zero, true, Assembler::pt, do_card_marks); |
2655 __ delayed()->set(0, O0); // return -1 on success | |
2656 | |
2657 // ======== loop entry is here ======== | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2658 __ BIND(load_element); |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2659 __ load_heap_oop(O0_from, O5_offset, G3_oop); // load the oop |
0 | 2660 __ br_null(G3_oop, true, Assembler::pt, store_element); |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2661 __ delayed()->nop(); |
0 | 2662 |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2663 __ load_klass(G3_oop, G4_klass); // query the object klass |
0 | 2664 |
2665 generate_type_check(G4_klass, O3_ckoff, O4_ckval, G5_super, | |
2666 // branch to this on success: | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2667 store_element); |
0 | 2668 // ======== end loop ======== |
2669 | |
2670 // It was a real error; we must depend on the caller to finish the job. | |
2671 // Register G1 has number of *remaining* oops, O2 number of *total* oops. | |
2672 // Emit GC store barriers for the oops we have copied (O2 minus G1), | |
2673 // and report their number to the caller. | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2674 __ BIND(fail); |
0 | 2675 __ subcc(O2_count, G1_remain, O2_count); |
2676 __ brx(Assembler::zero, false, Assembler::pt, done); | |
2677 __ delayed()->not1(O2_count, O0); // report (-1^K) to caller | |
2678 | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2679 __ BIND(do_card_marks); |
0 | 2680 gen_write_ref_array_post_barrier(O1_to, O2_count, O3); // store check on O1[0..O2] |
2681 | |
644
c517646eef23
6813212: factor duplicated assembly code for general subclass check (for 6655638)
jrose
parents:
642
diff
changeset
|
2682 __ BIND(done); |
0 | 2683 inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4); |
2684 __ retl(); | |
2685 __ delayed()->nop(); // return value in 00 | |
2686 | |
2687 return start; | |
2688 } | |
2689 | |
2690 | |
2691 // Generate 'unsafe' array copy stub | |
2692 // Though just as safe as the other stubs, it takes an unscaled | |
2693 // size_t argument instead of an element count. | |
2694 // | |
2695 // Arguments for generated stub: | |
2696 // from: O0 | |
2697 // to: O1 | |
2698 // count: O2 byte count, treated as ssize_t, can be zero | |
2699 // | |
2700 // Examines the alignment of the operands and dispatches | |
2701 // to a long, int, short, or byte copy loop. | |
2702 // | |
2703 address generate_unsafe_copy(const char* name) { | |
2704 | |
2705 const Register O0_from = O0; // source array address | |
2706 const Register O1_to = O1; // destination array address | |
2707 const Register O2_count = O2; // elements count | |
2708 | |
2709 const Register G1_bits = G1; // test copy of low bits | |
2710 | |
2711 __ align(CodeEntryAlignment); | |
2712 StubCodeMark mark(this, "StubRoutines", name); | |
2713 address start = __ pc(); | |
2714 | |
2715 // bump this on entry, not on exit: | |
2716 inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, G1, G3); | |
2717 | |
2718 __ or3(O0_from, O1_to, G1_bits); | |
2719 __ or3(O2_count, G1_bits, G1_bits); | |
2720 | |
2721 __ btst(BytesPerLong-1, G1_bits); | |
2722 __ br(Assembler::zero, true, Assembler::pt, | |
2723 long_copy_entry, relocInfo::runtime_call_type); | |
2724 // scale the count on the way out: | |
2725 __ delayed()->srax(O2_count, LogBytesPerLong, O2_count); | |
2726 | |
2727 __ btst(BytesPerInt-1, G1_bits); | |
2728 __ br(Assembler::zero, true, Assembler::pt, | |
2729 int_copy_entry, relocInfo::runtime_call_type); | |
2730 // scale the count on the way out: | |
2731 __ delayed()->srax(O2_count, LogBytesPerInt, O2_count); | |
2732 | |
2733 __ btst(BytesPerShort-1, G1_bits); | |
2734 __ br(Assembler::zero, true, Assembler::pt, | |
2735 short_copy_entry, relocInfo::runtime_call_type); | |
2736 // scale the count on the way out: | |
2737 __ delayed()->srax(O2_count, LogBytesPerShort, O2_count); | |
2738 | |
2739 __ br(Assembler::always, false, Assembler::pt, | |
2740 byte_copy_entry, relocInfo::runtime_call_type); | |
2741 __ delayed()->nop(); | |
2742 | |
2743 return start; | |
2744 } | |
2745 | |
2746 | |
2747 // Perform range checks on the proposed arraycopy. | |
2748 // Kills the two temps, but nothing else. | |
2749 // Also, clean the sign bits of src_pos and dst_pos. | |
2750 void arraycopy_range_checks(Register src, // source array oop (O0) | |
2751 Register src_pos, // source position (O1) | |
2752 Register dst, // destination array oo (O2) | |
2753 Register dst_pos, // destination position (O3) | |
2754 Register length, // length of copy (O4) | |
2755 Register temp1, Register temp2, | |
2756 Label& L_failed) { | |
2757 BLOCK_COMMENT("arraycopy_range_checks:"); | |
2758 | |
2759 // if (src_pos + length > arrayOop(src)->length() ) FAIL; | |
2760 | |
2761 const Register array_length = temp1; // scratch | |
2762 const Register end_pos = temp2; // scratch | |
2763 | |
2764 // Note: This next instruction may be in the delay slot of a branch: | |
2765 __ add(length, src_pos, end_pos); // src_pos + length | |
2766 __ lduw(src, arrayOopDesc::length_offset_in_bytes(), array_length); | |
2767 __ cmp(end_pos, array_length); | |
2768 __ br(Assembler::greater, false, Assembler::pn, L_failed); | |
2769 | |
2770 // if (dst_pos + length > arrayOop(dst)->length() ) FAIL; | |
2771 __ delayed()->add(length, dst_pos, end_pos); // dst_pos + length | |
2772 __ lduw(dst, arrayOopDesc::length_offset_in_bytes(), array_length); | |
2773 __ cmp(end_pos, array_length); | |
2774 __ br(Assembler::greater, false, Assembler::pn, L_failed); | |
2775 | |
2776 // Have to clean up high 32-bits of 'src_pos' and 'dst_pos'. | |
2777 // Move with sign extension can be used since they are positive. | |
2778 __ delayed()->signx(src_pos, src_pos); | |
2779 __ signx(dst_pos, dst_pos); | |
2780 | |
2781 BLOCK_COMMENT("arraycopy_range_checks done"); | |
2782 } | |
2783 | |
2784 | |
2785 // | |
2786 // Generate generic array copy stubs | |
2787 // | |
2788 // Input: | |
2789 // O0 - src oop | |
2790 // O1 - src_pos | |
2791 // O2 - dst oop | |
2792 // O3 - dst_pos | |
2793 // O4 - element count | |
2794 // | |
2795 // Output: | |
2796 // O0 == 0 - success | |
2797 // O0 == -1 - need to call System.arraycopy | |
2798 // | |
2799 address generate_generic_copy(const char *name) { | |
2800 | |
2801 Label L_failed, L_objArray; | |
2802 | |
2803 // Input registers | |
2804 const Register src = O0; // source array oop | |
2805 const Register src_pos = O1; // source position | |
2806 const Register dst = O2; // destination array oop | |
2807 const Register dst_pos = O3; // destination position | |
2808 const Register length = O4; // elements count | |
2809 | |
2810 // registers used as temp | |
2811 const Register G3_src_klass = G3; // source array klass | |
2812 const Register G4_dst_klass = G4; // destination array klass | |
2813 const Register G5_lh = G5; // layout handler | |
2814 const Register O5_temp = O5; | |
2815 | |
2816 __ align(CodeEntryAlignment); | |
2817 StubCodeMark mark(this, "StubRoutines", name); | |
2818 address start = __ pc(); | |
2819 | |
2820 // bump this on entry, not on exit: | |
2821 inc_counter_np(SharedRuntime::_generic_array_copy_ctr, G1, G3); | |
2822 | |
2823 // In principle, the int arguments could be dirty. | |
2824 //assert_clean_int(src_pos, G1); | |
2825 //assert_clean_int(dst_pos, G1); | |
2826 //assert_clean_int(length, G1); | |
2827 | |
2828 //----------------------------------------------------------------------- | |
2829 // Assembler stubs will be used for this call to arraycopy | |
2830 // if the following conditions are met: | |
2831 // | |
2832 // (1) src and dst must not be null. | |
2833 // (2) src_pos must not be negative. | |
2834 // (3) dst_pos must not be negative. | |
2835 // (4) length must not be negative. | |
2836 // (5) src klass and dst klass should be the same and not NULL. | |
2837 // (6) src and dst should be arrays. | |
2838 // (7) src_pos + length must not exceed length of src. | |
2839 // (8) dst_pos + length must not exceed length of dst. | |
2840 BLOCK_COMMENT("arraycopy initial argument checks"); | |
2841 | |
2842 // if (src == NULL) return -1; | |
2843 __ br_null(src, false, Assembler::pn, L_failed); | |
2844 | |
2845 // if (src_pos < 0) return -1; | |
2846 __ delayed()->tst(src_pos); | |
2847 __ br(Assembler::negative, false, Assembler::pn, L_failed); | |
2848 __ delayed()->nop(); | |
2849 | |
2850 // if (dst == NULL) return -1; | |
2851 __ br_null(dst, false, Assembler::pn, L_failed); | |
2852 | |
2853 // if (dst_pos < 0) return -1; | |
2854 __ delayed()->tst(dst_pos); | |
2855 __ br(Assembler::negative, false, Assembler::pn, L_failed); | |
2856 | |
2857 // if (length < 0) return -1; | |
2858 __ delayed()->tst(length); | |
2859 __ br(Assembler::negative, false, Assembler::pn, L_failed); | |
2860 | |
2861 BLOCK_COMMENT("arraycopy argument klass checks"); | |
2862 // get src->klass() | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2863 if (UseCompressedOops) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2864 __ delayed()->nop(); // ??? not good |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2865 __ load_klass(src, G3_src_klass); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2866 } else { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2867 __ delayed()->ld_ptr(src, oopDesc::klass_offset_in_bytes(), G3_src_klass); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2868 } |
0 | 2869 |
2870 #ifdef ASSERT | |
2871 // assert(src->klass() != NULL); | |
2872 BLOCK_COMMENT("assert klasses not null"); | |
2873 { Label L_a, L_b; | |
2874 __ br_notnull(G3_src_klass, false, Assembler::pt, L_b); // it is broken if klass is NULL | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2875 __ delayed()->nop(); |
0 | 2876 __ bind(L_a); |
2877 __ stop("broken null klass"); | |
2878 __ bind(L_b); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2879 __ load_klass(dst, G4_dst_klass); |
0 | 2880 __ br_null(G4_dst_klass, false, Assembler::pn, L_a); // this would be broken also |
2881 __ delayed()->mov(G0, G4_dst_klass); // scribble the temp | |
2882 BLOCK_COMMENT("assert done"); | |
2883 } | |
2884 #endif | |
2885 | |
2886 // Load layout helper | |
2887 // | |
2888 // |array_tag| | header_size | element_type | |log2_element_size| | |
2889 // 32 30 24 16 8 2 0 | |
2890 // | |
2891 // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 | |
2892 // | |
2893 | |
2894 int lh_offset = klassOopDesc::header_size() * HeapWordSize + | |
2895 Klass::layout_helper_offset_in_bytes(); | |
2896 | |
2897 // Load 32-bits signed value. Use br() instruction with it to check icc. | |
2898 __ lduw(G3_src_klass, lh_offset, G5_lh); | |
2899 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2900 if (UseCompressedOops) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2901 __ load_klass(dst, G4_dst_klass); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2902 } |
0 | 2903 // Handle objArrays completely differently... |
2904 juint objArray_lh = Klass::array_layout_helper(T_OBJECT); | |
2905 __ set(objArray_lh, O5_temp); | |
2906 __ cmp(G5_lh, O5_temp); | |
2907 __ br(Assembler::equal, false, Assembler::pt, L_objArray); | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2908 if (UseCompressedOops) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2909 __ delayed()->nop(); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2910 } else { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2911 __ delayed()->ld_ptr(dst, oopDesc::klass_offset_in_bytes(), G4_dst_klass); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
2912 } |
0 | 2913 |
2914 // if (src->klass() != dst->klass()) return -1; | |
2915 __ cmp(G3_src_klass, G4_dst_klass); | |
2916 __ brx(Assembler::notEqual, false, Assembler::pn, L_failed); | |
2917 __ delayed()->nop(); | |
2918 | |
2919 // if (!src->is_Array()) return -1; | |
2920 __ cmp(G5_lh, Klass::_lh_neutral_value); // < 0 | |
2921 __ br(Assembler::greaterEqual, false, Assembler::pn, L_failed); | |
2922 | |
2923 // At this point, it is known to be a typeArray (array_tag 0x3). | |
2924 #ifdef ASSERT | |
2925 __ delayed()->nop(); | |
2926 { Label L; | |
2927 jint lh_prim_tag_in_place = (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); | |
2928 __ set(lh_prim_tag_in_place, O5_temp); | |
2929 __ cmp(G5_lh, O5_temp); | |
2930 __ br(Assembler::greaterEqual, false, Assembler::pt, L); | |
2931 __ delayed()->nop(); | |
2932 __ stop("must be a primitive array"); | |
2933 __ bind(L); | |
2934 } | |
2935 #else | |
2936 __ delayed(); // match next insn to prev branch | |
2937 #endif | |
2938 | |
2939 arraycopy_range_checks(src, src_pos, dst, dst_pos, length, | |
2940 O5_temp, G4_dst_klass, L_failed); | |
2941 | |
2942 // typeArrayKlass | |
2943 // | |
2944 // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); | |
2945 // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); | |
2946 // | |
2947 | |
2948 const Register G4_offset = G4_dst_klass; // array offset | |
2949 const Register G3_elsize = G3_src_klass; // log2 element size | |
2950 | |
2951 __ srl(G5_lh, Klass::_lh_header_size_shift, G4_offset); | |
2952 __ and3(G4_offset, Klass::_lh_header_size_mask, G4_offset); // array_offset | |
2953 __ add(src, G4_offset, src); // src array offset | |
2954 __ add(dst, G4_offset, dst); // dst array offset | |
2955 __ and3(G5_lh, Klass::_lh_log2_element_size_mask, G3_elsize); // log2 element size | |
2956 | |
2957 // next registers should be set before the jump to corresponding stub | |
2958 const Register from = O0; // source array address | |
2959 const Register to = O1; // destination array address | |
2960 const Register count = O2; // elements count | |
2961 | |
2962 // 'from', 'to', 'count' registers should be set in this order | |
2963 // since they are the same as 'src', 'src_pos', 'dst'. | |
2964 | |
2965 BLOCK_COMMENT("scale indexes to element size"); | |
2966 __ sll_ptr(src_pos, G3_elsize, src_pos); | |
2967 __ sll_ptr(dst_pos, G3_elsize, dst_pos); | |
2968 __ add(src, src_pos, from); // src_addr | |
2969 __ add(dst, dst_pos, to); // dst_addr | |
2970 | |
2971 BLOCK_COMMENT("choose copy loop based on element size"); | |
2972 __ cmp(G3_elsize, 0); | |
2973 __ br(Assembler::equal,true,Assembler::pt,StubRoutines::_jbyte_arraycopy); | |
2974 __ delayed()->signx(length, count); // length | |
2975 | |
2976 __ cmp(G3_elsize, LogBytesPerShort); | |
2977 __ br(Assembler::equal,true,Assembler::pt,StubRoutines::_jshort_arraycopy); | |
2978 __ delayed()->signx(length, count); // length | |
2979 | |
2980 __ cmp(G3_elsize, LogBytesPerInt); | |
2981 __ br(Assembler::equal,true,Assembler::pt,StubRoutines::_jint_arraycopy); | |
2982 __ delayed()->signx(length, count); // length | |
2983 #ifdef ASSERT | |
2984 { Label L; | |
2985 __ cmp(G3_elsize, LogBytesPerLong); | |
2986 __ br(Assembler::equal, false, Assembler::pt, L); | |
2987 __ delayed()->nop(); | |
2988 __ stop("must be long copy, but elsize is wrong"); | |
2989 __ bind(L); | |
2990 } | |
2991 #endif | |
2992 __ br(Assembler::always,false,Assembler::pt,StubRoutines::_jlong_arraycopy); | |
2993 __ delayed()->signx(length, count); // length | |
2994 | |
2995 // objArrayKlass | |
2996 __ BIND(L_objArray); | |
2997 // live at this point: G3_src_klass, G4_dst_klass, src[_pos], dst[_pos], length | |
2998 | |
2999 Label L_plain_copy, L_checkcast_copy; | |
3000 // test array classes for subtyping | |
3001 __ cmp(G3_src_klass, G4_dst_klass); // usual case is exact equality | |
3002 __ brx(Assembler::notEqual, true, Assembler::pn, L_checkcast_copy); | |
3003 __ delayed()->lduw(G4_dst_klass, lh_offset, O5_temp); // hoisted from below | |
3004 | |
3005 // Identically typed arrays can be copied without element-wise checks. | |
3006 arraycopy_range_checks(src, src_pos, dst, dst_pos, length, | |
3007 O5_temp, G5_lh, L_failed); | |
3008 | |
3009 __ add(src, arrayOopDesc::base_offset_in_bytes(T_OBJECT), src); //src offset | |
3010 __ add(dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT), dst); //dst offset | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
3011 __ sll_ptr(src_pos, LogBytesPerHeapOop, src_pos); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
3012 __ sll_ptr(dst_pos, LogBytesPerHeapOop, dst_pos); |
0 | 3013 __ add(src, src_pos, from); // src_addr |
3014 __ add(dst, dst_pos, to); // dst_addr | |
3015 __ BIND(L_plain_copy); | |
3016 __ br(Assembler::always, false, Assembler::pt,StubRoutines::_oop_arraycopy); | |
3017 __ delayed()->signx(length, count); // length | |
3018 | |
3019 __ BIND(L_checkcast_copy); | |
3020 // live at this point: G3_src_klass, G4_dst_klass | |
3021 { | |
3022 // Before looking at dst.length, make sure dst is also an objArray. | |
3023 // lduw(G4_dst_klass, lh_offset, O5_temp); // hoisted to delay slot | |
3024 __ cmp(G5_lh, O5_temp); | |
3025 __ br(Assembler::notEqual, false, Assembler::pn, L_failed); | |
3026 | |
3027 // It is safe to examine both src.length and dst.length. | |
3028 __ delayed(); // match next insn to prev branch | |
3029 arraycopy_range_checks(src, src_pos, dst, dst_pos, length, | |
3030 O5_temp, G5_lh, L_failed); | |
3031 | |
3032 // Marshal the base address arguments now, freeing registers. | |
3033 __ add(src, arrayOopDesc::base_offset_in_bytes(T_OBJECT), src); //src offset | |
3034 __ add(dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT), dst); //dst offset | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
3035 __ sll_ptr(src_pos, LogBytesPerHeapOop, src_pos); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
16
diff
changeset
|
3036 __ sll_ptr(dst_pos, LogBytesPerHeapOop, dst_pos); |
0 | 3037 __ add(src, src_pos, from); // src_addr |
3038 __ add(dst, dst_pos, to); // dst_addr | |
3039 __ signx(length, count); // length (reloaded) | |
3040 | |
3041 Register sco_temp = O3; // this register is free now | |
3042 assert_different_registers(from, to, count, sco_temp, | |
3043 G4_dst_klass, G3_src_klass); | |
3044 | |
3045 // Generate the type check. | |
3046 int sco_offset = (klassOopDesc::header_size() * HeapWordSize + | |
3047 Klass::super_check_offset_offset_in_bytes()); | |
3048 __ lduw(G4_dst_klass, sco_offset, sco_temp); | |
3049 generate_type_check(G3_src_klass, sco_temp, G4_dst_klass, | |
3050 O5_temp, L_plain_copy); | |
3051 | |
3052 // Fetch destination element klass from the objArrayKlass header. | |
3053 int ek_offset = (klassOopDesc::header_size() * HeapWordSize + | |
3054 objArrayKlass::element_klass_offset_in_bytes()); | |
3055 | |
3056 // the checkcast_copy loop needs two extra arguments: | |
3057 __ ld_ptr(G4_dst_klass, ek_offset, O4); // dest elem klass | |
3058 // lduw(O4, sco_offset, O3); // sco of elem klass | |
3059 | |
3060 __ br(Assembler::always, false, Assembler::pt, checkcast_copy_entry); | |
3061 __ delayed()->lduw(O4, sco_offset, O3); | |
3062 } | |
3063 | |
3064 __ BIND(L_failed); | |
3065 __ retl(); | |
3066 __ delayed()->sub(G0, 1, O0); // return -1 | |
3067 return start; | |
3068 } | |
3069 | |
3070 void generate_arraycopy_stubs() { | |
3071 | |
3072 // Note: the disjoint stubs must be generated first, some of | |
3073 // the conjoint stubs use them. | |
3074 StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(false, "jbyte_disjoint_arraycopy"); | |
3075 StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_short_copy(false, "jshort_disjoint_arraycopy"); | |
3076 StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_int_copy(false, "jint_disjoint_arraycopy"); | |
3077 StubRoutines::_jlong_disjoint_arraycopy = generate_disjoint_long_copy(false, "jlong_disjoint_arraycopy"); | |
3078 StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_oop_copy(false, "oop_disjoint_arraycopy"); | |
3079 StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(true, "arrayof_jbyte_disjoint_arraycopy"); | |
3080 StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_short_copy(true, "arrayof_jshort_disjoint_arraycopy"); | |
3081 StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_int_copy(true, "arrayof_jint_disjoint_arraycopy"); | |
3082 StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_long_copy(true, "arrayof_jlong_disjoint_arraycopy"); | |
3083 StubRoutines::_arrayof_oop_disjoint_arraycopy = generate_disjoint_oop_copy(true, "arrayof_oop_disjoint_arraycopy"); | |
3084 | |
3085 StubRoutines::_jbyte_arraycopy = generate_conjoint_byte_copy(false, "jbyte_arraycopy"); | |
3086 StubRoutines::_jshort_arraycopy = generate_conjoint_short_copy(false, "jshort_arraycopy"); | |
3087 StubRoutines::_jint_arraycopy = generate_conjoint_int_copy(false, "jint_arraycopy"); | |
3088 StubRoutines::_jlong_arraycopy = generate_conjoint_long_copy(false, "jlong_arraycopy"); | |
3089 StubRoutines::_oop_arraycopy = generate_conjoint_oop_copy(false, "oop_arraycopy"); | |
3090 StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_byte_copy(true, "arrayof_jbyte_arraycopy"); | |
3091 StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_short_copy(true, "arrayof_jshort_arraycopy"); | |
3092 #ifdef _LP64 | |
3093 // since sizeof(jint) < sizeof(HeapWord), there's a different flavor: | |
3094 StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_int_copy(true, "arrayof_jint_arraycopy"); | |
3095 #else | |
3096 StubRoutines::_arrayof_jint_arraycopy = StubRoutines::_jint_arraycopy; | |
3097 #endif | |
3098 StubRoutines::_arrayof_jlong_arraycopy = StubRoutines::_jlong_arraycopy; | |
3099 StubRoutines::_arrayof_oop_arraycopy = StubRoutines::_oop_arraycopy; | |
3100 | |
3101 StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy"); | |
3102 StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy"); | |
3103 StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy"); | |
1763 | 3104 |
3105 StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); | |
3106 StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); | |
3107 StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); | |
3108 StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); | |
3109 StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); | |
3110 StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); | |
0 | 3111 } |
3112 | |
3113 void generate_initial() { | |
3114 // Generates all stubs and initializes the entry points | |
3115 | |
3116 //------------------------------------------------------------------------------------------------------------------------ | |
3117 // entry points that exist in all platforms | |
3118 // Note: This is code that could be shared among different platforms - however the benefit seems to be smaller than | |
3119 // the disadvantage of having a much more complicated generator structure. See also comment in stubRoutines.hpp. | |
3120 StubRoutines::_forward_exception_entry = generate_forward_exception(); | |
3121 | |
3122 StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address); | |
3123 StubRoutines::_catch_exception_entry = generate_catch_exception(); | |
3124 | |
3125 //------------------------------------------------------------------------------------------------------------------------ | |
3126 // entry points that are platform specific | |
3127 StubRoutines::Sparc::_test_stop_entry = generate_test_stop(); | |
3128 | |
3129 StubRoutines::Sparc::_stop_subroutine_entry = generate_stop_subroutine(); | |
3130 StubRoutines::Sparc::_flush_callers_register_windows_entry = generate_flush_callers_register_windows(); | |
3131 | |
3132 #if !defined(COMPILER2) && !defined(_LP64) | |
3133 StubRoutines::_atomic_xchg_entry = generate_atomic_xchg(); | |
3134 StubRoutines::_atomic_cmpxchg_entry = generate_atomic_cmpxchg(); | |
3135 StubRoutines::_atomic_add_entry = generate_atomic_add(); | |
3136 StubRoutines::_atomic_xchg_ptr_entry = StubRoutines::_atomic_xchg_entry; | |
3137 StubRoutines::_atomic_cmpxchg_ptr_entry = StubRoutines::_atomic_cmpxchg_entry; | |
3138 StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long(); | |
3139 StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry; | |
3140 #endif // COMPILER2 !=> _LP64 | |
3141 } | |
3142 | |
3143 | |
3144 void generate_all() { | |
3145 // Generates all stubs and initializes the entry points | |
3146 | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
422
diff
changeset
|
3147 // Generate partial_subtype_check first here since its code depends on |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
422
diff
changeset
|
3148 // UseZeroBaseCompressedOops which is defined after heap initialization. |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
422
diff
changeset
|
3149 StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check(); |
0 | 3150 // These entry points require SharedInfo::stack0 to be set up in non-core builds |
3151 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
|
3152 StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); |
0 | 3153 StubRoutines::_throw_ArithmeticException_entry = generate_throw_exception("ArithmeticException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_ArithmeticException), true); |
3154 StubRoutines::_throw_NullPointerException_entry = generate_throw_exception("NullPointerException throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException), true); | |
3155 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); | |
3156 StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); | |
3157 | |
3158 StubRoutines::_handler_for_unsafe_access_entry = | |
3159 generate_handler_for_unsafe_access(); | |
3160 | |
3161 // support for verify_oop (must happen after universe_init) | |
3162 StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine(); | |
3163 | |
3164 // arraycopy stubs used by compilers | |
3165 generate_arraycopy_stubs(); | |
1174
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
727
diff
changeset
|
3166 |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
727
diff
changeset
|
3167 // Don't initialize the platform math functions since sparc |
ddb7834449d0
6849984: Value methods for platform dependent math functions constant fold incorrectly
never
parents:
727
diff
changeset
|
3168 // doesn't have intrinsics for these operations. |
0 | 3169 } |
3170 | |
3171 | |
3172 public: | |
3173 StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { | |
3174 // replace the standard masm with a special one: | |
3175 _masm = new MacroAssembler(code); | |
3176 | |
3177 _stub_count = !all ? 0x100 : 0x200; | |
3178 if (all) { | |
3179 generate_all(); | |
3180 } else { | |
3181 generate_initial(); | |
3182 } | |
3183 | |
3184 // make sure this stub is available for all local calls | |
3185 if (_atomic_add_stub.is_unbound()) { | |
3186 // generate a second time, if necessary | |
3187 (void) generate_atomic_add(); | |
3188 } | |
3189 } | |
3190 | |
3191 | |
3192 private: | |
3193 int _stub_count; | |
3194 void stub_prolog(StubCodeDesc* cdesc) { | |
3195 # ifdef ASSERT | |
3196 // put extra information in the stub code, to make it more readable | |
3197 #ifdef _LP64 | |
3198 // Write the high part of the address | |
3199 // [RGV] Check if there is a dependency on the size of this prolog | |
3200 __ emit_data((intptr_t)cdesc >> 32, relocInfo::none); | |
3201 #endif | |
3202 __ emit_data((intptr_t)cdesc, relocInfo::none); | |
3203 __ emit_data(++_stub_count, relocInfo::none); | |
3204 # endif | |
3205 align(true); | |
3206 } | |
3207 | |
3208 void align(bool at_header = false) { | |
3209 // %%%%% move this constant somewhere else | |
3210 // UltraSPARC cache line size is 8 instructions: | |
3211 const unsigned int icache_line_size = 32; | |
3212 const unsigned int icache_half_line_size = 16; | |
3213 | |
3214 if (at_header) { | |
3215 while ((intptr_t)(__ pc()) % icache_line_size != 0) { | |
3216 __ emit_data(0, relocInfo::none); | |
3217 } | |
3218 } else { | |
3219 while ((intptr_t)(__ pc()) % icache_half_line_size != 0) { | |
3220 __ nop(); | |
3221 } | |
3222 } | |
3223 } | |
3224 | |
3225 }; // end class declaration | |
3226 | |
3227 | |
3228 address StubGenerator::disjoint_byte_copy_entry = NULL; | |
3229 address StubGenerator::disjoint_short_copy_entry = NULL; | |
3230 address StubGenerator::disjoint_int_copy_entry = NULL; | |
3231 address StubGenerator::disjoint_long_copy_entry = NULL; | |
3232 address StubGenerator::disjoint_oop_copy_entry = NULL; | |
3233 | |
3234 address StubGenerator::byte_copy_entry = NULL; | |
3235 address StubGenerator::short_copy_entry = NULL; | |
3236 address StubGenerator::int_copy_entry = NULL; | |
3237 address StubGenerator::long_copy_entry = NULL; | |
3238 address StubGenerator::oop_copy_entry = NULL; | |
3239 | |
3240 address StubGenerator::checkcast_copy_entry = NULL; | |
3241 | |
3242 void StubGenerator_generate(CodeBuffer* code, bool all) { | |
3243 StubGenerator g(code, all); | |
3244 } |