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