| 1 | /* |
| 2 | * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. |
| 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 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #include "precompiled.hpp" |
| 26 | #include "asm/codeBuffer.hpp" |
| 27 | #include "memory/resourceArea.hpp" |
| 28 | #include "oops/access.inline.hpp" |
| 29 | #include "oops/oop.inline.hpp" |
| 30 | #include "runtime/interfaceSupport.inline.hpp" |
| 31 | #include "runtime/timerTrace.hpp" |
| 32 | #include "runtime/sharedRuntime.hpp" |
| 33 | #include "runtime/stubRoutines.hpp" |
| 34 | #include "utilities/align.hpp" |
| 35 | #include "utilities/copy.hpp" |
| 36 | #include "utilities/vmError.hpp" |
| 37 | #ifdef COMPILER2 |
| 38 | #include "opto/runtime.hpp" |
| 39 | #endif |
| 40 | |
| 41 | |
| 42 | // Implementation of StubRoutines - for a description |
| 43 | // of how to extend it, see the header file. |
| 44 | |
| 45 | // Class Variables |
| 46 | |
| 47 | BufferBlob* StubRoutines::_code1 = NULL; |
| 48 | BufferBlob* StubRoutines::_code2 = NULL; |
| 49 | |
| 50 | address StubRoutines::_call_stub_return_address = NULL; |
| 51 | address StubRoutines::_call_stub_entry = NULL; |
| 52 | |
| 53 | address StubRoutines::_catch_exception_entry = NULL; |
| 54 | address StubRoutines::_forward_exception_entry = NULL; |
| 55 | address StubRoutines::_throw_AbstractMethodError_entry = NULL; |
| 56 | address StubRoutines::_throw_IncompatibleClassChangeError_entry = NULL; |
| 57 | address StubRoutines::_throw_NullPointerException_at_call_entry = NULL; |
| 58 | address StubRoutines::_throw_StackOverflowError_entry = NULL; |
| 59 | address StubRoutines::_throw_delayed_StackOverflowError_entry = NULL; |
| 60 | jint StubRoutines::_verify_oop_count = 0; |
| 61 | address StubRoutines::_verify_oop_subroutine_entry = NULL; |
| 62 | address StubRoutines::_atomic_xchg_entry = NULL; |
| 63 | address StubRoutines::_atomic_xchg_long_entry = NULL; |
| 64 | address StubRoutines::_atomic_store_entry = NULL; |
| 65 | address StubRoutines::_atomic_cmpxchg_entry = NULL; |
| 66 | address StubRoutines::_atomic_cmpxchg_byte_entry = NULL; |
| 67 | address StubRoutines::_atomic_cmpxchg_long_entry = NULL; |
| 68 | address StubRoutines::_atomic_add_entry = NULL; |
| 69 | address StubRoutines::_atomic_add_long_entry = NULL; |
| 70 | address StubRoutines::_fence_entry = NULL; |
| 71 | address StubRoutines::_d2i_wrapper = NULL; |
| 72 | address StubRoutines::_d2l_wrapper = NULL; |
| 73 | |
| 74 | jint StubRoutines::_fpu_cntrl_wrd_std = 0; |
| 75 | jint StubRoutines::_fpu_cntrl_wrd_24 = 0; |
| 76 | jint StubRoutines::_fpu_cntrl_wrd_trunc = 0; |
| 77 | jint StubRoutines::_mxcsr_std = 0; |
| 78 | jint StubRoutines::_fpu_subnormal_bias1[3] = { 0, 0, 0 }; |
| 79 | jint StubRoutines::_fpu_subnormal_bias2[3] = { 0, 0, 0 }; |
| 80 | |
| 81 | // Compiled code entry points default values |
| 82 | // The default functions don't have separate disjoint versions. |
| 83 | address StubRoutines::_jbyte_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jbyte_copy); |
| 84 | address StubRoutines::_jshort_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jshort_copy); |
| 85 | address StubRoutines::_jint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jint_copy); |
| 86 | address StubRoutines::_jlong_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jlong_copy); |
| 87 | address StubRoutines::_oop_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::oop_copy); |
| 88 | address StubRoutines::_oop_arraycopy_uninit = CAST_FROM_FN_PTR(address, StubRoutines::oop_copy_uninit); |
| 89 | address StubRoutines::_jbyte_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jbyte_copy); |
| 90 | address StubRoutines::_jshort_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jshort_copy); |
| 91 | address StubRoutines::_jint_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jint_copy); |
| 92 | address StubRoutines::_jlong_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::jlong_copy); |
| 93 | address StubRoutines::_oop_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::oop_copy); |
| 94 | address StubRoutines::_oop_disjoint_arraycopy_uninit = CAST_FROM_FN_PTR(address, StubRoutines::oop_copy_uninit); |
| 95 | |
| 96 | address StubRoutines::_arrayof_jbyte_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jbyte_copy); |
| 97 | address StubRoutines::_arrayof_jshort_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jshort_copy); |
| 98 | address StubRoutines::_arrayof_jint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jint_copy); |
| 99 | address StubRoutines::_arrayof_jlong_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jlong_copy); |
| 100 | address StubRoutines::_arrayof_oop_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy); |
| 101 | address StubRoutines::_arrayof_oop_arraycopy_uninit = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy_uninit); |
| 102 | address StubRoutines::_arrayof_jbyte_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jbyte_copy); |
| 103 | address StubRoutines::_arrayof_jshort_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jshort_copy); |
| 104 | address StubRoutines::_arrayof_jint_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jint_copy); |
| 105 | address StubRoutines::_arrayof_jlong_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_jlong_copy); |
| 106 | address StubRoutines::_arrayof_oop_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy); |
| 107 | address StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy_uninit); |
| 108 | |
| 109 | address StubRoutines::_zero_aligned_words = CAST_FROM_FN_PTR(address, Copy::zero_to_words); |
| 110 | |
| 111 | address StubRoutines::_checkcast_arraycopy = NULL; |
| 112 | address StubRoutines::_checkcast_arraycopy_uninit = NULL; |
| 113 | address StubRoutines::_unsafe_arraycopy = NULL; |
| 114 | address StubRoutines::_generic_arraycopy = NULL; |
| 115 | |
| 116 | |
| 117 | address StubRoutines::_jbyte_fill; |
| 118 | address StubRoutines::_jshort_fill; |
| 119 | address StubRoutines::_jint_fill; |
| 120 | address StubRoutines::_arrayof_jbyte_fill; |
| 121 | address StubRoutines::_arrayof_jshort_fill; |
| 122 | address StubRoutines::_arrayof_jint_fill; |
| 123 | |
| 124 | address StubRoutines::_aescrypt_encryptBlock = NULL; |
| 125 | address StubRoutines::_aescrypt_decryptBlock = NULL; |
| 126 | address StubRoutines::_cipherBlockChaining_encryptAESCrypt = NULL; |
| 127 | address StubRoutines::_cipherBlockChaining_decryptAESCrypt = NULL; |
| 128 | address StubRoutines::_counterMode_AESCrypt = NULL; |
| 129 | address StubRoutines::_ghash_processBlocks = NULL; |
| 130 | address StubRoutines::_base64_encodeBlock = NULL; |
| 131 | |
| 132 | address StubRoutines::_sha1_implCompress = NULL; |
| 133 | address StubRoutines::_sha1_implCompressMB = NULL; |
| 134 | address StubRoutines::_sha256_implCompress = NULL; |
| 135 | address StubRoutines::_sha256_implCompressMB = NULL; |
| 136 | address StubRoutines::_sha512_implCompress = NULL; |
| 137 | address StubRoutines::_sha512_implCompressMB = NULL; |
| 138 | |
| 139 | address StubRoutines::_updateBytesCRC32 = NULL; |
| 140 | address StubRoutines::_crc_table_adr = NULL; |
| 141 | |
| 142 | address StubRoutines::_crc32c_table_addr = NULL; |
| 143 | address StubRoutines::_updateBytesCRC32C = NULL; |
| 144 | address StubRoutines::_updateBytesAdler32 = NULL; |
| 145 | |
| 146 | address StubRoutines::_multiplyToLen = NULL; |
| 147 | address StubRoutines::_squareToLen = NULL; |
| 148 | address StubRoutines::_mulAdd = NULL; |
| 149 | address StubRoutines::_montgomeryMultiply = NULL; |
| 150 | address StubRoutines::_montgomerySquare = NULL; |
| 151 | |
| 152 | address StubRoutines::_vectorizedMismatch = NULL; |
| 153 | |
| 154 | address StubRoutines::_dexp = NULL; |
| 155 | address StubRoutines::_dlog = NULL; |
| 156 | address StubRoutines::_dlog10 = NULL; |
| 157 | address StubRoutines::_dpow = NULL; |
| 158 | address StubRoutines::_dsin = NULL; |
| 159 | address StubRoutines::_dcos = NULL; |
| 160 | address StubRoutines::_dlibm_sin_cos_huge = NULL; |
| 161 | address StubRoutines::_dlibm_reduce_pi04l = NULL; |
| 162 | address StubRoutines::_dlibm_tan_cot_huge = NULL; |
| 163 | address StubRoutines::_dtan = NULL; |
| 164 | |
| 165 | address StubRoutines::_safefetch32_entry = NULL; |
| 166 | address StubRoutines::_safefetch32_fault_pc = NULL; |
| 167 | address StubRoutines::_safefetch32_continuation_pc = NULL; |
| 168 | address StubRoutines::_safefetchN_entry = NULL; |
| 169 | address StubRoutines::_safefetchN_fault_pc = NULL; |
| 170 | address StubRoutines::_safefetchN_continuation_pc = NULL; |
| 171 | |
| 172 | // Initialization |
| 173 | // |
| 174 | // Note: to break cycle with universe initialization, stubs are generated in two phases. |
| 175 | // The first one generates stubs needed during universe init (e.g., _handle_must_compile_first_entry). |
| 176 | // The second phase includes all other stubs (which may depend on universe being initialized.) |
| 177 | |
| 178 | extern void StubGenerator_generate(CodeBuffer* code, bool all); // only interface to generators |
| 179 | |
| 180 | void StubRoutines::initialize1() { |
| 181 | if (_code1 == NULL) { |
| 182 | ResourceMark rm; |
| 183 | TraceTime timer("StubRoutines generation 1" , TRACETIME_LOG(Info, startuptime)); |
| 184 | _code1 = BufferBlob::create("StubRoutines (1)" , code_size1); |
| 185 | if (_code1 == NULL) { |
| 186 | vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)" ); |
| 187 | } |
| 188 | CodeBuffer buffer(_code1); |
| 189 | StubGenerator_generate(&buffer, false); |
| 190 | // When new stubs added we need to make sure there is some space left |
| 191 | // to catch situation when we should increase size again. |
| 192 | assert(code_size1 == 0 || buffer.insts_remaining() > 200, "increase code_size1" ); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | |
| 197 | #ifdef ASSERT |
| 198 | typedef void (*arraycopy_fn)(address src, address dst, int count); |
| 199 | |
| 200 | // simple tests of generated arraycopy functions |
| 201 | static void test_arraycopy_func(address func, int alignment) { |
| 202 | int v = 0xcc; |
| 203 | int v2 = 0x11; |
| 204 | jlong lbuffer[8]; |
| 205 | jlong lbuffer2[8]; |
| 206 | address fbuffer = (address) lbuffer; |
| 207 | address fbuffer2 = (address) lbuffer2; |
| 208 | unsigned int i; |
| 209 | for (i = 0; i < sizeof(lbuffer); i++) { |
| 210 | fbuffer[i] = v; fbuffer2[i] = v2; |
| 211 | } |
| 212 | // C++ does not guarantee jlong[] array alignment to 8 bytes. |
| 213 | // Use middle of array to check that memory before it is not modified. |
| 214 | address buffer = align_up((address)&lbuffer[4], BytesPerLong); |
| 215 | address buffer2 = align_up((address)&lbuffer2[4], BytesPerLong); |
| 216 | // do an aligned copy |
| 217 | ((arraycopy_fn)func)(buffer, buffer2, 0); |
| 218 | for (i = 0; i < sizeof(lbuffer); i++) { |
| 219 | assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything" ); |
| 220 | } |
| 221 | // adjust destination alignment |
| 222 | ((arraycopy_fn)func)(buffer, buffer2 + alignment, 0); |
| 223 | for (i = 0; i < sizeof(lbuffer); i++) { |
| 224 | assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything" ); |
| 225 | } |
| 226 | // adjust source alignment |
| 227 | ((arraycopy_fn)func)(buffer + alignment, buffer2, 0); |
| 228 | for (i = 0; i < sizeof(lbuffer); i++) { |
| 229 | assert(fbuffer[i] == v && fbuffer2[i] == v2, "shouldn't have copied anything" ); |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | // simple test for SafeFetch32 |
| 234 | static void test_safefetch32() { |
| 235 | if (CanUseSafeFetch32()) { |
| 236 | int dummy = 17; |
| 237 | int* const p_invalid = (int*) VMError::get_segfault_address(); |
| 238 | int* const p_valid = &dummy; |
| 239 | int result_invalid = SafeFetch32(p_invalid, 0xABC); |
| 240 | assert(result_invalid == 0xABC, "SafeFetch32 error" ); |
| 241 | int result_valid = SafeFetch32(p_valid, 0xABC); |
| 242 | assert(result_valid == 17, "SafeFetch32 error" ); |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | // simple test for SafeFetchN |
| 247 | static void test_safefetchN() { |
| 248 | if (CanUseSafeFetchN()) { |
| 249 | #ifdef _LP64 |
| 250 | const intptr_t v1 = UCONST64(0xABCD00000000ABCD); |
| 251 | const intptr_t v2 = UCONST64(0xDEFD00000000DEFD); |
| 252 | #else |
| 253 | const intptr_t v1 = 0xABCDABCD; |
| 254 | const intptr_t v2 = 0xDEFDDEFD; |
| 255 | #endif |
| 256 | intptr_t dummy = v1; |
| 257 | intptr_t* const p_invalid = (intptr_t*) VMError::get_segfault_address(); |
| 258 | intptr_t* const p_valid = &dummy; |
| 259 | intptr_t result_invalid = SafeFetchN(p_invalid, v2); |
| 260 | assert(result_invalid == v2, "SafeFetchN error" ); |
| 261 | intptr_t result_valid = SafeFetchN(p_valid, v2); |
| 262 | assert(result_valid == v1, "SafeFetchN error" ); |
| 263 | } |
| 264 | } |
| 265 | #endif |
| 266 | |
| 267 | void StubRoutines::initialize2() { |
| 268 | if (_code2 == NULL) { |
| 269 | ResourceMark rm; |
| 270 | TraceTime timer("StubRoutines generation 2" , TRACETIME_LOG(Info, startuptime)); |
| 271 | _code2 = BufferBlob::create("StubRoutines (2)" , code_size2); |
| 272 | if (_code2 == NULL) { |
| 273 | vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)" ); |
| 274 | } |
| 275 | CodeBuffer buffer(_code2); |
| 276 | StubGenerator_generate(&buffer, true); |
| 277 | // When new stubs added we need to make sure there is some space left |
| 278 | // to catch situation when we should increase size again. |
| 279 | assert(code_size2 == 0 || buffer.insts_remaining() > 200, "increase code_size2" ); |
| 280 | } |
| 281 | |
| 282 | #ifdef ASSERT |
| 283 | |
| 284 | #define TEST_ARRAYCOPY(type) \ |
| 285 | test_arraycopy_func( type##_arraycopy(), sizeof(type)); \ |
| 286 | test_arraycopy_func( type##_disjoint_arraycopy(), sizeof(type)); \ |
| 287 | test_arraycopy_func(arrayof_##type##_arraycopy(), sizeof(HeapWord)); \ |
| 288 | test_arraycopy_func(arrayof_##type##_disjoint_arraycopy(), sizeof(HeapWord)) |
| 289 | |
| 290 | // Make sure all the arraycopy stubs properly handle zero count |
| 291 | TEST_ARRAYCOPY(jbyte); |
| 292 | TEST_ARRAYCOPY(jshort); |
| 293 | TEST_ARRAYCOPY(jint); |
| 294 | TEST_ARRAYCOPY(jlong); |
| 295 | |
| 296 | #undef TEST_ARRAYCOPY |
| 297 | |
| 298 | #define TEST_FILL(type) \ |
| 299 | if (_##type##_fill != NULL) { \ |
| 300 | union { \ |
| 301 | double d; \ |
| 302 | type body[96]; \ |
| 303 | } s; \ |
| 304 | \ |
| 305 | int v = 32; \ |
| 306 | for (int offset = -2; offset <= 2; offset++) { \ |
| 307 | for (int i = 0; i < 96; i++) { \ |
| 308 | s.body[i] = 1; \ |
| 309 | } \ |
| 310 | type* start = s.body + 8 + offset; \ |
| 311 | for (int aligned = 0; aligned < 2; aligned++) { \ |
| 312 | if (aligned) { \ |
| 313 | if (((intptr_t)start) % HeapWordSize == 0) { \ |
| 314 | ((void (*)(type*, int, int))StubRoutines::_arrayof_##type##_fill)(start, v, 80); \ |
| 315 | } else { \ |
| 316 | continue; \ |
| 317 | } \ |
| 318 | } else { \ |
| 319 | ((void (*)(type*, int, int))StubRoutines::_##type##_fill)(start, v, 80); \ |
| 320 | } \ |
| 321 | for (int i = 0; i < 96; i++) { \ |
| 322 | if (i < (8 + offset) || i >= (88 + offset)) { \ |
| 323 | assert(s.body[i] == 1, "what?"); \ |
| 324 | } else { \ |
| 325 | assert(s.body[i] == 32, "what?"); \ |
| 326 | } \ |
| 327 | } \ |
| 328 | } \ |
| 329 | } \ |
| 330 | } \ |
| 331 | |
| 332 | TEST_FILL(jbyte); |
| 333 | TEST_FILL(jshort); |
| 334 | TEST_FILL(jint); |
| 335 | |
| 336 | #undef TEST_FILL |
| 337 | |
| 338 | #define TEST_COPYRTN(type) \ |
| 339 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::conjoint_##type##s_atomic), sizeof(type)); \ |
| 340 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::arrayof_conjoint_##type##s), (int)MAX2(sizeof(HeapWord), sizeof(type))) |
| 341 | |
| 342 | // Make sure all the copy runtime routines properly handle zero count |
| 343 | TEST_COPYRTN(jbyte); |
| 344 | TEST_COPYRTN(jshort); |
| 345 | TEST_COPYRTN(jint); |
| 346 | TEST_COPYRTN(jlong); |
| 347 | |
| 348 | #undef TEST_COPYRTN |
| 349 | |
| 350 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::conjoint_words), sizeof(HeapWord)); |
| 351 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::disjoint_words), sizeof(HeapWord)); |
| 352 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::disjoint_words_atomic), sizeof(HeapWord)); |
| 353 | // Aligned to BytesPerLong |
| 354 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_conjoint_words), sizeof(jlong)); |
| 355 | test_arraycopy_func(CAST_FROM_FN_PTR(address, Copy::aligned_disjoint_words), sizeof(jlong)); |
| 356 | |
| 357 | // test safefetch routines |
| 358 | // Not on Windows 32bit until 8074860 is fixed |
| 359 | #if ! (defined(_WIN32) && defined(_M_IX86)) |
| 360 | test_safefetch32(); |
| 361 | test_safefetchN(); |
| 362 | #endif |
| 363 | |
| 364 | #endif |
| 365 | } |
| 366 | |
| 367 | |
| 368 | void stubRoutines_init1() { StubRoutines::initialize1(); } |
| 369 | void stubRoutines_init2() { StubRoutines::initialize2(); } |
| 370 | |
| 371 | // |
| 372 | // Default versions of arraycopy functions |
| 373 | // |
| 374 | |
| 375 | JRT_LEAF(void, StubRoutines::jbyte_copy(jbyte* src, jbyte* dest, size_t count)) |
| 376 | #ifndef PRODUCT |
| 377 | SharedRuntime::_jbyte_array_copy_ctr++; // Slow-path byte array copy |
| 378 | #endif // !PRODUCT |
| 379 | Copy::conjoint_jbytes_atomic(src, dest, count); |
| 380 | JRT_END |
| 381 | |
| 382 | JRT_LEAF(void, StubRoutines::jshort_copy(jshort* src, jshort* dest, size_t count)) |
| 383 | #ifndef PRODUCT |
| 384 | SharedRuntime::_jshort_array_copy_ctr++; // Slow-path short/char array copy |
| 385 | #endif // !PRODUCT |
| 386 | Copy::conjoint_jshorts_atomic(src, dest, count); |
| 387 | JRT_END |
| 388 | |
| 389 | JRT_LEAF(void, StubRoutines::jint_copy(jint* src, jint* dest, size_t count)) |
| 390 | #ifndef PRODUCT |
| 391 | SharedRuntime::_jint_array_copy_ctr++; // Slow-path int/float array copy |
| 392 | #endif // !PRODUCT |
| 393 | Copy::conjoint_jints_atomic(src, dest, count); |
| 394 | JRT_END |
| 395 | |
| 396 | JRT_LEAF(void, StubRoutines::jlong_copy(jlong* src, jlong* dest, size_t count)) |
| 397 | #ifndef PRODUCT |
| 398 | SharedRuntime::_jlong_array_copy_ctr++; // Slow-path long/double array copy |
| 399 | #endif // !PRODUCT |
| 400 | Copy::conjoint_jlongs_atomic(src, dest, count); |
| 401 | JRT_END |
| 402 | |
| 403 | JRT_LEAF(void, StubRoutines::oop_copy(oop* src, oop* dest, size_t count)) |
| 404 | #ifndef PRODUCT |
| 405 | SharedRuntime::_oop_array_copy_ctr++; // Slow-path oop array copy |
| 406 | #endif // !PRODUCT |
| 407 | assert(count != 0, "count should be non-zero" ); |
| 408 | ArrayAccess<>::oop_arraycopy_raw((HeapWord*)src, (HeapWord*)dest, count); |
| 409 | JRT_END |
| 410 | |
| 411 | JRT_LEAF(void, StubRoutines::oop_copy_uninit(oop* src, oop* dest, size_t count)) |
| 412 | #ifndef PRODUCT |
| 413 | SharedRuntime::_oop_array_copy_ctr++; // Slow-path oop array copy |
| 414 | #endif // !PRODUCT |
| 415 | assert(count != 0, "count should be non-zero" ); |
| 416 | ArrayAccess<IS_DEST_UNINITIALIZED>::oop_arraycopy_raw((HeapWord*)src, (HeapWord*)dest, count); |
| 417 | JRT_END |
| 418 | |
| 419 | JRT_LEAF(void, StubRoutines::arrayof_jbyte_copy(HeapWord* src, HeapWord* dest, size_t count)) |
| 420 | #ifndef PRODUCT |
| 421 | SharedRuntime::_jbyte_array_copy_ctr++; // Slow-path byte array copy |
| 422 | #endif // !PRODUCT |
| 423 | Copy::arrayof_conjoint_jbytes(src, dest, count); |
| 424 | JRT_END |
| 425 | |
| 426 | JRT_LEAF(void, StubRoutines::arrayof_jshort_copy(HeapWord* src, HeapWord* dest, size_t count)) |
| 427 | #ifndef PRODUCT |
| 428 | SharedRuntime::_jshort_array_copy_ctr++; // Slow-path short/char array copy |
| 429 | #endif // !PRODUCT |
| 430 | Copy::arrayof_conjoint_jshorts(src, dest, count); |
| 431 | JRT_END |
| 432 | |
| 433 | JRT_LEAF(void, StubRoutines::arrayof_jint_copy(HeapWord* src, HeapWord* dest, size_t count)) |
| 434 | #ifndef PRODUCT |
| 435 | SharedRuntime::_jint_array_copy_ctr++; // Slow-path int/float array copy |
| 436 | #endif // !PRODUCT |
| 437 | Copy::arrayof_conjoint_jints(src, dest, count); |
| 438 | JRT_END |
| 439 | |
| 440 | JRT_LEAF(void, StubRoutines::arrayof_jlong_copy(HeapWord* src, HeapWord* dest, size_t count)) |
| 441 | #ifndef PRODUCT |
| 442 | SharedRuntime::_jlong_array_copy_ctr++; // Slow-path int/float array copy |
| 443 | #endif // !PRODUCT |
| 444 | Copy::arrayof_conjoint_jlongs(src, dest, count); |
| 445 | JRT_END |
| 446 | |
| 447 | JRT_LEAF(void, StubRoutines::arrayof_oop_copy(HeapWord* src, HeapWord* dest, size_t count)) |
| 448 | #ifndef PRODUCT |
| 449 | SharedRuntime::_oop_array_copy_ctr++; // Slow-path oop array copy |
| 450 | #endif // !PRODUCT |
| 451 | assert(count != 0, "count should be non-zero" ); |
| 452 | ArrayAccess<ARRAYCOPY_ARRAYOF>::oop_arraycopy_raw(src, dest, count); |
| 453 | JRT_END |
| 454 | |
| 455 | JRT_LEAF(void, StubRoutines::arrayof_oop_copy_uninit(HeapWord* src, HeapWord* dest, size_t count)) |
| 456 | #ifndef PRODUCT |
| 457 | SharedRuntime::_oop_array_copy_ctr++; // Slow-path oop array copy |
| 458 | #endif // !PRODUCT |
| 459 | assert(count != 0, "count should be non-zero" ); |
| 460 | ArrayAccess<ARRAYCOPY_ARRAYOF | IS_DEST_UNINITIALIZED>::oop_arraycopy_raw(src, dest, count); |
| 461 | JRT_END |
| 462 | |
| 463 | address StubRoutines::select_fill_function(BasicType t, bool aligned, const char* &name) { |
| 464 | #define RETURN_STUB(xxx_fill) { \ |
| 465 | name = #xxx_fill; \ |
| 466 | return StubRoutines::xxx_fill(); } |
| 467 | |
| 468 | switch (t) { |
| 469 | case T_BYTE: |
| 470 | case T_BOOLEAN: |
| 471 | if (!aligned) RETURN_STUB(jbyte_fill); |
| 472 | RETURN_STUB(arrayof_jbyte_fill); |
| 473 | case T_CHAR: |
| 474 | case T_SHORT: |
| 475 | if (!aligned) RETURN_STUB(jshort_fill); |
| 476 | RETURN_STUB(arrayof_jshort_fill); |
| 477 | case T_INT: |
| 478 | case T_FLOAT: |
| 479 | if (!aligned) RETURN_STUB(jint_fill); |
| 480 | RETURN_STUB(arrayof_jint_fill); |
| 481 | case T_DOUBLE: |
| 482 | case T_LONG: |
| 483 | case T_ARRAY: |
| 484 | case T_OBJECT: |
| 485 | case T_NARROWOOP: |
| 486 | case T_NARROWKLASS: |
| 487 | case T_ADDRESS: |
| 488 | // Currently unsupported |
| 489 | return NULL; |
| 490 | |
| 491 | default: |
| 492 | ShouldNotReachHere(); |
| 493 | return NULL; |
| 494 | } |
| 495 | |
| 496 | #undef RETURN_STUB |
| 497 | } |
| 498 | |
| 499 | // constants for computing the copy function |
| 500 | enum { |
| 501 | COPYFUNC_UNALIGNED = 0, |
| 502 | COPYFUNC_ALIGNED = 1, // src, dest aligned to HeapWordSize |
| 503 | COPYFUNC_CONJOINT = 0, |
| 504 | COPYFUNC_DISJOINT = 2 // src != dest, or transfer can descend |
| 505 | }; |
| 506 | |
| 507 | // Note: The condition "disjoint" applies also for overlapping copies |
| 508 | // where an descending copy is permitted (i.e., dest_offset <= src_offset). |
| 509 | address |
| 510 | StubRoutines::select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized) { |
| 511 | int selector = |
| 512 | (aligned ? COPYFUNC_ALIGNED : COPYFUNC_UNALIGNED) + |
| 513 | (disjoint ? COPYFUNC_DISJOINT : COPYFUNC_CONJOINT); |
| 514 | |
| 515 | #define RETURN_STUB(xxx_arraycopy) { \ |
| 516 | name = #xxx_arraycopy; \ |
| 517 | return StubRoutines::xxx_arraycopy(); } |
| 518 | |
| 519 | #define RETURN_STUB_PARM(xxx_arraycopy, parm) { \ |
| 520 | name = #xxx_arraycopy; \ |
| 521 | return StubRoutines::xxx_arraycopy(parm); } |
| 522 | |
| 523 | switch (t) { |
| 524 | case T_BYTE: |
| 525 | case T_BOOLEAN: |
| 526 | switch (selector) { |
| 527 | case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_arraycopy); |
| 528 | case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_arraycopy); |
| 529 | case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_disjoint_arraycopy); |
| 530 | case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_disjoint_arraycopy); |
| 531 | } |
| 532 | case T_CHAR: |
| 533 | case T_SHORT: |
| 534 | switch (selector) { |
| 535 | case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_arraycopy); |
| 536 | case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_arraycopy); |
| 537 | case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_disjoint_arraycopy); |
| 538 | case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_disjoint_arraycopy); |
| 539 | } |
| 540 | case T_INT: |
| 541 | case T_FLOAT: |
| 542 | switch (selector) { |
| 543 | case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_arraycopy); |
| 544 | case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_arraycopy); |
| 545 | case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_disjoint_arraycopy); |
| 546 | case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_disjoint_arraycopy); |
| 547 | } |
| 548 | case T_DOUBLE: |
| 549 | case T_LONG: |
| 550 | switch (selector) { |
| 551 | case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_arraycopy); |
| 552 | case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_arraycopy); |
| 553 | case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_disjoint_arraycopy); |
| 554 | case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_disjoint_arraycopy); |
| 555 | } |
| 556 | case T_ARRAY: |
| 557 | case T_OBJECT: |
| 558 | switch (selector) { |
| 559 | case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_arraycopy, dest_uninitialized); |
| 560 | case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_arraycopy, dest_uninitialized); |
| 561 | case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_disjoint_arraycopy, dest_uninitialized); |
| 562 | case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_disjoint_arraycopy, dest_uninitialized); |
| 563 | } |
| 564 | default: |
| 565 | ShouldNotReachHere(); |
| 566 | return NULL; |
| 567 | } |
| 568 | |
| 569 | #undef RETURN_STUB |
| 570 | #undef RETURN_STUB_PARM |
| 571 | } |
| 572 | |