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