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