diff options
171 files changed, 2615 insertions, 1814 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 3a19c402db..a34058864c 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -179,6 +179,42 @@ ifeq ($(ART_USE_PORTABLE_COMPILER),true) 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 := @@ -285,12 +321,12 @@ define define-art-gtest 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) @@ -304,7 +340,6 @@ define define-art-gtest $$(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 @@ -328,10 +363,6 @@ test-art-target-gtest-$$(art_gtest_name): $$(ART_TEST_TARGET_GTEST_$$(art_gtest_ 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 diff --git a/compiler/Android.mk b/compiler/Android.mk index 98a4c2fbb9..02dad2ae36 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -72,6 +72,7 @@ LIBART_COMPILER_SRC_FILES := \ 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 \ diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc new file mode 100644 index 0000000000..051cfb6dbc --- /dev/null +++ b/compiler/common_compiler_test.cc @@ -0,0 +1,413 @@ +/* + * 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 diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index e11f61a285..df06b71c7d 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -17,409 +17,68 @@ #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_; diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index f4ea592781..2fcc3a5abc 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -341,7 +341,7 @@ void ArmMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { * is responsible for setting branch target field. */ LIR* ArmMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) { - LIR* branch; + LIR* branch = nullptr; ArmConditionCode arm_cond = ArmConditionEncoding(cond); /* * A common use of OpCmpImmBranch is for null checks, and using the Thumb 16-bit @@ -354,14 +354,22 @@ LIR* ArmMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_va */ bool skip = ((target != NULL) && (target->opcode == kPseudoThrowTarget)); skip &= ((cu_->code_item->insns_size_in_code_units_ - current_dalvik_offset_) > 64); - if (!skip && reg.Low8() && (check_value == 0) && - ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) { - branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, - reg.GetReg(), 0); - } else { + if (!skip && reg.Low8() && (check_value == 0)) { + if (arm_cond == kArmCondEq || arm_cond == kArmCondNe) { + branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, + reg.GetReg(), 0); + } else if (arm_cond == kArmCondLs) { + // kArmCondLs is an unsigned less or equal. A comparison r <= 0 is then the same as cbz. + // This case happens for a bounds check of array[0]. + branch = NewLIR2(kThumb2Cbz, reg.GetReg(), 0); + } + } + + if (branch == nullptr) { OpRegImm(kOpCmp, reg, check_value); branch = NewLIR2(kThumbBCond, 0, arm_cond); } + branch->target = target; return branch; } diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc index 083277de43..462be54e57 100644 --- a/compiler/dex/quick/arm64/assemble_arm64.cc +++ b/compiler/dex/quick/arm64/assemble_arm64.cc @@ -655,10 +655,10 @@ uint8_t* Arm64Mir2Lir::EncodeLIRs(uint8_t* write_pos, LIR* lir) { if (kIsDebugBuild && (kFailOnSizeError || kReportSizeError)) { // Register usage checks: First establish register usage requirements based on the // format in `kind'. - bool want_float = false; - bool want_64_bit = false; - bool want_var_size = true; - bool want_zero = false; + bool want_float = false; // Want a float (rather than core) register. + bool want_64_bit = false; // Want a 64-bit (rather than 32-bit) register. + bool want_var_size = true; // Want register with variable size (kFmtReg{R,F}). + bool want_zero = false; // Want the zero (rather than sp) register. switch (kind) { case kFmtRegX: want_64_bit = true; @@ -717,9 +717,6 @@ uint8_t* Arm64Mir2Lir::EncodeLIRs(uint8_t* write_pos, LIR* lir) { } } - // TODO(Arm64): if !want_size_match, then we still should compare the size of the - // register with the size required by the instruction width (kA64Wide). - // Fail, if `expected' contains an unsatisfied requirement. if (expected != nullptr) { LOG(WARNING) << "Method: " << PrettyMethod(cu_->method_idx, *cu_->dex_file) @@ -734,11 +731,12 @@ uint8_t* Arm64Mir2Lir::EncodeLIRs(uint8_t* write_pos, LIR* lir) { } } - // TODO(Arm64): this may or may not be necessary, depending on how wzr, xzr are - // defined. - if (is_zero) { - operand = 31; - } + // In the lines below, we rely on (operand & 0x1f) == 31 to be true for register sp + // and zr. This means that these two registers do not need any special treatment, as + // their bottom 5 bits are correctly set to 31 == 0b11111, which is the right + // value for encoding both sp and zr. + COMPILE_ASSERT((rxzr & 0x1f) == 0x1f, rzr_register_number_must_be_31); + COMPILE_ASSERT((rsp & 0x1f) == 0x1f, rsp_register_number_must_be_31); } value = (operand << encoder->field_loc[i].start) & diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h index e4eeeaf580..de976531c2 100644 --- a/compiler/dex/quick/arm64/codegen_arm64.h +++ b/compiler/dex/quick/arm64/codegen_arm64.h @@ -105,16 +105,14 @@ class Arm64Mir2Lir FINAL : public Mir2Lir { // Required for target - register utilities. RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE; RegStorage TargetReg(SpecialTargetRegister symbolic_reg, WideKind wide_kind) OVERRIDE { - RegStorage reg = TargetReg(symbolic_reg); if (wide_kind == kWide || wide_kind == kRef) { - return (reg.Is64Bit()) ? reg : As64BitReg(reg); + return As64BitReg(TargetReg(symbolic_reg)); } else { - return (reg.Is32Bit()) ? reg : As32BitReg(reg); + return Check32BitReg(TargetReg(symbolic_reg)); } } RegStorage TargetPtrReg(SpecialTargetRegister symbolic_reg) OVERRIDE { - RegStorage reg = TargetReg(symbolic_reg); - return (reg.Is64Bit() ? reg : As64BitReg(reg)); + return As64BitReg(TargetReg(symbolic_reg)); } RegStorage GetArgMappingToPhysicalReg(int arg_num); RegLocation GetReturnAlt(); diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc index 2650892975..6dc4a7ab51 100644 --- a/compiler/dex/quick/arm64/int_arm64.cc +++ b/compiler/dex/quick/arm64/int_arm64.cc @@ -269,16 +269,27 @@ void Arm64Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { */ LIR* Arm64Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) { - LIR* branch; + LIR* branch = nullptr; ArmConditionCode arm_cond = ArmConditionEncoding(cond); - if (check_value == 0 && (arm_cond == kArmCondEq || arm_cond == kArmCondNe)) { - ArmOpcode opcode = (arm_cond == kArmCondEq) ? kA64Cbz2rt : kA64Cbnz2rt; - ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0); - branch = NewLIR2(opcode | wide, reg.GetReg(), 0); - } else { + if (check_value == 0) { + if (arm_cond == kArmCondEq || arm_cond == kArmCondNe) { + ArmOpcode opcode = (arm_cond == kArmCondEq) ? kA64Cbz2rt : kA64Cbnz2rt; + ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0); + branch = NewLIR2(opcode | wide, reg.GetReg(), 0); + } else if (arm_cond == kArmCondLs) { + // kArmCondLs is an unsigned less or equal. A comparison r <= 0 is then the same as cbz. + // This case happens for a bounds check of array[0]. + ArmOpcode opcode = kA64Cbz2rt; + ArmOpcode wide = reg.Is64Bit() ? WIDE(0) : UNWIDE(0); + branch = NewLIR2(opcode | wide, reg.GetReg(), 0); + } + } + + if (branch == nullptr) { OpRegImm(kOpCmp, reg, check_value); branch = NewLIR2(kA64B2ct, arm_cond, 0); } + branch->target = target; return branch; } diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc index 2212380eb4..6a27ad0b14 100644 --- a/compiler/dex/quick/arm64/target_arm64.cc +++ b/compiler/dex/quick/arm64/target_arm64.cc @@ -108,19 +108,19 @@ RegLocation Arm64Mir2Lir::LocCReturnDouble() { RegStorage Arm64Mir2Lir::TargetReg(SpecialTargetRegister reg) { RegStorage res_reg = RegStorage::InvalidReg(); switch (reg) { - case kSelf: res_reg = rs_xSELF; break; - case kSuspend: res_reg = rs_xSUSPEND; break; - case kLr: res_reg = rs_xLR; break; + case kSelf: res_reg = rs_wSELF; break; + case kSuspend: res_reg = rs_wSUSPEND; break; + case kLr: res_reg = rs_wLR; break; case kPc: res_reg = RegStorage::InvalidReg(); break; - case kSp: res_reg = rs_sp; break; - case kArg0: res_reg = rs_x0; break; - case kArg1: res_reg = rs_x1; break; - case kArg2: res_reg = rs_x2; break; - case kArg3: res_reg = rs_x3; break; - case kArg4: res_reg = rs_x4; break; - case kArg5: res_reg = rs_x5; break; - case kArg6: res_reg = rs_x6; break; - case kArg7: res_reg = rs_x7; break; + case kSp: res_reg = rs_wsp; break; + case kArg0: res_reg = rs_w0; break; + case kArg1: res_reg = rs_w1; break; + case kArg2: res_reg = rs_w2; break; + case kArg3: res_reg = rs_w3; break; + case kArg4: res_reg = rs_w4; break; + case kArg5: res_reg = rs_w5; break; + case kArg6: res_reg = rs_w6; break; + case kArg7: res_reg = rs_w7; break; case kFArg0: res_reg = rs_f0; break; case kFArg1: res_reg = rs_f1; break; case kFArg2: res_reg = rs_f2; break; @@ -129,10 +129,10 @@ RegStorage Arm64Mir2Lir::TargetReg(SpecialTargetRegister reg) { case kFArg5: res_reg = rs_f5; break; case kFArg6: res_reg = rs_f6; break; case kFArg7: res_reg = rs_f7; break; - case kRet0: res_reg = rs_x0; break; - case kRet1: res_reg = rs_x1; break; - case kInvokeTgt: res_reg = rs_xLR; break; - case kHiddenArg: res_reg = rs_x12; break; + case kRet0: res_reg = rs_w0; break; + case kRet1: res_reg = rs_w1; break; + case kInvokeTgt: res_reg = rs_wLR; break; + case kHiddenArg: res_reg = rs_w12; break; case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break; case kCount: res_reg = RegStorage::InvalidReg(); break; default: res_reg = RegStorage::InvalidReg(); @@ -929,13 +929,13 @@ void Arm64Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) { */ RegLocation rl_src = rl_method; rl_src.location = kLocPhysReg; - rl_src.reg = TargetReg(kArg0); + rl_src.reg = TargetReg(kArg0, kRef); rl_src.home = false; MarkLive(rl_src); StoreValue(rl_method, rl_src); // If Method* has been promoted, explicitly flush if (rl_method.location == kLocPhysReg) { - StoreRefDisp(TargetReg(kSp), 0, TargetReg(kArg0), kNotVolatile); + StoreRefDisp(TargetPtrReg(kSp), 0, rl_src.reg, kNotVolatile); } if (cu_->num_ins == 0) { @@ -961,9 +961,9 @@ void Arm64Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) { } else { // Needs flush. if (t_loc->ref) { - StoreRefDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, kNotVolatile); + StoreRefDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg, kNotVolatile); } else { - StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, t_loc->wide ? k64 : k32, + StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg, t_loc->wide ? k64 : k32, kNotVolatile); } } @@ -971,9 +971,9 @@ void Arm64Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) { // If arriving in frame & promoted. if (t_loc->location == kLocPhysReg) { if (t_loc->ref) { - LoadRefDisp(TargetReg(kSp), SRegOffset(start_vreg + i), t_loc->reg, kNotVolatile); + LoadRefDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), t_loc->reg, kNotVolatile); } else { - LoadBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), t_loc->reg, + LoadBaseDisp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), t_loc->reg, t_loc->wide ? k64 : k32, kNotVolatile); } } @@ -1070,7 +1070,7 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, loc = UpdateLocWide(loc); if (loc.location == kLocPhysReg) { ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); - StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile); + StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile); } next_arg += 2; } else { @@ -1078,9 +1078,10 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, if (loc.location == kLocPhysReg) { ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); if (loc.ref) { - StoreRefDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile); + StoreRefDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, kNotVolatile); } else { - StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32, kNotVolatile); + StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k32, + kNotVolatile); } } next_arg++; @@ -1114,8 +1115,8 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, RegStorage temp = TargetReg(kArg3, kNotWide); // Now load the argument VR and store to the outs. - Load32Disp(TargetReg(kSp), current_src_offset, temp); - Store32Disp(TargetReg(kSp), current_dest_offset, temp); + Load32Disp(TargetPtrReg(kSp), current_src_offset, temp); + Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp); current_src_offset += bytes_to_move; current_dest_offset += bytes_to_move; @@ -1126,8 +1127,7 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, // Now handle rest not registers if they are if (in_to_reg_storage_mapping.IsThereStackMapped()) { - RegStorage regSingle = TargetReg(kArg2); - RegStorage regWide = RegStorage::Solo64(TargetReg(kArg3).GetReg()); + RegStorage regWide = TargetReg(kArg3, kWide); for (int i = start_index; i <= last_mapped_in + regs_left_to_pass_via_stack; i++) { RegLocation rl_arg = info->args[i]; rl_arg = UpdateRawLoc(rl_arg); @@ -1139,25 +1139,27 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); if (rl_arg.wide) { if (rl_arg.location == kLocPhysReg) { - StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile); + StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k64, kNotVolatile); } else { LoadValueDirectWideFixed(rl_arg, regWide); - StoreBaseDisp(TargetReg(kSp), out_offset, regWide, k64, kNotVolatile); + StoreBaseDisp(TargetPtrReg(kSp), out_offset, regWide, k64, kNotVolatile); } } else { if (rl_arg.location == kLocPhysReg) { if (rl_arg.ref) { - StoreRefDisp(TargetReg(kSp), out_offset, rl_arg.reg, kNotVolatile); + StoreRefDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, kNotVolatile); } else { - StoreBaseDisp(TargetReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile); + StoreBaseDisp(TargetPtrReg(kSp), out_offset, rl_arg.reg, k32, kNotVolatile); } } else { if (rl_arg.ref) { + RegStorage regSingle = TargetReg(kArg2, kRef); LoadValueDirectFixed(rl_arg, regSingle); - StoreRefDisp(TargetReg(kSp), out_offset, regSingle, kNotVolatile); + StoreRefDisp(TargetPtrReg(kSp), out_offset, regSingle, kNotVolatile); } else { - LoadValueDirectFixed(rl_arg, As32BitReg(regSingle)); - StoreBaseDisp(TargetReg(kSp), out_offset, As32BitReg(regSingle), k32, kNotVolatile); + RegStorage regSingle = TargetReg(kArg2, kNotWide); + LoadValueDirectFixed(rl_arg, regSingle); + StoreBaseDisp(TargetPtrReg(kSp), out_offset, regSingle, k32, kNotVolatile); } } } @@ -1194,13 +1196,13 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, direct_code, direct_method, type); if (pcrLabel) { if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) { - *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1), info->opt_flags); + *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags); } else { *pcrLabel = nullptr; // In lieu of generating a check for kArg1 being null, we need to // perform a load when doing implicit checks. RegStorage tmp = AllocTemp(); - Load32Disp(TargetReg(kArg1), 0, tmp); + Load32Disp(TargetReg(kArg1, kRef), 0, tmp); MarkPossibleNullPointerException(info->opt_flags); FreeTemp(tmp); } diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index 45dd7f08a6..0e46c96501 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -48,6 +48,7 @@ static constexpr bool kIntrinsicIsStatic[] = { true, // kIntrinsicMinMaxFloat true, // kIntrinsicMinMaxDouble true, // kIntrinsicSqrt + false, // kIntrinsicGet false, // kIntrinsicCharAt false, // kIntrinsicCompareTo false, // kIntrinsicIsEmptyOrLength @@ -74,6 +75,7 @@ COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxLong], MinMaxLong_must_be_stat COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], MinMaxFloat_must_be_static); COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], MinMaxDouble_must_be_static); COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicSqrt], Sqrt_must_be_static); +COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicGet], Get_must_not_be_static); COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCharAt], CharAt_must_not_be_static); COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCompareTo], CompareTo_must_not_be_static); COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], IsEmptyOrLength_must_not_be_static); @@ -126,6 +128,7 @@ const char* const DexFileMethodInliner::kClassCacheNames[] = { "D", // kClassCacheDouble "V", // kClassCacheVoid "Ljava/lang/Object;", // kClassCacheJavaLangObject + "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference "Ljava/lang/String;", // kClassCacheJavaLangString "Ljava/lang/Double;", // kClassCacheJavaLangDouble "Ljava/lang/Float;", // kClassCacheJavaLangFloat @@ -152,6 +155,7 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "max", // kNameCacheMax "min", // kNameCacheMin "sqrt", // kNameCacheSqrt + "get", // kNameCacheGet "charAt", // kNameCacheCharAt "compareTo", // kNameCacheCompareTo "isEmpty", // kNameCacheIsEmpty @@ -220,6 +224,8 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { { kClassCacheBoolean, 0, { } }, // kProtoCache_I { kClassCacheInt, 0, { } }, + // kProtoCache_Object + { kClassCacheJavaLangObject, 0, { } }, // kProtoCache_Thread { kClassCacheJavaLangThread, 0, { } }, // kProtoCacheJ_B @@ -308,6 +314,8 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), + INTRINSIC(JavaLangRefReference, Get, _Object, kIntrinsicGet, 0), + INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), @@ -428,6 +436,8 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */); case kIntrinsicSqrt: return backend->GenInlinedSqrt(info); + case kIntrinsicGet: + return backend->GenInlinedGet(info); case kIntrinsicCharAt: return backend->GenInlinedCharAt(info); case kIntrinsicCompareTo: diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index 5b3b104150..cb8c165ce5 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -107,6 +107,7 @@ class DexFileMethodInliner { kClassCacheDouble, kClassCacheVoid, kClassCacheJavaLangObject, + kClassCacheJavaLangRefReference, kClassCacheJavaLangString, kClassCacheJavaLangDouble, kClassCacheJavaLangFloat, @@ -140,6 +141,7 @@ class DexFileMethodInliner { kNameCacheMax, kNameCacheMin, kNameCacheSqrt, + kNameCacheGet, kNameCacheCharAt, kNameCacheCompareTo, kNameCacheIsEmpty, @@ -199,6 +201,7 @@ class DexFileMethodInliner { kProtoCacheString_I, kProtoCache_Z, kProtoCache_I, + kProtoCache_Object, kProtoCache_Thread, kProtoCacheJ_B, kProtoCacheJ_I, diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 79065b3474..9dedeae071 100755 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -23,9 +23,12 @@ #include "invoke_type.h" #include "mirror/array.h" #include "mirror/class-inl.h" +#include "mirror/dex_cache.h" #include "mirror/object_array-inl.h" +#include "mirror/reference-inl.h" #include "mirror/string.h" #include "mir_to_lir-inl.h" +#include "scoped_thread_state_change.h" #include "x86/codegen_x86.h" namespace art { @@ -1218,6 +1221,88 @@ RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) { return res; } +bool Mir2Lir::GenInlinedGet(CallInfo* info) { + if (cu_->instruction_set == kMips) { + // TODO - add Mips implementation + return false; + } + + // the refrence class is stored in the image dex file which might not be the same as the cu's + // dex file. Query the reference class for the image dex file then reset to starting dex file + // in after loading class type. + uint16_t type_idx = 0; + const DexFile* ref_dex_file = nullptr; + { + ScopedObjectAccess soa(Thread::Current()); + type_idx = mirror::Reference::GetJavaLangRefReference()->GetDexTypeIndex(); + ref_dex_file = mirror::Reference::GetJavaLangRefReference()->GetDexCache()->GetDexFile(); + } + CHECK(LIKELY(ref_dex_file != nullptr)); + + // address is either static within the image file, or needs to be patched up after compilation. + bool unused_type_initialized; + bool use_direct_type_ptr; + uintptr_t direct_type_ptr; + bool is_finalizable; + const DexFile* old_dex = cu_->dex_file; + cu_->dex_file = ref_dex_file; + RegStorage reg_class = TargetPtrReg(kArg1); + if (!cu_->compiler_driver->CanEmbedTypeInCode(*ref_dex_file, type_idx, &unused_type_initialized, + &use_direct_type_ptr, &direct_type_ptr, + &is_finalizable) || is_finalizable) { + cu_->dex_file = old_dex; + // address is not known and post-compile patch is not possible, cannot insert intrinsic. + return false; + } + if (use_direct_type_ptr) { + LoadConstant(reg_class, direct_type_ptr); + } else { + LoadClassType(type_idx, kArg1); + } + cu_->dex_file = old_dex; + + // get the offset for flags in reference class. + uint32_t slow_path_flag_offset = 0; + uint32_t disable_flag_offset = 0; + { + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* reference_class = mirror::Reference::GetJavaLangRefReference(); + slow_path_flag_offset = reference_class->GetSlowPathFlagOffset().Uint32Value(); + disable_flag_offset = reference_class->GetDisableIntrinsicFlagOffset().Uint32Value(); + } + CHECK(slow_path_flag_offset && disable_flag_offset && + (slow_path_flag_offset != disable_flag_offset)); + + // intrinsic logic start. + RegLocation rl_obj = info->args[0]; + rl_obj = LoadValue(rl_obj); + + RegStorage reg_slow_path = AllocTemp(); + RegStorage reg_disabled = AllocTemp(); + Load32Disp(reg_class, slow_path_flag_offset, reg_slow_path); + Load32Disp(reg_class, disable_flag_offset, reg_disabled); + OpRegRegReg(kOpOr, reg_slow_path, reg_slow_path, reg_disabled); + FreeTemp(reg_disabled); + + // if slow path, jump to JNI path target + LIR* slow_path_branch = OpCmpImmBranch(kCondNe, reg_slow_path, 0, nullptr); + FreeTemp(reg_slow_path); + + // slow path not enabled, simply load the referent of the reference object + RegLocation rl_dest = InlineTarget(info); + RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); + GenNullCheck(rl_obj.reg, info->opt_flags); + LoadRefDisp(rl_obj.reg, mirror::Reference::ReferentOffset().Int32Value(), rl_result.reg, + kNotVolatile); + MarkPossibleNullPointerException(info->opt_flags); + StoreValue(rl_dest, rl_result); + + LIR* intrinsic_finish = NewLIR0(kPseudoTargetLabel); + AddIntrinsicSlowPath(info, slow_path_branch, intrinsic_finish); + + return true; +} + bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { if (cu_->instruction_set == kMips) { // TODO - add Mips implementation diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 07c615f342..edb3b23493 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -18,7 +18,6 @@ #include "dex/dataflow_iterator-inl.h" #include "dex/quick/dex_file_method_inliner.h" #include "mir_to_lir-inl.h" -#include "object_utils.h" #include "thread-inl.h" namespace art { diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 634ab943cf..c68ad6be4b 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -982,6 +982,7 @@ class Mir2Lir : public Backend { */ RegLocation InlineTargetWide(CallInfo* info); + bool GenInlinedGet(CallInfo* info); bool GenInlinedCharAt(CallInfo* info); bool GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty); virtual bool GenInlinedReverseBits(CallInfo* info, OpSize size); @@ -1201,7 +1202,7 @@ class Mir2Lir : public Backend { * @param wide_kind What kind of view of the special register is required. * @return Return the #RegStorage corresponding to the given purpose @p reg. * - * Note: For 32b system, wide (kWide) views only make sense for the argument registers and the + * @note For 32b system, wide (kWide) views only make sense for the argument registers and the * return. In that case, this function should return a pair where the first component of * the result will be the indicated special register. */ diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc new file mode 100644 index 0000000000..03bda78498 --- /dev/null +++ b/compiler/dex/quick_compiler_callbacks.cc @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/compiler/driver/compiler_callbacks_impl.h b/compiler/dex/quick_compiler_callbacks.h index 92adb20c1f..7c9614f73a 100644 --- a/compiler/driver/compiler_callbacks_impl.h +++ b/compiler/dex/quick_compiler_callbacks.h @@ -14,48 +14,38 @@ * 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_ diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index e175d37914..89295f2786 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -20,12 +20,10 @@ #include "compiler_driver.h" #include "dex/compiler_ir.h" -#include "mirror/art_field.h" +#include "field_helper.h" #include "mirror/art_field-inl.h" -#include "mirror/art_method.h" #include "mirror/art_method-inl.h" #include "mirror/class_loader.h" -#include "mirror/dex_cache.h" #include "mirror/dex_cache-inl.h" #include "mirror/art_field-inl.h" #include "scoped_thread_state_change.h" diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 7014c3b3f8..9e88c8d875 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -35,7 +35,7 @@ #include "dex/quick/dex_file_method_inliner.h" #include "driver/compiler_options.h" #include "jni_internal.h" -#include "object_utils.h" +#include "object_lock.h" #include "profiler.h" #include "runtime.h" #include "gc/accounting/card_table-inl.h" diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 5325a68b37..9ae9bd400a 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -25,12 +25,13 @@ #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 { diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index e637cfbe1d..e479322238 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -16,8 +16,10 @@ #include "elf_file.h" +#include "base/stringprintf.h" #include "common_compiler_test.h" #include "oat.h" +#include "utils.h" namespace art { diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 6b2698085c..982e6d4f2c 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -20,14 +20,16 @@ #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" @@ -138,7 +140,7 @@ TEST_F(ImageTest, WriteRead) { // 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))); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 38b4100ebe..8ef2964270 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -51,7 +51,6 @@ #include "mirror/string-inl.h" #include "oat.h" #include "oat_file.h" -#include "object_utils.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "handle_scope-inl.h" diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h index efc0b42db4..6db0c3b8b3 100644 --- a/compiler/jni/quick/calling_convention.h +++ b/compiler/jni/quick/calling_convention.h @@ -19,6 +19,7 @@ #include <vector> #include "handle_scope.h" +#include "primitive.h" #include "thread.h" #include "utils/managed_register.h" diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index d2ee0ede80..1444ca0309 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -15,15 +15,19 @@ */ #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 { @@ -95,8 +99,8 @@ TEST_F(OatTest, WriteRead) { 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(), diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index b0e6a75b3d..e0db0f18be 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -38,7 +38,7 @@ void CodeGenerator::CompileBaseline(CodeAllocator* allocator) { DCHECK_EQ(frame_size_, kUninitializedFrameSize); ComputeFrameSize(GetGraph()->GetMaximumNumberOfOutVRegs() - + GetGraph()->GetNumberOfVRegs() + + GetGraph()->GetNumberOfLocalVRegs() + GetGraph()->GetNumberOfTemporaries() + 1 /* filler */); GenerateFrameEntry(); @@ -106,6 +106,39 @@ size_t CodeGenerator::AllocateFreeRegisterInternal( return -1; } +void CodeGenerator::ComputeFrameSize(size_t number_of_spill_slots) { + SetFrameSize(RoundUp( + number_of_spill_slots * kVRegSize + + kVRegSize // Art method + + FrameEntrySpillSize(), + kStackAlignment)); +} + +Location CodeGenerator::GetTemporaryLocation(HTemporary* temp) const { + uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs(); + // Use the temporary region (right below the dex registers). + int32_t slot = GetFrameSize() - FrameEntrySpillSize() + - kVRegSize // filler + - (number_of_locals * kVRegSize) + - ((1 + temp->GetIndex()) * kVRegSize); + return Location::StackSlot(slot); +} + +int32_t CodeGenerator::GetStackSlot(HLocal* local) const { + uint16_t reg_number = local->GetRegNumber(); + uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs(); + if (reg_number >= number_of_locals) { + // Local is a parameter of the method. It is stored in the caller's frame. + return GetFrameSize() + kVRegSize // ART method + + (reg_number - number_of_locals) * kVRegSize; + } else { + // Local is a temporary in this method. It is stored in this method's frame. + return GetFrameSize() - FrameEntrySpillSize() + - kVRegSize // filler. + - (number_of_locals * kVRegSize) + + (reg_number * kVRegSize); + } +} void CodeGenerator::AllocateRegistersLocally(HInstruction* instruction) const { LocationSummary* locations = instruction->GetLocations(); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index abfb790d8f..18e3e5a056 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -96,7 +96,10 @@ class CodeGenerator : public ArenaObject { virtual HGraphVisitor* GetInstructionVisitor() = 0; virtual Assembler* GetAssembler() = 0; virtual size_t GetWordSize() const = 0; - virtual void ComputeFrameSize(size_t number_of_spill_slots) = 0; + void ComputeFrameSize(size_t number_of_spill_slots); + virtual size_t FrameEntrySpillSize() const = 0; + int32_t GetStackSlot(HLocal* local) const; + Location GetTemporaryLocation(HTemporary* temp) const; uint32_t GetFrameSize() const { return frame_size_; } void SetFrameSize(uint32_t size) { frame_size_ = size; } @@ -150,7 +153,6 @@ class CodeGenerator : public ArenaObject { size_t AllocateFreeRegisterInternal(bool* blocked_registers, size_t number_of_registers) const; virtual Location GetStackLocation(HLoadLocal* load) const = 0; - virtual Location GetTemporaryLocation(HTemporary* temp) const = 0; // Frame size required for this method. uint32_t frame_size_; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index e70240783a..73c2d48320 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -99,6 +99,10 @@ CodeGeneratorARM::CodeGeneratorARM(HGraph* graph) instruction_visitor_(graph, this), move_resolver_(graph->GetArena(), this) {} +size_t CodeGeneratorARM::FrameEntrySpillSize() const { + return kNumberOfPushedRegistersAtEntry * kArmWordSize; +} + static bool* GetBlockedRegisterPairs(bool* blocked_registers) { return blocked_registers + kNumberOfAllocIds; } @@ -200,14 +204,6 @@ InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGene assembler_(codegen->GetAssembler()), codegen_(codegen) {} -void CodeGeneratorARM::ComputeFrameSize(size_t number_of_spill_slots) { - SetFrameSize(RoundUp( - number_of_spill_slots * kVRegSize - + kVRegSize // Art method - + kNumberOfPushedRegistersAtEntry * kArmWordSize, - kStackAlignment)); -} - void CodeGeneratorARM::GenerateFrameEntry() { core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7); __ PushList(1 << LR | 1 << R6 | 1 << R7); @@ -226,33 +222,6 @@ void CodeGeneratorARM::Bind(Label* label) { __ Bind(label); } -Location CodeGeneratorARM::GetTemporaryLocation(HTemporary* temp) const { - uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); - // Use the temporary region (right below the dex registers). - int32_t slot = GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize) - - kVRegSize // filler - - (number_of_vregs * kVRegSize) - - ((1 + temp->GetIndex()) * kVRegSize); - return Location::StackSlot(slot); -} - -int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { - uint16_t reg_number = local->GetRegNumber(); - uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); - uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); - if (reg_number >= number_of_vregs - number_of_in_vregs) { - // Local is a parameter of the method. It is stored in the caller's frame. - return GetFrameSize() + kVRegSize // ART method - + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; - } else { - // Local is a temporary in this method. It is stored in this method's frame. - return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize) - - kVRegSize // filler. - - (number_of_vregs * kVRegSize) - + (reg_number * kVRegSize); - } -} - Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { switch (load->GetType()) { case Primitive::kPrimLong: diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index b7322b271e..1b5974f9a2 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -126,7 +126,6 @@ class CodeGeneratorARM : public CodeGenerator { explicit CodeGeneratorARM(HGraph* graph); virtual ~CodeGeneratorARM() { } - virtual void ComputeFrameSize(size_t number_of_spill_slots) OVERRIDE; virtual void GenerateFrameEntry() OVERRIDE; virtual void GenerateFrameExit() OVERRIDE; virtual void Bind(Label* label) OVERRIDE; @@ -136,6 +135,8 @@ class CodeGeneratorARM : public CodeGenerator { return kArmWordSize; } + virtual size_t FrameEntrySpillSize() const OVERRIDE; + virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } @@ -153,9 +154,7 @@ class CodeGeneratorARM : public CodeGenerator { Primitive::Type type, bool* blocked_registers) const OVERRIDE; virtual size_t GetNumberOfRegisters() const OVERRIDE; - int32_t GetStackSlot(HLocal* local) const; virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE; - virtual Location GetTemporaryLocation(HTemporary* temp) const OVERRIDE; virtual size_t GetNumberOfCoreRegisters() const OVERRIDE { return kNumberOfCoreRegisters; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 52cb39dc7f..4e69a0cad8 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -83,12 +83,8 @@ CodeGeneratorX86::CodeGeneratorX86(HGraph* graph) instruction_visitor_(graph, this), move_resolver_(graph->GetArena(), this) {} -void CodeGeneratorX86::ComputeFrameSize(size_t number_of_spill_slots) { - SetFrameSize(RoundUp( - number_of_spill_slots * kVRegSize - + kVRegSize // Art method - + kNumberOfPushedRegistersAtEntry * kX86WordSize, - kStackAlignment)); +size_t CodeGeneratorX86::FrameEntrySpillSize() const { + return kNumberOfPushedRegistersAtEntry * kX86WordSize; } static bool* GetBlockedRegisterPairs(bool* blocked_registers) { @@ -204,34 +200,6 @@ void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) { __ movl(reg, Address(ESP, kCurrentMethodStackOffset)); } -Location CodeGeneratorX86::GetTemporaryLocation(HTemporary* temp) const { - uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); - // Use the temporary region (right below the dex registers). - int32_t slot = GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86WordSize) - - kVRegSize // filler - - (number_of_vregs * kVRegSize) - - ((1 + temp->GetIndex()) * kVRegSize); - return Location::StackSlot(slot); -} - -int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const { - uint16_t reg_number = local->GetRegNumber(); - uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); - uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); - if (reg_number >= number_of_vregs - number_of_in_vregs) { - // Local is a parameter of the method. It is stored in the caller's frame. - return GetFrameSize() + kVRegSize // ART method - + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; - } else { - // Local is a temporary in this method. It is stored in this method's frame. - return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86WordSize) - - kVRegSize // filler. - - (number_of_vregs * kVRegSize) - + (reg_number * kVRegSize); - } -} - - Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const { switch (load->GetType()) { case Primitive::kPrimLong: diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 2a4595447d..d622d2a685 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -128,7 +128,6 @@ class CodeGeneratorX86 : public CodeGenerator { explicit CodeGeneratorX86(HGraph* graph); virtual ~CodeGeneratorX86() { } - virtual void ComputeFrameSize(size_t number_of_spill_slots) OVERRIDE; virtual void GenerateFrameEntry() OVERRIDE; virtual void GenerateFrameExit() OVERRIDE; virtual void Bind(Label* label) OVERRIDE; @@ -138,6 +137,8 @@ class CodeGeneratorX86 : public CodeGenerator { return kX86WordSize; } + virtual size_t FrameEntrySpillSize() const OVERRIDE; + virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } @@ -155,9 +156,7 @@ class CodeGeneratorX86 : public CodeGenerator { virtual ManagedRegister AllocateFreeRegister( Primitive::Type type, bool* blocked_registers) const OVERRIDE; - int32_t GetStackSlot(HLocal* local) const; virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE; - virtual Location GetTemporaryLocation(HTemporary* temp) const OVERRIDE; virtual size_t GetNumberOfCoreRegisters() const OVERRIDE { return kNumberOfCpuRegisters; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 93d74ee1a2..e3ce5ceb4f 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -91,6 +91,10 @@ CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph) instruction_visitor_(graph, this), move_resolver_(graph->GetArena(), this) {} +size_t CodeGeneratorX86_64::FrameEntrySpillSize() const { + return kNumberOfPushedRegistersAtEntry * kX86_64WordSize; +} + InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen) : HGraphVisitor(graph), assembler_(codegen->GetAssembler()), @@ -137,16 +141,6 @@ void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const { blocked_registers[R15] = true; } -void CodeGeneratorX86_64::ComputeFrameSize(size_t number_of_spill_slots) { - // Add the current ART method to the frame size, the return PC, and the filler. - SetFrameSize(RoundUp( - number_of_spill_slots * kVRegSize - + kVRegSize // filler - + kVRegSize // Art method - + kNumberOfPushedRegistersAtEntry * kX86_64WordSize, - kStackAlignment)); -} - void CodeGeneratorX86_64::GenerateFrameEntry() { // Create a fake register to mimic Quick. static const int kFakeReturnRegister = 16; @@ -170,33 +164,6 @@ void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) { __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset)); } -Location CodeGeneratorX86_64::GetTemporaryLocation(HTemporary* temp) const { - uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); - // Use the temporary region (right below the dex registers). - int32_t slot = GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86_64WordSize) - - kVRegSize // filler - - (number_of_vregs * kVRegSize) - - ((1 + temp->GetIndex()) * kVRegSize); - return Location::StackSlot(slot); -} - -int32_t CodeGeneratorX86_64::GetStackSlot(HLocal* local) const { - uint16_t reg_number = local->GetRegNumber(); - uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); - uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); - if (reg_number >= number_of_vregs - number_of_in_vregs) { - // Local is a parameter of the method. It is stored in the caller's frame. - return GetFrameSize() + kVRegSize // ART method - + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; - } else { - // Local is a temporary in this method. It is stored in this method's frame. - return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86_64WordSize) - - kVRegSize // filler - - (number_of_vregs * kVRegSize) - + (reg_number * kVRegSize); - } -} - Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const { switch (load->GetType()) { case Primitive::kPrimLong: diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 97a0b2e579..8283dda4a5 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -125,7 +125,6 @@ class CodeGeneratorX86_64 : public CodeGenerator { explicit CodeGeneratorX86_64(HGraph* graph); virtual ~CodeGeneratorX86_64() {} - virtual void ComputeFrameSize(size_t number_of_spill_slots) OVERRIDE; virtual void GenerateFrameEntry() OVERRIDE; virtual void GenerateFrameExit() OVERRIDE; virtual void Bind(Label* label) OVERRIDE; @@ -135,6 +134,8 @@ class CodeGeneratorX86_64 : public CodeGenerator { return kX86_64WordSize; } + virtual size_t FrameEntrySpillSize() const OVERRIDE; + virtual HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } @@ -151,9 +152,7 @@ class CodeGeneratorX86_64 : public CodeGenerator { return &move_resolver_; } - int32_t GetStackSlot(HLocal* local) const; virtual Location GetStackLocation(HLoadLocal* load) const OVERRIDE; - virtual Location GetTemporaryLocation(HTemporary* temp) const OVERRIDE; virtual size_t GetNumberOfRegisters() const OVERRIDE { return kNumberOfRegIds; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 689aab08b3..e87b044cc9 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -19,6 +19,7 @@ #include "locations.h" #include "offsets.h" +#include "primitive.h" #include "utils/allocation.h" #include "utils/arena_bit_vector.h" #include "utils/growable_array.h" @@ -138,6 +139,10 @@ class HGraph : public ArenaObject { return number_of_in_vregs_; } + uint16_t GetNumberOfLocalVRegs() const { + return number_of_vregs_ - number_of_in_vregs_; + } + const GrowableArray<HBasicBlock*>& GetReversePostOrder() const { return reverse_post_order_; } diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h index 7d4cd1a862..e35ff56c75 100644 --- a/compiler/optimizing/register_allocator.h +++ b/compiler/optimizing/register_allocator.h @@ -18,6 +18,7 @@ #define ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_H_ #include "base/macros.h" +#include "primitive.h" #include "utils/growable_array.h" namespace art { diff --git a/compiler/output_stream_test.cc b/compiler/output_stream_test.cc index 5fa0ccb143..315ca09e59 100644 --- a/compiler/output_stream_test.cc +++ b/compiler/output_stream_test.cc @@ -17,6 +17,7 @@ #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" diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 0d40c8d209..77946b03ae 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -40,7 +40,8 @@ #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" @@ -56,7 +57,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "oat_writer.h" -#include "object_utils.h" #include "os.h" #include "runtime.h" #include "ScopedLocalRef.h" @@ -233,7 +233,7 @@ static void Usage(const char* fmt, ...) { 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, @@ -460,7 +460,7 @@ class Dex2Oat { 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"; @@ -1230,7 +1230,7 @@ static int dex2oat(int argc, char** argv) { 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); @@ -1249,7 +1249,7 @@ static int dex2oat(int argc, char** argv) { 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", diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 0fa1a96bd9..b8f20f3650 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -29,6 +29,7 @@ #include "dex_file-inl.h" #include "dex_instruction.h" #include "disassembler.h" +#include "field_helper.h" #include "gc_map.h" #include "gc/space/image_space.h" #include "gc/space/large_object_space.h" @@ -45,7 +46,6 @@ #include "noop_compiler_callbacks.h" #include "oat.h" #include "oat_file-inl.h" -#include "object_utils.h" #include "os.h" #include "runtime.h" #include "safe_map.h" @@ -1548,7 +1548,7 @@ static int oatdump(int argc, char** argv) { return EXIT_SUCCESS; } - Runtime::Options options; + RuntimeOptions options; std::string image_option; std::string oat_option; std::string boot_image_option; diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index dcf8c70501..85b4e6df32 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -26,6 +26,7 @@ #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" @@ -92,7 +93,7 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta, } // 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; @@ -176,7 +177,7 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o } // 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; diff --git a/runtime/Android.mk b/runtime/Android.mk index b0c1a9ca04..f2d3c8e8c0 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -19,290 +19,294 @@ LOCAL_PATH := $(call my-dir) include art/build/Android.common_build.mk LIBART_COMMON_SRC_FILES := \ - atomic.cc.arm \ - barrier.cc \ - base/allocator.cc \ - base/bit_vector.cc \ - base/hex_dump.cc \ - base/logging.cc \ - base/mutex.cc \ - base/scoped_flock.cc \ - base/stringpiece.cc \ - base/stringprintf.cc \ - base/timing_logger.cc \ - base/unix_file/fd_file.cc \ - base/unix_file/mapped_file.cc \ - base/unix_file/null_file.cc \ - base/unix_file/random_access_file_utils.cc \ - base/unix_file/string_file.cc \ - check_jni.cc \ - class_linker.cc \ - common_throws.cc \ - debugger.cc \ - dex_file.cc \ - dex_file_verifier.cc \ - dex_instruction.cc \ - elf_file.cc \ - gc/allocator/dlmalloc.cc \ - gc/allocator/rosalloc.cc \ - gc/accounting/card_table.cc \ - gc/accounting/gc_allocator.cc \ - gc/accounting/heap_bitmap.cc \ - gc/accounting/mod_union_table.cc \ - gc/accounting/remembered_set.cc \ - gc/accounting/space_bitmap.cc \ - gc/collector/concurrent_copying.cc \ - gc/collector/garbage_collector.cc \ - gc/collector/immune_region.cc \ - gc/collector/mark_compact.cc \ - gc/collector/mark_sweep.cc \ - gc/collector/partial_mark_sweep.cc \ - gc/collector/semi_space.cc \ - gc/collector/sticky_mark_sweep.cc \ - gc/gc_cause.cc \ - gc/heap.cc \ - gc/reference_processor.cc \ - gc/reference_queue.cc \ - gc/space/bump_pointer_space.cc \ - gc/space/dlmalloc_space.cc \ - gc/space/image_space.cc \ - gc/space/large_object_space.cc \ - gc/space/malloc_space.cc \ - gc/space/rosalloc_space.cc \ - gc/space/space.cc \ - gc/space/zygote_space.cc \ - hprof/hprof.cc \ - image.cc \ - indirect_reference_table.cc \ - instruction_set.cc \ - instrumentation.cc \ - intern_table.cc \ - interpreter/interpreter.cc \ - interpreter/interpreter_common.cc \ - interpreter/interpreter_switch_impl.cc \ - jdwp/jdwp_event.cc \ - jdwp/jdwp_expand_buf.cc \ - jdwp/jdwp_handler.cc \ - jdwp/jdwp_main.cc \ - jdwp/jdwp_request.cc \ - jdwp/jdwp_socket.cc \ - jdwp/object_registry.cc \ - jni_internal.cc \ - jobject_comparator.cc \ - mem_map.cc \ - memory_region.cc \ - mirror/art_field.cc \ - mirror/art_method.cc \ - mirror/array.cc \ - mirror/class.cc \ - mirror/dex_cache.cc \ - mirror/object.cc \ - mirror/stack_trace_element.cc \ - mirror/string.cc \ - mirror/throwable.cc \ - monitor.cc \ - native/dalvik_system_DexFile.cc \ - native/dalvik_system_VMDebug.cc \ - native/dalvik_system_VMRuntime.cc \ - native/dalvik_system_VMStack.cc \ - native/dalvik_system_ZygoteHooks.cc \ - native/java_lang_Class.cc \ - native/java_lang_DexCache.cc \ - native/java_lang_Object.cc \ - native/java_lang_Runtime.cc \ - native/java_lang_String.cc \ - native/java_lang_System.cc \ - native/java_lang_Thread.cc \ - native/java_lang_Throwable.cc \ - native/java_lang_VMClassLoader.cc \ - native/java_lang_ref_Reference.cc \ - native/java_lang_reflect_Array.cc \ - native/java_lang_reflect_Constructor.cc \ - native/java_lang_reflect_Field.cc \ - native/java_lang_reflect_Method.cc \ - native/java_lang_reflect_Proxy.cc \ - native/java_util_concurrent_atomic_AtomicLong.cc \ - native/org_apache_harmony_dalvik_ddmc_DdmServer.cc \ - native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \ - native/sun_misc_Unsafe.cc \ - oat.cc \ - oat_file.cc \ - offsets.cc \ - os_linux.cc \ - parsed_options.cc \ - primitive.cc \ - quick_exception_handler.cc \ - quick/inline_method_analyser.cc \ - reference_table.cc \ - reflection.cc \ - runtime.cc \ - signal_catcher.cc \ - stack.cc \ - thread.cc \ - thread_list.cc \ - thread_pool.cc \ - throw_location.cc \ - trace.cc \ - transaction.cc \ - profiler.cc \ - fault_handler.cc \ - utf.cc \ - utils.cc \ - verifier/dex_gc_map.cc \ - verifier/instruction_flags.cc \ - verifier/method_verifier.cc \ - verifier/reg_type.cc \ - verifier/reg_type_cache.cc \ - verifier/register_line.cc \ - well_known_classes.cc \ - zip_archive.cc + atomic.cc.arm \ + barrier.cc \ + base/allocator.cc \ + base/bit_vector.cc \ + base/hex_dump.cc \ + base/logging.cc \ + base/mutex.cc \ + base/scoped_flock.cc \ + base/stringpiece.cc \ + base/stringprintf.cc \ + base/timing_logger.cc \ + base/unix_file/fd_file.cc \ + base/unix_file/mapped_file.cc \ + base/unix_file/null_file.cc \ + base/unix_file/random_access_file_utils.cc \ + base/unix_file/string_file.cc \ + check_jni.cc \ + class_linker.cc \ + common_throws.cc \ + debugger.cc \ + dex_file.cc \ + dex_file_verifier.cc \ + dex_instruction.cc \ + elf_file.cc \ + field_helper.cc \ + gc/allocator/dlmalloc.cc \ + gc/allocator/rosalloc.cc \ + gc/accounting/card_table.cc \ + gc/accounting/gc_allocator.cc \ + gc/accounting/heap_bitmap.cc \ + gc/accounting/mod_union_table.cc \ + gc/accounting/remembered_set.cc \ + gc/accounting/space_bitmap.cc \ + gc/collector/concurrent_copying.cc \ + gc/collector/garbage_collector.cc \ + gc/collector/immune_region.cc \ + gc/collector/mark_compact.cc \ + gc/collector/mark_sweep.cc \ + gc/collector/partial_mark_sweep.cc \ + gc/collector/semi_space.cc \ + gc/collector/sticky_mark_sweep.cc \ + gc/gc_cause.cc \ + gc/heap.cc \ + gc/reference_processor.cc \ + gc/reference_queue.cc \ + gc/space/bump_pointer_space.cc \ + gc/space/dlmalloc_space.cc \ + gc/space/image_space.cc \ + gc/space/large_object_space.cc \ + gc/space/malloc_space.cc \ + gc/space/rosalloc_space.cc \ + gc/space/space.cc \ + gc/space/zygote_space.cc \ + hprof/hprof.cc \ + image.cc \ + indirect_reference_table.cc \ + instruction_set.cc \ + instrumentation.cc \ + intern_table.cc \ + interpreter/interpreter.cc \ + interpreter/interpreter_common.cc \ + interpreter/interpreter_switch_impl.cc \ + jdwp/jdwp_event.cc \ + jdwp/jdwp_expand_buf.cc \ + jdwp/jdwp_handler.cc \ + jdwp/jdwp_main.cc \ + jdwp/jdwp_request.cc \ + jdwp/jdwp_socket.cc \ + jdwp/object_registry.cc \ + jni_internal.cc \ + jobject_comparator.cc \ + mem_map.cc \ + memory_region.cc \ + method_helper.cc \ + mirror/art_field.cc \ + mirror/art_method.cc \ + mirror/array.cc \ + mirror/class.cc \ + mirror/dex_cache.cc \ + mirror/object.cc \ + mirror/reference.cc \ + mirror/stack_trace_element.cc \ + mirror/string.cc \ + mirror/throwable.cc \ + monitor.cc \ + native/dalvik_system_DexFile.cc \ + native/dalvik_system_VMDebug.cc \ + native/dalvik_system_VMRuntime.cc \ + native/dalvik_system_VMStack.cc \ + native/dalvik_system_ZygoteHooks.cc \ + native/java_lang_Class.cc \ + native/java_lang_DexCache.cc \ + native/java_lang_Object.cc \ + native/java_lang_Runtime.cc \ + native/java_lang_String.cc \ + native/java_lang_System.cc \ + native/java_lang_Thread.cc \ + native/java_lang_Throwable.cc \ + native/java_lang_VMClassLoader.cc \ + native/java_lang_ref_Reference.cc \ + native/java_lang_reflect_Array.cc \ + native/java_lang_reflect_Constructor.cc \ + native/java_lang_reflect_Field.cc \ + native/java_lang_reflect_Method.cc \ + native/java_lang_reflect_Proxy.cc \ + native/java_util_concurrent_atomic_AtomicLong.cc \ + native/org_apache_harmony_dalvik_ddmc_DdmServer.cc \ + native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \ + native/sun_misc_Unsafe.cc \ + oat.cc \ + oat_file.cc \ + object_lock.cc \ + offsets.cc \ + os_linux.cc \ + parsed_options.cc \ + primitive.cc \ + quick_exception_handler.cc \ + quick/inline_method_analyser.cc \ + reference_table.cc \ + reflection.cc \ + runtime.cc \ + signal_catcher.cc \ + stack.cc \ + thread.cc \ + thread_list.cc \ + thread_pool.cc \ + throw_location.cc \ + trace.cc \ + transaction.cc \ + profiler.cc \ + fault_handler.cc \ + utf.cc \ + utils.cc \ + verifier/dex_gc_map.cc \ + verifier/instruction_flags.cc \ + verifier/method_verifier.cc \ + verifier/reg_type.cc \ + verifier/reg_type_cache.cc \ + verifier/register_line.cc \ + well_known_classes.cc \ + zip_archive.cc LIBART_COMMON_SRC_FILES += \ - arch/context.cc \ - arch/memcmp16.cc \ - arch/arm/registers_arm.cc \ - arch/arm64/registers_arm64.cc \ - arch/x86/registers_x86.cc \ - arch/mips/registers_mips.cc \ - entrypoints/entrypoint_utils.cc \ - entrypoints/interpreter/interpreter_entrypoints.cc \ - entrypoints/jni/jni_entrypoints.cc \ - entrypoints/math_entrypoints.cc \ - entrypoints/portable/portable_alloc_entrypoints.cc \ - entrypoints/portable/portable_cast_entrypoints.cc \ - entrypoints/portable/portable_dexcache_entrypoints.cc \ - entrypoints/portable/portable_field_entrypoints.cc \ - entrypoints/portable/portable_fillarray_entrypoints.cc \ - entrypoints/portable/portable_invoke_entrypoints.cc \ - entrypoints/portable/portable_jni_entrypoints.cc \ - entrypoints/portable/portable_lock_entrypoints.cc \ - entrypoints/portable/portable_thread_entrypoints.cc \ - entrypoints/portable/portable_throw_entrypoints.cc \ - entrypoints/portable/portable_trampoline_entrypoints.cc \ - entrypoints/quick/quick_alloc_entrypoints.cc \ - entrypoints/quick/quick_cast_entrypoints.cc \ - entrypoints/quick/quick_deoptimization_entrypoints.cc \ - entrypoints/quick/quick_dexcache_entrypoints.cc \ - entrypoints/quick/quick_field_entrypoints.cc \ - entrypoints/quick/quick_fillarray_entrypoints.cc \ - entrypoints/quick/quick_instrumentation_entrypoints.cc \ - entrypoints/quick/quick_jni_entrypoints.cc \ - entrypoints/quick/quick_lock_entrypoints.cc \ - entrypoints/quick/quick_math_entrypoints.cc \ - entrypoints/quick/quick_thread_entrypoints.cc \ - entrypoints/quick/quick_throw_entrypoints.cc \ - entrypoints/quick/quick_trampoline_entrypoints.cc + arch/context.cc \ + arch/memcmp16.cc \ + arch/arm/registers_arm.cc \ + arch/arm64/registers_arm64.cc \ + arch/x86/registers_x86.cc \ + arch/mips/registers_mips.cc \ + entrypoints/entrypoint_utils.cc \ + entrypoints/interpreter/interpreter_entrypoints.cc \ + entrypoints/jni/jni_entrypoints.cc \ + entrypoints/math_entrypoints.cc \ + entrypoints/portable/portable_alloc_entrypoints.cc \ + entrypoints/portable/portable_cast_entrypoints.cc \ + entrypoints/portable/portable_dexcache_entrypoints.cc \ + entrypoints/portable/portable_field_entrypoints.cc \ + entrypoints/portable/portable_fillarray_entrypoints.cc \ + entrypoints/portable/portable_invoke_entrypoints.cc \ + entrypoints/portable/portable_jni_entrypoints.cc \ + entrypoints/portable/portable_lock_entrypoints.cc \ + entrypoints/portable/portable_thread_entrypoints.cc \ + entrypoints/portable/portable_throw_entrypoints.cc \ + entrypoints/portable/portable_trampoline_entrypoints.cc \ + entrypoints/quick/quick_alloc_entrypoints.cc \ + entrypoints/quick/quick_cast_entrypoints.cc \ + entrypoints/quick/quick_deoptimization_entrypoints.cc \ + entrypoints/quick/quick_dexcache_entrypoints.cc \ + entrypoints/quick/quick_field_entrypoints.cc \ + entrypoints/quick/quick_fillarray_entrypoints.cc \ + entrypoints/quick/quick_instrumentation_entrypoints.cc \ + entrypoints/quick/quick_jni_entrypoints.cc \ + entrypoints/quick/quick_lock_entrypoints.cc \ + entrypoints/quick/quick_math_entrypoints.cc \ + entrypoints/quick/quick_thread_entrypoints.cc \ + entrypoints/quick/quick_throw_entrypoints.cc \ + entrypoints/quick/quick_trampoline_entrypoints.cc # Source files that only compile with GCC. LIBART_GCC_ONLY_SRC_FILES := \ - interpreter/interpreter_goto_table_impl.cc + interpreter/interpreter_goto_table_impl.cc LIBART_TARGET_LDFLAGS := LIBART_HOST_LDFLAGS := LIBART_TARGET_SRC_FILES := \ - $(LIBART_COMMON_SRC_FILES) \ - base/logging_android.cc \ - jdwp/jdwp_adb.cc \ - monitor_android.cc \ - runtime_android.cc \ - thread_android.cc + $(LIBART_COMMON_SRC_FILES) \ + base/logging_android.cc \ + jdwp/jdwp_adb.cc \ + monitor_android.cc \ + runtime_android.cc \ + thread_android.cc LIBART_TARGET_SRC_FILES_arm := \ - arch/arm/context_arm.cc.arm \ - arch/arm/entrypoints_init_arm.cc \ - arch/arm/jni_entrypoints_arm.S \ - arch/arm/memcmp16_arm.S \ - arch/arm/portable_entrypoints_arm.S \ - arch/arm/quick_entrypoints_arm.S \ - arch/arm/arm_sdiv.S \ - arch/arm/thread_arm.cc \ - arch/arm/fault_handler_arm.cc + arch/arm/context_arm.cc.arm \ + arch/arm/entrypoints_init_arm.cc \ + arch/arm/jni_entrypoints_arm.S \ + arch/arm/memcmp16_arm.S \ + arch/arm/portable_entrypoints_arm.S \ + arch/arm/quick_entrypoints_arm.S \ + arch/arm/arm_sdiv.S \ + arch/arm/thread_arm.cc \ + arch/arm/fault_handler_arm.cc LIBART_TARGET_SRC_FILES_arm64 := \ - arch/arm64/context_arm64.cc \ - arch/arm64/entrypoints_init_arm64.cc \ - arch/arm64/jni_entrypoints_arm64.S \ - arch/arm64/memcmp16_arm64.S \ - arch/arm64/portable_entrypoints_arm64.S \ - arch/arm64/quick_entrypoints_arm64.S \ - arch/arm64/thread_arm64.cc \ - monitor_pool.cc \ - arch/arm64/fault_handler_arm64.cc + arch/arm64/context_arm64.cc \ + arch/arm64/entrypoints_init_arm64.cc \ + arch/arm64/jni_entrypoints_arm64.S \ + arch/arm64/memcmp16_arm64.S \ + arch/arm64/portable_entrypoints_arm64.S \ + arch/arm64/quick_entrypoints_arm64.S \ + arch/arm64/thread_arm64.cc \ + monitor_pool.cc \ + arch/arm64/fault_handler_arm64.cc LIBART_SRC_FILES_x86 := \ - arch/x86/context_x86.cc \ - arch/x86/entrypoints_init_x86.cc \ - arch/x86/jni_entrypoints_x86.S \ - arch/x86/portable_entrypoints_x86.S \ - arch/x86/quick_entrypoints_x86.S \ - arch/x86/thread_x86.cc \ - arch/x86/fault_handler_x86.cc + arch/x86/context_x86.cc \ + arch/x86/entrypoints_init_x86.cc \ + arch/x86/jni_entrypoints_x86.S \ + arch/x86/portable_entrypoints_x86.S \ + arch/x86/quick_entrypoints_x86.S \ + arch/x86/thread_x86.cc \ + arch/x86/fault_handler_x86.cc LIBART_TARGET_SRC_FILES_x86 := \ - $(LIBART_SRC_FILES_x86) + $(LIBART_SRC_FILES_x86) LIBART_SRC_FILES_x86_64 := \ - arch/x86_64/context_x86_64.cc \ - arch/x86_64/entrypoints_init_x86_64.cc \ - arch/x86_64/jni_entrypoints_x86_64.S \ - arch/x86_64/portable_entrypoints_x86_64.S \ - arch/x86_64/quick_entrypoints_x86_64.S \ - arch/x86_64/thread_x86_64.cc \ - monitor_pool.cc \ - arch/x86_64/fault_handler_x86_64.cc + arch/x86_64/context_x86_64.cc \ + arch/x86_64/entrypoints_init_x86_64.cc \ + arch/x86_64/jni_entrypoints_x86_64.S \ + arch/x86_64/portable_entrypoints_x86_64.S \ + arch/x86_64/quick_entrypoints_x86_64.S \ + arch/x86_64/thread_x86_64.cc \ + monitor_pool.cc \ + arch/x86_64/fault_handler_x86_64.cc LIBART_TARGET_SRC_FILES_x86_64 := \ - $(LIBART_SRC_FILES_x86_64) \ + $(LIBART_SRC_FILES_x86_64) \ LIBART_TARGET_SRC_FILES_mips := \ - arch/mips/context_mips.cc \ - arch/mips/entrypoints_init_mips.cc \ - arch/mips/jni_entrypoints_mips.S \ - arch/mips/memcmp16_mips.S \ - arch/mips/portable_entrypoints_mips.S \ - arch/mips/quick_entrypoints_mips.S \ - arch/mips/thread_mips.cc \ - arch/mips/fault_handler_mips.cc + arch/mips/context_mips.cc \ + arch/mips/entrypoints_init_mips.cc \ + arch/mips/jni_entrypoints_mips.S \ + arch/mips/memcmp16_mips.S \ + arch/mips/portable_entrypoints_mips.S \ + arch/mips/quick_entrypoints_mips.S \ + arch/mips/thread_mips.cc \ + arch/mips/fault_handler_mips.cc ifeq ($(TARGET_ARCH),mips64) $(info TODOMips64: $(LOCAL_PATH)/Android.mk Add mips64 specific runtime files) endif # TARGET_ARCH != mips64 LIBART_HOST_SRC_FILES := \ - $(LIBART_COMMON_SRC_FILES) \ - base/logging_linux.cc \ - monitor_linux.cc \ - runtime_linux.cc \ - thread_linux.cc + $(LIBART_COMMON_SRC_FILES) \ + base/logging_linux.cc \ + monitor_linux.cc \ + runtime_linux.cc \ + thread_linux.cc LIBART_HOST_SRC_FILES_32 := \ - $(LIBART_SRC_FILES_x86) + $(LIBART_SRC_FILES_x86) LIBART_HOST_SRC_FILES_64 := \ - $(LIBART_SRC_FILES_x86_64) + $(LIBART_SRC_FILES_x86_64) LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \ - arch/x86_64/registers_x86_64.h \ - base/mutex.h \ - dex_file.h \ - dex_instruction.h \ - gc/collector/gc_type.h \ - gc/space/space.h \ - gc/heap.h \ - indirect_reference_table.h \ - instruction_set.h \ - invoke_type.h \ - jdwp/jdwp.h \ - jdwp/jdwp_constants.h \ - lock_word.h \ - mirror/class.h \ - oat.h \ - object_callbacks.h \ - quick/inline_method_analyser.h \ - thread.h \ - thread_state.h \ - verifier/method_verifier.h + arch/x86_64/registers_x86_64.h \ + base/mutex.h \ + dex_file.h \ + dex_instruction.h \ + gc/collector/gc_type.h \ + gc/space/space.h \ + gc/heap.h \ + indirect_reference_table.h \ + instruction_set.h \ + invoke_type.h \ + jdwp/jdwp.h \ + jdwp/jdwp_constants.h \ + lock_word.h \ + mirror/class.h \ + oat.h \ + object_callbacks.h \ + quick/inline_method_analyser.h \ + thread.h \ + thread_state.h \ + verifier/method_verifier.h LIBART_CFLAGS := ifeq ($(ART_USE_PORTABLE_COMPILER),true) diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index cf68c65dbd..8c6afd66bd 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -26,11 +26,11 @@ namespace art { // 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*); diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index ce8faea709..25f9a5a251 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -14,13 +14,14 @@ * 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 { @@ -45,7 +46,7 @@ class StubTest : public CommonRuntimeTest { } } - 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) { diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc index 086ef440a3..de348dc79d 100644 --- a/runtime/barrier_test.cc +++ b/runtime/barrier_test.cc @@ -22,6 +22,7 @@ #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 { diff --git a/runtime/base/mutex_test.cc b/runtime/base/mutex_test.cc index ee0b1beba9..289d3ef8c1 100644 --- a/runtime/base/mutex_test.cc +++ b/runtime/base/mutex_test.cc @@ -17,6 +17,7 @@ #include "mutex.h" #include "common_runtime_test.h" +#include "thread-inl.h" namespace art { diff --git a/runtime/base/scoped_flock_test.cc b/runtime/base/scoped_flock_test.cc index 8fa181ab6b..1fa7a12d17 100644 --- a/runtime/base/scoped_flock_test.cc +++ b/runtime/base/scoped_flock_test.cc @@ -15,9 +15,8 @@ */ #include "scoped_flock.h" -#include "common_runtime_test.h" -#include "gtest/gtest.h" +#include "common_runtime_test.h" namespace art { diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc index fefb907422..9ad8a07d3c 100644 --- a/runtime/check_jni.cc +++ b/runtime/check_jni.cc @@ -23,6 +23,7 @@ #include "class_linker.h" #include "class_linker-inl.h" #include "dex_file-inl.h" +#include "field_helper.h" #include "gc/space/space.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" @@ -31,7 +32,6 @@ #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" #include "mirror/throwable.h" -#include "object_utils.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "thread.h" diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index a40a2e4cd2..25eb3a342d 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -24,7 +24,6 @@ #include "mirror/dex_cache-inl.h" #include "mirror/iftable.h" #include "mirror/object_array.h" -#include "object_utils.h" #include "handle_scope-inl.h" namespace art { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 1436810f36..2c11f8b89c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -42,8 +42,10 @@ #include "intern_table.h" #include "interpreter/interpreter.h" #include "leb128.h" +#include "method_helper.h" #include "oat.h" #include "oat_file.h" +#include "object_lock.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class.h" @@ -54,9 +56,9 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/proxy.h" +#include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" #include "mirror/string-inl.h" -#include "object_utils.h" #include "os.h" #include "runtime.h" #include "entrypoints/entrypoint_utils.h" @@ -257,6 +259,13 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class java_lang_String->SetObjectSize(mirror::String::InstanceSize()); java_lang_String->SetStatus(mirror::Class::kStatusResolved, self); + // Setup Reference. + Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle( + AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize()))); + mirror::Reference::SetClass(java_lang_ref_Reference.Get()); + java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize()); + java_lang_ref_Reference->SetStatus(mirror::Class::kStatusResolved, self); + // Create storage for root classes, save away our work so far (requires descriptors). class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(), kClassRootsMax); @@ -267,6 +276,7 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class SetClassRoot(kObjectArrayClass, object_array_class.Get()); SetClassRoot(kCharArrayClass, char_array_class.Get()); SetClassRoot(kJavaLangString, java_lang_String.Get()); + SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference.Get()); // Setup the primitive type classes. SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); @@ -461,8 +471,12 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy); // java.lang.ref classes need to be specially flagged, but otherwise are normal classes - mirror::Class* java_lang_ref_Reference = FindSystemClass(self, "Ljava/lang/ref/Reference;"); - SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference); + // finish initializing Reference class + java_lang_ref_Reference->SetStatus(mirror::Class::kStatusNotReady, self); + mirror::Class* Reference_class = FindSystemClass(self, "Ljava/lang/ref/Reference;"); + CHECK_EQ(java_lang_ref_Reference.Get(), Reference_class); + CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize()); + CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize()); mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); java_lang_ref_FinalizerReference->SetAccessFlags( @@ -811,9 +825,20 @@ bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_ } } else { // TODO: What to lock here? + bool obsolete_file_cleanup_failed; open_oat_file.reset(FindOatFileContainingDexFileFromDexLocation(dex_location, dex_location_checksum_pointer, - kRuntimeISA, error_msgs)); + kRuntimeISA, error_msgs, + &obsolete_file_cleanup_failed)); + // There's no point in going forward and eventually try to regenerate the + // file if we couldn't remove the obsolete one. Mostly likely we will fail + // with the same error when trying to write the new file. + // In case the clean up failure is due to permission issues it's *mandatory* + // to stop to avoid regenerating under the wrong user. + // TODO: should we maybe do this only when we get permission issues? (i.e. EACCESS). + if (obsolete_file_cleanup_failed) { + return false; + } } needs_registering = true; } @@ -1071,7 +1096,9 @@ const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation( const char* dex_location, const uint32_t* const dex_location_checksum, InstructionSet isa, - std::vector<std::string>* error_msgs) { + std::vector<std::string>* error_msgs, + bool* obsolete_file_cleanup_failed) { + *obsolete_file_cleanup_failed = false; // Look for an existing file next to dex. for example, for // /foo/bar/baz.jar, look for /foo/bar/<isa>/baz.odex. std::string odex_filename(DexFilenameToOdexFilename(dex_location, isa)); @@ -1098,9 +1125,18 @@ const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation( if (oat_file != nullptr) { return oat_file; } + if (!open_failed && TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) { - PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location; + std::string error_msg = StringPrintf("Failed to remove obsolete file from %s when searching" + "for dex file %s: %s", + cache_location.c_str(), dex_location, strerror(errno)); + error_msgs->push_back(error_msg); + VLOG(class_linker) << error_msg; + // Let the caller know that we couldn't remove the obsolete file. + // This is a good indication that further writes may fail as well. + *obsolete_file_cleanup_failed = true; } + std::string compound_msg = StringPrintf("Failed to open oat file from %s (error '%s') or %s " "(error '%s').", odex_filename.c_str(), error_msg.c_str(), cache_location.c_str(), cache_error_msg.c_str()); @@ -1231,6 +1267,7 @@ void ClassLinker::InitFromImage() { array_iftable_ = GetClassRoot(kObjectArrayClass)->GetIfTable(); DCHECK(array_iftable_ == GetClassRoot(kBooleanArrayClass)->GetIfTable()); // String class root was set above + mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); mirror::ArtField::SetClass(GetClassRoot(kJavaLangReflectArtField)); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); @@ -1354,6 +1391,7 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* ar ClassLinker::~ClassLinker() { mirror::Class::ResetClass(); mirror::String::ResetClass(); + mirror::Reference::ResetClass(); mirror::ArtField::ResetClass(); mirror::ArtMethod::ResetClass(); mirror::BooleanArray::ResetArrayClass(); @@ -1600,6 +1638,8 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor, klass.Assign(GetClassRoot(kJavaLangClass)); } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) { klass.Assign(GetClassRoot(kJavaLangString)); + } else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) { + klass.Assign(GetClassRoot(kJavaLangRefReference)); } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) { klass.Assign(GetClassRoot(kJavaLangDexCache)); } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtField;") == 0) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index d9b3d2541c..64bffc9bf3 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -571,7 +571,8 @@ class ClassLinker { const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* location, const uint32_t* const location_checksum, InstructionSet isa, - std::vector<std::string>* error_msgs) + std::vector<std::string>* error_msgs, + bool* obsolete_file_cleanup_failed) LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_); // Find a verify an oat file with the given dex file. Will return nullptr when the oat file diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 7b5a5026df..21fe0067ed 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -23,6 +23,7 @@ #include "common_runtime_test.h" #include "dex_file.h" #include "entrypoints/entrypoint_utils-inl.h" +#include "field_helper.h" #include "gc/heap.h" #include "mirror/art_field-inl.h" #include "mirror/art_method.h" @@ -36,6 +37,8 @@ #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 { diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 0ed8b63b4d..f47f13d4b5 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -14,8 +14,31 @@ * 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); @@ -23,3 +46,293 @@ int main(int argc, char **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 diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index ac6d44b950..d0450317a3 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -17,73 +17,33 @@ #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_; @@ -93,17 +53,9 @@ class ScratchFile { 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_; @@ -112,222 +64,37 @@ class ScratchFile { 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_; @@ -338,7 +105,7 @@ class CommonRuntimeTest : public testing::Test { ClassLinker* class_linker_; private: - NoopCompilerCallbacks callbacks_; + std::unique_ptr<CompilerCallbacks> callbacks_; std::vector<const DexFile*> opened_dex_files_; }; @@ -346,29 +113,14 @@ class CommonRuntimeTest : public testing::Test { // 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_; @@ -399,10 +151,7 @@ namespace std { // TODO: isn't gtest supposed to be able to print STL types for itself? template <typename T> -std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs) { - os << ::art::ToString(rhs); - return os; -} +std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs); } // namespace std diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 8de3068dca..970593d119 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -16,6 +16,8 @@ #include "common_throws.h" +#include <sstream> + #include "base/logging.h" #include "class_linker-inl.h" #include "dex_file-inl.h" @@ -25,12 +27,9 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "thread.h" #include "verifier/method_verifier.h" -#include <sstream> - namespace art { static void AddReferrerLocation(std::ostream& os, mirror::Class* referrer) diff --git a/runtime/debugger.cc b/runtime/debugger.cc index c95be0154a..4cf4c099b2 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -25,11 +25,13 @@ #include "class_linker-inl.h" #include "dex_file-inl.h" #include "dex_instruction.h" +#include "field_helper.h" #include "gc/accounting/card_table-inl.h" #include "gc/space/large_object_space.h" #include "gc/space/space-inl.h" #include "handle_scope.h" #include "jdwp/object_registry.h" +#include "method_helper.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class.h" @@ -39,7 +41,6 @@ #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" #include "mirror/throwable.h" -#include "object_utils.h" #include "quick/inline_method_analyser.h" #include "reflection.h" #include "safe_map.h" diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index c1e00fcb0a..284aa89d99 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -18,7 +18,12 @@ #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 { diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc index 93faeaee7c..d475d426ff 100644 --- a/runtime/dex_file_verifier_test.cc +++ b/runtime/dex_file_verifier_test.cc @@ -16,11 +16,15 @@ #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 { diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc index 0d00cc3134..b8f180b46f 100644 --- a/runtime/dex_method_iterator_test.cc +++ b/runtime/dex_method_iterator_test.cc @@ -16,7 +16,10 @@ #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 { diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 482ad47d5d..542e1a9e2e 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -25,12 +25,12 @@ #include "indirect_reference_table.h" #include "invoke_type.h" #include "jni_internal.h" +#include "method_helper.h" #include "mirror/art_method.h" #include "mirror/array.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/throwable.h" -#include "object_utils.h" #include "handle_scope-inl.h" #include "thread.h" diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index d029df2c7f..d063dfb425 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -24,7 +24,6 @@ #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "mirror/object_array-inl.h" #include "reflection.h" #include "scoped_thread_state_change.h" diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc index 329c175986..64faf76213 100644 --- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc +++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc @@ -18,7 +18,6 @@ #include "interpreter/interpreter.h" #include "mirror/art_method-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "reflection.h" #include "runtime.h" #include "stack.h" diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc index bae4023c1d..edb3b723ef 100644 --- a/runtime/entrypoints/jni/jni_entrypoints.cc +++ b/runtime/entrypoints/jni/jni_entrypoints.cc @@ -18,7 +18,6 @@ #include "entrypoints/entrypoint_utils.h" #include "mirror/art_method-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" #include "thread.h" diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc index 9e36a05841..be6231cae5 100644 --- a/runtime/entrypoints/portable/portable_throw_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_throw_entrypoints.cc @@ -80,7 +80,6 @@ extern "C" int32_t art_portable_find_catch_block_from_code(mirror::ArtMethod* cu } mirror::Class* exception_type = exception->GetClass(); StackHandleScope<1> hs(self); - MethodHelper mh(hs.NewHandle(current_method)); const DexFile::CodeItem* code_item = current_method->GetCodeItem(); DCHECK_LT(ti_offset, code_item->tries_size_); const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset); @@ -98,7 +97,8 @@ extern "C" int32_t art_portable_find_catch_block_from_code(mirror::ArtMethod* cu break; } // Does this catch exception type apply? - mirror::Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx); + mirror::Class* iter_exception_type = + current_method->GetDexCacheResolvedTypes()->Get(iter_type_idx); if (UNLIKELY(iter_exception_type == NULL)) { // TODO: check, the verifier (class linker?) should take care of resolving all exception // classes early. diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc index 7ee869b67f..9f75b0fcf0 100644 --- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc @@ -22,7 +22,6 @@ #include "interpreter/interpreter.h" #include "mirror/art_method-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" namespace art { diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index 47fb9d66f8..f9f62c2721 100644 --- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc @@ -21,7 +21,6 @@ #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "stack.h" #include "thread.h" #include "verifier/method_verifier.h" diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc index 30e86097a6..653724989a 100644 --- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc @@ -21,7 +21,6 @@ #include "mirror/object.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "verify_object-inl.h" diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc index 4dcb1c8dc6..879010e36e 100644 --- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc @@ -18,7 +18,6 @@ #include "common_throws.h" #include "entrypoints/entrypoint_utils-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "thread.h" #include "well_known_classes.h" diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index f7cb1263f2..338bd06f7c 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -27,7 +27,6 @@ #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "runtime.h" #include "scoped_thread_state_change.h" diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc index c572baf937..79c68a24e0 100644 --- a/runtime/entrypoints_order_test.cc +++ b/runtime/entrypoints_order_test.cc @@ -121,7 +121,7 @@ class EntrypointsOrderTest : public CommonRuntimeTest { 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); diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index 3112bc0a28..b4355cad5c 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -15,23 +15,16 @@ */ #include "fault_handler.h" + #include <sys/mman.h> #include <sys/ucontext.h> -#include "base/macros.h" -#include "globals.h" -#include "base/logging.h" -#include "base/hex_dump.h" -#include "thread.h" -#include "mirror/art_method-inl.h" -#include "mirror/class-inl.h" -#include "mirror/dex_cache.h" -#include "mirror/object_array-inl.h" -#include "mirror/object-inl.h" -#include "object_utils.h" -#include "scoped_thread_state_change.h" + +#include "mirror/art_method.h" +#include "mirror/class.h" #ifdef HAVE_ANDROID_OS #include "sigchain.h" #endif +#include "thread-inl.h" #include "verify_object-inl.h" namespace art { diff --git a/runtime/field_helper.cc b/runtime/field_helper.cc new file mode 100644 index 0000000000..40daa6db3f --- /dev/null +++ b/runtime/field_helper.cc @@ -0,0 +1,57 @@ +/* + * 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 "field_helper.h" + +#include "class_linker-inl.h" +#include "dex_file.h" +#include "mirror/dex_cache.h" +#include "runtime.h" +#include "thread-inl.h" + +namespace art { + +mirror::Class* FieldHelper::GetType(bool resolve) { + uint32_t field_index = field_->GetDexFieldIndex(); + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { + return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), + field_->GetTypeDescriptor()); + } + const DexFile* dex_file = field_->GetDexFile(); + const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); + mirror::Class* type = field_->GetDexCache()->GetResolvedType(field_id.type_idx_); + if (resolve && (type == nullptr)) { + type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, field_.Get()); + CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); + } + return type; +} + +const char* FieldHelper::GetDeclaringClassDescriptor() { + uint32_t field_index = field_->GetDexFieldIndex(); + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { + DCHECK(field_->IsStatic()); + DCHECK_LT(field_index, 2U); + // 0 == Class[] interfaces; 1 == Class[][] throws; + declaring_class_descriptor_ = field_->GetDeclaringClass()->GetDescriptor(); + return declaring_class_descriptor_.c_str(); + } + const DexFile* dex_file = field_->GetDexFile(); + const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); + return dex_file->GetFieldDeclaringClassDescriptor(field_id); +} + +} // namespace art diff --git a/runtime/field_helper.h b/runtime/field_helper.h new file mode 100644 index 0000000000..5eae55e09c --- /dev/null +++ b/runtime/field_helper.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_FIELD_HELPER_H_ +#define ART_RUNTIME_FIELD_HELPER_H_ + +#include "base/macros.h" +#include "handle.h" +#include "mirror/art_field.h" + +namespace art { + +class FieldHelper { + public: + explicit FieldHelper(Handle<mirror::ArtField> f) : field_(f) {} + + void ChangeField(mirror::ArtField* new_f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(new_f != nullptr); + field_.Assign(new_f); + } + + mirror::ArtField* GetField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return field_.Get(); + } + + mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // The returned const char* is only guaranteed to be valid for the lifetime of the FieldHelper. + // If you need it longer, copy it into a std::string. + const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + Handle<mirror::ArtField> field_; + std::string declaring_class_descriptor_; + + DISALLOW_COPY_AND_ASSIGN(FieldHelper); +}; + +} // namespace art + +#endif // ART_RUNTIME_FIELD_HELPER_H_ diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h index 1e9556a076..fc4213e8c6 100644 --- a/runtime/gc/accounting/space_bitmap-inl.h +++ b/runtime/gc/accounting/space_bitmap-inl.h @@ -23,14 +23,6 @@ #include "atomic.h" #include "base/logging.h" -#include "dex_file-inl.h" -#include "heap_bitmap.h" -#include "mirror/art_field-inl.h" -#include "mirror/class-inl.h" -#include "mirror/object-inl.h" -#include "mirror/object_array-inl.h" -#include "object_utils.h" -#include "space_bitmap-inl.h" #include "utils.h" namespace art { diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index c0aa43ea41..39d1f9e132 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -16,6 +16,13 @@ #include "space_bitmap-inl.h" +#include "base/stringprintf.h" +#include "mem_map.h" +#include "mirror/object-inl.h" +#include "mirror/class.h" +#include "mirror/art_field.h" +#include "mirror/object_array.h" + namespace art { namespace gc { namespace accounting { @@ -46,6 +53,9 @@ SpaceBitmap<kAlignment>::SpaceBitmap(const std::string& name, MemMap* mem_map, u } template<size_t kAlignment> +SpaceBitmap<kAlignment>::~SpaceBitmap() {} + +template<size_t kAlignment> SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create( const std::string& name, byte* heap_begin, size_t heap_capacity) { // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord. diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h index 6d1ba870db..a3073bda07 100644 --- a/runtime/gc/accounting/space_bitmap.h +++ b/runtime/gc/accounting/space_bitmap.h @@ -54,8 +54,7 @@ class SpaceBitmap { static SpaceBitmap* CreateFromMemMap(const std::string& name, MemMap* mem_map, byte* heap_begin, size_t heap_capacity); - ~SpaceBitmap() { - } + ~SpaceBitmap(); // <offset> is the difference from .base to a pointer address. // <index> is the index of .bits that contains the bit representing diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h index c0ab151d6c..b2a5a3c96c 100644 --- a/runtime/gc/allocator/rosalloc.h +++ b/runtime/gc/allocator/rosalloc.h @@ -30,6 +30,7 @@ #include "base/logging.h" #include "globals.h" #include "mem_map.h" +#include "thread.h" #include "utils.h" namespace art { @@ -261,7 +262,7 @@ class RosAlloc { // 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. diff --git a/runtime/gc/collector/immune_region.h b/runtime/gc/collector/immune_region.h index 0c0a89b253..277525e831 100644 --- a/runtime/gc/collector/immune_region.h +++ b/runtime/gc/collector/immune_region.h @@ -19,7 +19,6 @@ #include "base/macros.h" #include "base/mutex.h" -#include "gc/space/space-inl.h" namespace art { namespace mirror { diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h index 25cfe0fbfd..bb85fa0a81 100644 --- a/runtime/gc/collector/mark_compact.h +++ b/runtime/gc/collector/mark_compact.h @@ -49,6 +49,7 @@ namespace accounting { } // namespace accounting namespace space { + class BumpPointerSpace; class ContinuousMemMapAllocSpace; class ContinuousSpace; } // namespace space diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index bff08478e0..7f6d1dc01f 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -25,6 +25,7 @@ #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" diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 4ec9bc2f6a..292173da50 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -58,7 +58,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/reference-inl.h" -#include "object_utils.h" #include "os.h" #include "reflection.h" #include "runtime.h" diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc index 4176f4ad08..e6b5c75f4f 100644 --- a/runtime/gc/heap_test.cc +++ b/runtime/gc/heap_test.cc @@ -17,10 +17,11 @@ #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 { diff --git a/runtime/gc/reference_processor-inl.h b/runtime/gc/reference_processor-inl.h new file mode 100644 index 0000000000..f619a15f74 --- /dev/null +++ b/runtime/gc/reference_processor-inl.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_GC_REFERENCE_PROCESSOR_INL_H_ +#define ART_RUNTIME_GC_REFERENCE_PROCESSOR_INL_H_ + +#include "reference_processor.h" + +namespace art { +namespace gc { + +inline bool ReferenceProcessor::SlowPathEnabled() { + return mirror::Reference::GetJavaLangRefReference()->GetSlowPathEnabled(); +} + +} // namespace gc +} // namespace art + +#endif // ART_RUNTIME_GC_REFERENCE_PROCESSOR_INL_H_ diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index e52bc1fd1e..d3641d196f 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -17,7 +17,9 @@ #include "reference_processor.h" #include "mirror/object-inl.h" +#include "mirror/reference.h" #include "mirror/reference-inl.h" +#include "reference_processor-inl.h" #include "reflection.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" @@ -27,18 +29,17 @@ namespace art { namespace gc { ReferenceProcessor::ReferenceProcessor() - : process_references_args_(nullptr, nullptr, nullptr), slow_path_enabled_(false), + : process_references_args_(nullptr, nullptr, nullptr), preserving_references_(false), lock_("reference processor lock", kReferenceProcessorLock), condition_("reference processor condition", lock_) { } void ReferenceProcessor::EnableSlowPath() { - Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current()); - slow_path_enabled_ = true; + mirror::Reference::GetJavaLangRefReference()->SetSlowPath(true); } void ReferenceProcessor::DisableSlowPath(Thread* self) { - slow_path_enabled_ = false; + mirror::Reference::GetJavaLangRefReference()->SetSlowPath(false); condition_.Broadcast(self); } @@ -46,11 +47,11 @@ mirror::Object* ReferenceProcessor::GetReferent(Thread* self, mirror::Reference* mirror::Object* const referent = reference->GetReferent(); // If the referent is null then it is already cleared, we can just return null since there is no // scenario where it becomes non-null during the reference processing phase. - if (LIKELY(!slow_path_enabled_) || referent == nullptr) { + if (UNLIKELY(!SlowPathEnabled()) || referent == nullptr) { return referent; } MutexLock mu(self, lock_); - while (slow_path_enabled_) { + while (SlowPathEnabled()) { mirror::HeapReference<mirror::Object>* const referent_addr = reference->GetReferentReferenceAddr(); // If the referent became cleared, return it. Don't need barrier since thread roots can't get @@ -117,7 +118,7 @@ void ReferenceProcessor::ProcessReferences(bool concurrent, TimingLogger* timing process_references_args_.is_marked_callback_ = is_marked_callback; process_references_args_.mark_callback_ = mark_object_callback; process_references_args_.arg_ = arg; - CHECK_EQ(slow_path_enabled_, concurrent) << "Slow path must be enabled iff concurrent"; + CHECK_EQ(SlowPathEnabled(), concurrent) << "Slow path must be enabled iff concurrent"; } // Unless required to clear soft references with white references, preserve some white referents. if (!clear_soft_references) { @@ -182,7 +183,7 @@ void ReferenceProcessor::DelayReferenceReferent(mirror::Class* klass, mirror::Re void* arg) { // klass can be the class of the old object if the visitor already updated the class of ref. DCHECK(klass != nullptr); - DCHECK(klass->IsReferenceClass()); + DCHECK(klass->IsTypeOfReferenceClass()); mirror::HeapReference<mirror::Object>* referent = ref->GetReferentReferenceAddr(); if (referent->AsMirrorPtr() != nullptr && !is_marked_callback(referent, arg)) { Thread* self = Thread::Current(); diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h index 2771ea809b..7274457a5d 100644 --- a/runtime/gc/reference_processor.h +++ b/runtime/gc/reference_processor.h @@ -49,6 +49,7 @@ class ReferenceProcessor { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) LOCKS_EXCLUDED(lock_); + // The slow path bool is contained in the reference class object, can only be set once // Only allow setting this with mutators suspended so that we can avoid using a lock in the // GetReferent fast path as an optimization. void EnableSlowPath() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -60,7 +61,7 @@ class ReferenceProcessor { IsHeapReferenceMarkedCallback* is_marked_callback, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void UpdateRoots(IsMarkedCallback* callback, void* arg) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_); private: class ProcessReferencesArgs { @@ -75,8 +76,10 @@ class ReferenceProcessor { MarkObjectCallback* mark_callback_; void* arg_; }; + bool SlowPathEnabled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Called by ProcessReferences. - void DisableSlowPath(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(lock_); + void DisableSlowPath(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // If we are preserving references it means that some dead objects may become live, we use start // and stop preserving to block mutators using GetReferrent from getting access to these // referents. @@ -84,8 +87,6 @@ class ReferenceProcessor { void StopPreservingReferences(Thread* self) LOCKS_EXCLUDED(lock_); // Process args, used by the GetReferent to return referents which are already marked. ProcessReferencesArgs process_references_args_ GUARDED_BY(lock_); - // Boolean for whether or not we need to go slow path in GetReferent. - volatile bool slow_path_enabled_; // Boolean for whether or not we are preserving references (either soft references or finalizers). // If this is true, then we cannot return a referent (see comment in GetReferent). bool preserving_references_ GUARDED_BY(lock_); diff --git a/runtime/gc/space/dlmalloc_space_base_test.cc b/runtime/gc/space/dlmalloc_space_base_test.cc index 129eace199..02fc4a52e1 100644 --- a/runtime/gc/space/dlmalloc_space_base_test.cc +++ b/runtime/gc/space/dlmalloc_space_base_test.cc @@ -15,7 +15,9 @@ */ #include "space_test.h" + #include "dlmalloc_space.h" +#include "scoped_thread_state_change.h" namespace art { namespace gc { diff --git a/runtime/gc/space/dlmalloc_space_random_test.cc b/runtime/gc/space/dlmalloc_space_random_test.cc index c4f8baedfb..4b1a1b1cc0 100644 --- a/runtime/gc/space/dlmalloc_space_random_test.cc +++ b/runtime/gc/space/dlmalloc_space_random_test.cc @@ -15,6 +15,7 @@ */ #include "space_test.h" + #include "dlmalloc_space.h" namespace art { diff --git a/runtime/gc/space/dlmalloc_space_static_test.cc b/runtime/gc/space/dlmalloc_space_static_test.cc index edaa1988ab..d17d0a7d54 100644 --- a/runtime/gc/space/dlmalloc_space_static_test.cc +++ b/runtime/gc/space/dlmalloc_space_static_test.cc @@ -15,6 +15,7 @@ */ #include "space_test.h" + #include "dlmalloc_space.h" namespace art { diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index a2d4942c8d..02911557f3 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -17,8 +17,6 @@ #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> @@ -26,6 +24,8 @@ #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 { diff --git a/runtime/globals.h b/runtime/globals.h index 3a906f15f5..1d9f22c35e 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -105,6 +105,19 @@ static constexpr bool kUseBakerOrBrooksReadBarrier = kUseBakerReadBarrier || kUs // 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_ diff --git a/runtime/handle.h b/runtime/handle.h index 7e13601af9..f70faf40d0 100644 --- a/runtime/handle.h +++ b/runtime/handle.h @@ -28,29 +28,40 @@ class Thread; template<class T> class Handle; +// Handles are memory locations that contain GC roots. As the mirror::Object*s within a handle are +// GC visible then the GC may move the references within them, something that couldn't be done with +// a wrap pointer. Handles are generally allocated within HandleScopes. ConstHandle is a super-class +// of Handle and doesn't support assignment operations. template<class T> class ConstHandle { public: ConstHandle() : reference_(nullptr) { } - ConstHandle(const ConstHandle<T>& handle) ALWAYS_INLINE : reference_(handle.reference_) { + + ALWAYS_INLINE ConstHandle(const ConstHandle<T>& handle) : reference_(handle.reference_) { } - ConstHandle<T>& operator=(const ConstHandle<T>& handle) ALWAYS_INLINE { + + ALWAYS_INLINE ConstHandle<T>& operator=(const ConstHandle<T>& handle) { reference_ = handle.reference_; return *this; } - explicit ConstHandle(StackReference<T>* reference) ALWAYS_INLINE : reference_(reference) { + + ALWAYS_INLINE explicit ConstHandle(StackReference<T>* reference) : reference_(reference) { } - T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE { + + ALWAYS_INLINE T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return *Get(); } - T* operator->() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE { + + ALWAYS_INLINE T* operator->() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return Get(); } - T* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE { + + ALWAYS_INLINE T* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return reference_->AsMirrorPtr(); } - jobject ToJObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE { + + ALWAYS_INLINE jobject ToJObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(reference_->AsMirrorPtr() == nullptr)) { // Special case so that we work with NullHandles. return nullptr; @@ -73,8 +84,8 @@ class ConstHandle { StackReference<T>* GetReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE { return reference_; } - const StackReference<T>* GetReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - ALWAYS_INLINE { + ALWAYS_INLINE const StackReference<T>* GetReference() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return reference_; } @@ -86,47 +97,54 @@ class ConstHandle { template<size_t kNumReferences> friend class StackHandleScope; }; +// Handles that support assignment. template<class T> class Handle : public ConstHandle<T> { public: Handle() { } - Handle(const Handle<T>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE + + ALWAYS_INLINE Handle(const Handle<T>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : ConstHandle<T>(handle.reference_) { } - Handle<T>& operator=(const Handle<T>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - ALWAYS_INLINE { + + ALWAYS_INLINE Handle<T>& operator=(const Handle<T>& handle) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ConstHandle<T>::operator=(handle); return *this; } - explicit Handle(StackReference<T>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - ALWAYS_INLINE : ConstHandle<T>(reference) { + + ALWAYS_INLINE explicit Handle(StackReference<T>* reference) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : ConstHandle<T>(reference) { } - T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE { + + ALWAYS_INLINE T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { StackReference<T>* ref = ConstHandle<T>::GetReference(); T* const old = ref->AsMirrorPtr(); ref->Assign(reference); return old; } + template<typename S> + explicit Handle(const Handle<S>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : ConstHandle<T>(handle) { + } + protected: template<typename S> explicit Handle(StackReference<S>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : ConstHandle<T>(reference) { } - template<typename S> - explicit Handle(const Handle<S>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : ConstHandle<T>(handle) { - } private: friend class BuildGenericJniFrameVisitor; - template<class S> friend class Handle; friend class HandleScope; template<class S> friend class HandleWrapper; template<size_t kNumReferences> friend class StackHandleScope; }; +// A special case of Handle that only holds references to null. template<class T> class NullHandle : public Handle<T> { public: diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h index 62c761475a..7bc811db87 100644 --- a/runtime/handle_scope-inl.h +++ b/runtime/handle_scope-inl.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_HANDLE_SCOPE_INL_H_ #define ART_RUNTIME_HANDLE_SCOPE_INL_H_ -#include "handle_scope-inl.h" +#include "handle_scope.h" #include "handle.h" #include "thread.h" diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h index 629e4ecf2f..42ef77927c 100644 --- a/runtime/handle_scope.h +++ b/runtime/handle_scope.h @@ -27,10 +27,12 @@ namespace art { namespace mirror { class Object; } + class Thread; -// HandleScopes can be allocated within the bridge frame between managed and native code backed by -// stack storage or manually allocated in native. +// HandleScopes are scoped objects containing a number of Handles. They are used to allocate +// handles, for these handles (and the objects contained within them) to be visible/roots for the +// GC. It is most common to stack allocate HandleScopes using StackHandleScope. class PACKED(4) HandleScope { public: ~HandleScope() {} @@ -130,6 +132,7 @@ class PACKED(4) HandleScope { private: template<size_t kNumReferences> friend class StackHandleScope; + DISALLOW_COPY_AND_ASSIGN(HandleScope); }; @@ -152,7 +155,7 @@ class HandleWrapper : public Handle<T> { // Scoped handle storage of a fixed size that is usually stack allocated. template<size_t kNumReferences> -class PACKED(4) StackHandleScope : public HandleScope { +class PACKED(4) StackHandleScope FINAL : public HandleScope { public: explicit StackHandleScope(Thread* self); ~StackHandleScope(); @@ -181,20 +184,29 @@ class PACKED(4) StackHandleScope : public HandleScope { template<class T> Handle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetReference(pos_, object); - return Handle<T>(GetHandle(pos_++)); + Handle<T> h(GetHandle(pos_)); + pos_++; + return h; } template<class T> HandleWrapper<T> NewHandleWrapper(T** object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { SetReference(pos_, *object); - Handle<T> h(GetHandle(pos_++)); + Handle<T> h(GetHandle(pos_)); + pos_++; return HandleWrapper<T>(object, h); } private: - // references_storage_ needs to be first so that it matches the address of references_. + // References_storage_ needs to be first so that it appears in the same location as + // HandleScope::references_. StackReference<mirror::Object> references_storage_[kNumReferences]; + + // The thread that the stack handle scope is a linked list upon. The stack handle scope will + // push and pop itself from this thread. Thread* const self_; + + // Position new handles will be created. size_t pos_; template<size_t kNumRefs> friend class StackHandleScope; diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 33339f8f6c..7e3b6bab26 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -52,7 +52,6 @@ #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "os.h" #include "safe_map.h" #include "scoped_thread_state_change.h" diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc index 449817add6..a33a981545 100644 --- a/runtime/indirect_reference_table_test.cc +++ b/runtime/indirect_reference_table_test.cc @@ -18,6 +18,7 @@ #include "common_runtime_test.h" #include "mirror/object-inl.h" +#include "scoped_thread_state_change.h" namespace art { diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 05320ced6d..f4eaa61c1e 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -18,6 +18,7 @@ #include <sys/uio.h> +#include "arch/context.h" #include "atomic.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" @@ -34,7 +35,6 @@ #if !defined(ART_USE_PORTABLE_COMPILER) #include "entrypoints/quick/quick_entrypoints.h" #endif -#include "object_utils.h" #include "os.h" #include "scoped_thread_state_change.h" #include "thread.h" diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc index 5995d9e5d3..d462e1444f 100644 --- a/runtime/intern_table_test.cc +++ b/runtime/intern_table_test.cc @@ -19,6 +19,8 @@ #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 { diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index b552909498..b35da0cf1b 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -15,6 +15,8 @@ */ #include "interpreter_common.h" + +#include "field_helper.h" #include "mirror/array-inl.h" namespace art { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index db42eb06f1..1bcd27e2d4 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -30,6 +30,7 @@ #include "entrypoints/entrypoint_utils-inl.h" #include "gc/accounting/card_table-inl.h" #include "handle_scope-inl.h" +#include "method_helper-inl.h" #include "nth_caller_visitor.h" #include "mirror/art_field-inl.h" #include "mirror/art_method.h" @@ -39,7 +40,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" -#include "object_utils.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "thread.h" diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc index 29d3c8ab8e..ad18d8a2ce 100644 --- a/runtime/jdwp/object_registry.cc +++ b/runtime/jdwp/object_registry.cc @@ -16,6 +16,7 @@ #include "object_registry.h" +#include "mirror/class.h" #include "scoped_thread_state_change.h" namespace art { diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h index e1a687544a..f0314a382f 100644 --- a/runtime/jdwp/object_registry.h +++ b/runtime/jdwp/object_registry.h @@ -17,20 +17,21 @@ #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; diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 845691d182..f9c7ec692c 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -41,7 +41,6 @@ #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" #include "mirror/throwable.h" -#include "object_utils.h" #include "parsed_options.h" #include "reflection.h" #include "runtime.h" @@ -3002,7 +3001,7 @@ extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 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)); diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc index 8ef1cb6115..7c7e60c5ee 100644 --- a/runtime/jni_internal_test.cc +++ b/runtime/jni_internal_test.cc @@ -19,6 +19,7 @@ #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 { diff --git a/runtime/method_helper-inl.h b/runtime/method_helper-inl.h new file mode 100644 index 0000000000..42a60896a0 --- /dev/null +++ b/runtime/method_helper-inl.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_METHOD_HELPER_INL_H_ +#define ART_RUNTIME_METHOD_HELPER_INL_H_ + +#include "method_helper.h" + +#include "runtime.h" + +namespace art { + +inline mirror::Class* MethodHelper::GetClassFromTypeIdx(uint16_t type_idx, bool resolve) { + mirror::ArtMethod* method = GetMethod(); + mirror::Class* type = method->GetDexCacheResolvedTypes()->Get(type_idx); + if (type == nullptr && resolve) { + type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); + CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); + } + return type; +} + +inline mirror::String* MethodHelper::ResolveString(uint32_t string_idx) { + mirror::ArtMethod* method = GetMethod(); + mirror::String* s = method->GetDexCacheStrings()->Get(string_idx); + if (UNLIKELY(s == nullptr)) { + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); + s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx, + dex_cache); + } + return s; +} + +} // namespace art + +#endif // ART_RUNTIME_METHOD_HELPER_INL_H_ diff --git a/runtime/method_helper.cc b/runtime/method_helper.cc new file mode 100644 index 0000000000..4b1b1daa9e --- /dev/null +++ b/runtime/method_helper.cc @@ -0,0 +1,127 @@ +/* + * 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 "method_helper.h" + +#include "class_linker.h" +#include "dex_file-inl.h" +#include "handle_scope-inl.h" +#include "mirror/art_method-inl.h" +#include "mirror/dex_cache.h" +#include "runtime.h" + +namespace art { + +mirror::String* MethodHelper::GetNameAsString(Thread* self) { + const DexFile* dex_file = method_->GetDexFile(); + mirror::ArtMethod* method = method_->GetInterfaceMethodIfProxy(); + uint32_t dex_method_idx = method->GetDexMethodIndex(); + const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx); + StackHandleScope<1> hs(self); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); + return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_, + dex_cache); +} + +bool MethodHelper::HasSameNameAndSignature(MethodHelper* other) { + const DexFile* dex_file = method_->GetDexFile(); + const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex()); + if (method_->GetDexCache() == other->method_->GetDexCache()) { + const DexFile::MethodId& other_mid = + dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex()); + return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_; + } + const DexFile* other_dex_file = other->method_->GetDexFile(); + const DexFile::MethodId& other_mid = + other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex()); + if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) { + return false; // Name mismatch. + } + return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid); +} + +uint32_t MethodHelper::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtMethod* method = GetMethod(); + const DexFile* dexfile = method->GetDexFile(); + if (dexfile == &other_dexfile) { + return method->GetDexMethodIndex(); + } + const DexFile::MethodId& mid = dexfile->GetMethodId(method->GetDexMethodIndex()); + const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_); + const DexFile::StringId* other_descriptor = + other_dexfile.FindStringId(mid_declaring_class_descriptor); + if (other_descriptor != nullptr) { + const DexFile::TypeId* other_type_id = + other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor)); + if (other_type_id != nullptr) { + const char* mid_name = dexfile->GetMethodName(mid); + const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name); + if (other_name != nullptr) { + uint16_t other_return_type_idx; + std::vector<uint16_t> other_param_type_idxs; + bool success = other_dexfile.CreateTypeList( + dexfile->GetMethodSignature(mid).ToString(), &other_return_type_idx, + &other_param_type_idxs); + if (success) { + const DexFile::ProtoId* other_sig = + other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs); + if (other_sig != nullptr) { + const DexFile::MethodId* other_mid = other_dexfile.FindMethodId( + *other_type_id, *other_name, *other_sig); + if (other_mid != nullptr) { + return other_dexfile.GetIndexForMethodId(*other_mid); + } + } + } + } + } + } + return DexFile::kDexNoIndex; +} + +uint32_t MethodHelper::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile, + uint32_t name_and_signature_idx) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtMethod* method = GetMethod(); + const DexFile* dexfile = method->GetDexFile(); + const uint32_t dex_method_idx = method->GetDexMethodIndex(); + const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx); + const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx); + DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid)); + DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid)); + if (dexfile == &other_dexfile) { + return dex_method_idx; + } + const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_); + const DexFile::StringId* other_descriptor = + other_dexfile.FindStringId(mid_declaring_class_descriptor); + if (other_descriptor != nullptr) { + const DexFile::TypeId* other_type_id = + other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor)); + if (other_type_id != nullptr) { + const DexFile::MethodId* other_mid = other_dexfile.FindMethodId( + *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_), + other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_)); + if (other_mid != nullptr) { + return other_dexfile.GetIndexForMethodId(*other_mid); + } + } + } + return DexFile::kDexNoIndex; +} + +} // namespace art diff --git a/runtime/method_helper.h b/runtime/method_helper.h new file mode 100644 index 0000000000..012695e4d1 --- /dev/null +++ b/runtime/method_helper.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_METHOD_HELPER_H_ +#define ART_RUNTIME_METHOD_HELPER_H_ + +#include "base/macros.h" +#include "handle.h" +#include "mirror/art_method.h" +#include "primitive.h" + +namespace art { + +class MethodHelper { + public: + explicit MethodHelper(Handle<mirror::ArtMethod> m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : method_(m), shorty_(nullptr), shorty_len_(0) { + SetMethod(m.Get()); + } + + void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(new_m != nullptr); + SetMethod(new_m); + shorty_ = nullptr; + } + + mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return method_->GetInterfaceMethodIfProxy(); + } + + mirror::String* GetNameAsString(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const char* result = shorty_; + if (result == nullptr) { + result = method_->GetShorty(&shorty_len_); + shorty_ = result; + } + return result; + } + + uint32_t GetShortyLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (shorty_ == nullptr) { + GetShorty(); + } + return shorty_len_; + } + + // Counts the number of references in the parameter list of the corresponding method. + // Note: Thus does _not_ include "this" for non-static methods. + uint32_t GetNumberOfReferenceArgsWithoutReceiver() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const char* shorty = GetShorty(); + uint32_t refs = 0; + for (uint32_t i = 1; i < shorty_len_ ; ++i) { + if (shorty[i] == 'L') { + refs++; + } + } + + return refs; + } + + // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large + // number of bugs at call sites. + mirror::Class* GetReturnType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + mirror::ArtMethod* method = GetMethod(); + const DexFile* dex_file = method->GetDexFile(); + const DexFile::MethodId& method_id = dex_file->GetMethodId(method->GetDexMethodIndex()); + const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id); + uint16_t return_type_idx = proto_id.return_type_idx_; + return GetClassFromTypeIdx(return_type_idx, resolve); + } + + size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // "1 +" because the first in Args is the receiver. + // "- 1" because we don't count the return type. + return (method_->IsStatic() ? 0 : 1) + GetShortyLength() - 1; + } + + // Get the primitive type associated with the given parameter. + Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK_LT(param, NumArgs()); + if (GetMethod()->IsStatic()) { + param++; // 0th argument must skip return value at start of the shorty + } else if (param == 0) { + return Primitive::kPrimNot; + } + return Primitive::GetType(GetShorty()[param]); + } + + // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods. + bool IsParamALongOrDouble(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Primitive::Type type = GetParamPrimitiveType(param); + return type == Primitive::kPrimLong || type == Primitive::kPrimDouble; + } + + // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods. + bool IsParamAReference(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetParamPrimitiveType(param) == Primitive::kPrimNot; + } + + bool HasSameNameAndSignature(MethodHelper* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + bool HasSameSignatureWithDifferentClassLoaders(MethodHelper* other) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (UNLIKELY(GetReturnType() != other->GetReturnType())) { + return false; + } + const DexFile::TypeList* types = method_->GetParameterTypeList(); + const DexFile::TypeList* other_types = other->method_->GetParameterTypeList(); + if (types == nullptr) { + return (other_types == nullptr) || (other_types->Size() == 0); + } else if (UNLIKELY(other_types == nullptr)) { + return types->Size() == 0; + } + uint32_t num_types = types->Size(); + if (UNLIKELY(num_types != other_types->Size())) { + return false; + } + for (uint32_t i = 0; i < num_types; ++i) { + mirror::Class* param_type = GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_); + mirror::Class* other_param_type = + other->GetClassFromTypeIdx(other_types->GetTypeItem(i).type_idx_); + if (UNLIKELY(param_type != other_param_type)) { + return false; + } + } + return true; + } + + mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + mirror::String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // The name_and_signature_idx MUST point to a MethodId with the same name and signature in the + // other_dexfile, such as the method index used to resolve this method in the other_dexfile. + uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile, + uint32_t name_and_signature_idx) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + // Set the method_ field, for proxy methods looking up the interface method via the resolved + // methods table. + void SetMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + method_.Assign(method); + } + + Handle<mirror::ArtMethod> method_; + const char* shorty_; + uint32_t shorty_len_; + + DISALLOW_COPY_AND_ASSIGN(MethodHelper); +}; + +} // namespace art + +#endif // ART_RUNTIME_METHOD_HELPER_H_ diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc index f7b573729b..63f9860278 100644 --- a/runtime/mirror/array.cc +++ b/runtime/mirror/array.cc @@ -25,7 +25,6 @@ #include "object-inl.h" #include "object_array.h" #include "object_array-inl.h" -#include "object_utils.h" #include "handle_scope-inl.h" #include "thread.h" #include "utils.h" diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h index 90247edc76..00bed92cb3 100644 --- a/runtime/mirror/art_field-inl.h +++ b/runtime/mirror/art_field-inl.h @@ -20,10 +20,10 @@ #include "art_field.h" #include "base/logging.h" +#include "dex_cache.h" #include "gc/accounting/card_table-inl.h" #include "jvalue.h" #include "object-inl.h" -#include "object_utils.h" #include "primitive.h" namespace art { diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc index f2729f660e..da21dfef06 100644 --- a/runtime/mirror/art_field.cc +++ b/runtime/mirror/art_field.cc @@ -20,7 +20,6 @@ #include "gc/accounting/card_table-inl.h" #include "object-inl.h" #include "object_array-inl.h" -#include "object_utils.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "utils.h" diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index a5b5df6137..01b05a6e6f 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -19,11 +19,13 @@ #include "art_method.h" +#include "class_linker.h" +#include "dex_cache.h" #include "dex_file.h" #include "entrypoints/entrypoint_utils.h" +#include "method_helper.h" #include "object-inl.h" #include "object_array.h" -#include "object_utils.h" #include "oat.h" #include "quick/quick_method_frame_info.h" #include "read_barrier-inl.h" diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index 1fa680d148..167f848824 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -16,6 +16,7 @@ #include "art_method.h" +#include "arch/context.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/stringpiece.h" @@ -26,12 +27,12 @@ #include "interpreter/interpreter.h" #include "jni_internal.h" #include "mapping_table.h" -#include "object-inl.h" -#include "object_array.h" +#include "method_helper.h" #include "object_array-inl.h" +#include "object_array.h" +#include "object-inl.h" #include "scoped_thread_state_change.h" #include "string.h" -#include "object_utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 349d4a34df..329a984842 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -30,6 +30,7 @@ #include "iftable.h" #include "object_array-inl.h" #include "read_barrier-inl.h" +#include "reference-inl.h" #include "runtime.h" #include "string.h" @@ -591,6 +592,11 @@ inline bool Class::IsArtMethodClass() const { return this == ArtMethod::GetJavaLangReflectArtMethod<kReadBarrierOption>(); } +template<ReadBarrierOption kReadBarrierOption> +inline bool Class::IsReferenceClass() const { + return this == Reference::GetJavaLangRefReference<kReadBarrierOption>(); +} + template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline bool Class::IsClassClass() { Class* java_lang_Class = GetClass<kVerifyFlags, kReadBarrierOption>()-> @@ -642,6 +648,30 @@ inline ObjectArray<ObjectArray<Class>>* Class::GetThrows() { return GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset); } +inline MemberOffset Class::GetDisableIntrinsicFlagOffset() { + CHECK(IsReferenceClass()); + // First static field + DCHECK(GetSFields()->Get(0)->IsArtField()); + DCHECK_STREQ(GetSFields()->Get(0)->GetName(), "disableIntrinsic"); + return GetSFields()->Get(0)->GetOffset(); +} + +inline MemberOffset Class::GetSlowPathFlagOffset() { + CHECK(IsReferenceClass()); + // Second static field + DCHECK(GetSFields()->Get(1)->IsArtField()); + DCHECK_STREQ(GetSFields()->Get(1)->GetName(), "slowPathEnabled"); + return GetSFields()->Get(1)->GetOffset(); +} + +inline bool Class::GetSlowPathEnabled() { + return GetField32(GetSlowPathFlagOffset()); +} + +inline void Class::SetSlowPath(bool enabled) { + SetField32<false>(GetSlowPathFlagOffset(), enabled); +} + inline void Class::InitializeClassVisitor::operator()( mirror::Object* obj, size_t usable_size) const { DCHECK_LE(class_size_, usable_size); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index be05fb8a9b..fadf80ebcf 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -18,17 +18,16 @@ #include "art_field-inl.h" #include "art_method-inl.h" -#include "class-inl.h" #include "class_linker.h" #include "class_loader.h" +#include "class-inl.h" #include "dex_cache.h" #include "dex_file-inl.h" #include "gc/accounting/card_table-inl.h" -#include "object-inl.h" +#include "handle_scope-inl.h" #include "object_array-inl.h" -#include "object_utils.h" +#include "object-inl.h" #include "runtime.h" -#include "handle_scope-inl.h" #include "thread.h" #include "throwable.h" #include "utils.h" diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 0f42044b37..648bddeca5 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -261,7 +261,7 @@ class MANAGED Class FINAL : public Object { } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool IsReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + bool IsTypeOfReferenceClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return (GetAccessFlags<kVerifyFlags>() & kAccClassIsReference) != 0; } @@ -419,6 +419,9 @@ class MANAGED Class FINAL : public Object { template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> bool IsArtMethodClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + bool IsReferenceClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static MemberOffset ComponentTypeOffset() { return OFFSET_OF_OBJECT_MEMBER(Class, component_type_); } @@ -976,6 +979,12 @@ class MANAGED Class FINAL : public Object { // For proxy class only. ObjectArray<ObjectArray<Class>>* GetThrows() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // For reference class only. + MemberOffset GetDisableIntrinsicFlagOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + MemberOffset GetSlowPathFlagOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool GetSlowPathEnabled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetSlowPath(bool enabled) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore // fence. class InitializeClassVisitor { diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 3d28dc603f..ef6fc67c75 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -24,6 +24,7 @@ #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 { diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 3d4568379d..9dbfb56c79 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -249,7 +249,7 @@ inline ArtMethod* Object::AsArtMethod() { template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsReferenceInstance() { - return GetClass<kVerifyFlags>()->IsReferenceClass(); + return GetClass<kVerifyFlags>()->IsTypeOfReferenceClass(); } template<VerifyObjectFlags kVerifyFlags> @@ -806,7 +806,7 @@ inline void Object::VisitReferences(const Visitor& visitor, } else { DCHECK(!klass->IsVariableSize()); VisitInstanceFieldsReferences<kVisitClass>(klass, visitor); - if (UNLIKELY(klass->IsReferenceClass<kVerifyNone>())) { + if (UNLIKELY(klass->IsTypeOfReferenceClass<kVerifyNone>())) { ref_visitor(klass, AsReference()); } } diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 5f88d54fe0..961bc64819 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -24,13 +24,13 @@ #include "class.h" #include "class-inl.h" #include "class_linker-inl.h" +#include "field_helper.h" #include "gc/accounting/card_table-inl.h" #include "gc/heap.h" #include "iftable-inl.h" #include "monitor.h" #include "object-inl.h" #include "object_array-inl.h" -#include "object_utils.h" #include "runtime.h" #include "handle_scope-inl.h" #include "throwable.h" @@ -57,7 +57,7 @@ class CopyReferenceFieldsWithReadBarrierVisitor { ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Copy java.lang.ref.Reference.referent which isn't visited in // Object::VisitReferences(). - DCHECK(klass->IsReferenceClass()); + DCHECK(klass->IsTypeOfReferenceClass()); this->operator()(ref, mirror::Reference::ReferentOffset(), false); } diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 7e1de5d060..a7ea6c9c08 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -36,6 +36,7 @@ #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 { diff --git a/runtime/mirror/reference-inl.h b/runtime/mirror/reference-inl.h index 43767c8792..b353402602 100644 --- a/runtime/mirror/reference-inl.h +++ b/runtime/mirror/reference-inl.h @@ -22,6 +22,11 @@ namespace art { namespace mirror { +inline uint32_t Reference::ClassSize() { + uint32_t vtable_entries = Object::kVTableLength + 5; + return Class::ComputeClassSize(false, vtable_entries, 2, 0, 0); +} + inline bool Reference::IsEnqueuable() { // Not using volatile reads as an optimization since this is only called with all the mutators // suspended. diff --git a/runtime/mirror/reference.cc b/runtime/mirror/reference.cc new file mode 100644 index 0000000000..077cd4b913 --- /dev/null +++ b/runtime/mirror/reference.cc @@ -0,0 +1,43 @@ +/* + * 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 "reference.h" + +namespace art { +namespace mirror { + +Class* Reference::java_lang_ref_Reference_ = nullptr; + +void Reference::SetClass(Class* java_lang_ref_Reference) { + CHECK(java_lang_ref_Reference_ == nullptr); + CHECK(java_lang_ref_Reference != nullptr); + java_lang_ref_Reference_ = java_lang_ref_Reference; +} + +void Reference::ResetClass() { + CHECK(java_lang_ref_Reference_ != nullptr); + java_lang_ref_Reference_ = nullptr; +} + +void Reference::VisitRoots(RootCallback* callback, void* arg) { + if (java_lang_ref_Reference_ != nullptr) { + callback(reinterpret_cast<mirror::Object**>(&java_lang_ref_Reference_), + arg, 0, kRootStickyClass); + } +} + +} // namespace mirror +} // namespace art diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h index 9c9d87be01..07d47d31e7 100644 --- a/runtime/mirror/reference.h +++ b/runtime/mirror/reference.h @@ -17,7 +17,11 @@ #ifndef ART_RUNTIME_MIRROR_REFERENCE_H_ #define ART_RUNTIME_MIRROR_REFERENCE_H_ +#include "class.h" #include "object.h" +#include "object_callbacks.h" +#include "read_barrier.h" +#include "thread.h" namespace art { @@ -36,6 +40,14 @@ namespace mirror { // C++ mirror of java.lang.ref.Reference class MANAGED Reference : public Object { public: + // Size of java.lang.ref.Reference.class. + static uint32_t ClassSize(); + + // Size of an instance of java.lang.ref.Reference. + static constexpr uint32_t InstanceSize() { + return sizeof(Reference); + } + static MemberOffset PendingNextOffset() { return OFFSET_OF_OBJECT_MEMBER(Reference, pending_next_); } @@ -80,6 +92,16 @@ class MANAGED Reference : public Object { bool IsEnqueuable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + static Class* GetJavaLangRefReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(java_lang_ref_Reference_ != nullptr); + return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>( + &java_lang_ref_Reference_); + } + static void SetClass(Class* klass); + static void ResetClass(void); + static void VisitRoots(RootCallback* callback, void* arg); + private: // Note: This avoids a read barrier, it should only be used by the GC. HeapReference<Object>* GetReferentReferenceAddr() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -92,6 +114,8 @@ class MANAGED Reference : public Object { HeapReference<Reference> queue_next_; // Note this is Java volatile: HeapReference<Object> referent_; // Note this is Java volatile: + static Class* java_lang_ref_Reference_; + friend struct art::ReferenceOffsets; // for verifying offset information friend class gc::ReferenceProcessor; friend class gc::ReferenceQueue; diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 8ab4db90e9..46bdd59b5c 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -19,6 +19,7 @@ #include <gtest/gtest.h> +#include "object.h" #include "object_callbacks.h" #include "read_barrier.h" diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index 6efc9e2f54..1c3f1ed5bf 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -23,7 +23,6 @@ #include "object-inl.h" #include "object_array.h" #include "object_array-inl.h" -#include "object_utils.h" #include "stack_trace_element.h" #include "utils.h" #include "well_known_classes.h" diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 5633a77b6f..4b26edac61 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -28,7 +28,6 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "thread_list.h" @@ -746,7 +745,11 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { contention_count++; Runtime* runtime = Runtime::Current(); if (contention_count <= runtime->GetMaxSpinsBeforeThinkLockInflation()) { - NanoSleep(1000); // Sleep for 1us and re-attempt. + // TODO: Consider switch thread state to kBlocked when we are yielding. + // Use sched_yield instead of NanoSleep since NanoSleep can wait much longer than the + // parameter you pass in. This can cause thread suspension to take excessively long + // make long pauses. See b/16307460. + sched_yield(); } else { contention_count = 0; InflateThinLocked(self, h_obj, lock_word, 0); diff --git a/runtime/monitor_pool_test.cc b/runtime/monitor_pool_test.cc index cddc245a42..e1837f52ab 100644 --- a/runtime/monitor_pool_test.cc +++ b/runtime/monitor_pool_test.cc @@ -17,6 +17,8 @@ #include "monitor_pool.h" #include "common_runtime_test.h" +#include "scoped_thread_state_change.h" +#include "thread-inl.h" namespace art { diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc index bdba494e14..af24368e2f 100644 --- a/runtime/monitor_test.cc +++ b/runtime/monitor_test.cc @@ -24,6 +24,7 @@ #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" @@ -31,7 +32,7 @@ namespace art { 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) { diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index f1a987f80a..b0b64aac16 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -30,7 +30,6 @@ #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "runtime.h" #include "scoped_fast_native_object_access.h" #include "scoped_thread_state_change.h" diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index cede1a0899..e577c2c960 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -21,7 +21,6 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" #include "scoped_fast_native_object_access.h" #include "ScopedLocalRef.h" diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc index eae4584019..f94e42b260 100644 --- a/runtime/native/java_lang_reflect_Array.cc +++ b/runtime/native/java_lang_reflect_Array.cc @@ -20,7 +20,6 @@ #include "jni_internal.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "scoped_fast_native_object_access.h" #include "handle_scope-inl.h" diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 1981bfd5ab..34cb93ae94 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -20,7 +20,6 @@ #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "reflection.h" #include "scoped_fast_native_object_access.h" #include "well_known_classes.h" diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 3564dfdf47..3903ffcd6a 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -18,11 +18,11 @@ #include "class_linker-inl.h" #include "common_throws.h" #include "dex_file-inl.h" +#include "field_helper.h" #include "jni_internal.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" -#include "object_utils.h" #include "reflection.h" #include "scoped_fast_native_object_access.h" diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index ac602acb21..f029b16746 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -21,7 +21,6 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "reflection.h" #include "scoped_fast_native_object_access.h" #include "well_known_classes.h" diff --git a/runtime/noop_compiler_callbacks.h b/runtime/noop_compiler_callbacks.h index 702b2e1f5c..65498deaab 100644 --- a/runtime/noop_compiler_callbacks.h +++ b/runtime/noop_compiler_callbacks.h @@ -25,10 +25,15 @@ class NoopCompilerCallbacks FINAL : public CompilerCallbacks { public: NoopCompilerCallbacks() {} ~NoopCompilerCallbacks() {} + bool MethodVerified(verifier::MethodVerifier* verifier) OVERRIDE { return true; } + void ClassRejected(ClassReference ref) OVERRIDE {} + + private: + DISALLOW_COPY_AND_ASSIGN(NoopCompilerCallbacks); }; } // namespace art diff --git a/runtime/object_lock.cc b/runtime/object_lock.cc new file mode 100644 index 0000000000..f7accc0f31 --- /dev/null +++ b/runtime/object_lock.cc @@ -0,0 +1,53 @@ +/* + * 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 "object_lock.h" + +#include "mirror/object-inl.h" +#include "monitor.h" + +namespace art { + +template <typename T> +ObjectLock<T>::ObjectLock(Thread* self, Handle<T> object) : self_(self), obj_(object) { + CHECK(object.Get() != nullptr); + obj_->MonitorEnter(self_); +} + +template <typename T> +ObjectLock<T>::~ObjectLock() { + obj_->MonitorExit(self_); +} + +template <typename T> +void ObjectLock<T>::WaitIgnoringInterrupts() { + Monitor::Wait(self_, obj_.Get(), 0, 0, false, kWaiting); +} + +template <typename T> +void ObjectLock<T>::Notify() { + obj_->Notify(self_); +} + +template <typename T> +void ObjectLock<T>::NotifyAll() { + obj_->NotifyAll(self_); +} + +template class ObjectLock<mirror::Class>; +template class ObjectLock<mirror::Object>; + +} // namespace art diff --git a/runtime/object_lock.h b/runtime/object_lock.h new file mode 100644 index 0000000000..acddc03e29 --- /dev/null +++ b/runtime/object_lock.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_OBJECT_LOCK_H_ +#define ART_RUNTIME_OBJECT_LOCK_H_ + +#include "base/macros.h" +#include "base/mutex.h" +#include "handle.h" + +namespace art { + +class Thread; + +template <typename T> +class ObjectLock { + public: + ObjectLock(Thread* self, Handle<T> object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void WaitIgnoringInterrupts() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void Notify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void NotifyAll() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + Thread* const self_; + Handle<T> const obj_; + + DISALLOW_COPY_AND_ASSIGN(ObjectLock); +}; + +} // namespace art + +#endif // ART_RUNTIME_OBJECT_LOCK_H_ diff --git a/runtime/object_utils.h b/runtime/object_utils.h deleted file mode 100644 index 4379b4ad2a..0000000000 --- a/runtime/object_utils.h +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_RUNTIME_OBJECT_UTILS_H_ -#define ART_RUNTIME_OBJECT_UTILS_H_ - -#include "class_linker.h" -#include "dex_file.h" -#include "monitor.h" -#include "mirror/art_field.h" -#include "mirror/art_method.h" -#include "mirror/class.h" -#include "mirror/dex_cache.h" -#include "mirror/iftable.h" -#include "mirror/string.h" - -#include "runtime.h" -#include "handle_scope-inl.h" - -#include <string> - -namespace art { - -template <typename T> -class ObjectLock { - public: - ObjectLock(Thread* self, Handle<T> object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : self_(self), obj_(object) { - CHECK(object.Get() != nullptr); - obj_->MonitorEnter(self_); - } - - ~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - obj_->MonitorExit(self_); - } - - void WaitIgnoringInterrupts() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Monitor::Wait(self_, obj_.Get(), 0, 0, false, kWaiting); - } - - void Notify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - obj_->Notify(self_); - } - - void NotifyAll() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - obj_->NotifyAll(self_); - } - - private: - Thread* const self_; - Handle<T> const obj_; - DISALLOW_COPY_AND_ASSIGN(ObjectLock); -}; - -class FieldHelper { - public: - explicit FieldHelper(Handle<mirror::ArtField> f) : field_(f) {} - - void ChangeField(mirror::ArtField* new_f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(new_f != nullptr); - field_.Assign(new_f); - } - - mirror::ArtField* GetField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return field_.Get(); - } - - mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint32_t field_index = field_->GetDexFieldIndex(); - if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { - return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), - field_->GetTypeDescriptor()); - } - const DexFile* dex_file = field_->GetDexFile(); - const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); - mirror::Class* type = field_->GetDexCache()->GetResolvedType(field_id.type_idx_); - if (resolve && (type == nullptr)) { - type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, field_.Get()); - CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); - } - return type; - } - - // The returned const char* is only guaranteed to be valid for the lifetime of the FieldHelper. - // If you need it longer, copy it into a std::string. - const char* GetDeclaringClassDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint32_t field_index = field_->GetDexFieldIndex(); - if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { - DCHECK(field_->IsStatic()); - DCHECK_LT(field_index, 2U); - // 0 == Class[] interfaces; 1 == Class[][] throws; - declaring_class_descriptor_ = field_->GetDeclaringClass()->GetDescriptor(); - return declaring_class_descriptor_.c_str(); - } - const DexFile* dex_file = field_->GetDexFile(); - const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); - return dex_file->GetFieldDeclaringClassDescriptor(field_id); - } - - private: - Handle<mirror::ArtField> field_; - std::string declaring_class_descriptor_; - - DISALLOW_COPY_AND_ASSIGN(FieldHelper); -}; - -class MethodHelper { - public: - explicit MethodHelper(Handle<mirror::ArtMethod> m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : method_(m), shorty_(nullptr), shorty_len_(0) { - SetMethod(m.Get()); - } - - void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - DCHECK(new_m != nullptr); - SetMethod(new_m); - shorty_ = nullptr; - } - - mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return method_->GetInterfaceMethodIfProxy(); - } - - mirror::String* GetNameAsString(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile* dex_file = method_->GetDexFile(); - mirror::ArtMethod* method = method_->GetInterfaceMethodIfProxy(); - uint32_t dex_method_idx = method->GetDexMethodIndex(); - const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx); - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); - return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_, - dex_cache); - } - - const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* result = shorty_; - if (result == nullptr) { - result = method_->GetShorty(&shorty_len_); - shorty_ = result; - } - return result; - } - - uint32_t GetShortyLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (shorty_ == nullptr) { - GetShorty(); - } - return shorty_len_; - } - - // Counts the number of references in the parameter list of the corresponding method. - // Note: Thus does _not_ include "this" for non-static methods. - uint32_t GetNumberOfReferenceArgsWithoutReceiver() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* shorty = GetShorty(); - uint32_t refs = 0; - for (uint32_t i = 1; i < shorty_len_ ; ++i) { - if (shorty[i] == 'L') { - refs++; - } - } - - return refs; - } - - // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large - // number of bugs at call sites. - mirror::Class* GetReturnType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method = GetMethod(); - const DexFile* dex_file = method->GetDexFile(); - const DexFile::MethodId& method_id = dex_file->GetMethodId(method->GetDexMethodIndex()); - const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id); - uint16_t return_type_idx = proto_id.return_type_idx_; - return GetClassFromTypeIdx(return_type_idx, resolve); - } - - size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - // "1 +" because the first in Args is the receiver. - // "- 1" because we don't count the return type. - return (method_->IsStatic() ? 0 : 1) + GetShortyLength() - 1; - } - - // Get the primitive type associated with the given parameter. - Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK_LT(param, NumArgs()); - if (GetMethod()->IsStatic()) { - param++; // 0th argument must skip return value at start of the shorty - } else if (param == 0) { - return Primitive::kPrimNot; - } - return Primitive::GetType(GetShorty()[param]); - } - - // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods. - bool IsParamALongOrDouble(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Primitive::Type type = GetParamPrimitiveType(param); - return type == Primitive::kPrimLong || type == Primitive::kPrimDouble; - } - - // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods. - bool IsParamAReference(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetParamPrimitiveType(param) == Primitive::kPrimNot; - } - - bool HasSameNameAndSignature(MethodHelper* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile* dex_file = method_->GetDexFile(); - const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex()); - if (method_->GetDexCache() == other->method_->GetDexCache()) { - const DexFile::MethodId& other_mid = - dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex()); - return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_; - } - const DexFile* other_dex_file = other->method_->GetDexFile(); - const DexFile::MethodId& other_mid = - other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex()); - if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) { - return false; // Name mismatch. - } - return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid); - } - - bool HasSameSignatureWithDifferentClassLoaders(MethodHelper* other) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (UNLIKELY(GetReturnType() != other->GetReturnType())) { - return false; - } - const DexFile::TypeList* types = method_->GetParameterTypeList(); - const DexFile::TypeList* other_types = other->method_->GetParameterTypeList(); - if (types == nullptr) { - return (other_types == nullptr) || (other_types->Size() == 0); - } else if (UNLIKELY(other_types == nullptr)) { - return types->Size() == 0; - } - uint32_t num_types = types->Size(); - if (UNLIKELY(num_types != other_types->Size())) { - return false; - } - for (uint32_t i = 0; i < num_types; ++i) { - mirror::Class* param_type = GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_); - mirror::Class* other_param_type = - other->GetClassFromTypeIdx(other_types->GetTypeItem(i).type_idx_); - if (UNLIKELY(param_type != other_param_type)) { - return false; - } - } - return true; - } - - mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method = GetMethod(); - mirror::Class* type = method->GetDexCacheResolvedTypes()->Get(type_idx); - if (type == nullptr && resolve) { - type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); - CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); - } - return type; - } - - mirror::Class* GetDexCacheResolvedType(uint16_t type_idx) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return GetMethod()->GetDexCacheResolvedTypes()->Get(type_idx); - } - - mirror::String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method = GetMethod(); - mirror::String* s = method->GetDexCacheStrings()->Get(string_idx); - if (UNLIKELY(s == nullptr)) { - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); - s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx, - dex_cache); - } - return s; - } - - uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method = GetMethod(); - const DexFile* dexfile = method->GetDexFile(); - if (dexfile == &other_dexfile) { - return method->GetDexMethodIndex(); - } - const DexFile::MethodId& mid = dexfile->GetMethodId(method->GetDexMethodIndex()); - const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_); - const DexFile::StringId* other_descriptor = - other_dexfile.FindStringId(mid_declaring_class_descriptor); - if (other_descriptor != nullptr) { - const DexFile::TypeId* other_type_id = - other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor)); - if (other_type_id != nullptr) { - const char* mid_name = dexfile->GetMethodName(mid); - const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name); - if (other_name != nullptr) { - uint16_t other_return_type_idx; - std::vector<uint16_t> other_param_type_idxs; - bool success = other_dexfile.CreateTypeList( - dexfile->GetMethodSignature(mid).ToString(), &other_return_type_idx, - &other_param_type_idxs); - if (success) { - const DexFile::ProtoId* other_sig = - other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs); - if (other_sig != nullptr) { - const DexFile::MethodId* other_mid = other_dexfile.FindMethodId( - *other_type_id, *other_name, *other_sig); - if (other_mid != nullptr) { - return other_dexfile.GetIndexForMethodId(*other_mid); - } - } - } - } - } - } - return DexFile::kDexNoIndex; - } - - // The name_and_signature_idx MUST point to a MethodId with the same name and signature in the - // other_dexfile, such as the method index used to resolve this method in the other_dexfile. - uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile, - uint32_t name_and_signature_idx) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method = GetMethod(); - const DexFile* dexfile = method->GetDexFile(); - const uint32_t dex_method_idx = method->GetDexMethodIndex(); - const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx); - const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx); - DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid)); - DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid)); - if (dexfile == &other_dexfile) { - return dex_method_idx; - } - const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_); - const DexFile::StringId* other_descriptor = - other_dexfile.FindStringId(mid_declaring_class_descriptor); - if (other_descriptor != nullptr) { - const DexFile::TypeId* other_type_id = - other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor)); - if (other_type_id != nullptr) { - const DexFile::MethodId* other_mid = other_dexfile.FindMethodId( - *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_), - other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_)); - if (other_mid != nullptr) { - return other_dexfile.GetIndexForMethodId(*other_mid); - } - } - } - return DexFile::kDexNoIndex; - } - - private: - // Set the method_ field, for proxy methods looking up the interface method via the resolved - // methods table. - void SetMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - method_.Assign(method); - } - - Handle<mirror::ArtMethod> method_; - const char* shorty_; - uint32_t shorty_len_; - - DISALLOW_COPY_AND_ASSIGN(MethodHelper); -}; - -} // namespace art - -#endif // ART_RUNTIME_OBJECT_UTILS_H_ diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index a016cc50ac..577691c90b 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -24,11 +24,13 @@ #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(); @@ -164,7 +166,7 @@ bool ParsedOptions::ParseXGcOption(const std::string& option) { 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; @@ -258,7 +260,7 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni 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; @@ -542,11 +544,11 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni 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:")) { diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h index 4c74be680c..b1de62a54f 100644 --- a/runtime/parsed_options.h +++ b/runtime/parsed_options.h @@ -18,17 +18,26 @@ #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_; @@ -80,7 +89,7 @@ class ParsedOptions { 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_; @@ -105,7 +114,7 @@ class ParsedOptions { 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); diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc index b58a29c471..5154d69292 100644 --- a/runtime/parsed_options_test.cc +++ b/runtime/parsed_options_test.cc @@ -36,7 +36,7 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { 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)); diff --git a/runtime/profiler.cc b/runtime/profiler.cc index 7a7a92a7c0..951444812b 100644 --- a/runtime/profiler.cc +++ b/runtime/profiler.cc @@ -32,7 +32,6 @@ #include "mirror/dex_cache.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "os.h" #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 093c129add..bd6656dda1 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -14,12 +14,14 @@ * 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 "field_helper.h" +#include "mirror/art_field-inl.h" +#include "scoped_thread_state_change.h" + namespace art { class ProxyTest : public CommonCompilerTest { diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h index 5128b19d12..982553d3af 100644 --- a/runtime/quick/inline_method_analyser.h +++ b/runtime/quick/inline_method_analyser.h @@ -48,6 +48,7 @@ enum InlineMethodOpcode : uint16_t { kIntrinsicMinMaxFloat, kIntrinsicMinMaxDouble, kIntrinsicSqrt, + kIntrinsicGet, kIntrinsicCharAt, kIntrinsicCompareTo, kIntrinsicIsEmptyOrLength, diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 49f6fe015e..6581f9b627 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -16,6 +16,7 @@ #include "quick_exception_handler.h" +#include "arch/context.h" #include "dex_instruction.h" #include "entrypoints/entrypoint_utils.h" #include "handle_scope-inl.h" diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 32290393ce..d2877f98d1 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -17,6 +17,10 @@ #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 { diff --git a/runtime/reflection.cc b/runtime/reflection.cc index fe5e1043a9..0af4117783 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -20,14 +20,14 @@ #include "common_throws.h" #include "dex_file-inl.h" #include "jni_internal.h" +#include "method_helper.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" -#include "mirror/class.h" #include "mirror/class-inl.h" -#include "mirror/object_array.h" +#include "mirror/class.h" #include "mirror/object_array-inl.h" +#include "mirror/object_array.h" #include "nth_caller_visitor.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" #include "stack.h" #include "well_known_classes.h" @@ -567,6 +567,11 @@ bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) { 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) { diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc index abe68ef8d7..9d10daaffc 100644 --- a/runtime/reflection_test.cc +++ b/runtime/reflection_test.cc @@ -18,9 +18,11 @@ #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 { diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h index d08e658824..f776bcd336 100644 --- a/runtime/runtime-inl.h +++ b/runtime/runtime-inl.h @@ -19,6 +19,8 @@ #include "runtime.h" +#include "read_barrier-inl.h" + namespace art { inline QuickMethodFrameInfo Runtime::GetRuntimeMethodFrameInfo(mirror::ArtMethod* method) { @@ -37,6 +39,36 @@ inline QuickMethodFrameInfo Runtime::GetRuntimeMethodFrameInfo(mirror::ArtMethod } } +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_ diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c354ad51ca..0ddd2aed4a 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -49,6 +49,7 @@ #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" @@ -324,7 +325,7 @@ void Runtime::SweepSystemWeaks(IsMarkedCallback* visitor, void* arg) { 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; @@ -534,7 +535,7 @@ void Runtime::StartDaemonThreads() { 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)); @@ -925,6 +926,7 @@ void Runtime::VisitConstantRoots(RootCallback* callback, void* arg) { mirror::ArtField::VisitRoots(callback, arg); mirror::ArtMethod::VisitRoots(callback, arg); mirror::Class::VisitRoots(callback, arg); + mirror::Reference::VisitRoots(callback, arg); mirror::StackTraceElement::VisitRoots(callback, arg); mirror::String::VisitRoots(callback, arg); mirror::Throwable::VisitRoots(callback, arg); diff --git a/runtime/runtime.h b/runtime/runtime.h index 45af437edb..fccccbdfd7 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -32,7 +32,6 @@ #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" @@ -69,6 +68,8 @@ class ThreadList; 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). @@ -82,10 +83,8 @@ enum VisitRootFlags : uint8_t { 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 { @@ -266,13 +265,10 @@ class Runtime { 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) { @@ -281,14 +277,11 @@ class Runtime { 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) { @@ -299,14 +292,10 @@ class Runtime { // 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) { @@ -329,17 +318,10 @@ class Runtime { } 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]; @@ -474,7 +456,7 @@ class Runtime { 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); diff --git a/runtime/stack.cc b/runtime/stack.cc index d5405fbdf0..71e566efc3 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -16,13 +16,13 @@ #include "stack.h" +#include "arch/context.h" #include "base/hex_dump.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "quick/quick_method_frame_info.h" #include "runtime.h" #include "thread.h" @@ -366,9 +366,10 @@ std::string StackVisitor::DescribeLocation() const { 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 { @@ -431,7 +432,7 @@ void StackVisitor::WalkStack(bool include_transitions) { // 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. diff --git a/runtime/stack.h b/runtime/stack.h index 9402cddf56..ef498ef06f 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -17,20 +17,16 @@ #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 { @@ -711,8 +707,6 @@ class StackVisitor { 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_; diff --git a/runtime/thread.cc b/runtime/thread.cc index 7827dfb650..9fa158d5e0 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -32,27 +32,29 @@ #include "arch/context.h" #include "base/mutex.h" -#include "class_linker.h" #include "class_linker-inl.h" +#include "class_linker.h" #include "debugger.h" #include "dex_file-inl.h" #include "entrypoints/entrypoint_utils.h" #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-inl.h" #include "handle_scope.h" #include "indirect_reference_table-inl.h" #include "jni_internal.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" -#include "mirror/class-inl.h" #include "mirror/class_loader.h" +#include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/stack_trace_element.h" #include "monitor.h" -#include "object_utils.h" +#include "object_lock.h" #include "quick_exception_handler.h" #include "quick/quick_method_frame_info.h" #include "reflection.h" @@ -60,10 +62,9 @@ #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" #include "ScopedUtfChars.h" -#include "handle_scope-inl.h" #include "stack.h" -#include "thread-inl.h" #include "thread_list.h" +#include "thread-inl.h" #include "utils.h" #include "verifier/dex_gc_map.h" #include "verify_object-inl.h" @@ -1055,7 +1056,7 @@ Thread::Thread(bool daemon) : tls32_(daemon), wait_monitor_(nullptr), interrupte 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; diff --git a/runtime/thread.h b/runtime/thread.h index bf125f9b7a..d08c2fce82 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -31,7 +31,6 @@ #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" @@ -93,6 +92,8 @@ enum ThreadFlag { 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. @@ -1076,7 +1077,7 @@ class Thread { 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; diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 54732fae04..b649b626ca 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -39,6 +39,8 @@ namespace art { +static constexpr uint64_t kLongThreadSuspendThreshold = MsToNs(5); + ThreadList::ThreadList() : suspend_all_count_(0), debug_suspend_all_count_(0), thread_exit_cond_("thread exit condition variable", *Locks::thread_list_lock_) { @@ -304,8 +306,8 @@ void ThreadList::SuspendAll() { DCHECK(self != nullptr); VLOG(threads) << *self << " SuspendAll starting..."; - ATRACE_BEGIN("Suspending mutator threads"); + uint64_t start_time = NanoTime(); Locks::mutator_lock_->AssertNotHeld(self); Locks::thread_list_lock_->AssertNotHeld(self); @@ -338,6 +340,11 @@ void ThreadList::SuspendAll() { Locks::mutator_lock_->ExclusiveLock(self); #endif + uint64_t end_time = NanoTime(); + if (end_time - start_time > kLongThreadSuspendThreshold) { + LOG(WARNING) << "Suspending all threads took: " << PrettyDuration(end_time - start_time); + } + if (kDebugLocking) { // Debug check that all threads are suspended. AssertThreadsAreSuspended(self, self); diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index 292c94f64b..4bd44dcb0f 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -20,6 +20,7 @@ #include "atomic.h" #include "common_runtime_test.h" +#include "thread-inl.h" namespace art { diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc index a1347a49bb..04abe64453 100644 --- a/runtime/throw_location.cc +++ b/runtime/throw_location.cc @@ -19,7 +19,6 @@ #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "utils.h" namespace art { diff --git a/runtime/trace.cc b/runtime/trace.cc index 1a450c4cb9..f51b8c435a 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -30,7 +30,6 @@ #include "mirror/dex_cache.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "os.h" #include "scoped_thread_state_change.h" #include "ScopedLocalRef.h" @@ -115,7 +114,7 @@ static const uint16_t kTraceVersionDualClock = 3; 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; @@ -149,34 +148,34 @@ void Trace::FreeStackTrace(std::vector<mirror::ArtMethod*>* stack_trace) { 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) { @@ -462,7 +461,7 @@ Trace::Trace(File* trace_file, int buffer_size, int flags, bool sampling_enabled 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; diff --git a/runtime/trace.h b/runtime/trace.h index 9c8d35bb93..d7836b8965 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -36,19 +36,8 @@ namespace mirror { 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, @@ -62,7 +51,7 @@ class Trace FINAL : public instrumentation::InstrumentationListener { 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) @@ -138,7 +127,7 @@ class Trace FINAL : public instrumentation::InstrumentationListener { 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_; @@ -158,7 +147,7 @@ class Trace FINAL : public instrumentation::InstrumentationListener { // 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_; diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc index a03b389e0b..691aec4f2c 100644 --- a/runtime/transaction_test.cc +++ b/runtime/transaction_test.cc @@ -20,6 +20,7 @@ #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 { diff --git a/runtime/utils.cc b/runtime/utils.cc index d038571e96..8b1ad39edc 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -28,6 +28,7 @@ #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "dex_file-inl.h" +#include "field_helper.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" @@ -35,7 +36,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string.h" -#include "object_utils.h" #include "os.h" #include "scoped_thread_state_change.h" #include "utf-inl.h" @@ -281,11 +281,6 @@ std::string PrettyDescriptor(const std::string& descriptor) { 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"; diff --git a/runtime/utils.h b/runtime/utils.h index b47de81d62..2cb3af7aec 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -26,7 +26,7 @@ #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" @@ -279,7 +279,6 @@ bool EndsWith(const std::string& s, const char* suffix); 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_); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index eabb993879..a1b86e05f5 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -25,10 +25,12 @@ #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "dex_instruction_visitor.h" +#include "field_helper.h" #include "gc/accounting/card_table-inl.h" #include "indenter.h" #include "intern_table.h" #include "leb128.h" +#include "method_helper.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class.h" @@ -36,7 +38,6 @@ #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "register_line-inl.h" #include "runtime.h" #include "scoped_thread_state_change.h" diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index f70faf59a4..a5895e6dbf 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -22,6 +22,7 @@ #include "class_linker-inl.h" #include "common_runtime_test.h" #include "dex_file.h" +#include "scoped_thread_state_change.h" namespace art { namespace verifier { diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index e24c92091c..f0729e4271 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -24,7 +24,6 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" -#include "object_utils.h" #include "reg_type_cache-inl.h" #include "scoped_thread_state_change.h" diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index ff9edbbeaf..91fba4d2bb 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -21,7 +21,6 @@ #include "dex_file-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" namespace art { namespace verifier { diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc index 1935a5b1bc..9dc0df13fb 100644 --- a/runtime/verifier/reg_type_test.cc +++ b/runtime/verifier/reg_type_test.cc @@ -21,6 +21,8 @@ #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 { diff --git a/runtime/verify_object.h b/runtime/verify_object.h index 6640e0dd4a..8e1653ddb9 100644 --- a/runtime/verify_object.h +++ b/runtime/verify_object.h @@ -52,10 +52,10 @@ static constexpr VerifyObjectFlags kDefaultVerifyFlags = kVerifyNone; static constexpr VerifyObjectMode kVerifyObjectSupport = kDefaultVerifyFlags != 0 ? kVerifyObjectModeFast : kVerifyObjectModeDisabled; -void VerifyObject(mirror::Object* obj) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS; +ALWAYS_INLINE void VerifyObject(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS; // Check that c.getClass() == c.getClass().getClass(). -bool VerifyClassClass(mirror::Class* c) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS; +ALWAYS_INLINE bool VerifyClassClass(mirror::Class* c) NO_THREAD_SAFETY_ANALYSIS; } // namespace art diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc index d303d1e502..96abee2dc3 100644 --- a/runtime/zip_archive_test.cc +++ b/runtime/zip_archive_test.cc @@ -22,6 +22,7 @@ #include <zlib.h> #include <memory> +#include "base/unix_file/fd_file.h" #include "common_runtime_test.h" #include "os.h" diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h index f6f2253d72..a4ce81ce4c 100644 --- a/sigchainlib/sigchain.h +++ b/sigchainlib/sigchain.h @@ -18,10 +18,13 @@ #define ART_SIGCHAINLIB_SIGCHAIN_H_ #include <signal.h> + namespace art { void ClaimSignalChain(int signal, struct sigaction* oldaction); + void UnclaimSignalChain(int signal); + void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context); } // namespace art diff --git a/test/401-optimizing-compiler/expected.txt b/test/401-optimizing-compiler/expected.txt index 97492a411f..d6ef64b96b 100644 --- a/test/401-optimizing-compiler/expected.txt +++ b/test/401-optimizing-compiler/expected.txt @@ -11,3 +11,4 @@ Forced GC Forced GC Forced GC Forced GC +Forced GC diff --git a/test/401-optimizing-compiler/src/Main.java b/test/401-optimizing-compiler/src/Main.java index e5706a52fe..a5192e1e64 100644 --- a/test/401-optimizing-compiler/src/Main.java +++ b/test/401-optimizing-compiler/src/Main.java @@ -71,6 +71,10 @@ public class Main { if (m.$opt$TestOtherParameter(new Main()) == m) { throw new Error("Unexpected value returned"); } + + if (m.$opt$TestReturnNewObject(m) == m) { + throw new Error("Unexpected value returned"); + } } static int $opt$TestInvokeIntParameter(int param) { @@ -108,6 +112,12 @@ public class Main { return other; } + Object $opt$TestReturnNewObject(Object other) { + Object o = new Object(); + forceGCStaticMethod(); + return o; + } + public static void $opt$TestInvokeStatic() { printStaticMethod(); printStaticMethodWith2Args(1, 2); diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 25bcf0a790..1683074eba 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -21,26 +21,62 @@ include art/build/Android.common_test.mk TEST_ART_RUN_TESTS := $(wildcard $(LOCAL_PATH)/[0-9]*) TEST_ART_RUN_TESTS := $(subst $(LOCAL_PATH)/,, $(TEST_ART_RUN_TESTS)) +# List all the test names for host and target excluding the -trace suffix +# $(1): test name, e.g. 003-omnibus-opcodes +# $(2): undefined or -trace +define all-run-test-names + test-art-host-run-test$(2)-default-$(1)32 \ + test-art-host-run-test$(2)-optimizing-$(1)32 \ + test-art-host-run-test$(2)-interpreter-$(1)32 \ + test-art-host-run-test$(2)-default-$(1)64 \ + test-art-host-run-test$(2)-optimizing-$(1)64 \ + test-art-host-run-test$(2)-interpreter-$(1)64 \ + test-art-target-run-test$(2)-default-$(1)32 \ + test-art-target-run-test$(2)-optimizing-$(1)32 \ + test-art-target-run-test$(2)-interpreter-$(1)32 \ + test-art-target-run-test$(2)-default-$(1)64 \ + test-art-target-run-test$(2)-optimizing-$(1)64 \ + test-art-target-run-test$(2)-interpreter-$(1)64 +endef # all-run-test-names + # Tests that are timing sensitive and flaky on heavily loaded systems. TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \ - test-art-host-run-test-default-053-wait-some32 \ - test-art-host-run-test-default-053-wait-some64 \ - test-art-host-run-test-interpreter-053-wait-some32 \ - test-art-host-run-test-interpreter-053-wait-some64 \ - test-art-host-run-test-optimizing-053-wait-some32 \ - test-art-host-run-test-optimizing-053-wait-some64 \ - test-art-host-run-test-default-055-enum-performance32 \ - test-art-host-run-test-default-055-enum-performance64 \ - test-art-host-run-test-interpreter-055-enum-performance32 \ - test-art-host-run-test-interpreter-055-enum-performance64 \ - test-art-host-run-test-optimizing-055-enum-performance32 \ - test-art-host-run-test-optimizing-055-enum-performance64 + 053-wait-some \ + 055-enum-performance # disable timing sensitive tests on "dist" builds. ifdef dist_goal - ART_TEST_KNOWN_BROKEN += $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS) + ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(call all-run-test-names,$(test),)) + ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(call all-run-test-names,$(test),-trace)) endif +# Tests that are broken in --trace mode. +TEST_ART_BROKEN_TRACE_RUN_TESTS := \ + 003-omnibus-opcodes \ + 004-annotations \ + 018-stack-overflow \ + 023-many-interfaces \ + 031-class-attributes \ + 037-inherit \ + 044-proxy \ + 046-reflect \ + 051-thread \ + 055-enum-performance \ + 064-field-access \ + 078-polymorphic-virtual \ + 080-oom-throw \ + 082-inline-execute \ + 083-compiler-regressions \ + 097-duplicate-method \ + 100-reflect2 \ + 102-concurrent-gc \ + 103-string-append \ + 107-int-math2 \ + 112-double-math \ + 701-easy-div-rem + +ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_TRACE_RUN_TESTS), $(call all-run-test-names,$(test),-trace)) + # The path where build only targets will be output, e.g. # out/target/product/generic_x86_64/obj/PACKAGING/art-run-tests_intermediates/DATA art_run_tests_dir := $(call intermediates-dir-for,PACKAGING,art-run-tests)/DATA @@ -96,9 +132,11 @@ ART_TEST_HOST_RUN_TEST_ALL_RULES := ART_TEST_HOST_RUN_TEST_DEFAULT_RULES := ART_TEST_HOST_RUN_TEST_INTERPRETER_RULES := ART_TEST_HOST_RUN_TEST_OPTIMIZING_RULES := +ART_TEST_HOST_RUN_TEST_ALL$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := +ART_TEST_HOST_RUN_TEST_ALL$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := @@ -124,8 +162,10 @@ endif # $(2): host or target # $(3): default, optimizing or interpreter # $(4): 32 or 64 +# $(5): run tests with tracing enabled or not: trace or undefined define define-test-art-run-test run_test_options := $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) + run_test_rule_name := test-art-$(2)-run-test-$(3)-$(1)$(4) uc_host_or_target := prereq_rule := ifeq ($(2),host) @@ -163,7 +203,14 @@ define define-test-art-run-test $$(error found $(4) expected 32 or 64) endif endif - run_test_rule_name := test-art-$(2)-run-test-$(3)-$(1)$(4) + ifeq ($(5),trace) + run_test_options += --trace + run_test_rule_name := test-art-$(2)-run-test-trace-$(3)-$(1)$(4) + else + ifneq (,$(5)) + $$(error found $(5) expected undefined or -trace) + endif + endif run_test_options := --output-path $(ART_HOST_TEST_DIR)/run-test-output/$$(run_test_rule_name) \ $$(run_test_options) $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options) @@ -222,9 +269,13 @@ define define-test-art-run-test-group ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES := ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES := ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES := - $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX))) - $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX))) - $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX))) + $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),)) + $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),)) + $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),)) + ifeq ($(2),host) + # For now just test tracing on the host with default. + $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),trace)) + endif do_second := false ifeq ($(2),host) ifneq ($$(HOST_PREFER_32_BIT),true) @@ -236,9 +287,13 @@ define define-test-art-run-test-group endif endif ifeq (true,$$(do_second)) - $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX))) - $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX))) - $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX))) + $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),)) + $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),)) + $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),)) + ifeq ($(2),host) + # For now just test tracing on the host with default. + $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),trace)) + endif endif $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-default-$(1), \ @@ -319,6 +374,7 @@ endif define-test-art-run-test := define-test-art-run-test-group-rule := define-test-art-run-test-group := +all-run-test-names := ART_TEST_TARGET_RUN_TEST_ALL_RULES := ART_TEST_TARGET_RUN_TEST_DEFAULT_RULES := ART_TEST_TARGET_RUN_TEST_INTERPRETER_RULES := @@ -335,9 +391,11 @@ ART_TEST_HOST_RUN_TEST_ALL_RULES := ART_TEST_HOST_RUN_TEST_DEFAULT_RULES := ART_TEST_HOST_RUN_TEST_INTERPRETER_RULES := ART_TEST_HOST_RUN_TEST_OPTIMIZING_RULES := +ART_TEST_HOST_RUN_TEST_ALL$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES := +ART_TEST_HOST_RUN_TEST_ALL$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := ART_TEST_HOST_RUN_TEST_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES := diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc index 87187ed19d..e5a1786102 100644 --- a/test/ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/ReferenceMap/stack_walk_refmap_jni.cc @@ -20,12 +20,10 @@ #include "class_linker.h" #include "dex_file-inl.h" #include "gc_map.h" -#include "mirror/art_method.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "jni.h" diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc index c849c54bbe..e404f6ab7d 100644 --- a/test/StackWalk/stack_walk_jni.cc +++ b/test/StackWalk/stack_walk_jni.cc @@ -19,12 +19,10 @@ #include "class_linker.h" #include "gc_map.h" -#include "mirror/art_method.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "object_utils.h" #include "jni.h" #include "scoped_thread_state_change.h" |