Create libart-gtest for common runtime and compiler gtest routines.
Rename CompilerCallbacksImpl that is quick compiler specific.
Rename trace clock source constants to not use the overloaded profiler term.
Change-Id: I4aac4bdc7e7850c68335f81e59a390133b54e933
ART_TEST_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
endif
+include $(CLEAR_VARS)
+LOCAL_MODULE := libart-gtest
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := cc
+LOCAL_CFLAGS := $(ART_TARGET_CFLAGS)
+LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
+LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler
+LOCAL_SHARED_LIBRARIES := libcutils libartd libartd-compiler libdl
+LOCAL_STATIC_LIBRARIES += libgtest_libc++
+LOCAL_CLANG := $(ART_TARGET_CLANG)
+LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
+include external/libcxx/libcxx.mk
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libart-gtest
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := cc
+LOCAL_CFLAGS := $(ART_HOST_CFLAGS)
+LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
+LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler
+LOCAL_SHARED_LIBRARIES := libartd libartd-compiler
+LOCAL_STATIC_LIBRARIES := libcutils
+ifneq ($(WITHOUT_HOST_CLANG),true)
+ # GCC host compiled tests fail with this linked, presumably due to destructors that run.
+ LOCAL_STATIC_LIBRARIES += libgtest_libc++_host
+endif
+LOCAL_LDLIBS += -ldl -lpthread
+LOCAL_MULTILIB := both
+LOCAL_CLANG := $(ART_HOST_CLANG)
+LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
+include external/libcxx/libcxx.mk
+include $(BUILD_HOST_SHARED_LIBRARY)
+
# Variables holding collections of gtest pre-requisits used to run a number of gtests.
ART_TEST_HOST_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
ART_TEST_HOST_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
LOCAL_MODULE_TAGS := tests
endif
LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION)
- LOCAL_SRC_FILES := $$(art_gtest_filename) runtime/common_runtime_test.cc
+ LOCAL_SRC_FILES := $$(art_gtest_filename)
LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime $$(art_gtest_extra_c_includes)
- LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries)
+ LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries) libart-gtest
- # LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
- # LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
+ LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+ LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
# Mac OS linker doesn't understand --export-dynamic.
ifneq ($$(HOST_OS)-$$(art_target_or_host),darwin-host)
$$(eval $$(call set-target-local-clang-vars))
$$(eval $$(call set-target-local-cflags-vars,debug))
LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils libvixl
- LOCAL_STATIC_LIBRARIES += libgtest_libc++
LOCAL_MODULE_PATH_32 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_32)
LOCAL_MODULE_PATH_64 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_64)
LOCAL_MULTILIB := both
LOCAL_CFLAGS += $$(ART_HOST_CFLAGS) $$(ART_HOST_DEBUG_CFLAGS)
LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libz-host
LOCAL_STATIC_LIBRARIES += libcutils libvixl
- ifneq ($$(WITHOUT_HOST_CLANG),true)
- # GCC host compiled tests fail with this linked, presumably due to destructors that run.
- LOCAL_STATIC_LIBRARIES += libgtest_libc++_host
- endif
LOCAL_LDLIBS += -lpthread -ldl
LOCAL_IS_HOST_MODULE := true
LOCAL_MULTILIB := both
dex/verification_results.cc \
dex/vreg_analysis.cc \
dex/ssa_transformation.cc \
+ dex/quick_compiler_callbacks.cc \
driver/compiler_driver.cc \
driver/dex_compilation_unit.cc \
jni/quick/arm/calling_convention_arm.cc \
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "common_compiler_test.h"
+
+#if defined(__arm__)
+#include <sys/ucontext.h>
+#endif
+#include <fstream>
+
+#include "class_linker.h"
+#include "compiled_method.h"
+#include "dex/quick_compiler_callbacks.h"
+#include "dex/verification_results.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "driver/compiler_driver.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "interpreter/interpreter.h"
+#include "mirror/art_method.h"
+#include "mirror/dex_cache.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
+#include "utils.h"
+
+namespace art {
+
+// Normally the ClassLinker supplies this.
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+
+#if defined(__arm__)
+// 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) {
+ UNUSED(signo);
+ UNUSED(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, nullptr);
+
+ // 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;
+}
+
+CommonCompilerTest::CommonCompilerTest() {}
+CommonCompilerTest::~CommonCompilerTest() {}
+
+OatFile::OatMethod CommonCompilerTest::CreateOatMethod(const void* code, const uint8_t* gc_map) {
+ CHECK(code != nullptr);
+ const byte* base;
+ uint32_t code_offset, gc_map_offset;
+ if (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;
+ gc_map_offset = 0;
+ } else {
+ // TODO: 64bit support.
+ base = nullptr; // Base of data in oat file, ie 0.
+ code_offset = PointerToLowMemUInt32(code);
+ gc_map_offset = PointerToLowMemUInt32(gc_map);
+ }
+ return OatFile::OatMethod(base, code_offset, gc_map_offset);
+}
+
+void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) {
+ 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();
+ const void* code_ptr;
+ if (code != nullptr) {
+ uint32_t code_size = code->size();
+ CHECK_NE(0u, code_size);
+ const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
+ uint32_t vmap_table_offset = vmap_table.empty() ? 0u
+ : sizeof(OatQuickMethodHeader) + vmap_table.size();
+ const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
+ uint32_t mapping_table_offset = mapping_table.empty() ? 0u
+ : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size();
+ OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
+ compiled_method->GetFrameSizeInBytes(),
+ compiled_method->GetCoreSpillMask(),
+ compiled_method->GetFpSpillMask(), code_size);
+
+ header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
+ std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
+ size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
+ size_t code_offset = compiled_method->AlignCode(size - code_size);
+ size_t padding = code_offset - (size - code_size);
+ chunk->reserve(padding + size);
+ chunk->resize(sizeof(method_header));
+ memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
+ chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
+ chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
+ chunk->insert(chunk->begin(), padding, 0);
+ chunk->insert(chunk->end(), code->begin(), code->end());
+ CHECK_EQ(padding + size, chunk->size());
+ code_ptr = &(*chunk)[code_offset];
+ } else {
+ code = compiled_method->GetPortableCode();
+ code_ptr = &(*code)[0];
+ }
+ MakeExecutable(code_ptr, code->size());
+ const void* method_code = CompiledMethod::CodePointer(code_ptr,
+ compiled_method->GetInstructionSet());
+ LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ } else {
+ // No code? You must mean to go into the interpreter.
+ // Or the generic JNI...
+ if (!method->IsNative()) {
+ const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge()
+ : GetQuickToInterpreterBridge();
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ } else {
+ const void* method_code = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ }
+ }
+ // 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();
+ }
+}
+
+void CommonCompilerTest::MakeExecutable(const void* code_start, size_t code_length) {
+ CHECK(code_start != nullptr);
+ 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
+ // Only warn if not Intel as Intel doesn't have cache flush instructions.
+#if !defined(__i386__) && !defined(__x86_64__)
+ LOG(WARNING) << "UNIMPLEMENTED: cache flush";
+#endif
+#endif
+}
+
+void CommonCompilerTest::MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name) {
+ std::string class_descriptor(DotToDescriptor(class_name));
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
+ mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
+ CHECK(klass != nullptr) << "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));
+ }
+}
+
+void CommonCompilerTest::SetUp() {
+ CommonRuntimeTest::SetUp();
+ {
+ ScopedObjectAccess soa(Thread::Current());
+
+ InstructionSet instruction_set = kRuntimeISA;
+
+ // Take the default set of instruction features from the build.
+ InstructionSetFeatures instruction_set_features =
+ ParseFeatureList(Runtime::GetDefaultInstructionSetFeatures());
+
+#if defined(__arm__)
+ 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_LE(instruction_set_features, runtime_features);
+#endif
+
+ runtime_->SetInstructionSet(instruction_set);
+ for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+ Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+ if (!runtime_->HasCalleeSaveMethod(type)) {
+ runtime_->SetCalleeSaveMethod(
+ runtime_->CreateCalleeSaveMethod(type), type);
+ }
+ }
+
+ // TODO: make selectable
+ Compiler::Kind compiler_kind
+ = (kUsePortableCompiler) ? Compiler::kPortable : Compiler::kQuick;
+ timer_.reset(new CumulativeLogger("Compilation times"));
+ compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
+ verification_results_.get(),
+ method_inliner_map_.get(),
+ compiler_kind, 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);
+}
+
+void CommonCompilerTest::SetUpRuntimeOptions(RuntimeOptions* options) {
+ CommonRuntimeTest::SetUpRuntimeOptions(options);
+
+ compiler_options_.reset(new CompilerOptions);
+ verification_results_.reset(new VerificationResults(compiler_options_.get()));
+ method_inliner_map_.reset(new DexFileToMethodInlinerMap);
+ callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
+ method_inliner_map_.get()));
+ options->push_back(std::make_pair("compilercallbacks", callbacks_.get()));
+}
+
+void CommonCompilerTest::TearDown() {
+ timer_.reset();
+ compiler_driver_.reset();
+ callbacks_.reset();
+ method_inliner_map_.reset();
+ verification_results_.reset();
+ compiler_options_.reset();
+
+ CommonRuntimeTest::TearDown();
+}
+
+void CommonCompilerTest::CompileClass(mirror::ClassLoader* class_loader, const char* class_name) {
+ std::string class_descriptor(DotToDescriptor(class_name));
+ Thread* self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
+ mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
+ CHECK(klass != nullptr) << "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 CommonCompilerTest::CompileMethod(mirror::ArtMethod* method) {
+ CHECK(method != nullptr);
+ TimingLogger timings("CommonTest::CompileMethod", false, false);
+ TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
+ compiler_driver_->CompileOne(method, &timings);
+ TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
+ MakeExecutable(method);
+}
+
+void CommonCompilerTest::CompileDirectMethod(Handle<mirror::ClassLoader> class_loader,
+ const char* class_name, const char* method_name,
+ const char* signature) {
+ 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 != nullptr) << "Class not found " << class_name;
+ mirror::ArtMethod* method = klass->FindDirectMethod(method_name, signature);
+ CHECK(method != nullptr) << "Direct method not found: "
+ << class_name << "." << method_name << signature;
+ CompileMethod(method);
+}
+
+void CommonCompilerTest::CompileVirtualMethod(Handle<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 != nullptr) << "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 CommonCompilerTest::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 CommonCompilerTest::UnreserveImageSpace() {
+ image_reservation_.reset();
+}
+
+} // namespace art
#ifndef ART_COMPILER_COMMON_COMPILER_TEST_H_
#define ART_COMPILER_COMMON_COMPILER_TEST_H_
-#include "compiler.h"
-#include "compiler_callbacks.h"
+#include <list>
+#include <vector>
+
#include "common_runtime_test.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
-#include "dex/verification_results.h"
-#include "driver/compiler_callbacks_impl.h"
-#include "driver/compiler_driver.h"
-#include "driver/compiler_options.h"
+#include "oat_file.h"
namespace art {
+namespace mirror {
+ class ClassLoader;
+} // namespace mirror
-#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 inline void baddivideinst(int signo, siginfo *si, void *data) {
- UNUSED(signo);
- UNUSED(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 inline 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, nullptr);
-
- // 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 inline 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 CompilerDriver;
+class CompilerOptions;
+class CumulativeLogger;
+class DexFileToMethodInlinerMap;
+class VerificationResults;
-// Normally the ClassLinker supplies this.
-extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+template<class T> class Handle;
class CommonCompilerTest : public CommonRuntimeTest {
public:
- // Create an OatMethod based on pointers (for unit tests).
- OatFile::OatMethod CreateOatMethod(const void* code,
- const uint8_t* gc_map) {
- CHECK(code != nullptr);
- const byte* base;
- uint32_t code_offset, gc_map_offset;
- if (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;
- gc_map_offset = 0;
- } else {
- // TODO: 64bit support.
- base = nullptr; // Base of data in oat file, ie 0.
- code_offset = PointerToLowMemUInt32(code);
- gc_map_offset = PointerToLowMemUInt32(gc_map);
- }
- return OatFile::OatMethod(base,
- code_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();
- const void* code_ptr;
- if (code != nullptr) {
- uint32_t code_size = code->size();
- CHECK_NE(0u, code_size);
- const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
- uint32_t vmap_table_offset = vmap_table.empty() ? 0u
- : sizeof(OatQuickMethodHeader) + vmap_table.size();
- const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
- uint32_t mapping_table_offset = mapping_table.empty() ? 0u
- : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size();
- OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
- compiled_method->GetFrameSizeInBytes(),
- compiled_method->GetCoreSpillMask(),
- compiled_method->GetFpSpillMask(), code_size);
-
- header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
- std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
- size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
- size_t code_offset = compiled_method->AlignCode(size - code_size);
- size_t padding = code_offset - (size - code_size);
- chunk->reserve(padding + size);
- chunk->resize(sizeof(method_header));
- memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
- chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
- chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
- chunk->insert(chunk->begin(), padding, 0);
- chunk->insert(chunk->end(), code->begin(), code->end());
- CHECK_EQ(padding + size, chunk->size());
- code_ptr = &(*chunk)[code_offset];
- } else {
- code = compiled_method->GetPortableCode();
- code_ptr = &(*code)[0];
- }
- MakeExecutable(code_ptr, code->size());
- const void* method_code = CompiledMethod::CodePointer(code_ptr,
- compiled_method->GetInstructionSet());
- LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
- OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
- oat_method.LinkMethod(method);
- method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
- } else {
- // No code? You must mean to go into the interpreter.
- // Or the generic JNI...
- if (!method->IsNative()) {
- const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge()
- : GetQuickToInterpreterBridge();
- OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
- oat_method.LinkMethod(method);
- method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
- } else {
- const void* method_code = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+ CommonCompilerTest();
+ ~CommonCompilerTest();
- OatFile::OatMethod oat_method = CreateOatMethod(method_code, nullptr);
- oat_method.LinkMethod(method);
- method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
- }
- }
- // 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();
- }
- }
+ // Create an OatMethod based on pointers (for unit tests).
+ OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map);
- static void MakeExecutable(const void* code_start, size_t code_length) {
- CHECK(code_start != nullptr);
- 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);
+ void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // 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(WARNING) << "UNIMPLEMENTED: cache flush";
-#endif
- }
+ static void MakeExecutable(const void* code_start, size_t code_length);
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();
- StackHandleScope<1> hs(self);
- Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
- mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
- CHECK(klass != nullptr) << "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));
- }
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual void SetUp() {
- CommonRuntimeTest::SetUp();
- {
- ScopedObjectAccess soa(Thread::Current());
-
- InstructionSet instruction_set = kNone;
-
- // Take the default set of instruction features from the build.
- InstructionSetFeatures instruction_set_features =
- ParseFeatureList(Runtime::GetDefaultInstructionSetFeatures());
-
-#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_LE(instruction_set_features, runtime_features);
-#elif defined(__aarch64__)
- instruction_set = kArm64;
-#elif defined(__mips__)
- instruction_set = kMips;
-#elif defined(__i386__)
- instruction_set = kX86;
-#elif defined(__x86_64__)
- instruction_set = kX86_64;
-#endif
-
- runtime_->SetInstructionSet(instruction_set);
- for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
- Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
- if (!runtime_->HasCalleeSaveMethod(type)) {
- runtime_->SetCalleeSaveMethod(
- runtime_->CreateCalleeSaveMethod(type), type);
- }
- }
-
- // TODO: make selectable
- Compiler::Kind compiler_kind
- = (kUsePortableCompiler) ? Compiler::kPortable : Compiler::kQuick;
- timer_.reset(new CumulativeLogger("Compilation times"));
- compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
- verification_results_.get(),
- method_inliner_map_.get(),
- compiler_kind, 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);
- }
-
- virtual void SetUpRuntimeOptions(Runtime::Options *options) {
- CommonRuntimeTest::SetUpRuntimeOptions(options);
-
- 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()));
- options->push_back(std::make_pair("compilercallbacks", callbacks_.get()));
- }
+ virtual void SetUp();
- virtual void TearDown() {
- timer_.reset();
- compiler_driver_.reset();
- callbacks_.reset();
- method_inliner_map_.reset();
- verification_results_.reset();
- compiler_options_.reset();
+ virtual void SetUpRuntimeOptions(RuntimeOptions *options);
- CommonRuntimeTest::TearDown();
- }
+ virtual void TearDown();
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();
- StackHandleScope<1> hs(self);
- Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
- mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
- CHECK(klass != nullptr) << "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));
- }
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK(method != nullptr);
- TimingLogger timings("CommonTest::CompileMethod", false, false);
- TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
- compiler_driver_->CompileOne(method, &timings);
- TimingLogger::ScopedTiming t2("MakeExecutable", &timings);
- MakeExecutable(method);
- }
+ void CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void CompileDirectMethod(Handle<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 != nullptr) << "Class not found " << class_name;
- mirror::ArtMethod* method = klass->FindDirectMethod(method_name, signature);
- CHECK(method != nullptr) << "Direct method not found: "
- << class_name << "." << method_name << signature;
- CompileMethod(method);
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void CompileVirtualMethod(Handle<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 != nullptr) << "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);
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- 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 ReserveImageSpace();
- void UnreserveImageSpace() {
- image_reservation_.reset();
- }
+ void UnreserveImageSpace();
std::unique_ptr<CompilerOptions> compiler_options_;
std::unique_ptr<VerificationResults> verification_results_;
std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
- std::unique_ptr<CompilerCallbacksImpl> callbacks_;
+ std::unique_ptr<CompilerCallbacks> callbacks_;
std::unique_ptr<CompilerDriver> compiler_driver_;
std::unique_ptr<CumulativeLogger> timer_;
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "quick_compiler_callbacks.h"
+
+#include "quick/dex_file_to_method_inliner_map.h"
+#include "verifier/method_verifier-inl.h"
+#include "verification_results.h"
+
+namespace art {
+
+bool QuickCompilerCallbacks::MethodVerified(verifier::MethodVerifier* verifier) {
+ bool result = verification_results_->ProcessVerifiedMethod(verifier);
+ if (result) {
+ MethodReference ref = verifier->GetMethodReference();
+ method_inliner_map_->GetMethodInliner(ref.dex_file)
+ ->AnalyseMethodCode(verifier);
+ }
+ return result;
+}
+
+void QuickCompilerCallbacks::ClassRejected(ClassReference ref) {
+ verification_results_->AddRejectedClass(ref);
+}
+
+} // namespace art
* limitations under the License.
*/
-#ifndef ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
-#define ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
+#ifndef ART_COMPILER_DEX_QUICK_COMPILER_CALLBACKS_H_
+#define ART_COMPILER_DEX_QUICK_COMPILER_CALLBACKS_H_
#include "compiler_callbacks.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
-#include "verifier/method_verifier-inl.h"
namespace art {
-class CompilerCallbacksImpl FINAL : public CompilerCallbacks {
+class VerificationResults;
+class DexFileToMethodInlinerMap;
+
+class QuickCompilerCallbacks FINAL : public CompilerCallbacks {
public:
- CompilerCallbacksImpl(VerificationResults* verification_results,
- DexFileToMethodInlinerMap* method_inliner_map)
+ QuickCompilerCallbacks(VerificationResults* verification_results,
+ DexFileToMethodInlinerMap* method_inliner_map)
: verification_results_(verification_results),
method_inliner_map_(method_inliner_map) {
CHECK(verification_results != nullptr);
CHECK(method_inliner_map != nullptr);
}
- ~CompilerCallbacksImpl() { }
+ ~QuickCompilerCallbacks() { }
bool MethodVerified(verifier::MethodVerifier* verifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE;
- void ClassRejected(ClassReference ref) OVERRIDE {
- verification_results_->AddRejectedClass(ref);
- }
+
+ void ClassRejected(ClassReference ref) OVERRIDE;
private:
VerificationResults* const verification_results_;
DexFileToMethodInlinerMap* const method_inliner_map_;
};
-inline bool CompilerCallbacksImpl::MethodVerified(verifier::MethodVerifier* verifier) {
- bool result = verification_results_->ProcessVerifiedMethod(verifier);
- if (result) {
- MethodReference ref = verifier->GetMethodReference();
- method_inliner_map_->GetMethodInliner(ref.dex_file)
- ->AnalyseMethodCode(verifier);
- }
- return result;
-}
-
} // namespace art
-#endif // ART_COMPILER_DRIVER_COMPILER_CALLBACKS_IMPL_H_
+#endif // ART_COMPILER_DEX_QUICK_COMPILER_CALLBACKS_H_
#include "dex_file.h"
#include "gc/heap.h"
#include "mirror/art_method-inl.h"
-#include "mirror/class.h"
#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "handle_scope-inl.h"
+#include "scoped_thread_state_change.h"
namespace art {
#include "elf_file.h"
+#include "base/stringprintf.h"
#include "common_compiler_test.h"
#include "oat.h"
+#include "utils.h"
namespace art {
#include <string>
#include <vector>
+#include "base/unix_file/fd_file.h"
#include "common_compiler_test.h"
-#include "compiler/elf_fixup.h"
-#include "compiler/image_writer.h"
-#include "compiler/oat_writer.h"
+#include "elf_fixup.h"
#include "gc/space/image_space.h"
+#include "image_writer.h"
#include "implicit_check_options.h"
#include "lock_word.h"
#include "mirror/object-inl.h"
+#include "oat_writer.h"
+#include "scoped_thread_state_change.h"
#include "signal_catcher.h"
#include "utils.h"
#include "vector_output_stream.h"
// Remove the reservation of the memory for use to load the image.
UnreserveImageSpace();
- Runtime::Options options;
+ RuntimeOptions options;
std::string image("-Ximage:");
image.append(image_location.GetFilename());
options.push_back(std::make_pair(image.c_str(), reinterpret_cast<void*>(NULL)));
#include <vector>
#include "handle_scope.h"
+#include "primitive.h"
#include "thread.h"
#include "utils/managed_register.h"
*/
#include "common_compiler_test.h"
-#include "compiler/compiler.h"
-#include "compiler/oat_writer.h"
+#include "compiler.h"
+#include "dex/verification_results.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "dex/quick_compiler_callbacks.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "implicit_check_options.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
-#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
#include "oat_file-inl.h"
+#include "oat_writer.h"
+#include "scoped_thread_state_change.h"
#include "vector_output_stream.h"
namespace art {
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()));
+ callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
+ method_inliner_map_.get()));
timer_.reset(new CumulativeLogger("Compilation times"));
compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
verification_results_.get(),
#include "locations.h"
#include "offsets.h"
+#include "primitive.h"
#include "utils/allocation.h"
#include "utils/arena_bit_vector.h"
#include "utils/growable_array.h"
#define ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_H_
#include "base/macros.h"
+#include "primitive.h"
#include "utils/growable_array.h"
namespace art {
#include "file_output_stream.h"
#include "vector_output_stream.h"
+#include "base/unix_file/fd_file.h"
#include "base/logging.h"
#include "buffered_output_stream.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
#include "dex/pass_driver_me_opts.h"
#include "dex/verification_results.h"
-#include "driver/compiler_callbacks_impl.h"
+#include "dex/quick_compiler_callbacks.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "elf_fixup.h"
class Dex2Oat {
public:
static bool Create(Dex2Oat** p_dex2oat,
- const Runtime::Options& runtime_options,
+ const RuntimeOptions& runtime_options,
const CompilerOptions& compiler_options,
Compiler::Kind compiler_kind,
InstructionSet instruction_set,
CHECK(method_inliner_map != nullptr);
}
- bool CreateRuntime(const Runtime::Options& runtime_options, InstructionSet instruction_set)
+ bool CreateRuntime(const RuntimeOptions& runtime_options, InstructionSet instruction_set)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
if (!Runtime::Create(runtime_options, false)) {
LOG(ERROR) << "Failed to create runtime";
timings.StartTiming("dex2oat Setup");
LOG(INFO) << CommandLine();
- Runtime::Options runtime_options;
+ RuntimeOptions runtime_options;
std::vector<const DexFile*> boot_class_path;
if (boot_image_option.empty()) {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
std::unique_ptr<VerificationResults> verification_results(new VerificationResults(
compiler_options.get()));
DexFileToMethodInlinerMap method_inliner_map;
- CompilerCallbacksImpl callbacks(verification_results.get(), &method_inliner_map);
+ QuickCompilerCallbacks callbacks(verification_results.get(), &method_inliner_map);
runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
runtime_options.push_back(
std::make_pair("imageinstructionset",
return EXIT_SUCCESS;
}
- Runtime::Options options;
+ RuntimeOptions options;
std::string image_option;
std::string oat_option;
std::string boot_image_option;
#include "base/stringprintf.h"
#include "elf_utils.h"
#include "elf_file.h"
+#include "gc/space/image_space.h"
#include "image.h"
#include "instruction_set.h"
#include "mirror/art_field.h"
}
// Set up the runtime
- Runtime::Options options;
+ RuntimeOptions options;
NoopCompilerCallbacks callbacks;
options.push_back(std::make_pair("compilercallbacks", &callbacks));
std::string img = "-Ximage:" + image_location;
}
// Set up the runtime
- Runtime::Options options;
+ RuntimeOptions options;
NoopCompilerCallbacks callbacks;
options.push_back(std::make_pair("compilercallbacks", &callbacks));
std::string img = "-Ximage:" + image_location;
// Interpreter entrypoints.
extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result);
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
// Portable entrypoints.
extern "C" void art_portable_resolution_trampoline(mirror::ArtMethod*);
* limitations under the License.
*/
+#include <cstdio>
+
#include "common_runtime_test.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/string-inl.h"
-
-#include <cstdio>
+#include "scoped_thread_state_change.h"
namespace art {
}
}
- void SetUpRuntimeOptions(Runtime::Options *options) OVERRIDE {
+ void SetUpRuntimeOptions(RuntimeOptions *options) OVERRIDE {
// Use a smaller heap
for (std::pair<std::string, const void*>& pair : *options) {
if (pair.first.find("-Xmx") == 0) {
#include "common_runtime_test.h"
#include "mirror/object_array-inl.h"
#include "thread_pool.h"
+#include "thread-inl.h"
namespace art {
class CheckWaitTask : public Task {
#include "mutex.h"
#include "common_runtime_test.h"
+#include "thread-inl.h"
namespace art {
*/
#include "scoped_flock.h"
-#include "common_runtime_test.h"
-#include "gtest/gtest.h"
+#include "common_runtime_test.h"
namespace art {
#include "mirror/stack_trace_element.h"
#include "mirror/string-inl.h"
#include "handle_scope-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
* limitations under the License.
*/
+#include "common_runtime_test.h"
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <ScopedLocalRef.h>
+
+#include "../../external/icu/icu4c/source/common/unicode/uvernum.h"
#include "base/logging.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.h"
+#include "gc/heap.h"
#include "gtest/gtest.h"
+#include "jni_internal.h"
+#include "mirror/class_loader.h"
+#include "noop_compiler_callbacks.h"
+#include "os.h"
+#include "runtime-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+#include "well_known_classes.h"
int main(int argc, char **argv) {
art::InitLogging(argv);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
+
+namespace art {
+
+ScratchFile::ScratchFile() {
+ // ANDROID_DATA needs to be set
+ CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
+ "Are you subclassing RuntimeTest?";
+ filename_ = getenv("ANDROID_DATA");
+ filename_ += "/TmpFile-XXXXXX";
+ int fd = mkstemp(&filename_[0]);
+ CHECK_NE(-1, fd);
+ file_.reset(new File(fd, GetFilename()));
+}
+
+ScratchFile::ScratchFile(const ScratchFile& other, const char* suffix) {
+ filename_ = other.GetFilename();
+ filename_ += suffix;
+ int fd = open(filename_.c_str(), O_RDWR | O_CREAT, 0666);
+ CHECK_NE(-1, fd);
+ file_.reset(new File(fd, GetFilename()));
+}
+
+ScratchFile::ScratchFile(File* file) {
+ CHECK(file != NULL);
+ filename_ = file->GetPath();
+ file_.reset(file);
+}
+
+ScratchFile::~ScratchFile() {
+ Unlink();
+}
+
+int ScratchFile::GetFd() const {
+ return file_->Fd();
+}
+
+void ScratchFile::Unlink() {
+ if (!OS::FileExists(filename_.c_str())) {
+ return;
+ }
+ int unlink_result = unlink(filename_.c_str());
+ CHECK_EQ(0, unlink_result);
+}
+
+CommonRuntimeTest::CommonRuntimeTest() {}
+CommonRuntimeTest::~CommonRuntimeTest() {}
+
+void CommonRuntimeTest::SetEnvironmentVariables(std::string& android_data) {
+ if (IsHost()) {
+ // $ANDROID_ROOT is set on the device, but not necessarily on the host.
+ // But it needs to be set so that icu4c can find its locale data.
+ const char* android_root_from_env = getenv("ANDROID_ROOT");
+ if (android_root_from_env == nullptr) {
+ // Use ANDROID_HOST_OUT for ANDROID_ROOT if it is set.
+ const char* android_host_out = getenv("ANDROID_HOST_OUT");
+ if (android_host_out != nullptr) {
+ setenv("ANDROID_ROOT", android_host_out, 1);
+ } else {
+ // Build it from ANDROID_BUILD_TOP or cwd
+ 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", getenv("ANDROID_ROOT"), 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);
+}
+
+const DexFile* CommonRuntimeTest::LoadExpectSingleDexFile(const char* location) {
+ std::vector<const DexFile*> dex_files;
+ std::string error_msg;
+ if (!DexFile::Open(location, location, &error_msg, &dex_files)) {
+ LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
+ return nullptr;
+ } else {
+ CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location;
+ return dex_files[0];
+ }
+}
+
+void CommonRuntimeTest::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_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
+ 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));
+
+ callbacks_.reset(new NoopCompilerCallbacks());
+
+ RuntimeOptions 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_.get()));
+ 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());
+ class_linker_->RunRootClinits();
+
+ // 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
+}
+
+void CommonRuntimeTest::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) << dlerror();
+ 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 CommonRuntimeTest::GetLibCoreDexFileName() {
+ return GetDexFileName("core-libart");
+}
+
+std::string CommonRuntimeTest::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 CommonRuntimeTest::GetTestAndroidRoot() {
+ if (IsHost()) {
+ const char* host_dir = getenv("ANDROID_HOST_OUT");
+ CHECK(host_dir != nullptr);
+ return host_dir;
+ }
+ return GetAndroidRoot();
+}
+
+std::vector<const DexFile*> CommonRuntimeTest::OpenTestDexFiles(const char* name) {
+ CHECK(name != nullptr);
+ std::string filename;
+ if (IsHost()) {
+ filename += getenv("ANDROID_HOST_OUT");
+ filename += "/framework/";
+ } else {
+ filename += "/data/nativetest/art/";
+ }
+ filename += "art-gtest-";
+ filename += name;
+ filename += ".jar";
+ std::string error_msg;
+ std::vector<const DexFile*> dex_files;
+ bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files);
+ CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
+ for (const DexFile* dex_file : dex_files) {
+ CHECK_EQ(PROT_READ, dex_file->GetPermissions());
+ CHECK(dex_file->IsReadOnly());
+ }
+ opened_dex_files_.insert(opened_dex_files_.end(), dex_files.begin(), dex_files.end());
+ return dex_files;
+}
+
+const DexFile* CommonRuntimeTest::OpenTestDexFile(const char* name) {
+ std::vector<const DexFile*> vector = OpenTestDexFiles(name);
+ EXPECT_EQ(1U, vector.size());
+ return vector[0];
+}
+
+jobject CommonRuntimeTest::LoadDex(const char* dex_name) {
+ std::vector<const DexFile*> dex_files = OpenTestDexFiles(dex_name);
+ CHECK_NE(0U, dex_files.size());
+ for (const DexFile* dex_file : dex_files) {
+ class_linker_->RegisterDexFile(*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, dex_files);
+ return class_loader;
+}
+
+CheckJniAbortCatcher::CheckJniAbortCatcher() : vm_(Runtime::Current()->GetJavaVM()) {
+ vm_->check_jni_abort_hook = Hook;
+ vm_->check_jni_abort_hook_data = &actual_;
+}
+
+CheckJniAbortCatcher::~CheckJniAbortCatcher() {
+ vm_->check_jni_abort_hook = nullptr;
+ vm_->check_jni_abort_hook_data = nullptr;
+ EXPECT_TRUE(actual_.empty()) << actual_;
+}
+
+void CheckJniAbortCatcher::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();
+}
+
+void CheckJniAbortCatcher::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;
+}
+
+} // namespace art
+
+namespace std {
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) {
+os << ::art::ToString(rhs);
+return os;
+}
+
+} // namespace std
#ifndef ART_RUNTIME_COMMON_RUNTIME_TEST_H_
#define ART_RUNTIME_COMMON_RUNTIME_TEST_H_
-#include <dirent.h>
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fstream>
-#include <memory>
-
-#include "../../external/icu/icu4c/source/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 "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 "noop_compiler_callbacks.h"
-#include "oat_file.h"
-#include "object_utils.h"
+#include <gtest/gtest.h>
+#include <jni.h>
+
+#include <string>
+
+#include "base/mutex.h"
+#include "globals.h"
#include "os.h"
-#include "runtime.h"
-#include "scoped_thread_state_change.h"
-#include "ScopedLocalRef.h"
-#include "thread.h"
-#include "utils.h"
-#include "verifier/method_verifier.h"
-#include "verifier/method_verifier-inl.h"
-#include "well_known_classes.h"
namespace art {
+class ClassLinker;
+class CompilerCallbacks;
+class DexFile;
+class JavaVMExt;
+class Runtime;
+typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
+
class ScratchFile {
public:
- ScratchFile() {
- // ANDROID_DATA needs to be set
- CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
- "Are you subclassing RuntimeTest?";
- filename_ = getenv("ANDROID_DATA");
- filename_ += "/TmpFile-XXXXXX";
- int fd = mkstemp(&filename_[0]);
- CHECK_NE(-1, fd);
- file_.reset(new File(fd, GetFilename()));
- }
+ ScratchFile();
- ScratchFile(const ScratchFile& other, const char* suffix) {
- filename_ = other.GetFilename();
- filename_ += suffix;
- int fd = open(filename_.c_str(), O_RDWR | O_CREAT, 0666);
- CHECK_NE(-1, fd);
- file_.reset(new File(fd, GetFilename()));
- }
+ ScratchFile(const ScratchFile& other, const char* suffix);
- explicit ScratchFile(File* file) {
- CHECK(file != NULL);
- filename_ = file->GetPath();
- file_.reset(file);
- }
+ explicit ScratchFile(File* file);
- ~ScratchFile() {
- Unlink();
- }
+ ~ScratchFile();
const std::string& GetFilename() const {
return filename_;
return file_.get();
}
- int GetFd() const {
- return file_->Fd();
- }
+ int GetFd() const;
- void Unlink() {
- if (!OS::FileExists(filename_.c_str())) {
- return;
- }
- int unlink_result = unlink(filename_.c_str());
- CHECK_EQ(0, unlink_result);
- }
+ void Unlink();
private:
std::string filename_;
class CommonRuntimeTest : public testing::Test {
public:
- static void SetEnvironmentVariables(std::string& android_data) {
- if (IsHost()) {
- // $ANDROID_ROOT is set on the device, but not necessarily on the host.
- // But it needs to be set so that icu4c can find its locale data.
- const char* android_root_from_env = getenv("ANDROID_ROOT");
- if (android_root_from_env == nullptr) {
- // Use ANDROID_HOST_OUT for ANDROID_ROOT if it is set.
- const char* android_host_out = getenv("ANDROID_HOST_OUT");
- if (android_host_out != nullptr) {
- setenv("ANDROID_ROOT", android_host_out, 1);
- } else {
- // Build it from ANDROID_BUILD_TOP or cwd
- 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", getenv("ANDROID_ROOT"), 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);
- }
+ static void SetEnvironmentVariables(std::string& android_data);
+
+ CommonRuntimeTest();
+ ~CommonRuntimeTest();
protected:
static bool IsHost() {
return !kIsTargetBuild;
}
- const DexFile* LoadExpectSingleDexFile(const char* location) {
- std::vector<const DexFile*> dex_files;
- std::string error_msg;
- if (!DexFile::Open(location, location, &error_msg, &dex_files)) {
- LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
- return nullptr;
- } else {
- CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location;
- return dex_files[0];
- }
- }
+ const DexFile* LoadExpectSingleDexFile(const char* location);
- 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_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
- 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());
- class_linker_->RunRootClinits();
-
- // 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
- }
+ virtual void SetUp();
// 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) << dlerror();
- 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
- }
+ virtual void SetUpRuntimeOptions(RuntimeOptions* options) {}
- std::string GetLibCoreDexFileName() {
- return GetDexFileName("core-libart");
- }
+ virtual void TearDown();
- 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 GetLibCoreDexFileName();
- std::string GetTestAndroidRoot() {
- if (IsHost()) {
- const char* host_dir = getenv("ANDROID_HOST_OUT");
- CHECK(host_dir != nullptr);
- return host_dir;
- }
- return GetAndroidRoot();
- }
+ std::string GetDexFileName(const std::string& jar_prefix);
+
+ std::string GetTestAndroidRoot();
std::vector<const DexFile*> OpenTestDexFiles(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-gtest-";
- filename += name;
- filename += ".jar";
- std::string error_msg;
- std::vector<const DexFile*> dex_files;
- bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files);
- CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
- for (const DexFile* dex_file : dex_files) {
- CHECK_EQ(PROT_READ, dex_file->GetPermissions());
- CHECK(dex_file->IsReadOnly());
- }
- opened_dex_files_.insert(opened_dex_files_.end(), dex_files.begin(), dex_files.end());
- return dex_files;
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const DexFile* OpenTestDexFile(const char* name)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- std::vector<const DexFile*> vector = OpenTestDexFiles(name);
- EXPECT_EQ(1U, vector.size());
- return vector[0];
- }
+ const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- std::vector<const DexFile*> dex_files = OpenTestDexFiles(dex_name);
- CHECK_NE(0U, dex_files.size());
- for (const DexFile* dex_file : dex_files) {
- class_linker_->RegisterDexFile(*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, dex_files);
- return class_loader;
- }
+ jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
std::string android_data_;
std::string dalvik_cache_;
ClassLinker* class_linker_;
private:
- NoopCompilerCallbacks callbacks_;
+ std::unique_ptr<CompilerCallbacks> callbacks_;
std::vector<const DexFile*> opened_dex_files_;
};
// 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();
- ~CheckJniAbortCatcher() {
- vm_->check_jni_abort_hook = nullptr;
- vm_->check_jni_abort_hook_data = nullptr;
- EXPECT_TRUE(actual_.empty()) << actual_;
- }
+ ~CheckJniAbortCatcher();
- 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();
- }
+ void Check(const char* expected_text);
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;
- }
+ static void Hook(void* data, const std::string& reason);
JavaVMExt* vm_;
std::string actual_;
// 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;
-}
+std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs);
} // namespace std
#include <memory>
+#include "base/stl_util.h"
+#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
+#include "os.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
#include "dex_file_verifier.h"
-#include <memory>
+#include "sys/mman.h"
#include "zlib.h"
+#include <memory>
-#include "common_runtime_test.h"
+#include "base/unix_file/fd_file.h"
#include "base/macros.h"
+#include "common_runtime_test.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
#include "dex_method_iterator.h"
+#include "base/stl_util.h"
#include "common_runtime_test.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, kPointerSize);
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, rosalloc_runs, kPointerSize);
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, rosalloc_runs, thread_local_alloc_stack_top,
- kPointerSize * gc::allocator::RosAlloc::kNumThreadLocalSizeBrackets);
+ kPointerSize * kNumRosAllocThreadLocalSizeBrackets);
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_top, thread_local_alloc_stack_end,
kPointerSize);
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, kPointerSize);
#include "base/logging.h"
#include "globals.h"
#include "mem_map.h"
+#include "thread.h"
#include "utils.h"
namespace art {
// The magic number for free pages.
static const byte kMagicNumFree = 43;
// The number of size brackets. Sync this with the length of Thread::rosalloc_runs_.
- static const size_t kNumOfSizeBrackets = 34;
+ static const size_t kNumOfSizeBrackets = kNumRosAllocThreadLocalSizeBrackets;
// The number of smaller size brackets that are 16 bytes apart.
static const size_t kNumOfQuantumSizeBrackets = 32;
// The sizes (the slot sizes, in bytes) of the size brackets.
#include "base/macros.h"
#include "base/mutex.h"
-#include "gc/space/space-inl.h"
namespace art {
namespace mirror {
} // namespace accounting
namespace space {
+ class BumpPointerSpace;
class ContinuousMemMapAllocSpace;
class ContinuousSpace;
} // namespace space
#include "garbage_collector.h"
#include "gc/accounting/heap_bitmap.h"
#include "immune_region.h"
+#include "mirror/object_reference.h"
#include "object_callbacks.h"
#include "offsets.h"
#include "common_runtime_test.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/accounting/space_bitmap-inl.h"
+#include "handle_scope-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "handle_scope-inl.h"
+#include "scoped_thread_state_change.h"
namespace art {
namespace gc {
*/
#include "space_test.h"
+
#include "dlmalloc_space.h"
+#include "scoped_thread_state_change.h"
namespace art {
namespace gc {
*/
#include "space_test.h"
+
#include "dlmalloc_space.h"
namespace art {
*/
#include "space_test.h"
+
#include "dlmalloc_space.h"
namespace art {
#ifndef ART_RUNTIME_GC_SPACE_SPACE_TEST_H_
#define ART_RUNTIME_GC_SPACE_SPACE_TEST_H_
-#include "zygote_space.h"
-
#include <stdint.h>
#include <memory>
#include "globals.h"
#include "mirror/array-inl.h"
#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+#include "zygote_space.h"
namespace art {
namespace gc {
// If true, references within the heap are poisoned (negated).
static constexpr bool kPoisonHeapReferences = false;
+// Kinds of tracing clocks.
+enum TraceClockSource {
+ kTraceClockSourceThreadCpu,
+ kTraceClockSourceWall,
+ kTraceClockSourceDual, // Both wall and thread CPU clocks.
+};
+
+#if defined(HAVE_POSIX_CLOCKS)
+static constexpr TraceClockSource kDefaultTraceClockSource = kTraceClockSourceDual;
+#else
+static constexpr TraceClockSource kDefaultTraceClockSource = kTraceClockSourceWall;
+#endif
+
} // namespace art
#endif // ART_RUNTIME_GLOBALS_H_
namespace mirror {
class Object;
}
+
class Thread;
// HandleScopes can be allocated within the bridge frame between managed and native code backed by
#include "common_runtime_test.h"
#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
namespace art {
#include <sys/uio.h>
+#include "arch/context.h"
#include "atomic.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "common_runtime_test.h"
#include "mirror/object.h"
#include "handle_scope-inl.h"
+#include "mirror/string.h"
+#include "scoped_thread_state_change.h"
namespace art {
#include "object_registry.h"
+#include "mirror/class.h"
#include "scoped_thread_state_change.h"
namespace art {
#ifndef ART_RUNTIME_JDWP_OBJECT_REGISTRY_H_
#define ART_RUNTIME_JDWP_OBJECT_REGISTRY_H_
+#include <jni.h>
#include <stdint.h>
#include <map>
#include "jdwp/jdwp.h"
-#include "mirror/art_field-inl.h"
-#include "mirror/class.h"
-#include "mirror/class-inl.h"
-#include "mirror/object-inl.h"
-#include "object_callbacks.h"
#include "safe_map.h"
namespace art {
+namespace mirror {
+ class Object;
+ class Class;
+} // namespace mirror
+
struct ObjectRegistryEntry {
// Is jni_reference a weak global or a regular global reference?
jobjectRefType jni_reference_type;
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
return JNI_EVERSION;
}
- Runtime::Options options;
+ RuntimeOptions options;
for (int i = 0; i < args->nOptions; ++i) {
JavaVMOption* option = &args->options[i];
options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
#include "common_compiler_test.h"
#include "mirror/art_method-inl.h"
#include "mirror/string-inl.h"
+#include "scoped_thread_state_change.h"
#include "ScopedLocalRef.h"
namespace art {
#include "art_method.h"
+#include "arch/context.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/stringpiece.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "handle_scope-inl.h"
+#include "scoped_thread_state_change.h"
namespace art {
namespace mirror {
#include "object-inl.h"
#include "object_array-inl.h"
#include "handle_scope-inl.h"
+#include "scoped_thread_state_change.h"
#include "string-inl.h"
namespace art {
#include <gtest/gtest.h>
+#include "object.h"
#include "object_callbacks.h"
#include "read_barrier.h"
#include "monitor_pool.h"
#include "common_runtime_test.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
#include "handle_scope-inl.h"
#include "mirror/class-inl.h"
#include "mirror/string-inl.h" // Strings are easiest to allocate
+#include "scoped_thread_state_change.h"
#include "thread_pool.h"
#include "utils.h"
class MonitorTest : public CommonRuntimeTest {
protected:
- void SetUpRuntimeOptions(Runtime::Options *options) OVERRIDE {
+ void SetUpRuntimeOptions(RuntimeOptions *options) OVERRIDE {
// Use a smaller heap
for (std::pair<std::string, const void*>& pair : *options) {
if (pair.first.find("-Xmx") == 0) {
public:
NoopCompilerCallbacks() {}
~NoopCompilerCallbacks() {}
+
bool MethodVerified(verifier::MethodVerifier* verifier) OVERRIDE {
return true;
}
+
void ClassRejected(ClassReference ref) OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NoopCompilerCallbacks);
};
} // namespace art
#include "debugger.h"
#include "gc/heap.h"
#include "monitor.h"
+#include "runtime.h"
+#include "trace.h"
#include "utils.h"
namespace art {
-ParsedOptions* ParsedOptions::Create(const Runtime::Options& options, bool ignore_unrecognized) {
+ParsedOptions* ParsedOptions::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
std::unique_ptr<ParsedOptions> parsed(new ParsedOptions());
if (parsed->Parse(options, ignore_unrecognized)) {
return parsed.release();
return true;
}
-bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecognized) {
+bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized) {
const char* boot_class_path_string = getenv("BOOTCLASSPATH");
if (boot_class_path_string != NULL) {
boot_class_path_string_ = boot_class_path_string;
method_trace_file_ = "/data/method-trace-file.bin";
method_trace_file_size_ = 10 * MB;
- profile_clock_source_ = kDefaultProfilerClockSource;
+ profile_clock_source_ = kDefaultTraceClockSource;
verify_ = true;
image_isa_ = kRuntimeISA;
return false;
}
} else if (option == "-Xprofile:threadcpuclock") {
- Trace::SetDefaultClockSource(kProfilerClockSourceThreadCpu);
+ Trace::SetDefaultClockSource(kTraceClockSourceThreadCpu);
} else if (option == "-Xprofile:wallclock") {
- Trace::SetDefaultClockSource(kProfilerClockSourceWall);
+ Trace::SetDefaultClockSource(kTraceClockSourceWall);
} else if (option == "-Xprofile:dualclock") {
- Trace::SetDefaultClockSource(kProfilerClockSourceDual);
+ Trace::SetDefaultClockSource(kTraceClockSourceDual);
} else if (option == "-Xenable-profiler") {
profiler_options_.enabled_ = true;
} else if (StartsWith(option, "-Xprofile-filename:")) {
#define ART_RUNTIME_PARSED_OPTIONS_H_
#include <string>
+#include <vector>
+#include <jni.h>
+
+#include "globals.h"
#include "gc/collector_type.h"
-#include "runtime.h"
-#include "trace.h"
+#include "instruction_set.h"
+#include "profiler_options.h"
namespace art {
+class CompilerCallbacks;
+class DexFile;
+
+typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
+
class ParsedOptions {
public:
// returns null if problem parsing and ignore_unrecognized is false
- static ParsedOptions* Create(const Runtime::Options& options, bool ignore_unrecognized);
+ static ParsedOptions* Create(const RuntimeOptions& options, bool ignore_unrecognized);
const std::vector<const DexFile*>* boot_class_path_;
std::string boot_class_path_string_;
std::vector<std::string> image_compiler_options_;
ProfilerOptions profiler_options_;
std::string profile_output_filename_;
- ProfilerClockSource profile_clock_source_;
+ TraceClockSource profile_clock_source_;
bool verify_;
InstructionSet image_isa_;
void Exit(int status);
void Abort();
- bool Parse(const Runtime::Options& options, bool ignore_unrecognized);
+ bool Parse(const RuntimeOptions& options, bool ignore_unrecognized);
bool ParseXGcOption(const std::string& option);
bool ParseStringAfterChar(const std::string& option, char after_char, std::string* parsed_value);
bool ParseInteger(const std::string& option, char after_char, int* parsed_value);
boot_class_path += "-Xbootclasspath:";
boot_class_path += lib_core;
- Runtime::Options options;
+ RuntimeOptions options;
options.push_back(std::make_pair(boot_class_path.c_str(), null));
options.push_back(std::make_pair("-classpath", null));
options.push_back(std::make_pair(lib_core.c_str(), null));
* limitations under the License.
*/
-#include "common_compiler_test.h"
-#include "mirror/art_field-inl.h"
-
#include <jni.h>
#include <vector>
+#include "common_compiler_test.h"
+#include "mirror/art_field-inl.h"
+#include "scoped_thread_state_change.h"
+
namespace art {
class ProxyTest : public CommonCompilerTest {
#include "quick_exception_handler.h"
+#include "arch/context.h"
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
#include "handle_scope-inl.h"
#include "reference_table.h"
#include "common_runtime_test.h"
+#include "mirror/array.h"
+#include "mirror/string.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
return true;
}
+static std::string PrettyDescriptor(Primitive::Type type) {
+ std::string descriptor_string(Primitive::Descriptor(type));
+ return PrettyDescriptor(descriptor_string);
+}
+
bool ConvertPrimitiveValue(const ThrowLocation* throw_location, bool unbox_for_result,
Primitive::Type srcType, Primitive::Type dstType,
const JValue& src, JValue* dst) {
#include <float.h>
#include <limits.h>
+#include "ScopedLocalRef.h"
#include "common_compiler_test.h"
#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
namespace art {
#include "runtime.h"
+#include "read_barrier-inl.h"
+
namespace art {
inline QuickMethodFrameInfo Runtime::GetRuntimeMethodFrameInfo(mirror::ArtMethod* method) {
}
}
+inline mirror::ArtMethod* Runtime::GetResolutionMethod() {
+ CHECK(HasResolutionMethod());
+ return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(&resolution_method_);
+}
+
+inline mirror::ArtMethod* Runtime::GetImtConflictMethod() {
+ CHECK(HasImtConflictMethod());
+ return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(&imt_conflict_method_);
+}
+
+inline mirror::ObjectArray<mirror::ArtMethod>* Runtime::GetDefaultImt()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(HasDefaultImt());
+ return ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::ArtMethod>, kWithReadBarrier>(
+ &default_imt_);
+}
+
+inline mirror::ArtMethod* Runtime::GetCalleeSaveMethod(CalleeSaveType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(HasCalleeSaveMethod(type));
+ return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(
+ &callee_save_methods_[type]);
+}
+
+inline mirror::ArtMethod* Runtime::GetCalleeSaveMethodUnchecked(CalleeSaveType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(
+ &callee_save_methods_[type]);
+}
+
} // namespace art
#endif // ART_RUNTIME_RUNTIME_INL_H_
#include "fault_handler.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
+#include "gc/space/image_space.h"
#include "gc/space/space.h"
#include "image.h"
#include "instrumentation.h"
GetJavaVM()->SweepJniWeakGlobals(visitor, arg);
}
-bool Runtime::Create(const Options& options, bool ignore_unrecognized) {
+bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
// TODO: acquire a static mutex on Runtime to avoid racing.
if (Runtime::instance_ != NULL) {
return false;
VLOG(startup) << "Runtime::StartDaemonThreads exiting";
}
-bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
+bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
#include "offsets.h"
#include "profiler_options.h"
#include "quick/quick_method_frame_info.h"
-#include "read_barrier-inl.h"
#include "runtime_stats.h"
#include "safe_map.h"
class Trace;
class Transaction;
+typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
+
// Not all combinations of flags are valid. You may not visit all roots as well as the new roots
// (no logical reason to do this). You also may not start logging new roots and stop logging new
// roots (also no logical reason to do this).
class Runtime {
public:
- typedef std::vector<std::pair<std::string, const void*>> Options;
-
// Creates and initializes a new runtime.
- static bool Create(const Options& options, bool ignore_unrecognized)
+ static bool Create(const RuntimeOptions& options, bool ignore_unrecognized)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_);
bool IsCompiler() const {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Returns a special method that calls into a trampoline for runtime method resolution
- mirror::ArtMethod* GetResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK(HasResolutionMethod());
- return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(&resolution_method_);
- }
+ mirror::ArtMethod* GetResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool HasResolutionMethod() const {
- return resolution_method_ != NULL;
+ return resolution_method_ != nullptr;
}
void SetResolutionMethod(mirror::ArtMethod* method) {
mirror::ArtMethod* CreateResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Returns a special method that calls into a trampoline for runtime imt conflicts
- mirror::ArtMethod* GetImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK(HasImtConflictMethod());
- return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(&imt_conflict_method_);
- }
+ // Returns a special method that calls into a trampoline for runtime imt conflicts.
+ mirror::ArtMethod* GetImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool HasImtConflictMethod() const {
- return imt_conflict_method_ != NULL;
+ return imt_conflict_method_ != nullptr;
}
void SetImtConflictMethod(mirror::ArtMethod* method) {
// Returns an imt with every entry set to conflict, used as default imt for all classes.
mirror::ObjectArray<mirror::ArtMethod>* GetDefaultImt()
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK(HasDefaultImt());
- return ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::ArtMethod>, kWithReadBarrier>(
- &default_imt_);
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool HasDefaultImt() const {
- return default_imt_ != NULL;
+ return default_imt_ != nullptr;
}
void SetDefaultImt(mirror::ObjectArray<mirror::ArtMethod>* imt) {
}
mirror::ArtMethod* GetCalleeSaveMethod(CalleeSaveType type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(HasCalleeSaveMethod(type));
- return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(
- &callee_save_methods_[type]);
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::ArtMethod* GetCalleeSaveMethodUnchecked(CalleeSaveType type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(
- &callee_save_methods_[type]);
- }
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
QuickMethodFrameInfo GetCalleeSaveMethodFrameInfo(CalleeSaveType type) const {
return callee_save_method_frame_infos_[type];
void BlockSignals();
- bool Init(const Options& options, bool ignore_unrecognized)
+ bool Init(const RuntimeOptions& options, bool ignore_unrecognized)
SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_);
void InitNativeMethods() LOCKS_EXCLUDED(Locks::mutator_lock_);
void InitThreadGroups(Thread* self);
#include "stack.h"
+#include "arch/context.h"
#include "base/hex_dump.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
return result;
}
-instrumentation::InstrumentationStackFrame& StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
- CHECK_LT(depth, thread_->GetInstrumentationStack()->size());
- return thread_->GetInstrumentationStack()->at(depth);
+static instrumentation::InstrumentationStackFrame& GetInstrumentationStackFrame(Thread* thread,
+ uint32_t depth) {
+ CHECK_LT(depth, thread->GetInstrumentationStack()->size());
+ return thread->GetInstrumentationStack()->at(depth);
}
void StackVisitor::SanityCheckFrame() const {
// the stack for an exception where the side stack will be unwound in VisitFrame.
if (GetQuickInstrumentationExitPc() == return_pc) {
const instrumentation::InstrumentationStackFrame& instrumentation_frame =
- GetInstrumentationStackFrame(instrumentation_stack_depth);
+ GetInstrumentationStackFrame(thread_, instrumentation_stack_depth);
instrumentation_stack_depth++;
if (GetMethod() == Runtime::Current()->GetCalleeSaveMethod(Runtime::kSaveAll)) {
// Skip runtime save all callee frames which are used to deliver exceptions.
#ifndef ART_RUNTIME_STACK_H_
#define ART_RUNTIME_STACK_H_
+#include <stdint.h>
+#include <string>
+
#include "dex_file.h"
-#include "instrumentation.h"
-#include "arch/context.h"
-#include "base/casts.h"
-#include "base/macros.h"
#include "instruction_set.h"
-#include "mirror/object.h"
#include "mirror/object_reference.h"
+#include "throw_location.h"
#include "utils.h"
#include "verify_object.h"
-#include <stdint.h>
-#include <string>
-
namespace art {
namespace mirror {
bool GetFPR(uint32_t reg, uintptr_t* val) const;
bool SetFPR(uint32_t reg, uintptr_t value);
- instrumentation::InstrumentationStackFrame& GetInstrumentationStackFrame(uint32_t depth) const;
-
void SanityCheckFrame() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Thread* const thread_;
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "gc_map.h"
#include "gc/accounting/card_table-inl.h"
+#include "gc/allocator/rosalloc.h"
#include "gc/heap.h"
#include "gc/space/space.h"
#include "handle_scope.h"
tls32_.state_and_flags.as_struct.state = kNative;
memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes));
std::fill(tlsPtr_.rosalloc_runs,
- tlsPtr_.rosalloc_runs + gc::allocator::RosAlloc::kNumThreadLocalSizeBrackets,
+ tlsPtr_.rosalloc_runs + kNumRosAllocThreadLocalSizeBrackets,
gc::allocator::RosAlloc::GetDedicatedFullRun());
for (uint32_t i = 0; i < kMaxCheckpoints; ++i) {
tlsPtr_.checkpoint_functions[i] = nullptr;
#include "entrypoints/jni/jni_entrypoints.h"
#include "entrypoints/portable/portable_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints.h"
-#include "gc/allocator/rosalloc.h"
#include "globals.h"
#include "handle_scope.h"
#include "instruction_set.h"
kCheckpointRequest = 2 // Request that the thread do some checkpoint work and then continue.
};
+static constexpr size_t kNumRosAllocThreadLocalSizeBrackets = 34;
+
class Thread {
public:
// How much of the reserved bytes is reserved for incoming signals.
size_t thread_local_objects;
// There are RosAlloc::kNumThreadLocalSizeBrackets thread-local size brackets per thread.
- void* rosalloc_runs[gc::allocator::RosAlloc::kNumThreadLocalSizeBrackets];
+ void* rosalloc_runs[kNumRosAllocThreadLocalSizeBrackets];
// Thread-local allocation stack data/routines.
mirror::Object** thread_local_alloc_stack_top;
#include "atomic.h"
#include "common_runtime_test.h"
+#include "thread-inl.h"
namespace art {
static const uint16_t kTraceRecordSizeSingleClock = 10; // using v2
static const uint16_t kTraceRecordSizeDualClock = 14; // using v3 with two timestamps
-ProfilerClockSource Trace::default_clock_source_ = kDefaultProfilerClockSource;
+TraceClockSource Trace::default_clock_source_ = kDefaultTraceClockSource;
Trace* volatile Trace::the_trace_ = NULL;
pthread_t Trace::sampling_pthread_ = 0U;
temp_stack_trace_.reset(stack_trace);
}
-void Trace::SetDefaultClockSource(ProfilerClockSource clock_source) {
+void Trace::SetDefaultClockSource(TraceClockSource clock_source) {
#if defined(HAVE_POSIX_CLOCKS)
default_clock_source_ = clock_source;
#else
- if (clock_source != kProfilerClockSourceWall) {
+ if (clock_source != kTraceClockSourceWall) {
LOG(WARNING) << "Ignoring tracing request to use CPU time.";
}
#endif
}
-static uint16_t GetTraceVersion(ProfilerClockSource clock_source) {
- return (clock_source == kProfilerClockSourceDual) ? kTraceVersionDualClock
+static uint16_t GetTraceVersion(TraceClockSource clock_source) {
+ return (clock_source == kTraceClockSourceDual) ? kTraceVersionDualClock
: kTraceVersionSingleClock;
}
-static uint16_t GetRecordSize(ProfilerClockSource clock_source) {
- return (clock_source == kProfilerClockSourceDual) ? kTraceRecordSizeDualClock
+static uint16_t GetRecordSize(TraceClockSource clock_source) {
+ return (clock_source == kTraceClockSourceDual) ? kTraceRecordSizeDualClock
: kTraceRecordSizeSingleClock;
}
bool Trace::UseThreadCpuClock() {
- return (clock_source_ == kProfilerClockSourceThreadCpu) ||
- (clock_source_ == kProfilerClockSourceDual);
+ return (clock_source_ == kTraceClockSourceThreadCpu) ||
+ (clock_source_ == kTraceClockSourceDual);
}
bool Trace::UseWallClock() {
- return (clock_source_ == kProfilerClockSourceWall) ||
- (clock_source_ == kProfilerClockSourceDual);
+ return (clock_source_ == kTraceClockSourceWall) ||
+ (clock_source_ == kTraceClockSourceDual);
}
static void MeasureClockOverhead(Trace* trace) {
cur_offset_.StoreRelaxed(kTraceHeaderLength);
}
-static void DumpBuf(uint8_t* buf, size_t buf_size, ProfilerClockSource clock_source)
+static void DumpBuf(uint8_t* buf, size_t buf_size, TraceClockSource clock_source)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uint8_t* ptr = buf + kTraceHeaderLength;
uint8_t* end = buf + buf_size;
class ArtField;
class ArtMethod;
} // namespace mirror
-class Thread;
-
-enum ProfilerClockSource {
- kProfilerClockSourceThreadCpu,
- kProfilerClockSourceWall,
- kProfilerClockSourceDual, // Both wall and thread CPU clocks.
-};
-#if defined(HAVE_POSIX_CLOCKS)
-const ProfilerClockSource kDefaultProfilerClockSource = kProfilerClockSourceDual;
-#else
-const ProfilerClockSource kDefaultProfilerClockSource = kProfilerClockSourceWall;
-#endif
+class Thread;
enum TracingMode {
kTracingInactive,
kTraceCountAllocs = 1,
};
- static void SetDefaultClockSource(ProfilerClockSource clock_source);
+ static void SetDefaultClockSource(TraceClockSource clock_source);
static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags,
bool direct_to_ddms, bool sampling_enabled, int interval_us)
static Trace* volatile the_trace_ GUARDED_BY(Locks::trace_lock_);
// The default profiler clock source.
- static ProfilerClockSource default_clock_source_;
+ static TraceClockSource default_clock_source_;
// Sampling thread, non-zero when sampling.
static pthread_t sampling_pthread_;
// True if traceview should sample instead of instrumenting method entry/exit.
const bool sampling_enabled_;
- const ProfilerClockSource clock_source_;
+ const TraceClockSource clock_source_;
// Size of buf_.
const int buffer_size_;
#include "mirror/array-inl.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
namespace art {
return result;
}
-std::string PrettyDescriptor(Primitive::Type type) {
- std::string descriptor_string(Primitive::Descriptor(type));
- return PrettyDescriptor(descriptor_string);
-}
-
std::string PrettyField(mirror::ArtField* f, bool with_type) {
if (f == NULL) {
return "null";
#include "base/logging.h"
#include "globals.h"
#include "instruction_set.h"
-#include "primitive.h"
+#include "base/mutex.h"
#ifdef HAVE_ANDROID_OS
#include "cutils/properties.h"
std::string PrettyDescriptor(mirror::String* descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
std::string PrettyDescriptor(const std::string& descriptor);
-std::string PrettyDescriptor(Primitive::Type type);
std::string PrettyDescriptor(mirror::Class* klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "dex_file.h"
+#include "scoped_thread_state_change.h"
namespace art {
namespace verifier {
#include "base/casts.h"
#include "common_runtime_test.h"
#include "reg_type_cache-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
namespace art {
namespace verifier {
#include <zlib.h>
#include <memory>
+#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "os.h"