common_test.h revision 234da578a2d91ed7f2ef47b2ec23fb0033e2746b
1934486cf07c578b6494417ca5dcbae89cf04b019Brian Carlstrom// Copyright 2011 Google Inc. All Rights Reserved.
2934486cf07c578b6494417ca5dcbae89cf04b019Brian Carlstrom
3b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom#include <dirent.h>
40af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes#include <dlfcn.h>
527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#include <sys/mman.h>
6b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom#include <sys/stat.h>
7b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom#include <sys/types.h>
8b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom
990a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes#include "UniquePtr.h"
10578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "base64.h"
11578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "class_linker.h"
121f87008b165d26541d832ff805250afdc89c253dBrian Carlstrom#include "class_loader.h"
139baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom#include "compiler.h"
142c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#include "constants.h"
15578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "dex_file.h"
1633f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom#include "file.h"
1790a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes#include "gtest/gtest.h"
181f87008b165d26541d832ff805250afdc89c253dBrian Carlstrom#include "heap.h"
193320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom#include "oat_file.h"
2033f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom#include "os.h"
211f87008b165d26541d832ff805250afdc89c253dBrian Carlstrom#include "runtime.h"
2214134a10e9bbaff0faf314dc00c1a1aeef8ef86bElliott Hughes#include "stl_util.h"
2390a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes#include "stringprintf.h"
2490a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes#include "thread.h"
250af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes#include "unicode/uclean.h"
260af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes#include "unicode/uvernum.h"
270af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes
28934486cf07c578b6494417ca5dcbae89cf04b019Brian Carlstromnamespace art {
29934486cf07c578b6494417ca5dcbae89cf04b019Brian Carlstrom
309f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstromstatic inline const DexFile* OpenDexFileBase64(const char* base64,
319f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom                                               const std::string& location) {
3233f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  // decode base64
33578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom  CHECK(base64 != NULL);
34578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom  size_t length;
35f615a61aef972cfc1dc23931ac2ed0da14c3fedbBrian Carlstrom  byte* dex_bytes = DecodeBase64(base64, &length);
36f615a61aef972cfc1dc23931ac2ed0da14c3fedbBrian Carlstrom  CHECK(dex_bytes != NULL);
3733f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom
3833f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  // write to provided file
3933f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  UniquePtr<File> file(OS::OpenFile(location.c_str(), true));
4033f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  CHECK(file.get() != NULL);
4133f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  if (!file->WriteFully(dex_bytes, length)) {
4233f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom    PLOG(FATAL) << "Failed to write base64 as dex file";
4333f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  }
4433f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  file.reset();
4533f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom
4633f741eefef8f8012f6c190b39355f2e0430d535Brian Carlstrom  // read dex file
4758ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom  const DexFile* dex_file = DexFile::Open(location, "");
48578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom  CHECK(dex_file != NULL);
49f615a61aef972cfc1dc23931ac2ed0da14c3fedbBrian Carlstrom  return dex_file;
50578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom}
51578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
52db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstromclass ScratchFile {
53db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom public:
54db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  ScratchFile() {
5534023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    filename_ = getenv("ANDROID_DATA");
5634023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    filename_ += "/TmpFile-XXXXXX";
5734023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    fd_ = mkstemp(&filename_[0]);
58db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom    CHECK_NE(-1, fd_);
59234da578a2d91ed7f2ef47b2ec23fb0033e2746bElliott Hughes    file_.reset(OS::FileFromFd(GetFilename(), fd_));
60db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  }
61db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom
62db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  ~ScratchFile() {
6334023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    int unlink_result = unlink(filename_.c_str());
64db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom    CHECK_EQ(0, unlink_result);
65db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom    int close_result = close(fd_);
66db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom    CHECK_EQ(0, close_result);
67db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  }
68db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom
69db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  const char* GetFilename() const {
7034023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    return filename_.c_str();
71db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  }
72db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom
73234da578a2d91ed7f2ef47b2ec23fb0033e2746bElliott Hughes  File* GetFile() const {
74234da578a2d91ed7f2ef47b2ec23fb0033e2746bElliott Hughes    return file_.get();
75234da578a2d91ed7f2ef47b2ec23fb0033e2746bElliott Hughes  }
76234da578a2d91ed7f2ef47b2ec23fb0033e2746bElliott Hughes
77db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  int GetFd() const {
78db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom    return fd_;
79db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  }
80db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom
81db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom private:
8234023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes  std::string filename_;
83db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom  int fd_;
84234da578a2d91ed7f2ef47b2ec23fb0033e2746bElliott Hughes  UniquePtr<File> file_;
85db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom};
86db4d54081f09abcbe97ffdf615874f2809a9e777Brian Carlstrom
87f734cf55d510976f4862b15e35fc86eae2a3daf8Brian Carlstromclass CommonTest : public testing::Test {
889baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom public:
893320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
903320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  static void MakeExecutable(const ByteArray* code_array) {
913320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    CHECK(code_array != NULL);
923320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    MakeExecutable(code_array->GetData(), code_array->GetLength());
933320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  }
943320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
953320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  static void MakeExecutable(const std::vector<uint8_t>& code) {
963320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    CHECK_NE(code.size(), 0U);
973320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    MakeExecutable(&code[0], code.size());
983320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  }
993320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
1003320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  void MakeExecutable(Method* method) {
1013320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    CHECK(method != NULL);
1023320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
1033320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
1043320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    CHECK(compiled_invoke_stub != NULL) << PrettyMethod(method);
1053320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
1063320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    MakeExecutable(invoke_stub);
1073320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    const Method::InvokeStub* method_invoke_stub
1083320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom        = reinterpret_cast<const Method::InvokeStub*>(&invoke_stub[0]);
1093320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    LOG(INFO) << "MakeExecutable " << PrettyMethod(method)
1103320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom              << " invoke_stub=" << reinterpret_cast<void*>(method_invoke_stub);
1113320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
1123320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    if (!method->IsAbstract()) {
1133320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
1143320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      CHECK(compiled_method != NULL) << PrettyMethod(method);
1153320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      const std::vector<uint8_t>& code = compiled_method->GetCode();
1163320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      MakeExecutable(code);
1173320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      const void* method_code
1183320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom          = CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
1193320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
1203320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      OatFile::OatMethod oat_method(method_code,
1213320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    compiled_method->GetFrameSizeInBytes(),
1223320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    compiled_method->GetReturnPcOffsetInBytes(),
1233320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    compiled_method->GetCoreSpillMask(),
1243320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    compiled_method->GetFpSpillMask(),
1253320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    &compiled_method->GetMappingTable()[0],
1263320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    &compiled_method->GetVmapTable()[0],
1273320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    method_invoke_stub);
1283320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      oat_method.LinkMethod(method);
1293320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    } else {
1303320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
1313320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
1323320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
1333320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      OatFile::OatMethod oat_method(method_code,
1343320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    kStackAlignment,
1353320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    0,
1363320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    0,
1373320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    0,
1383320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    NULL,
1393320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    NULL,
1403320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom                                    method_invoke_stub);
1413320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom      oat_method.LinkMethod(method);
1423320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    }
1433320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  }
1443320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
1453320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom  static void MakeExecutable(const void* code_start, size_t code_length) {
1463320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    CHECK(code_start != NULL);
1473320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    CHECK_NE(code_length, 0U);
1483320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    uintptr_t data = reinterpret_cast<uintptr_t>(code_start);
1499baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    uintptr_t base = RoundDown(data, kPageSize);
1503320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    uintptr_t limit = RoundUp(data + code_length, kPageSize);
1519baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    uintptr_t len = limit - base;
1529baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC);
1531634155a231665f16867cbecab9332a8b1cf3b1eIan Rogers    // Flush instruction cache
1541634155a231665f16867cbecab9332a8b1cf3b1eIan Rogers    __builtin___clear_cache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len));
1559baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CHECK_EQ(result, 0);
1569baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  }
1579baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom
158578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom protected:
159578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom  virtual void SetUp() {
1604a96b60e45fba4a9d4a2e9c8fc849660eacef684Brian Carlstrom    is_host_ = getenv("ANDROID_BUILD_TOP") != NULL;
1614a96b60e45fba4a9d4a2e9c8fc849660eacef684Brian Carlstrom
1620af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    if (is_host_) {
1630af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes      // $ANDROID_ROOT is set on the device, but not on the host.
1640af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes      // We need to set this so that icu4c can find its locale data.
1650af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes      std::string root;
1660af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes      root += getenv("ANDROID_BUILD_TOP");
1670af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes      root += "/out/host/linux-x86";
1680af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes      setenv("ANDROID_ROOT", root.c_str(), 1);
1690af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    }
1700af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes
17169b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of art-cache
17269b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    android_data_ = (is_host_ ? "/tmp/art-data-XXXXXX" : "/data/art-cache/art-data-XXXXXX");
1730f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes    if (mkdtemp(&android_data_[0]) == NULL) {
1740f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes      PLOG(FATAL) << "mkdtemp(\"" << &android_data_[0] << "\") failed";
1750f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes    }
17634023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    setenv("ANDROID_DATA", android_data_.c_str(), 1);
17734023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    art_cache_.append(android_data_.c_str());
178b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    art_cache_.append("/art-cache");
179b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    int mkdir_result = mkdir(art_cache_.c_str(), 0700);
180b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    ASSERT_EQ(mkdir_result, 0);
181b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom
182a5b897eae4b6f9f9608faa9eada7ddf42bf1bfd2Elliott Hughes    java_lang_dex_file_.reset(GetLibCoreDex());
183578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
18458ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    std::string boot_class_path;
18558ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    boot_class_path += "-Xbootclasspath:";
18658ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    boot_class_path += GetLibCoreDexFileName();
187578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
18869b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    Runtime::Options options;
189a4a7b48c813ad73ac795d0b405de69755b36dd6bBrian Carlstrom    options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
19058ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    options.push_back(std::make_pair(boot_class_path.c_str(), reinterpret_cast<void*>(NULL)));
19169b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
192e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom    options.push_back(std::make_pair("-Xms64m", reinterpret_cast<void*>(NULL)));
193e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom    options.push_back(std::make_pair("-Xmx64m", reinterpret_cast<void*>(NULL)));
19469b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    runtime_.reset(Runtime::Create(options, false));
19590a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes    ASSERT_TRUE(runtime_.get() != NULL);
1967a90959d4ef7a69f3bcb7b8763f646e12d9267d3Carl Shapiro    class_linker_ = runtime_->GetClassLinker();
1970cfe1fb7060576d047f7f894fc0d8b87de84fcabIan Rogers
1984f0d07c783afef89703dce32c94440fc8621a29bIan Rogers    InstructionSet instruction_set = kNone;
1992c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#if defined(__i386__)
2004f0d07c783afef89703dce32c94440fc8621a29bIan Rogers    instruction_set = kX86;
2012c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#elif defined(__arm__)
2024f0d07c783afef89703dce32c94440fc8621a29bIan Rogers    instruction_set = kThumb2;
2032c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers#endif
2044f0d07c783afef89703dce32c94440fc8621a29bIan Rogers    runtime_->SetJniStubArray(JniCompiler::CreateJniStub(instruction_set));
2054f0d07c783afef89703dce32c94440fc8621a29bIan Rogers    runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(instruction_set));
206362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
2071cb0a1dfc32531c79a968aeac26ccb5525862497Ian Rogers      Runtime::TrampolineType type = Runtime::TrampolineType(i);
2081cb0a1dfc32531c79a968aeac26ccb5525862497Ian Rogers      if (!runtime_->HasResolutionStubArray(type)) {
2094f0d07c783afef89703dce32c94440fc8621a29bIan Rogers        runtime_->SetResolutionStubArray(
2104f0d07c783afef89703dce32c94440fc8621a29bIan Rogers            Compiler::CreateResolutionStub(instruction_set, type), type);
2111cb0a1dfc32531c79a968aeac26ccb5525862497Ian Rogers      }
2121cb0a1dfc32531c79a968aeac26ccb5525862497Ian Rogers    }
213362f9bc807169bcfc8761dde067bbfb79b5ad0fdElliott Hughes    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
2144f0d07c783afef89703dce32c94440fc8621a29bIan Rogers      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
2154f0d07c783afef89703dce32c94440fc8621a29bIan Rogers      if (!runtime_->HasCalleeSaveMethod(type)) {
2164f0d07c783afef89703dce32c94440fc8621a29bIan Rogers        runtime_->SetCalleeSaveMethod(
2174f0d07c783afef89703dce32c94440fc8621a29bIan Rogers            runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
2184f0d07c783afef89703dce32c94440fc8621a29bIan Rogers      }
2194f0d07c783afef89703dce32c94440fc8621a29bIan Rogers    }
220aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    compiler_.reset(new Compiler(instruction_set, false));
2212c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
2220cfe1fb7060576d047f7f894fc0d8b87de84fcabIan Rogers    Heap::VerifyHeap();  // Check for heap corruption before the test
223578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom  }
224578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
225b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom  virtual void TearDown() {
226b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    const char* android_data = getenv("ANDROID_DATA");
227b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    ASSERT_TRUE(android_data != NULL);
228b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    DIR* dir = opendir(art_cache_.c_str());
229b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    ASSERT_TRUE(dir != NULL);
230b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    while (true) {
231b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      struct dirent entry;
232b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      struct dirent* entry_ptr;
233b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      int readdir_result = readdir_r(dir, &entry, &entry_ptr);
234b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      ASSERT_EQ(0, readdir_result);
235b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      if (entry_ptr == NULL) {
236b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom        break;
237b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      }
238b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      if ((strcmp(entry_ptr->d_name, ".") == 0) || (strcmp(entry_ptr->d_name, "..") == 0)) {
239b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom        continue;
240b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      }
241b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      std::string filename(art_cache_);
242b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      filename.push_back('/');
243b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      filename.append(entry_ptr->d_name);
244b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      int unlink_result = unlink(filename.c_str());
245b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      ASSERT_EQ(0, unlink_result);
246b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    }
247b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    closedir(dir);
248b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    int rmdir_cache_result = rmdir(art_cache_.c_str());
249b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    ASSERT_EQ(0, rmdir_cache_result);
25034023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes    int rmdir_data_result = rmdir(android_data_.c_str());
251b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    ASSERT_EQ(0, rmdir_data_result);
2520af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes
2530af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    // icu4c has a fixed 10-element array "gCommonICUDataArray".
2540af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    // If we run > 10 tests, we fill that array and u_setCommonData fails.
2550af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    // There's a function to clear the array, but it's not public...
2560af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    typedef void (*IcuCleanupFn)();
2570af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT);
2580af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    CHECK(sym != NULL);
2590af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym);
2600af5543f8ea20c3e655b2d748a1b7dcf283792feElliott Hughes    (*icu_cleanup_fn)();
2610cfe1fb7060576d047f7f894fc0d8b87de84fcabIan Rogers
2620e073f7b9386a461b470d30415a96480ab1b76afIan Rogers    compiler_.reset();
2632c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers
2640cfe1fb7060576d047f7f894fc0d8b87de84fcabIan Rogers    Heap::VerifyHeap();  // Check for heap corruption after the test
265b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom  }
266b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom
267b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom  std::string GetLibCoreDexFileName() {
268b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    if (is_host_) {
269b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      const char* host_dir = getenv("ANDROID_HOST_OUT");
270b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      CHECK(host_dir != NULL);
271b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom      return StringPrintf("%s/framework/core-hostdex.jar", host_dir);
272ac5b9e22d32c4f986783a2207b08ade769619f6fJesse Wilson    }
273b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    return std::string("/system/framework/core.jar");
274b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom  }
275ac5b9e22d32c4f986783a2207b08ade769619f6fJesse Wilson
2769f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom  const DexFile* GetLibCoreDex() {
277b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom    std::string libcore_dex_file_name = GetLibCoreDexFileName();
27858ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    return DexFile::Open(libcore_dex_file_name, "");
279ac5b9e22d32c4f986783a2207b08ade769619f6fJesse Wilson  }
280ac5b9e22d32c4f986783a2207b08ade769619f6fJesse Wilson
281848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom  uint32_t FindTypeIdxByDescriptor(const DexFile& dex_file, const StringPiece& descriptor) {
282848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom    for (size_t i = 0; i < dex_file.NumTypeIds(); i++) {
283848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom      const DexFile::TypeId& type_id = dex_file.GetTypeId(i);
284848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom      if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
285848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom        return i;
286848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom      }
287848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom    }
28869b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    CHECK(false) << "Failed to find type index for " << descriptor;
289848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom    return 0;
290848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom  }
291848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom
292848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom  uint32_t FindFieldIdxByDescriptorAndName(const DexFile& dex_file,
293848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom                                           const StringPiece& class_descriptor,
294848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom                                           const StringPiece& field_name) {
295848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom    for (size_t i = 0; i < dex_file.NumFieldIds(); i++) {
296848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom      const DexFile::FieldId& field_id = dex_file.GetFieldId(i);
2976b4ef025af12b158d117fc80fc79acf620f411a0Brian Carlstrom      if (class_descriptor == dex_file.GetFieldDeclaringClassDescriptor(field_id)
298848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom          && field_name == dex_file.GetFieldName(field_id)) {
299848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom        return i;
300848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom      }
301848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom    }
30269b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    CHECK(false) << "Failed to find field index for " << class_descriptor << " " << field_name;
303848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom    return 0;
304848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom  }
305848a4b339936cec230512705c9d5eeed55ca74caBrian Carlstrom
3069f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom  const DexFile* OpenTestDexFile(const char* name) {
3079f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    CHECK(name != NULL);
3089f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    std::string filename;
3099f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    if (is_host_) {
3109f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom      // on the host, just read target dex file
3119f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom      filename += getenv("ANDROID_PRODUCT_OUT");
3129f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    }
31347a0d5a6f221066c3daf7f67f2122ed9c9cd217cBrian Carlstrom    filename += "/data/art-test/art-test-dex-";
3149f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    filename += name;
3159f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    filename += ".jar";
31658ae9416e197ae68ed12ed43d87407d4dfb15093Brian Carlstrom    const DexFile* dex_file = DexFile::Open(filename, "");
31769b15fb098162f19a4c20e6dccdcead04d9c77f0Brian Carlstrom    CHECK(dex_file != NULL) << "Failed to open " << filename;
3189f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom    return dex_file;
3199f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom  }
3209f30b38d74990286ce27c3a45368f73dbe3638f0Brian Carlstrom
32140381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom  ClassLoader* LoadDex(const char* dex_name) {
3229baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    const DexFile* dex_file = OpenTestDexFile(dex_name);
3239baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CHECK(dex_file != NULL);
3249baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    loaded_dex_files_.push_back(dex_file);
3259baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    class_linker_->RegisterDexFile(*dex_file);
3269baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    std::vector<const DexFile*> class_path;
3279baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    class_path.push_back(dex_file);
32840381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom    SirtRef<ClassLoader> class_loader(PathClassLoader::AllocCompileTime(class_path));
32940381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom    CHECK(class_loader.get() != NULL);
33040381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom    Thread::Current()->SetClassLoaderOverride(class_loader.get());
33140381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom    return class_loader.get();
3329baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  }
3339baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom
334aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  void CompileClass(const ClassLoader* class_loader, const char* class_name) {
335aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    std::string class_descriptor = DotToDescriptor(class_name);
336aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    Class* klass = class_linker_->FindClass(class_descriptor, class_loader);
337aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    CHECK(klass != NULL) << "Class not found " << class_name;
338aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
339aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      CompileMethod(klass->GetDirectMethod(i));
340aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
341aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
342aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom      CompileMethod(klass->GetVirtualMethod(i));
343aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom    }
344aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom  }
345aded5f7ab991f3c1132851599d3bc60ff6707eedBrian Carlstrom
3469baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  void CompileMethod(Method* method) {
3479baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CHECK(method != NULL);
3482c8f653c98d658419f464b6147c10e11a664d2e6Ian Rogers    compiler_->CompileOne(method);
3493320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom    MakeExecutable(method);
3503320cf46afd082398aa401b246e6f301cebdf64dBrian Carlstrom
351161928613d3f097108319de60494fab1aab8d48aBrian Carlstrom    MakeExecutable(runtime_->GetJniStubArray());
3529baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  }
3539baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom
35440381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom  void CompileDirectMethod(ClassLoader* class_loader,
3559baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom                           const char* class_name,
3569baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom                           const char* method_name,
3579baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom                           const char* signature) {
358f91c8c328c922ecd522e1d3508d2603e78de8a7bBrian Carlstrom    std::string class_descriptor = DotToDescriptor(class_name);
3599baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    Class* klass = class_linker_->FindClass(class_descriptor, class_loader);
3609baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CHECK(klass != NULL) << "Class not found " << class_name;
3619baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    Method* method = klass->FindDirectMethod(method_name, signature);
3620f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes    CHECK(method != NULL) << "Direct method not found: "
3630f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes                          << class_name << "." << method_name << signature;
3649baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CompileMethod(method);
3659baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  }
3669baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom
36740381fb9dc4b4cf274f1e58b2cdf4396202c6189Brian Carlstrom  void CompileVirtualMethod(ClassLoader* class_loader,
3689baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom                            const char* class_name,
3699baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom                            const char* method_name,
3709baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom                            const char* signature) {
371f91c8c328c922ecd522e1d3508d2603e78de8a7bBrian Carlstrom    std::string class_descriptor = DotToDescriptor(class_name);
3729baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    Class* klass = class_linker_->FindClass(class_descriptor, class_loader);
3739baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CHECK(klass != NULL) << "Class not found " << class_name;
3749baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    Method* method = klass->FindVirtualMethod(method_name, signature);
3750f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes    CHECK(method != NULL) << "Virtual method not found: "
3760f4c41d75c821162184501cd4b510a93f6eb580fElliott Hughes                          << class_name << "." << method_name << signature;
3779baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom    CompileMethod(method);
3789baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  }
3799baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom
3804a96b60e45fba4a9d4a2e9c8fc849660eacef684Brian Carlstrom  bool is_host_;
38134023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes  std::string android_data_;
382b0460eaa2cb131f1dbdd5a7217bd36b9a9f1b995Brian Carlstrom  std::string art_cache_;
38390a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes  UniquePtr<const DexFile> java_lang_dex_file_;
3849ea1cb1a22be5b85dc2622e3836c46a1c48e3f25Brian Carlstrom  std::vector<const DexFile*> boot_class_path_;
38590a3369d3b6238f1a4c9b19ca68978dab1c39bc4Elliott Hughes  UniquePtr<Runtime> runtime_;
3860e073f7b9386a461b470d30415a96480ab1b76afIan Rogers  // Owned by the runtime
3877a90959d4ef7a69f3bcb7b8763f646e12d9267d3Carl Shapiro  ClassLinker* class_linker_;
3880e073f7b9386a461b470d30415a96480ab1b76afIan Rogers  UniquePtr<Compiler> compiler_;
3899baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom
3909baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom private:
3919baa4aefc370f48774b6104680193d9a7e4fb631Brian Carlstrom  std::vector<const DexFile*> loaded_dex_files_;
392578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom};
393578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom
394934486cf07c578b6494417ca5dcbae89cf04b019Brian Carlstrom}  // namespace art
39534023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes
39634023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughesnamespace std {
39734023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes
39834023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes// TODO: isn't gtest supposed to be able to print STL types for itself?
39934023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughestemplate <typename T>
40034023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughesstd::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) {
40114134a10e9bbaff0faf314dc00c1a1aeef8ef86bElliott Hughes  os << ::art::ToString(rhs);
40234023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes  return os;
40334023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes}
40434023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes
40534023801bd544e613d6e85c9a5b2e743f3710e8fElliott Hughes}  // namespace std
406