1 /* 2 * Copyright (C) 2011 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 #ifndef ART_RUNTIME_COMMON_TEST_H_ 18 #define ART_RUNTIME_COMMON_TEST_H_ 19 20 #include <dirent.h> 21 #include <dlfcn.h> 22 #include <sys/mman.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 26 #include "../../external/icu4c/common/unicode/uvernum.h" 27 #include "base/macros.h" 28 #include "base/stl_util.h" 29 #include "base/stringprintf.h" 30 #include "base/unix_file/fd_file.h" 31 #include "class_linker.h" 32 #include "compiler/driver/compiler_driver.h" 33 #include "dex_file-inl.h" 34 #include "entrypoints/entrypoint_utils.h" 35 #include "gc/heap.h" 36 #include "gtest/gtest.h" 37 #include "instruction_set.h" 38 #include "interpreter/interpreter.h" 39 #include "mirror/class_loader.h" 40 #include "oat_file.h" 41 #include "object_utils.h" 42 #include "os.h" 43 #include "runtime.h" 44 #include "scoped_thread_state_change.h" 45 #include "ScopedLocalRef.h" 46 #include "thread.h" 47 #include "UniquePtr.h" 48 #include "well_known_classes.h" 49 50 namespace art { 51 52 static const byte kBase64Map[256] = { 53 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 54 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 55 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 56 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 57 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 58 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 59 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT 60 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT 61 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 62 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT 63 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT 64 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 65 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 66 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 67 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 68 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 69 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 70 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 71 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 72 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 73 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 74 255, 255, 255, 255 75 }; 76 77 byte* DecodeBase64(const char* src, size_t* dst_size) { 78 std::vector<byte> tmp; 79 uint32_t t = 0, y = 0; 80 int g = 3; 81 for (size_t i = 0; src[i] != '\0'; ++i) { 82 byte c = kBase64Map[src[i] & 0xFF]; 83 if (c == 255) continue; 84 // the final = symbols are read and used to trim the remaining bytes 85 if (c == 254) { 86 c = 0; 87 // prevent g < 0 which would potentially allow an overflow later 88 if (--g < 0) { 89 *dst_size = 0; 90 return NULL; 91 } 92 } else if (g != 3) { 93 // we only allow = to be at the end 94 *dst_size = 0; 95 return NULL; 96 } 97 t = (t << 6) | c; 98 if (++y == 4) { 99 tmp.push_back((t >> 16) & 255); 100 if (g > 1) { 101 tmp.push_back((t >> 8) & 255); 102 } 103 if (g > 2) { 104 tmp.push_back(t & 255); 105 } 106 y = t = 0; 107 } 108 } 109 if (y != 0) { 110 *dst_size = 0; 111 return NULL; 112 } 113 UniquePtr<byte[]> dst(new byte[tmp.size()]); 114 if (dst_size != NULL) { 115 *dst_size = tmp.size(); 116 } else { 117 *dst_size = 0; 118 } 119 std::copy(tmp.begin(), tmp.end(), dst.get()); 120 return dst.release(); 121 } 122 123 class ScratchFile { 124 public: 125 ScratchFile() { 126 filename_ = getenv("ANDROID_DATA"); 127 filename_ += "/TmpFile-XXXXXX"; 128 int fd = mkstemp(&filename_[0]); 129 CHECK_NE(-1, fd); 130 file_.reset(new File(fd, GetFilename())); 131 } 132 133 ~ScratchFile() { 134 int unlink_result = unlink(filename_.c_str()); 135 CHECK_EQ(0, unlink_result); 136 } 137 138 const std::string& GetFilename() const { 139 return filename_; 140 } 141 142 File* GetFile() const { 143 return file_.get(); 144 } 145 146 int GetFd() const { 147 return file_->Fd(); 148 } 149 150 private: 151 std::string filename_; 152 UniquePtr<File> file_; 153 }; 154 155 class CommonTest : public testing::Test { 156 public: 157 static void MakeExecutable(const mirror::ByteArray* code_array) { 158 CHECK(code_array != NULL); 159 MakeExecutable(code_array->GetData(), code_array->GetLength()); 160 } 161 162 static void MakeExecutable(const std::vector<uint8_t>& code) { 163 CHECK_NE(code.size(), 0U); 164 MakeExecutable(&code[0], code.size()); 165 } 166 167 // Create an OatMethod based on pointers (for unit tests) 168 OatFile::OatMethod CreateOatMethod(const void* code, 169 const size_t frame_size_in_bytes, 170 const uint32_t core_spill_mask, 171 const uint32_t fp_spill_mask, 172 const uint8_t* mapping_table, 173 const uint8_t* vmap_table, 174 const uint8_t* gc_map) { 175 return OatFile::OatMethod(NULL, 176 reinterpret_cast<uint32_t>(code), 177 frame_size_in_bytes, 178 core_spill_mask, 179 fp_spill_mask, 180 reinterpret_cast<uint32_t>(mapping_table), 181 reinterpret_cast<uint32_t>(vmap_table), 182 reinterpret_cast<uint32_t>(gc_map)); 183 } 184 185 void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 186 CHECK(method != NULL); 187 LOG(INFO) << "MakeExecutable " << PrettyMethod(method); 188 189 const CompiledMethod* compiled_method = NULL; 190 if (!method->IsAbstract()) { 191 const mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); 192 const DexFile& dex_file = *dex_cache->GetDexFile(); 193 compiled_method = 194 compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, 195 method->GetDexMethodIndex())); 196 } 197 if (compiled_method != NULL) { 198 const std::vector<uint8_t>& code = compiled_method->GetCode(); 199 MakeExecutable(code); 200 const void* method_code = CompiledMethod::CodePointer(&code[0], 201 compiled_method->GetInstructionSet()); 202 LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code; 203 OatFile::OatMethod oat_method = CreateOatMethod(method_code, 204 compiled_method->GetFrameSizeInBytes(), 205 compiled_method->GetCoreSpillMask(), 206 compiled_method->GetFpSpillMask(), 207 &compiled_method->GetMappingTable()[0], 208 &compiled_method->GetVmapTable()[0], 209 NULL); 210 oat_method.LinkMethod(method); 211 method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); 212 } else { 213 const void* method_code; 214 // No code? You must mean to go into the interpreter. 215 method_code = GetCompiledCodeToInterpreterBridge(); 216 LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code; 217 OatFile::OatMethod oat_method = CreateOatMethod(method_code, 218 kStackAlignment, 219 0, 220 0, 221 NULL, 222 NULL, 223 NULL); 224 oat_method.LinkMethod(method); 225 method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge); 226 } 227 } 228 229 static void MakeExecutable(const void* code_start, size_t code_length) { 230 CHECK(code_start != NULL); 231 CHECK_NE(code_length, 0U); 232 uintptr_t data = reinterpret_cast<uintptr_t>(code_start); 233 uintptr_t base = RoundDown(data, kPageSize); 234 uintptr_t limit = RoundUp(data + code_length, kPageSize); 235 uintptr_t len = limit - base; 236 int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC); 237 CHECK_EQ(result, 0); 238 239 // Flush instruction cache 240 // Only uses __builtin___clear_cache if GCC >= 4.3.3 241 #if GCC_VERSION >= 40303 242 __builtin___clear_cache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len)); 243 #else 244 LOG(FATAL) << "UNIMPLEMENTED: cache flush"; 245 #endif 246 } 247 248 static void SetEnvironmentVariables(std::string& android_data) { 249 if (IsHost()) { 250 // $ANDROID_ROOT is set on the device, but not on the host. 251 // We need to set this so that icu4c can find its locale data. 252 std::string root; 253 root += getenv("ANDROID_BUILD_TOP"); 254 #if defined(__linux__) 255 root += "/out/host/linux-x86"; 256 #elif defined(__APPLE__) 257 root += "/out/host/darwin-x86"; 258 #else 259 #error unsupported OS 260 #endif 261 setenv("ANDROID_ROOT", root.c_str(), 1); 262 setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. 263 } 264 265 // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache 266 android_data = (IsHost() ? "/tmp/art-data-XXXXXX" : "/data/dalvik-cache/art-data-XXXXXX"); 267 if (mkdtemp(&android_data[0]) == NULL) { 268 PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed"; 269 } 270 setenv("ANDROID_DATA", android_data.c_str(), 1); 271 } 272 273 protected: 274 static bool IsHost() { 275 return (getenv("ANDROID_BUILD_TOP") != NULL); 276 } 277 278 virtual void SetUp() { 279 SetEnvironmentVariables(android_data_); 280 dalvik_cache_.append(android_data_.c_str()); 281 dalvik_cache_.append("/dalvik-cache"); 282 int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); 283 ASSERT_EQ(mkdir_result, 0); 284 285 java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName(), GetLibCoreDexFileName()); 286 if (java_lang_dex_file_ == NULL) { 287 LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "'\n"; 288 } 289 conscrypt_file_ = DexFile::Open(GetConscryptFileName(), GetConscryptFileName()); 290 if (conscrypt_file_ == NULL) { 291 LOG(FATAL) << "Could not open .dex file '" << GetConscryptFileName() << "'\n"; 292 } 293 boot_class_path_.push_back(java_lang_dex_file_); 294 boot_class_path_.push_back(conscrypt_file_); 295 296 std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); 297 std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); 298 299 Runtime::Options options; 300 options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL))); 301 options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); 302 options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL))); 303 options.push_back(std::make_pair(min_heap_string.c_str(), reinterpret_cast<void*>(NULL))); 304 options.push_back(std::make_pair(max_heap_string.c_str(), reinterpret_cast<void*>(NULL))); 305 if (!Runtime::Create(options, false)) { 306 LOG(FATAL) << "Failed to create runtime"; 307 return; 308 } 309 runtime_.reset(Runtime::Current()); 310 // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start, 311 // give it away now and then switch to a more managable ScopedObjectAccess. 312 Thread::Current()->TransitionFromRunnableToSuspended(kNative); 313 { 314 ScopedObjectAccess soa(Thread::Current()); 315 ASSERT_TRUE(runtime_.get() != NULL); 316 class_linker_ = runtime_->GetClassLinker(); 317 318 InstructionSet instruction_set = kNone; 319 #if defined(__arm__) 320 instruction_set = kThumb2; 321 #elif defined(__mips__) 322 instruction_set = kMips; 323 #elif defined(__i386__) 324 instruction_set = kX86; 325 #endif 326 327 // TODO: make selectable 328 #if defined(ART_USE_PORTABLE_COMPILER) 329 CompilerBackend compiler_backend = kPortable; 330 #else 331 CompilerBackend compiler_backend = kQuick; 332 #endif 333 334 if (!runtime_->HasResolutionMethod()) { 335 runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod()); 336 } 337 for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { 338 Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); 339 if (!runtime_->HasCalleeSaveMethod(type)) { 340 runtime_->SetCalleeSaveMethod( 341 runtime_->CreateCalleeSaveMethod(instruction_set, type), type); 342 } 343 } 344 class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); 345 compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, 346 true, new CompilerDriver::DescriptorSet, 347 2, true)); 348 } 349 // We typically don't generate an image in unit tests, disable this optimization by default. 350 compiler_driver_->SetSupportBootImageFixup(false); 351 352 // We're back in native, take the opportunity to initialize well known classes. 353 WellKnownClasses::Init(Thread::Current()->GetJniEnv()); 354 // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread 355 // pool is created by the runtime. 356 runtime_->GetHeap()->CreateThreadPool(); 357 runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test 358 } 359 360 virtual void TearDown() { 361 const char* android_data = getenv("ANDROID_DATA"); 362 ASSERT_TRUE(android_data != NULL); 363 DIR* dir = opendir(dalvik_cache_.c_str()); 364 ASSERT_TRUE(dir != NULL); 365 dirent* e; 366 while ((e = readdir(dir)) != NULL) { 367 if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) { 368 continue; 369 } 370 std::string filename(dalvik_cache_); 371 filename.push_back('/'); 372 filename.append(e->d_name); 373 int unlink_result = unlink(filename.c_str()); 374 ASSERT_EQ(0, unlink_result); 375 } 376 closedir(dir); 377 int rmdir_cache_result = rmdir(dalvik_cache_.c_str()); 378 ASSERT_EQ(0, rmdir_cache_result); 379 int rmdir_data_result = rmdir(android_data_.c_str()); 380 ASSERT_EQ(0, rmdir_data_result); 381 382 // icu4c has a fixed 10-element array "gCommonICUDataArray". 383 // If we run > 10 tests, we fill that array and u_setCommonData fails. 384 // There's a function to clear the array, but it's not public... 385 typedef void (*IcuCleanupFn)(); 386 void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT); 387 CHECK(sym != NULL); 388 IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym); 389 (*icu_cleanup_fn)(); 390 391 compiler_driver_.reset(); 392 STLDeleteElements(&opened_dex_files_); 393 394 Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test 395 } 396 397 std::string GetLibCoreDexFileName() { 398 return GetDexFileName("core-libart"); 399 } 400 401 std::string GetConscryptFileName() { 402 return GetDexFileName("conscrypt"); 403 } 404 405 std::string GetDexFileName(const std::string& jar_prefix) { 406 if (IsHost()) { 407 const char* host_dir = getenv("ANDROID_HOST_OUT"); 408 CHECK(host_dir != NULL); 409 return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str()); 410 } 411 return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); 412 } 413 414 std::string GetTestAndroidRoot() { 415 if (IsHost()) { 416 const char* host_dir = getenv("ANDROID_HOST_OUT"); 417 CHECK(host_dir != NULL); 418 return host_dir; 419 } 420 return GetAndroidRoot(); 421 } 422 423 const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 424 CHECK(name != NULL); 425 std::string filename; 426 if (IsHost()) { 427 filename += getenv("ANDROID_HOST_OUT"); 428 filename += "/framework/"; 429 } else { 430 filename += "/data/nativetest/art/"; 431 } 432 filename += "art-test-dex-"; 433 filename += name; 434 filename += ".jar"; 435 const DexFile* dex_file = DexFile::Open(filename, filename); 436 CHECK(dex_file != NULL) << "Failed to open " << filename; 437 CHECK_EQ(PROT_READ, dex_file->GetPermissions()); 438 CHECK(dex_file->IsReadOnly()); 439 opened_dex_files_.push_back(dex_file); 440 return dex_file; 441 } 442 443 jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 444 const DexFile* dex_file = OpenTestDexFile(dex_name); 445 CHECK(dex_file != NULL); 446 class_linker_->RegisterDexFile(*dex_file); 447 std::vector<const DexFile*> class_path; 448 class_path.push_back(dex_file); 449 ScopedObjectAccessUnchecked soa(Thread::Current()); 450 ScopedLocalRef<jobject> class_loader_local(soa.Env(), 451 soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader)); 452 jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get()); 453 soa.Self()->SetClassLoaderOverride(soa.Decode<mirror::ClassLoader*>(class_loader_local.get())); 454 Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path); 455 return class_loader; 456 } 457 458 void CompileClass(mirror::ClassLoader* class_loader, const char* class_name) 459 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 460 std::string class_descriptor(DotToDescriptor(class_name)); 461 mirror::Class* klass = class_linker_->FindClass(class_descriptor.c_str(), class_loader); 462 CHECK(klass != NULL) << "Class not found " << class_name; 463 for (size_t i = 0; i < klass->NumDirectMethods(); i++) { 464 CompileMethod(klass->GetDirectMethod(i)); 465 } 466 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { 467 CompileMethod(klass->GetVirtualMethod(i)); 468 } 469 } 470 471 void CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 472 CHECK(method != NULL); 473 base::TimingLogger timings("CommonTest::CompileMethod", false, false); 474 timings.StartSplit("CompileOne"); 475 compiler_driver_->CompileOne(method, timings); 476 MakeExecutable(method); 477 } 478 479 void CompileDirectMethod(mirror::ClassLoader* class_loader, 480 const char* class_name, 481 const char* method_name, 482 const char* signature) 483 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 484 std::string class_descriptor(DotToDescriptor(class_name)); 485 mirror::Class* klass = class_linker_->FindClass(class_descriptor.c_str(), class_loader); 486 CHECK(klass != NULL) << "Class not found " << class_name; 487 mirror::ArtMethod* method = klass->FindDirectMethod(method_name, signature); 488 CHECK(method != NULL) << "Direct method not found: " 489 << class_name << "." << method_name << signature; 490 CompileMethod(method); 491 } 492 493 void CompileVirtualMethod(mirror::ClassLoader* class_loader, 494 const char* class_name, 495 const char* method_name, 496 const char* signature) 497 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 498 std::string class_descriptor(DotToDescriptor(class_name)); 499 mirror::Class* klass = class_linker_->FindClass(class_descriptor.c_str(), class_loader); 500 CHECK(klass != NULL) << "Class not found " << class_name; 501 mirror::ArtMethod* method = klass->FindVirtualMethod(method_name, signature); 502 CHECK(method != NULL) << "Virtual method not found: " 503 << class_name << "." << method_name << signature; 504 CompileMethod(method); 505 } 506 507 void ReserveImageSpace() { 508 // Reserve where the image will be loaded up front so that other parts of test set up don't 509 // accidentally end up colliding with the fixed memory address when we need to load the image. 510 image_reservation_.reset(MemMap::MapAnonymous("image reservation", 511 reinterpret_cast<byte*>(ART_BASE_ADDRESS), 512 (size_t)100 * 1024 * 1024, // 100MB 513 PROT_NONE)); 514 } 515 516 void UnreserveImageSpace() { 517 image_reservation_.reset(); 518 } 519 520 std::string android_data_; 521 std::string dalvik_cache_; 522 const DexFile* java_lang_dex_file_; // owned by runtime_ 523 const DexFile* conscrypt_file_; // owned by runtime_ 524 std::vector<const DexFile*> boot_class_path_; 525 UniquePtr<Runtime> runtime_; 526 // Owned by the runtime 527 ClassLinker* class_linker_; 528 UniquePtr<CompilerDriver> compiler_driver_; 529 530 private: 531 std::vector<const DexFile*> opened_dex_files_; 532 UniquePtr<MemMap> image_reservation_; 533 }; 534 535 // Sets a CheckJni abort hook to catch failures. Note that this will cause CheckJNI to carry on 536 // rather than aborting, so be careful! 537 class CheckJniAbortCatcher { 538 public: 539 CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) { 540 vm_->check_jni_abort_hook = Hook; 541 vm_->check_jni_abort_hook_data = &actual_; 542 } 543 544 ~CheckJniAbortCatcher() { 545 vm_->check_jni_abort_hook = NULL; 546 vm_->check_jni_abort_hook_data = NULL; 547 EXPECT_TRUE(actual_.empty()) << actual_; 548 } 549 550 void Check(const char* expected_text) { 551 EXPECT_TRUE(actual_.find(expected_text) != std::string::npos) << "\n" 552 << "Expected to find: " << expected_text << "\n" 553 << "In the output : " << actual_; 554 actual_.clear(); 555 } 556 557 private: 558 static void Hook(void* data, const std::string& reason) { 559 // We use += because when we're hooking the aborts like this, multiple problems can be found. 560 *reinterpret_cast<std::string*>(data) += reason; 561 } 562 563 JavaVMExt* vm_; 564 std::string actual_; 565 566 DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher); 567 }; 568 569 // TODO: These tests were disabled for portable when we went to having 570 // MCLinker link LLVM ELF output because we no longer just have code 571 // blobs in memory. We'll need to dlopen to load and relocate 572 // temporary output to resurrect these tests. 573 #if defined(ART_USE_PORTABLE_COMPILER) 574 #define TEST_DISABLED_FOR_PORTABLE() printf("WARNING: TEST DISABLED FOR PORTABLE\n"); return 575 #else 576 #define TEST_DISABLED_FOR_PORTABLE() 577 #endif 578 579 } // namespace art 580 581 namespace std { 582 583 // TODO: isn't gtest supposed to be able to print STL types for itself? 584 template <typename T> 585 std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) { 586 os << ::art::ToString(rhs); 587 return os; 588 } 589 590 } // namespace std 591 592 #endif // ART_RUNTIME_COMMON_TEST_H_ 593