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