diff options
author | Brian Carlstrom <bdc@google.com> | 2014-02-24 23:23:58 -0800 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2014-02-26 13:17:44 -0800 |
commit | a1ce1fef2d49d1d537776a5308ace7102a815fe5 (patch) | |
tree | a1afe850d9ebd21f4b751eb68e1ec3dc60dab001 /runtime | |
parent | 930f7b843ddc6e6530439d3fdb0e2133a6292f1e (diff) | |
download | art-a1ce1fef2d49d1d537776a5308ace7102a815fe5.zip art-a1ce1fef2d49d1d537776a5308ace7102a815fe5.tar.gz art-a1ce1fef2d49d1d537776a5308ace7102a815fe5.tar.bz2 |
Split up CommonTest into CommonRuntimeTest and CommonCompilerTest
Change-Id: I8dcf6b29a5aecd445f1a3ddb06386cf81dbc9c70
Diffstat (limited to 'runtime')
33 files changed, 887 insertions, 870 deletions
diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc index 69951c5..7d32338 100644 --- a/runtime/barrier_test.cc +++ b/runtime/barrier_test.cc @@ -19,7 +19,7 @@ #include <string> #include "atomic.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "mirror/object_array-inl.h" #include "thread_pool.h" #include "UniquePtr.h" @@ -56,7 +56,7 @@ class CheckWaitTask : public Task { AtomicInteger* const count3_; }; -class BarrierTest : public CommonTest { +class BarrierTest : public CommonRuntimeTest { public: static int32_t num_threads; }; diff --git a/runtime/base/mutex_test.cc b/runtime/base/mutex_test.cc index 1af8e0a..ee0b1be 100644 --- a/runtime/base/mutex_test.cc +++ b/runtime/base/mutex_test.cc @@ -16,11 +16,11 @@ #include "mutex.h" -#include "common_test.h" +#include "common_runtime_test.h" namespace art { -class MutexTest : public CommonTest {}; +class MutexTest : public CommonRuntimeTest {}; struct MutexTester { static void AssertDepth(Mutex& mu, uint32_t expected_depth) { diff --git a/runtime/base/timing_logger_test.cc b/runtime/base/timing_logger_test.cc index 03cc9cc..0757751 100644 --- a/runtime/base/timing_logger_test.cc +++ b/runtime/base/timing_logger_test.cc @@ -16,11 +16,11 @@ #include "timing_logger.h" -#include "common_test.h" +#include "common_runtime_test.h" namespace art { -class TimingLoggerTest : public CommonTest {}; +class TimingLoggerTest : public CommonRuntimeTest {}; // TODO: Negative test cases (improper pairing of EndSplit, etc.) diff --git a/runtime/base/unix_file/mapped_file_test.cc b/runtime/base/unix_file/mapped_file_test.cc index 49750f4..7e45321 100644 --- a/runtime/base/unix_file/mapped_file_test.cc +++ b/runtime/base/unix_file/mapped_file_test.cc @@ -30,7 +30,7 @@ class MappedFileTest : public RandomAccessFileTest { } void SetUp() { - art::CommonTest::SetEnvironmentVariables(android_data_); + art::CommonRuntimeTest::SetEnvironmentVariables(android_data_); good_path_ = GetTmpPath("some-file.txt"); int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666)); diff --git a/runtime/base/unix_file/random_access_file_test.h b/runtime/base/unix_file/random_access_file_test.h index 3152788..8a6605e 100644 --- a/runtime/base/unix_file/random_access_file_test.h +++ b/runtime/base/unix_file/random_access_file_test.h @@ -21,8 +21,7 @@ #include <string> -#include "common_test.h" -#include "gtest/gtest.h" +#include "common_runtime_test.h" #include "UniquePtr.h" namespace unix_file { @@ -37,7 +36,7 @@ class RandomAccessFileTest : public testing::Test { virtual RandomAccessFile* MakeTestFile() = 0; virtual void SetUp() { - art::CommonTest::SetEnvironmentVariables(android_data_); + art::CommonRuntimeTest::SetEnvironmentVariables(android_data_); } std::string GetTmpPath(const std::string& name) { diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 0cd8e71..55c23f4 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -20,7 +20,7 @@ #include "UniquePtr.h" #include "class_linker-inl.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "dex_file.h" #include "entrypoints/entrypoint_utils.h" #include "gc/heap.h" @@ -37,7 +37,7 @@ namespace art { -class ClassLinkerTest : public CommonTest { +class ClassLinkerTest : public CommonRuntimeTest { protected: void AssertNonExistentClass(const std::string& descriptor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -339,7 +339,7 @@ class ClassLinkerTest : public CommonTest { mirror::DexCache* dex_cache = class_linker_->FindDexCache(*dex); mirror::ObjectArray<mirror::ArtMethod>* resolved_methods = dex_cache->GetResolvedMethods(); for (size_t i = 0; i < static_cast<size_t>(resolved_methods->GetLength()); i++) { - EXPECT_TRUE(resolved_methods->Get(i) != NULL); + EXPECT_TRUE(resolved_methods->Get(i) != NULL) << dex->GetLocation() << " i=" << i; } } diff --git a/runtime/common_test.cc b/runtime/common_runtime_test.cc index 5df7d41..0ed8b63 100644 --- a/runtime/common_test.cc +++ b/runtime/common_runtime_test.cc @@ -19,7 +19,7 @@ int main(int argc, char **argv) { art::InitLogging(argv); - LOG(INFO) << "Running main() from common_test.cc..."; + LOG(INFO) << "Running main() from common_runtime_test.cc..."; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h new file mode 100644 index 0000000..e2ecf4b --- /dev/null +++ b/runtime/common_runtime_test.h @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_COMMON_RUNTIME_TEST_H_ +#define ART_RUNTIME_COMMON_RUNTIME_TEST_H_ + +#include <dirent.h> +#include <dlfcn.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fstream> + +#include "../../external/icu4c/common/unicode/uvernum.h" +#include "base/macros.h" +#include "base/stl_util.h" +#include "base/stringprintf.h" +#include "base/unix_file/fd_file.h" +#include "class_linker.h" +#include "compiler_callbacks.h" +#include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" +#include "gc/heap.h" +#include "gtest/gtest.h" +#include "instruction_set.h" +#include "interpreter/interpreter.h" +#include "mirror/class_loader.h" +#include "oat_file.h" +#include "object_utils.h" +#include "os.h" +#include "runtime.h" +#include "scoped_thread_state_change.h" +#include "ScopedLocalRef.h" +#include "thread.h" +#include "utils.h" +#include "UniquePtr.h" +#include "verifier/method_verifier.h" +#include "verifier/method_verifier-inl.h" +#include "well_known_classes.h" + +namespace art { + +class ScratchFile { + public: + ScratchFile() { + filename_ = getenv("ANDROID_DATA"); + filename_ += "/TmpFile-XXXXXX"; + int fd = mkstemp(&filename_[0]); + CHECK_NE(-1, fd); + file_.reset(new File(fd, GetFilename())); + } + + ~ScratchFile() { + int unlink_result = unlink(filename_.c_str()); + CHECK_EQ(0, unlink_result); + } + + const std::string& GetFilename() const { + return filename_; + } + + File* GetFile() const { + return file_.get(); + } + + int GetFd() const { + return file_->Fd(); + } + + private: + std::string filename_; + UniquePtr<File> file_; +}; + +class NoopCompilerCallbacks : public CompilerCallbacks { + public: + NoopCompilerCallbacks() {} + virtual ~NoopCompilerCallbacks() {} + virtual bool MethodVerified(verifier::MethodVerifier* verifier) { + return true; + } + virtual void ClassRejected(ClassReference ref) {} +}; + +class CommonRuntimeTest : public testing::Test { + public: + static void SetEnvironmentVariables(std::string& android_data) { + if (IsHost()) { + // $ANDROID_ROOT is set on the device, but not on the host. + // We need to set this so that icu4c can find its locale data. + std::string root; + const char* android_build_top = getenv("ANDROID_BUILD_TOP"); + if (android_build_top != nullptr) { + root += android_build_top; + } else { + // Not set by build server, so default to current directory + char* cwd = getcwd(nullptr, 0); + setenv("ANDROID_BUILD_TOP", cwd, 1); + root += cwd; + free(cwd); + } +#if defined(__linux__) + root += "/out/host/linux-x86"; +#elif defined(__APPLE__) + root += "/out/host/darwin-x86"; +#else +#error unsupported OS +#endif + setenv("ANDROID_ROOT", root.c_str(), 1); + setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. + + // Not set by build server, so default + if (getenv("ANDROID_HOST_OUT") == nullptr) { + setenv("ANDROID_HOST_OUT", root.c_str(), 1); + } + } + + // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache + android_data = (IsHost() ? "/tmp/art-data-XXXXXX" : "/data/dalvik-cache/art-data-XXXXXX"); + if (mkdtemp(&android_data[0]) == nullptr) { + PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed"; + } + setenv("ANDROID_DATA", android_data.c_str(), 1); + } + + protected: + static bool IsHost() { + return !kIsTargetBuild; + } + + virtual void SetUp() { + SetEnvironmentVariables(android_data_); + dalvik_cache_.append(android_data_.c_str()); + dalvik_cache_.append("/dalvik-cache"); + int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); + ASSERT_EQ(mkdir_result, 0); + + std::string error_msg; + java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName().c_str(), + GetLibCoreDexFileName().c_str(), &error_msg); + if (java_lang_dex_file_ == nullptr) { + LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "': " + << error_msg << "\n"; + } + boot_class_path_.push_back(java_lang_dex_file_); + + std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); + std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); + + Runtime::Options options; + options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); + options.push_back(std::make_pair("-Xcheck:jni", nullptr)); + options.push_back(std::make_pair(min_heap_string.c_str(), nullptr)); + options.push_back(std::make_pair(max_heap_string.c_str(), nullptr)); + options.push_back(std::make_pair("compilercallbacks", &callbacks_)); + SetUpRuntimeOptions(&options); + if (!Runtime::Create(options, false)) { + LOG(FATAL) << "Failed to create runtime"; + return; + } + runtime_.reset(Runtime::Current()); + class_linker_ = runtime_->GetClassLinker(); + class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); + + // Runtime::Create acquired the mutator_lock_ that is normally given away when we + // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess. + Thread::Current()->TransitionFromRunnableToSuspended(kNative); + + // We're back in native, take the opportunity to initialize well known classes. + WellKnownClasses::Init(Thread::Current()->GetJniEnv()); + + // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread + // pool is created by the runtime. + runtime_->GetHeap()->CreateThreadPool(); + runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test + } + + // Allow subclases such as CommonCompilerTest to add extra options. + virtual void SetUpRuntimeOptions(Runtime::Options *options) {} + + virtual void TearDown() { + const char* android_data = getenv("ANDROID_DATA"); + ASSERT_TRUE(android_data != nullptr); + DIR* dir = opendir(dalvik_cache_.c_str()); + ASSERT_TRUE(dir != nullptr); + dirent* e; + while ((e = readdir(dir)) != nullptr) { + if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) { + continue; + } + std::string filename(dalvik_cache_); + filename.push_back('/'); + filename.append(e->d_name); + int unlink_result = unlink(filename.c_str()); + ASSERT_EQ(0, unlink_result); + } + closedir(dir); + int rmdir_cache_result = rmdir(dalvik_cache_.c_str()); + ASSERT_EQ(0, rmdir_cache_result); + int rmdir_data_result = rmdir(android_data_.c_str()); + ASSERT_EQ(0, rmdir_data_result); + + // icu4c has a fixed 10-element array "gCommonICUDataArray". + // If we run > 10 tests, we fill that array and u_setCommonData fails. + // There's a function to clear the array, but it's not public... + typedef void (*IcuCleanupFn)(); + void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT); + CHECK(sym != nullptr); + IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym); + (*icu_cleanup_fn)(); + + STLDeleteElements(&opened_dex_files_); + + Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test + } + + std::string GetLibCoreDexFileName() { + return GetDexFileName("core-libart"); + } + + std::string GetDexFileName(const std::string& jar_prefix) { + if (IsHost()) { + const char* host_dir = getenv("ANDROID_HOST_OUT"); + CHECK(host_dir != nullptr); + return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str()); + } + return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); + } + + std::string GetTestAndroidRoot() { + if (IsHost()) { + const char* host_dir = getenv("ANDROID_HOST_OUT"); + CHECK(host_dir != nullptr); + return host_dir; + } + return GetAndroidRoot(); + } + + const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(name != nullptr); + std::string filename; + if (IsHost()) { + filename += getenv("ANDROID_HOST_OUT"); + filename += "/framework/"; + } else { + filename += "/data/nativetest/art/"; + } + filename += "art-test-dex-"; + filename += name; + filename += ".jar"; + std::string error_msg; + const DexFile* dex_file = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg); + CHECK(dex_file != nullptr) << "Failed to open '" << filename << "': " << error_msg; + CHECK_EQ(PROT_READ, dex_file->GetPermissions()); + CHECK(dex_file->IsReadOnly()); + opened_dex_files_.push_back(dex_file); + return dex_file; + } + + jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile* dex_file = OpenTestDexFile(dex_name); + CHECK(dex_file != nullptr); + class_linker_->RegisterDexFile(*dex_file); + std::vector<const DexFile*> class_path; + class_path.push_back(dex_file); + ScopedObjectAccessUnchecked soa(Thread::Current()); + ScopedLocalRef<jobject> class_loader_local(soa.Env(), + soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader)); + jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get()); + soa.Self()->SetClassLoaderOverride(soa.Decode<mirror::ClassLoader*>(class_loader_local.get())); + Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path); + return class_loader; + } + + std::string android_data_; + std::string dalvik_cache_; + const DexFile* java_lang_dex_file_; // owned by runtime_ + std::vector<const DexFile*> boot_class_path_; + UniquePtr<Runtime> runtime_; + // Owned by the runtime + ClassLinker* class_linker_; + + private: + NoopCompilerCallbacks callbacks_; + std::vector<const DexFile*> opened_dex_files_; +}; + +// Sets a CheckJni abort hook to catch failures. Note that this will cause CheckJNI to carry on +// rather than aborting, so be careful! +class CheckJniAbortCatcher { + public: + CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) { + vm_->check_jni_abort_hook = Hook; + vm_->check_jni_abort_hook_data = &actual_; + } + + ~CheckJniAbortCatcher() { + vm_->check_jni_abort_hook = nullptr; + vm_->check_jni_abort_hook_data = nullptr; + EXPECT_TRUE(actual_.empty()) << actual_; + } + + void Check(const char* expected_text) { + EXPECT_TRUE(actual_.find(expected_text) != std::string::npos) << "\n" + << "Expected to find: " << expected_text << "\n" + << "In the output : " << actual_; + actual_.clear(); + } + + private: + static void Hook(void* data, const std::string& reason) { + // We use += because when we're hooking the aborts like this, multiple problems can be found. + *reinterpret_cast<std::string*>(data) += reason; + } + + JavaVMExt* vm_; + std::string actual_; + + DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher); +}; + +// TODO: These tests were disabled for portable when we went to having +// MCLinker link LLVM ELF output because we no longer just have code +// blobs in memory. We'll need to dlopen to load and relocate +// temporary output to resurrect these tests. +#define TEST_DISABLED_FOR_PORTABLE() \ + if (kUsePortableCompiler) { \ + printf("WARNING: TEST DISABLED FOR PORTABLE\n"); \ + return; \ + } + +} // namespace art + +namespace std { + +// TODO: isn't gtest supposed to be able to print STL types for itself? +template <typename T> +std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) { + os << ::art::ToString(rhs); + return os; +} + +} // namespace std + +#endif // ART_RUNTIME_COMMON_RUNTIME_TEST_H_ diff --git a/runtime/common_test.h b/runtime/common_test.h deleted file mode 100644 index 9eaec46..0000000 --- a/runtime/common_test.h +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_RUNTIME_COMMON_TEST_H_ -#define ART_RUNTIME_COMMON_TEST_H_ - -#include <dirent.h> -#include <dlfcn.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <fstream> - -#include "../../external/icu4c/common/unicode/uvernum.h" -#include "../compiler/compiler_backend.h" -#include "../compiler/dex/quick/dex_file_to_method_inliner_map.h" -#include "../compiler/dex/verification_results.h" -#include "../compiler/driver/compiler_callbacks_impl.h" -#include "../compiler/driver/compiler_driver.h" -#include "../compiler/driver/compiler_options.h" -#include "base/macros.h" -#include "base/stl_util.h" -#include "base/stringprintf.h" -#include "base/unix_file/fd_file.h" -#include "class_linker.h" -#include "compiler_callbacks.h" -#include "dex_file-inl.h" -#include "entrypoints/entrypoint_utils.h" -#include "gc/heap.h" -#include "gtest/gtest.h" -#include "instruction_set.h" -#include "interpreter/interpreter.h" -#include "mirror/class_loader.h" -#include "oat_file.h" -#include "object_utils.h" -#include "os.h" -#include "runtime.h" -#include "scoped_thread_state_change.h" -#include "ScopedLocalRef.h" -#include "thread.h" -#include "utils.h" -#include "UniquePtr.h" -#include "verifier/method_verifier.h" -#include "verifier/method_verifier-inl.h" -#include "well_known_classes.h" - -namespace art { - -static const byte kBase64Map[256] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT - 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255 -}; - -byte* DecodeBase64(const char* src, size_t* dst_size) { - std::vector<byte> tmp; - uint32_t t = 0, y = 0; - int g = 3; - for (size_t i = 0; src[i] != '\0'; ++i) { - byte c = kBase64Map[src[i] & 0xFF]; - if (c == 255) continue; - // the final = symbols are read and used to trim the remaining bytes - if (c == 254) { - c = 0; - // prevent g < 0 which would potentially allow an overflow later - if (--g < 0) { - *dst_size = 0; - return NULL; - } - } else if (g != 3) { - // we only allow = to be at the end - *dst_size = 0; - return NULL; - } - t = (t << 6) | c; - if (++y == 4) { - tmp.push_back((t >> 16) & 255); - if (g > 1) { - tmp.push_back((t >> 8) & 255); - } - if (g > 2) { - tmp.push_back(t & 255); - } - y = t = 0; - } - } - if (y != 0) { - *dst_size = 0; - return NULL; - } - UniquePtr<byte[]> dst(new byte[tmp.size()]); - if (dst_size != NULL) { - *dst_size = tmp.size(); - } else { - *dst_size = 0; - } - std::copy(tmp.begin(), tmp.end(), dst.get()); - return dst.release(); -} - -class ScratchFile { - public: - ScratchFile() { - filename_ = getenv("ANDROID_DATA"); - filename_ += "/TmpFile-XXXXXX"; - int fd = mkstemp(&filename_[0]); - CHECK_NE(-1, fd); - file_.reset(new File(fd, GetFilename())); - } - - ~ScratchFile() { - int unlink_result = unlink(filename_.c_str()); - CHECK_EQ(0, unlink_result); - } - - const std::string& GetFilename() const { - return filename_; - } - - File* GetFile() const { - return file_.get(); - } - - int GetFd() const { - return file_->Fd(); - } - - private: - std::string filename_; - UniquePtr<File> file_; -}; - -#if defined(__arm__) - -#include <sys/ucontext.h> - -// A signal handler called when have an illegal instruction. We record the fact in -// a global boolean and then increment the PC in the signal context to return to -// the next instruction. We know the instruction is an sdiv (4 bytes long). -static void baddivideinst(int signo, siginfo *si, void *data) { - (void)signo; - (void)si; - struct ucontext *uc = (struct ucontext *)data; - struct sigcontext *sc = &uc->uc_mcontext; - sc->arm_r0 = 0; // set R0 to #0 to signal error - sc->arm_pc += 4; // skip offending instruction -} - -// This is in arch/arm/arm_sdiv.S. It does the following: -// mov r1,#1 -// sdiv r0,r1,r1 -// bx lr -// -// the result will be the value 1 if sdiv is supported. If it is not supported -// a SIGILL signal will be raised and the signal handler (baddivideinst) called. -// The signal handler sets r0 to #0 and then increments pc beyond the failed instruction. -// Thus if the instruction is not supported, the result of this function will be #0 - -extern "C" bool CheckForARMSDIVInstruction(); - -static InstructionSetFeatures GuessInstructionFeatures() { - InstructionSetFeatures f; - - // Uncomment this for processing of /proc/cpuinfo. - if (false) { - // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that - // the kernel puts the appropriate feature flags in here. Sometimes it doesn't. - std::ifstream in("/proc/cpuinfo"); - if (in) { - while (!in.eof()) { - std::string line; - std::getline(in, line); - if (!in.eof()) { - if (line.find("Features") != std::string::npos) { - if (line.find("idivt") != std::string::npos) { - f.SetHasDivideInstruction(true); - } - } - } - in.close(); - } - } else { - LOG(INFO) << "Failed to open /proc/cpuinfo"; - } - } - - // See if have a sdiv instruction. Register a signal handler and try to execute - // an sdiv instruction. If we get a SIGILL then it's not supported. We can't use - // the /proc/cpuinfo method for this because Krait devices don't always put the idivt - // feature in the list. - struct sigaction sa, osa; - sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; - sa.sa_sigaction = baddivideinst; - sigaction(SIGILL, &sa, &osa); - - if (CheckForARMSDIVInstruction()) { - f.SetHasDivideInstruction(true); - } - - // Restore the signal handler. - sigaction(SIGILL, &osa, NULL); - - // Other feature guesses in here. - return f; -} - -#endif - -// Given a set of instruction features from the build, parse it. The -// input 'str' is a comma separated list of feature names. Parse it and -// return the InstructionSetFeatures object. -static InstructionSetFeatures ParseFeatureList(std::string str) { - InstructionSetFeatures result; - typedef std::vector<std::string> FeatureList; - FeatureList features; - Split(str, ',', features); - for (FeatureList::iterator i = features.begin(); i != features.end(); i++) { - std::string feature = Trim(*i); - if (feature == "default") { - // Nothing to do. - } else if (feature == "div") { - // Supports divide instruction. - result.SetHasDivideInstruction(true); - } else if (feature == "nodiv") { - // Turn off support for divide instruction. - result.SetHasDivideInstruction(false); - } else { - LOG(FATAL) << "Unknown instruction set feature: '" << feature << "'"; - } - } - // Others... - return result; -} - -class CommonTest : public testing::Test { - public: - static void MakeExecutable(const std::vector<uint8_t>& code) { - CHECK_NE(code.size(), 0U); - MakeExecutable(&code[0], code.size()); - } - - // Create an OatMethod based on pointers (for unit tests). - OatFile::OatMethod CreateOatMethod(const void* code, - const size_t frame_size_in_bytes, - const uint32_t core_spill_mask, - const uint32_t fp_spill_mask, - const uint8_t* mapping_table, - const uint8_t* vmap_table, - const uint8_t* gc_map) { - const byte* base; - uint32_t code_offset, mapping_table_offset, vmap_table_offset, gc_map_offset; - if (mapping_table == nullptr && vmap_table == nullptr && gc_map == nullptr) { - base = reinterpret_cast<const byte*>(code); // Base of data points at code. - base -= kPointerSize; // Move backward so that code_offset != 0. - code_offset = kPointerSize; - mapping_table_offset = 0; - vmap_table_offset = 0; - gc_map_offset = 0; - } else { - // TODO: 64bit support. - base = nullptr; // Base of data in oat file, ie 0. - code_offset = PointerToLowMemUInt32(code); - mapping_table_offset = PointerToLowMemUInt32(mapping_table); - vmap_table_offset = PointerToLowMemUInt32(vmap_table); - gc_map_offset = PointerToLowMemUInt32(gc_map); - } - return OatFile::OatMethod(base, - code_offset, - frame_size_in_bytes, - core_spill_mask, - fp_spill_mask, - mapping_table_offset, - vmap_table_offset, - gc_map_offset); - } - - void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(method != nullptr); - - const CompiledMethod* compiled_method = nullptr; - if (!method->IsAbstract()) { - mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); - const DexFile& dex_file = *dex_cache->GetDexFile(); - compiled_method = - compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, - method->GetDexMethodIndex())); - } - if (compiled_method != nullptr) { - const std::vector<uint8_t>* code = compiled_method->GetQuickCode(); - if (code == nullptr) { - code = compiled_method->GetPortableCode(); - } - MakeExecutable(*code); - const void* method_code = CompiledMethod::CodePointer(&(*code)[0], - compiled_method->GetInstructionSet()); - LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code; - OatFile::OatMethod oat_method = CreateOatMethod(method_code, - compiled_method->GetFrameSizeInBytes(), - compiled_method->GetCoreSpillMask(), - compiled_method->GetFpSpillMask(), - &compiled_method->GetMappingTable()[0], - &compiled_method->GetVmapTable()[0], - NULL); - oat_method.LinkMethod(method); - method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); - } else { - // No code? You must mean to go into the interpreter. - const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge() - : GetQuickToInterpreterBridge(); - OatFile::OatMethod oat_method = CreateOatMethod(method_code, - kStackAlignment, - 0, - 0, - NULL, - NULL, - NULL); - oat_method.LinkMethod(method); - method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge); - } - // Create bridges to transition between different kinds of compiled bridge. - if (method->GetEntryPointFromPortableCompiledCode() == nullptr) { - method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge()); - } else { - CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr); - method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge()); - method->SetIsPortableCompiled(); - } - } - - static void MakeExecutable(const void* code_start, size_t code_length) { - CHECK(code_start != NULL); - CHECK_NE(code_length, 0U); - uintptr_t data = reinterpret_cast<uintptr_t>(code_start); - uintptr_t base = RoundDown(data, kPageSize); - uintptr_t limit = RoundUp(data + code_length, kPageSize); - uintptr_t len = limit - base; - int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC); - CHECK_EQ(result, 0); - - // Flush instruction cache - // Only uses __builtin___clear_cache if GCC >= 4.3.3 -#if GCC_VERSION >= 40303 - __builtin___clear_cache(reinterpret_cast<void*>(base), reinterpret_cast<void*>(base + len)); -#else - LOG(FATAL) << "UNIMPLEMENTED: cache flush"; -#endif - } - - static void SetEnvironmentVariables(std::string& android_data) { - if (IsHost()) { - // $ANDROID_ROOT is set on the device, but not on the host. - // We need to set this so that icu4c can find its locale data. - std::string root; - const char* android_build_top = getenv("ANDROID_BUILD_TOP"); - if (android_build_top != nullptr) { - root += android_build_top; - } else { - // Not set by build server, so default to current directory - char* cwd = getcwd(nullptr, 0); - setenv("ANDROID_BUILD_TOP", cwd, 1); - root += cwd; - free(cwd); - } -#if defined(__linux__) - root += "/out/host/linux-x86"; -#elif defined(__APPLE__) - root += "/out/host/darwin-x86"; -#else -#error unsupported OS -#endif - setenv("ANDROID_ROOT", root.c_str(), 1); - setenv("LD_LIBRARY_PATH", ":", 0); // Required by java.lang.System.<clinit>. - - // Not set by build server, so default - if (getenv("ANDROID_HOST_OUT") == nullptr) { - setenv("ANDROID_HOST_OUT", root.c_str(), 1); - } - } - - // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache - android_data = (IsHost() ? "/tmp/art-data-XXXXXX" : "/data/dalvik-cache/art-data-XXXXXX"); - if (mkdtemp(&android_data[0]) == NULL) { - PLOG(FATAL) << "mkdtemp(\"" << &android_data[0] << "\") failed"; - } - setenv("ANDROID_DATA", android_data.c_str(), 1); - } - - void MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string class_descriptor(DotToDescriptor(class_name)); - Thread* self = Thread::Current(); - SirtRef<mirror::ClassLoader> loader(self, class_loader); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); - CHECK(klass != NULL) << "Class not found " << class_name; - for (size_t i = 0; i < klass->NumDirectMethods(); i++) { - MakeExecutable(klass->GetDirectMethod(i)); - } - for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { - MakeExecutable(klass->GetVirtualMethod(i)); - } - } - - protected: - static bool IsHost() { - return !kIsTargetBuild; - } - - virtual void SetUp() { - SetEnvironmentVariables(android_data_); - dalvik_cache_.append(android_data_.c_str()); - dalvik_cache_.append("/dalvik-cache"); - int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700); - ASSERT_EQ(mkdir_result, 0); - - std::string error_msg; - java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName().c_str(), - GetLibCoreDexFileName().c_str(), &error_msg); - if (java_lang_dex_file_ == NULL) { - LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "': " - << error_msg << "\n"; - } - boot_class_path_.push_back(java_lang_dex_file_); - - std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); - std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); - - // TODO: make selectable - CompilerBackend::Kind compiler_backend = kUsePortableCompiler - ? CompilerBackend::kPortable - : CompilerBackend::kQuick; - - compiler_options_.reset(new CompilerOptions); - verification_results_.reset(new VerificationResults(compiler_options_.get())); - method_inliner_map_.reset(new DexFileToMethodInlinerMap); - callbacks_.reset(new CompilerCallbacksImpl(verification_results_.get(), - method_inliner_map_.get())); - Runtime::Options options; - options.push_back(std::make_pair("compilercallbacks", callbacks_.get())); - options.push_back(std::make_pair("bootclasspath", &boot_class_path_)); - options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL))); - options.push_back(std::make_pair(min_heap_string.c_str(), reinterpret_cast<void*>(NULL))); - options.push_back(std::make_pair(max_heap_string.c_str(), reinterpret_cast<void*>(NULL))); - if (!Runtime::Create(options, false)) { - LOG(FATAL) << "Failed to create runtime"; - return; - } - runtime_.reset(Runtime::Current()); - // Runtime::Create acquired the mutator_lock_ that is normally given away when we - // Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess. - Thread::Current()->TransitionFromRunnableToSuspended(kNative); - { - ScopedObjectAccess soa(Thread::Current()); - ASSERT_TRUE(runtime_.get() != NULL); - class_linker_ = runtime_->GetClassLinker(); - - InstructionSet instruction_set = kNone; - - // Take the default set of instruction features from the build. - InstructionSetFeatures instruction_set_features = - ParseFeatureList(STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES)); - -#if defined(__arm__) - instruction_set = kThumb2; - InstructionSetFeatures runtime_features = GuessInstructionFeatures(); - - // for ARM, do a runtime check to make sure that the features we are passed from - // the build match the features we actually determine at runtime. - ASSERT_EQ(instruction_set_features, runtime_features); -#elif defined(__mips__) - instruction_set = kMips; -#elif defined(__i386__) - instruction_set = kX86; -#elif defined(__x86_64__) - instruction_set = kX86_64; - // TODO: x86_64 compilation support. - runtime_->SetCompilerFilter(Runtime::kInterpretOnly); -#endif - - for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { - Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); - if (!runtime_->HasCalleeSaveMethod(type)) { - runtime_->SetCalleeSaveMethod( - runtime_->CreateCalleeSaveMethod(instruction_set, type), type); - } - } - class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); - timer_.reset(new CumulativeLogger("Compilation times")); - compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), - verification_results_.get(), - method_inliner_map_.get(), - compiler_backend, instruction_set, - instruction_set_features, - true, new CompilerDriver::DescriptorSet, - 2, true, true, timer_.get())); - } - // We typically don't generate an image in unit tests, disable this optimization by default. - compiler_driver_->SetSupportBootImageFixup(false); - - // We're back in native, take the opportunity to initialize well known classes. - WellKnownClasses::Init(Thread::Current()->GetJniEnv()); - // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread - // pool is created by the runtime. - runtime_->GetHeap()->CreateThreadPool(); - runtime_->GetHeap()->VerifyHeap(); // Check for heap corruption before the test - } - - virtual void TearDown() { - const char* android_data = getenv("ANDROID_DATA"); - ASSERT_TRUE(android_data != NULL); - DIR* dir = opendir(dalvik_cache_.c_str()); - ASSERT_TRUE(dir != NULL); - dirent* e; - while ((e = readdir(dir)) != NULL) { - if ((strcmp(e->d_name, ".") == 0) || (strcmp(e->d_name, "..") == 0)) { - continue; - } - std::string filename(dalvik_cache_); - filename.push_back('/'); - filename.append(e->d_name); - int unlink_result = unlink(filename.c_str()); - ASSERT_EQ(0, unlink_result); - } - closedir(dir); - int rmdir_cache_result = rmdir(dalvik_cache_.c_str()); - ASSERT_EQ(0, rmdir_cache_result); - int rmdir_data_result = rmdir(android_data_.c_str()); - ASSERT_EQ(0, rmdir_data_result); - - // icu4c has a fixed 10-element array "gCommonICUDataArray". - // If we run > 10 tests, we fill that array and u_setCommonData fails. - // There's a function to clear the array, but it's not public... - typedef void (*IcuCleanupFn)(); - void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT); - CHECK(sym != NULL); - IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym); - (*icu_cleanup_fn)(); - - compiler_driver_.reset(); - timer_.reset(); - callbacks_.reset(); - method_inliner_map_.reset(); - verification_results_.reset(); - compiler_options_.reset(); - STLDeleteElements(&opened_dex_files_); - - Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test - } - - std::string GetLibCoreDexFileName() { - return GetDexFileName("core-libart"); - } - - std::string GetDexFileName(const std::string& jar_prefix) { - if (IsHost()) { - const char* host_dir = getenv("ANDROID_HOST_OUT"); - CHECK(host_dir != NULL); - return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str()); - } - return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); - } - - std::string GetTestAndroidRoot() { - if (IsHost()) { - const char* host_dir = getenv("ANDROID_HOST_OUT"); - CHECK(host_dir != NULL); - return host_dir; - } - return GetAndroidRoot(); - } - - const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(name != NULL); - std::string filename; - if (IsHost()) { - filename += getenv("ANDROID_HOST_OUT"); - filename += "/framework/"; - } else { - filename += "/data/nativetest/art/"; - } - filename += "art-test-dex-"; - filename += name; - filename += ".jar"; - std::string error_msg; - const DexFile* dex_file = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg); - CHECK(dex_file != NULL) << "Failed to open '" << filename << "': " << error_msg; - CHECK_EQ(PROT_READ, dex_file->GetPermissions()); - CHECK(dex_file->IsReadOnly()); - opened_dex_files_.push_back(dex_file); - return dex_file; - } - - jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile* dex_file = OpenTestDexFile(dex_name); - CHECK(dex_file != NULL); - class_linker_->RegisterDexFile(*dex_file); - std::vector<const DexFile*> class_path; - class_path.push_back(dex_file); - ScopedObjectAccessUnchecked soa(Thread::Current()); - ScopedLocalRef<jobject> class_loader_local(soa.Env(), - soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader)); - jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get()); - soa.Self()->SetClassLoaderOverride(soa.Decode<mirror::ClassLoader*>(class_loader_local.get())); - Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path); - return class_loader; - } - - void CompileClass(mirror::ClassLoader* class_loader, const char* class_name) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string class_descriptor(DotToDescriptor(class_name)); - Thread* self = Thread::Current(); - SirtRef<mirror::ClassLoader> loader(self, class_loader); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); - CHECK(klass != NULL) << "Class not found " << class_name; - for (size_t i = 0; i < klass->NumDirectMethods(); i++) { - CompileMethod(klass->GetDirectMethod(i)); - } - for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { - CompileMethod(klass->GetVirtualMethod(i)); - } - } - - void CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(method != NULL); - TimingLogger timings("CommonTest::CompileMethod", false, false); - timings.StartSplit("CompileOne"); - compiler_driver_->CompileOne(method, timings); - MakeExecutable(method); - timings.EndSplit(); - } - - void CompileDirectMethod(SirtRef<mirror::ClassLoader>& class_loader, const char* class_name, - const char* method_name, const char* signature) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string class_descriptor(DotToDescriptor(class_name)); - Thread* self = Thread::Current(); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); - CHECK(klass != NULL) << "Class not found " << class_name; - mirror::ArtMethod* method = klass->FindDirectMethod(method_name, signature); - CHECK(method != NULL) << "Direct method not found: " - << class_name << "." << method_name << signature; - CompileMethod(method); - } - - void CompileVirtualMethod(SirtRef<mirror::ClassLoader>& class_loader, const char* class_name, - const char* method_name, const char* signature) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string class_descriptor(DotToDescriptor(class_name)); - Thread* self = Thread::Current(); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); - CHECK(klass != NULL) << "Class not found " << class_name; - mirror::ArtMethod* method = klass->FindVirtualMethod(method_name, signature); - CHECK(method != NULL) << "Virtual method not found: " - << class_name << "." << method_name << signature; - CompileMethod(method); - } - - void ReserveImageSpace() { - // Reserve where the image will be loaded up front so that other parts of test set up don't - // accidentally end up colliding with the fixed memory address when we need to load the image. - std::string error_msg; - image_reservation_.reset(MemMap::MapAnonymous("image reservation", - reinterpret_cast<byte*>(ART_BASE_ADDRESS), - (size_t)100 * 1024 * 1024, // 100MB - PROT_NONE, - false /* no need for 4gb flag with fixed mmap*/, - &error_msg)); - CHECK(image_reservation_.get() != nullptr) << error_msg; - } - - void UnreserveImageSpace() { - image_reservation_.reset(); - } - - std::string android_data_; - std::string dalvik_cache_; - const DexFile* java_lang_dex_file_; // owned by runtime_ - std::vector<const DexFile*> boot_class_path_; - UniquePtr<Runtime> runtime_; - // Owned by the runtime - ClassLinker* class_linker_; - UniquePtr<CompilerOptions> compiler_options_; - UniquePtr<VerificationResults> verification_results_; - UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_; - UniquePtr<CompilerCallbacksImpl> callbacks_; - UniquePtr<CompilerDriver> compiler_driver_; - UniquePtr<CumulativeLogger> timer_; - - private: - std::vector<const DexFile*> opened_dex_files_; - UniquePtr<MemMap> image_reservation_; -}; - -// Sets a CheckJni abort hook to catch failures. Note that this will cause CheckJNI to carry on -// rather than aborting, so be careful! -class CheckJniAbortCatcher { - public: - CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) { - vm_->check_jni_abort_hook = Hook; - vm_->check_jni_abort_hook_data = &actual_; - } - - ~CheckJniAbortCatcher() { - vm_->check_jni_abort_hook = NULL; - vm_->check_jni_abort_hook_data = NULL; - EXPECT_TRUE(actual_.empty()) << actual_; - } - - void Check(const char* expected_text) { - EXPECT_TRUE(actual_.find(expected_text) != std::string::npos) << "\n" - << "Expected to find: " << expected_text << "\n" - << "In the output : " << actual_; - actual_.clear(); - } - - private: - static void Hook(void* data, const std::string& reason) { - // We use += because when we're hooking the aborts like this, multiple problems can be found. - *reinterpret_cast<std::string*>(data) += reason; - } - - JavaVMExt* vm_; - std::string actual_; - - DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher); -}; - -// TODO: These tests were disabled for portable when we went to having -// MCLinker link LLVM ELF output because we no longer just have code -// blobs in memory. We'll need to dlopen to load and relocate -// temporary output to resurrect these tests. -#define TEST_DISABLED_FOR_PORTABLE() \ - if (kUsePortableCompiler) { \ - printf("WARNING: TEST DISABLED FOR PORTABLE\n"); \ - return; \ - } - -} // namespace art - -namespace std { - -// TODO: isn't gtest supposed to be able to print STL types for itself? -template <typename T> -std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) { - os << ::art::ToString(rhs); - return os; -} - -} // namespace std - -#endif // ART_RUNTIME_COMMON_TEST_H_ diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 543a7b0..9b6859a 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -17,11 +17,11 @@ #include "dex_file.h" #include "UniquePtr.h" -#include "common_test.h" +#include "common_runtime_test.h" namespace art { -class DexFileTest : public CommonTest {}; +class DexFileTest : public CommonRuntimeTest {}; TEST_F(DexFileTest, Open) { ScopedObjectAccess soa(Thread::Current()); @@ -29,6 +29,77 @@ TEST_F(DexFileTest, Open) { ASSERT_TRUE(dex != NULL); } +static const byte kBase64Map[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT + 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255 +}; + +static inline byte* DecodeBase64(const char* src, size_t* dst_size) { + std::vector<byte> tmp; + uint32_t t = 0, y = 0; + int g = 3; + for (size_t i = 0; src[i] != '\0'; ++i) { + byte c = kBase64Map[src[i] & 0xFF]; + if (c == 255) continue; + // the final = symbols are read and used to trim the remaining bytes + if (c == 254) { + c = 0; + // prevent g < 0 which would potentially allow an overflow later + if (--g < 0) { + *dst_size = 0; + return nullptr; + } + } else if (g != 3) { + // we only allow = to be at the end + *dst_size = 0; + return nullptr; + } + t = (t << 6) | c; + if (++y == 4) { + tmp.push_back((t >> 16) & 255); + if (g > 1) { + tmp.push_back((t >> 8) & 255); + } + if (g > 2) { + tmp.push_back(t & 255); + } + y = t = 0; + } + } + if (y != 0) { + *dst_size = 0; + return nullptr; + } + UniquePtr<byte[]> dst(new byte[tmp.size()]); + if (dst_size != nullptr) { + *dst_size = tmp.size(); + } else { + *dst_size = 0; + } + std::copy(tmp.begin(), tmp.end(), dst.get()); + return dst.release(); +} + // Although this is the same content logically as the Nested test dex, // the DexFileHeader test is sensitive to subtle changes in the // contents due to the checksum etc, so we embed the exact input here. diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc index 2941db6..5e2d89e 100644 --- a/runtime/dex_method_iterator_test.cc +++ b/runtime/dex_method_iterator_test.cc @@ -16,11 +16,11 @@ #include "dex_method_iterator.h" -#include "common_test.h" +#include "common_runtime_test.h" namespace art { -class DexMethodIteratorTest : public CommonTest { +class DexMethodIteratorTest : public CommonRuntimeTest { public: const DexFile* OpenDexFile(const std::string& partial_filename) { std::string dfn = GetDexFileName(partial_filename); diff --git a/runtime/entrypoints/math_entrypoints_test.cc b/runtime/entrypoints/math_entrypoints_test.cc index ca8b931..b69aeb4 100644 --- a/runtime/entrypoints/math_entrypoints_test.cc +++ b/runtime/entrypoints/math_entrypoints_test.cc @@ -16,12 +16,13 @@ #include "math_entrypoints.h" -#include "common_test.h" #include <limits> +#include "common_runtime_test.h" + namespace art { -class MathEntrypointsTest : public CommonTest {}; +class MathEntrypointsTest : public CommonRuntimeTest {}; TEST_F(MathEntrypointsTest, DoubleToLong) { EXPECT_EQ(std::numeric_limits<int64_t>::max(), art_d2l(1.85e19)); diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc index 910a817..3653b37 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -15,10 +15,10 @@ */ #include "class_linker.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "dex_file.h" #include "gtest/gtest.h" -#include "leb128_encoder.h" +#include "leb128.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" @@ -32,10 +32,10 @@ namespace art { -class ExceptionTest : public CommonTest { +class ExceptionTest : public CommonRuntimeTest { protected: virtual void SetUp() { - CommonTest::SetUp(); + CommonRuntimeTest::SetUp(); ScopedObjectAccess soa(Thread::Current()); SirtRef<mirror::ClassLoader> class_loader( @@ -77,7 +77,7 @@ class ExceptionTest : public CommonTest { method_f_ = my_klass_->FindVirtualMethod("f", "()I"); ASSERT_TRUE(method_f_ != NULL); method_f_->SetFrameSizeInBytes(kStackAlignment); - method_f_->SetEntryPointFromQuickCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); + method_f_->SetEntryPointFromQuickCompiledCode(&fake_code_[sizeof(code_size)]); method_f_->SetMappingTable(&fake_mapping_data_.GetData()[0]); method_f_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]); method_f_->SetNativeGcMap(&fake_gc_map_[0]); @@ -85,7 +85,7 @@ class ExceptionTest : public CommonTest { method_g_ = my_klass_->FindVirtualMethod("g", "(I)V"); ASSERT_TRUE(method_g_ != NULL); method_g_->SetFrameSizeInBytes(kStackAlignment); - method_g_->SetEntryPointFromQuickCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); + method_g_->SetEntryPointFromQuickCompiledCode(&fake_code_[sizeof(code_size)]); method_g_->SetMappingTable(&fake_mapping_data_.GetData()[0]); method_g_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]); method_g_->SetNativeGcMap(&fake_gc_map_[0]); diff --git a/runtime/gc/accounting/space_bitmap_test.cc b/runtime/gc/accounting/space_bitmap_test.cc index e70704f..ba4e2ac 100644 --- a/runtime/gc/accounting/space_bitmap_test.cc +++ b/runtime/gc/accounting/space_bitmap_test.cc @@ -16,20 +16,18 @@ #include "space_bitmap.h" -#include "common_test.h" +#include <stdint.h> + +#include "common_runtime_test.h" #include "globals.h" #include "space_bitmap-inl.h" #include "UniquePtr.h" -#include <stdint.h> - namespace art { namespace gc { namespace accounting { -class SpaceBitmapTest : public CommonTest { - public: -}; +class SpaceBitmapTest : public CommonRuntimeTest {}; TEST_F(SpaceBitmapTest, Init) { byte* heap_begin = reinterpret_cast<byte*>(0x10000000); diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc index 4b86339..07e5088 100644 --- a/runtime/gc/heap_test.cc +++ b/runtime/gc/heap_test.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "common_test.h" +#include "common_runtime_test.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/space_bitmap-inl.h" #include "mirror/class-inl.h" @@ -25,7 +25,7 @@ namespace art { namespace gc { -class HeapTest : public CommonTest {}; +class HeapTest : public CommonRuntimeTest {}; TEST_F(HeapTest, ClearGrowthLimit) { Heap* heap = Runtime::Current()->GetHeap(); diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index 41077f3..f17d6f4 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -19,19 +19,19 @@ #include "zygote_space.h" -#include "common_test.h" +#include <stdint.h> + +#include "common_runtime_test.h" #include "globals.h" #include "UniquePtr.h" #include "mirror/array-inl.h" #include "mirror/object-inl.h" -#include <stdint.h> - namespace art { namespace gc { namespace space { -class SpaceTest : public CommonTest { +class SpaceTest : public CommonRuntimeTest { public: void AddSpace(ContinuousSpace* space) { // For RosAlloc, revoke the thread local runs before moving onto a diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc index 78e1992..9b42e59 100644 --- a/runtime/indirect_reference_table_test.cc +++ b/runtime/indirect_reference_table_test.cc @@ -14,15 +14,14 @@ * limitations under the License. */ -#include "common_test.h" - #include "indirect_reference_table.h" + +#include "common_runtime_test.h" #include "mirror/object-inl.h" namespace art { -class IndirectReferenceTableTest : public CommonTest { -}; +class IndirectReferenceTableTest : public CommonRuntimeTest {}; static void CheckDump(IndirectReferenceTable* irt, size_t num_objects, size_t num_unique) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc index c328245..8987127 100644 --- a/runtime/intern_table_test.cc +++ b/runtime/intern_table_test.cc @@ -16,13 +16,13 @@ #include "intern_table.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "mirror/object.h" #include "sirt_ref.h" namespace art { -class InternTableTest : public CommonTest {}; +class InternTableTest : public CommonRuntimeTest {}; TEST_F(InternTableTest, Intern) { ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 76aa734..37fb2db 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -263,7 +263,7 @@ static mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa) // See if the override ClassLoader is set for gtests. class_loader = soa.Self()->GetClassLoaderOverride(); if (class_loader != nullptr) { - // If so, CommonTest should have set UseCompileTimeClassPath. + // If so, CommonCompilerTest should have set UseCompileTimeClassPath. CHECK(Runtime::Current()->UseCompileTimeClassPath()); return class_loader; } diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc index 63bc45c..28408d2 100644 --- a/runtime/jni_internal_test.cc +++ b/runtime/jni_internal_test.cc @@ -20,7 +20,7 @@ #include <cfloat> #include <cmath> -#include "common_test.h" +#include "common_compiler_test.h" #include "invoke_arg_array_builder.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" @@ -31,10 +31,11 @@ namespace art { -class JniInternalTest : public CommonTest { +// TODO: Convert to CommonRuntimeTest. Currently MakeExecutable is used. +class JniInternalTest : public CommonCompilerTest { protected: virtual void SetUp() { - CommonTest::SetUp(); + CommonCompilerTest::SetUp(); vm_ = Runtime::Current()->GetJavaVM(); @@ -75,7 +76,7 @@ class JniInternalTest : public CommonTest { virtual void TearDown() { CleanUpJniEnv(); - CommonTest::TearDown(); + CommonCompilerTest::TearDown(); } jclass GetPrimitiveClass(char descriptor) { @@ -2070,7 +2071,7 @@ TEST_F(JniInternalTest, DetachCurrentThread) { jint err = vm_->DetachCurrentThread(); EXPECT_EQ(JNI_ERR, err); - vm_->AttachCurrentThread(&env_, NULL); // need attached thread for CommonTest::TearDown + vm_->AttachCurrentThread(&env_, NULL); // need attached thread for CommonRuntimeTest::TearDown } } // namespace art diff --git a/runtime/leb128.h b/runtime/leb128.h index 7a7d38d..0e80fe2 100644 --- a/runtime/leb128.h +++ b/runtime/leb128.h @@ -112,6 +112,88 @@ static inline uint32_t SignedLeb128Size(int32_t data) { return (x * 37) >> 8; } +static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) { + uint8_t out = value & 0x7f; + value >>= 7; + while (value != 0) { + *dest++ = out | 0x80; + out = value & 0x7f; + value >>= 7; + } + *dest++ = out; + return dest; +} + +static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) { + uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6; + uint8_t out = value & 0x7f; + while (extra_bits != 0u) { + *dest++ = out | 0x80; + value >>= 7; + out = value & 0x7f; + extra_bits >>= 7; + } + *dest++ = out; + return dest; +} + +// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format. +class Leb128EncodingVector { + public: + Leb128EncodingVector() { + } + + void Reserve(uint32_t size) { + data_.reserve(size); + } + + void PushBackUnsigned(uint32_t value) { + uint8_t out = value & 0x7f; + value >>= 7; + while (value != 0) { + data_.push_back(out | 0x80); + out = value & 0x7f; + value >>= 7; + } + data_.push_back(out); + } + + template<typename It> + void InsertBackUnsigned(It cur, It end) { + for (; cur != end; ++cur) { + PushBackUnsigned(*cur); + } + } + + void PushBackSigned(int32_t value) { + uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6; + uint8_t out = value & 0x7f; + while (extra_bits != 0u) { + data_.push_back(out | 0x80); + value >>= 7; + out = value & 0x7f; + extra_bits >>= 7; + } + data_.push_back(out); + } + + template<typename It> + void InsertBackSigned(It cur, It end) { + for (; cur != end; ++cur) { + PushBackSigned(*cur); + } + } + + const std::vector<uint8_t>& GetData() const { + return data_; + } + + private: + std::vector<uint8_t> data_; + + DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector); +}; + } // namespace art #endif // ART_RUNTIME_LEB128_H_ diff --git a/runtime/leb128_test.cc b/runtime/leb128_test.cc new file mode 100644 index 0000000..d75d5c2 --- /dev/null +++ b/runtime/leb128_test.cc @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "leb128.h" + +#include "gtest/gtest.h" +#include "base/histogram-inl.h" + +namespace art { + +struct DecodeUnsignedLeb128TestCase { + uint32_t decoded; + uint8_t leb128_data[5]; +}; + +static DecodeUnsignedLeb128TestCase uleb128_tests[] = { + {0, {0, 0, 0, 0, 0}}, + {1, {1, 0, 0, 0, 0}}, + {0x7F, {0x7F, 0, 0, 0, 0}}, + {0x80, {0x80, 1, 0, 0, 0}}, + {0x81, {0x81, 1, 0, 0, 0}}, + {0xFF, {0xFF, 1, 0, 0, 0}}, + {0x4000, {0x80, 0x80, 1, 0, 0}}, + {0x4001, {0x81, 0x80, 1, 0, 0}}, + {0x4081, {0x81, 0x81, 1, 0, 0}}, + {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0x7F, 0}}, + {0xFFFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xF}}, +}; + +struct DecodeSignedLeb128TestCase { + int32_t decoded; + uint8_t leb128_data[5]; +}; + +static DecodeSignedLeb128TestCase sleb128_tests[] = { + {0, {0, 0, 0, 0, 0}}, + {1, {1, 0, 0, 0, 0}}, + {0x3F, {0x3F, 0, 0, 0, 0}}, + {0x40, {0xC0, 0 /* sign bit */, 0, 0, 0}}, + {0x41, {0xC1, 0 /* sign bit */, 0, 0, 0}}, + {0x80, {0x80, 1, 0, 0, 0}}, + {0xFF, {0xFF, 1, 0, 0, 0}}, + {0x1FFF, {0xFF, 0x3F, 0, 0, 0}}, + {0x2000, {0x80, 0xC0, 0 /* sign bit */, 0, 0}}, + {0x2001, {0x81, 0xC0, 0 /* sign bit */, 0, 0}}, + {0x2081, {0x81, 0xC1, 0 /* sign bit */, 0, 0}}, + {0x4000, {0x80, 0x80, 1, 0, 0}}, + {0x0FFFFF, {0xFF, 0xFF, 0x3F, 0, 0}}, + {0x100000, {0x80, 0x80, 0xC0, 0 /* sign bit */, 0}}, + {0x100001, {0x81, 0x80, 0xC0, 0 /* sign bit */, 0}}, + {0x100081, {0x81, 0x81, 0xC0, 0 /* sign bit */, 0}}, + {0x104081, {0x81, 0x81, 0xC1, 0 /* sign bit */, 0}}, + {0x200000, {0x80, 0x80, 0x80, 1, 0}}, + {0x7FFFFFF, {0xFF, 0xFF, 0xFF, 0x3F, 0}}, + {0x8000000, {0x80, 0x80, 0x80, 0xC0, 0 /* sign bit */}}, + {0x8000001, {0x81, 0x80, 0x80, 0xC0, 0 /* sign bit */}}, + {0x8000081, {0x81, 0x81, 0x80, 0xC0, 0 /* sign bit */}}, + {0x8004081, {0x81, 0x81, 0x81, 0xC0, 0 /* sign bit */}}, + {0x8204081, {0x81, 0x81, 0x81, 0xC1, 0 /* sign bit */}}, + {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0 /* sign bit */}}, + {0x10000000, {0x80, 0x80, 0x80, 0x80, 1}}, + {0x7FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0x7}}, + {-1, {0x7F, 0, 0, 0, 0}}, + {-2, {0x7E, 0, 0, 0, 0}}, + {-0x3F, {0x41, 0, 0, 0, 0}}, + {-0x40, {0x40, 0, 0, 0, 0}}, + {-0x41, {0xBF, 0x7F, 0, 0, 0}}, + {-0x80, {0x80, 0x7F, 0, 0, 0}}, + {-0x81, {0xFF, 0x7E, 0, 0, 0}}, + {-0x00002000, {0x80, 0x40, 0, 0, 0}}, + {-0x00002001, {0xFF, 0xBF, 0x7F, 0, 0}}, + {-0x00100000, {0x80, 0x80, 0x40, 0, 0}}, + {-0x00100001, {0xFF, 0xFF, 0xBF, 0x7F, 0}}, + {-0x08000000, {0x80, 0x80, 0x80, 0x40, 0}}, + {-0x08000001, {0xFF, 0xFF, 0xFF, 0xBF, 0x7F}}, + {-0x20000000, {0x80, 0x80, 0x80, 0x80, 0x7E}}, + {(-1) << 31, {0x80, 0x80, 0x80, 0x80, 0x78}}, +}; + +TEST(Leb128Test, UnsignedSinglesVector) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + Leb128EncodingVector builder; + builder.PushBackUnsigned(uleb128_tests[i].decoded); + EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), builder.GetData().size()); + const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; + for (size_t j = 0; j < 5; ++j) { + if (j < builder.GetData().size()) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; + } + } + EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST(Leb128Test, UnsignedSingles) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + uint8_t encoded_data[5]; + uint8_t* end = EncodeUnsignedLeb128(encoded_data, uleb128_tests[i].decoded); + size_t data_size = static_cast<size_t>(end - encoded_data); + EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), data_size); + const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < 5; ++j) { + if (j < data_size) { + EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; + } + } + EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST(Leb128Test, UnsignedStreamVector) { + // Encode a number of entries. + Leb128EncodingVector builder; + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + builder.PushBackUnsigned(uleb128_tests[i].decoded); + } + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(builder.GetData().size(), + static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0])); +} + +TEST(Leb128Test, UnsignedStream) { + // Encode a number of entries. + uint8_t encoded_data[5 * arraysize(uleb128_tests)]; + uint8_t* end = encoded_data; + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + end = EncodeUnsignedLeb128(end, uleb128_tests[i].decoded); + } + size_t data_size = static_cast<size_t>(end - encoded_data); + const uint8_t* encoded_data_ptr = encoded_data; + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data)); +} + +TEST(Leb128Test, SignedSinglesVector) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + Leb128EncodingVector builder; + builder.PushBackSigned(sleb128_tests[i].decoded); + EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), builder.GetData().size()); + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; + for (size_t j = 0; j < 5; ++j) { + if (j < builder.GetData().size()) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; + } + } + EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST(Leb128Test, SignedSingles) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + uint8_t encoded_data[5]; + uint8_t* end = EncodeSignedLeb128(encoded_data, sleb128_tests[i].decoded); + size_t data_size = static_cast<size_t>(end - encoded_data); + EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), data_size); + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < 5; ++j) { + if (j < data_size) { + EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; + } + } + EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST(Leb128Test, SignedStreamVector) { + // Encode a number of entries. + Leb128EncodingVector builder; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + builder.PushBackSigned(sleb128_tests[i].decoded); + } + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(builder.GetData().size(), + static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0])); +} + +TEST(Leb128Test, SignedStream) { + // Encode a number of entries. + uint8_t encoded_data[5 * arraysize(sleb128_tests)]; + uint8_t* end = encoded_data; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + end = EncodeSignedLeb128(end, sleb128_tests[i].decoded); + } + size_t data_size = static_cast<size_t>(end - encoded_data); + const uint8_t* encoded_data_ptr = encoded_data; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data)); +} + +TEST(Leb128Test, Speed) { + UniquePtr<Histogram<uint64_t> > enc_hist(new Histogram<uint64_t>("Leb128EncodeSpeedTest", 5)); + UniquePtr<Histogram<uint64_t> > dec_hist(new Histogram<uint64_t>("Leb128DecodeSpeedTest", 5)); + Leb128EncodingVector builder; + // Push back 1024 chunks of 1024 values measuring encoding speed. + uint64_t last_time = NanoTime(); + for (size_t i = 0; i < 1024; i++) { + for (size_t j = 0; j < 1024; j++) { + builder.PushBackUnsigned((i * 1024) + j); + } + uint64_t cur_time = NanoTime(); + enc_hist->AddValue(cur_time - last_time); + last_time = cur_time; + } + // Verify encoding and measure decode speed. + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; + last_time = NanoTime(); + for (size_t i = 0; i < 1024; i++) { + for (size_t j = 0; j < 1024; j++) { + EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), (i * 1024) + j); + } + uint64_t cur_time = NanoTime(); + dec_hist->AddValue(cur_time - last_time); + last_time = cur_time; + } + + Histogram<uint64_t>::CumulativeData enc_data; + enc_hist->CreateHistogram(&enc_data); + enc_hist->PrintConfidenceIntervals(std::cout, 0.99, enc_data); + + Histogram<uint64_t>::CumulativeData dec_data; + dec_hist->CreateHistogram(&dec_data); + dec_hist->PrintConfidenceIntervals(std::cout, 0.99, dec_data); +} + +} // namespace art diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 6bed224..fef1f9b 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -14,20 +14,21 @@ * limitations under the License. */ -#include "class_linker.h" -#include "common_test.h" #include "dex_cache.h" + +#include <stdio.h> + +#include "class_linker.h" +#include "common_runtime_test.h" #include "gc/heap.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "sirt_ref.h" -#include <stdio.h> - namespace art { namespace mirror { -class DexCacheTest : public CommonTest {}; +class DexCacheTest : public CommonRuntimeTest {}; TEST_F(DexCacheTest, Open) { ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 34fb15e..5dfd007 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -25,7 +25,7 @@ #include "class-inl.h" #include "class_linker.h" #include "class_linker-inl.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "dex_file.h" #include "entrypoints/entrypoint_utils.h" #include "gc/accounting/card_table-inl.h" @@ -40,7 +40,7 @@ namespace art { namespace mirror { -class ObjectTest : public CommonTest { +class ObjectTest : public CommonRuntimeTest { protected: void AssertString(int32_t expected_utf16_length, const char* utf8_in, diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 16fbd94..3229039 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -14,14 +14,13 @@ * limitations under the License. */ -#include "common_test.h" - #include "reference_table.h" +#include "common_runtime_test.h" + namespace art { -class ReferenceTableTest : public CommonTest { -}; +class ReferenceTableTest : public CommonRuntimeTest {}; TEST_F(ReferenceTableTest, Basics) { ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/runtime_test.cc b/runtime/runtime_test.cc index d53b4a6..5b881e5 100644 --- a/runtime/runtime_test.cc +++ b/runtime/runtime_test.cc @@ -17,11 +17,11 @@ #include "runtime.h" #include "UniquePtr.h" -#include "common_test.h" +#include "common_runtime_test.h" namespace art { -class RuntimeTest : public CommonTest {}; +class RuntimeTest : public CommonRuntimeTest {}; TEST_F(RuntimeTest, ParsedOptions) { void* test_vfprintf = reinterpret_cast<void*>(0xa); diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index c6f0e92..c1a1ad7 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -14,12 +14,12 @@ * limitations under the License. */ +#include "thread_pool.h" #include <string> #include "atomic.h" -#include "common_test.h" -#include "thread_pool.h" +#include "common_runtime_test.h" namespace art { @@ -49,7 +49,7 @@ class CountTask : public Task { const bool verbose_; }; -class ThreadPoolTest : public CommonTest { +class ThreadPoolTest : public CommonRuntimeTest { public: static int32_t num_threads; }; diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc index 9dc7b44..44e24fb 100644 --- a/runtime/transaction_test.cc +++ b/runtime/transaction_test.cc @@ -14,17 +14,17 @@ * limitations under the License. */ -#include "common_test.h" +#include "transaction.h" + +#include "common_runtime_test.h" #include "invoke_arg_array_builder.h" #include "mirror/array-inl.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" -#include "transaction.h" namespace art { -class TransactionTest : public CommonTest { -}; +class TransactionTest : public CommonRuntimeTest {}; TEST_F(TransactionTest, Object_class) { ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/utils.cc b/runtime/utils.cc index 68d8417..df1ab94 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -1232,7 +1232,7 @@ bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) { execv(program, &args[0]); - *error_msg = StringPrintf("Failed to execv(%s): %s", command_line.c_str(), strerror(errno)); + PLOG(FATAL) << "Failed to execv(" << command_line << ")"; return false; } else { if (pid == -1) { diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc index 0d237e2..d804f6a 100644 --- a/runtime/utils_test.cc +++ b/runtime/utils_test.cc @@ -14,7 +14,9 @@ * limitations under the License. */ -#include "common_test.h" +#include "utils.h" + +#include "common_runtime_test.h" #include "mirror/array.h" #include "mirror/array-inl.h" #include "mirror/object-inl.h" @@ -22,15 +24,13 @@ #include "mirror/string.h" #include "scoped_thread_state_change.h" #include "sirt_ref.h" -#include "utils.h" namespace art { std::string PrettyArguments(const char* signature); std::string PrettyReturnType(const char* signature); -class UtilsTest : public CommonTest { -}; +class UtilsTest : public CommonRuntimeTest {}; TEST_F(UtilsTest, PrettyDescriptor_ArrayReferences) { EXPECT_EQ("java.lang.Class[]", PrettyDescriptor("[Ljava/lang/Class;")); @@ -362,9 +362,7 @@ TEST_F(UtilsTest, ExecSuccess) { EXPECT_EQ(0U, error_msg.size()) << error_msg; } -// TODO: Disabled due to hang tearing down CommonTest. -// Renable after splitting into RuntimeTest and CompilerTest. -TEST_F(UtilsTest, DISABLED_ExecError) { +TEST_F(UtilsTest, ExecError) { std::vector<std::string> command; command.push_back("bogus"); std::string error_msg; diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index ffa2455..9dca7f5 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -14,18 +14,19 @@ * limitations under the License. */ +#include "method_verifier.h" + #include <stdio.h> #include "UniquePtr.h" #include "class_linker.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "dex_file.h" -#include "method_verifier.h" namespace art { namespace verifier { -class MethodVerifierTest : public CommonTest { +class MethodVerifierTest : public CommonRuntimeTest { protected: void VerifyClass(const std::string& descriptor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc index dc320be..1a64c00 100644 --- a/runtime/verifier/reg_type_test.cc +++ b/runtime/verifier/reg_type_test.cc @@ -15,16 +15,17 @@ */ #include "reg_type.h" -#include "reg_type_cache-inl.h" -#include "base/casts.h" -#include "common_test.h" #include <set> +#include "base/casts.h" +#include "common_runtime_test.h" +#include "reg_type_cache-inl.h" + namespace art { namespace verifier { -class RegTypeTest : public CommonTest {}; +class RegTypeTest : public CommonRuntimeTest {}; TEST_F(RegTypeTest, ConstLoHi) { // Tests creating primitive types types. @@ -335,7 +336,7 @@ TEST_F(RegTypeTest, Primitives) { } -class RegTypeReferenceTest : public CommonTest {}; +class RegTypeReferenceTest : public CommonRuntimeTest {}; TEST_F(RegTypeReferenceTest, JavalangObjectImprecise) { // Tests matching precisions. A reference type that was created precise doesn't diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc index 16394b0..0bf6767 100644 --- a/runtime/zip_archive_test.cc +++ b/runtime/zip_archive_test.cc @@ -22,12 +22,12 @@ #include <zlib.h> #include "UniquePtr.h" -#include "common_test.h" +#include "common_runtime_test.h" #include "os.h" namespace art { -class ZipArchiveTest : public CommonTest {}; +class ZipArchiveTest : public CommonRuntimeTest {}; TEST_F(ZipArchiveTest, FindAndExtract) { std::string error_msg; |