1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <cstdio> 18 19 #include "art_field-inl.h" 20 #include "art_method-inl.h" 21 #include "base/callee_save_type.h" 22 #include "base/enums.h" 23 #include "class_linker-inl.h" 24 #include "common_runtime_test.h" 25 #include "entrypoints/quick/quick_entrypoints_enum.h" 26 #include "imt_conflict_table.h" 27 #include "jni_internal.h" 28 #include "linear_alloc.h" 29 #include "mirror/class-inl.h" 30 #include "mirror/string-inl.h" 31 #include "scoped_thread_state_change-inl.h" 32 33 namespace art { 34 35 36 class StubTest : public CommonRuntimeTest { 37 protected: 38 // We need callee-save methods set up in the Runtime for exceptions. 39 void SetUp() OVERRIDE { 40 // Do the normal setup. 41 CommonRuntimeTest::SetUp(); 42 43 { 44 // Create callee-save methods 45 ScopedObjectAccess soa(Thread::Current()); 46 runtime_->SetInstructionSet(kRuntimeISA); 47 for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); ++i) { 48 CalleeSaveType type = CalleeSaveType(i); 49 if (!runtime_->HasCalleeSaveMethod(type)) { 50 runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(), type); 51 } 52 } 53 } 54 } 55 56 void SetUpRuntimeOptions(RuntimeOptions *options) OVERRIDE { 57 // Use a smaller heap 58 for (std::pair<std::string, const void*>& pair : *options) { 59 if (pair.first.find("-Xmx") == 0) { 60 pair.first = "-Xmx4M"; // Smallest we can go. 61 } 62 } 63 options->push_back(std::make_pair("-Xint", nullptr)); 64 } 65 66 // Helper function needed since TEST_F makes a new class. 67 Thread::tls_ptr_sized_values* GetTlsPtr(Thread* self) { 68 return &self->tlsPtr_; 69 } 70 71 public: 72 size_t Invoke3(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self) { 73 return Invoke3WithReferrer(arg0, arg1, arg2, code, self, nullptr); 74 } 75 76 // TODO: Set up a frame according to referrer's specs. 77 size_t Invoke3WithReferrer(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self, 78 ArtMethod* referrer) { 79 return Invoke3WithReferrerAndHidden(arg0, arg1, arg2, code, self, referrer, 0); 80 } 81 82 // TODO: Set up a frame according to referrer's specs. 83 size_t Invoke3WithReferrerAndHidden(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, 84 Thread* self, ArtMethod* referrer, size_t hidden) { 85 // Push a transition back into managed code onto the linked list in thread. 86 ManagedStack fragment; 87 self->PushManagedStackFragment(&fragment); 88 89 size_t result; 90 size_t fpr_result = 0; 91 #if defined(__i386__) 92 // TODO: Set the thread? 93 #define PUSH(reg) "push " # reg "\n\t .cfi_adjust_cfa_offset 4\n\t" 94 #define POP(reg) "pop " # reg "\n\t .cfi_adjust_cfa_offset -4\n\t" 95 __asm__ __volatile__( 96 "movd %[hidden], %%xmm7\n\t" // This is a memory op, so do this early. If it is off of 97 // esp, then we won't be able to access it after spilling. 98 99 // Spill 6 registers. 100 PUSH(%%ebx) 101 PUSH(%%ecx) 102 PUSH(%%edx) 103 PUSH(%%esi) 104 PUSH(%%edi) 105 PUSH(%%ebp) 106 107 // Store the inputs to the stack, but keep the referrer up top, less work. 108 PUSH(%[referrer]) // Align stack. 109 PUSH(%[referrer]) // Store referrer 110 111 PUSH(%[arg0]) 112 PUSH(%[arg1]) 113 PUSH(%[arg2]) 114 PUSH(%[code]) 115 // Now read them back into the required registers. 116 POP(%%edi) 117 POP(%%edx) 118 POP(%%ecx) 119 POP(%%eax) 120 // Call is prepared now. 121 122 "call *%%edi\n\t" // Call the stub 123 "addl $8, %%esp\n\t" // Pop referrer and padding. 124 ".cfi_adjust_cfa_offset -8\n\t" 125 126 // Restore 6 registers. 127 POP(%%ebp) 128 POP(%%edi) 129 POP(%%esi) 130 POP(%%edx) 131 POP(%%ecx) 132 POP(%%ebx) 133 134 : "=a" (result) 135 // Use the result from eax 136 : [arg0] "r"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), 137 [referrer]"r"(referrer), [hidden]"m"(hidden) 138 // This places code into edi, arg0 into eax, arg1 into ecx, and arg2 into edx 139 : "memory", "xmm7"); // clobber. 140 #undef PUSH 141 #undef POP 142 #elif defined(__arm__) 143 __asm__ __volatile__( 144 "push {r1-r12, lr}\n\t" // Save state, 13*4B = 52B 145 ".cfi_adjust_cfa_offset 52\n\t" 146 "push {r9}\n\t" 147 ".cfi_adjust_cfa_offset 4\n\t" 148 "mov r9, %[referrer]\n\n" 149 "str r9, [sp, #-8]!\n\t" // Push referrer, +8B padding so 16B aligned 150 ".cfi_adjust_cfa_offset 8\n\t" 151 "ldr r9, [sp, #8]\n\t" 152 153 // Push everything on the stack, so we don't rely on the order. What a mess. :-( 154 "sub sp, sp, #24\n\t" 155 "str %[arg0], [sp]\n\t" 156 "str %[arg1], [sp, #4]\n\t" 157 "str %[arg2], [sp, #8]\n\t" 158 "str %[code], [sp, #12]\n\t" 159 "str %[self], [sp, #16]\n\t" 160 "str %[hidden], [sp, #20]\n\t" 161 "ldr r0, [sp]\n\t" 162 "ldr r1, [sp, #4]\n\t" 163 "ldr r2, [sp, #8]\n\t" 164 "ldr r3, [sp, #12]\n\t" 165 "ldr r9, [sp, #16]\n\t" 166 "ldr r12, [sp, #20]\n\t" 167 "add sp, sp, #24\n\t" 168 169 "blx r3\n\t" // Call the stub 170 "add sp, sp, #12\n\t" // Pop null and padding 171 ".cfi_adjust_cfa_offset -12\n\t" 172 "pop {r1-r12, lr}\n\t" // Restore state 173 ".cfi_adjust_cfa_offset -52\n\t" 174 "mov %[result], r0\n\t" // Save the result 175 : [result] "=r" (result) 176 // Use the result from r0 177 : [arg0] "r"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self), 178 [referrer] "r"(referrer), [hidden] "r"(hidden) 179 : "r0", "memory"); // clobber. 180 #elif defined(__aarch64__) 181 __asm__ __volatile__( 182 // Spill x0-x7 which we say we don't clobber. May contain args. 183 "sub sp, sp, #80\n\t" 184 ".cfi_adjust_cfa_offset 80\n\t" 185 "stp x0, x1, [sp]\n\t" 186 "stp x2, x3, [sp, #16]\n\t" 187 "stp x4, x5, [sp, #32]\n\t" 188 "stp x6, x7, [sp, #48]\n\t" 189 // To be extra defensive, store x20,x21. We do this because some of the stubs might make a 190 // transition into the runtime via the blr instruction below and *not* save x20. 191 "stp x20, x21, [sp, #64]\n\t" 192 193 "sub sp, sp, #16\n\t" // Reserve stack space, 16B aligned 194 ".cfi_adjust_cfa_offset 16\n\t" 195 "str %[referrer], [sp]\n\t" // referrer 196 197 // Push everything on the stack, so we don't rely on the order. What a mess. :-( 198 "sub sp, sp, #48\n\t" 199 ".cfi_adjust_cfa_offset 48\n\t" 200 // All things are "r" constraints, so direct str/stp should work. 201 "stp %[arg0], %[arg1], [sp]\n\t" 202 "stp %[arg2], %[code], [sp, #16]\n\t" 203 "stp %[self], %[hidden], [sp, #32]\n\t" 204 205 // Now we definitely have x0-x3 free, use it to garble d8 - d15 206 "movk x0, #0xfad0\n\t" 207 "movk x0, #0xebad, lsl #16\n\t" 208 "movk x0, #0xfad0, lsl #32\n\t" 209 "movk x0, #0xebad, lsl #48\n\t" 210 "fmov d8, x0\n\t" 211 "add x0, x0, 1\n\t" 212 "fmov d9, x0\n\t" 213 "add x0, x0, 1\n\t" 214 "fmov d10, x0\n\t" 215 "add x0, x0, 1\n\t" 216 "fmov d11, x0\n\t" 217 "add x0, x0, 1\n\t" 218 "fmov d12, x0\n\t" 219 "add x0, x0, 1\n\t" 220 "fmov d13, x0\n\t" 221 "add x0, x0, 1\n\t" 222 "fmov d14, x0\n\t" 223 "add x0, x0, 1\n\t" 224 "fmov d15, x0\n\t" 225 226 // Load call params into the right registers. 227 "ldp x0, x1, [sp]\n\t" 228 "ldp x2, x3, [sp, #16]\n\t" 229 "ldp x19, x17, [sp, #32]\n\t" 230 "add sp, sp, #48\n\t" 231 ".cfi_adjust_cfa_offset -48\n\t" 232 233 "blr x3\n\t" // Call the stub 234 "mov x8, x0\n\t" // Store result 235 "add sp, sp, #16\n\t" // Drop the quick "frame" 236 ".cfi_adjust_cfa_offset -16\n\t" 237 238 // Test d8 - d15. We can use x1 and x2. 239 "movk x1, #0xfad0\n\t" 240 "movk x1, #0xebad, lsl #16\n\t" 241 "movk x1, #0xfad0, lsl #32\n\t" 242 "movk x1, #0xebad, lsl #48\n\t" 243 "fmov x2, d8\n\t" 244 "cmp x1, x2\n\t" 245 "b.ne 1f\n\t" 246 "add x1, x1, 1\n\t" 247 248 "fmov x2, d9\n\t" 249 "cmp x1, x2\n\t" 250 "b.ne 1f\n\t" 251 "add x1, x1, 1\n\t" 252 253 "fmov x2, d10\n\t" 254 "cmp x1, x2\n\t" 255 "b.ne 1f\n\t" 256 "add x1, x1, 1\n\t" 257 258 "fmov x2, d11\n\t" 259 "cmp x1, x2\n\t" 260 "b.ne 1f\n\t" 261 "add x1, x1, 1\n\t" 262 263 "fmov x2, d12\n\t" 264 "cmp x1, x2\n\t" 265 "b.ne 1f\n\t" 266 "add x1, x1, 1\n\t" 267 268 "fmov x2, d13\n\t" 269 "cmp x1, x2\n\t" 270 "b.ne 1f\n\t" 271 "add x1, x1, 1\n\t" 272 273 "fmov x2, d14\n\t" 274 "cmp x1, x2\n\t" 275 "b.ne 1f\n\t" 276 "add x1, x1, 1\n\t" 277 278 "fmov x2, d15\n\t" 279 "cmp x1, x2\n\t" 280 "b.ne 1f\n\t" 281 282 "mov x9, #0\n\t" // Use x9 as flag, in clobber list 283 284 // Finish up. 285 "2:\n\t" 286 "ldp x0, x1, [sp]\n\t" // Restore stuff not named clobbered, may contain fpr_result 287 "ldp x2, x3, [sp, #16]\n\t" 288 "ldp x4, x5, [sp, #32]\n\t" 289 "ldp x6, x7, [sp, #48]\n\t" 290 "ldp x20, x21, [sp, #64]\n\t" 291 "add sp, sp, #80\n\t" // Free stack space, now sp as on entry 292 ".cfi_adjust_cfa_offset -80\n\t" 293 294 "str x9, %[fpr_result]\n\t" // Store the FPR comparison result 295 "mov %[result], x8\n\t" // Store the call result 296 297 "b 3f\n\t" // Goto end 298 299 // Failed fpr verification. 300 "1:\n\t" 301 "mov x9, #1\n\t" 302 "b 2b\n\t" // Goto finish-up 303 304 // End 305 "3:\n\t" 306 : [result] "=r" (result) 307 // Use the result from r0 308 : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self), 309 [referrer] "r"(referrer), [hidden] "r"(hidden), [fpr_result] "m" (fpr_result) 310 // Leave one register unclobbered, which is needed for compiling with 311 // -fstack-protector-strong. According to AAPCS64 registers x9-x15 are caller-saved, 312 // which means we should unclobber one of the callee-saved registers that are unused. 313 // Here we use x20. 314 // http://b/72613441, Clang 7.0 asks for one more register, so we do not reserve x21. 315 : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", 316 "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x30", 317 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", 318 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", 319 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", 320 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", 321 "memory"); 322 #elif defined(__mips__) && !defined(__LP64__) 323 __asm__ __volatile__ ( 324 // Spill a0-a3 and t0-t7 which we say we don't clobber. May contain args. 325 "addiu $sp, $sp, -64\n\t" 326 "sw $a0, 0($sp)\n\t" 327 "sw $a1, 4($sp)\n\t" 328 "sw $a2, 8($sp)\n\t" 329 "sw $a3, 12($sp)\n\t" 330 "sw $t0, 16($sp)\n\t" 331 "sw $t1, 20($sp)\n\t" 332 "sw $t2, 24($sp)\n\t" 333 "sw $t3, 28($sp)\n\t" 334 "sw $t4, 32($sp)\n\t" 335 "sw $t5, 36($sp)\n\t" 336 "sw $t6, 40($sp)\n\t" 337 "sw $t7, 44($sp)\n\t" 338 // Spill gp register since it is caller save. 339 "sw $gp, 52($sp)\n\t" 340 341 "addiu $sp, $sp, -16\n\t" // Reserve stack space, 16B aligned. 342 "sw %[referrer], 0($sp)\n\t" 343 344 // Push everything on the stack, so we don't rely on the order. 345 "addiu $sp, $sp, -24\n\t" 346 "sw %[arg0], 0($sp)\n\t" 347 "sw %[arg1], 4($sp)\n\t" 348 "sw %[arg2], 8($sp)\n\t" 349 "sw %[code], 12($sp)\n\t" 350 "sw %[self], 16($sp)\n\t" 351 "sw %[hidden], 20($sp)\n\t" 352 353 // Load call params into the right registers. 354 "lw $a0, 0($sp)\n\t" 355 "lw $a1, 4($sp)\n\t" 356 "lw $a2, 8($sp)\n\t" 357 "lw $t9, 12($sp)\n\t" 358 "lw $s1, 16($sp)\n\t" 359 "lw $t7, 20($sp)\n\t" 360 "addiu $sp, $sp, 24\n\t" 361 362 "jalr $t9\n\t" // Call the stub. 363 "nop\n\t" 364 "addiu $sp, $sp, 16\n\t" // Drop the quick "frame". 365 366 // Restore stuff not named clobbered. 367 "lw $a0, 0($sp)\n\t" 368 "lw $a1, 4($sp)\n\t" 369 "lw $a2, 8($sp)\n\t" 370 "lw $a3, 12($sp)\n\t" 371 "lw $t0, 16($sp)\n\t" 372 "lw $t1, 20($sp)\n\t" 373 "lw $t2, 24($sp)\n\t" 374 "lw $t3, 28($sp)\n\t" 375 "lw $t4, 32($sp)\n\t" 376 "lw $t5, 36($sp)\n\t" 377 "lw $t6, 40($sp)\n\t" 378 "lw $t7, 44($sp)\n\t" 379 // Restore gp. 380 "lw $gp, 52($sp)\n\t" 381 "addiu $sp, $sp, 64\n\t" // Free stack space, now sp as on entry. 382 383 "move %[result], $v0\n\t" // Store the call result. 384 : [result] "=r" (result) 385 : [arg0] "r"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self), 386 [referrer] "r"(referrer), [hidden] "r"(hidden) 387 : "at", "v0", "v1", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", 388 "fp", "ra", 389 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", 390 "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", 391 "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", 392 "memory"); // clobber. 393 #elif defined(__mips__) && defined(__LP64__) 394 __asm__ __volatile__ ( 395 // Spill a0-a7 which we say we don't clobber. May contain args. 396 "daddiu $sp, $sp, -64\n\t" 397 "sd $a0, 0($sp)\n\t" 398 "sd $a1, 8($sp)\n\t" 399 "sd $a2, 16($sp)\n\t" 400 "sd $a3, 24($sp)\n\t" 401 "sd $a4, 32($sp)\n\t" 402 "sd $a5, 40($sp)\n\t" 403 "sd $a6, 48($sp)\n\t" 404 "sd $a7, 56($sp)\n\t" 405 406 "daddiu $sp, $sp, -16\n\t" // Reserve stack space, 16B aligned. 407 "sd %[referrer], 0($sp)\n\t" 408 409 // Push everything on the stack, so we don't rely on the order. 410 "daddiu $sp, $sp, -48\n\t" 411 "sd %[arg0], 0($sp)\n\t" 412 "sd %[arg1], 8($sp)\n\t" 413 "sd %[arg2], 16($sp)\n\t" 414 "sd %[code], 24($sp)\n\t" 415 "sd %[self], 32($sp)\n\t" 416 "sd %[hidden], 40($sp)\n\t" 417 418 // Load call params into the right registers. 419 "ld $a0, 0($sp)\n\t" 420 "ld $a1, 8($sp)\n\t" 421 "ld $a2, 16($sp)\n\t" 422 "ld $t9, 24($sp)\n\t" 423 "ld $s1, 32($sp)\n\t" 424 "ld $t0, 40($sp)\n\t" 425 "daddiu $sp, $sp, 48\n\t" 426 427 "jalr $t9\n\t" // Call the stub. 428 "nop\n\t" 429 "daddiu $sp, $sp, 16\n\t" // Drop the quick "frame". 430 431 // Restore stuff not named clobbered. 432 "ld $a0, 0($sp)\n\t" 433 "ld $a1, 8($sp)\n\t" 434 "ld $a2, 16($sp)\n\t" 435 "ld $a3, 24($sp)\n\t" 436 "ld $a4, 32($sp)\n\t" 437 "ld $a5, 40($sp)\n\t" 438 "ld $a6, 48($sp)\n\t" 439 "ld $a7, 56($sp)\n\t" 440 "daddiu $sp, $sp, 64\n\t" 441 442 "move %[result], $v0\n\t" // Store the call result. 443 : [result] "=r" (result) 444 : [arg0] "r"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self), 445 [referrer] "r"(referrer), [hidden] "r"(hidden) 446 // Instead aliases t0-t3, register names $12-$15 has been used in the clobber list because 447 // t0-t3 are ambiguous. 448 : "at", "v0", "v1", "$12", "$13", "$14", "$15", "s0", "s1", "s2", "s3", "s4", "s5", "s6", 449 "s7", "t8", "t9", "k0", "k1", "fp", "ra", 450 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", 451 "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", 452 "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", 453 "memory"); // clobber. 454 #elif defined(__x86_64__) && !defined(__APPLE__) 455 #define PUSH(reg) "pushq " # reg "\n\t .cfi_adjust_cfa_offset 8\n\t" 456 #define POP(reg) "popq " # reg "\n\t .cfi_adjust_cfa_offset -8\n\t" 457 // Note: Uses the native convention. We do a callee-save regimen by manually spilling and 458 // restoring almost all registers. 459 // TODO: Set the thread? 460 __asm__ __volatile__( 461 // Spill almost everything (except rax, rsp). 14 registers. 462 PUSH(%%rbx) 463 PUSH(%%rcx) 464 PUSH(%%rdx) 465 PUSH(%%rsi) 466 PUSH(%%rdi) 467 PUSH(%%rbp) 468 PUSH(%%r8) 469 PUSH(%%r9) 470 PUSH(%%r10) 471 PUSH(%%r11) 472 PUSH(%%r12) 473 PUSH(%%r13) 474 PUSH(%%r14) 475 PUSH(%%r15) 476 477 PUSH(%[referrer]) // Push referrer & 16B alignment padding 478 PUSH(%[referrer]) 479 480 // Now juggle the input registers. 481 PUSH(%[arg0]) 482 PUSH(%[arg1]) 483 PUSH(%[arg2]) 484 PUSH(%[hidden]) 485 PUSH(%[code]) 486 POP(%%r8) 487 POP(%%rax) 488 POP(%%rdx) 489 POP(%%rsi) 490 POP(%%rdi) 491 492 "call *%%r8\n\t" // Call the stub 493 "addq $16, %%rsp\n\t" // Pop null and padding 494 ".cfi_adjust_cfa_offset -16\n\t" 495 496 POP(%%r15) 497 POP(%%r14) 498 POP(%%r13) 499 POP(%%r12) 500 POP(%%r11) 501 POP(%%r10) 502 POP(%%r9) 503 POP(%%r8) 504 POP(%%rbp) 505 POP(%%rdi) 506 POP(%%rsi) 507 POP(%%rdx) 508 POP(%%rcx) 509 POP(%%rbx) 510 511 : "=a" (result) 512 // Use the result from rax 513 : [arg0] "r"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), 514 [referrer] "r"(referrer), [hidden] "r"(hidden) 515 // This places arg0 into rdi, arg1 into rsi, arg2 into rdx, and code into some other 516 // register. We can't use "b" (rbx), as ASAN uses this for the frame pointer. 517 : "memory"); // We spill and restore (almost) all registers, so only mention memory here. 518 #undef PUSH 519 #undef POP 520 #else 521 UNUSED(arg0, arg1, arg2, code, referrer, hidden); 522 LOG(WARNING) << "Was asked to invoke for an architecture I do not understand."; 523 result = 0; 524 #endif 525 // Pop transition. 526 self->PopManagedStackFragment(fragment); 527 528 fp_result = fpr_result; 529 EXPECT_EQ(0U, fp_result); 530 531 return result; 532 } 533 534 static uintptr_t GetEntrypoint(Thread* self, QuickEntrypointEnum entrypoint) { 535 int32_t offset; 536 offset = GetThreadOffset<kRuntimePointerSize>(entrypoint).Int32Value(); 537 return *reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(self) + offset); 538 } 539 540 protected: 541 size_t fp_result; 542 }; 543 544 545 TEST_F(StubTest, Memcpy) { 546 #if defined(__i386__) || (defined(__x86_64__) && !defined(__APPLE__)) || defined(__mips__) 547 Thread* self = Thread::Current(); 548 549 uint32_t orig[20]; 550 uint32_t trg[20]; 551 for (size_t i = 0; i < 20; ++i) { 552 orig[i] = i; 553 trg[i] = 0; 554 } 555 556 Invoke3(reinterpret_cast<size_t>(&trg[4]), reinterpret_cast<size_t>(&orig[4]), 557 10 * sizeof(uint32_t), StubTest::GetEntrypoint(self, kQuickMemcpy), self); 558 559 EXPECT_EQ(orig[0], trg[0]); 560 561 for (size_t i = 1; i < 4; ++i) { 562 EXPECT_NE(orig[i], trg[i]); 563 } 564 565 for (size_t i = 4; i < 14; ++i) { 566 EXPECT_EQ(orig[i], trg[i]); 567 } 568 569 for (size_t i = 14; i < 20; ++i) { 570 EXPECT_NE(orig[i], trg[i]); 571 } 572 573 // TODO: Test overlapping? 574 575 #else 576 LOG(INFO) << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA; 577 // Force-print to std::cout so it's also outside the logcat. 578 std::cout << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA << std::endl; 579 #endif 580 } 581 582 TEST_F(StubTest, LockObject) { 583 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 584 (defined(__x86_64__) && !defined(__APPLE__)) 585 static constexpr size_t kThinLockLoops = 100; 586 587 Thread* self = Thread::Current(); 588 589 const uintptr_t art_quick_lock_object = StubTest::GetEntrypoint(self, kQuickLockObject); 590 591 // Create an object 592 ScopedObjectAccess soa(self); 593 // garbage is created during ClassLinker::Init 594 595 StackHandleScope<2> hs(soa.Self()); 596 Handle<mirror::String> obj( 597 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"))); 598 LockWord lock = obj->GetLockWord(false); 599 LockWord::LockState old_state = lock.GetState(); 600 EXPECT_EQ(LockWord::LockState::kUnlocked, old_state); 601 602 Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_lock_object, self); 603 604 LockWord lock_after = obj->GetLockWord(false); 605 LockWord::LockState new_state = lock_after.GetState(); 606 EXPECT_EQ(LockWord::LockState::kThinLocked, new_state); 607 EXPECT_EQ(lock_after.ThinLockCount(), 0U); // Thin lock starts count at zero 608 609 for (size_t i = 1; i < kThinLockLoops; ++i) { 610 Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_lock_object, self); 611 612 // Check we're at lock count i 613 614 LockWord l_inc = obj->GetLockWord(false); 615 LockWord::LockState l_inc_state = l_inc.GetState(); 616 EXPECT_EQ(LockWord::LockState::kThinLocked, l_inc_state); 617 EXPECT_EQ(l_inc.ThinLockCount(), i); 618 } 619 620 // Force a fat lock by running identity hashcode to fill up lock word. 621 Handle<mirror::String> obj2(hs.NewHandle( 622 mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"))); 623 624 obj2->IdentityHashCode(); 625 626 Invoke3(reinterpret_cast<size_t>(obj2.Get()), 0U, 0U, art_quick_lock_object, self); 627 628 LockWord lock_after2 = obj2->GetLockWord(false); 629 LockWord::LockState new_state2 = lock_after2.GetState(); 630 EXPECT_EQ(LockWord::LockState::kFatLocked, new_state2); 631 EXPECT_NE(lock_after2.FatLockMonitor(), static_cast<Monitor*>(nullptr)); 632 633 // Test done. 634 #else 635 LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA; 636 // Force-print to std::cout so it's also outside the logcat. 637 std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl; 638 #endif 639 } 640 641 642 class RandGen { 643 public: 644 explicit RandGen(uint32_t seed) : val_(seed) {} 645 646 uint32_t next() { 647 val_ = val_ * 48271 % 2147483647 + 13; 648 return val_; 649 } 650 651 uint32_t val_; 652 }; 653 654 655 // NO_THREAD_SAFETY_ANALYSIS as we do not want to grab exclusive mutator lock for MonitorInfo. 656 static void TestUnlockObject(StubTest* test) NO_THREAD_SAFETY_ANALYSIS { 657 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 658 (defined(__x86_64__) && !defined(__APPLE__)) 659 static constexpr size_t kThinLockLoops = 100; 660 661 Thread* self = Thread::Current(); 662 663 const uintptr_t art_quick_lock_object = StubTest::GetEntrypoint(self, kQuickLockObject); 664 const uintptr_t art_quick_unlock_object = StubTest::GetEntrypoint(self, kQuickUnlockObject); 665 // Create an object 666 ScopedObjectAccess soa(self); 667 // garbage is created during ClassLinker::Init 668 static constexpr size_t kNumberOfLocks = 10; // Number of objects = lock 669 StackHandleScope<kNumberOfLocks + 1> hs(self); 670 Handle<mirror::String> obj( 671 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"))); 672 LockWord lock = obj->GetLockWord(false); 673 LockWord::LockState old_state = lock.GetState(); 674 EXPECT_EQ(LockWord::LockState::kUnlocked, old_state); 675 676 test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_unlock_object, self); 677 // This should be an illegal monitor state. 678 EXPECT_TRUE(self->IsExceptionPending()); 679 self->ClearException(); 680 681 LockWord lock_after = obj->GetLockWord(false); 682 LockWord::LockState new_state = lock_after.GetState(); 683 EXPECT_EQ(LockWord::LockState::kUnlocked, new_state); 684 685 test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_lock_object, self); 686 687 LockWord lock_after2 = obj->GetLockWord(false); 688 LockWord::LockState new_state2 = lock_after2.GetState(); 689 EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2); 690 691 test->Invoke3(reinterpret_cast<size_t>(obj.Get()), 0U, 0U, art_quick_unlock_object, self); 692 693 LockWord lock_after3 = obj->GetLockWord(false); 694 LockWord::LockState new_state3 = lock_after3.GetState(); 695 EXPECT_EQ(LockWord::LockState::kUnlocked, new_state3); 696 697 // Stress test: 698 // Keep a number of objects and their locks in flight. Randomly lock or unlock one of them in 699 // each step. 700 701 RandGen r(0x1234); 702 703 constexpr size_t kIterations = 10000; // Number of iterations 704 constexpr size_t kMoveToFat = 1000; // Chance of 1:kMoveFat to make a lock fat. 705 706 size_t counts[kNumberOfLocks]; 707 bool fat[kNumberOfLocks]; // Whether a lock should be thin or fat. 708 Handle<mirror::String> objects[kNumberOfLocks]; 709 710 // Initialize = allocate. 711 for (size_t i = 0; i < kNumberOfLocks; ++i) { 712 counts[i] = 0; 713 fat[i] = false; 714 objects[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "")); 715 } 716 717 for (size_t i = 0; i < kIterations; ++i) { 718 // Select which lock to update. 719 size_t index = r.next() % kNumberOfLocks; 720 721 // Make lock fat? 722 if (!fat[index] && (r.next() % kMoveToFat == 0)) { 723 fat[index] = true; 724 objects[index]->IdentityHashCode(); 725 726 LockWord lock_iter = objects[index]->GetLockWord(false); 727 LockWord::LockState iter_state = lock_iter.GetState(); 728 if (counts[index] == 0) { 729 EXPECT_EQ(LockWord::LockState::kHashCode, iter_state); 730 } else { 731 EXPECT_EQ(LockWord::LockState::kFatLocked, iter_state); 732 } 733 } else { 734 bool take_lock; // Whether to lock or unlock in this step. 735 if (counts[index] == 0) { 736 take_lock = true; 737 } else if (counts[index] == kThinLockLoops) { 738 take_lock = false; 739 } else { 740 // Randomly. 741 take_lock = r.next() % 2 == 0; 742 } 743 744 if (take_lock) { 745 test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U, art_quick_lock_object, 746 self); 747 counts[index]++; 748 } else { 749 test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U, 750 art_quick_unlock_object, self); 751 counts[index]--; 752 } 753 754 EXPECT_FALSE(self->IsExceptionPending()); 755 756 // Check the new state. 757 LockWord lock_iter = objects[index]->GetLockWord(true); 758 LockWord::LockState iter_state = lock_iter.GetState(); 759 if (fat[index]) { 760 // Abuse MonitorInfo. 761 EXPECT_EQ(LockWord::LockState::kFatLocked, iter_state) << index; 762 MonitorInfo info(objects[index].Get()); 763 EXPECT_EQ(counts[index], info.entry_count_) << index; 764 } else { 765 if (counts[index] > 0) { 766 EXPECT_EQ(LockWord::LockState::kThinLocked, iter_state); 767 EXPECT_EQ(counts[index] - 1, lock_iter.ThinLockCount()); 768 } else { 769 EXPECT_EQ(LockWord::LockState::kUnlocked, iter_state); 770 } 771 } 772 } 773 } 774 775 // Unlock the remaining count times and then check it's unlocked. Then deallocate. 776 // Go reverse order to correctly handle Handles. 777 for (size_t i = 0; i < kNumberOfLocks; ++i) { 778 size_t index = kNumberOfLocks - 1 - i; 779 size_t count = counts[index]; 780 while (count > 0) { 781 test->Invoke3(reinterpret_cast<size_t>(objects[index].Get()), 0U, 0U, art_quick_unlock_object, 782 self); 783 count--; 784 } 785 786 LockWord lock_after4 = objects[index]->GetLockWord(false); 787 LockWord::LockState new_state4 = lock_after4.GetState(); 788 EXPECT_TRUE(LockWord::LockState::kUnlocked == new_state4 789 || LockWord::LockState::kFatLocked == new_state4); 790 } 791 792 // Test done. 793 #else 794 UNUSED(test); 795 LOG(INFO) << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA; 796 // Force-print to std::cout so it's also outside the logcat. 797 std::cout << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA << std::endl; 798 #endif 799 } 800 801 TEST_F(StubTest, UnlockObject) { 802 // This will lead to monitor error messages in the log. 803 ScopedLogSeverity sls(LogSeverity::FATAL); 804 805 TestUnlockObject(this); 806 } 807 808 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 809 (defined(__x86_64__) && !defined(__APPLE__)) 810 extern "C" void art_quick_check_instance_of(void); 811 #endif 812 813 TEST_F(StubTest, CheckCast) { 814 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 815 (defined(__x86_64__) && !defined(__APPLE__)) 816 Thread* self = Thread::Current(); 817 818 const uintptr_t art_quick_check_instance_of = 819 StubTest::GetEntrypoint(self, kQuickCheckInstanceOf); 820 821 // Find some classes. 822 ScopedObjectAccess soa(self); 823 // garbage is created during ClassLinker::Init 824 825 VariableSizedHandleScope hs(soa.Self()); 826 Handle<mirror::Class> klass_obj( 827 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"))); 828 Handle<mirror::Class> klass_str( 829 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;"))); 830 Handle<mirror::Class> klass_list( 831 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/util/List;"))); 832 Handle<mirror::Class> klass_cloneable( 833 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Cloneable;"))); 834 Handle<mirror::Class> klass_array_list( 835 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/util/ArrayList;"))); 836 Handle<mirror::Object> obj(hs.NewHandle(klass_obj->AllocObject(soa.Self()))); 837 Handle<mirror::String> string(hs.NewHandle( 838 mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABCD"))); 839 Handle<mirror::Object> array_list(hs.NewHandle(klass_array_list->AllocObject(soa.Self()))); 840 841 EXPECT_FALSE(self->IsExceptionPending()); 842 843 Invoke3(reinterpret_cast<size_t>(obj.Get()), 844 reinterpret_cast<size_t>(klass_obj.Get()), 845 0U, 846 art_quick_check_instance_of, 847 self); 848 EXPECT_FALSE(self->IsExceptionPending()); 849 850 // Expected true: Test string instance of java.lang.String. 851 Invoke3(reinterpret_cast<size_t>(string.Get()), 852 reinterpret_cast<size_t>(klass_str.Get()), 853 0U, 854 art_quick_check_instance_of, 855 self); 856 EXPECT_FALSE(self->IsExceptionPending()); 857 858 // Expected true: Test string instance of java.lang.Object. 859 Invoke3(reinterpret_cast<size_t>(string.Get()), 860 reinterpret_cast<size_t>(klass_obj.Get()), 861 0U, 862 art_quick_check_instance_of, 863 self); 864 EXPECT_FALSE(self->IsExceptionPending()); 865 866 // Expected false: Test object instance of java.lang.String. 867 Invoke3(reinterpret_cast<size_t>(obj.Get()), 868 reinterpret_cast<size_t>(klass_str.Get()), 869 0U, 870 art_quick_check_instance_of, 871 self); 872 EXPECT_TRUE(self->IsExceptionPending()); 873 self->ClearException(); 874 875 Invoke3(reinterpret_cast<size_t>(array_list.Get()), 876 reinterpret_cast<size_t>(klass_list.Get()), 877 0U, 878 art_quick_check_instance_of, 879 self); 880 EXPECT_FALSE(self->IsExceptionPending()); 881 882 Invoke3(reinterpret_cast<size_t>(array_list.Get()), 883 reinterpret_cast<size_t>(klass_cloneable.Get()), 884 0U, 885 art_quick_check_instance_of, 886 self); 887 EXPECT_FALSE(self->IsExceptionPending()); 888 889 Invoke3(reinterpret_cast<size_t>(string.Get()), 890 reinterpret_cast<size_t>(klass_array_list.Get()), 891 0U, 892 art_quick_check_instance_of, 893 self); 894 EXPECT_TRUE(self->IsExceptionPending()); 895 self->ClearException(); 896 897 Invoke3(reinterpret_cast<size_t>(string.Get()), 898 reinterpret_cast<size_t>(klass_cloneable.Get()), 899 0U, 900 art_quick_check_instance_of, 901 self); 902 EXPECT_TRUE(self->IsExceptionPending()); 903 self->ClearException(); 904 905 #else 906 LOG(INFO) << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA; 907 // Force-print to std::cout so it's also outside the logcat. 908 std::cout << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA << std::endl; 909 #endif 910 } 911 912 TEST_F(StubTest, AllocObject) { 913 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 914 (defined(__x86_64__) && !defined(__APPLE__)) 915 // This will lead to OOM error messages in the log. 916 ScopedLogSeverity sls(LogSeverity::FATAL); 917 918 // TODO: Check the "Unresolved" allocation stubs 919 920 Thread* self = Thread::Current(); 921 // Create an object 922 ScopedObjectAccess soa(self); 923 // garbage is created during ClassLinker::Init 924 925 StackHandleScope<2> hs(soa.Self()); 926 Handle<mirror::Class> c( 927 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"))); 928 929 // Play with it... 930 931 EXPECT_FALSE(self->IsExceptionPending()); 932 { 933 size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U, 934 StubTest::GetEntrypoint(self, kQuickAllocObjectWithChecks), 935 self); 936 937 EXPECT_FALSE(self->IsExceptionPending()); 938 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result); 939 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result); 940 EXPECT_EQ(c.Get(), obj->GetClass()); 941 VerifyObject(obj); 942 } 943 944 { 945 size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U, 946 StubTest::GetEntrypoint(self, kQuickAllocObjectResolved), 947 self); 948 949 EXPECT_FALSE(self->IsExceptionPending()); 950 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result); 951 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result); 952 EXPECT_EQ(c.Get(), obj->GetClass()); 953 VerifyObject(obj); 954 } 955 956 { 957 size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U, 958 StubTest::GetEntrypoint(self, kQuickAllocObjectInitialized), 959 self); 960 961 EXPECT_FALSE(self->IsExceptionPending()); 962 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result); 963 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result); 964 EXPECT_EQ(c.Get(), obj->GetClass()); 965 VerifyObject(obj); 966 } 967 968 // Failure tests. 969 970 // Out-of-memory. 971 { 972 Runtime::Current()->GetHeap()->SetIdealFootprint(1 * GB); 973 974 // Array helps to fill memory faster. 975 Handle<mirror::Class> ca( 976 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;"))); 977 978 // Use arbitrary large amount for now. 979 static const size_t kMaxHandles = 1000000; 980 std::unique_ptr<StackHandleScope<kMaxHandles>> hsp(new StackHandleScope<kMaxHandles>(self)); 981 982 std::vector<Handle<mirror::Object>> handles; 983 // Start allocating with 128K 984 size_t length = 128 * KB / 4; 985 while (length > 10) { 986 Handle<mirror::Object> h(hsp->NewHandle<mirror::Object>( 987 mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.Get(), length / 4))); 988 if (self->IsExceptionPending() || h == nullptr) { 989 self->ClearException(); 990 991 // Try a smaller length 992 length = length / 8; 993 // Use at most half the reported free space. 994 size_t mem = Runtime::Current()->GetHeap()->GetFreeMemory(); 995 if (length * 8 > mem) { 996 length = mem / 8; 997 } 998 } else { 999 handles.push_back(h); 1000 } 1001 } 1002 LOG(INFO) << "Used " << handles.size() << " arrays to fill space."; 1003 1004 // Allocate simple objects till it fails. 1005 while (!self->IsExceptionPending()) { 1006 Handle<mirror::Object> h = hsp->NewHandle(c->AllocObject(soa.Self())); 1007 if (!self->IsExceptionPending() && h != nullptr) { 1008 handles.push_back(h); 1009 } 1010 } 1011 self->ClearException(); 1012 1013 size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 0u, 0U, 1014 StubTest::GetEntrypoint(self, kQuickAllocObjectInitialized), 1015 self); 1016 EXPECT_TRUE(self->IsExceptionPending()); 1017 self->ClearException(); 1018 EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result); 1019 } 1020 1021 // Tests done. 1022 #else 1023 LOG(INFO) << "Skipping alloc_object as I don't know how to do that on " << kRuntimeISA; 1024 // Force-print to std::cout so it's also outside the logcat. 1025 std::cout << "Skipping alloc_object as I don't know how to do that on " << kRuntimeISA << std::endl; 1026 #endif 1027 } 1028 1029 TEST_F(StubTest, AllocObjectArray) { 1030 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1031 (defined(__x86_64__) && !defined(__APPLE__)) 1032 // TODO: Check the "Unresolved" allocation stubs 1033 1034 // This will lead to OOM error messages in the log. 1035 ScopedLogSeverity sls(LogSeverity::FATAL); 1036 1037 Thread* self = Thread::Current(); 1038 // Create an object 1039 ScopedObjectAccess soa(self); 1040 // garbage is created during ClassLinker::Init 1041 1042 StackHandleScope<1> hs(self); 1043 Handle<mirror::Class> c( 1044 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;"))); 1045 1046 // Play with it... 1047 1048 EXPECT_FALSE(self->IsExceptionPending()); 1049 1050 { 1051 // We can use null in the second argument as we do not need a method here (not used in 1052 // resolved/initialized cases) 1053 size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 10U, 1054 reinterpret_cast<size_t>(nullptr), 1055 StubTest::GetEntrypoint(self, kQuickAllocArrayResolved32), 1056 self); 1057 EXPECT_FALSE(self->IsExceptionPending()) << mirror::Object::PrettyTypeOf(self->GetException()); 1058 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result); 1059 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result); 1060 EXPECT_TRUE(obj->IsArrayInstance()); 1061 EXPECT_TRUE(obj->IsObjectArray()); 1062 EXPECT_EQ(c.Get(), obj->GetClass()); 1063 VerifyObject(obj); 1064 mirror::Array* array = reinterpret_cast<mirror::Array*>(result); 1065 EXPECT_EQ(array->GetLength(), 10); 1066 } 1067 1068 // Failure tests. 1069 1070 // Out-of-memory. 1071 { 1072 size_t result = Invoke3(reinterpret_cast<size_t>(c.Get()), 1073 GB, // that should fail... 1074 reinterpret_cast<size_t>(nullptr), 1075 StubTest::GetEntrypoint(self, kQuickAllocArrayResolved32), 1076 self); 1077 1078 EXPECT_TRUE(self->IsExceptionPending()); 1079 self->ClearException(); 1080 EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result); 1081 } 1082 1083 // Tests done. 1084 #else 1085 LOG(INFO) << "Skipping alloc_array as I don't know how to do that on " << kRuntimeISA; 1086 // Force-print to std::cout so it's also outside the logcat. 1087 std::cout << "Skipping alloc_array as I don't know how to do that on " << kRuntimeISA << std::endl; 1088 #endif 1089 } 1090 1091 1092 TEST_F(StubTest, StringCompareTo) { 1093 TEST_DISABLED_FOR_STRING_COMPRESSION(); 1094 // There is no StringCompareTo runtime entrypoint for __arm__ or __aarch64__. 1095 #if defined(__i386__) || defined(__mips__) || \ 1096 (defined(__x86_64__) && !defined(__APPLE__)) 1097 // TODO: Check the "Unresolved" allocation stubs 1098 1099 Thread* self = Thread::Current(); 1100 1101 const uintptr_t art_quick_string_compareto = StubTest::GetEntrypoint(self, kQuickStringCompareTo); 1102 1103 ScopedObjectAccess soa(self); 1104 // garbage is created during ClassLinker::Init 1105 1106 // Create some strings 1107 // Use array so we can index into it and use a matrix for expected results 1108 // Setup: The first half is standard. The second half uses a non-zero offset. 1109 // TODO: Shared backing arrays. 1110 const char* c[] = { "", "", "a", "aa", "ab", 1111 "aacaacaacaacaacaac", // This one's under the default limit to go to __memcmp16. 1112 "aacaacaacaacaacaacaacaacaacaacaacaac", // This one's over. 1113 "aacaacaacaacaacaacaacaacaacaacaacaaca" }; // As is this one. We need a separate one to 1114 // defeat object-equal optimizations. 1115 static constexpr size_t kStringCount = arraysize(c); 1116 1117 StackHandleScope<kStringCount> hs(self); 1118 Handle<mirror::String> s[kStringCount]; 1119 1120 for (size_t i = 0; i < kStringCount; ++i) { 1121 s[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), c[i])); 1122 } 1123 1124 // TODO: wide characters 1125 1126 // Matrix of expectations. First component is first parameter. Note we only check against the 1127 // sign, not the value. As we are testing random offsets, we need to compute this and need to 1128 // rely on String::CompareTo being correct. 1129 int32_t expected[kStringCount][kStringCount]; 1130 for (size_t x = 0; x < kStringCount; ++x) { 1131 for (size_t y = 0; y < kStringCount; ++y) { 1132 expected[x][y] = s[x]->CompareTo(s[y].Get()); 1133 } 1134 } 1135 1136 // Play with it... 1137 1138 for (size_t x = 0; x < kStringCount; ++x) { 1139 for (size_t y = 0; y < kStringCount; ++y) { 1140 // Test string_compareto x y 1141 size_t result = Invoke3(reinterpret_cast<size_t>(s[x].Get()), 1142 reinterpret_cast<size_t>(s[y].Get()), 0U, 1143 art_quick_string_compareto, self); 1144 1145 EXPECT_FALSE(self->IsExceptionPending()); 1146 1147 // The result is a 32b signed integer 1148 union { 1149 size_t r; 1150 int32_t i; 1151 } conv; 1152 conv.r = result; 1153 int32_t e = expected[x][y]; 1154 EXPECT_TRUE(e == 0 ? conv.i == 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" << 1155 conv.r; 1156 EXPECT_TRUE(e < 0 ? conv.i < 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" << 1157 conv.r; 1158 EXPECT_TRUE(e > 0 ? conv.i > 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" << 1159 conv.r; 1160 } 1161 } 1162 1163 // TODO: Deallocate things. 1164 1165 // Tests done. 1166 #else 1167 LOG(INFO) << "Skipping string_compareto as I don't know how to do that on " << kRuntimeISA; 1168 // Force-print to std::cout so it's also outside the logcat. 1169 std::cout << "Skipping string_compareto as I don't know how to do that on " << kRuntimeISA << 1170 std::endl; 1171 #endif 1172 } 1173 1174 1175 static void GetSetBooleanStatic(ArtField* f, Thread* self, 1176 ArtMethod* referrer, StubTest* test) 1177 REQUIRES_SHARED(Locks::mutator_lock_) { 1178 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1179 (defined(__x86_64__) && !defined(__APPLE__)) 1180 constexpr size_t num_values = 5; 1181 uint8_t values[num_values] = { 0, 1, 2, 128, 0xFF }; 1182 1183 for (size_t i = 0; i < num_values; ++i) { 1184 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1185 static_cast<size_t>(values[i]), 1186 0U, 1187 StubTest::GetEntrypoint(self, kQuickSet8Static), 1188 self, 1189 referrer); 1190 1191 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1192 0U, 0U, 1193 StubTest::GetEntrypoint(self, kQuickGetBooleanStatic), 1194 self, 1195 referrer); 1196 // Boolean currently stores bools as uint8_t, be more zealous about asserting correct writes/gets. 1197 EXPECT_EQ(values[i], static_cast<uint8_t>(res)) << "Iteration " << i; 1198 } 1199 #else 1200 UNUSED(f, self, referrer, test); 1201 LOG(INFO) << "Skipping set_boolean_static as I don't know how to do that on " << kRuntimeISA; 1202 // Force-print to std::cout so it's also outside the logcat. 1203 std::cout << "Skipping set_boolean_static as I don't know how to do that on " << kRuntimeISA << std::endl; 1204 #endif 1205 } 1206 static void GetSetByteStatic(ArtField* f, Thread* self, ArtMethod* referrer, 1207 StubTest* test) 1208 REQUIRES_SHARED(Locks::mutator_lock_) { 1209 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1210 (defined(__x86_64__) && !defined(__APPLE__)) 1211 int8_t values[] = { -128, -64, 0, 64, 127 }; 1212 1213 for (size_t i = 0; i < arraysize(values); ++i) { 1214 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1215 static_cast<size_t>(values[i]), 1216 0U, 1217 StubTest::GetEntrypoint(self, kQuickSet8Static), 1218 self, 1219 referrer); 1220 1221 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1222 0U, 0U, 1223 StubTest::GetEntrypoint(self, kQuickGetByteStatic), 1224 self, 1225 referrer); 1226 EXPECT_EQ(values[i], static_cast<int8_t>(res)) << "Iteration " << i; 1227 } 1228 #else 1229 UNUSED(f, self, referrer, test); 1230 LOG(INFO) << "Skipping set_byte_static as I don't know how to do that on " << kRuntimeISA; 1231 // Force-print to std::cout so it's also outside the logcat. 1232 std::cout << "Skipping set_byte_static as I don't know how to do that on " << kRuntimeISA << std::endl; 1233 #endif 1234 } 1235 1236 1237 static void GetSetBooleanInstance(Handle<mirror::Object>* obj, ArtField* f, Thread* self, 1238 ArtMethod* referrer, StubTest* test) 1239 REQUIRES_SHARED(Locks::mutator_lock_) { 1240 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1241 (defined(__x86_64__) && !defined(__APPLE__)) 1242 uint8_t values[] = { 0, true, 2, 128, 0xFF }; 1243 1244 for (size_t i = 0; i < arraysize(values); ++i) { 1245 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1246 reinterpret_cast<size_t>(obj->Get()), 1247 static_cast<size_t>(values[i]), 1248 StubTest::GetEntrypoint(self, kQuickSet8Instance), 1249 self, 1250 referrer); 1251 1252 uint8_t res = f->GetBoolean(obj->Get()); 1253 EXPECT_EQ(values[i], res) << "Iteration " << i; 1254 1255 f->SetBoolean<false>(obj->Get(), res); 1256 1257 size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1258 reinterpret_cast<size_t>(obj->Get()), 1259 0U, 1260 StubTest::GetEntrypoint(self, kQuickGetBooleanInstance), 1261 self, 1262 referrer); 1263 EXPECT_EQ(res, static_cast<uint8_t>(res2)); 1264 } 1265 #else 1266 UNUSED(obj, f, self, referrer, test); 1267 LOG(INFO) << "Skipping set_boolean_instance as I don't know how to do that on " << kRuntimeISA; 1268 // Force-print to std::cout so it's also outside the logcat. 1269 std::cout << "Skipping set_boolean_instance as I don't know how to do that on " << kRuntimeISA << std::endl; 1270 #endif 1271 } 1272 static void GetSetByteInstance(Handle<mirror::Object>* obj, ArtField* f, 1273 Thread* self, ArtMethod* referrer, StubTest* test) 1274 REQUIRES_SHARED(Locks::mutator_lock_) { 1275 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1276 (defined(__x86_64__) && !defined(__APPLE__)) 1277 int8_t values[] = { -128, -64, 0, 64, 127 }; 1278 1279 for (size_t i = 0; i < arraysize(values); ++i) { 1280 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1281 reinterpret_cast<size_t>(obj->Get()), 1282 static_cast<size_t>(values[i]), 1283 StubTest::GetEntrypoint(self, kQuickSet8Instance), 1284 self, 1285 referrer); 1286 1287 int8_t res = f->GetByte(obj->Get()); 1288 EXPECT_EQ(res, values[i]) << "Iteration " << i; 1289 f->SetByte<false>(obj->Get(), ++res); 1290 1291 size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1292 reinterpret_cast<size_t>(obj->Get()), 1293 0U, 1294 StubTest::GetEntrypoint(self, kQuickGetByteInstance), 1295 self, 1296 referrer); 1297 EXPECT_EQ(res, static_cast<int8_t>(res2)); 1298 } 1299 #else 1300 UNUSED(obj, f, self, referrer, test); 1301 LOG(INFO) << "Skipping set_byte_instance as I don't know how to do that on " << kRuntimeISA; 1302 // Force-print to std::cout so it's also outside the logcat. 1303 std::cout << "Skipping set_byte_instance as I don't know how to do that on " << kRuntimeISA << std::endl; 1304 #endif 1305 } 1306 1307 static void GetSetCharStatic(ArtField* f, Thread* self, ArtMethod* referrer, 1308 StubTest* test) 1309 REQUIRES_SHARED(Locks::mutator_lock_) { 1310 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1311 (defined(__x86_64__) && !defined(__APPLE__)) 1312 uint16_t values[] = { 0, 1, 2, 255, 32768, 0xFFFF }; 1313 1314 for (size_t i = 0; i < arraysize(values); ++i) { 1315 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1316 static_cast<size_t>(values[i]), 1317 0U, 1318 StubTest::GetEntrypoint(self, kQuickSet16Static), 1319 self, 1320 referrer); 1321 1322 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1323 0U, 0U, 1324 StubTest::GetEntrypoint(self, kQuickGetCharStatic), 1325 self, 1326 referrer); 1327 1328 EXPECT_EQ(values[i], static_cast<uint16_t>(res)) << "Iteration " << i; 1329 } 1330 #else 1331 UNUSED(f, self, referrer, test); 1332 LOG(INFO) << "Skipping set_char_static as I don't know how to do that on " << kRuntimeISA; 1333 // Force-print to std::cout so it's also outside the logcat. 1334 std::cout << "Skipping set_char_static as I don't know how to do that on " << kRuntimeISA << std::endl; 1335 #endif 1336 } 1337 static void GetSetShortStatic(ArtField* f, Thread* self, 1338 ArtMethod* referrer, StubTest* test) 1339 REQUIRES_SHARED(Locks::mutator_lock_) { 1340 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1341 (defined(__x86_64__) && !defined(__APPLE__)) 1342 int16_t values[] = { -0x7FFF, -32768, 0, 255, 32767, 0x7FFE }; 1343 1344 for (size_t i = 0; i < arraysize(values); ++i) { 1345 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1346 static_cast<size_t>(values[i]), 1347 0U, 1348 StubTest::GetEntrypoint(self, kQuickSet16Static), 1349 self, 1350 referrer); 1351 1352 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1353 0U, 0U, 1354 StubTest::GetEntrypoint(self, kQuickGetShortStatic), 1355 self, 1356 referrer); 1357 1358 EXPECT_EQ(static_cast<int16_t>(res), values[i]) << "Iteration " << i; 1359 } 1360 #else 1361 UNUSED(f, self, referrer, test); 1362 LOG(INFO) << "Skipping set_short_static as I don't know how to do that on " << kRuntimeISA; 1363 // Force-print to std::cout so it's also outside the logcat. 1364 std::cout << "Skipping set_short_static as I don't know how to do that on " << kRuntimeISA << std::endl; 1365 #endif 1366 } 1367 1368 static void GetSetCharInstance(Handle<mirror::Object>* obj, ArtField* f, 1369 Thread* self, ArtMethod* referrer, StubTest* test) 1370 REQUIRES_SHARED(Locks::mutator_lock_) { 1371 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1372 (defined(__x86_64__) && !defined(__APPLE__)) 1373 uint16_t values[] = { 0, 1, 2, 255, 32768, 0xFFFF }; 1374 1375 for (size_t i = 0; i < arraysize(values); ++i) { 1376 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1377 reinterpret_cast<size_t>(obj->Get()), 1378 static_cast<size_t>(values[i]), 1379 StubTest::GetEntrypoint(self, kQuickSet16Instance), 1380 self, 1381 referrer); 1382 1383 uint16_t res = f->GetChar(obj->Get()); 1384 EXPECT_EQ(res, values[i]) << "Iteration " << i; 1385 f->SetChar<false>(obj->Get(), ++res); 1386 1387 size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1388 reinterpret_cast<size_t>(obj->Get()), 1389 0U, 1390 StubTest::GetEntrypoint(self, kQuickGetCharInstance), 1391 self, 1392 referrer); 1393 EXPECT_EQ(res, static_cast<uint16_t>(res2)); 1394 } 1395 #else 1396 UNUSED(obj, f, self, referrer, test); 1397 LOG(INFO) << "Skipping set_char_instance as I don't know how to do that on " << kRuntimeISA; 1398 // Force-print to std::cout so it's also outside the logcat. 1399 std::cout << "Skipping set_char_instance as I don't know how to do that on " << kRuntimeISA << std::endl; 1400 #endif 1401 } 1402 static void GetSetShortInstance(Handle<mirror::Object>* obj, ArtField* f, 1403 Thread* self, ArtMethod* referrer, StubTest* test) 1404 REQUIRES_SHARED(Locks::mutator_lock_) { 1405 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1406 (defined(__x86_64__) && !defined(__APPLE__)) 1407 int16_t values[] = { -0x7FFF, -32768, 0, 255, 32767, 0x7FFE }; 1408 1409 for (size_t i = 0; i < arraysize(values); ++i) { 1410 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1411 reinterpret_cast<size_t>(obj->Get()), 1412 static_cast<size_t>(values[i]), 1413 StubTest::GetEntrypoint(self, kQuickSet16Instance), 1414 self, 1415 referrer); 1416 1417 int16_t res = f->GetShort(obj->Get()); 1418 EXPECT_EQ(res, values[i]) << "Iteration " << i; 1419 f->SetShort<false>(obj->Get(), ++res); 1420 1421 size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1422 reinterpret_cast<size_t>(obj->Get()), 1423 0U, 1424 StubTest::GetEntrypoint(self, kQuickGetShortInstance), 1425 self, 1426 referrer); 1427 EXPECT_EQ(res, static_cast<int16_t>(res2)); 1428 } 1429 #else 1430 UNUSED(obj, f, self, referrer, test); 1431 LOG(INFO) << "Skipping set_short_instance as I don't know how to do that on " << kRuntimeISA; 1432 // Force-print to std::cout so it's also outside the logcat. 1433 std::cout << "Skipping set_short_instance as I don't know how to do that on " << kRuntimeISA << std::endl; 1434 #endif 1435 } 1436 1437 static void GetSet32Static(ArtField* f, Thread* self, ArtMethod* referrer, 1438 StubTest* test) 1439 REQUIRES_SHARED(Locks::mutator_lock_) { 1440 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1441 (defined(__x86_64__) && !defined(__APPLE__)) 1442 uint32_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF }; 1443 1444 for (size_t i = 0; i < arraysize(values); ++i) { 1445 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1446 static_cast<size_t>(values[i]), 1447 0U, 1448 StubTest::GetEntrypoint(self, kQuickSet32Static), 1449 self, 1450 referrer); 1451 1452 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1453 0U, 0U, 1454 StubTest::GetEntrypoint(self, kQuickGet32Static), 1455 self, 1456 referrer); 1457 1458 #if defined(__mips__) && defined(__LP64__) 1459 EXPECT_EQ(static_cast<uint32_t>(res), values[i]) << "Iteration " << i; 1460 #else 1461 EXPECT_EQ(res, values[i]) << "Iteration " << i; 1462 #endif 1463 } 1464 #else 1465 UNUSED(f, self, referrer, test); 1466 LOG(INFO) << "Skipping set32static as I don't know how to do that on " << kRuntimeISA; 1467 // Force-print to std::cout so it's also outside the logcat. 1468 std::cout << "Skipping set32static as I don't know how to do that on " << kRuntimeISA << std::endl; 1469 #endif 1470 } 1471 1472 1473 static void GetSet32Instance(Handle<mirror::Object>* obj, ArtField* f, 1474 Thread* self, ArtMethod* referrer, StubTest* test) 1475 REQUIRES_SHARED(Locks::mutator_lock_) { 1476 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1477 (defined(__x86_64__) && !defined(__APPLE__)) 1478 uint32_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF }; 1479 1480 for (size_t i = 0; i < arraysize(values); ++i) { 1481 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1482 reinterpret_cast<size_t>(obj->Get()), 1483 static_cast<size_t>(values[i]), 1484 StubTest::GetEntrypoint(self, kQuickSet32Instance), 1485 self, 1486 referrer); 1487 1488 int32_t res = f->GetInt(obj->Get()); 1489 EXPECT_EQ(res, static_cast<int32_t>(values[i])) << "Iteration " << i; 1490 1491 res++; 1492 f->SetInt<false>(obj->Get(), res); 1493 1494 size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1495 reinterpret_cast<size_t>(obj->Get()), 1496 0U, 1497 StubTest::GetEntrypoint(self, kQuickGet32Instance), 1498 self, 1499 referrer); 1500 EXPECT_EQ(res, static_cast<int32_t>(res2)); 1501 } 1502 #else 1503 UNUSED(obj, f, self, referrer, test); 1504 LOG(INFO) << "Skipping set32instance as I don't know how to do that on " << kRuntimeISA; 1505 // Force-print to std::cout so it's also outside the logcat. 1506 std::cout << "Skipping set32instance as I don't know how to do that on " << kRuntimeISA << std::endl; 1507 #endif 1508 } 1509 1510 1511 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1512 (defined(__x86_64__) && !defined(__APPLE__)) 1513 1514 static void set_and_check_static(uint32_t f_idx, mirror::Object* val, Thread* self, 1515 ArtMethod* referrer, StubTest* test) 1516 REQUIRES_SHARED(Locks::mutator_lock_) { 1517 test->Invoke3WithReferrer(static_cast<size_t>(f_idx), 1518 reinterpret_cast<size_t>(val), 1519 0U, 1520 StubTest::GetEntrypoint(self, kQuickSetObjStatic), 1521 self, 1522 referrer); 1523 1524 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f_idx), 1525 0U, 0U, 1526 StubTest::GetEntrypoint(self, kQuickGetObjStatic), 1527 self, 1528 referrer); 1529 1530 EXPECT_EQ(res, reinterpret_cast<size_t>(val)) << "Value " << val; 1531 } 1532 #endif 1533 1534 static void GetSetObjStatic(ArtField* f, Thread* self, ArtMethod* referrer, 1535 StubTest* test) 1536 REQUIRES_SHARED(Locks::mutator_lock_) { 1537 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1538 (defined(__x86_64__) && !defined(__APPLE__)) 1539 set_and_check_static(f->GetDexFieldIndex(), nullptr, self, referrer, test); 1540 1541 // Allocate a string object for simplicity. 1542 mirror::String* str = mirror::String::AllocFromModifiedUtf8(self, "Test"); 1543 set_and_check_static(f->GetDexFieldIndex(), str, self, referrer, test); 1544 1545 set_and_check_static(f->GetDexFieldIndex(), nullptr, self, referrer, test); 1546 #else 1547 UNUSED(f, self, referrer, test); 1548 LOG(INFO) << "Skipping setObjstatic as I don't know how to do that on " << kRuntimeISA; 1549 // Force-print to std::cout so it's also outside the logcat. 1550 std::cout << "Skipping setObjstatic as I don't know how to do that on " << kRuntimeISA << std::endl; 1551 #endif 1552 } 1553 1554 1555 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1556 (defined(__x86_64__) && !defined(__APPLE__)) 1557 static void set_and_check_instance(ArtField* f, mirror::Object* trg, 1558 mirror::Object* val, Thread* self, ArtMethod* referrer, 1559 StubTest* test) 1560 REQUIRES_SHARED(Locks::mutator_lock_) { 1561 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1562 reinterpret_cast<size_t>(trg), 1563 reinterpret_cast<size_t>(val), 1564 StubTest::GetEntrypoint(self, kQuickSetObjInstance), 1565 self, 1566 referrer); 1567 1568 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1569 reinterpret_cast<size_t>(trg), 1570 0U, 1571 StubTest::GetEntrypoint(self, kQuickGetObjInstance), 1572 self, 1573 referrer); 1574 1575 EXPECT_EQ(res, reinterpret_cast<size_t>(val)) << "Value " << val; 1576 1577 EXPECT_OBJ_PTR_EQ(val, f->GetObj(trg)); 1578 } 1579 #endif 1580 1581 static void GetSetObjInstance(Handle<mirror::Object>* obj, ArtField* f, 1582 Thread* self, ArtMethod* referrer, StubTest* test) 1583 REQUIRES_SHARED(Locks::mutator_lock_) { 1584 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1585 (defined(__x86_64__) && !defined(__APPLE__)) 1586 set_and_check_instance(f, obj->Get(), nullptr, self, referrer, test); 1587 1588 // Allocate a string object for simplicity. 1589 mirror::String* str = mirror::String::AllocFromModifiedUtf8(self, "Test"); 1590 set_and_check_instance(f, obj->Get(), str, self, referrer, test); 1591 1592 set_and_check_instance(f, obj->Get(), nullptr, self, referrer, test); 1593 #else 1594 UNUSED(obj, f, self, referrer, test); 1595 LOG(INFO) << "Skipping setObjinstance as I don't know how to do that on " << kRuntimeISA; 1596 // Force-print to std::cout so it's also outside the logcat. 1597 std::cout << "Skipping setObjinstance as I don't know how to do that on " << kRuntimeISA << std::endl; 1598 #endif 1599 } 1600 1601 1602 // TODO: Complete these tests for 32b architectures 1603 1604 static void GetSet64Static(ArtField* f, Thread* self, ArtMethod* referrer, 1605 StubTest* test) 1606 REQUIRES_SHARED(Locks::mutator_lock_) { 1607 #if (defined(__x86_64__) && !defined(__APPLE__)) || (defined(__mips__) && defined(__LP64__)) \ 1608 || defined(__aarch64__) 1609 uint64_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF }; 1610 1611 for (size_t i = 0; i < arraysize(values); ++i) { 1612 // 64 bit FieldSet stores the set value in the second register. 1613 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1614 values[i], 1615 0U, 1616 StubTest::GetEntrypoint(self, kQuickSet64Static), 1617 self, 1618 referrer); 1619 1620 size_t res = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1621 0U, 0U, 1622 StubTest::GetEntrypoint(self, kQuickGet64Static), 1623 self, 1624 referrer); 1625 1626 EXPECT_EQ(res, values[i]) << "Iteration " << i; 1627 } 1628 #else 1629 UNUSED(f, self, referrer, test); 1630 LOG(INFO) << "Skipping set64static as I don't know how to do that on " << kRuntimeISA; 1631 // Force-print to std::cout so it's also outside the logcat. 1632 std::cout << "Skipping set64static as I don't know how to do that on " << kRuntimeISA << std::endl; 1633 #endif 1634 } 1635 1636 1637 static void GetSet64Instance(Handle<mirror::Object>* obj, ArtField* f, 1638 Thread* self, ArtMethod* referrer, StubTest* test) 1639 REQUIRES_SHARED(Locks::mutator_lock_) { 1640 #if (defined(__x86_64__) && !defined(__APPLE__)) || (defined(__mips__) && defined(__LP64__)) || \ 1641 defined(__aarch64__) 1642 uint64_t values[] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF }; 1643 1644 for (size_t i = 0; i < arraysize(values); ++i) { 1645 test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1646 reinterpret_cast<size_t>(obj->Get()), 1647 static_cast<size_t>(values[i]), 1648 StubTest::GetEntrypoint(self, kQuickSet64Instance), 1649 self, 1650 referrer); 1651 1652 int64_t res = f->GetLong(obj->Get()); 1653 EXPECT_EQ(res, static_cast<int64_t>(values[i])) << "Iteration " << i; 1654 1655 res++; 1656 f->SetLong<false>(obj->Get(), res); 1657 1658 size_t res2 = test->Invoke3WithReferrer(static_cast<size_t>(f->GetDexFieldIndex()), 1659 reinterpret_cast<size_t>(obj->Get()), 1660 0U, 1661 StubTest::GetEntrypoint(self, kQuickGet64Instance), 1662 self, 1663 referrer); 1664 EXPECT_EQ(res, static_cast<int64_t>(res2)); 1665 } 1666 #else 1667 UNUSED(obj, f, self, referrer, test); 1668 LOG(INFO) << "Skipping set64instance as I don't know how to do that on " << kRuntimeISA; 1669 // Force-print to std::cout so it's also outside the logcat. 1670 std::cout << "Skipping set64instance as I don't know how to do that on " << kRuntimeISA << std::endl; 1671 #endif 1672 } 1673 1674 static void TestFields(Thread* self, StubTest* test, Primitive::Type test_type) { 1675 // garbage is created during ClassLinker::Init 1676 1677 JNIEnv* env = Thread::Current()->GetJniEnv(); 1678 jclass jc = env->FindClass("AllFields"); 1679 CHECK(jc != nullptr); 1680 jobject o = env->AllocObject(jc); 1681 CHECK(o != nullptr); 1682 1683 ScopedObjectAccess soa(self); 1684 StackHandleScope<3> hs(self); 1685 Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(o))); 1686 Handle<mirror::Class> c(hs.NewHandle(obj->GetClass())); 1687 // Need a method as a referrer 1688 ArtMethod* m = c->GetDirectMethod(0, kRuntimePointerSize); 1689 1690 // Play with it... 1691 1692 // Static fields. 1693 for (ArtField& f : c->GetSFields()) { 1694 Primitive::Type type = f.GetTypeAsPrimitiveType(); 1695 if (test_type != type) { 1696 continue; 1697 } 1698 switch (type) { 1699 case Primitive::Type::kPrimBoolean: 1700 GetSetBooleanStatic(&f, self, m, test); 1701 break; 1702 case Primitive::Type::kPrimByte: 1703 GetSetByteStatic(&f, self, m, test); 1704 break; 1705 case Primitive::Type::kPrimChar: 1706 GetSetCharStatic(&f, self, m, test); 1707 break; 1708 case Primitive::Type::kPrimShort: 1709 GetSetShortStatic(&f, self, m, test); 1710 break; 1711 case Primitive::Type::kPrimInt: 1712 GetSet32Static(&f, self, m, test); 1713 break; 1714 case Primitive::Type::kPrimLong: 1715 GetSet64Static(&f, self, m, test); 1716 break; 1717 case Primitive::Type::kPrimNot: 1718 // Don't try array. 1719 if (f.GetTypeDescriptor()[0] != '[') { 1720 GetSetObjStatic(&f, self, m, test); 1721 } 1722 break; 1723 default: 1724 break; // Skip. 1725 } 1726 } 1727 1728 // Instance fields. 1729 for (ArtField& f : c->GetIFields()) { 1730 Primitive::Type type = f.GetTypeAsPrimitiveType(); 1731 if (test_type != type) { 1732 continue; 1733 } 1734 switch (type) { 1735 case Primitive::Type::kPrimBoolean: 1736 GetSetBooleanInstance(&obj, &f, self, m, test); 1737 break; 1738 case Primitive::Type::kPrimByte: 1739 GetSetByteInstance(&obj, &f, self, m, test); 1740 break; 1741 case Primitive::Type::kPrimChar: 1742 GetSetCharInstance(&obj, &f, self, m, test); 1743 break; 1744 case Primitive::Type::kPrimShort: 1745 GetSetShortInstance(&obj, &f, self, m, test); 1746 break; 1747 case Primitive::Type::kPrimInt: 1748 GetSet32Instance(&obj, &f, self, m, test); 1749 break; 1750 case Primitive::Type::kPrimLong: 1751 GetSet64Instance(&obj, &f, self, m, test); 1752 break; 1753 case Primitive::Type::kPrimNot: 1754 // Don't try array. 1755 if (f.GetTypeDescriptor()[0] != '[') { 1756 GetSetObjInstance(&obj, &f, self, m, test); 1757 } 1758 break; 1759 default: 1760 break; // Skip. 1761 } 1762 } 1763 1764 // TODO: Deallocate things. 1765 } 1766 1767 TEST_F(StubTest, Fields8) { 1768 Thread* self = Thread::Current(); 1769 1770 self->TransitionFromSuspendedToRunnable(); 1771 LoadDex("AllFields"); 1772 bool started = runtime_->Start(); 1773 CHECK(started); 1774 1775 TestFields(self, this, Primitive::Type::kPrimBoolean); 1776 TestFields(self, this, Primitive::Type::kPrimByte); 1777 } 1778 1779 TEST_F(StubTest, Fields16) { 1780 Thread* self = Thread::Current(); 1781 1782 self->TransitionFromSuspendedToRunnable(); 1783 LoadDex("AllFields"); 1784 bool started = runtime_->Start(); 1785 CHECK(started); 1786 1787 TestFields(self, this, Primitive::Type::kPrimChar); 1788 TestFields(self, this, Primitive::Type::kPrimShort); 1789 } 1790 1791 TEST_F(StubTest, Fields32) { 1792 Thread* self = Thread::Current(); 1793 1794 self->TransitionFromSuspendedToRunnable(); 1795 LoadDex("AllFields"); 1796 bool started = runtime_->Start(); 1797 CHECK(started); 1798 1799 TestFields(self, this, Primitive::Type::kPrimInt); 1800 } 1801 1802 TEST_F(StubTest, FieldsObj) { 1803 Thread* self = Thread::Current(); 1804 1805 self->TransitionFromSuspendedToRunnable(); 1806 LoadDex("AllFields"); 1807 bool started = runtime_->Start(); 1808 CHECK(started); 1809 1810 TestFields(self, this, Primitive::Type::kPrimNot); 1811 } 1812 1813 TEST_F(StubTest, Fields64) { 1814 Thread* self = Thread::Current(); 1815 1816 self->TransitionFromSuspendedToRunnable(); 1817 LoadDex("AllFields"); 1818 bool started = runtime_->Start(); 1819 CHECK(started); 1820 1821 TestFields(self, this, Primitive::Type::kPrimLong); 1822 } 1823 1824 // Disabled, b/27991555 . 1825 // FIXME: Hacking the entry point to point to art_quick_to_interpreter_bridge is broken. 1826 // The bridge calls through to GetCalleeSaveMethodCaller() which looks up the pre-header 1827 // and gets a bogus OatQuickMethodHeader* pointing into our assembly code just before 1828 // the bridge and uses that to check for inlined frames, crashing in the process. 1829 TEST_F(StubTest, DISABLED_IMT) { 1830 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 1831 (defined(__x86_64__) && !defined(__APPLE__)) 1832 Thread* self = Thread::Current(); 1833 1834 ScopedObjectAccess soa(self); 1835 StackHandleScope<7> hs(self); 1836 1837 JNIEnv* env = Thread::Current()->GetJniEnv(); 1838 1839 // ArrayList 1840 1841 // Load ArrayList and used methods (JNI). 1842 jclass arraylist_jclass = env->FindClass("java/util/ArrayList"); 1843 ASSERT_NE(nullptr, arraylist_jclass); 1844 jmethodID arraylist_constructor = env->GetMethodID(arraylist_jclass, "<init>", "()V"); 1845 ASSERT_NE(nullptr, arraylist_constructor); 1846 jmethodID contains_jmethod = env->GetMethodID( 1847 arraylist_jclass, "contains", "(Ljava/lang/Object;)Z"); 1848 ASSERT_NE(nullptr, contains_jmethod); 1849 jmethodID add_jmethod = env->GetMethodID(arraylist_jclass, "add", "(Ljava/lang/Object;)Z"); 1850 ASSERT_NE(nullptr, add_jmethod); 1851 1852 // Get representation. 1853 ArtMethod* contains_amethod = jni::DecodeArtMethod(contains_jmethod); 1854 1855 // Patch up ArrayList.contains. 1856 if (contains_amethod->GetEntryPointFromQuickCompiledCode() == nullptr) { 1857 contains_amethod->SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>( 1858 StubTest::GetEntrypoint(self, kQuickQuickToInterpreterBridge))); 1859 } 1860 1861 // List 1862 1863 // Load List and used methods (JNI). 1864 jclass list_jclass = env->FindClass("java/util/List"); 1865 ASSERT_NE(nullptr, list_jclass); 1866 jmethodID inf_contains_jmethod = env->GetMethodID( 1867 list_jclass, "contains", "(Ljava/lang/Object;)Z"); 1868 ASSERT_NE(nullptr, inf_contains_jmethod); 1869 1870 // Get mirror representation. 1871 ArtMethod* inf_contains = jni::DecodeArtMethod(inf_contains_jmethod); 1872 1873 // Object 1874 1875 jclass obj_jclass = env->FindClass("java/lang/Object"); 1876 ASSERT_NE(nullptr, obj_jclass); 1877 jmethodID obj_constructor = env->GetMethodID(obj_jclass, "<init>", "()V"); 1878 ASSERT_NE(nullptr, obj_constructor); 1879 1880 // Create instances. 1881 1882 jobject jarray_list = env->NewObject(arraylist_jclass, arraylist_constructor); 1883 ASSERT_NE(nullptr, jarray_list); 1884 Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object>(jarray_list))); 1885 1886 jobject jobj = env->NewObject(obj_jclass, obj_constructor); 1887 ASSERT_NE(nullptr, jobj); 1888 Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(jobj))); 1889 1890 // Invocation tests. 1891 1892 // 1. imt_conflict 1893 1894 // Contains. 1895 1896 // We construct the ImtConflictTable ourselves, as we cannot go into the runtime stub 1897 // that will create it: the runtime stub expects to be called by compiled code. 1898 LinearAlloc* linear_alloc = Runtime::Current()->GetLinearAlloc(); 1899 ArtMethod* conflict_method = Runtime::Current()->CreateImtConflictMethod(linear_alloc); 1900 ImtConflictTable* empty_conflict_table = 1901 Runtime::Current()->GetClassLinker()->CreateImtConflictTable(/*count*/0u, linear_alloc); 1902 void* data = linear_alloc->Alloc( 1903 self, 1904 ImtConflictTable::ComputeSizeWithOneMoreEntry(empty_conflict_table, kRuntimePointerSize)); 1905 ImtConflictTable* new_table = new (data) ImtConflictTable( 1906 empty_conflict_table, inf_contains, contains_amethod, kRuntimePointerSize); 1907 conflict_method->SetImtConflictTable(new_table, kRuntimePointerSize); 1908 1909 size_t result = 1910 Invoke3WithReferrerAndHidden(reinterpret_cast<size_t>(conflict_method), 1911 reinterpret_cast<size_t>(array_list.Get()), 1912 reinterpret_cast<size_t>(obj.Get()), 1913 StubTest::GetEntrypoint(self, kQuickQuickImtConflictTrampoline), 1914 self, 1915 contains_amethod, 1916 static_cast<size_t>(inf_contains->GetDexMethodIndex())); 1917 1918 ASSERT_FALSE(self->IsExceptionPending()); 1919 EXPECT_EQ(static_cast<size_t>(JNI_FALSE), result); 1920 1921 // Add object. 1922 1923 env->CallBooleanMethod(jarray_list, add_jmethod, jobj); 1924 1925 ASSERT_FALSE(self->IsExceptionPending()) << mirror::Object::PrettyTypeOf(self->GetException()); 1926 1927 // Contains. 1928 1929 result = 1930 Invoke3WithReferrerAndHidden(reinterpret_cast<size_t>(conflict_method), 1931 reinterpret_cast<size_t>(array_list.Get()), 1932 reinterpret_cast<size_t>(obj.Get()), 1933 StubTest::GetEntrypoint(self, kQuickQuickImtConflictTrampoline), 1934 self, 1935 contains_amethod, 1936 static_cast<size_t>(inf_contains->GetDexMethodIndex())); 1937 1938 ASSERT_FALSE(self->IsExceptionPending()); 1939 EXPECT_EQ(static_cast<size_t>(JNI_TRUE), result); 1940 1941 // 2. regular interface trampoline 1942 1943 result = Invoke3WithReferrer(static_cast<size_t>(inf_contains->GetDexMethodIndex()), 1944 reinterpret_cast<size_t>(array_list.Get()), 1945 reinterpret_cast<size_t>(obj.Get()), 1946 StubTest::GetEntrypoint(self, 1947 kQuickInvokeInterfaceTrampolineWithAccessCheck), 1948 self, contains_amethod); 1949 1950 ASSERT_FALSE(self->IsExceptionPending()); 1951 EXPECT_EQ(static_cast<size_t>(JNI_TRUE), result); 1952 1953 result = Invoke3WithReferrer( 1954 static_cast<size_t>(inf_contains->GetDexMethodIndex()), 1955 reinterpret_cast<size_t>(array_list.Get()), reinterpret_cast<size_t>(array_list.Get()), 1956 StubTest::GetEntrypoint(self, kQuickInvokeInterfaceTrampolineWithAccessCheck), self, 1957 contains_amethod); 1958 1959 ASSERT_FALSE(self->IsExceptionPending()); 1960 EXPECT_EQ(static_cast<size_t>(JNI_FALSE), result); 1961 #else 1962 LOG(INFO) << "Skipping imt as I don't know how to do that on " << kRuntimeISA; 1963 // Force-print to std::cout so it's also outside the logcat. 1964 std::cout << "Skipping imt as I don't know how to do that on " << kRuntimeISA << std::endl; 1965 #endif 1966 } 1967 1968 TEST_F(StubTest, StringIndexOf) { 1969 #if defined(__arm__) || defined(__aarch64__) || defined(__mips__) 1970 Thread* self = Thread::Current(); 1971 ScopedObjectAccess soa(self); 1972 // garbage is created during ClassLinker::Init 1973 1974 // Create some strings 1975 // Use array so we can index into it and use a matrix for expected results 1976 // Setup: The first half is standard. The second half uses a non-zero offset. 1977 // TODO: Shared backing arrays. 1978 const char* c_str[] = { "", "a", "ba", "cba", "dcba", "edcba", "asdfghjkl" }; 1979 static constexpr size_t kStringCount = arraysize(c_str); 1980 const char c_char[] = { 'a', 'b', 'c', 'd', 'e' }; 1981 static constexpr size_t kCharCount = arraysize(c_char); 1982 1983 StackHandleScope<kStringCount> hs(self); 1984 Handle<mirror::String> s[kStringCount]; 1985 1986 for (size_t i = 0; i < kStringCount; ++i) { 1987 s[i] = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), c_str[i])); 1988 } 1989 1990 // Matrix of expectations. First component is first parameter. Note we only check against the 1991 // sign, not the value. As we are testing random offsets, we need to compute this and need to 1992 // rely on String::CompareTo being correct. 1993 static constexpr size_t kMaxLen = 9; 1994 DCHECK_LE(strlen(c_str[kStringCount-1]), kMaxLen) << "Please fix the indexof test."; 1995 1996 // Last dimension: start, offset by 1. 1997 int32_t expected[kStringCount][kCharCount][kMaxLen + 3]; 1998 for (size_t x = 0; x < kStringCount; ++x) { 1999 for (size_t y = 0; y < kCharCount; ++y) { 2000 for (size_t z = 0; z <= kMaxLen + 2; ++z) { 2001 expected[x][y][z] = s[x]->FastIndexOf(c_char[y], static_cast<int32_t>(z) - 1); 2002 } 2003 } 2004 } 2005 2006 // Play with it... 2007 2008 for (size_t x = 0; x < kStringCount; ++x) { 2009 for (size_t y = 0; y < kCharCount; ++y) { 2010 for (size_t z = 0; z <= kMaxLen + 2; ++z) { 2011 int32_t start = static_cast<int32_t>(z) - 1; 2012 2013 // Test string_compareto x y 2014 size_t result = Invoke3(reinterpret_cast<size_t>(s[x].Get()), c_char[y], start, 2015 StubTest::GetEntrypoint(self, kQuickIndexOf), self); 2016 2017 EXPECT_FALSE(self->IsExceptionPending()); 2018 2019 // The result is a 32b signed integer 2020 union { 2021 size_t r; 2022 int32_t i; 2023 } conv; 2024 conv.r = result; 2025 2026 EXPECT_EQ(expected[x][y][z], conv.i) << "Wrong result for " << c_str[x] << " / " << 2027 c_char[y] << " @ " << start; 2028 } 2029 } 2030 } 2031 2032 // TODO: Deallocate things. 2033 2034 // Tests done. 2035 #else 2036 LOG(INFO) << "Skipping indexof as I don't know how to do that on " << kRuntimeISA; 2037 // Force-print to std::cout so it's also outside the logcat. 2038 std::cout << "Skipping indexof as I don't know how to do that on " << kRuntimeISA << std::endl; 2039 #endif 2040 } 2041 2042 // TODO: Exercise the ReadBarrierMarkRegX entry points. 2043 2044 TEST_F(StubTest, ReadBarrier) { 2045 #if defined(ART_USE_READ_BARRIER) && (defined(__i386__) || defined(__arm__) || \ 2046 defined(__aarch64__) || defined(__mips__) || (defined(__x86_64__) && !defined(__APPLE__))) 2047 Thread* self = Thread::Current(); 2048 2049 const uintptr_t readBarrierSlow = StubTest::GetEntrypoint(self, kQuickReadBarrierSlow); 2050 2051 // Create an object 2052 ScopedObjectAccess soa(self); 2053 // garbage is created during ClassLinker::Init 2054 2055 StackHandleScope<2> hs(soa.Self()); 2056 Handle<mirror::Class> c( 2057 hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"))); 2058 2059 // Build an object instance 2060 Handle<mirror::Object> obj(hs.NewHandle(c->AllocObject(soa.Self()))); 2061 2062 EXPECT_FALSE(self->IsExceptionPending()); 2063 2064 size_t result = Invoke3(0U, reinterpret_cast<size_t>(obj.Get()), 2065 mirror::Object::ClassOffset().SizeValue(), readBarrierSlow, self); 2066 2067 EXPECT_FALSE(self->IsExceptionPending()); 2068 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result); 2069 mirror::Class* klass = reinterpret_cast<mirror::Class*>(result); 2070 EXPECT_EQ(klass, obj->GetClass()); 2071 2072 // Tests done. 2073 #else 2074 LOG(INFO) << "Skipping read_barrier_slow"; 2075 // Force-print to std::cout so it's also outside the logcat. 2076 std::cout << "Skipping read_barrier_slow" << std::endl; 2077 #endif 2078 } 2079 2080 TEST_F(StubTest, ReadBarrierForRoot) { 2081 #if defined(ART_USE_READ_BARRIER) && (defined(__i386__) || defined(__arm__) || \ 2082 defined(__aarch64__) || defined(__mips__) || (defined(__x86_64__) && !defined(__APPLE__))) 2083 Thread* self = Thread::Current(); 2084 2085 const uintptr_t readBarrierForRootSlow = 2086 StubTest::GetEntrypoint(self, kQuickReadBarrierForRootSlow); 2087 2088 // Create an object 2089 ScopedObjectAccess soa(self); 2090 // garbage is created during ClassLinker::Init 2091 2092 StackHandleScope<1> hs(soa.Self()); 2093 2094 Handle<mirror::String> obj( 2095 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"))); 2096 2097 EXPECT_FALSE(self->IsExceptionPending()); 2098 2099 GcRoot<mirror::Class>& root = mirror::String::java_lang_String_; 2100 size_t result = Invoke3(reinterpret_cast<size_t>(&root), 0U, 0U, readBarrierForRootSlow, self); 2101 2102 EXPECT_FALSE(self->IsExceptionPending()); 2103 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result); 2104 mirror::Class* klass = reinterpret_cast<mirror::Class*>(result); 2105 EXPECT_EQ(klass, obj->GetClass()); 2106 2107 // Tests done. 2108 #else 2109 LOG(INFO) << "Skipping read_barrier_for_root_slow"; 2110 // Force-print to std::cout so it's also outside the logcat. 2111 std::cout << "Skipping read_barrier_for_root_slow" << std::endl; 2112 #endif 2113 } 2114 2115 } // namespace art 2116