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