summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/Android.mk18
-rw-r--r--compiler/common_compiler_test.h417
-rw-r--r--compiler/compiled_method.cc15
-rw-r--r--compiler/compiled_method.h9
-rw-r--r--compiler/compiler_backend.cc39
-rw-r--r--compiler/compiler_backend.h34
-rw-r--r--compiler/dex/bb_optimizations.h14
-rw-r--r--compiler/dex/bit_vector_block_iterator.cc32
-rw-r--r--compiler/dex/bit_vector_block_iterator.h58
-rw-r--r--compiler/dex/compiler_enums.h23
-rw-r--r--compiler/dex/compiler_ir.h2
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc8
-rw-r--r--compiler/dex/frontend.cc18
-rw-r--r--compiler/dex/frontend.h2
-rw-r--r--compiler/dex/local_value_numbering.cc73
-rw-r--r--compiler/dex/local_value_numbering_test.cc75
-rw-r--r--compiler/dex/mir_analysis.cc114
-rw-r--r--compiler/dex/mir_field_info.cc124
-rw-r--r--compiler/dex/mir_field_info.h211
-rw-r--r--compiler/dex/mir_graph.cc19
-rw-r--r--compiler/dex/mir_graph.h30
-rw-r--r--compiler/dex/pass.h4
-rw-r--r--compiler/dex/pass_driver.cc1
-rw-r--r--compiler/dex/portable/mir_to_gbc.cc1
-rw-r--r--compiler/dex/portable/mir_to_gbc.h7
-rw-r--r--compiler/dex/quick/arm/arm_lir.h1
-rw-r--r--compiler/dex/quick/arm/assemble_arm.cc5
-rw-r--r--compiler/dex/quick/arm/call_arm.cc3
-rw-r--r--compiler/dex/quick/arm/int_arm.cc3
-rw-r--r--compiler/dex/quick/arm/utility_arm.cc15
-rw-r--r--compiler/dex/quick/codegen_util.cc14
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.h11
-rw-r--r--compiler/dex/quick/gen_common.cc124
-rw-r--r--compiler/dex/quick/mir_to_lir.cc36
-rw-r--r--compiler/dex/quick/mir_to_lir.h16
-rw-r--r--compiler/dex/quick/x86/call_x86.cc4
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h18
-rw-r--r--compiler/dex/quick/x86/target_x86.cc165
-rw-r--r--compiler/dex/ssa_transformation.cc5
-rw-r--r--compiler/driver/compiler_driver-inl.h165
-rw-r--r--compiler/driver/compiler_driver.cc294
-rw-r--r--compiler/driver/compiler_driver.h117
-rw-r--r--compiler/driver/compiler_driver_test.cc6
-rw-r--r--compiler/driver/compiler_options.h14
-rw-r--r--compiler/elf_writer.cc7
-rw-r--r--compiler/elf_writer.h17
-rw-r--r--compiler/elf_writer_mclinker.cc42
-rw-r--r--compiler/elf_writer_mclinker.h17
-rw-r--r--compiler/elf_writer_quick.cc347
-rw-r--r--compiler/elf_writer_quick.h28
-rw-r--r--compiler/elf_writer_test.cc8
-rw-r--r--compiler/image_test.cc23
-rw-r--r--compiler/image_writer.cc6
-rw-r--r--compiler/jni/jni_compiler_test.cc4
-rw-r--r--compiler/leb128_encoder.h109
-rw-r--r--compiler/leb128_encoder_test.cc291
-rw-r--r--compiler/llvm/compiler_llvm.cc10
-rw-r--r--compiler/llvm/compiler_llvm.h2
-rw-r--r--compiler/llvm/gbc_expander.cc33
-rw-r--r--compiler/llvm/llvm_compilation_unit.cc3
-rw-r--r--compiler/oat_test.cc17
-rw-r--r--compiler/oat_writer.cc179
-rw-r--r--compiler/oat_writer.h39
-rw-r--r--compiler/optimizing/builder.cc107
-rw-r--r--compiler/optimizing/builder.h16
-rw-r--r--compiler/optimizing/dominator_test.cc261
-rw-r--r--compiler/optimizing/nodes.cc97
-rw-r--r--compiler/optimizing/nodes.h96
-rw-r--r--compiler/optimizing/pretty_printer.h18
-rw-r--r--compiler/optimizing/pretty_printer_test.cc221
-rw-r--r--compiler/output_stream_test.cc9
-rw-r--r--compiler/sea_ir/ir/regions_test.cc5
-rw-r--r--compiler/sea_ir/types/type_data_test.cc5
-rw-r--r--compiler/sea_ir/types/type_inference_visitor_test.cc5
-rw-r--r--compiler/utils/arena_allocator_test.cc2
-rw-r--r--compiler/utils/arena_bit_vector.cc (renamed from compiler/dex/arena_bit_vector.cc)16
-rw-r--r--compiler/utils/arena_bit_vector.h (renamed from compiler/dex/arena_bit_vector.h)59
-rw-r--r--compiler/utils/arm/managed_register_arm.cc10
-rw-r--r--compiler/utils/assembler.h2
-rw-r--r--compiler/utils/growable_array.h12
-rw-r--r--compiler/utils/mips/managed_register_mips.cc11
-rw-r--r--compiler/utils/scoped_hashtable_test.cc8
-rw-r--r--compiler/utils/x86/managed_register_x86.cc13
83 files changed, 3335 insertions, 1184 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 77dc367c7d..2f785ce5d7 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -21,7 +21,6 @@ include art/build/Android.common.mk
LIBART_COMPILER_SRC_FILES := \
compiled_method.cc \
dex/local_value_numbering.cc \
- dex/arena_bit_vector.cc \
dex/quick/arm/assemble_arm.cc \
dex/quick/arm/call_arm.cc \
dex/quick/arm/fp_arm.cc \
@@ -51,9 +50,11 @@ LIBART_COMPILER_SRC_FILES := \
dex/quick/x86/utility_x86.cc \
dex/dex_to_dex_compiler.cc \
dex/mir_dataflow.cc \
+ dex/mir_field_info.cc \
dex/mir_optimization.cc \
dex/pass_driver.cc \
dex/bb_optimizations.cc \
+ dex/bit_vector_block_iterator.cc \
dex/frontend.cc \
dex/mir_graph.cc \
dex/mir_analysis.cc \
@@ -72,6 +73,7 @@ LIBART_COMPILER_SRC_FILES := \
optimizing/nodes.cc \
trampolines/trampoline_compiler.cc \
utils/arena_allocator.cc \
+ utils/arena_bit_vector.cc \
utils/arm/assembler_arm.cc \
utils/arm/managed_register_arm.cc \
utils/assembler.cc \
@@ -105,7 +107,7 @@ endif
LIBART_COMPILER_CFLAGS :=
ifeq ($(ART_USE_PORTABLE_COMPILER),true)
-LIBART_COMPILER_SRC_FILES +=
+LIBART_COMPILER_SRC_FILES += \
dex/portable/mir_to_gbc.cc \
elf_writer_mclinker.cc \
jni/portable/jni_compiler.cc \
@@ -119,11 +121,12 @@ LIBART_COMPILER_SRC_FILES +=
llvm/runtime_support_builder.cc \
llvm/runtime_support_builder_arm.cc \
llvm/runtime_support_builder_x86.cc
- LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
+LIBART_COMPILER_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
endif
LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \
- dex/compiler_enums.h
+ dex/compiler_enums.h \
+ dex/quick/dex_file_method_inliner.h
# $(1): target or host
# $(2): ndebug or debug
@@ -210,12 +213,15 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
ifeq ($(TARGET_ARCH),arm64)
$$(info TODOAArch64: $$(LOCAL_PATH)/Android.mk Add Arm64 specific MCLinker libraries)
endif # TARGET_ARCH != arm64
+ include $(LLVM_DEVICE_BUILD_MK)
else # host
LOCAL_STATIC_LIBRARIES += libmcldARMInfo libmcldARMTarget
LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
LOCAL_STATIC_LIBRARIES += libmcldMipsInfo libmcldMipsTarget
+ include $(LLVM_HOST_BUILD_MK)
endif
LOCAL_STATIC_LIBRARIES += libmcldCore libmcldObject libmcldADT libmcldFragment libmcldTarget libmcldCodeGen libmcldLDVariant libmcldMC libmcldSupport libmcldLD
+ include $(LLVM_GEN_INTRINSICS_MK)
endif
LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
@@ -227,13 +233,9 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
ifeq ($$(art_target_or_host),target)
LOCAL_SHARED_LIBRARIES += libcutils
- include $(LLVM_GEN_INTRINSICS_MK)
- include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_SHARED_LIBRARY)
else # host
LOCAL_STATIC_LIBRARIES += libcutils
- include $(LLVM_GEN_INTRINSICS_MK)
- include $(LLVM_HOST_BUILD_MK)
include $(BUILD_HOST_SHARED_LIBRARY)
endif
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
new file mode 100644
index 0000000000..d034b7922e
--- /dev/null
+++ b/compiler/common_compiler_test.h
@@ -0,0 +1,417 @@
+/*
+ * 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_COMPILER_COMMON_COMPILER_TEST_H_
+#define ART_COMPILER_COMMON_COMPILER_TEST_H_
+
+#include "compiler_backend.h"
+#include "compiler_callbacks.h"
+#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"
+
+namespace art {
+
+#if defined(__arm__)
+
+#include <sys/ucontext.h>
+
+// A signal handler called when have an illegal instruction. We record the fact in
+// a global boolean and then increment the PC in the signal context to return to
+// the next instruction. We know the instruction is an sdiv (4 bytes long).
+static void baddivideinst(int signo, siginfo *si, void *data) {
+ (void)signo;
+ (void)si;
+ struct ucontext *uc = (struct ucontext *)data;
+ struct sigcontext *sc = &uc->uc_mcontext;
+ sc->arm_r0 = 0; // set R0 to #0 to signal error
+ sc->arm_pc += 4; // skip offending instruction
+}
+
+// This is in arch/arm/arm_sdiv.S. It does the following:
+// mov r1,#1
+// sdiv r0,r1,r1
+// bx lr
+//
+// the result will be the value 1 if sdiv is supported. If it is not supported
+// a SIGILL signal will be raised and the signal handler (baddivideinst) called.
+// The signal handler sets r0 to #0 and then increments pc beyond the failed instruction.
+// Thus if the instruction is not supported, the result of this function will be #0
+
+extern "C" bool CheckForARMSDIVInstruction();
+
+static InstructionSetFeatures GuessInstructionFeatures() {
+ InstructionSetFeatures f;
+
+ // Uncomment this for processing of /proc/cpuinfo.
+ if (false) {
+ // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
+ // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
+ std::ifstream in("/proc/cpuinfo");
+ if (in) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ if (line.find("Features") != std::string::npos) {
+ if (line.find("idivt") != std::string::npos) {
+ f.SetHasDivideInstruction(true);
+ }
+ }
+ }
+ in.close();
+ }
+ } else {
+ LOG(INFO) << "Failed to open /proc/cpuinfo";
+ }
+ }
+
+ // See if have a sdiv instruction. Register a signal handler and try to execute
+ // an sdiv instruction. If we get a SIGILL then it's not supported. We can't use
+ // the /proc/cpuinfo method for this because Krait devices don't always put the idivt
+ // feature in the list.
+ struct sigaction sa, osa;
+ sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+ sa.sa_sigaction = baddivideinst;
+ sigaction(SIGILL, &sa, &osa);
+
+ if (CheckForARMSDIVInstruction()) {
+ f.SetHasDivideInstruction(true);
+ }
+
+ // Restore the signal handler.
+ sigaction(SIGILL, &osa, 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;
+}
+
+class CommonCompilerTest : public CommonRuntimeTest {
+ public:
+ static void MakeExecutable(const std::vector<uint8_t>& code) {
+ CHECK_NE(code.size(), 0U);
+ MakeExecutable(&code[0], code.size());
+ }
+
+ // Create an OatMethod based on pointers (for unit tests).
+ OatFile::OatMethod CreateOatMethod(const void* code,
+ const size_t frame_size_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const uint8_t* mapping_table,
+ const uint8_t* vmap_table,
+ const uint8_t* gc_map) {
+ const byte* base;
+ uint32_t code_offset, mapping_table_offset, vmap_table_offset, gc_map_offset;
+ if (mapping_table == nullptr && vmap_table == nullptr && gc_map == nullptr) {
+ base = reinterpret_cast<const byte*>(code); // Base of data points at code.
+ base -= kPointerSize; // Move backward so that code_offset != 0.
+ code_offset = kPointerSize;
+ mapping_table_offset = 0;
+ vmap_table_offset = 0;
+ gc_map_offset = 0;
+ } else {
+ // TODO: 64bit support.
+ base = nullptr; // Base of data in oat file, ie 0.
+ code_offset = PointerToLowMemUInt32(code);
+ mapping_table_offset = PointerToLowMemUInt32(mapping_table);
+ vmap_table_offset = PointerToLowMemUInt32(vmap_table);
+ gc_map_offset = PointerToLowMemUInt32(gc_map);
+ }
+ return OatFile::OatMethod(base,
+ code_offset,
+ frame_size_in_bytes,
+ core_spill_mask,
+ fp_spill_mask,
+ mapping_table_offset,
+ vmap_table_offset,
+ gc_map_offset);
+ }
+
+ void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(method != nullptr);
+
+ const CompiledMethod* compiled_method = nullptr;
+ if (!method->IsAbstract()) {
+ mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ compiled_method =
+ compiler_driver_->GetCompiledMethod(MethodReference(&dex_file,
+ method->GetDexMethodIndex()));
+ }
+ if (compiled_method != nullptr) {
+ const std::vector<uint8_t>* code = compiled_method->GetQuickCode();
+ if (code == nullptr) {
+ code = compiled_method->GetPortableCode();
+ }
+ MakeExecutable(*code);
+ const void* method_code = CompiledMethod::CodePointer(&(*code)[0],
+ compiled_method->GetInstructionSet());
+ LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code,
+ compiled_method->GetFrameSizeInBytes(),
+ compiled_method->GetCoreSpillMask(),
+ compiled_method->GetFpSpillMask(),
+ &compiled_method->GetMappingTable()[0],
+ &compiled_method->GetVmapTable()[0],
+ nullptr);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+ } else {
+ // No code? You must mean to go into the interpreter.
+ const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge()
+ : GetQuickToInterpreterBridge();
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code,
+ kStackAlignment,
+ 0,
+ 0,
+ nullptr,
+ nullptr,
+ nullptr);
+ oat_method.LinkMethod(method);
+ method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
+ }
+ // Create bridges to transition between different kinds of compiled bridge.
+ if (method->GetEntryPointFromPortableCompiledCode() == nullptr) {
+ method->SetEntryPointFromPortableCompiledCode(GetPortableToQuickBridge());
+ } else {
+ CHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToPortableBridge());
+ method->SetIsPortableCompiled();
+ }
+ }
+
+ static void MakeExecutable(const void* code_start, size_t code_length) {
+ CHECK(code_start != 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
+ LOG(WARNING) << "UNIMPLEMENTED: cache flush";
+#endif
+ }
+
+ void MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::string class_descriptor(DotToDescriptor(class_name));
+ Thread* self = Thread::Current();
+ SirtRef<mirror::ClassLoader> loader(self, class_loader);
+ mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader);
+ CHECK(klass != 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));
+ }
+ }
+
+ 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(STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES));
+
+#if defined(__arm__)
+ instruction_set = kThumb2;
+ InstructionSetFeatures runtime_features = GuessInstructionFeatures();
+
+ // for ARM, do a runtime check to make sure that the features we are passed from
+ // the build match the features we actually determine at runtime.
+ ASSERT_EQ(instruction_set_features, runtime_features);
+#elif defined(__mips__)
+ instruction_set = kMips;
+#elif defined(__i386__)
+ instruction_set = kX86;
+#elif defined(__x86_64__)
+ instruction_set = kX86_64;
+ // TODO: x86_64 compilation support.
+ compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
+#endif
+
+ for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+ Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+ if (!runtime_->HasCalleeSaveMethod(type)) {
+ runtime_->SetCalleeSaveMethod(
+ runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
+ }
+ }
+
+ // TODO: make selectable
+ CompilerBackend::Kind compiler_backend
+ = (kUsePortableCompiler) ? CompilerBackend::kPortable : CompilerBackend::kQuick;
+ timer_.reset(new CumulativeLogger("Compilation times"));
+ compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
+ verification_results_.get(),
+ method_inliner_map_.get(),
+ compiler_backend, instruction_set,
+ instruction_set_features,
+ true, new CompilerDriver::DescriptorSet,
+ 2, true, true, timer_.get()));
+ }
+ // We typically don't generate an image in unit tests, disable this optimization by default.
+ compiler_driver_->SetSupportBootImageFixup(false);
+ }
+
+ 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 TearDown() {
+ timer_.reset();
+ compiler_driver_.reset();
+ callbacks_.reset();
+ method_inliner_map_.reset();
+ verification_results_.reset();
+ compiler_options_.reset();
+
+ CommonRuntimeTest::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();
+ SirtRef<mirror::ClassLoader> loader(self, 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 CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(method != nullptr);
+ TimingLogger timings("CommonTest::CompileMethod", false, false);
+ timings.StartSplit("CompileOne");
+ compiler_driver_->CompileOne(method, &timings);
+ MakeExecutable(method);
+ timings.EndSplit();
+ }
+
+ void CompileDirectMethod(SirtRef<mirror::ClassLoader>& class_loader, const char* class_name,
+ const char* method_name, const char* signature)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::string class_descriptor(DotToDescriptor(class_name));
+ Thread* self = Thread::Current();
+ mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), class_loader);
+ CHECK(klass != 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 CompileVirtualMethod(SirtRef<mirror::ClassLoader>& class_loader, const char* class_name,
+ const char* method_name, const char* signature)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::string class_descriptor(DotToDescriptor(class_name));
+ Thread* self = Thread::Current();
+ mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), class_loader);
+ CHECK(klass != 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 ReserveImageSpace() {
+ // Reserve where the image will be loaded up front so that other parts of test set up don't
+ // accidentally end up colliding with the fixed memory address when we need to load the image.
+ std::string error_msg;
+ image_reservation_.reset(MemMap::MapAnonymous("image reservation",
+ reinterpret_cast<byte*>(ART_BASE_ADDRESS),
+ (size_t)100 * 1024 * 1024, // 100MB
+ PROT_NONE,
+ false /* no need for 4gb flag with fixed mmap*/,
+ &error_msg));
+ CHECK(image_reservation_.get() != nullptr) << error_msg;
+ }
+
+ void UnreserveImageSpace() {
+ image_reservation_.reset();
+ }
+
+ UniquePtr<CompilerOptions> compiler_options_;
+ UniquePtr<VerificationResults> verification_results_;
+ UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
+ UniquePtr<CompilerCallbacksImpl> callbacks_;
+ UniquePtr<CompilerDriver> compiler_driver_;
+ UniquePtr<CumulativeLogger> timer_;
+
+ private:
+ UniquePtr<MemMap> image_reservation_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_COMMON_COMPILER_TEST_H_
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f6d724ab56..d884bc0ef8 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -153,12 +153,14 @@ CompiledMethod::CompiledMethod(CompilerDriver& driver,
const uint32_t fp_spill_mask,
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
- const std::vector<uint8_t>& native_gc_map)
+ const std::vector<uint8_t>& native_gc_map,
+ const std::vector<uint8_t>* cfi_info)
: CompiledCode(&driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
mapping_table_(driver.DeduplicateMappingTable(mapping_table)),
vmap_table_(driver.DeduplicateVMapTable(vmap_table)),
- gc_map_(driver.DeduplicateGCMap(native_gc_map)) {
+ gc_map_(driver.DeduplicateGCMap(native_gc_map)),
+ cfi_info_(driver.DeduplicateCFIInfo(cfi_info)) {
}
CompiledMethod::CompiledMethod(CompilerDriver& driver,
@@ -169,10 +171,11 @@ CompiledMethod::CompiledMethod(CompilerDriver& driver,
const uint32_t fp_spill_mask)
: CompiledCode(&driver, instruction_set, code),
frame_size_in_bytes_(frame_size_in_bytes),
- core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {
- mapping_table_ = driver.DeduplicateMappingTable(std::vector<uint8_t>());
- vmap_table_ = driver.DeduplicateVMapTable(std::vector<uint8_t>());
- gc_map_ = driver.DeduplicateGCMap(std::vector<uint8_t>());
+ core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
+ mapping_table_(driver.DeduplicateMappingTable(std::vector<uint8_t>())),
+ vmap_table_(driver.DeduplicateVMapTable(std::vector<uint8_t>())),
+ gc_map_(driver.DeduplicateGCMap(std::vector<uint8_t>())),
+ cfi_info_(nullptr) {
}
// Constructs a CompiledMethod for the Portable compiler.
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 611230509a..90ae6eeae8 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -110,7 +110,8 @@ class CompiledMethod : public CompiledCode {
const uint32_t fp_spill_mask,
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
- const std::vector<uint8_t>& native_gc_map);
+ const std::vector<uint8_t>& native_gc_map,
+ const std::vector<uint8_t>* cfi_info);
// Constructs a CompiledMethod for the QuickJniCompiler.
CompiledMethod(CompilerDriver& driver,
@@ -157,6 +158,10 @@ class CompiledMethod : public CompiledCode {
return *gc_map_;
}
+ const std::vector<uint8_t>* GetCFIInfo() const {
+ return cfi_info_;
+ }
+
private:
// For quick code, the size of the activation used by the code.
const size_t frame_size_in_bytes_;
@@ -172,6 +177,8 @@ class CompiledMethod : public CompiledCode {
// For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers
// are live. For portable code, the key is a dalvik PC.
std::vector<uint8_t>* gc_map_;
+ // For quick code, a FDE entry for the debug_frame section.
+ std::vector<uint8_t>* cfi_info_;
};
} // namespace art
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
index eaa39f83c1..0afa665eb7 100644
--- a/compiler/compiler_backend.cc
+++ b/compiler/compiler_backend.cc
@@ -83,6 +83,9 @@ static CompiledMethod* TryCompileWithSeaIR(art::CompilerDriver& compiler,
}
+// Hack for CFI CIE initialization
+extern std::vector<uint8_t>* X86CFIInitialization();
+
class QuickBackend : public CompilerBackend {
public:
QuickBackend() : CompilerBackend(100) {}
@@ -135,10 +138,11 @@ class QuickBackend : public CompilerBackend {
}
bool WriteElf(art::File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host, const CompilerDriver& driver) const
+ OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
}
@@ -165,11 +169,27 @@ class QuickBackend : public CompilerBackend {
bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
CHECK(set_max);
}
- return mir_to_lir;;
+ return mir_to_lir;
}
void InitCompilationUnit(CompilationUnit& cu) const {}
+ /*
+ * @brief Generate and return Dwarf CFI initialization, if supported by the
+ * backend.
+ * @param driver CompilerDriver for this compile.
+ * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+ * information.
+ * @note This is used for backtrace information in generated code.
+ */
+ std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver) const
+ OVERRIDE {
+ if (driver.GetInstructionSet() == kX86) {
+ return X86CFIInitialization();
+ }
+ return nullptr;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(QuickBackend);
};
@@ -249,11 +269,12 @@ class LLVMBackend : public CompilerBackend {
}
bool WriteElf(art::File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host, const CompilerDriver& driver) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ OVERRIDE
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return art::ElfWriterMclinker::Create(
file, oat_writer, dex_files, android_root, is_host, driver);
}
@@ -271,15 +292,17 @@ class LLVMBackend : public CompilerBackend {
(1 << kSuppressExceptionEdges);
}
- bool isPortable() const { return true; }
+ bool IsPortable() const OVERRIDE {
+ return true;
+ }
- void SetBitcodeFileName(std::string const& filename) {
- typedef void (*SetBitcodeFileNameFn)(CompilerDriver&, std::string const&);
+ void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+ typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&);
SetBitcodeFileNameFn set_bitcode_file_name =
reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
- set_bitcode_file_name(*this, filename);
+ set_bitcode_file_name(driver, filename);
}
private:
diff --git a/compiler/compiler_backend.h b/compiler/compiler_backend.h
index 01a69afc89..b473806bba 100644
--- a/compiler/compiler_backend.h
+++ b/compiler/compiler_backend.h
@@ -23,7 +23,7 @@
namespace art {
class Backend;
-class CompilationUnit;
+struct CompilationUnit;
class CompilerDriver;
class CompiledMethod;
class MIRGraph;
@@ -40,8 +40,9 @@ class CompilerBackend {
kPortable
};
- explicit CompilerBackend(int warning)
- : maximum_compilation_time_before_warning_(warning) {}
+ explicit CompilerBackend(uint64_t warning)
+ : maximum_compilation_time_before_warning_(warning) {
+ }
static CompilerBackend* Create(Kind kind);
@@ -49,7 +50,7 @@ class CompilerBackend {
virtual void UnInit(CompilerDriver& driver) const = 0;
- virtual CompiledMethod* Compile(CompilerDriver& compiler,
+ virtual CompiledMethod* Compile(CompilerDriver& driver,
const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -66,7 +67,7 @@ class CompilerBackend {
virtual uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const = 0;
virtual bool WriteElf(art::File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const art::DexFile*>& dex_files,
const std::string& android_root,
bool is_host, const CompilerDriver& driver) const
@@ -79,8 +80,12 @@ class CompilerBackend {
return maximum_compilation_time_before_warning_;
}
- virtual bool IsPortable() const { return false; }
- void SetBitcodeFileName(std::string const& filename) {
+ virtual bool IsPortable() const {
+ return false;
+ }
+
+ void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) {
+ UNUSED(driver);
UNUSED(filename);
}
@@ -88,8 +93,21 @@ class CompilerBackend {
virtual ~CompilerBackend() {}
+ /*
+ * @brief Generate and return Dwarf CFI initialization, if supported by the
+ * backend.
+ * @param driver CompilerDriver for this compile.
+ * @returns nullptr if not supported by backend or a vector of bytes for CFI DWARF
+ * information.
+ * @note This is used for backtrace information in generated code.
+ */
+ virtual std::vector<uint8_t>* GetCallFrameInformationInitialization(const CompilerDriver& driver)
+ const {
+ return nullptr;
+ }
+
private:
- uint64_t maximum_compilation_time_before_warning_;
+ const uint64_t maximum_compilation_time_before_warning_;
DISALLOW_COPY_AND_ASSIGN(CompilerBackend);
};
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h
index 1286a8e52e..bd7c40ba5b 100644
--- a/compiler/dex/bb_optimizations.h
+++ b/compiler/dex/bb_optimizations.h
@@ -23,6 +23,20 @@
namespace art {
/**
+ * @class CacheFieldLoweringInfo
+ * @brief Cache the lowering info for fields used by IGET/IPUT/SGET/SPUT insns.
+ */
+class CacheFieldLoweringInfo : public Pass {
+ public:
+ CacheFieldLoweringInfo() : Pass("CacheFieldLoweringInfo", kNoNodes) {
+ }
+
+ void Start(CompilationUnit* cUnit) const {
+ cUnit->mir_graph->DoCacheFieldLoweringInfo();
+ }
+};
+
+/**
* @class CodeLayout
* @brief Perform the code layout pass.
*/
diff --git a/compiler/dex/bit_vector_block_iterator.cc b/compiler/dex/bit_vector_block_iterator.cc
new file mode 100644
index 0000000000..32d7d71ede
--- /dev/null
+++ b/compiler/dex/bit_vector_block_iterator.cc
@@ -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.
+ */
+
+#include "bit_vector_block_iterator.h"
+#include "mir_graph.h"
+
+namespace art {
+
+BasicBlock* BitVectorBlockIterator::Next() {
+ int idx = internal_iterator_.Next();
+
+ if (idx == -1) {
+ return nullptr;
+ }
+
+ return mir_graph_->GetBasicBlock(idx);
+}
+
+} // namespace art
diff --git a/compiler/dex/bit_vector_block_iterator.h b/compiler/dex/bit_vector_block_iterator.h
new file mode 100644
index 0000000000..0821e9e238
--- /dev/null
+++ b/compiler/dex/bit_vector_block_iterator.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_
+#define ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_
+
+#include "base/bit_vector.h"
+#include "compiler_enums.h"
+#include "utils/arena_bit_vector.h"
+#include "utils/arena_allocator.h"
+#include "compiler_ir.h"
+
+namespace art {
+
+class MIRGraph;
+
+/**
+ * @class BasicBlockIterator
+ * @brief Helper class to get the BasicBlocks when iterating through the ArenaBitVector.
+ */
+class BitVectorBlockIterator {
+ public:
+ explicit BitVectorBlockIterator(BitVector* bv, MIRGraph* mir_graph)
+ : mir_graph_(mir_graph),
+ internal_iterator_(bv) {}
+
+ explicit BitVectorBlockIterator(BitVector* bv, CompilationUnit* c_unit)
+ : mir_graph_(c_unit->mir_graph.get()),
+ internal_iterator_(bv) {}
+
+ BasicBlock* Next();
+
+ void* operator new(size_t size, ArenaAllocator* arena) {
+ return arena->Alloc(size, ArenaAllocator::kAllocGrowableArray);
+ };
+ void operator delete(void* p) {} // Nop.
+
+ private:
+ MIRGraph* const mir_graph_;
+ BitVector::Iterator internal_iterator_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index 2bc36a5e9f..0cd9ba3603 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -402,29 +402,6 @@ enum SelectInstructionKind {
std::ostream& operator<<(std::ostream& os, const SelectInstructionKind& kind);
-// Type of growable bitmap for memory tuning.
-enum OatBitMapKind {
- kBitMapMisc = 0,
- kBitMapUse,
- kBitMapDef,
- kBitMapLiveIn,
- kBitMapBMatrix,
- kBitMapDominators,
- kBitMapIDominated,
- kBitMapDomFrontier,
- kBitMapPhi,
- kBitMapTmpBlocks,
- kBitMapInputBlocks,
- kBitMapRegisterV,
- kBitMapTempSSARegisterV,
- kBitMapNullCheck,
- kBitMapTmpBlockV,
- kBitMapPredecessors,
- kNumBitMapKinds
-};
-
-std::ostream& operator<<(std::ostream& os, const OatBitMapKind& kind);
-
// LIR fixup kinds for Arm
enum FixupKind {
kFixupNone,
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 8447d23ddc..b9a26d6dbb 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -64,7 +64,7 @@ struct CompilationUnit {
const CompilerBackend* compiler_backend;
InstructionSet instruction_set;
- const InstructionSetFeatures& GetInstructionSetFeatures() {
+ InstructionSetFeatures GetInstructionSetFeatures() {
return compiler_driver->GetInstructionSetFeatures();
}
// TODO: much of this info available elsewhere. Go to the original source?
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index ff8fea0f88..b9f9437c95 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -208,21 +208,21 @@ void DexCompiler::CompileInstanceFieldAccess(Instruction* inst,
return;
}
uint32_t field_idx = inst->VRegC_22c();
- int field_offset;
+ MemberOffset field_offset(0u);
bool is_volatile;
bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
&field_offset, &is_volatile);
- if (fast_path && !is_volatile && IsUint(16, field_offset)) {
+ if (fast_path && !is_volatile && IsUint(16, field_offset.Int32Value())) {
VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
<< " to " << Instruction::Name(new_opcode)
<< " by replacing field index " << field_idx
- << " by field offset " << field_offset
+ << " by field offset " << field_offset.Int32Value()
<< " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
<< PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
// We are modifying 4 consecutive bytes.
inst->SetOpcode(new_opcode);
// Replace field index by field offset.
- inst->SetVRegC_22c(static_cast<uint16_t>(field_offset));
+ inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
}
}
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 6800f7b2a4..26192589e1 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -128,7 +128,7 @@ void CompilationUnit::EndTiming() {
}
}
-static CompiledMethod* CompileMethod(CompilerDriver& compiler,
+static CompiledMethod* CompileMethod(CompilerDriver& driver,
CompilerBackend* compiler_backend,
const DexFile::CodeItem* code_item,
uint32_t access_flags, InvokeType invoke_type,
@@ -143,11 +143,11 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler,
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- CompilationUnit cu(&compiler.GetArenaPool());
+ CompilationUnit cu(driver.GetArenaPool());
- cu.compiler_driver = &compiler;
+ cu.compiler_driver = &driver;
cu.class_linker = class_linker;
- cu.instruction_set = compiler.GetInstructionSet();
+ cu.instruction_set = driver.GetInstructionSet();
cu.compiler_backend = compiler_backend;
DCHECK((cu.instruction_set == kThumb2) ||
(cu.instruction_set == kX86) ||
@@ -216,8 +216,8 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler,
}
/* Create the pass driver and launch it */
- PassDriver driver(&cu);
- driver.Launch();
+ PassDriver pass_driver(&cu);
+ pass_driver.Launch();
if (cu.enable_debug & (1 << kDebugDumpCheckStats)) {
cu.mir_graph->DumpCheckStats();
@@ -257,9 +257,9 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler,
}
cu.EndTiming();
- compiler.GetTimingsLogger().Start();
- compiler.GetTimingsLogger().AddLogger(cu.timings);
- compiler.GetTimingsLogger().End();
+ driver.GetTimingsLogger()->Start();
+ driver.GetTimingsLogger()->AddLogger(cu.timings);
+ driver.GetTimingsLogger()->End();
return result;
}
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 8ce12067ee..22a7b8cfb0 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -105,7 +105,7 @@ class LLVMInfo {
UniquePtr<art::llvm::IRBuilder> ir_builder_;
};
-struct CompiledMethod;
+class CompiledMethod;
class CompilerDriver;
} // namespace art
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index a3ea034902..61c676784f 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -16,6 +16,7 @@
#include "local_value_numbering.h"
+#include "mir_field_info.h"
#include "mir_graph.h"
namespace art {
@@ -534,16 +535,24 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::IGET_BYTE:
case Instruction::IGET_CHAR:
case Instruction::IGET_SHORT: {
+ uint16_t type = opcode - Instruction::IGET;
uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
HandleNullCheck(mir, base);
+ const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir);
uint16_t memory_version;
uint16_t field_id;
- // TODO: all gets treated as volatile.
- // Volatile fields always get a new memory version; field id is irrelevant.
- // Unresolved fields are always marked as volatile and handled the same way here.
- field_id = 0u;
- memory_version = next_memory_version_;
- ++next_memory_version_;
+ if (!field_info.IsResolved() || field_info.IsVolatile()) {
+ // Volatile fields always get a new memory version; field id is irrelevant.
+ // Unresolved fields may be volatile, so handle them as such to be safe.
+ field_id = 0u;
+ memory_version = next_memory_version_;
+ ++next_memory_version_;
+ } else {
+ DCHECK(field_info.IsResolved());
+ field_id = GetFieldId(field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex());
+ memory_version = std::max(unresolved_ifield_version_[type],
+ GetMemoryVersion(base, field_id, type));
+ }
if (opcode == Instruction::IGET_WIDE) {
res = LookupValue(Instruction::IGET_WIDE, base, field_id, memory_version);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
@@ -567,10 +576,18 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
HandleNullCheck(mir, base);
- // TODO: all puts treated as unresolved.
- // Unresolved fields always alias with everything of the same type.
- unresolved_ifield_version_[type] = next_memory_version_;
- ++next_memory_version_;
+ const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir);
+ if (!field_info.IsResolved()) {
+ // Unresolved fields always alias with everything of the same type.
+ unresolved_ifield_version_[type] = next_memory_version_;
+ ++next_memory_version_;
+ } else if (field_info.IsVolatile()) {
+ // Nothing to do, resolved volatile fields always get a new memory version anyway and
+ // can't alias with resolved non-volatile fields.
+ } else {
+ AdvanceMemoryVersion(base, GetFieldId(field_info.DeclaringDexFile(),
+ field_info.DeclaringFieldIndex()), type);
+ }
}
break;
@@ -581,14 +598,22 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
case Instruction::SGET_SHORT: {
+ uint16_t type = opcode - Instruction::SGET;
+ const MirFieldInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir);
uint16_t memory_version;
uint16_t field_id;
- // TODO: all gets treated as volatile.
- // Volatile fields always get a new memory version; field id is irrelevant.
- // Unresolved fields are always marked as volatile and handled the same way here.
- field_id = 0u;
- memory_version = next_memory_version_;
- ++next_memory_version_;
+ if (!field_info.IsResolved() || field_info.IsVolatile()) {
+ // Volatile fields always get a new memory version; field id is irrelevant.
+ // Unresolved fields may be volatile, so handle them as such to be safe.
+ field_id = 0u;
+ memory_version = next_memory_version_;
+ ++next_memory_version_;
+ } else {
+ DCHECK(field_info.IsResolved());
+ field_id = GetFieldId(field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex());
+ memory_version = std::max(unresolved_sfield_version_[type],
+ GetMemoryVersion(NO_VALUE, field_id, type));
+ }
if (opcode == Instruction::SGET_WIDE) {
res = LookupValue(Instruction::SGET_WIDE, NO_VALUE, field_id, memory_version);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
@@ -609,10 +634,18 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::SPUT_CHAR:
case Instruction::SPUT_SHORT: {
uint16_t type = opcode - Instruction::SPUT;
- // TODO: all puts treated as unresolved.
- // Unresolved fields always alias with everything of the same type.
- unresolved_sfield_version_[type] = next_memory_version_;
- ++next_memory_version_;
+ const MirFieldInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir);
+ if (!field_info.IsResolved()) {
+ // Unresolved fields always alias with everything of the same type.
+ unresolved_sfield_version_[type] = next_memory_version_;
+ ++next_memory_version_;
+ } else if (field_info.IsVolatile()) {
+ // Nothing to do, resolved volatile fields always get a new memory version anyway and
+ // can't alias with resolved non-volatile fields.
+ } else {
+ AdvanceMemoryVersion(NO_VALUE, GetFieldId(field_info.DeclaringDexFile(),
+ field_info.DeclaringFieldIndex()), type);
+ }
}
break;
}
diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc
index 6ab6c51a1f..4599612db6 100644
--- a/compiler/dex/local_value_numbering_test.cc
+++ b/compiler/dex/local_value_numbering_test.cc
@@ -44,7 +44,7 @@ class LocalValueNumberingTest : public testing::Test {
Instruction::Code opcode;
int64_t value;
- uint32_t field_annotation;
+ uint32_t field_info;
size_t num_uses;
int32_t uses[kMaxSsaUses];
size_t num_defs;
@@ -55,28 +55,41 @@ class LocalValueNumberingTest : public testing::Test {
{ opcode, value, 0u, 0, { }, 1, { reg } }
#define DEF_CONST_WIDE(opcode, reg, value) \
{ opcode, value, 0u, 0, { }, 2, { reg, reg + 1 } }
-#define DEF_IGET(opcode, reg, obj, field_annotation) \
- { opcode, 0u, field_annotation, 1, { obj }, 1, { reg } }
-#define DEF_IGET_WIDE(opcode, reg, obj, field_annotation) \
- { opcode, 0u, field_annotation, 1, { obj }, 2, { reg, reg + 1 } }
-#define DEF_IPUT(opcode, reg, obj, field_annotation) \
- { opcode, 0u, field_annotation, 2, { reg, obj }, 0, { } }
-#define DEF_IPUT_WIDE(opcode, reg, obj, field_annotation) \
- { opcode, 0u, field_annotation, 3, { reg, reg + 1, obj }, 0, { } }
-#define DEF_SGET(opcode, reg, field_annotation) \
- { opcode, 0u, field_annotation, 0, { }, 1, { reg } }
-#define DEF_SGET_WIDE(opcode, reg, field_annotation) \
- { opcode, 0u, field_annotation, 0, { }, 2, { reg, reg + 1 } }
-#define DEF_SPUT(opcode, reg, field_annotation) \
- { opcode, 0u, field_annotation, 1, { reg }, 0, { } }
-#define DEF_SPUT_WIDE(opcode, reg, field_annotation) \
- { opcode, 0u, field_annotation, 2, { reg, reg + 1 }, 0, { } }
+#define DEF_IGET(opcode, reg, obj, field_info) \
+ { opcode, 0u, field_info, 1, { obj }, 1, { reg } }
+#define DEF_IGET_WIDE(opcode, reg, obj, field_info) \
+ { opcode, 0u, field_info, 1, { obj }, 2, { reg, reg + 1 } }
+#define DEF_IPUT(opcode, reg, obj, field_info) \
+ { opcode, 0u, field_info, 2, { reg, obj }, 0, { } }
+#define DEF_IPUT_WIDE(opcode, reg, obj, field_info) \
+ { opcode, 0u, field_info, 3, { reg, reg + 1, obj }, 0, { } }
+#define DEF_SGET(opcode, reg, field_info) \
+ { opcode, 0u, field_info, 0, { }, 1, { reg } }
+#define DEF_SGET_WIDE(opcode, reg, field_info) \
+ { opcode, 0u, field_info, 0, { }, 2, { reg, reg + 1 } }
+#define DEF_SPUT(opcode, reg, field_info) \
+ { opcode, 0u, field_info, 1, { reg }, 0, { } }
+#define DEF_SPUT_WIDE(opcode, reg, field_info) \
+ { opcode, 0u, field_info, 2, { reg, reg + 1 }, 0, { } }
#define DEF_INVOKE1(opcode, reg) \
{ opcode, 0u, 0u, 1, { reg }, 0, { } }
#define DEF_UNIQUE_REF(opcode, reg) \
{ opcode, 0u, 0u, 0, { }, 1, { reg } } // CONST_CLASS, CONST_STRING, NEW_ARRAY, ...
void DoPrepareIFields(const IFieldDef* defs, size_t count) {
+ cu_.mir_graph->ifield_lowering_infos_.Reset();
+ cu_.mir_graph->ifield_lowering_infos_.Resize(count);
+ for (size_t i = 0u; i != count; ++i) {
+ const IFieldDef* def = &defs[i];
+ MirIFieldLoweringInfo field_info(def->field_idx);
+ if (def->declaring_dex_file != 0u) {
+ field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
+ field_info.declaring_field_idx_ = def->declaring_field_idx;
+ field_info.flags_ = 0u | // Without kFlagIsStatic.
+ (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u);
+ }
+ cu_.mir_graph->ifield_lowering_infos_.Insert(field_info);
+ }
}
template <size_t count>
@@ -85,6 +98,19 @@ class LocalValueNumberingTest : public testing::Test {
}
void DoPrepareSFields(const SFieldDef* defs, size_t count) {
+ cu_.mir_graph->sfield_lowering_infos_.Reset();
+ cu_.mir_graph->sfield_lowering_infos_.Resize(count);
+ for (size_t i = 0u; i != count; ++i) {
+ const SFieldDef* def = &defs[i];
+ MirSFieldLoweringInfo field_info(def->field_idx);
+ if (def->declaring_dex_file != 0u) {
+ field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file);
+ field_info.declaring_field_idx_ = def->declaring_field_idx;
+ field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic |
+ (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u);
+ }
+ cu_.mir_graph->sfield_lowering_infos_.Insert(field_info);
+ }
}
template <size_t count>
@@ -102,6 +128,13 @@ class LocalValueNumberingTest : public testing::Test {
mir->dalvikInsn.opcode = def->opcode;
mir->dalvikInsn.vB = static_cast<int32_t>(def->value);
mir->dalvikInsn.vB_wide = def->value;
+ if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) {
+ ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.Size());
+ mir->meta.ifield_lowering_info = def->field_info;
+ } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) {
+ ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.Size());
+ mir->meta.sfield_lowering_info = def->field_info;
+ }
mir->ssa_rep = &ssa_reps_[i];
mir->ssa_rep->num_uses = def->num_uses;
mir->ssa_rep->uses = const_cast<int32_t*>(def->uses); // Not modified by LVN.
@@ -146,7 +179,6 @@ class LocalValueNumberingTest : public testing::Test {
LocalValueNumbering lvn_;
};
-#if 0 // TODO: re-enable when LVN is handling memory igets.
TEST_F(LocalValueNumberingTest, TestIGetIGetInvokeIGet) {
static const IFieldDef ifields[] = {
{ 1u, 1u, 1u, false }
@@ -169,7 +201,6 @@ TEST_F(LocalValueNumberingTest, TestIGetIGetInvokeIGet) {
EXPECT_EQ(mirs_[2].optimization_flags, 0u);
EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
}
-#endif
TEST_F(LocalValueNumberingTest, TestIGetIPutIGetIGetIGet) {
static const IFieldDef ifields[] = {
@@ -197,7 +228,6 @@ TEST_F(LocalValueNumberingTest, TestIGetIPutIGetIGetIGet) {
EXPECT_EQ(mirs_[4].optimization_flags, 0u);
}
-#if 0 // TODO: re-enable when LVN is handling memory igets.
TEST_F(LocalValueNumberingTest, TestUniquePreserve1) {
static const IFieldDef ifields[] = {
{ 1u, 1u, 1u, false },
@@ -218,9 +248,7 @@ TEST_F(LocalValueNumberingTest, TestUniquePreserve1) {
EXPECT_EQ(mirs_[2].optimization_flags, 0u);
EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
}
-#endif
-#if 0 // TODO: re-enable when LVN is handling memory igets.
TEST_F(LocalValueNumberingTest, TestUniquePreserve2) {
static const IFieldDef ifields[] = {
{ 1u, 1u, 1u, false },
@@ -241,9 +269,7 @@ TEST_F(LocalValueNumberingTest, TestUniquePreserve2) {
EXPECT_EQ(mirs_[2].optimization_flags, MIR_IGNORE_NULL_CHECK);
EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
}
-#endif
-#if 0 // TODO: re-enable when LVN is handling memory igets.
TEST_F(LocalValueNumberingTest, TestUniquePreserveAndEscape) {
static const IFieldDef ifields[] = {
{ 1u, 1u, 1u, false },
@@ -267,7 +293,6 @@ TEST_F(LocalValueNumberingTest, TestUniquePreserveAndEscape) {
EXPECT_EQ(mirs_[3].optimization_flags, MIR_IGNORE_NULL_CHECK);
EXPECT_EQ(mirs_[5].optimization_flags, MIR_IGNORE_NULL_CHECK);
}
-#endif
TEST_F(LocalValueNumberingTest, TestVolatile) {
static const IFieldDef ifields[] = {
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index 7ce8f696be..d159f49b3e 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -14,11 +14,15 @@
* limitations under the License.
*/
+#include <algorithm>
#include "compiler_internals.h"
#include "dataflow_iterator-inl.h"
+#include "dex_instruction.h"
+#include "dex_instruction-inl.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_options.h"
+#include "UniquePtr.h"
namespace art {
@@ -1004,6 +1008,11 @@ bool MIRGraph::SkipCompilation() {
return false;
}
+ // Contains a pattern we don't want to compile?
+ if (punt_to_interpreter_) {
+ return true;
+ }
+
if (compiler_filter == CompilerOptions::kInterpretOnly) {
LOG(WARNING) << "InterpretOnly should ideally be filtered out prior to parsing.";
return true;
@@ -1085,4 +1094,109 @@ bool MIRGraph::SkipCompilation() {
return ComputeSkipCompilation(&stats, skip_compilation);
}
+void MIRGraph::DoCacheFieldLoweringInfo() {
+ // Try to use stack-allocated array, resort to heap if we exceed the initial size.
+ static constexpr size_t kInitialSize = 32;
+ uint16_t stack_idxs[kInitialSize];
+ UniquePtr<uint16_t[]> allocated_idxs;
+ uint16_t* field_idxs = stack_idxs;
+ size_t size = kInitialSize;
+
+ // Find IGET/IPUT/SGET/SPUT insns, store IGET/IPUT fields at the beginning, SGET/SPUT at the end.
+ size_t ifield_pos = 0u;
+ size_t sfield_pos = size;
+ AllNodesIterator iter(this);
+ for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) {
+ if (bb->block_type != kDalvikByteCode) {
+ continue;
+ }
+ for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) {
+ if (mir->dalvikInsn.opcode >= Instruction::IGET &&
+ mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) {
+ bool need_alloc = false;
+ const Instruction* insn = Instruction::At(current_code_item_->insns_ + mir->offset);
+ uint16_t field_idx;
+ // Get field index and try to find it among existing indexes. If found, it's usually among
+ // the last few added, so we'll start the search from ifield_pos/sfield_pos. Though this
+ // is a linear search, it actually performs much better than map based approach.
+ if (mir->dalvikInsn.opcode <= Instruction::IPUT_SHORT) {
+ field_idx = insn->VRegC_22c();
+ size_t i = ifield_pos;
+ while (i != 0u && field_idxs[i - 1] != field_idx) {
+ --i;
+ }
+ if (i != 0u) {
+ mir->meta.ifield_lowering_info = i - 1;
+ } else {
+ mir->meta.ifield_lowering_info = ifield_pos;
+ if (UNLIKELY(ifield_pos == sfield_pos)) {
+ need_alloc = true;
+ } else {
+ field_idxs[ifield_pos++] = field_idx;
+ }
+ }
+ } else {
+ field_idx = insn->VRegB_21c();
+ size_t i = sfield_pos;
+ while (i != size && field_idxs[i] != field_idx) {
+ ++i;
+ }
+ if (i != size) {
+ mir->meta.sfield_lowering_info = size - i - 1u;
+ } else {
+ mir->meta.sfield_lowering_info = size - sfield_pos;
+ if (UNLIKELY(ifield_pos == sfield_pos)) {
+ need_alloc = true;
+ } else {
+ field_idxs[--sfield_pos] = field_idx;
+ }
+ }
+ }
+ if (UNLIKELY(need_alloc)) {
+ DCHECK(field_idxs == stack_idxs);
+ // All IGET/IPUT/SGET/SPUT instructions take 2 code units and there must also be a RETURN.
+ uint32_t max_refs = (current_code_item_->insns_size_in_code_units_ - 1u) / 2u;
+ allocated_idxs.reset(new uint16_t[max_refs]);
+ field_idxs = allocated_idxs.get();
+ size_t sfield_count = size - sfield_pos;
+ sfield_pos = max_refs - sfield_count;
+ size = max_refs;
+ memcpy(field_idxs, stack_idxs, ifield_pos * sizeof(field_idxs[0]));
+ memcpy(field_idxs + sfield_pos, stack_idxs + ifield_pos,
+ sfield_count * sizeof(field_idxs[0]));
+ if (mir->dalvikInsn.opcode <= Instruction::IPUT_SHORT) {
+ field_idxs[ifield_pos++] = field_idx;
+ } else {
+ field_idxs[--sfield_pos] = field_idx;
+ }
+ }
+ DCHECK_LE(ifield_pos, sfield_pos);
+ }
+ }
+ }
+
+ if (ifield_pos != 0u) {
+ // Resolve instance field infos.
+ DCHECK_EQ(ifield_lowering_infos_.Size(), 0u);
+ ifield_lowering_infos_.Resize(ifield_pos);
+ for (size_t pos = 0u; pos != ifield_pos; ++pos) {
+ ifield_lowering_infos_.Insert(MirIFieldLoweringInfo(field_idxs[pos]));
+ }
+ MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(),
+ ifield_lowering_infos_.GetRawStorage(), ifield_pos);
+ }
+
+ if (sfield_pos != size) {
+ // Resolve static field infos.
+ DCHECK_EQ(sfield_lowering_infos_.Size(), 0u);
+ sfield_lowering_infos_.Resize(size - sfield_pos);
+ for (size_t pos = size; pos != sfield_pos;) {
+ --pos;
+ sfield_lowering_infos_.Insert(MirSFieldLoweringInfo(field_idxs[pos]));
+ }
+ MirSFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(),
+ sfield_lowering_infos_.GetRawStorage(), size - sfield_pos);
+ }
+}
+
} // namespace art
diff --git a/compiler/dex/mir_field_info.cc b/compiler/dex/mir_field_info.cc
new file mode 100644
index 0000000000..96eda01d1e
--- /dev/null
+++ b/compiler/dex/mir_field_info.cc
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include "mir_field_info.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "driver/compiler_driver.h"
+#include "driver/compiler_driver-inl.h"
+#include "mirror/class_loader.h" // Only to allow casts in SirtRef<ClassLoader>.
+#include "mirror/dex_cache.h" // Only to allow casts in SirtRef<DexCache>.
+#include "scoped_thread_state_change.h"
+#include "sirt_ref.h"
+
+namespace art {
+
+void MirIFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver,
+ const DexCompilationUnit* mUnit,
+ MirIFieldLoweringInfo* field_infos, size_t count) {
+ if (kIsDebugBuild) {
+ DCHECK(field_infos != nullptr);
+ DCHECK_NE(count, 0u);
+ for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
+ MirIFieldLoweringInfo unresolved(it->field_idx_);
+ DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0);
+ }
+ }
+
+ // We're going to resolve fields and check access in a tight loop. It's better to hold
+ // the lock and needed references once than re-acquiring them again and again.
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::DexCache> dex_cache(soa.Self(), compiler_driver->GetDexCache(mUnit));
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+ compiler_driver->GetClassLoader(soa, mUnit));
+ SirtRef<mirror::Class> referrer_class(soa.Self(),
+ compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit));
+ // Even if the referrer class is unresolved (i.e. we're compiling a method without class
+ // definition) we still want to resolve fields and record all available info.
+
+ for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
+ uint32_t field_idx = it->field_idx_;
+ mirror::ArtField* resolved_field =
+ compiler_driver->ResolveField(soa, dex_cache, class_loader, mUnit, field_idx, false);
+ if (UNLIKELY(resolved_field == nullptr)) {
+ continue;
+ }
+ compiler_driver->GetResolvedFieldDexFileLocation(resolved_field,
+ &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_field_idx_);
+ bool is_volatile = compiler_driver->IsFieldVolatile(resolved_field);
+
+ std::pair<bool, bool> fast_path = compiler_driver->IsFastInstanceField(
+ dex_cache.get(), referrer_class.get(), resolved_field, field_idx, &it->field_offset_);
+ it->flags_ = 0u | // Without kFlagIsStatic.
+ (is_volatile ? kFlagIsVolatile : 0u) |
+ (fast_path.first ? kFlagFastGet : 0u) |
+ (fast_path.second ? kFlagFastPut : 0u);
+ }
+}
+
+void MirSFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver,
+ const DexCompilationUnit* mUnit,
+ MirSFieldLoweringInfo* field_infos, size_t count) {
+ if (kIsDebugBuild) {
+ DCHECK(field_infos != nullptr);
+ DCHECK_NE(count, 0u);
+ for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
+ MirSFieldLoweringInfo unresolved(it->field_idx_);
+ // In 64-bit builds, there's padding after storage_index_, don't include it in memcmp.
+ size_t size = OFFSETOF_MEMBER(MirSFieldLoweringInfo, storage_index_) +
+ sizeof(it->storage_index_);
+ DCHECK_EQ(memcmp(&unresolved, &*it, size), 0);
+ }
+ }
+
+ // We're going to resolve fields and check access in a tight loop. It's better to hold
+ // the lock and needed references once than re-acquiring them again and again.
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::DexCache> dex_cache(soa.Self(), compiler_driver->GetDexCache(mUnit));
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+ compiler_driver->GetClassLoader(soa, mUnit));
+ SirtRef<mirror::Class> referrer_class(soa.Self(),
+ compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit));
+ // Even if the referrer class is unresolved (i.e. we're compiling a method without class
+ // definition) we still want to resolve fields and record all available info.
+
+ for (auto it = field_infos, end = field_infos + count; it != end; ++it) {
+ uint32_t field_idx = it->field_idx_;
+ mirror::ArtField* resolved_field =
+ compiler_driver->ResolveField(soa, dex_cache, class_loader, mUnit, field_idx, true);
+ if (UNLIKELY(resolved_field == nullptr)) {
+ continue;
+ }
+ compiler_driver->GetResolvedFieldDexFileLocation(resolved_field,
+ &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_field_idx_);
+ bool is_volatile = compiler_driver->IsFieldVolatile(resolved_field) ? 1u : 0u;
+
+ bool is_referrers_class, is_initialized;
+ std::pair<bool, bool> fast_path = compiler_driver->IsFastStaticField(
+ dex_cache.get(), referrer_class.get(), resolved_field, field_idx, &it->field_offset_,
+ &it->storage_index_, &is_referrers_class, &is_initialized);
+ it->flags_ = kFlagIsStatic |
+ (is_volatile ? kFlagIsVolatile : 0u) |
+ (fast_path.first ? kFlagFastGet : 0u) |
+ (fast_path.second ? kFlagFastPut : 0u) |
+ (is_referrers_class ? kFlagIsReferrersClass : 0u) |
+ (is_initialized ? kFlagIsInitialized : 0u);
+ }
+}
+
+} // namespace art
diff --git a/compiler/dex/mir_field_info.h b/compiler/dex/mir_field_info.h
new file mode 100644
index 0000000000..41cb4cee14
--- /dev/null
+++ b/compiler/dex/mir_field_info.h
@@ -0,0 +1,211 @@
+/*
+ * 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_COMPILER_DEX_MIR_FIELD_INFO_H_
+#define ART_COMPILER_DEX_MIR_FIELD_INFO_H_
+
+#include "base/macros.h"
+#include "dex_file.h"
+#include "offsets.h"
+
+namespace art {
+
+class CompilerDriver;
+class DexCompilationUnit;
+
+/*
+ * Field info is calculated from the perspective of the compilation unit that accesses
+ * the field and stored in that unit's MIRGraph. Therefore it does not need to reference the
+ * dex file or method for which it has been calculated. However, we do store the declaring
+ * field index, class index and dex file of the resolved field to help distinguish between fields.
+ */
+
+class MirFieldInfo {
+ public:
+ uint16_t FieldIndex() const {
+ return field_idx_;
+ }
+
+ bool IsStatic() const {
+ return (flags_ & kFlagIsStatic) != 0u;
+ }
+
+ bool IsResolved() const {
+ return declaring_dex_file_ != nullptr;
+ }
+
+ const DexFile* DeclaringDexFile() const {
+ return declaring_dex_file_;
+ }
+
+ uint16_t DeclaringClassIndex() const {
+ return declaring_class_idx_;
+ }
+
+ uint16_t DeclaringFieldIndex() const {
+ return declaring_field_idx_;
+ }
+
+ bool IsVolatile() const {
+ return (flags_ & kFlagIsVolatile) != 0u;
+ }
+
+ protected:
+ enum {
+ kBitIsStatic = 0,
+ kBitIsVolatile,
+ kFieldInfoBitEnd
+ };
+ static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile;
+ static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic;
+
+ MirFieldInfo(uint16_t field_idx, uint16_t flags)
+ : field_idx_(field_idx),
+ flags_(flags),
+ declaring_field_idx_(0u),
+ declaring_class_idx_(0u),
+ declaring_dex_file_(nullptr) {
+ }
+
+ // Make copy-ctor/assign/dtor protected to avoid slicing.
+ MirFieldInfo(const MirFieldInfo& other) = default;
+ MirFieldInfo& operator=(const MirFieldInfo& other) = default;
+ ~MirFieldInfo() = default;
+
+ // The field index in the compiling method's dex file.
+ uint16_t field_idx_;
+ // Flags, for volatility and derived class data.
+ uint16_t flags_;
+ // The field index in the dex file that defines field, 0 if unresolved.
+ uint16_t declaring_field_idx_;
+ // The type index of the class declaring the field, 0 if unresolved.
+ uint16_t declaring_class_idx_;
+ // The dex file that defines the class containing the field and the field, nullptr if unresolved.
+ const DexFile* declaring_dex_file_;
+};
+
+class MirIFieldLoweringInfo : public MirFieldInfo {
+ public:
+ // For each requested instance field retrieve the field's declaring location (dex file, class
+ // index and field index) and volatility and compute the whether we can fast path the access
+ // with IGET/IPUT. For fast path fields, retrieve the field offset.
+ static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit,
+ MirIFieldLoweringInfo* field_infos, size_t count)
+ LOCKS_EXCLUDED(Locks::mutator_lock_);
+
+ // Construct an unresolved instance field lowering info.
+ explicit MirIFieldLoweringInfo(uint16_t field_idx)
+ : MirFieldInfo(field_idx, kFlagIsVolatile), // Without kFlagIsStatic.
+ field_offset_(0u) {
+ }
+
+ bool FastGet() const {
+ return (flags_ & kFlagFastGet) != 0u;
+ }
+
+ bool FastPut() const {
+ return (flags_ & kFlagFastPut) != 0u;
+ }
+
+ MemberOffset FieldOffset() const {
+ return field_offset_;
+ }
+
+ private:
+ enum {
+ kBitFastGet = kFieldInfoBitEnd,
+ kBitFastPut,
+ kIFieldLoweringInfoBitEnd
+ };
+ COMPILE_ASSERT(kIFieldLoweringInfoBitEnd <= 16, too_many_flags);
+ static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet;
+ static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut;
+
+ // The member offset of the field, 0u if unresolved.
+ MemberOffset field_offset_;
+
+ friend class LocalValueNumberingTest;
+};
+
+class MirSFieldLoweringInfo : public MirFieldInfo {
+ public:
+ // For each requested static field retrieve the field's declaring location (dex file, class
+ // index and field index) and volatility and compute the whether we can fast path the access with
+ // IGET/IPUT. For fast path fields (at least for IGET), retrieve the information needed for
+ // the field access, i.e. the field offset, whether the field is in the same class as the
+ // method being compiled, whether the declaring class can be safely assumed to be initialized
+ // and the type index of the declaring class in the compiled method's dex file.
+ static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit,
+ MirSFieldLoweringInfo* field_infos, size_t count)
+ LOCKS_EXCLUDED(Locks::mutator_lock_);
+
+ // Construct an unresolved static field lowering info.
+ explicit MirSFieldLoweringInfo(uint16_t field_idx)
+ : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic),
+ field_offset_(0u),
+ storage_index_(DexFile::kDexNoIndex) {
+ }
+
+ bool FastGet() const {
+ return (flags_ & kFlagFastGet) != 0u;
+ }
+
+ bool FastPut() const {
+ return (flags_ & kFlagFastPut) != 0u;
+ }
+
+ bool IsReferrersClass() const {
+ return (flags_ & kFlagIsReferrersClass) != 0u;
+ }
+
+ bool IsInitialized() const {
+ return (flags_ & kFlagIsInitialized) != 0u;
+ }
+
+ MemberOffset FieldOffset() const {
+ return field_offset_;
+ }
+
+ uint32_t StorageIndex() const {
+ return storage_index_;
+ }
+
+ private:
+ enum {
+ kBitFastGet = kFieldInfoBitEnd,
+ kBitFastPut,
+ kBitIsReferrersClass,
+ kBitIsInitialized,
+ kSFieldLoweringInfoBitEnd
+ };
+ COMPILE_ASSERT(kSFieldLoweringInfoBitEnd <= 16, too_many_flags);
+ static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet;
+ static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut;
+ static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass;
+ static constexpr uint16_t kFlagIsInitialized = 1u << kBitIsInitialized;
+
+ // The member offset of the field, 0u if unresolved.
+ MemberOffset field_offset_;
+ // The type index of the declaring class in the compiling method's dex file,
+ // -1 if the field is unresolved or there's no appropriate TypeId in that dex file.
+ uint32_t storage_index_;
+
+ friend class LocalValueNumberingTest;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_MIR_FIELD_INFO_H_
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index e4550d1e60..46e854fb2b 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -86,7 +86,10 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena)
forward_branches_(0),
compiler_temps_(arena, 6, kGrowableArrayMisc),
num_non_special_compiler_temps_(0),
- max_available_non_special_compiler_temps_(0) {
+ max_available_non_special_compiler_temps_(0),
+ punt_to_interpreter_(false),
+ ifield_lowering_infos_(arena, 0u),
+ sfield_lowering_infos_(arena, 0u) {
try_block_addr_ = new (arena_) ArenaBitVector(arena_, 0, true /* expandable */);
max_available_special_compiler_temps_ = std::abs(static_cast<int>(kVRegNonSpecialTempBaseReg))
- std::abs(static_cast<int>(kVRegTempBaseReg));
@@ -610,6 +613,7 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_
}
int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
+ int verify_flags = Instruction::VerifyFlagsOf(insn->dalvikInsn.opcode);
uint64_t df_flags = oat_data_flow_attributes_[insn->dalvikInsn.opcode];
@@ -676,6 +680,19 @@ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_
} else if (flags & Instruction::kSwitch) {
cur_block = ProcessCanSwitch(cur_block, insn, current_offset_, width, flags);
}
+ if (verify_flags & Instruction::kVerifyVarArgRange) {
+ /*
+ * The Quick backend's runtime model includes a gap between a method's
+ * argument ("in") vregs and the rest of its vregs. Handling a range instruction
+ * which spans the gap is somewhat complicated, and should not happen
+ * in normal usage of dx. Punt to the interpreter.
+ */
+ int first_reg_in_range = insn->dalvikInsn.vC;
+ int last_reg_in_range = first_reg_in_range + insn->dalvikInsn.vA - 1;
+ if (IsInVReg(first_reg_in_range) != IsInVReg(last_reg_in_range)) {
+ punt_to_interpreter_ = true;
+ }
+ }
current_offset_ += width;
BasicBlock *next_block = FindBlock(current_offset_, /* split */ false, /* create */
false, /* immed_pred_block_p */ NULL);
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 2174f679bf..d4aafbc0f4 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -20,7 +20,9 @@
#include "dex_file.h"
#include "dex_instruction.h"
#include "compiler_ir.h"
-#include "arena_bit_vector.h"
+#include "mir_field_info.h"
+#include "invoke_type.h"
+#include "utils/arena_bit_vector.h"
#include "utils/growable_array.h"
namespace art {
@@ -258,6 +260,12 @@ struct MIR {
MIR* throw_insn;
// Fused cmp branch condition.
ConditionCode ccode;
+ // IGET/IPUT lowering info index, points to MIRGraph::ifield_lowering_infos_. Due to limit on
+ // the number of code points (64K) and size of IGET/IPUT insn (2), this will never exceed 32K.
+ uint32_t ifield_lowering_info;
+ // SGET/SPUT lowering info index, points to MIRGraph::sfield_lowering_infos_. Due to limit on
+ // the number of code points (64K) and size of SGET/SPUT insn (2), this will never exceed 32K.
+ uint32_t sfield_lowering_info;
} meta;
};
@@ -466,6 +474,18 @@ class MIRGraph {
*/
void DumpCFG(const char* dir_prefix, bool all_blocks, const char* suffix = nullptr);
+ void DoCacheFieldLoweringInfo();
+
+ const MirIFieldLoweringInfo& GetIFieldLoweringInfo(MIR* mir) {
+ DCHECK_LT(mir->meta.ifield_lowering_info, ifield_lowering_infos_.Size());
+ return ifield_lowering_infos_.GetRawStorage()[mir->meta.ifield_lowering_info];
+ }
+
+ const MirSFieldLoweringInfo& GetSFieldLoweringInfo(MIR* mir) {
+ DCHECK_LT(mir->meta.sfield_lowering_info, sfield_lowering_infos_.Size());
+ return sfield_lowering_infos_.GetRawStorage()[mir->meta.sfield_lowering_info];
+ }
+
void InitRegLocations();
void RemapRegLocations();
@@ -684,6 +704,11 @@ class MIRGraph {
return opcode >= static_cast<int>(kMirOpFirst);
}
+ // Is this vreg in the in set?
+ bool IsInVReg(int vreg) {
+ return (vreg >= cu_->num_regs);
+ }
+
void DumpCheckStats();
MIR* FindMoveResult(BasicBlock* bb, MIR* mir);
int SRegToVReg(int ssa_reg) const;
@@ -917,6 +942,9 @@ class MIRGraph {
size_t num_non_special_compiler_temps_;
size_t max_available_non_special_compiler_temps_;
size_t max_available_special_compiler_temps_;
+ bool punt_to_interpreter_; // Difficult or not worthwhile - just interpret.
+ GrowableArray<MirIFieldLoweringInfo> ifield_lowering_infos_;
+ GrowableArray<MirSFieldLoweringInfo> sfield_lowering_infos_;
friend class LocalValueNumberingTest;
};
diff --git a/compiler/dex/pass.h b/compiler/dex/pass.h
index 255892e324..9457d5be76 100644
--- a/compiler/dex/pass.h
+++ b/compiler/dex/pass.h
@@ -22,8 +22,8 @@
namespace art {
// Forward declarations.
-class BasicBlock;
-class CompilationUnit;
+struct BasicBlock;
+struct CompilationUnit;
class Pass;
/**
diff --git a/compiler/dex/pass_driver.cc b/compiler/dex/pass_driver.cc
index b60f29697b..256bcb1473 100644
--- a/compiler/dex/pass_driver.cc
+++ b/compiler/dex/pass_driver.cc
@@ -91,6 +91,7 @@ void PassDriver::CreatePasses() {
* - This is not yet an issue: no current pass would require it.
*/
static const Pass* const passes[] = {
+ GetPassInstance<CacheFieldLoweringInfo>(),
GetPassInstance<CodeLayout>(),
GetPassInstance<SSATransformation>(),
GetPassInstance<ConstantPropagation>(),
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 3187fbb28c..70438ecd50 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -30,6 +30,7 @@
#include "dex/compiler_internals.h"
#include "dex/dataflow_iterator-inl.h"
#include "dex/frontend.h"
+#include "llvm/ir_builder.h"
#include "llvm/llvm_compilation_unit.h"
#include "llvm/utils_llvm.h"
#include "mir_to_gbc.h"
diff --git a/compiler/dex/portable/mir_to_gbc.h b/compiler/dex/portable/mir_to_gbc.h
index 2b681f6097..e97634c519 100644
--- a/compiler/dex/portable/mir_to_gbc.h
+++ b/compiler/dex/portable/mir_to_gbc.h
@@ -17,11 +17,18 @@
#ifndef ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
#define ART_COMPILER_DEX_PORTABLE_MIR_TO_GBC_H_
+#include <llvm/ADT/ArrayRef.h>
+#include <llvm/IR/BasicBlock.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+
#include "invoke_type.h"
#include "compiled_method.h"
#include "dex/compiler_enums.h"
#include "dex/compiler_ir.h"
#include "dex/backend.h"
+#include "llvm/intrinsic_helper.h"
#include "llvm/llvm_compilation_unit.h"
#include "safe_map.h"
diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h
index 37b4ec6dc7..7aab55ffc4 100644
--- a/compiler/dex/quick/arm/arm_lir.h
+++ b/compiler/dex/quick/arm/arm_lir.h
@@ -451,7 +451,6 @@ enum ArmOpcode {
kThumb2MovImm16LST, // Special purpose version for switch table use.
kThumb2MovImm16HST, // Special purpose version for switch table use.
kThumb2LdmiaWB, // ldmia [111010011001[ rn[19..16] mask[15..0].
- kThumb2SubsRRI12, // setflags encoding.
kThumb2OrrRRRs, // orrs [111010100101] rn[19..16] [0000] rd[11..8] [0000] rm[3..0].
kThumb2Push1, // t3 encoding of push.
kThumb2Pop1, // t3 encoding of pop.
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index 00939ec98b..2a9b5a50e2 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -995,11 +995,6 @@ const ArmEncodingMap ArmMir2Lir::EncodingMap[kArmLast] = {
kFmtUnused, -1, -1,
IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1 | IS_LOAD,
"ldmia", "!0C!!, <!1R>", 4, kFixupNone),
- ENCODING_MAP(kThumb2SubsRRI12, 0xf1b00000,
- kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
- kFmtUnused, -1, -1,
- IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
- "subs", "!0C,!1C,#!2d", 4, kFixupNone),
ENCODING_MAP(kThumb2OrrRRRs, 0xea500000,
kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index b36dde98b2..9f75422a49 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -85,7 +85,8 @@ void ArmMir2Lir::GenSparseSwitch(MIR* mir, uint32_t table_offset,
LIR* switch_branch = NewLIR1(kThumb2AddPCR, r_disp);
tab_rec->anchor = switch_branch;
// Needs to use setflags encoding here
- NewLIR3(kThumb2SubsRRI12, r_idx, r_idx, 1);
+ OpRegRegImm(kOpSub, r_idx, r_idx, 1); // For value == 1, this should set flags.
+ DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
OpCondBranch(kCondNe, target);
}
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 43928fc5e2..1e290ad302 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -753,7 +753,8 @@ LIR* ArmMir2Lir::OpTestSuspend(LIR* target) {
// Decrement register and branch on condition
LIR* ArmMir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) {
// Combine sub & test using sub setflags encoding here
- NewLIR3(kThumb2SubsRRI12, reg, reg, 1);
+ OpRegRegImm(kOpSub, reg, reg, 1); // For value == 1, this should set flags.
+ DCHECK(last_lir_insn_->u.m.def_mask & ENCODE_CCODE);
return OpCondBranch(c_code, target);
}
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 9d3968bff2..c2cfb4dbc1 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -499,12 +499,6 @@ LIR* ArmMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) {
else
opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
return NewLIR3(opcode, r_dest, r_src1, abs_value);
- } else if ((abs_value & 0x3ff) == abs_value) {
- if (op == kOpAdd)
- opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
- else
- opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
- return NewLIR3(opcode, r_dest, r_src1, abs_value);
}
if (mod_imm < 0) {
mod_imm = ModifiedImmediate(-value);
@@ -512,6 +506,15 @@ LIR* ArmMir2Lir::OpRegRegImm(OpKind op, int r_dest, int r_src1, int value) {
op = (op == kOpAdd) ? kOpSub : kOpAdd;
}
}
+ if (mod_imm < 0 && (abs_value & 0x3ff) == abs_value) {
+ // This is deliberately used only if modified immediate encoding is inadequate since
+ // we sometimes actually use the flags for small values but not necessarily low regs.
+ if (op == kOpAdd)
+ opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
+ else
+ opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
+ return NewLIR3(opcode, r_dest, r_src1, abs_value);
+ }
if (op == kOpSub) {
opcode = kThumb2SubRRI8M;
alt_opcode = kThumb2SubRRR;
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 31854496ab..db7bdc84e8 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -78,11 +78,6 @@ void Mir2Lir::MarkSafepointPC(LIR* inst) {
DCHECK_EQ(safepoint_pc->u.m.def_mask, ENCODE_ALL);
}
-bool Mir2Lir::FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile) {
- return cu_->compiler_driver->ComputeInstanceFieldInfo(
- field_idx, mir_graph_->GetCurrentDexCompilationUnit(), is_put, field_offset, is_volatile);
-}
-
/* Remove a LIR from the list. */
void Mir2Lir::UnlinkLIR(LIR* lir) {
if (UNLIKELY(lir == first_lir_insn_)) {
@@ -1070,10 +1065,12 @@ CompiledMethod* Mir2Lir::GetCompiledMethod() {
DCHECK_EQ(fp_vmap_table_.size(), 0u);
vmap_encoder.PushBackUnsigned(0u); // Size is 0.
}
+
+ UniquePtr<std::vector<uint8_t> > cfi_info(ReturnCallFrameInformation());
CompiledMethod* result =
new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
- vmap_encoder.GetData(), native_gc_map_);
+ vmap_encoder.GetData(), native_gc_map_, cfi_info.get());
return result;
}
@@ -1216,4 +1213,9 @@ void Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_re
AppendLIR(load_pc_rel);
}
+std::vector<uint8_t>* Mir2Lir::ReturnCallFrameInformation() {
+ // Default case is to do nothing.
+ return nullptr;
+}
+
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 3dcb964fab..b4d8dd6009 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -31,7 +31,7 @@ namespace verifier {
class MethodVerifier;
} // namespace verifier
-class CallInfo;
+struct CallInfo;
class Mir2Lir;
enum InlineMethodOpcode : uint16_t {
@@ -61,6 +61,7 @@ enum InlineMethodOpcode : uint16_t {
kInlineOpIGet,
kInlineOpIPut,
};
+std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
enum InlineMethodFlags : uint16_t {
kNoInlineMethodFlags = 0x0000,
@@ -78,13 +79,13 @@ enum IntrinsicFlags {
// kIntrinsicIsEmptyOrLength
kIntrinsicFlagLength = kIntrinsicFlagNone,
- kIntrinsicFlagIsEmpty = 1,
+ kIntrinsicFlagIsEmpty = kIntrinsicFlagMin,
// kIntrinsicIndexOf
- kIntrinsicFlagBase0 = 1,
+ kIntrinsicFlagBase0 = kIntrinsicFlagMin,
// kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas
- kIntrinsicFlagIsLong = 1,
+ kIntrinsicFlagIsLong = kIntrinsicFlagMin,
// kIntrinsicUnsafeGet, kIntrinsicUnsafePut
kIntrinsicFlagIsVolatile = 2,
// kIntrinsicUnsafePut, kIntrinsicUnsafeCas
@@ -187,7 +188,6 @@ class DexFileMethodInliner {
*/
bool GenSpecial(Mir2Lir* backend, uint32_t method_idx);
- private:
/**
* To avoid multiple lookups of a class by its descriptor, we cache its
* type index in the IndexCache. These are the indexes into the IndexCache
@@ -311,6 +311,7 @@ class DexFileMethodInliner {
kProtoCacheLast
};
+ private:
/**
* The maximum number of method parameters we support in the ProtoDef.
*/
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 0533fbfcd7..49e3c6f2cc 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -381,20 +381,14 @@ class StaticFieldSlowPath : public Mir2Lir::LIRSlowPath {
const int r_base_;
};
-void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_double,
+void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, bool is_long_or_double,
bool is_object) {
- int field_offset;
- int storage_index;
- bool is_volatile;
- bool is_referrers_class;
- bool is_initialized;
- bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo(
- field_idx, mir_graph_->GetCurrentDexCompilationUnit(), true,
- &field_offset, &storage_index, &is_referrers_class, &is_volatile, &is_initialized);
- if (fast_path && !SLOW_FIELD_PATH) {
- DCHECK_GE(field_offset, 0);
+ const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
+ cu_->compiler_driver->ProcessedStaticField(field_info.FastPut(), field_info.IsReferrersClass());
+ if (field_info.FastPut() && !SLOW_FIELD_PATH) {
+ DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
int r_base;
- if (is_referrers_class) {
+ if (field_info.IsReferrersClass()) {
// Fast path, static storage base is this method's class
RegLocation rl_method = LoadCurrMethod();
r_base = AllocTemp();
@@ -407,7 +401,7 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do
// Medium path, static storage base in a different class which requires checks that the other
// class is initialized.
// TODO: remove initialized check now that we are initializing classes in the compiler driver.
- DCHECK_GE(storage_index, 0);
+ DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex);
// May do runtime call so everything to home locations.
FlushAllRegs();
// Using fixed register to sync with possible call to runtime support.
@@ -420,9 +414,9 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do
mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
r_base);
LoadWordDisp(r_base, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
- sizeof(int32_t*) * storage_index, r_base);
+ sizeof(int32_t*) * field_info.StorageIndex(), r_base);
// r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
- if (!is_initialized) {
+ if (!field_info.IsInitialized()) {
// Check if r_base is NULL or a not yet initialized class.
// The slow path is invoked if the r_base is NULL or the class pointed
@@ -437,7 +431,7 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do
AddSlowPath(new (arena_) StaticFieldSlowPath(this,
unresolved_branch, uninit_branch, cont,
- storage_index, r_base));
+ field_info.StorageIndex(), r_base));
FreeTemp(r_tmp);
}
@@ -449,16 +443,16 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do
} else {
rl_src = LoadValue(rl_src, kAnyReg);
}
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kStoreStore);
}
if (is_long_or_double) {
- StoreBaseDispWide(r_base, field_offset, rl_src.low_reg,
+ StoreBaseDispWide(r_base, field_info.FieldOffset().Int32Value(), rl_src.low_reg,
rl_src.high_reg);
} else {
- StoreWordDisp(r_base, field_offset, rl_src.low_reg);
+ StoreWordDisp(r_base, field_info.FieldOffset().Int32Value(), rl_src.low_reg);
}
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kStoreLoad);
}
if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
@@ -471,24 +465,18 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do
is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Static)
: (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjStatic)
: QUICK_ENTRYPOINT_OFFSET(pSet32Static));
- CallRuntimeHelperImmRegLocation(setter_offset, field_idx, rl_src, true);
+ CallRuntimeHelperImmRegLocation(setter_offset, field_info.FieldIndex(), rl_src, true);
}
}
-void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
+void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest,
bool is_long_or_double, bool is_object) {
- int field_offset;
- int storage_index;
- bool is_volatile;
- bool is_referrers_class;
- bool is_initialized;
- bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo(
- field_idx, mir_graph_->GetCurrentDexCompilationUnit(), false,
- &field_offset, &storage_index, &is_referrers_class, &is_volatile, &is_initialized);
- if (fast_path && !SLOW_FIELD_PATH) {
- DCHECK_GE(field_offset, 0);
+ const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir);
+ cu_->compiler_driver->ProcessedStaticField(field_info.FastGet(), field_info.IsReferrersClass());
+ if (field_info.FastGet() && !SLOW_FIELD_PATH) {
+ DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
int r_base;
- if (is_referrers_class) {
+ if (field_info.IsReferrersClass()) {
// Fast path, static storage base is this method's class
RegLocation rl_method = LoadCurrMethod();
r_base = AllocTemp();
@@ -497,7 +485,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
} else {
// Medium path, static storage base in a different class which requires checks that the other
// class is initialized
- DCHECK_GE(storage_index, 0);
+ DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex);
// May do runtime call so everything to home locations.
FlushAllRegs();
// Using fixed register to sync with possible call to runtime support.
@@ -510,9 +498,9 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
r_base);
LoadWordDisp(r_base, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
- sizeof(int32_t*) * storage_index, r_base);
+ sizeof(int32_t*) * field_info.StorageIndex(), r_base);
// r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
- if (!is_initialized) {
+ if (!field_info.IsInitialized()) {
// Check if r_base is NULL or a not yet initialized class.
// The slow path is invoked if the r_base is NULL or the class pointed
@@ -527,7 +515,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
AddSlowPath(new (arena_) StaticFieldSlowPath(this,
unresolved_branch, uninit_branch, cont,
- storage_index, r_base));
+ field_info.StorageIndex(), r_base));
FreeTemp(r_tmp);
}
@@ -535,14 +523,14 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
}
// r_base now holds static storage base
RegLocation rl_result = EvalLoc(rl_dest, kAnyReg, true);
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
if (is_long_or_double) {
- LoadBaseDispWide(r_base, field_offset, rl_result.low_reg,
+ LoadBaseDispWide(r_base, field_info.FieldOffset().Int32Value(), rl_result.low_reg,
rl_result.high_reg, INVALID_SREG);
} else {
- LoadWordDisp(r_base, field_offset, rl_result.low_reg);
+ LoadWordDisp(r_base, field_info.FieldOffset().Int32Value(), rl_result.low_reg);
}
FreeTemp(r_base);
if (is_long_or_double) {
@@ -556,7 +544,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest,
is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Static)
:(is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjStatic)
: QUICK_ENTRYPOINT_OFFSET(pGet32Static));
- CallRuntimeHelperImm(getterOffset, field_idx, true);
+ CallRuntimeHelperImm(getterOffset, field_info.FieldIndex(), true);
if (is_long_or_double) {
RegLocation rl_result = GetReturnWide(rl_dest.fp);
StoreValueWide(rl_dest, rl_result);
@@ -698,18 +686,15 @@ void Mir2Lir::HandleThrowLaunchPads() {
}
}
-void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
+void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size,
RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double,
bool is_object) {
- int field_offset;
- bool is_volatile;
-
- bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile);
-
- if (fast_path && !SLOW_FIELD_PATH) {
+ const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
+ cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet());
+ if (field_info.FastGet() && !SLOW_FIELD_PATH) {
RegLocation rl_result;
RegisterClass reg_class = oat_reg_class_by_size(size);
- DCHECK_GE(field_offset, 0);
+ DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
rl_obj = LoadValue(rl_obj, kCoreReg);
if (is_long_or_double) {
DCHECK(rl_dest.wide);
@@ -717,17 +702,17 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
if (cu_->instruction_set == kX86) {
rl_result = EvalLoc(rl_dest, reg_class, true);
GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
- LoadBaseDispWide(rl_obj.low_reg, field_offset, rl_result.low_reg,
+ LoadBaseDispWide(rl_obj.low_reg, field_info.FieldOffset().Int32Value(), rl_result.low_reg,
rl_result.high_reg, rl_obj.s_reg_low);
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
} else {
int reg_ptr = AllocTemp();
- OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
+ OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_info.FieldOffset().Int32Value());
rl_result = EvalLoc(rl_dest, reg_class, true);
LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
FreeTemp(reg_ptr);
@@ -736,9 +721,9 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
} else {
rl_result = EvalLoc(rl_dest, reg_class, true);
GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
- LoadBaseDisp(rl_obj.low_reg, field_offset, rl_result.low_reg,
+ LoadBaseDisp(rl_obj.low_reg, field_info.FieldOffset().Int32Value(), rl_result.low_reg,
kWord, rl_obj.s_reg_low);
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
StoreValue(rl_dest, rl_result);
@@ -748,7 +733,7 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Instance)
: (is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjInstance)
: QUICK_ENTRYPOINT_OFFSET(pGet32Instance));
- CallRuntimeHelperImmRegLocation(getterOffset, field_idx, rl_obj, true);
+ CallRuntimeHelperImmRegLocation(getterOffset, field_info.FieldIndex(), rl_obj, true);
if (is_long_or_double) {
RegLocation rl_result = GetReturnWide(rl_dest.fp);
StoreValueWide(rl_dest, rl_result);
@@ -759,39 +744,37 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
}
}
-void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size,
+void Mir2Lir::GenIPut(MIR* mir, int opt_flags, OpSize size,
RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double,
bool is_object) {
- int field_offset;
- bool is_volatile;
-
- bool fast_path = FastInstance(field_idx, true, &field_offset, &is_volatile);
- if (fast_path && !SLOW_FIELD_PATH) {
+ const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir);
+ cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut());
+ if (field_info.FastPut() && !SLOW_FIELD_PATH) {
RegisterClass reg_class = oat_reg_class_by_size(size);
- DCHECK_GE(field_offset, 0);
+ DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
rl_obj = LoadValue(rl_obj, kCoreReg);
if (is_long_or_double) {
int reg_ptr;
rl_src = LoadValueWide(rl_src, kAnyReg);
GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
reg_ptr = AllocTemp();
- OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
- if (is_volatile) {
+ OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_info.FieldOffset().Int32Value());
+ if (field_info.IsVolatile()) {
GenMemBarrier(kStoreStore);
}
StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
FreeTemp(reg_ptr);
} else {
rl_src = LoadValue(rl_src, reg_class);
GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
- if (is_volatile) {
+ if (field_info.IsVolatile()) {
GenMemBarrier(kStoreStore);
}
- StoreBaseDisp(rl_obj.low_reg, field_offset, rl_src.low_reg, kWord);
- if (is_volatile) {
+ StoreBaseDisp(rl_obj.low_reg, field_info.FieldOffset().Int32Value(), rl_src.low_reg, kWord);
+ if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) {
@@ -803,7 +786,8 @@ void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size,
is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Instance)
: (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjInstance)
: QUICK_ENTRYPOINT_OFFSET(pSet32Instance));
- CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_idx, rl_obj, rl_src, true);
+ CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_info.FieldIndex(),
+ rl_obj, rl_src, true);
}
}
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 8c2ed3667b..00518bdb2f 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -596,72 +596,72 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
break;
case Instruction::IGET_OBJECT:
- GenIGet(vC, opt_flags, kWord, rl_dest, rl_src[0], false, true);
+ GenIGet(mir, opt_flags, kWord, rl_dest, rl_src[0], false, true);
break;
case Instruction::IGET_WIDE:
- GenIGet(vC, opt_flags, kLong, rl_dest, rl_src[0], true, false);
+ GenIGet(mir, opt_flags, kLong, rl_dest, rl_src[0], true, false);
break;
case Instruction::IGET:
- GenIGet(vC, opt_flags, kWord, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kWord, rl_dest, rl_src[0], false, false);
break;
case Instruction::IGET_CHAR:
- GenIGet(vC, opt_flags, kUnsignedHalf, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kUnsignedHalf, rl_dest, rl_src[0], false, false);
break;
case Instruction::IGET_SHORT:
- GenIGet(vC, opt_flags, kSignedHalf, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kSignedHalf, rl_dest, rl_src[0], false, false);
break;
case Instruction::IGET_BOOLEAN:
case Instruction::IGET_BYTE:
- GenIGet(vC, opt_flags, kUnsignedByte, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kUnsignedByte, rl_dest, rl_src[0], false, false);
break;
case Instruction::IPUT_WIDE:
- GenIPut(vC, opt_flags, kLong, rl_src[0], rl_src[1], true, false);
+ GenIPut(mir, opt_flags, kLong, rl_src[0], rl_src[1], true, false);
break;
case Instruction::IPUT_OBJECT:
- GenIPut(vC, opt_flags, kWord, rl_src[0], rl_src[1], false, true);
+ GenIPut(mir, opt_flags, kWord, rl_src[0], rl_src[1], false, true);
break;
case Instruction::IPUT:
- GenIPut(vC, opt_flags, kWord, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, kWord, rl_src[0], rl_src[1], false, false);
break;
case Instruction::IPUT_BOOLEAN:
case Instruction::IPUT_BYTE:
- GenIPut(vC, opt_flags, kUnsignedByte, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, kUnsignedByte, rl_src[0], rl_src[1], false, false);
break;
case Instruction::IPUT_CHAR:
- GenIPut(vC, opt_flags, kUnsignedHalf, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, kUnsignedHalf, rl_src[0], rl_src[1], false, false);
break;
case Instruction::IPUT_SHORT:
- GenIPut(vC, opt_flags, kSignedHalf, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, kSignedHalf, rl_src[0], rl_src[1], false, false);
break;
case Instruction::SGET_OBJECT:
- GenSget(vB, rl_dest, false, true);
+ GenSget(mir, rl_dest, false, true);
break;
case Instruction::SGET:
case Instruction::SGET_BOOLEAN:
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
case Instruction::SGET_SHORT:
- GenSget(vB, rl_dest, false, false);
+ GenSget(mir, rl_dest, false, false);
break;
case Instruction::SGET_WIDE:
- GenSget(vB, rl_dest, true, false);
+ GenSget(mir, rl_dest, true, false);
break;
case Instruction::SPUT_OBJECT:
- GenSput(vB, rl_src[0], false, true);
+ GenSput(mir, rl_src[0], false, true);
break;
case Instruction::SPUT:
@@ -669,11 +669,11 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list
case Instruction::SPUT_BYTE:
case Instruction::SPUT_CHAR:
case Instruction::SPUT_SHORT:
- GenSput(vB, rl_src[0], false, false);
+ GenSput(mir, rl_src[0], false, false);
break;
case Instruction::SPUT_WIDE:
- GenSput(vB, rl_src[0], true, false);
+ GenSput(mir, rl_src[0], true, false);
break;
case Instruction::INVOKE_STATIC_RANGE:
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 6e97c531cd..e230c9d67b 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -23,7 +23,7 @@
#include "dex/compiler_ir.h"
#include "dex/backend.h"
#include "driver/compiler_driver.h"
-#include "leb128_encoder.h"
+#include "leb128.h"
#include "safe_map.h"
#include "utils/arena_allocator.h"
#include "utils/growable_array.h"
@@ -395,7 +395,6 @@ class Mir2Lir : public Backend {
virtual void Materialize();
virtual CompiledMethod* GetCompiledMethod();
void MarkSafepointPC(LIR* inst);
- bool FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile);
void SetupResourceMasks(LIR* lir);
void SetMemRefType(LIR* lir, bool is_load, int mem_type);
void AnnotateDalvikRegAccess(LIR* lir, int reg_id, bool is_load, bool is64bit);
@@ -558,13 +557,13 @@ class Mir2Lir : public Backend {
void GenNewArray(uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src);
void GenFilledNewArray(CallInfo* info);
- void GenSput(uint32_t field_idx, RegLocation rl_src,
+ void GenSput(MIR* mir, RegLocation rl_src,
bool is_long_or_double, bool is_object);
- void GenSget(uint32_t field_idx, RegLocation rl_dest,
+ void GenSget(MIR* mir, RegLocation rl_dest,
bool is_long_or_double, bool is_object);
- void GenIGet(uint32_t field_idx, int opt_flags, OpSize size,
+ void GenIGet(MIR* mir, int opt_flags, OpSize size,
RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double, bool is_object);
- void GenIPut(uint32_t field_idx, int opt_flags, OpSize size,
+ void GenIPut(MIR* mir, int opt_flags, OpSize size,
RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double, bool is_object);
void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
RegLocation rl_src);
@@ -1089,6 +1088,11 @@ class Mir2Lir : public Backend {
bool can_assume_type_is_in_dex_cache,
uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src);
+ /*
+ * @brief Generate the debug_frame FDE information if possible.
+ * @returns pointer to vector containg CFE information, or NULL.
+ */
+ virtual std::vector<uint8_t>* ReturnCallFrameInformation();
/**
* @brief Used to insert marker that can be used to associate MIR with LIR.
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 0613cdff7a..399001c397 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -198,7 +198,7 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
LockTemp(rX86_ARG2);
/* Build frame, return address already on stack */
- OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
+ stack_decrement_ = OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
/*
* We can safely skip the stack overflow check if we're
@@ -246,7 +246,7 @@ void X86Mir2Lir::GenExitSequence() {
NewLIR0(kPseudoMethodExit);
UnSpillCoreRegs();
/* Remove frame except for return address */
- OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
+ stack_increment_ = OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4);
NewLIR0(kX86Ret);
}
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 421d51e4fd..c97d0e6f4d 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -302,6 +302,18 @@ class X86Mir2Lir : public Mir2Lir {
*/
void InstallLiteralPools();
+ /*
+ * @brief Generate the debug_frame CFI information.
+ * @returns pointer to vector containing CFE information
+ */
+ static std::vector<uint8_t>* ReturnCommonCallFrameInformation();
+
+ /*
+ * @brief Generate the debug_frame FDE information.
+ * @returns pointer to vector containing CFE information
+ */
+ std::vector<uint8_t>* ReturnCallFrameInformation();
+
private:
void EmitPrefix(const X86EncodingMap* entry);
void EmitOpcode(const X86EncodingMap* entry);
@@ -549,6 +561,12 @@ class X86Mir2Lir : public Mir2Lir {
// Instructions needing patching with PC relative code addresses.
GrowableArray<LIR*> call_method_insns_;
+
+ // Prologue decrement of stack pointer.
+ LIR* stack_decrement_;
+
+ // Epilogue increment of stack pointer.
+ LIR* stack_increment_;
};
} // namespace art
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index eea7191c3b..7bb866d4aa 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -539,7 +539,8 @@ X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator*
: Mir2Lir(cu, mir_graph, arena),
method_address_insns_(arena, 100, kGrowableArrayMisc),
class_type_address_insns_(arena, 100, kGrowableArrayMisc),
- call_method_insns_(arena, 100, kGrowableArrayMisc) {
+ call_method_insns_(arena, 100, kGrowableArrayMisc),
+ stack_decrement_(nullptr), stack_increment_(nullptr) {
store_method_addr_used_ = false;
for (int i = 0; i < kX86Last; i++) {
if (X86Mir2Lir::EncodingMap[i].opcode != i) {
@@ -1118,4 +1119,166 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
return true;
}
+/*
+ * @brief Enter a 32 bit quantity into the FDE buffer
+ * @param buf FDE buffer.
+ * @param data Data value.
+ */
+static void PushWord(std::vector<uint8_t>&buf, int data) {
+ buf.push_back(data & 0xff);
+ buf.push_back((data >> 8) & 0xff);
+ buf.push_back((data >> 16) & 0xff);
+ buf.push_back((data >> 24) & 0xff);
+}
+
+/*
+ * @brief Enter an 'advance LOC' into the FDE buffer
+ * @param buf FDE buffer.
+ * @param increment Amount by which to increase the current location.
+ */
+static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) {
+ if (increment < 64) {
+ // Encoding in opcode.
+ buf.push_back(0x1 << 6 | increment);
+ } else if (increment < 256) {
+ // Single byte delta.
+ buf.push_back(0x02);
+ buf.push_back(increment);
+ } else if (increment < 256 * 256) {
+ // Two byte delta.
+ buf.push_back(0x03);
+ buf.push_back(increment & 0xff);
+ buf.push_back((increment >> 8) & 0xff);
+ } else {
+ // Four byte delta.
+ buf.push_back(0x04);
+ PushWord(buf, increment);
+ }
+}
+
+
+std::vector<uint8_t>* X86CFIInitialization() {
+ return X86Mir2Lir::ReturnCommonCallFrameInformation();
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation() {
+ std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+ // Length of the CIE (except for this field).
+ PushWord(*cfi_info, 16);
+
+ // CIE id.
+ PushWord(*cfi_info, 0xFFFFFFFFU);
+
+ // Version: 3.
+ cfi_info->push_back(0x03);
+
+ // Augmentation: empty string.
+ cfi_info->push_back(0x0);
+
+ // Code alignment: 1.
+ cfi_info->push_back(0x01);
+
+ // Data alignment: -4.
+ cfi_info->push_back(0x7C);
+
+ // Return address register (R8).
+ cfi_info->push_back(0x08);
+
+ // Initial return PC is 4(ESP): DW_CFA_def_cfa R4 4.
+ cfi_info->push_back(0x0C);
+ cfi_info->push_back(0x04);
+ cfi_info->push_back(0x04);
+
+ // Return address location: 0(SP): DW_CFA_offset R8 1 (* -4);.
+ cfi_info->push_back(0x2 << 6 | 0x08);
+ cfi_info->push_back(0x01);
+
+ // And 2 Noops to align to 4 byte boundary.
+ cfi_info->push_back(0x0);
+ cfi_info->push_back(0x0);
+
+ DCHECK_EQ(cfi_info->size() & 3, 0U);
+ return cfi_info;
+}
+
+static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
+ uint8_t buffer[12];
+ uint8_t *ptr = EncodeUnsignedLeb128(buffer, value);
+ for (uint8_t *p = buffer; p < ptr; p++) {
+ buf.push_back(*p);
+ }
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
+ std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+ // Generate the FDE for the method.
+ DCHECK_NE(data_offset_, 0U);
+
+ // Length (will be filled in later in this routine).
+ PushWord(*cfi_info, 0);
+
+ // CIE_pointer (can be filled in by linker); might be left at 0 if there is only
+ // one CIE for the whole debug_frame section.
+ PushWord(*cfi_info, 0);
+
+ // 'initial_location' (filled in by linker).
+ PushWord(*cfi_info, 0);
+
+ // 'address_range' (number of bytes in the method).
+ PushWord(*cfi_info, data_offset_);
+
+ // The instructions in the FDE.
+ if (stack_decrement_ != nullptr) {
+ // Advance LOC to just past the stack decrement.
+ uint32_t pc = NEXT_LIR(stack_decrement_)->offset;
+ AdvanceLoc(*cfi_info, pc);
+
+ // Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size.
+ cfi_info->push_back(0x0e);
+ EncodeUnsignedLeb128(*cfi_info, frame_size_);
+
+ // We continue with that stack until the epilogue.
+ if (stack_increment_ != nullptr) {
+ uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
+ AdvanceLoc(*cfi_info, new_pc - pc);
+
+ // We probably have code snippets after the epilogue, so save the
+ // current state: DW_CFA_remember_state.
+ cfi_info->push_back(0x0a);
+
+ // We have now popped the stack: DW_CFA_def_cfa_offset 4. There is only the return
+ // PC on the stack now.
+ cfi_info->push_back(0x0e);
+ EncodeUnsignedLeb128(*cfi_info, 4);
+
+ // Everything after that is the same as before the epilogue.
+ // Stack bump was followed by RET instruction.
+ LIR *post_ret_insn = NEXT_LIR(NEXT_LIR(stack_increment_));
+ if (post_ret_insn != nullptr) {
+ pc = new_pc;
+ new_pc = post_ret_insn->offset;
+ AdvanceLoc(*cfi_info, new_pc - pc);
+ // Restore the state: DW_CFA_restore_state.
+ cfi_info->push_back(0x0b);
+ }
+ }
+ }
+
+ // Padding to a multiple of 4
+ while ((cfi_info->size() & 3) != 0) {
+ // DW_CFA_nop is encoded as 0.
+ cfi_info->push_back(0);
+ }
+
+ // Set the length of the FDE inside the generated bytes.
+ uint32_t length = cfi_info->size() - 4;
+ (*cfi_info)[0] = length;
+ (*cfi_info)[1] = length >> 8;
+ (*cfi_info)[2] = length >> 16;
+ (*cfi_info)[3] = length >> 24;
+ return cfi_info;
+}
+
} // namespace art
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index 0f79f4128f..4e258ef7c7 100644
--- a/compiler/dex/ssa_transformation.cc
+++ b/compiler/dex/ssa_transformation.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "bit_vector_block_iterator.h"
#include "compiler_internals.h"
#include "dataflow_iterator-inl.h"
@@ -248,9 +249,9 @@ bool MIRGraph::ComputeDominanceFrontier(BasicBlock* bb) {
}
/* Calculate DF_up */
- ArenaBitVector::BasicBlockIterator it(bb->i_dominated, cu_);
+ BitVectorBlockIterator it(bb->i_dominated, cu_);
for (BasicBlock *dominated_bb = it.Next(); dominated_bb != nullptr; dominated_bb = it.Next()) {
- ArenaBitVector::BasicBlockIterator inner_it(dominated_bb->dom_frontier, cu_);
+ BitVectorBlockIterator inner_it(dominated_bb->dom_frontier, cu_);
for (BasicBlock *df_up_block = inner_it.Next(); df_up_block != nullptr;
df_up_block = inner_it.Next()) {
CheckForDominanceFrontier(bb, df_up_block);
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
new file mode 100644
index 0000000000..d401398ca4
--- /dev/null
+++ b/compiler/driver/compiler_driver-inl.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 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_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
+#define ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
+
+#include "compiler_driver.h"
+#include "dex/compiler_ir.h"
+#include "mirror/art_field.h"
+#include "mirror/art_field-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/dex_cache.h"
+#include "mirror/art_field-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+inline mirror::DexCache* CompilerDriver::GetDexCache(const DexCompilationUnit* mUnit) {
+ return mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+}
+
+inline mirror::ClassLoader* CompilerDriver::GetClassLoader(ScopedObjectAccess& soa,
+ const DexCompilationUnit* mUnit) {
+ return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+}
+
+inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit) {
+ DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
+ DCHECK(class_loader.get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ const DexFile::MethodId& referrer_method_id =
+ mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
+ mirror::Class* referrer_class = mUnit->GetClassLinker()->ResolveType(
+ *mUnit->GetDexFile(), referrer_method_id.class_idx_, dex_cache, class_loader);
+ DCHECK_EQ(referrer_class == nullptr, soa.Self()->IsExceptionPending());
+ if (UNLIKELY(referrer_class == nullptr)) {
+ // Clean up any exception left by type resolution.
+ soa.Self()->ClearException();
+ }
+ return referrer_class;
+}
+
+inline mirror::ArtField* CompilerDriver::ResolveField(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ uint32_t field_idx, bool is_static) {
+ DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
+ DCHECK(class_loader.get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ mirror::ArtField* resolved_field = mUnit->GetClassLinker()->ResolveField(
+ *mUnit->GetDexFile(), field_idx, dex_cache, class_loader, is_static);
+ DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
+ if (UNLIKELY(resolved_field == nullptr)) {
+ // Clean up any exception left by type resolution.
+ soa.Self()->ClearException();
+ return nullptr;
+ }
+ if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+ // ClassLinker can return a field of the wrong kind directly from the DexCache.
+ // Silently return nullptr on such incompatible class change.
+ return nullptr;
+ }
+ return resolved_field;
+}
+
+inline void CompilerDriver::GetResolvedFieldDexFileLocation(
+ mirror::ArtField* resolved_field, const DexFile** declaring_dex_file,
+ uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) {
+ mirror::Class* declaring_class = resolved_field->GetDeclaringClass();
+ *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile();
+ *declaring_class_idx = declaring_class->GetDexTypeIndex();
+ *declaring_field_idx = resolved_field->GetDexFieldIndex();
+}
+
+inline bool CompilerDriver::IsFieldVolatile(mirror::ArtField* field) {
+ return field->IsVolatile();
+}
+
+inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
+ mirror::DexCache* dex_cache, mirror::Class* referrer_class,
+ mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset) {
+ DCHECK(!resolved_field->IsStatic());
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ bool fast_get = referrer_class != nullptr &&
+ referrer_class->CanAccessResolvedField(fields_class, resolved_field,
+ dex_cache, field_idx);
+ bool fast_put = fast_get && (!resolved_field->IsFinal() || fields_class == referrer_class);
+ *field_offset = fast_get ? resolved_field->GetOffset() : MemberOffset(0u);
+ return std::make_pair(fast_get, fast_put);
+}
+
+inline std::pair<bool, bool> CompilerDriver::IsFastStaticField(
+ mirror::DexCache* dex_cache, mirror::Class* referrer_class,
+ mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset,
+ uint32_t* storage_index, bool* is_referrers_class, bool* is_initialized) {
+ DCHECK(resolved_field->IsStatic());
+ if (LIKELY(referrer_class != nullptr)) {
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ if (fields_class == referrer_class) {
+ *field_offset = resolved_field->GetOffset();
+ *storage_index = fields_class->GetDexTypeIndex();
+ *is_referrers_class = true; // implies no worrying about class initialization
+ *is_initialized = true;
+ return std::make_pair(true, true);
+ }
+ if (referrer_class->CanAccessResolvedField(fields_class, resolved_field,
+ dex_cache, field_idx)) {
+ // We have the resolved field, we must make it into a index for the referrer
+ // in its static storage (which may fail if it doesn't have a slot for it)
+ // TODO: for images we can elide the static storage base null check
+ // if we know there's a non-null entry in the image
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ uint32_t storage_idx = DexFile::kDexNoIndex;
+ if (LIKELY(fields_class->GetDexCache() == dex_cache)) {
+ // common case where the dex cache of both the referrer and the field are the same,
+ // no need to search the dex file
+ storage_idx = fields_class->GetDexTypeIndex();
+ } else {
+ // Search dex file for localized ssb index, may fail if field's class is a parent
+ // of the class mentioned in the dex file and there is no dex cache entry.
+ const DexFile::StringId* string_id =
+ dex_file->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
+ if (string_id != nullptr) {
+ const DexFile::TypeId* type_id =
+ dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
+ if (type_id != nullptr) {
+ // medium path, needs check of static storage base being initialized
+ storage_idx = dex_file->GetIndexForTypeId(*type_id);
+ }
+ }
+ }
+ if (storage_idx != DexFile::kDexNoIndex) {
+ *field_offset = resolved_field->GetOffset();
+ *storage_index = storage_idx;
+ *is_referrers_class = false;
+ *is_initialized = fields_class->IsInitialized() &&
+ CanAssumeTypeIsPresentInDexCache(*dex_file, storage_idx);
+ return std::make_pair(true, !resolved_field->IsFinal());
+ }
+ }
+ }
+ // Conservative defaults.
+ *field_offset = MemberOffset(0u);
+ *storage_index = DexFile::kDexNoIndex;
+ *is_referrers_class = false;
+ *is_initialized = false;
+ return std::make_pair(false, false);
+}
+
+} // namespace art
+
+#endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1b284de9cc..501ea7c130 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -26,11 +26,13 @@
#include "base/timing_logger.h"
#include "class_linker.h"
#include "compiler_backend.h"
+#include "compiler_driver-inl.h"
#include "dex_compilation_unit.h"
#include "dex_file-inl.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "dex/quick/dex_file_method_inliner.h"
+#include "driver/compiler_options.h"
#include "jni_internal.h"
#include "object_utils.h"
#include "runtime.h"
@@ -323,10 +325,12 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
compiler_enable_auto_elf_loading_(NULL),
compiler_get_method_code_addr_(NULL),
support_boot_image_fixup_(instruction_set != kMips),
+ cfi_info_(nullptr),
dedupe_code_("dedupe code"),
dedupe_mapping_table_("dedupe mapping table"),
dedupe_vmap_table_("dedupe vmap table"),
- dedupe_gc_map_("dedupe gc map") {
+ dedupe_gc_map_("dedupe gc map"),
+ dedupe_cfi_info_("dedupe cfi info") {
DCHECK(compiler_options_ != nullptr);
DCHECK(verification_results_ != nullptr);
DCHECK(method_inliner_map_ != nullptr);
@@ -341,6 +345,11 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
if (!image_) {
CHECK(image_classes_.get() == NULL);
}
+
+ // Are we generating CFI information?
+ if (compiler_options->GetGenerateGDBInformation()) {
+ cfi_info_.reset(compiler_backend_->GetCallFrameInformationInitialization(*this));
+ }
}
std::vector<uint8_t>* CompilerDriver::DeduplicateCode(const std::vector<uint8_t>& code) {
@@ -359,6 +368,13 @@ std::vector<uint8_t>* CompilerDriver::DeduplicateGCMap(const std::vector<uint8_t
return dedupe_gc_map_.Add(Thread::Current(), code);
}
+std::vector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info) {
+ if (cfi_info == nullptr) {
+ return nullptr;
+ }
+ return dedupe_cfi_info_.Add(Thread::Current(), *cfi_info);
+}
+
CompilerDriver::~CompilerDriver() {
Thread* self = Thread::Current();
{
@@ -441,11 +457,11 @@ const std::vector<uint8_t>* CompilerDriver::CreateQuickToInterpreterBridge() con
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger& timings) {
+ TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
- PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
- Compile(class_loader, dex_files, *thread_pool.get(), timings);
+ PreCompile(class_loader, dex_files, thread_pool.get(), timings);
+ Compile(class_loader, dex_files, thread_pool.get(), timings);
if (dump_stats_) {
stats_->Dump();
}
@@ -483,7 +499,7 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel(
}
}
-void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger& timings) {
+void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
Thread* self = Thread::Current();
jobject jclass_loader;
@@ -510,7 +526,7 @@ void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger& timings
dex_files.push_back(dex_file);
UniquePtr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", 0U));
- PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
+ PreCompile(jclass_loader, dex_files, thread_pool.get(), timings);
// Can we run DEX-to-DEX compiler on this class ?
DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile;
@@ -531,7 +547,7 @@ void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger& timings
}
void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -540,7 +556,7 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi
}
void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
LoadImageClasses(timings);
Resolve(class_loader, dex_files, thread_pool, timings);
@@ -625,13 +641,13 @@ static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
}
// Make a list of descriptors for classes to include in the image
-void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+void CompilerDriver::LoadImageClasses(TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
if (!IsImage()) {
return;
}
- timings.NewSplit("LoadImageClasses");
+ timings->NewSplit("LoadImageClasses");
// Make a first class to load all classes explicitly listed in the file
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
@@ -713,9 +729,9 @@ void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void
MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
}
-void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
if (IsImage()) {
- timings.NewSplit("UpdateImageClasses");
+ timings->NewSplit("UpdateImageClasses");
// Update image_classes_ with classes for objects created by <clinit> methods.
Thread* self = Thread::Current();
@@ -886,6 +902,24 @@ bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_i
}
}
+void CompilerDriver::ProcessedInstanceField(bool resolved) {
+ if (!resolved) {
+ stats_->UnresolvedInstanceField();
+ } else {
+ stats_->ResolvedInstanceField();
+ }
+}
+
+void CompilerDriver::ProcessedStaticField(bool resolved, bool local) {
+ if (!resolved) {
+ stats_->UnresolvedStaticField();
+ } else if (local) {
+ stats_->ResolvedLocalStaticField();
+ } else {
+ stats_->ResolvedStaticField();
+ }
+}
+
static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
SirtRef<mirror::DexCache>& dex_cache,
const DexCompilationUnit* mUnit)
@@ -903,15 +937,6 @@ static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
dex_cache, class_loader);
}
-static mirror::ArtField* ComputeFieldReferencedFromCompilingMethod(
- ScopedObjectAccess& soa, const DexCompilationUnit* mUnit, uint32_t field_idx, bool is_static)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SirtRef<mirror::DexCache> dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
- return mUnit->GetClassLinker()->ResolveField(*mUnit->GetDexFile(), field_idx, dex_cache,
- class_loader, is_static);
-}
-
static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa,
const DexCompilationUnit* mUnit,
uint32_t method_idx,
@@ -947,117 +972,80 @@ bool CompilerDriver::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
}
bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
- bool is_put, int* field_offset, bool* is_volatile) {
+ bool is_put, MemberOffset* field_offset,
+ bool* is_volatile) {
ScopedObjectAccess soa(Thread::Current());
- // Conservative defaults.
- *field_offset = -1;
- *is_volatile = true;
- // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static).
- mirror::ArtField* resolved_field =
- ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx, false);
- if (resolved_field != NULL && !resolved_field->IsStatic()) {
- SirtRef<mirror::DexCache> dex_cache(soa.Self(),
- resolved_field->GetDeclaringClass()->GetDexCache());
- mirror::Class* referrer_class =
- ComputeCompilingMethodsClass(soa, dex_cache, mUnit);
- if (referrer_class != NULL) {
- mirror::Class* fields_class = resolved_field->GetDeclaringClass();
- bool access_ok = referrer_class->CanAccessResolvedField(fields_class, resolved_field,
- dex_cache.get(), field_idx);
- bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() &&
- fields_class != referrer_class;
- if (access_ok && !is_write_to_final_from_wrong_class) {
- *field_offset = resolved_field->GetOffset().Int32Value();
- *is_volatile = resolved_field->IsVolatile();
- stats_->ResolvedInstanceField();
- return true; // Fast path.
- }
- }
- }
- // Clean up any exception left by field/type resolution
- if (soa.Self()->IsExceptionPending()) {
- soa.Self()->ClearException();
+ // Try to resolve the field and compiling method's class.
+ mirror::ArtField* resolved_field;
+ mirror::Class* referrer_class;
+ mirror::DexCache* dex_cache;
+ {
+ SirtRef<mirror::DexCache> dex_cache_sirt(soa.Self(),
+ mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+ SirtRef<mirror::ClassLoader> class_loader_sirt(soa.Self(),
+ soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ SirtRef<mirror::ArtField> resolved_field_sirt(soa.Self(),
+ ResolveField(soa, dex_cache_sirt, class_loader_sirt, mUnit, field_idx, false));
+ referrer_class = (resolved_field_sirt.get() != nullptr)
+ ? ResolveCompilingMethodsClass(soa, dex_cache_sirt, class_loader_sirt, mUnit) : nullptr;
+ resolved_field = resolved_field_sirt.get();
+ dex_cache = dex_cache_sirt.get();
}
- stats_->UnresolvedInstanceField();
- return false; // Incomplete knowledge needs slow path.
+ bool result = false;
+ if (resolved_field != nullptr && referrer_class != nullptr) {
+ *is_volatile = IsFieldVolatile(resolved_field);
+ std::pair<bool, bool> fast_path = IsFastInstanceField(
+ dex_cache, referrer_class, resolved_field, field_idx, field_offset);
+ result = is_put ? fast_path.second : fast_path.first;
+ }
+ if (!result) {
+ // Conservative defaults.
+ *is_volatile = true;
+ *field_offset = MemberOffset(static_cast<size_t>(-1));
+ }
+ ProcessedInstanceField(result);
+ return result;
}
bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
- bool is_put, int* field_offset, int* storage_index,
- bool* is_referrers_class, bool* is_volatile,
- bool* is_initialized) {
+ bool is_put, MemberOffset* field_offset,
+ uint32_t* storage_index, bool* is_referrers_class,
+ bool* is_volatile, bool* is_initialized) {
ScopedObjectAccess soa(Thread::Current());
- // Conservative defaults.
- *field_offset = -1;
- *storage_index = -1;
- *is_referrers_class = false;
- *is_volatile = true;
- *is_initialized = false;
- // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static).
- mirror::ArtField* resolved_field =
- ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx, true);
- if (resolved_field != NULL && resolved_field->IsStatic()) {
- SirtRef<mirror::DexCache> dex_cache(soa.Self(), resolved_field->GetDeclaringClass()->GetDexCache());
- mirror::Class* referrer_class =
- ComputeCompilingMethodsClass(soa, dex_cache, mUnit);
- if (referrer_class != NULL) {
- mirror::Class* fields_class = resolved_field->GetDeclaringClass();
- if (fields_class == referrer_class) {
- *is_referrers_class = true; // implies no worrying about class initialization
- *is_initialized = true;
- *field_offset = resolved_field->GetOffset().Int32Value();
- *is_volatile = resolved_field->IsVolatile();
- stats_->ResolvedLocalStaticField();
- return true; // fast path
- } else {
- bool access_ok = referrer_class->CanAccessResolvedField(fields_class, resolved_field,
- dex_cache.get(), field_idx);
- bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal();
- if (access_ok && !is_write_to_final_from_wrong_class) {
- // We have the resolved field, we must make it into a index for the referrer
- // in its static storage (which may fail if it doesn't have a slot for it)
- // TODO: for images we can elide the static storage base null check
- // if we know there's a non-null entry in the image
- mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
- if (fields_class->GetDexCache() == dex_cache) {
- // common case where the dex cache of both the referrer and the field are the same,
- // no need to search the dex file
- *storage_index = fields_class->GetDexTypeIndex();
- *field_offset = resolved_field->GetOffset().Int32Value();
- *is_volatile = resolved_field->IsVolatile();
- *is_initialized = fields_class->IsInitialized() &&
- CanAssumeTypeIsPresentInDexCache(*mUnit->GetDexFile(), *storage_index);
- stats_->ResolvedStaticField();
- return true;
- }
- // Search dex file for localized ssb index, may fail if field's class is a parent
- // of the class mentioned in the dex file and there is no dex cache entry.
- const DexFile::StringId* string_id =
- mUnit->GetDexFile()->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
- if (string_id != NULL) {
- const DexFile::TypeId* type_id =
- mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id));
- if (type_id != NULL) {
- // medium path, needs check of static storage base being initialized
- *storage_index = mUnit->GetDexFile()->GetIndexForTypeId(*type_id);
- *field_offset = resolved_field->GetOffset().Int32Value();
- *is_volatile = resolved_field->IsVolatile();
- *is_initialized = fields_class->IsInitialized() &&
- CanAssumeTypeIsPresentInDexCache(*mUnit->GetDexFile(), *storage_index);
- stats_->ResolvedStaticField();
- return true;
- }
- }
- }
- }
- }
- }
- // Clean up any exception left by field/type resolution
- if (soa.Self()->IsExceptionPending()) {
- soa.Self()->ClearException();
+ // Try to resolve the field and compiling method's class.
+ mirror::ArtField* resolved_field;
+ mirror::Class* referrer_class;
+ mirror::DexCache* dex_cache;
+ {
+ SirtRef<mirror::DexCache> dex_cache_sirt(soa.Self(),
+ mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()));
+ SirtRef<mirror::ClassLoader> class_loader_sirt(soa.Self(),
+ soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ SirtRef<mirror::ArtField> resolved_field_sirt(soa.Self(),
+ ResolveField(soa, dex_cache_sirt, class_loader_sirt, mUnit, field_idx, true));
+ referrer_class = (resolved_field_sirt.get() != nullptr)
+ ? ResolveCompilingMethodsClass(soa, dex_cache_sirt, class_loader_sirt, mUnit) : nullptr;
+ resolved_field = resolved_field_sirt.get();
+ dex_cache = dex_cache_sirt.get();
}
- stats_->UnresolvedStaticField();
- return false; // Incomplete knowledge needs slow path.
+ bool result = false;
+ if (resolved_field != nullptr && referrer_class != nullptr) {
+ *is_volatile = IsFieldVolatile(resolved_field);
+ std::pair<bool, bool> fast_path = IsFastStaticField(
+ dex_cache, referrer_class, resolved_field, field_idx, field_offset,
+ storage_index, is_referrers_class, is_initialized);
+ result = is_put ? fast_path.second : fast_path.first;
+ }
+ if (!result) {
+ // Conservative defaults.
+ *is_volatile = true;
+ *field_offset = MemberOffset(static_cast<size_t>(-1));
+ *storage_index = -1;
+ *is_referrers_class = false;
+ *is_initialized = false;
+ }
+ ProcessedStaticField(result, *is_referrers_class);
+ return result;
}
void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type,
@@ -1368,13 +1356,13 @@ class ParallelCompilationManager {
jobject class_loader,
CompilerDriver* compiler,
const DexFile* dex_file,
- ThreadPool& thread_pool)
+ ThreadPool* thread_pool)
: index_(0),
class_linker_(class_linker),
class_loader_(class_loader),
compiler_(compiler),
dex_file_(dex_file),
- thread_pool_(&thread_pool) {}
+ thread_pool_(thread_pool) {}
ClassLinker* GetClassLinker() const {
CHECK(class_linker_ != NULL);
@@ -1628,7 +1616,7 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i
}
void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// TODO: we could resolve strings here, although the string table is largely filled with class
@@ -1638,16 +1626,16 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil
if (IsImage()) {
// For images we resolve all types, such as array, whereas for applications just those with
// classdefs are resolved by ResolveClassFieldsAndMethods.
- timings.NewSplit("Resolve Types");
+ timings->NewSplit("Resolve Types");
context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
}
- timings.NewSplit("Resolve MethodsAndFields");
+ timings->NewSplit("Resolve MethodsAndFields");
context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
}
void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -1702,8 +1690,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
}
void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
- timings.NewSplit("Verify Dex File");
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ timings->NewSplit("Verify Dex File");
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
@@ -1805,8 +1793,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
}
void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
- timings.NewSplit("InitializeNoClinit");
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ timings->NewSplit("InitializeNoClinit");
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
size_t thread_count;
@@ -1825,7 +1813,7 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile&
void CompilerDriver::InitializeClasses(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -1834,7 +1822,7 @@ void CompilerDriver::InitializeClasses(jobject class_loader,
}
void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings) {
+ ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
@@ -1916,8 +1904,8 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
}
void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings) {
- timings.NewSplit("Compile Dex File");
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ timings->NewSplit("Compile Dex File");
ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
&dex_file, thread_pool);
context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
@@ -2037,38 +2025,38 @@ bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex
bool CompilerDriver::WriteElf(const std::string& android_root,
bool is_host,
const std::vector<const art::DexFile*>& dex_files,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
art::File* file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return compiler_backend_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
}
void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
- std::string& target_triple,
- std::string& target_cpu,
- std::string& target_attr) {
+ std::string* target_triple,
+ std::string* target_cpu,
+ std::string* target_attr) {
switch (instruction_set) {
case kThumb2:
- target_triple = "thumb-none-linux-gnueabi";
- target_cpu = "cortex-a9";
- target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
+ *target_triple = "thumb-none-linux-gnueabi";
+ *target_cpu = "cortex-a9";
+ *target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
break;
case kArm:
- target_triple = "armv7-none-linux-gnueabi";
+ *target_triple = "armv7-none-linux-gnueabi";
// TODO: Fix for Nexus S.
- target_cpu = "cortex-a9";
+ *target_cpu = "cortex-a9";
// TODO: Fix for Xoom.
- target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
+ *target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
break;
case kX86:
- target_triple = "i386-pc-linux-gnu";
- target_attr = "";
+ *target_triple = "i386-pc-linux-gnu";
+ *target_attr = "";
break;
case kMips:
- target_triple = "mipsel-unknown-linux";
- target_attr = "mips32r2";
+ *target_triple = "mipsel-unknown-linux";
+ *target_attr = "mips32r2";
break;
default:
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 377eb6fa34..57c2908bfa 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -48,9 +48,10 @@ class AOTCompilationStats;
class CompilerOptions;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
-class InlineIGetIPutData;
+struct InlineIGetIPutData;
class OatWriter;
class ParallelCompilationManager;
+class ScopedObjectAccess;
class TimingLogger;
class VerificationResults;
class VerifiedMethod;
@@ -108,11 +109,11 @@ class CompilerDriver {
~CompilerDriver();
void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- TimingLogger& timings)
+ TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
// Compile a single Method.
- void CompileOne(mirror::ArtMethod* method, TimingLogger& timings)
+ void CompileOne(mirror::ArtMethod* method, TimingLogger* timings)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
VerificationResults* GetVerificationResults() const {
@@ -123,16 +124,15 @@ class CompilerDriver {
return method_inliner_map_;
}
- const InstructionSet& GetInstructionSet() const {
+ InstructionSet GetInstructionSet() const {
return instruction_set_;
}
- const InstructionSetFeatures& GetInstructionSetFeatures() const {
+ InstructionSetFeatures GetInstructionSetFeatures() const {
return instruction_set_features_;
}
const CompilerOptions& GetCompilerOptions() const {
- DCHECK(compiler_options_ != nullptr);
return *compiler_options_;
}
@@ -204,6 +204,53 @@ class CompilerDriver {
bool* is_type_initialized, bool* use_direct_type_ptr,
uintptr_t* direct_type_ptr);
+ // Get the DexCache for the
+ mirror::DexCache* GetDexCache(const DexCompilationUnit* mUnit)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ mirror::ClassLoader* GetClassLoader(ScopedObjectAccess& soa, const DexCompilationUnit* mUnit)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Resolve compiling method's class. Returns nullptr on failure.
+ mirror::Class* ResolveCompilingMethodsClass(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Resolve a field. Returns nullptr on failure, including incompatible class change.
+ // NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static.
+ mirror::ArtField* ResolveField(
+ ScopedObjectAccess& soa, const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ uint32_t field_idx, bool is_static)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Get declaration location of a resolved field.
+ void GetResolvedFieldDexFileLocation(
+ mirror::ArtField* resolved_field, const DexFile** declaring_dex_file,
+ uint16_t* declaring_class_idx, uint16_t* declaring_field_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ bool IsFieldVolatile(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset.
+ std::pair<bool, bool> IsFastInstanceField(
+ mirror::DexCache* dex_cache, mirror::Class* referrer_class,
+ mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Can we fast-path an SGET/SPUT access to a static field? If yes, compute the field offset,
+ // the type index of the declaring class in the referrer's dex file and whether the declaring
+ // class is the referrer's class or at least can be assumed to be initialized.
+ std::pair<bool, bool> IsFastStaticField(
+ mirror::DexCache* dex_cache, mirror::Class* referrer_class,
+ mirror::ArtField* resolved_field, uint16_t field_idx, MemberOffset* field_offset,
+ uint32_t* storage_index, bool* is_referrers_class, bool* is_initialized)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void ProcessedInstanceField(bool resolved);
+ void ProcessedStaticField(bool resolved, bool local);
+
// Can we fast path instance field access in a verified accessor?
// If yes, computes field's offset and volatility and whether the method is static or not.
static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
@@ -213,13 +260,13 @@ class CompilerDriver {
// Can we fast path instance field access? Computes field's offset and volatility.
bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
- int* field_offset, bool* is_volatile)
+ MemberOffset* field_offset, bool* is_volatile)
LOCKS_EXCLUDED(Locks::mutator_lock_);
// Can we fastpath static field access? Computes field's offset, volatility and whether the
// field is within the referrer (which can avoid checking class initialization).
bool ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
- int* field_offset, int* storage_index,
+ MemberOffset* field_offset, uint32_t* storage_index,
bool* is_referrers_class, bool* is_volatile, bool* is_initialized)
LOCKS_EXCLUDED(Locks::mutator_lock_);
@@ -275,21 +322,21 @@ class CompilerDriver {
support_boot_image_fixup_ = support_boot_image_fixup;
}
- ArenaPool& GetArenaPool() {
- return arena_pool_;
+ ArenaPool* GetArenaPool() {
+ return &arena_pool_;
}
bool WriteElf(const std::string& android_root,
bool is_host,
const std::vector<const DexFile*>& dex_files,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
File* file);
- // TODO: move to a common home for llvm helpers once quick/portable are merged
+ // TODO: move to a common home for llvm helpers once quick/portable are merged.
static void InstructionSetToLLVMTarget(InstructionSet instruction_set,
- std::string& target_triple,
- std::string& target_cpu,
- std::string& target_attr);
+ std::string* target_triple,
+ std::string* target_cpu,
+ std::string* target_attr);
void SetCompilerContext(void* compiler_context) {
compiler_context_ = compiler_context;
@@ -310,8 +357,8 @@ class CompilerDriver {
return dump_passes_;
}
- CumulativeLogger& GetTimingsLogger() const {
- return *timings_logger_;
+ CumulativeLogger* GetTimingsLogger() const {
+ return timings_logger_;
}
class PatchInformation {
@@ -494,6 +541,15 @@ class CompilerDriver {
std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
+ std::vector<uint8_t>* DeduplicateCFIInfo(const std::vector<uint8_t>* cfi_info);
+
+ /*
+ * @brief return the pointer to the Call Frame Information.
+ * @return pointer to call frame information for this compilation.
+ */
+ std::vector<uint8_t>* GetCallFrameInformation() const {
+ return cfi_info_.get();
+ }
private:
// Compute constant code and method pointers when possible
@@ -507,43 +563,42 @@ class CompilerDriver {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
- void LoadImageClasses(TimingLogger& timings);
+ void LoadImageClasses(TimingLogger* timings);
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
// ordering semantics.
void Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void ResolveDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings);
+ ThreadPool* thread_pool, TimingLogger* timings);
void VerifyDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void InitializeClasses(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
- void UpdateImageClasses(TimingLogger& timings)
- LOCKS_EXCLUDED(Locks::mutator_lock_);
+ void UpdateImageClasses(TimingLogger* timings) LOCKS_EXCLUDED(Locks::mutator_lock_);
static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool& thread_pool, TimingLogger& timings);
+ ThreadPool* thread_pool, TimingLogger* timings);
void CompileDexFile(jobject class_loader, const DexFile& dex_file,
- ThreadPool& thread_pool, TimingLogger& timings)
+ ThreadPool* thread_pool, TimingLogger* timings)
LOCKS_EXCLUDED(Locks::mutator_lock_);
void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx,
@@ -627,6 +682,9 @@ class CompilerDriver {
bool support_boot_image_fixup_;
+ // Call Frame Information, which might be generated to help stack tracebacks.
+ UniquePtr<std::vector<uint8_t> > cfi_info_;
+
// DeDuplication data structures, these own the corresponding byte arrays.
class DedupeHashFunc {
public:
@@ -665,6 +723,7 @@ class CompilerDriver {
DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_;
DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_;
DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_;
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_;
DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
};
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index ec0a8bdc63..2b3af6281f 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -21,7 +21,7 @@
#include "UniquePtr.h"
#include "class_linker.h"
-#include "common_test.h"
+#include "common_compiler_test.h"
#include "dex_file.h"
#include "gc/heap.h"
#include "mirror/art_method-inl.h"
@@ -33,14 +33,14 @@
namespace art {
-class CompilerDriverTest : public CommonTest {
+class CompilerDriverTest : public CommonCompilerTest {
protected:
void CompileAll(jobject class_loader) LOCKS_EXCLUDED(Locks::mutator_lock_) {
TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
timings.StartSplit("CompileAll");
compiler_driver_->CompileAll(class_loader,
Runtime::Current()->GetCompileTimeClassPath(class_loader),
- timings);
+ &timings);
MakeAllExecutable(class_loader);
timings.EndSplit();
}
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9f6745b015..39738ab049 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -43,7 +43,8 @@ class CompilerOptions {
large_method_threshold_(kDefaultLargeMethodThreshold),
small_method_threshold_(kDefaultSmallMethodThreshold),
tiny_method_threshold_(kDefaultTinyMethodThreshold),
- num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold)
+ num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
+ generate_gdb_information_(false)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(false)
#endif
@@ -54,7 +55,8 @@ class CompilerOptions {
size_t large_method_threshold,
size_t small_method_threshold,
size_t tiny_method_threshold,
- size_t num_dex_methods_threshold
+ size_t num_dex_methods_threshold,
+ bool generate_gdb_information
#ifdef ART_SEA_IR_MODE
, bool sea_ir_mode
#endif
@@ -64,7 +66,8 @@ class CompilerOptions {
large_method_threshold_(large_method_threshold),
small_method_threshold_(small_method_threshold),
tiny_method_threshold_(tiny_method_threshold),
- num_dex_methods_threshold_(num_dex_methods_threshold)
+ num_dex_methods_threshold_(num_dex_methods_threshold),
+ generate_gdb_information_(generate_gdb_information)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(sea_ir_mode)
#endif
@@ -118,6 +121,10 @@ class CompilerOptions {
bool GetSeaIrMode();
#endif
+ bool GetGenerateGDBInformation() const {
+ return generate_gdb_information_;
+ }
+
private:
CompilerFilter compiler_filter_;
size_t huge_method_threshold_;
@@ -125,6 +132,7 @@ class CompilerOptions {
size_t small_method_threshold_;
size_t tiny_method_threshold_;
size_t num_dex_methods_threshold_;
+ bool generate_gdb_information_;
#ifdef ART_SEA_IR_MODE
bool sea_ir_mode_;
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 6db3fa1a11..ccc26a1baf 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -30,12 +30,7 @@
namespace art {
-ElfWriter::ElfWriter(const CompilerDriver& driver, File* elf_file)
- : compiler_driver_(&driver), elf_file_(elf_file) {}
-
-ElfWriter::~ElfWriter() {}
-
-Elf32_Addr ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
+uint32_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
"oatdata",
false);
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 99dfc56d49..3610d1a8b2 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -23,7 +23,6 @@
#include <vector>
#include "base/macros.h"
-#include "elf_utils.h"
#include "os.h"
namespace art {
@@ -42,21 +41,23 @@ class ElfWriter {
size_t& oat_data_offset);
// Returns runtime oat_data runtime address for an opened ElfFile.
- static Elf32_Addr GetOatDataAddress(ElfFile* elf_file);
+ static uint32_t GetOatDataAddress(ElfFile* elf_file);
protected:
- ElfWriter(const CompilerDriver& driver, File* elf_file);
- virtual ~ElfWriter();
+ ElfWriter(const CompilerDriver& driver, File* elf_file)
+ : compiler_driver_(&driver), elf_file_(elf_file) {
+ }
- virtual bool Write(OatWriter& oat_writer,
+ virtual ~ElfWriter() {}
+
+ virtual bool Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
- // Setup by constructor
- const CompilerDriver* compiler_driver_;
- File* elf_file_;
+ const CompilerDriver* const compiler_driver_;
+ File* const elf_file_;
};
} // namespace art
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index c7baf4f3e5..b2d3a69e74 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -16,6 +16,7 @@
#include "elf_writer_mclinker.h"
+#include <llvm/Support/ELF.h>
#include <llvm/Support/TargetSelect.h>
#include <mcld/Environment.h>
@@ -32,7 +33,6 @@
#include "class_linker.h"
#include "dex_method_iterator.h"
#include "driver/compiler_driver.h"
-#include "elf_file.h"
#include "globals.h"
#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
@@ -44,12 +44,14 @@
namespace art {
ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
- : ElfWriter(driver, elf_file), oat_input_(NULL) {}
+ : ElfWriter(driver, elf_file), oat_input_(nullptr) {
+}
-ElfWriterMclinker::~ElfWriterMclinker() {}
+ElfWriterMclinker::~ElfWriterMclinker() {
+}
bool ElfWriterMclinker::Create(File* elf_file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -58,29 +60,29 @@ bool ElfWriterMclinker::Create(File* elf_file,
return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-bool ElfWriterMclinker::Write(OatWriter& oat_writer,
+bool ElfWriterMclinker::Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host) {
std::vector<uint8_t> oat_contents;
- oat_contents.reserve(oat_writer.GetSize());
+ oat_contents.reserve(oat_writer->GetSize());
VectorOutputStream output_stream("oat contents", oat_contents);
- CHECK(oat_writer.Write(output_stream));
- CHECK_EQ(oat_writer.GetSize(), oat_contents.size());
+ CHECK(oat_writer->Write(&output_stream));
+ CHECK_EQ(oat_writer->GetSize(), oat_contents.size());
Init();
AddOatInput(oat_contents);
-#if defined(ART_USE_PORTABLE_COMPILER)
- AddMethodInputs(dex_files);
- AddRuntimeInputs(android_root, is_host);
-#endif
+ if (kUsePortableCompiler) {
+ AddMethodInputs(dex_files);
+ AddRuntimeInputs(android_root, is_host);
+ }
if (!Link()) {
return false;
}
oat_contents.clear();
-#if defined(ART_USE_PORTABLE_COMPILER)
- FixupOatMethodOffsets(dex_files);
-#endif
+ if (kUsePortableCompiler) {
+ FixupOatMethodOffsets(dex_files);
+ }
return true;
}
@@ -100,9 +102,9 @@ void ElfWriterMclinker::Init() {
std::string target_cpu;
std::string target_attr;
CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
- target_triple,
- target_cpu,
- target_attr);
+ &target_triple,
+ &target_cpu,
+ &target_attr);
// Based on mclinker's llvm-mcld.cpp main() and LinkerTest
//
@@ -236,7 +238,6 @@ void ElfWriterMclinker::AddOatInput(std::vector<uint8_t>& oat_contents) {
text_section);
}
-#if defined(ART_USE_PORTABLE_COMPILER)
void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
DCHECK(oat_input_ != NULL);
@@ -320,7 +321,6 @@ void ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool i
mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
CHECK(libm_lib_input_input != NULL);
}
-#endif
bool ElfWriterMclinker::Link() {
// link inputs
@@ -345,7 +345,6 @@ bool ElfWriterMclinker::Link() {
return true;
}
-#if defined(ART_USE_PORTABLE_COMPILER)
void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
std::string error_msg;
UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false, &error_msg));
@@ -409,6 +408,5 @@ uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
}
return compiled_code_offset;
}
-#endif
} // namespace art
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
index 8ee7231f79..13757edecd 100644
--- a/compiler/elf_writer_mclinker.h
+++ b/compiler/elf_writer_mclinker.h
@@ -37,11 +37,11 @@ namespace art {
class CompiledCode;
-class ElfWriterMclinker : public ElfWriter {
+class ElfWriterMclinker FINAL : public ElfWriter {
public:
// Write an ELF file. Returns true on success, false on failure.
static bool Create(File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -49,10 +49,11 @@ class ElfWriterMclinker : public ElfWriter {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual bool Write(OatWriter& oat_writer,
- const std::vector<const DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host)
+ bool Write(OatWriter* oat_writer,
+ const std::vector<const DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host)
+ OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
@@ -65,13 +66,11 @@ class ElfWriterMclinker : public ElfWriter {
void AddCompiledCodeInput(const CompiledCode& compiled_code);
void AddRuntimeInputs(const std::string& android_root, bool is_host);
bool Link();
-#if defined(ART_USE_PORTABLE_COMPILER)
void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
- ::llvm::ELF::Elf32_Addr oatdata_address,
+ uint32_t oatdata_address,
const CompiledCode& compiled_code);
-#endif
// Setup by Init()
UniquePtr<mcld::LinkerConfig> linker_config_;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 3191374160..4b823ef5ec 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -29,13 +29,8 @@
namespace art {
-ElfWriterQuick::ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
- : ElfWriter(driver, elf_file) {}
-
-ElfWriterQuick::~ElfWriterQuick() {}
-
bool ElfWriterQuick::Create(File* elf_file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -44,7 +39,7 @@ bool ElfWriterQuick::Create(File* elf_file,
return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-bool ElfWriterQuick::Write(OatWriter& oat_writer,
+bool ElfWriterQuick::Write(OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files_unused,
const std::string& android_root_unused,
bool is_host_unused) {
@@ -103,6 +98,7 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
// | .rodata\0 |
// | .text\0 |
// | .shstrtab\0 |
+ // | .debug_frame\0 |
// +-------------------------+
// | Elf32_Shdr NULL |
// | Elf32_Shdr .dynsym |
@@ -112,6 +108,9 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
// | Elf32_Shdr .rodata |
// | Elf32_Shdr .dynamic |
// | Elf32_Shdr .shstrtab |
+ // | Elf32_Shdr .debug_info | (Optional)
+ // | Elf32_Shdr .debug_abbrev| (Optional)
+ // | Elf32_Shdr .debug_frame | (Optional)
// +-------------------------+
// phase 1: computing offsets
@@ -197,7 +196,7 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
// .rodata
uint32_t oat_data_alignment = kPageSize;
uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment);
- const OatHeader& oat_header = oat_writer.GetOatHeader();
+ const OatHeader& oat_header = oat_writer->GetOatHeader();
CHECK(oat_header.IsValid());
uint32_t oat_data_size = oat_header.GetExecutableOffset();
expected_offset += oat_data_size;
@@ -210,9 +209,9 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
uint32_t oat_exec_alignment = kPageSize;
CHECK_ALIGNED(expected_offset, kPageSize);
uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment);
- uint32_t oat_exec_size = oat_writer.GetSize() - oat_data_size;
+ uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size;
expected_offset += oat_exec_size;
- CHECK_EQ(oat_data_offset + oat_writer.GetSize(), expected_offset);
+ CHECK_EQ(oat_data_offset + oat_writer->GetSize(), expected_offset);
if (debug) {
LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset;
LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size;
@@ -264,6 +263,18 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
uint32_t shstrtab_shstrtab_offset = shstrtab.size();
shstrtab += ".shstrtab";
shstrtab += '\0';
+ uint32_t shstrtab_debug_info_offset = shstrtab.size();
+ shstrtab += ".debug_info";
+ shstrtab += '\0';
+ uint32_t shstrtab_debug_abbrev_offset = shstrtab.size();
+ shstrtab += ".debug_abbrev";
+ shstrtab += '\0';
+ uint32_t shstrtab_debug_str_offset = shstrtab.size();
+ shstrtab += ".debug_str";
+ shstrtab += '\0';
+ uint32_t shstrtab_debug_frame_offset = shstrtab.size();
+ shstrtab += ".debug_frame";
+ shstrtab += '\0';
uint32_t shstrtab_size = shstrtab.size();
expected_offset += shstrtab_size;
if (debug) {
@@ -271,6 +282,52 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size;
}
+ // Create debug informatin, if we have it.
+ bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr;
+ std::vector<uint8_t> dbg_info;
+ std::vector<uint8_t> dbg_abbrev;
+ std::vector<uint8_t> dbg_str;
+ if (generateDebugInformation) {
+ FillInCFIInformation(oat_writer, &dbg_info, &dbg_abbrev, &dbg_str);
+ }
+
+ uint32_t shdbg_info_alignment = 1;
+ uint32_t shdbg_info_offset = expected_offset;
+ uint32_t shdbg_info_size = dbg_info.size();
+ expected_offset += shdbg_info_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_info_offset=" << shdbg_info_offset << std::hex << " " << shdbg_info_offset;
+ LOG(INFO) << "shdbg_info_size=" << shdbg_info_size << std::hex << " " << shdbg_info_size;
+ }
+
+ uint32_t shdbg_abbrev_alignment = 1;
+ uint32_t shdbg_abbrev_offset = expected_offset;
+ uint32_t shdbg_abbrev_size = dbg_abbrev.size();
+ expected_offset += shdbg_abbrev_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_abbrev_offset=" << shdbg_abbrev_offset << std::hex << " " << shdbg_abbrev_offset;
+ LOG(INFO) << "shdbg_abbrev_size=" << shdbg_abbrev_size << std::hex << " " << shdbg_abbrev_size;
+ }
+
+ uint32_t shdbg_frm_alignment = 4;
+ uint32_t shdbg_frm_offset = expected_offset = RoundUp(expected_offset, shdbg_frm_alignment);
+ uint32_t shdbg_frm_size =
+ generateDebugInformation ? compiler_driver_->GetCallFrameInformation()->size() : 0;
+ expected_offset += shdbg_frm_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_frm_offset=" << shdbg_frm_offset << std::hex << " " << shdbg_frm_offset;
+ LOG(INFO) << "shdbg_frm_size=" << shdbg_frm_size << std::hex << " " << shdbg_frm_size;
+ }
+
+ uint32_t shdbg_str_alignment = 1;
+ uint32_t shdbg_str_offset = expected_offset;
+ uint32_t shdbg_str_size = dbg_str.size();
+ expected_offset += shdbg_str_size;
+ if (debug) {
+ LOG(INFO) << "shdbg_str_offset=" << shdbg_str_offset << std::hex << " " << shdbg_str_offset;
+ LOG(INFO) << "shdbg_str_size=" << shdbg_str_size << std::hex << " " << shdbg_str_size;
+ }
+
// section headers (after all sections)
uint32_t shdr_alignment = sizeof(Elf32_Word);
uint32_t shdr_offset = expected_offset = RoundUp(expected_offset, shdr_alignment);
@@ -282,7 +339,11 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
const uint8_t SH_TEXT = 5;
const uint8_t SH_DYNAMIC = 6;
const uint8_t SH_SHSTRTAB = 7;
- const uint8_t SH_NUM = 8;
+ const uint8_t SH_DBG_INFO = 8;
+ const uint8_t SH_DBG_ABRV = 9;
+ const uint8_t SH_DBG_FRM = 10;
+ const uint8_t SH_DBG_STR = 11;
+ const uint8_t SH_NUM = generateDebugInformation ? 12 : 8;
uint32_t shdr_size = sizeof(Elf32_Shdr) * SH_NUM;
expected_offset += shdr_size;
if (debug) {
@@ -559,6 +620,52 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
section_headers[SH_SHSTRTAB].sh_addralign = shstrtab_alignment;
section_headers[SH_SHSTRTAB].sh_entsize = 0;
+ if (generateDebugInformation) {
+ section_headers[SH_DBG_INFO].sh_name = shstrtab_debug_info_offset;
+ section_headers[SH_DBG_INFO].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_INFO].sh_flags = 0;
+ section_headers[SH_DBG_INFO].sh_addr = 0;
+ section_headers[SH_DBG_INFO].sh_offset = shdbg_info_offset;
+ section_headers[SH_DBG_INFO].sh_size = shdbg_info_size;
+ section_headers[SH_DBG_INFO].sh_link = 0;
+ section_headers[SH_DBG_INFO].sh_info = 0;
+ section_headers[SH_DBG_INFO].sh_addralign = shdbg_info_alignment;
+ section_headers[SH_DBG_INFO].sh_entsize = 0;
+
+ section_headers[SH_DBG_ABRV].sh_name = shstrtab_debug_abbrev_offset;
+ section_headers[SH_DBG_ABRV].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_ABRV].sh_flags = 0;
+ section_headers[SH_DBG_ABRV].sh_addr = 0;
+ section_headers[SH_DBG_ABRV].sh_offset = shdbg_abbrev_offset;
+ section_headers[SH_DBG_ABRV].sh_size = shdbg_abbrev_size;
+ section_headers[SH_DBG_ABRV].sh_link = 0;
+ section_headers[SH_DBG_ABRV].sh_info = 0;
+ section_headers[SH_DBG_ABRV].sh_addralign = shdbg_abbrev_alignment;
+ section_headers[SH_DBG_ABRV].sh_entsize = 0;
+
+ section_headers[SH_DBG_FRM].sh_name = shstrtab_debug_frame_offset;
+ section_headers[SH_DBG_FRM].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_FRM].sh_flags = 0;
+ section_headers[SH_DBG_FRM].sh_addr = 0;
+ section_headers[SH_DBG_FRM].sh_offset = shdbg_frm_offset;
+ section_headers[SH_DBG_FRM].sh_size = shdbg_frm_size;
+ section_headers[SH_DBG_FRM].sh_link = 0;
+ section_headers[SH_DBG_FRM].sh_info = 0;
+ section_headers[SH_DBG_FRM].sh_addralign = shdbg_frm_alignment;
+ section_headers[SH_DBG_FRM].sh_entsize = 0;
+
+ section_headers[SH_DBG_STR].sh_name = shstrtab_debug_str_offset;
+ section_headers[SH_DBG_STR].sh_type = SHT_PROGBITS;
+ section_headers[SH_DBG_STR].sh_flags = 0;
+ section_headers[SH_DBG_STR].sh_addr = 0;
+ section_headers[SH_DBG_STR].sh_offset = shdbg_str_offset;
+ section_headers[SH_DBG_STR].sh_size = shdbg_str_size;
+ section_headers[SH_DBG_STR].sh_link = 0;
+ section_headers[SH_DBG_STR].sh_info = 0;
+ section_headers[SH_DBG_STR].sh_addralign = shdbg_str_alignment;
+ section_headers[SH_DBG_STR].sh_entsize = 0;
+ }
+
// phase 3: writing file
// Elf32_Ehdr
@@ -622,13 +729,13 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
return false;
}
BufferedOutputStream output_stream(new FileOutputStream(elf_file_));
- if (!oat_writer.Write(output_stream)) {
+ if (!oat_writer->Write(&output_stream)) {
PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath();
return false;
}
// .dynamic
- DCHECK_LE(oat_data_offset + oat_writer.GetSize(), dynamic_offset);
+ DCHECK_LE(oat_data_offset + oat_writer->GetSize(), dynamic_offset);
if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) {
PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset
<< " for " << elf_file_->GetPath();
@@ -651,8 +758,62 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
return false;
}
+ if (generateDebugInformation) {
+ // .debug_info
+ DCHECK_LE(shstrtab_offset + shstrtab_size, shdbg_info_offset);
+ if (static_cast<off_t>(shdbg_info_offset) != lseek(elf_file_->Fd(), shdbg_info_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_info offset " << shdbg_info_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&dbg_info[0], shdbg_info_size)) {
+ PLOG(ERROR) << "Failed to write .debug_info for " << elf_file_->GetPath();
+ return false;
+ }
+
+ // .debug_abbrev
+ DCHECK_LE(shdbg_info_offset + shdbg_info_size, shdbg_abbrev_offset);
+ if (static_cast<off_t>(shdbg_abbrev_offset) != lseek(elf_file_->Fd(), shdbg_abbrev_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_abbrev offset " << shdbg_abbrev_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&dbg_abbrev[0], shdbg_abbrev_size)) {
+ PLOG(ERROR) << "Failed to write .debug_abbrev for " << elf_file_->GetPath();
+ return false;
+ }
+
+ // .debug_frame
+ DCHECK_LE(shdbg_abbrev_offset + shdbg_abbrev_size, shdbg_frm_offset);
+ if (static_cast<off_t>(shdbg_frm_offset) != lseek(elf_file_->Fd(), shdbg_frm_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_frm offset " << shdbg_frm_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&((*compiler_driver_->GetCallFrameInformation())[0]), shdbg_frm_size)) {
+ PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
+ return false;
+ }
+
+ // .debug_str
+ DCHECK_LE(shdbg_frm_offset + shdbg_frm_size, shdbg_str_offset);
+ if (static_cast<off_t>(shdbg_str_offset) != lseek(elf_file_->Fd(), shdbg_str_offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek to .shdbg_str offset " << shdbg_str_offset
+ << " for " << elf_file_->GetPath();
+ return false;
+ }
+ if (!elf_file_->WriteFully(&dbg_str[0], shdbg_str_size)) {
+ PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath();
+ return false;
+ }
+ }
+
// section headers (after all sections)
- DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+ if (generateDebugInformation) {
+ DCHECK_LE(shdbg_str_offset + shdbg_str_size, shdr_offset);
+ } else {
+ DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+ }
if (static_cast<off_t>(shdr_offset) != lseek(elf_file_->Fd(), shdr_offset, SEEK_SET)) {
PLOG(ERROR) << "Failed to seek to ELF section headers offset " << shdr_offset
<< " for " << elf_file_->GetPath();
@@ -665,6 +826,164 @@ bool ElfWriterQuick::Write(OatWriter& oat_writer,
VLOG(compiler) << "ELF file written successfully: " << elf_file_->GetPath();
return true;
+} // NOLINT(readability/fn_size)
+
+static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) {
+ (*buf)[offset+0] = data;
+ (*buf)[offset+1] = data >> 8;
+ (*buf)[offset+2] = data >> 16;
+ (*buf)[offset+3] = data >> 24;
+}
+
+static void PushWord(std::vector<uint8_t>*buf, int data) {
+ buf->push_back(data & 0xff);
+ buf->push_back((data >> 8) & 0xff);
+ buf->push_back((data >> 16) & 0xff);
+ buf->push_back((data >> 24) & 0xff);
+}
+
+static void PushHalf(std::vector<uint8_t>*buf, int data) {
+ buf->push_back(data & 0xff);
+ buf->push_back((data >> 8) & 0xff);
+}
+
+// DWARF constants needed to generate CFI information.
+enum {
+ // Tag encodings.
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_subprogram = 0X2e,
+
+ // Attribute encodings.
+ DW_AT_name = 0x03,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+
+ // Constant encoding.
+ DW_CHILDREN_no = 0x00,
+ DW_CHILDREN_yes = 0x01,
+
+ // Attribute form encodings.
+ DW_FORM_addr = 0x01,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_strp = 0x0e,
+
+ // Language encoding.
+ DW_LANG_Java = 0x000b
+};
+
+void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
+ std::vector<uint8_t>* dbg_info,
+ std::vector<uint8_t>* dbg_abbrev,
+ std::vector<uint8_t>* dbg_str) {
+ // Create the debug_abbrev section with boilerplate information.
+ // We only care about low_pc and high_pc right now for the compilation
+ // unit and methods.
+
+ // Tag 1: Compilation unit: DW_TAG_compile_unit.
+ dbg_abbrev->push_back(1);
+ dbg_abbrev->push_back(DW_TAG_compile_unit);
+
+ // There are children (the methods).
+ dbg_abbrev->push_back(DW_CHILDREN_yes);
+
+ // DW_LANG_Java DW_FORM_data1.
+ dbg_abbrev->push_back(DW_AT_language);
+ dbg_abbrev->push_back(DW_FORM_data1);
+
+ // DW_AT_low_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_low_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // DW_AT_high_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_high_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // End of DW_TAG_compile_unit.
+ PushHalf(dbg_abbrev, 0);
+
+ // Tag 2: Compilation unit: DW_TAG_subprogram.
+ dbg_abbrev->push_back(2);
+ dbg_abbrev->push_back(DW_TAG_subprogram);
+
+ // There are no children.
+ dbg_abbrev->push_back(DW_CHILDREN_no);
+
+ // Name of the method.
+ dbg_abbrev->push_back(DW_AT_name);
+ dbg_abbrev->push_back(DW_FORM_strp);
+
+ // DW_AT_low_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_low_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // DW_AT_high_pc DW_FORM_addr.
+ dbg_abbrev->push_back(DW_AT_high_pc);
+ dbg_abbrev->push_back(DW_FORM_addr);
+
+ // End of DW_TAG_subprogram.
+ PushHalf(dbg_abbrev, 0);
+
+ // Start the debug_info section with the header information
+ // 'unit_length' will be filled in later.
+ PushWord(dbg_info, 0);
+
+ // 'version' - 3.
+ PushHalf(dbg_info, 3);
+
+ // Offset into .debug_abbrev section (always 0).
+ PushWord(dbg_info, 0);
+
+ // Address size: 4.
+ dbg_info->push_back(4);
+
+ // Start the description for the compilation unit.
+ // This uses tag 1.
+ dbg_info->push_back(1);
+
+ // The language is Java.
+ dbg_info->push_back(DW_LANG_Java);
+
+ // Leave space for low_pc and high_pc.
+ int low_pc_offset = dbg_info->size();
+ PushWord(dbg_info, 0);
+ PushWord(dbg_info, 0);
+
+ // Walk through the information in the method table, and enter into dbg_info.
+ const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
+ uint32_t low_pc = 0xFFFFFFFFU;
+ uint32_t high_pc = 0;
+
+ for (uint32_t i = 0; i < dbg.size(); i++) {
+ const OatWriter::DebugInfo& info = dbg[i];
+ if (info.low_pc_ < low_pc) {
+ low_pc = info.low_pc_;
+ }
+ if (info.high_pc_ > high_pc) {
+ high_pc = info.high_pc_;
+ }
+
+ // Start a new TAG: subroutine (2).
+ dbg_info->push_back(2);
+
+ // Enter the name into the string table (and NUL terminate).
+ uint32_t str_offset = dbg_str->size();
+ dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
+ dbg_str->push_back('\0');
+
+ // Enter name, low_pc, high_pc.
+ PushWord(dbg_info, str_offset);
+ PushWord(dbg_info, info.low_pc_);
+ PushWord(dbg_info, info.high_pc_);
+ }
+
+ // One byte terminator
+ dbg_info->push_back(0);
+
+ // We have now walked all the methods. Fill in lengths and low/high PCs.
+ UpdateWord(dbg_info, 0, dbg_info->size() - 4);
+ UpdateWord(dbg_info, low_pc_offset, low_pc);
+ UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
}
} // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index f36d06f79d..dec75dc83f 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -21,11 +21,11 @@
namespace art {
-class ElfWriterQuick : public ElfWriter {
+class ElfWriterQuick FINAL : public ElfWriter {
public:
// Write an ELF file. Returns true on success, false on failure.
static bool Create(File* file,
- OatWriter& oat_writer,
+ OatWriter* oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -33,15 +33,27 @@ class ElfWriterQuick : public ElfWriter {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual bool Write(OatWriter& oat_writer,
- const std::vector<const DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host)
+ bool Write(OatWriter* oat_writer,
+ const std::vector<const DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host)
+ OVERRIDE
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
- ElfWriterQuick(const CompilerDriver& driver, File* elf_file);
- ~ElfWriterQuick();
+ ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
+ : ElfWriter(driver, elf_file) {}
+ ~ElfWriterQuick() {}
+
+ /*
+ * @brief Generate the DWARF debug_info and debug_abbrev sections
+ * @param oat_writer The Oat file Writer.
+ * @param dbg_info Compilation unit information.
+ * @param dbg_abbrev Abbreviations used to generate dbg_info.
+ * @param dbg_str Debug strings.
+ */
+ void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info,
+ std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str);
DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
};
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 5bad0d00ea..8175c35077 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-#include "common_test.h"
+#include "elf_file.h"
+#include "common_compiler_test.h"
#include "oat.h"
-#include "elf_file.h"
namespace art {
-class ElfWriterTest : public CommonTest {
+class ElfWriterTest : public CommonCompilerTest {
protected:
virtual void SetUp() {
ReserveImageSpace();
- CommonTest::SetUp();
+ CommonCompilerTest::SetUp();
}
};
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 49cabdce79..619b056f57 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -14,15 +14,16 @@
* limitations under the License.
*/
+#include "image.h"
+
#include <string>
#include <vector>
-#include "common_test.h"
+#include "common_compiler_test.h"
#include "compiler/elf_fixup.h"
#include "compiler/image_writer.h"
#include "compiler/oat_writer.h"
#include "gc/space/image_space.h"
-#include "image.h"
#include "lock_word.h"
#include "mirror/object-inl.h"
#include "signal_catcher.h"
@@ -32,11 +33,11 @@
namespace art {
-class ImageTest : public CommonTest {
+class ImageTest : public CommonCompilerTest {
protected:
virtual void SetUp() {
ReserveImageSpace();
- CommonTest::SetUp();
+ CommonCompilerTest::SetUp();
}
};
@@ -48,15 +49,15 @@ TEST_F(ImageTest, WriteRead) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
TimingLogger timings("ImageTest::WriteRead", false, false);
timings.StartSplit("CompileAll");
-#if defined(ART_USE_PORTABLE_COMPILER)
- // TODO: we disable this for portable so the test executes in a reasonable amount of time.
- // We shouldn't need to do this.
- runtime_->SetCompilerFilter(Runtime::kInterpretOnly);
-#endif
+ if (kUsePortableCompiler) {
+ // TODO: we disable this for portable so the test executes in a reasonable amount of time.
+ // We shouldn't need to do this.
+ compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
+ }
for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
dex_file->EnableWrite();
}
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
ScopedObjectAccess soa(Thread::Current());
OatWriter oat_writer(class_linker->GetBootClassPath(),
@@ -64,7 +65,7 @@ TEST_F(ImageTest, WriteRead) {
bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
!kIsTargetBuild,
class_linker->GetBootClassPath(),
- oat_writer,
+ &oat_writer,
tmp_elf.GetFile());
ASSERT_TRUE(success);
timings.EndSplit();
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index c8447beaa5..aa16885039 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -583,6 +583,12 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) {
DCHECK(orig != NULL);
DCHECK(copy != NULL);
copy->SetClass<kVerifyNone>(down_cast<Class*>(GetImageAddress(orig->GetClass())));
+ if (kUseBrooksPointer) {
+ orig->AssertSelfBrooksPointer();
+ // Note the address 'copy' isn't the same as the image address of 'orig'.
+ copy->SetBrooksPointer(GetImageAddress(orig));
+ DCHECK(copy->GetBrooksPointer() == GetImageAddress(orig));
+ }
// TODO: special case init of pointers to malloc data (or removal of these pointers)
if (orig->IsClass<kVerifyNone>()) {
FixupClass(orig->AsClass<kVerifyNone>(), down_cast<Class*>(copy));
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 1bdff37f04..f48cf6c7b0 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -15,7 +15,7 @@
*/
#include "class_linker.h"
-#include "common_test.h"
+#include "common_compiler_test.h"
#include "dex_file.h"
#include "gtest/gtest.h"
#include "indirect_reference_table.h"
@@ -43,7 +43,7 @@ extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_sbar(JNIEnv*, jclass, jint
namespace art {
-class JniCompilerTest : public CommonTest {
+class JniCompilerTest : public CommonCompilerTest {
protected:
void CompileForTest(jobject class_loader, bool direct,
const char* method_name, const char* method_sig) {
diff --git a/compiler/leb128_encoder.h b/compiler/leb128_encoder.h
deleted file mode 100644
index 67666831f0..0000000000
--- a/compiler/leb128_encoder.h
+++ /dev/null
@@ -1,109 +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_COMPILER_LEB128_ENCODER_H_
-#define ART_COMPILER_LEB128_ENCODER_H_
-
-#include "base/macros.h"
-#include "leb128.h"
-
-namespace art {
-
-static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) {
- uint8_t out = value & 0x7f;
- value >>= 7;
- while (value != 0) {
- *dest++ = out | 0x80;
- out = value & 0x7f;
- value >>= 7;
- }
- *dest++ = out;
- return dest;
-}
-
-static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) {
- uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
- uint8_t out = value & 0x7f;
- while (extra_bits != 0u) {
- *dest++ = out | 0x80;
- value >>= 7;
- out = value & 0x7f;
- extra_bits >>= 7;
- }
- *dest++ = out;
- return dest;
-}
-
-// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
-class Leb128EncodingVector {
- public:
- Leb128EncodingVector() {
- }
-
- void Reserve(uint32_t size) {
- data_.reserve(size);
- }
-
- void PushBackUnsigned(uint32_t value) {
- uint8_t out = value & 0x7f;
- value >>= 7;
- while (value != 0) {
- data_.push_back(out | 0x80);
- out = value & 0x7f;
- value >>= 7;
- }
- data_.push_back(out);
- }
-
- template<typename It>
- void InsertBackUnsigned(It cur, It end) {
- for (; cur != end; ++cur) {
- PushBackUnsigned(*cur);
- }
- }
-
- void PushBackSigned(int32_t value) {
- uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
- uint8_t out = value & 0x7f;
- while (extra_bits != 0u) {
- data_.push_back(out | 0x80);
- value >>= 7;
- out = value & 0x7f;
- extra_bits >>= 7;
- }
- data_.push_back(out);
- }
-
- template<typename It>
- void InsertBackSigned(It cur, It end) {
- for (; cur != end; ++cur) {
- PushBackSigned(*cur);
- }
- }
-
- const std::vector<uint8_t>& GetData() const {
- return data_;
- }
-
- private:
- std::vector<uint8_t> data_;
-
- DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector);
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_LEB128_ENCODER_H_
diff --git a/compiler/leb128_encoder_test.cc b/compiler/leb128_encoder_test.cc
deleted file mode 100644
index 7af851803e..0000000000
--- a/compiler/leb128_encoder_test.cc
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "leb128.h"
-#include "leb128_encoder.h"
-
-#include "gtest/gtest.h"
-#include "base/histogram-inl.h"
-
-namespace art {
-
-struct DecodeUnsignedLeb128TestCase {
- uint32_t decoded;
- uint8_t leb128_data[5];
-};
-
-static DecodeUnsignedLeb128TestCase uleb128_tests[] = {
- {0, {0, 0, 0, 0, 0}},
- {1, {1, 0, 0, 0, 0}},
- {0x7F, {0x7F, 0, 0, 0, 0}},
- {0x80, {0x80, 1, 0, 0, 0}},
- {0x81, {0x81, 1, 0, 0, 0}},
- {0xFF, {0xFF, 1, 0, 0, 0}},
- {0x4000, {0x80, 0x80, 1, 0, 0}},
- {0x4001, {0x81, 0x80, 1, 0, 0}},
- {0x4081, {0x81, 0x81, 1, 0, 0}},
- {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0x7F, 0}},
- {0xFFFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xF}},
-};
-
-struct DecodeSignedLeb128TestCase {
- int32_t decoded;
- uint8_t leb128_data[5];
-};
-
-static DecodeSignedLeb128TestCase sleb128_tests[] = {
- {0, {0, 0, 0, 0, 0}},
- {1, {1, 0, 0, 0, 0}},
- {0x3F, {0x3F, 0, 0, 0, 0}},
- {0x40, {0xC0, 0 /* sign bit */, 0, 0, 0}},
- {0x41, {0xC1, 0 /* sign bit */, 0, 0, 0}},
- {0x80, {0x80, 1, 0, 0, 0}},
- {0xFF, {0xFF, 1, 0, 0, 0}},
- {0x1FFF, {0xFF, 0x3F, 0, 0, 0}},
- {0x2000, {0x80, 0xC0, 0 /* sign bit */, 0, 0}},
- {0x2001, {0x81, 0xC0, 0 /* sign bit */, 0, 0}},
- {0x2081, {0x81, 0xC1, 0 /* sign bit */, 0, 0}},
- {0x4000, {0x80, 0x80, 1, 0, 0}},
- {0x0FFFFF, {0xFF, 0xFF, 0x3F, 0, 0}},
- {0x100000, {0x80, 0x80, 0xC0, 0 /* sign bit */, 0}},
- {0x100001, {0x81, 0x80, 0xC0, 0 /* sign bit */, 0}},
- {0x100081, {0x81, 0x81, 0xC0, 0 /* sign bit */, 0}},
- {0x104081, {0x81, 0x81, 0xC1, 0 /* sign bit */, 0}},
- {0x200000, {0x80, 0x80, 0x80, 1, 0}},
- {0x7FFFFFF, {0xFF, 0xFF, 0xFF, 0x3F, 0}},
- {0x8000000, {0x80, 0x80, 0x80, 0xC0, 0 /* sign bit */}},
- {0x8000001, {0x81, 0x80, 0x80, 0xC0, 0 /* sign bit */}},
- {0x8000081, {0x81, 0x81, 0x80, 0xC0, 0 /* sign bit */}},
- {0x8004081, {0x81, 0x81, 0x81, 0xC0, 0 /* sign bit */}},
- {0x8204081, {0x81, 0x81, 0x81, 0xC1, 0 /* sign bit */}},
- {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0 /* sign bit */}},
- {0x10000000, {0x80, 0x80, 0x80, 0x80, 1}},
- {0x7FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0x7}},
- {-1, {0x7F, 0, 0, 0, 0}},
- {-2, {0x7E, 0, 0, 0, 0}},
- {-0x3F, {0x41, 0, 0, 0, 0}},
- {-0x40, {0x40, 0, 0, 0, 0}},
- {-0x41, {0xBF, 0x7F, 0, 0, 0}},
- {-0x80, {0x80, 0x7F, 0, 0, 0}},
- {-0x81, {0xFF, 0x7E, 0, 0, 0}},
- {-0x00002000, {0x80, 0x40, 0, 0, 0}},
- {-0x00002001, {0xFF, 0xBF, 0x7F, 0, 0}},
- {-0x00100000, {0x80, 0x80, 0x40, 0, 0}},
- {-0x00100001, {0xFF, 0xFF, 0xBF, 0x7F, 0}},
- {-0x08000000, {0x80, 0x80, 0x80, 0x40, 0}},
- {-0x08000001, {0xFF, 0xFF, 0xFF, 0xBF, 0x7F}},
- {-0x20000000, {0x80, 0x80, 0x80, 0x80, 0x7E}},
- {(-1) << 31, {0x80, 0x80, 0x80, 0x80, 0x78}},
-};
-
-TEST(Leb128Test, UnsignedSinglesVector) {
- // Test individual encodings.
- for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- Leb128EncodingVector builder;
- builder.PushBackUnsigned(uleb128_tests[i].decoded);
- EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), builder.GetData().size());
- const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
- const uint8_t* encoded_data_ptr = &builder.GetData()[0];
- for (size_t j = 0; j < 5; ++j) {
- if (j < builder.GetData().size()) {
- EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
- } else {
- EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
- }
- }
- EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i;
- }
-}
-
-TEST(Leb128Test, UnsignedSingles) {
- // Test individual encodings.
- for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- uint8_t encoded_data[5];
- uint8_t* end = EncodeUnsignedLeb128(encoded_data, uleb128_tests[i].decoded);
- size_t data_size = static_cast<size_t>(end - encoded_data);
- EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), data_size);
- const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
- for (size_t j = 0; j < 5; ++j) {
- if (j < data_size) {
- EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j;
- } else {
- EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
- }
- }
- EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i;
- }
-}
-
-TEST(Leb128Test, UnsignedStreamVector) {
- // Encode a number of entries.
- Leb128EncodingVector builder;
- for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- builder.PushBackUnsigned(uleb128_tests[i].decoded);
- }
- const uint8_t* encoded_data_ptr = &builder.GetData()[0];
- for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
- for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) {
- EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
- }
- for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) {
- EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
- }
- EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
- }
- EXPECT_EQ(builder.GetData().size(),
- static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0]));
-}
-
-TEST(Leb128Test, UnsignedStream) {
- // Encode a number of entries.
- uint8_t encoded_data[5 * arraysize(uleb128_tests)];
- uint8_t* end = encoded_data;
- for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- end = EncodeUnsignedLeb128(end, uleb128_tests[i].decoded);
- }
- size_t data_size = static_cast<size_t>(end - encoded_data);
- const uint8_t* encoded_data_ptr = encoded_data;
- for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
- for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) {
- EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
- }
- for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) {
- EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
- }
- EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
- }
- EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
-}
-
-TEST(Leb128Test, SignedSinglesVector) {
- // Test individual encodings.
- for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
- Leb128EncodingVector builder;
- builder.PushBackSigned(sleb128_tests[i].decoded);
- EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), builder.GetData().size());
- const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
- const uint8_t* encoded_data_ptr = &builder.GetData()[0];
- for (size_t j = 0; j < 5; ++j) {
- if (j < builder.GetData().size()) {
- EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
- } else {
- EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
- }
- }
- EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i;
- }
-}
-
-TEST(Leb128Test, SignedSingles) {
- // Test individual encodings.
- for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
- uint8_t encoded_data[5];
- uint8_t* end = EncodeSignedLeb128(encoded_data, sleb128_tests[i].decoded);
- size_t data_size = static_cast<size_t>(end - encoded_data);
- EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), data_size);
- const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
- for (size_t j = 0; j < 5; ++j) {
- if (j < data_size) {
- EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j;
- } else {
- EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
- }
- }
- EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i;
- }
-}
-
-TEST(Leb128Test, SignedStreamVector) {
- // Encode a number of entries.
- Leb128EncodingVector builder;
- for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
- builder.PushBackSigned(sleb128_tests[i].decoded);
- }
- const uint8_t* encoded_data_ptr = &builder.GetData()[0];
- for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
- const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
- for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) {
- EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
- }
- for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) {
- EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
- }
- EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i;
- }
- EXPECT_EQ(builder.GetData().size(),
- static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0]));
-}
-
-TEST(Leb128Test, SignedStream) {
- // Encode a number of entries.
- uint8_t encoded_data[5 * arraysize(sleb128_tests)];
- uint8_t* end = encoded_data;
- for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
- end = EncodeSignedLeb128(end, sleb128_tests[i].decoded);
- }
- size_t data_size = static_cast<size_t>(end - encoded_data);
- const uint8_t* encoded_data_ptr = encoded_data;
- for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
- const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
- for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) {
- EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
- }
- for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) {
- EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
- }
- EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i;
- }
- EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
-}
-
-TEST(Leb128Test, Speed) {
- UniquePtr<Histogram<uint64_t> > enc_hist(new Histogram<uint64_t>("Leb128EncodeSpeedTest", 5));
- UniquePtr<Histogram<uint64_t> > dec_hist(new Histogram<uint64_t>("Leb128DecodeSpeedTest", 5));
- Leb128EncodingVector builder;
- // Push back 1024 chunks of 1024 values measuring encoding speed.
- uint64_t last_time = NanoTime();
- for (size_t i = 0; i < 1024; i++) {
- for (size_t j = 0; j < 1024; j++) {
- builder.PushBackUnsigned((i * 1024) + j);
- }
- uint64_t cur_time = NanoTime();
- enc_hist->AddValue(cur_time - last_time);
- last_time = cur_time;
- }
- // Verify encoding and measure decode speed.
- const uint8_t* encoded_data_ptr = &builder.GetData()[0];
- last_time = NanoTime();
- for (size_t i = 0; i < 1024; i++) {
- for (size_t j = 0; j < 1024; j++) {
- EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), (i * 1024) + j);
- }
- uint64_t cur_time = NanoTime();
- dec_hist->AddValue(cur_time - last_time);
- last_time = cur_time;
- }
-
- Histogram<uint64_t>::CumulativeData enc_data;
- enc_hist->CreateHistogram(&enc_data);
- enc_hist->PrintConfidenceIntervals(std::cout, 0.99, enc_data);
-
- Histogram<uint64_t>::CumulativeData dec_data;
- dec_hist->CreateHistogram(&dec_data);
- dec_hist->PrintConfidenceIntervals(std::cout, 0.99, dec_data);
-}
-
-} // namespace art
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index a5acd2a332..4ce714a183 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -175,16 +175,16 @@ CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) {
} // namespace llvm
} // namespace art
-inline static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) {
+static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver& driver) {
void *compiler_context = driver.GetCompilerContext();
CHECK(compiler_context != NULL);
return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context);
}
-inline static const art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
+static art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) {
void *compiler_context = driver.GetCompilerContext();
CHECK(compiler_context != NULL);
- return reinterpret_cast<const art::llvm::CompilerLLVM*>(compiler_context);
+ return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context);
}
extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver) {
@@ -233,7 +233,7 @@ extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& dri
return result;
}
-extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
- std::string const& filename) {
+extern "C" void compilerLLVMSetBitcodeFileName(const art::CompilerDriver& driver,
+ const std::string& filename) {
ContextOf(driver)->SetBitcodeFileName(filename);
}
diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h
index 65bc16bcd8..c2211fb92c 100644
--- a/compiler/llvm/compiler_llvm.h
+++ b/compiler/llvm/compiler_llvm.h
@@ -70,7 +70,7 @@ class CompilerLLVM {
return insn_set_;
}
- void SetBitcodeFileName(std::string const& filename) {
+ void SetBitcodeFileName(const std::string& filename) {
bitcode_filename_ = filename;
}
diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc
index 8f22a97968..cf28db3bfc 100644
--- a/compiler/llvm/gbc_expander.cc
+++ b/compiler/llvm/gbc_expander.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "dex_file.h"
#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
@@ -1602,7 +1603,7 @@ llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst,
llvm::Value* field_value;
- int field_offset;
+ art::MemberOffset field_offset(0u);
bool is_volatile;
bool is_fast_path = driver_->ComputeInstanceFieldInfo(
field_idx, dex_compilation_unit_, false, &field_offset, &is_volatile);
@@ -1633,12 +1634,12 @@ llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst,
field_value = irb_.CreateBitCast(field_value, irb_.getJType(field_jty));
}
} else {
- DCHECK_GE(field_offset, 0);
+ DCHECK_GE(field_offset.Int32Value(), 0);
llvm::PointerType* field_type =
irb_.getJType(field_jty)->getPointerTo();
- llvm::ConstantInt* field_offset_value = irb_.getPtrEquivInt(field_offset);
+ llvm::ConstantInt* field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
llvm::Value* field_addr =
irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
@@ -1664,7 +1665,7 @@ void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst,
EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
- int field_offset;
+ art::MemberOffset field_offset(0u);
bool is_volatile;
bool is_fast_path = driver_->ComputeInstanceFieldInfo(
field_idx, dex_compilation_unit_, true, &field_offset, &is_volatile);
@@ -1698,7 +1699,7 @@ void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst,
EmitGuard_ExceptionLandingPad(dex_pc);
} else {
- DCHECK_GE(field_offset, 0);
+ DCHECK_GE(field_offset.Int32Value(), 0);
if (is_volatile) {
irb_.CreateMemoryBarrier(art::kStoreStore);
@@ -1707,7 +1708,7 @@ void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst,
llvm::PointerType* field_type =
irb_.getJType(field_jty)->getPointerTo();
- llvm::Value* field_offset_value = irb_.getPtrEquivInt(field_offset);
+ llvm::Value* field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
llvm::Value* field_addr =
irb_.CreatePtrDisp(object_addr, field_offset_value, field_type);
@@ -1875,8 +1876,8 @@ llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst,
uint32_t dex_pc = LV2UInt(call_inst.getMetadata("DexOff")->getOperand(0));
uint32_t field_idx = LV2UInt(call_inst.getArgOperand(0));
- int field_offset;
- int ssb_index;
+ art::MemberOffset field_offset(0u);
+ uint32_t ssb_index;
bool is_referrers_class;
bool is_volatile;
bool is_initialized;
@@ -1913,7 +1914,7 @@ llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst,
static_field_value = irb_.CreateBitCast(static_field_value, irb_.getJType(field_jty));
}
} else {
- DCHECK_GE(field_offset, 0);
+ DCHECK_GE(field_offset.Int32Value(), 0);
llvm::Value* static_storage_addr = NULL;
@@ -1929,11 +1930,11 @@ llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst,
} else {
// Medium path, static storage base in a different class which
// requires checks that the other class is initialized
- DCHECK_GE(ssb_index, 0);
+ DCHECK_NE(ssb_index, art::DexFile::kDexNoIndex);
static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
}
- llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
+ llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
llvm::Value* static_field_addr =
irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
@@ -1960,8 +1961,8 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst,
new_value = irb_.CreateBitCast(new_value, irb_.getJType(field_jty));
}
- int field_offset;
- int ssb_index;
+ art::MemberOffset field_offset(0u);
+ uint32_t ssb_index;
bool is_referrers_class;
bool is_volatile;
bool is_initialized;
@@ -1999,7 +2000,7 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst,
EmitGuard_ExceptionLandingPad(dex_pc);
} else {
- DCHECK_GE(field_offset, 0);
+ DCHECK_GE(field_offset.Int32Value(), 0);
llvm::Value* static_storage_addr = NULL;
@@ -2015,7 +2016,7 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst,
} else {
// Medium path, static storage base in a different class which
// requires checks that the other class is initialized
- DCHECK_GE(ssb_index, 0);
+ DCHECK_NE(ssb_index, art::DexFile::kDexNoIndex);
static_storage_addr = EmitLoadStaticStorage(dex_pc, ssb_index);
}
@@ -2023,7 +2024,7 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst,
irb_.CreateMemoryBarrier(art::kStoreStore);
}
- llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset);
+ llvm::Value* static_field_offset_value = irb_.getPtrEquivInt(field_offset.Int32Value());
llvm::Value* static_field_addr =
irb_.CreatePtrDisp(static_storage_addr, static_field_offset_value,
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index d23706d9f4..1d027f9d3b 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -199,7 +199,8 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea
std::string target_triple;
std::string target_cpu;
std::string target_attr;
- CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), target_triple, target_cpu, target_attr);
+ CompilerDriver::InstructionSetToLLVMTarget(GetInstructionSet(), &target_triple, &target_cpu,
+ &target_attr);
std::string errmsg;
const ::llvm::Target* target =
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index e91ffcb519..6dbba9fddd 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-#include "compiler/oat_writer.h"
+#include "common_compiler_test.h"
#include "compiler/compiler_backend.h"
+#include "compiler/oat_writer.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
-#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
#include "oat_file.h"
#include "vector_output_stream.h"
-#include "common_test.h"
-
namespace art {
-class OatTest : public CommonTest {
+class OatTest : public CommonCompilerTest {
protected:
static const bool kCompile = false; // DISABLED_ due to the time to compile libcore
@@ -81,7 +80,7 @@ class OatTest : public CommonTest {
};
TEST_F(OatTest, WriteRead) {
- TimingLogger timings("CommonTest::WriteRead", false, false);
+ TimingLogger timings("OatTest::WriteRead", false, false);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// TODO: make selectable.
@@ -106,7 +105,7 @@ TEST_F(OatTest, WriteRead) {
jobject class_loader = NULL;
if (kCompile) {
TimingLogger timings("OatTest::WriteRead", false, false);
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
ScopedObjectAccess soa(Thread::Current());
@@ -120,12 +119,12 @@ TEST_F(OatTest, WriteRead) {
bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
!kIsTargetBuild,
class_linker->GetBootClassPath(),
- oat_writer,
+ &oat_writer,
tmp.GetFile());
ASSERT_TRUE(success);
if (kCompile) { // OatWriter strips the code, regenerate to compare
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
+ compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
std::string error_msg;
UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false,
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 7c5669a3ab..a400bdde6c 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -229,7 +229,7 @@ size_t OatWriter::InitOatClasses(size_t offset) {
oat_classes_.push_back(oat_class);
offset += oat_class->SizeOf();
}
- oat_dex_files_[i]->UpdateChecksum(*oat_header_);
+ oat_dex_files_[i]->UpdateChecksum(oat_header_);
}
return offset;
}
@@ -293,7 +293,7 @@ size_t OatWriter::InitOatCodeDexFile(size_t offset,
class_def_index++, (*oat_class_index)++) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
offset = InitOatCodeClassDef(offset, *oat_class_index, class_def_index, dex_file, class_def);
- oat_classes_[*oat_class_index]->UpdateChecksum(*oat_header_);
+ oat_classes_[*oat_class_index]->UpdateChecksum(oat_header_);
}
return offset;
}
@@ -378,6 +378,27 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
uint32_t thumb_offset = compiled_method->CodeDelta();
quick_code_offset = offset + sizeof(code_size) + thumb_offset;
+ std::vector<uint8_t>* cfi_info = compiler_driver_->GetCallFrameInformation();
+ if (cfi_info != nullptr) {
+ // Copy in the FDE, if present
+ const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo();
+ if (fde != nullptr) {
+ // Copy the information into cfi_info and then fix the address in the new copy.
+ int cur_offset = cfi_info->size();
+ cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
+
+ // Set the 'initial_location' field to address the start of the method.
+ uint32_t new_value = quick_code_offset - oat_header_->GetExecutableOffset();
+ uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t);
+ (*cfi_info)[offset_to_update+0] = new_value;
+ (*cfi_info)[offset_to_update+1] = new_value >> 8;
+ (*cfi_info)[offset_to_update+2] = new_value >> 16;
+ (*cfi_info)[offset_to_update+3] = new_value >> 24;
+ method_info_.push_back(DebugInfo(PrettyMethod(class_def_method_index, dex_file, false),
+ new_value, new_value + code_size));
+ }
+ }
+
// Deduplicate code arrays
SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter =
code_offsets_.find(quick_code);
@@ -499,42 +520,42 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
}
#define DCHECK_OFFSET() \
- DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
+ DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
<< "file_offset=" << file_offset << " relative_offset=" << relative_offset
#define DCHECK_OFFSET_() \
- DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
+ DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
<< "file_offset=" << file_offset << " offset_=" << offset_
-bool OatWriter::Write(OutputStream& out) {
- const size_t file_offset = out.Seek(0, kSeekCurrent);
+bool OatWriter::Write(OutputStream* out) {
+ const size_t file_offset = out->Seek(0, kSeekCurrent);
- if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
- PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
+ if (!out->WriteFully(oat_header_, sizeof(*oat_header_))) {
+ PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
return false;
}
size_oat_header_ += sizeof(*oat_header_);
- if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
- PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
+ if (!out->WriteFully(image_file_location_.data(), image_file_location_.size())) {
+ PLOG(ERROR) << "Failed to write oat header image file location to " << out->GetLocation();
return false;
}
size_oat_header_image_file_location_ += image_file_location_.size();
if (!WriteTables(out, file_offset)) {
- LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
+ LOG(ERROR) << "Failed to write oat tables to " << out->GetLocation();
return false;
}
size_t relative_offset = WriteCode(out, file_offset);
if (relative_offset == 0) {
- LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
+ LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
return false;
}
relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
if (relative_offset == 0) {
- LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
+ LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
return false;
}
@@ -577,26 +598,26 @@ bool OatWriter::Write(OutputStream& out) {
#undef DO_STAT
VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
- CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out->Seek(0, kSeekCurrent)));
CHECK_EQ(size_, size_total);
}
- CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out->Seek(0, kSeekCurrent)));
CHECK_EQ(size_, relative_offset);
return true;
}
-bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
+bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) {
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
- PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
return false;
}
}
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
- off_t actual_offset = out.Seek(expected_offset, kSeekSet);
+ off_t actual_offset = out->Seek(expected_offset, kSeekSet);
if (static_cast<uint32_t>(actual_offset) != expected_offset) {
const DexFile* dex_file = (*dex_files_)[i];
PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
@@ -604,29 +625,29 @@ bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
return false;
}
const DexFile* dex_file = (*dex_files_)[i];
- if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+ if (!out->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
- << " to " << out.GetLocation();
+ << " to " << out->GetLocation();
return false;
}
size_dex_file_ += dex_file->GetHeader().file_size_;
}
for (size_t i = 0; i != oat_classes_.size(); ++i) {
if (!oat_classes_[i]->Write(this, out, file_offset)) {
- PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
return false;
}
}
return true;
}
-size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
+size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset) {
size_t relative_offset = oat_header_->GetExecutableOffset();
- off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
+ off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
size_t expected_file_offset = file_offset + relative_offset;
if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
- << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
+ << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
return 0;
}
DCHECK_OFFSET();
@@ -637,10 +658,10 @@ size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
do { \
uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
uint32_t alignment_padding = aligned_offset - relative_offset; \
- out.Seek(alignment_padding, kSeekCurrent); \
+ out->Seek(alignment_padding, kSeekCurrent); \
size_trampoline_alignment_ += alignment_padding; \
- if (!out.WriteFully(&(*field)[0], field->size())) { \
- PLOG(ERROR) << "Failed to write " # field " to " << out.GetLocation(); \
+ if (!out->WriteFully(&(*field)[0], field->size())) { \
+ PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
return false; \
} \
size_ ## field += field->size(); \
@@ -662,7 +683,7 @@ size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
return relative_offset;
}
-size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
+size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
const size_t file_offset,
size_t relative_offset) {
size_t oat_class_index = 0;
@@ -678,7 +699,7 @@ size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
return relative_offset;
}
-size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
+size_t OatWriter::WriteCodeDexFile(OutputStream* out, const size_t file_offset,
size_t relative_offset, size_t* oat_class_index,
const DexFile& dex_file) {
for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
@@ -694,12 +715,12 @@ size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
}
void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
- const DexFile& dex_file, OutputStream& out) const {
+ const DexFile& dex_file, const OutputStream& out) const {
PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
<< " to " << out.GetLocation();
}
-size_t OatWriter::WriteCodeClassDef(OutputStream& out,
+size_t OatWriter::WriteCodeClassDef(OutputStream* out,
const size_t file_offset,
size_t relative_offset,
size_t oat_class_index,
@@ -747,7 +768,7 @@ size_t OatWriter::WriteCodeClassDef(OutputStream& out,
return relative_offset;
}
-size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
+size_t OatWriter::WriteCodeMethod(OutputStream* out, const size_t file_offset,
size_t relative_offset, size_t oat_class_index,
size_t class_def_method_index, size_t* method_offsets_index,
bool is_static, uint32_t method_idx, const DexFile& dex_file) {
@@ -763,12 +784,12 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
uint32_t aligned_code_delta = aligned_offset - relative_offset;
if (aligned_code_delta != 0) {
- off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+ off_t new_offset = out->Seek(aligned_code_delta, kSeekCurrent);
size_code_alignment_ += aligned_code_delta;
uint32_t expected_offset = file_offset + aligned_offset;
if (static_cast<uint32_t>(new_offset) != expected_offset) {
PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
- << " Expected: " << expected_offset << " File: " << out.GetLocation();
+ << " Expected: " << expected_offset << " File: " << out->GetLocation();
return 0;
}
relative_offset += aligned_code_delta;
@@ -787,15 +808,15 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
<< PrettyMethod(method_idx, dex_file);
} else {
DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&code_size, sizeof(code_size))) {
- ReportWriteFailure("method code size", method_idx, dex_file, out);
+ if (!out->WriteFully(&code_size, sizeof(code_size))) {
+ ReportWriteFailure("method code size", method_idx, dex_file, *out);
return 0;
}
size_code_size_ += sizeof(code_size);
relative_offset += sizeof(code_size);
DCHECK_OFFSET();
- if (!out.WriteFully(&(*quick_code)[0], code_size)) {
- ReportWriteFailure("method code", method_idx, dex_file, out);
+ if (!out->WriteFully(&(*quick_code)[0], code_size)) {
+ ReportWriteFailure("method code", method_idx, dex_file, *out);
return 0;
}
size_code_ += code_size;
@@ -818,8 +839,8 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
|| relative_offset == method_offsets.mapping_table_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
- ReportWriteFailure("mapping table", method_idx, dex_file, out);
+ if (!out->WriteFully(&mapping_table[0], mapping_table_size)) {
+ ReportWriteFailure("mapping table", method_idx, dex_file, *out);
return 0;
}
size_mapping_table_ += mapping_table_size;
@@ -842,8 +863,8 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
|| relative_offset == method_offsets.vmap_table_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
- ReportWriteFailure("vmap table", method_idx, dex_file, out);
+ if (!out->WriteFully(&vmap_table[0], vmap_table_size)) {
+ ReportWriteFailure("vmap table", method_idx, dex_file, *out);
return 0;
}
size_vmap_table_ += vmap_table_size;
@@ -866,8 +887,8 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
|| relative_offset == method_offsets.gc_map_offset_)
<< PrettyMethod(method_idx, dex_file);
- if (!out.WriteFully(&gc_map[0], gc_map_size)) {
- ReportWriteFailure("GC map", method_idx, dex_file, out);
+ if (!out->WriteFully(&gc_map[0], gc_map_size)) {
+ ReportWriteFailure("GC map", method_idx, dex_file, *out);
return 0;
}
size_gc_map_ += gc_map_size;
@@ -897,42 +918,42 @@ size_t OatWriter::OatDexFile::SizeOf() const {
+ (sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
-void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
- oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
- oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
- oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
- oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
- oat_header.UpdateChecksum(&methods_offsets_[0],
+void OatWriter::OatDexFile::UpdateChecksum(OatHeader* oat_header) const {
+ oat_header->UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
+ oat_header->UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
+ oat_header->UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
+ oat_header->UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
+ oat_header->UpdateChecksum(&methods_offsets_[0],
sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
- OutputStream& out,
+ OutputStream* out,
const size_t file_offset) const {
DCHECK_OFFSET_();
- if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
- PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
+ if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
+ PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
- if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
- PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
+ if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
+ PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
- if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
- PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
+ if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+ PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
- if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
- PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
+ if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+ PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
- if (!out.WriteFully(&methods_offsets_[0],
+ if (!out->WriteFully(&methods_offsets_[0],
sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
- PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write methods offsets to " << out->GetLocation();
return false;
}
oat_writer->size_oat_dex_file_methods_offsets_ +=
@@ -1020,48 +1041,48 @@ size_t OatWriter::OatClass::SizeOf() const {
+ (sizeof(method_offsets_[0]) * method_offsets_.size());
}
-void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
- oat_header.UpdateChecksum(&status_, sizeof(status_));
- oat_header.UpdateChecksum(&type_, sizeof(type_));
+void OatWriter::OatClass::UpdateChecksum(OatHeader* oat_header) const {
+ oat_header->UpdateChecksum(&status_, sizeof(status_));
+ oat_header->UpdateChecksum(&type_, sizeof(type_));
if (method_bitmap_size_ != 0) {
CHECK_EQ(kOatClassSomeCompiled, type_);
- oat_header.UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
- oat_header.UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
+ oat_header->UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
+ oat_header->UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
}
- oat_header.UpdateChecksum(&method_offsets_[0],
- sizeof(method_offsets_[0]) * method_offsets_.size());
+ oat_header->UpdateChecksum(&method_offsets_[0],
+ sizeof(method_offsets_[0]) * method_offsets_.size());
}
bool OatWriter::OatClass::Write(OatWriter* oat_writer,
- OutputStream& out,
+ OutputStream* out,
const size_t file_offset) const {
DCHECK_OFFSET_();
- if (!out.WriteFully(&status_, sizeof(status_))) {
- PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
+ if (!out->WriteFully(&status_, sizeof(status_))) {
+ PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_status_ += sizeof(status_);
- if (!out.WriteFully(&type_, sizeof(type_))) {
- PLOG(ERROR) << "Failed to write oat class type to " << out.GetLocation();
+ if (!out->WriteFully(&type_, sizeof(type_))) {
+ PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_type_ += sizeof(type_);
if (method_bitmap_size_ != 0) {
CHECK_EQ(kOatClassSomeCompiled, type_);
- if (!out.WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
- PLOG(ERROR) << "Failed to write method bitmap size to " << out.GetLocation();
+ if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
+ PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
- if (!out.WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
- PLOG(ERROR) << "Failed to write method bitmap to " << out.GetLocation();
+ if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
+ PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
}
- if (!out.WriteFully(&method_offsets_[0],
+ if (!out->WriteFully(&method_offsets_[0],
sizeof(method_offsets_[0]) * method_offsets_.size())) {
- PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
return false;
}
oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 067c78971f..3d4b48ae42 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -78,10 +78,23 @@ class OatWriter {
return size_;
}
- bool Write(OutputStream& out);
+ bool Write(OutputStream* out);
~OatWriter();
+ struct DebugInfo {
+ DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc)
+ : method_name_(method_name), low_pc_(low_pc), high_pc_(high_pc) {
+ }
+ std::string method_name_;
+ uint32_t low_pc_;
+ uint32_t high_pc_;
+ };
+
+ const std::vector<DebugInfo>& GetCFIMethodInfo() const {
+ return method_info_;
+ }
+
private:
size_t InitOatHeader();
size_t InitOatDexFiles(size_t offset);
@@ -105,28 +118,28 @@ class OatWriter {
bool is_native, InvokeType type, uint32_t method_idx, const DexFile&)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool WriteTables(OutputStream& out, const size_t file_offset);
- size_t WriteCode(OutputStream& out, const size_t file_offset);
- size_t WriteCodeDexFiles(OutputStream& out, const size_t file_offset, size_t relative_offset);
- size_t WriteCodeDexFile(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ bool WriteTables(OutputStream* out, const size_t file_offset);
+ size_t WriteCode(OutputStream* out, const size_t file_offset);
+ size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset);
+ size_t WriteCodeDexFile(OutputStream* out, const size_t file_offset, size_t relative_offset,
size_t* oat_class_index, const DexFile& dex_file);
- size_t WriteCodeClassDef(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t WriteCodeClassDef(OutputStream* out, const size_t file_offset, size_t relative_offset,
size_t oat_class_index, const DexFile& dex_file,
const DexFile::ClassDef& class_def);
- size_t WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t WriteCodeMethod(OutputStream* out, const size_t file_offset, size_t relative_offset,
size_t oat_class_index, size_t class_def_method_index,
size_t* method_offsets_index, bool is_static, uint32_t method_idx,
const DexFile& dex_file);
void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
- OutputStream& out) const;
+ const OutputStream& out) const;
class OatDexFile {
public:
explicit OatDexFile(size_t offset, const DexFile& dex_file);
size_t SizeOf() const;
- void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
+ void UpdateChecksum(OatHeader* oat_header) const;
+ bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
// Offset of start of OatDexFile from beginning of OatHeader. It is
// used to validate file position when writing.
@@ -153,8 +166,8 @@ class OatWriter {
size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
size_t SizeOf() const;
- void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
+ void UpdateChecksum(OatHeader* oat_header) const;
+ bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
DCHECK(compiled_methods_ != NULL);
@@ -205,6 +218,8 @@ class OatWriter {
DISALLOW_COPY_AND_ASSIGN(OatClass);
};
+ std::vector<DebugInfo> method_info_;
+
const CompilerDriver* const compiler_driver_;
// note OatFile does not take ownership of the DexFiles
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 2c1091c3c9..e6db7bccc3 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -22,39 +22,120 @@
namespace art {
HGraph* HGraphBuilder::BuildGraph(const uint16_t* code_ptr, const uint16_t* code_end) {
+ // Setup the graph with the entry block and exit block.
graph_ = new (arena_) HGraph(arena_);
-
entry_block_ = new (arena_) HBasicBlock(graph_);
graph_->AddBlock(entry_block_);
-
+ entry_block_->AddInstruction(new (arena_) HGoto());
exit_block_ = new (arena_) HBasicBlock(graph_);
- // The exit block is added at the end of this method to ensure
- // its id is the greatest. This is needed for dominator computation.
-
- entry_block_->AddInstruction(new (arena_) HGoto(entry_block_));
+ exit_block_->AddInstruction(new (arena_) HExit());
- current_block_ = new (arena_) HBasicBlock(graph_);
- graph_->AddBlock(current_block_);
- entry_block_->AddSuccessor(current_block_);
+ // To avoid splitting blocks, we compute ahead of time the instructions that
+ // start a new block, and create these blocks.
+ ComputeBranchTargets(code_ptr, code_end);
+ size_t dex_offset = 0;
while (code_ptr < code_end) {
+ // Update the current block if dex_offset starts a new block.
+ MaybeUpdateCurrentBlock(dex_offset);
const Instruction& instruction = *Instruction::At(code_ptr);
- if (!AnalyzeDexInstruction(instruction)) return nullptr;
+ if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
+ dex_offset += instruction.SizeInCodeUnits();
code_ptr += instruction.SizeInCodeUnits();
}
- exit_block_->AddInstruction(new (arena_) HExit(exit_block_));
+ // Add the exit block at the end to give it the highest id.
graph_->AddBlock(exit_block_);
return graph_;
}
-bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction) {
+void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
+ HBasicBlock* block = FindBlockStartingAt(index);
+ if (block == nullptr) return;
+
+ if (current_block_ != nullptr) {
+ // Branching instructions clear current_block, so we know
+ // the last instruction of the current block is not a branching
+ // instruction. We add an unconditional goto to the found block.
+ current_block_->AddInstruction(new (arena_) HGoto());
+ current_block_->AddSuccessor(block);
+ }
+ graph_->AddBlock(block);
+ current_block_ = block;
+}
+
+void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
+ // TODO: Support switch instructions.
+ branch_targets_.SetSize(code_end - code_ptr);
+
+ // Create the first block for the dex instructions, single successor of the entry block.
+ HBasicBlock* block = new (arena_) HBasicBlock(graph_);
+ branch_targets_.Put(0, block);
+ entry_block_->AddSuccessor(block);
+
+ // Iterate over all instructions and find branching instructions. Create blocks for
+ // the locations these instructions branch to.
+ size_t dex_offset = 0;
+ while (code_ptr < code_end) {
+ const Instruction& instruction = *Instruction::At(code_ptr);
+ if (instruction.IsBranch()) {
+ int32_t target = instruction.GetTargetOffset() + dex_offset;
+ // Create a block for the target instruction.
+ if (FindBlockStartingAt(target) == nullptr) {
+ block = new (arena_) HBasicBlock(graph_);
+ branch_targets_.Put(target, block);
+ }
+ dex_offset += instruction.SizeInCodeUnits();
+ code_ptr += instruction.SizeInCodeUnits();
+ if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
+ block = new (arena_) HBasicBlock(graph_);
+ branch_targets_.Put(dex_offset, block);
+ }
+ } else {
+ code_ptr += instruction.SizeInCodeUnits();
+ dex_offset += instruction.SizeInCodeUnits();
+ }
+ }
+}
+
+HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
+ DCHECK_GE(index, 0);
+ return branch_targets_.Get(index);
+}
+
+bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
+ if (current_block_ == nullptr) return true; // Dead code
+
switch (instruction.Opcode()) {
case Instruction::RETURN_VOID:
- current_block_->AddInstruction(new (arena_) HReturnVoid(current_block_));
+ current_block_->AddInstruction(new (arena_) HReturnVoid());
current_block_->AddSuccessor(exit_block_);
current_block_ = nullptr;
break;
+ case Instruction::IF_EQ: {
+ // TODO: Read the dex register.
+ HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
+ DCHECK(target != nullptr);
+ current_block_->AddInstruction(new (arena_) HIf());
+ current_block_->AddSuccessor(target);
+ target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
+ DCHECK(target != nullptr);
+ current_block_->AddSuccessor(target);
+ current_block_ = nullptr;
+ break;
+ }
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32: {
+ HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
+ DCHECK(target != nullptr);
+ current_block_->AddInstruction(new (arena_) HGoto());
+ current_block_->AddSuccessor(target);
+ current_block_ = nullptr;
+ break;
+ }
+ case Instruction::NOP:
+ break;
default:
return false;
}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 3e94fba228..fbeb7a7dab 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_BUILDER_H_
#include "utils/allocation.h"
+#include "utils/growable_array.h"
namespace art {
@@ -30,6 +31,7 @@ class HGraphBuilder : public ValueObject {
public:
explicit HGraphBuilder(ArenaAllocator* arena)
: arena_(arena),
+ branch_targets_(arena, 0),
entry_block_(nullptr),
exit_block_(nullptr),
current_block_(nullptr),
@@ -41,9 +43,21 @@ class HGraphBuilder : public ValueObject {
// Analyzes the dex instruction and adds HInstruction to the graph
// to execute that instruction. Returns whether the instruction can
// be handled.
- bool AnalyzeDexInstruction(const Instruction& instruction);
+ bool AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset);
+
+ // Finds all instructions that start a new block, and populates branch_targets_ with
+ // the newly created blocks.
+ void ComputeBranchTargets(const uint16_t* start, const uint16_t* end);
+ void MaybeUpdateCurrentBlock(size_t index);
+ HBasicBlock* FindBlockStartingAt(int32_t index) const;
ArenaAllocator* const arena_;
+
+ // A list of the size of the dex code holding block information for
+ // the method. If an entry contains a block, then the dex instruction
+ // starting at that entry is the first instruction of a new block.
+ GrowableArray<HBasicBlock*> branch_targets_;
+
HBasicBlock* entry_block_;
HBasicBlock* exit_block_;
HBasicBlock* current_block_;
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
new file mode 100644
index 0000000000..30f288ff54
--- /dev/null
+++ b/compiler/optimizing/dominator_test.cc
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ */
+
+#include "builder.h"
+#include "dex_instruction.h"
+#include "nodes.h"
+#include "utils/arena_allocator.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+static void TestCode(const uint16_t* data, int length, const int* blocks, size_t blocks_length) {
+ ArenaPool pool;
+ ArenaAllocator allocator(&pool);
+ HGraphBuilder builder(&allocator);
+ HGraph* graph = builder.BuildGraph(data, data + length);
+ ASSERT_NE(graph, nullptr);
+ graph->BuildDominatorTree();
+ ASSERT_EQ(graph->blocks()->Size(), blocks_length);
+ for (size_t i = 0; i < blocks_length; i++) {
+ if (blocks[i] == -1) {
+ ASSERT_EQ(nullptr, graph->blocks()->Get(i)->dominator());
+ } else {
+ ASSERT_NE(nullptr, graph->blocks()->Get(i)->dominator());
+ ASSERT_EQ(blocks[i], graph->blocks()->Get(i)->dominator()->block_id());
+ }
+ }
+}
+
+TEST(OptimizerTest, ReturnVoid) {
+ const uint16_t data[] = {
+ Instruction::RETURN_VOID // Block number 1
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG1) {
+ const uint16_t data[] = {
+ Instruction::GOTO | 0x100, // Block number 1
+ Instruction::RETURN_VOID // Block number 2
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 2
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG2) {
+ const uint16_t data[] = {
+ Instruction::GOTO | 0x100, // Block number 1
+ Instruction::GOTO | 0x100, // Block number 2
+ Instruction::RETURN_VOID // Block number 3
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 2,
+ 3
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG3) {
+ const uint16_t data1[] = {
+ Instruction::GOTO | 0x200, // Block number 1
+ Instruction::RETURN_VOID, // Block number 2
+ Instruction::GOTO | 0xFF00 // Block number 3
+ };
+ const int dominators[] = {
+ -1,
+ 0,
+ 3,
+ 1,
+ 2
+ };
+
+ TestCode(data1, sizeof(data1) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+
+ const uint16_t data2[] = {
+ Instruction::GOTO_16, 3,
+ Instruction::RETURN_VOID,
+ Instruction::GOTO_16, 0xFFFF
+ };
+
+ TestCode(data2, sizeof(data2) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+
+ const uint16_t data3[] = {
+ Instruction::GOTO_32, 4, 0,
+ Instruction::RETURN_VOID,
+ Instruction::GOTO_32, 0xFFFF, 0xFFFF
+ };
+
+ TestCode(data3, sizeof(data3) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG4) {
+ const uint16_t data1[] = {
+ Instruction::NOP,
+ Instruction::GOTO | 0xFF00
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ -1
+ };
+
+ TestCode(data1, sizeof(data1) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+
+ const uint16_t data2[] = {
+ Instruction::GOTO_32, 0, 0
+ };
+
+ TestCode(data2, sizeof(data2) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG5) {
+ const uint16_t data[] = {
+ Instruction::RETURN_VOID, // Block number 1
+ Instruction::GOTO | 0x100, // Dead block
+ Instruction::GOTO | 0xFE00 // Block number 2
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ -1,
+ 1
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG6) {
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 3,
+ Instruction::GOTO | 0x100,
+ Instruction::RETURN_VOID
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 1,
+ 3
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG7) {
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 3, // Block number 1
+ Instruction::GOTO | 0x100, // Block number 2
+ Instruction::GOTO | 0xFF00 // Block number 3
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 1,
+ -1 // exit block is not dominated by any block due to the spin loop.
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG8) {
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 3, // Block number 1
+ Instruction::GOTO | 0x200, // Block number 2
+ Instruction::GOTO | 0x100, // Block number 3
+ Instruction::GOTO | 0xFF00 // Block number 4
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 1,
+ 1,
+ -1 // exit block is not dominated by any block due to the spin loop.
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG9) {
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 3, // Block number 1
+ Instruction::GOTO | 0x200, // Block number 2
+ Instruction::GOTO | 0x100, // Block number 3
+ Instruction::GOTO | 0xFE00 // Block number 4
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 1,
+ 1,
+ -1 // exit block is not dominated by any block due to the spin loop.
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+TEST(OptimizerTest, CFG10) {
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 6, // Block number 1
+ Instruction::IF_EQ, 3, // Block number 2
+ Instruction::GOTO | 0x100, // Block number 3
+ Instruction::GOTO | 0x100, // Block number 4
+ Instruction::RETURN_VOID // Block number 5
+ };
+
+ const int dominators[] = {
+ -1,
+ 0,
+ 1,
+ 2,
+ 2,
+ 1,
+ 5 // Block number 5 dominates exit block
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), dominators, sizeof(dominators) / sizeof(int));
+}
+
+} // namespace art
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index e7e9f4746a..9ec8e89ff6 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -24,6 +24,103 @@ void HGraph::AddBlock(HBasicBlock* block) {
blocks_.Add(block);
}
+void HGraph::FindBackEdges(ArenaBitVector* visited) const {
+ ArenaBitVector visiting(arena_, blocks_.Size(), false);
+ VisitBlockForBackEdges(GetEntryBlock(), visited, &visiting);
+}
+
+void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) const {
+ for (size_t i = 0; i < blocks_.Size(); i++) {
+ if (!visited.IsBitSet(i)) {
+ HBasicBlock* block = blocks_.Get(i);
+ for (size_t j = 0; j < block->successors()->Size(); j++) {
+ block->successors()->Get(j)->RemovePredecessor(block);
+ }
+ }
+ }
+}
+
+void HGraph::VisitBlockForBackEdges(HBasicBlock* block,
+ ArenaBitVector* visited,
+ ArenaBitVector* visiting) const {
+ int id = block->block_id();
+ if (visited->IsBitSet(id)) return;
+
+ visited->SetBit(id);
+ visiting->SetBit(id);
+ for (size_t i = 0; i < block->successors()->Size(); i++) {
+ HBasicBlock* successor = block->successors()->Get(i);
+ if (visiting->IsBitSet(successor->block_id())) {
+ successor->AddBackEdge(block);
+ } else {
+ VisitBlockForBackEdges(successor, visited, visiting);
+ }
+ }
+ visiting->ClearBit(id);
+}
+
+void HGraph::BuildDominatorTree() {
+ ArenaBitVector visited(arena_, blocks_.Size(), false);
+
+ // (1) Find the back edges in the graph doing a DFS traversal.
+ FindBackEdges(&visited);
+
+ // (2) Remove blocks not visited during the initial DFS.
+ // Step (3) requires dead blocks to be removed from the
+ // predecessors list of live blocks.
+ RemoveDeadBlocks(visited);
+
+ // (3) Compute the immediate dominator of each block. We visit
+ // the successors of a block only when all its forward branches
+ // have been processed.
+ GrowableArray<size_t> visits(arena_, blocks_.Size());
+ visits.SetSize(blocks_.Size());
+ HBasicBlock* entry = GetEntryBlock();
+ dominator_order_.Add(entry);
+ for (size_t i = 0; i < entry->successors()->Size(); i++) {
+ VisitBlockForDominatorTree(entry->successors()->Get(i), entry, &visits);
+ }
+}
+
+HBasicBlock* HGraph::FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const {
+ ArenaBitVector visited(arena_, blocks_.Size(), false);
+ // Walk the dominator tree of the first block and mark the visited blocks.
+ while (first != nullptr) {
+ visited.SetBit(first->block_id());
+ first = first->dominator();
+ }
+ // Walk the dominator tree of the second block until a marked block is found.
+ while (second != nullptr) {
+ if (visited.IsBitSet(second->block_id())) {
+ return second;
+ }
+ second = second->dominator();
+ }
+ LOG(ERROR) << "Could not find common dominator";
+ return nullptr;
+}
+
+void HGraph::VisitBlockForDominatorTree(HBasicBlock* block,
+ HBasicBlock* predecessor,
+ GrowableArray<size_t>* visits) {
+ if (block->dominator() == nullptr) {
+ block->set_dominator(predecessor);
+ } else {
+ block->set_dominator(FindCommonDominator(block->dominator(), predecessor));
+ }
+
+ visits->Increment(block->block_id());
+ // Once all the forward edges have been visited, we know the immediate
+ // dominator of the block. We can then start visiting its successors.
+ if (visits->Get(block->block_id()) ==
+ block->predecessors()->Size() - block->NumberOfBackEdges()) {
+ dominator_order_.Add(block);
+ for (size_t i = 0; i < block->successors()->Size(); i++) {
+ VisitBlockForDominatorTree(block->successors()->Get(i), block, visits);
+ }
+ }
+}
+
void HBasicBlock::AddInstruction(HInstruction* instruction) {
if (first_instruction_ == nullptr) {
DCHECK(last_instruction_ == nullptr);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3d1c25e71b..3d5d531cfe 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_NODES_H_
#include "utils/allocation.h"
+#include "utils/arena_bit_vector.h"
#include "utils/growable_array.h"
namespace art {
@@ -29,26 +30,67 @@ class HGraphVisitor;
static const int kDefaultNumberOfBlocks = 8;
static const int kDefaultNumberOfSuccessors = 2;
static const int kDefaultNumberOfPredecessors = 2;
+static const int kDefaultNumberOfBackEdges = 1;
// Control-flow graph of a method. Contains a list of basic blocks.
class HGraph : public ArenaObject {
public:
explicit HGraph(ArenaAllocator* arena)
: arena_(arena),
- blocks_(arena, kDefaultNumberOfBlocks) { }
+ blocks_(arena, kDefaultNumberOfBlocks),
+ dominator_order_(arena, kDefaultNumberOfBlocks) { }
ArenaAllocator* arena() const { return arena_; }
const GrowableArray<HBasicBlock*>* blocks() const { return &blocks_; }
void AddBlock(HBasicBlock* block);
+ void BuildDominatorTree();
private:
+ HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
+ void VisitBlockForDominatorTree(HBasicBlock* block,
+ HBasicBlock* predecessor,
+ GrowableArray<size_t>* visits);
+ void FindBackEdges(ArenaBitVector* visited) const;
+ void VisitBlockForBackEdges(HBasicBlock* block,
+ ArenaBitVector* visited,
+ ArenaBitVector* visiting) const;
+ void RemoveDeadBlocks(const ArenaBitVector& visited) const;
+
+ HBasicBlock* GetEntryBlock() const { return blocks_.Get(0); }
+
ArenaAllocator* const arena_;
+
+ // List of blocks in insertion order.
GrowableArray<HBasicBlock*> blocks_;
+ // List of blocks to perform a pre-order dominator tree traversal.
+ GrowableArray<HBasicBlock*> dominator_order_;
+
DISALLOW_COPY_AND_ASSIGN(HGraph);
};
+class HLoopInformation : public ArenaObject {
+ public:
+ HLoopInformation(HBasicBlock* header, HGraph* graph)
+ : header_(header),
+ back_edges_(graph->arena(), kDefaultNumberOfBackEdges) { }
+
+ void AddBackEdge(HBasicBlock* back_edge) {
+ back_edges_.Add(back_edge);
+ }
+
+ int NumberOfBackEdges() const {
+ return back_edges_.Size();
+ }
+
+ private:
+ HBasicBlock* header_;
+ GrowableArray<HBasicBlock*> back_edges_;
+
+ DISALLOW_COPY_AND_ASSIGN(HLoopInformation);
+};
+
// A block in a method. Contains the list of instructions represented
// as a double linked list. Each block knows its predecessors and
// successors.
@@ -60,6 +102,8 @@ class HBasicBlock : public ArenaObject {
successors_(graph->arena(), kDefaultNumberOfSuccessors),
first_instruction_(nullptr),
last_instruction_(nullptr),
+ loop_information_(nullptr),
+ dominator_(nullptr),
block_id_(-1) { }
const GrowableArray<HBasicBlock*>* predecessors() const {
@@ -70,11 +114,27 @@ class HBasicBlock : public ArenaObject {
return &successors_;
}
+ void AddBackEdge(HBasicBlock* back_edge) {
+ if (loop_information_ == nullptr) {
+ loop_information_ = new (graph_->arena()) HLoopInformation(this, graph_);
+ }
+ loop_information_->AddBackEdge(back_edge);
+ }
+
HGraph* graph() const { return graph_; }
int block_id() const { return block_id_; }
void set_block_id(int id) { block_id_ = id; }
+ HBasicBlock* dominator() const { return dominator_; }
+ void set_dominator(HBasicBlock* dominator) { dominator_ = dominator; }
+
+ int NumberOfBackEdges() const {
+ return loop_information_ == nullptr
+ ? 0
+ : loop_information_->NumberOfBackEdges();
+ }
+
HInstruction* first_instruction() const { return first_instruction_; }
HInstruction* last_instruction() const { return last_instruction_; }
@@ -83,6 +143,10 @@ class HBasicBlock : public ArenaObject {
block->predecessors_.Add(this);
}
+ void RemovePredecessor(HBasicBlock* block) {
+ predecessors_.Delete(block);
+ }
+
void AddInstruction(HInstruction* instruction);
private:
@@ -91,6 +155,8 @@ class HBasicBlock : public ArenaObject {
GrowableArray<HBasicBlock*> successors_;
HInstruction* first_instruction_;
HInstruction* last_instruction_;
+ HLoopInformation* loop_information_;
+ HBasicBlock* dominator_;
int block_id_;
DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
@@ -99,6 +165,7 @@ class HBasicBlock : public ArenaObject {
#define FOR_EACH_INSTRUCTION(M) \
M(Exit) \
M(Goto) \
+ M(If) \
M(ReturnVoid) \
#define DECLARE_INSTRUCTION(type) \
@@ -107,9 +174,7 @@ class HBasicBlock : public ArenaObject {
class HInstruction : public ArenaObject {
public:
- explicit HInstruction(HBasicBlock* block)
- : previous_(nullptr),
- next_(nullptr) { }
+ HInstruction() : previous_(nullptr), next_(nullptr) { }
virtual ~HInstruction() { }
HInstruction* next() const { return next_; }
@@ -199,9 +264,7 @@ class EmbeddedArray<T, 0> {
template<intptr_t N>
class HTemplateInstruction: public HInstruction {
public:
- HTemplateInstruction<N>(HBasicBlock* block)
- : HInstruction(block),
- inputs_() { }
+ HTemplateInstruction<N>() : inputs_() { }
virtual ~HTemplateInstruction() { }
virtual intptr_t InputCount() const { return N; }
@@ -215,7 +278,7 @@ class HTemplateInstruction: public HInstruction {
// instruction that branches to the exit block.
class HReturnVoid : public HTemplateInstruction<0> {
public:
- explicit HReturnVoid(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+ HReturnVoid() { }
DECLARE_INSTRUCTION(ReturnVoid)
@@ -228,7 +291,7 @@ class HReturnVoid : public HTemplateInstruction<0> {
// exit block.
class HExit : public HTemplateInstruction<0> {
public:
- explicit HExit(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+ HExit() { }
DECLARE_INSTRUCTION(Exit)
@@ -239,7 +302,7 @@ class HExit : public HTemplateInstruction<0> {
// Jumps from one block to another.
class HGoto : public HTemplateInstruction<0> {
public:
- explicit HGoto(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+ HGoto() { }
DECLARE_INSTRUCTION(Goto)
@@ -247,6 +310,19 @@ class HGoto : public HTemplateInstruction<0> {
DISALLOW_COPY_AND_ASSIGN(HGoto);
};
+// Conditional branch. A block ending with an HIf instruction must have
+// two successors.
+// TODO: Make it take an input.
+class HIf : public HTemplateInstruction<0> {
+ public:
+ HIf() { }
+
+ DECLARE_INSTRUCTION(If)
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HIf);
+};
+
class HGraphVisitor : public ValueObject {
public:
explicit HGraphVisitor(HGraph* graph) : graph_(graph) { }
diff --git a/compiler/optimizing/pretty_printer.h b/compiler/optimizing/pretty_printer.h
index 62a5a2c0e0..d4b61651dc 100644
--- a/compiler/optimizing/pretty_printer.h
+++ b/compiler/optimizing/pretty_printer.h
@@ -34,6 +34,24 @@ class HPrettyPrinter : public HGraphVisitor {
virtual void VisitBasicBlock(HBasicBlock* block) {
PrintString("BasicBlock ");
PrintInt(block->block_id());
+ const GrowableArray<HBasicBlock*>* blocks = block->predecessors();
+ if (!blocks->IsEmpty()) {
+ PrintString(", pred: ");
+ for (size_t i = 0; i < blocks->Size() -1; i++) {
+ PrintInt(blocks->Get(i)->block_id());
+ PrintString(", ");
+ }
+ PrintInt(blocks->Peek()->block_id());
+ }
+ blocks = block->successors();
+ if (!blocks->IsEmpty()) {
+ PrintString(", succ: ");
+ for (size_t i = 0; i < blocks->Size() - 1; i++) {
+ PrintInt(blocks->Get(i)->block_id());
+ PrintString(", ");
+ }
+ PrintInt(blocks->Peek()->block_id());
+ }
PrintNewLine();
HGraphVisitor::VisitBasicBlock(block);
}
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 81a0d915aa..4c8201e53e 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -25,19 +25,10 @@
namespace art {
-const uint16_t data[] = { Instruction::RETURN_VOID };
-
-const char* expected =
- "BasicBlock 0\n"
- " Goto\n"
- "BasicBlock 1\n"
- " ReturnVoid\n"
- "BasicBlock 2\n"
- " Exit\n";
-
class StringPrettyPrinter : public HPrettyPrinter {
public:
- explicit StringPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") { }
+ explicit StringPrettyPrinter(HGraph* graph)
+ : HPrettyPrinter(graph), str_(""), current_block_(nullptr) { }
virtual void PrintInt(int value) {
str_ += StringPrintf("%d", value);
@@ -55,33 +46,213 @@ class StringPrettyPrinter : public HPrettyPrinter {
std::string str() const { return str_; }
+ virtual void VisitBasicBlock(HBasicBlock* block) {
+ current_block_ = block;
+ HPrettyPrinter::VisitBasicBlock(block);
+ }
+
+ virtual void VisitGoto(HGoto* gota) {
+ str_ += " Goto ";
+ PrintInt(current_block_->successors()->Get(0)->block_id());
+ PrintNewLine();
+ }
+
private:
std::string str_;
+ HBasicBlock* current_block_;
+
DISALLOW_COPY_AND_ASSIGN(StringPrettyPrinter);
};
-TEST(OptimizerTest, ReturnVoid) {
+
+static void TestCode(const uint16_t* data, int length, const char* expected) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HGraphBuilder builder(&allocator);
- HGraph* graph = builder.BuildGraph(data, data + 1);
+ HGraph* graph = builder.BuildGraph(data, data + length);
ASSERT_NE(graph, nullptr);
StringPrettyPrinter printer(graph);
printer.VisitInsertionOrder();
ASSERT_STREQ(expected, printer.str().c_str());
+}
+
+TEST(PrettyPrinterTest, ReturnVoid) {
+ const uint16_t data[] = { Instruction::RETURN_VOID };
+
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 2\n"
+ " ReturnVoid\n"
+ "BasicBlock 2, pred: 1\n"
+ " Exit\n";
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG1) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 2\n"
+ " Goto 2\n"
+ "BasicBlock 2, pred: 1, succ: 3\n"
+ " ReturnVoid\n"
+ "BasicBlock 3, pred: 2\n"
+ " Exit\n";
+
+ const uint16_t data[] = {
+ Instruction::GOTO | 0x100,
+ Instruction::RETURN_VOID
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG2) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 2\n"
+ " Goto 2\n"
+ "BasicBlock 2, pred: 1, succ: 3\n"
+ " Goto 3\n"
+ "BasicBlock 3, pred: 2, succ: 4\n"
+ " ReturnVoid\n"
+ "BasicBlock 4, pred: 3\n"
+ " Exit\n";
+
+ const uint16_t data[] = {
+ Instruction::GOTO | 0x100,
+ Instruction::GOTO | 0x100,
+ Instruction::RETURN_VOID
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG3) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 3\n"
+ " Goto 3\n"
+ "BasicBlock 2, pred: 3, succ: 4\n"
+ " ReturnVoid\n"
+ "BasicBlock 3, pred: 1, succ: 2\n"
+ " Goto 2\n"
+ "BasicBlock 4, pred: 2\n"
+ " Exit\n";
+
+ const uint16_t data1[] = {
+ Instruction::GOTO | 0x200,
+ Instruction::RETURN_VOID,
+ Instruction::GOTO | 0xFF00
+ };
+
+ TestCode(data1, sizeof(data1) / sizeof(uint16_t), expected);
+
+ const uint16_t data2[] = {
+ Instruction::GOTO_16, 3,
+ Instruction::RETURN_VOID,
+ Instruction::GOTO_16, 0xFFFF
+ };
+
+ TestCode(data2, sizeof(data2) / sizeof(uint16_t), expected);
+
+ const uint16_t data3[] = {
+ Instruction::GOTO_32, 4, 0,
+ Instruction::RETURN_VOID,
+ Instruction::GOTO_32, 0xFFFF, 0xFFFF
+ };
+
+ TestCode(data3, sizeof(data3) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG4) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, 1, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 2\n"
+ " Exit\n";
+
+ const uint16_t data1[] = {
+ Instruction::NOP,
+ Instruction::GOTO | 0xFF00
+ };
+
+ TestCode(data1, sizeof(data1) / sizeof(uint16_t), expected);
+
+ const uint16_t data2[] = {
+ Instruction::GOTO_32, 0, 0
+ };
+
+ TestCode(data2, sizeof(data2) / sizeof(uint16_t), expected);
+}
+
+TEST(PrettyPrinterTest, CFG5) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, 2, succ: 3\n"
+ " ReturnVoid\n"
+ "BasicBlock 2, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 3, pred: 1\n"
+ " Exit\n";
- const GrowableArray<HBasicBlock*>* blocks = graph->blocks();
- ASSERT_EQ(blocks->Get(0)->predecessors()->Size(), (size_t)0);
- ASSERT_EQ(blocks->Get(1)->predecessors()->Size(), (size_t)1);
- ASSERT_EQ(blocks->Get(1)->predecessors()->Get(0), blocks->Get(0));
- ASSERT_EQ(blocks->Get(2)->predecessors()->Size(), (size_t)1);
- ASSERT_EQ(blocks->Get(2)->predecessors()->Get(0), blocks->Get(1));
-
- ASSERT_EQ(blocks->Get(0)->successors()->Size(), (size_t)1);
- ASSERT_EQ(blocks->Get(1)->successors()->Get(0), blocks->Get(2));
- ASSERT_EQ(blocks->Get(1)->successors()->Size(), (size_t)1);
- ASSERT_EQ(blocks->Get(1)->successors()->Get(0), blocks->Get(2));
- ASSERT_EQ(blocks->Get(2)->successors()->Size(), (size_t)0);
+ const uint16_t data[] = {
+ Instruction::RETURN_VOID,
+ Instruction::GOTO | 0x100,
+ Instruction::GOTO | 0xFE00
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
}
+TEST(OptimizerTest, CFG6) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 3, 2\n"
+ " If\n"
+ "BasicBlock 2, pred: 1, succ: 3\n"
+ " Goto 3\n"
+ "BasicBlock 3, pred: 1, 2, succ: 4\n"
+ " ReturnVoid\n"
+ "BasicBlock 4, pred: 3\n"
+ " Exit\n";
+
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 3,
+ Instruction::GOTO | 0x100,
+ Instruction::RETURN_VOID
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
+
+TEST(OptimizerTest, CFG7) {
+ const char* expected =
+ "BasicBlock 0, succ: 1\n"
+ " Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 3, 2\n"
+ " If\n"
+ "BasicBlock 2, pred: 1, 3, succ: 3\n"
+ " Goto 3\n"
+ "BasicBlock 3, pred: 1, 2, succ: 2\n"
+ " Goto 2\n"
+ "BasicBlock 4\n"
+ " Exit\n";
+
+ const uint16_t data[] = {
+ Instruction::IF_EQ, 3,
+ Instruction::GOTO | 0x100,
+ Instruction::GOTO | 0xFF00
+ };
+
+ TestCode(data, sizeof(data) / sizeof(uint16_t), expected);
+}
} // namespace art
diff --git a/compiler/output_stream_test.cc b/compiler/output_stream_test.cc
index a957ee375a..290bf2519d 100644
--- a/compiler/output_stream_test.cc
+++ b/compiler/output_stream_test.cc
@@ -14,15 +14,16 @@
* limitations under the License.
*/
-#include "base/logging.h"
-#include "buffered_output_stream.h"
-#include "common_test.h"
#include "file_output_stream.h"
#include "vector_output_stream.h"
+#include "base/logging.h"
+#include "buffered_output_stream.h"
+#include "common_runtime_test.h"
+
namespace art {
-class OutputStreamTest : public CommonTest {
+class OutputStreamTest : public CommonRuntimeTest {
protected:
void CheckOffset(off_t expected) {
off_t actual = output_stream_->Seek(0, kSeekCurrent);
diff --git a/compiler/sea_ir/ir/regions_test.cc b/compiler/sea_ir/ir/regions_test.cc
index 8ca51e4851..95bd31075e 100644
--- a/compiler/sea_ir/ir/regions_test.cc
+++ b/compiler/sea_ir/ir/regions_test.cc
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#include "common_test.h"
+#include "common_compiler_test.h"
#include "sea_ir/ir/sea.h"
using utils::ScopedHashtable;
namespace sea_ir {
-class RegionsTest : public art::CommonTest {
-};
+class RegionsTest : public art::CommonCompilerTest {};
TEST_F(RegionsTest, Basics) {
sea_ir::SeaGraph sg(*java_lang_dex_file_);
diff --git a/compiler/sea_ir/types/type_data_test.cc b/compiler/sea_ir/types/type_data_test.cc
index f7a5362fa4..42c6973c61 100644
--- a/compiler/sea_ir/types/type_data_test.cc
+++ b/compiler/sea_ir/types/type_data_test.cc
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-#include "common_test.h"
+#include "common_compiler_test.h"
#include "sea_ir/types/types.h"
namespace sea_ir {
-class TypeDataTest : public art::CommonTest {
-};
+class TypeDataTest : public art::CommonCompilerTest {};
TEST_F(TypeDataTest, Basics) {
TypeData td;
diff --git a/compiler/sea_ir/types/type_inference_visitor_test.cc b/compiler/sea_ir/types/type_inference_visitor_test.cc
index 77acb3d277..ccb699137e 100644
--- a/compiler/sea_ir/types/type_inference_visitor_test.cc
+++ b/compiler/sea_ir/types/type_inference_visitor_test.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "common_test.h"
+#include "common_compiler_test.h"
#include "sea_ir/types/type_inference_visitor.h"
#include "sea_ir/ir/sea.h"
@@ -31,8 +31,7 @@ class TestInstructionNode:public InstructionNode {
std::vector<InstructionNode*> producers_;
};
-class TypeInferenceVisitorTest : public art::CommonTest {
-};
+class TypeInferenceVisitorTest : public art::CommonCompilerTest {};
TEST_F(TypeInferenceVisitorTest, MergeIntWithByte) {
TypeData td;
diff --git a/compiler/utils/arena_allocator_test.cc b/compiler/utils/arena_allocator_test.cc
index b76fe74988..71565407a2 100644
--- a/compiler/utils/arena_allocator_test.cc
+++ b/compiler/utils/arena_allocator_test.cc
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include "dex/arena_bit_vector.h"
#include "gtest/gtest.h"
#include "utils/arena_allocator.h"
+#include "utils/arena_bit_vector.h"
namespace art {
diff --git a/compiler/dex/arena_bit_vector.cc b/compiler/utils/arena_bit_vector.cc
index 1b37b7149e..220ff14baa 100644
--- a/compiler/dex/arena_bit_vector.cc
+++ b/compiler/utils/arena_bit_vector.cc
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "compiler_internals.h"
-#include "dex_file-inl.h"
+#include "arena_allocator.h"
+#include "arena_bit_vector.h"
namespace art {
@@ -42,16 +42,8 @@ class ArenaBitVectorAllocator : public Allocator {
ArenaBitVector::ArenaBitVector(ArenaAllocator* arena, unsigned int start_bits,
bool expandable, OatBitMapKind kind)
- : BitVector(start_bits, expandable, new (arena) ArenaBitVectorAllocator(arena)), kind_(kind) {}
-
-BasicBlock* ArenaBitVector::BasicBlockIterator::Next() {
- int idx = internal_iterator_.Next();
-
- if (idx == -1) {
- return nullptr;
- }
-
- return mir_graph_->GetBasicBlock(idx);
+ : BitVector(start_bits, expandable, new (arena) ArenaBitVectorAllocator(arena)), kind_(kind) {
+ UNUSED(kind_);
}
} // namespace art
diff --git a/compiler/dex/arena_bit_vector.h b/compiler/utils/arena_bit_vector.h
index cdd5c68111..6c1461727a 100644
--- a/compiler/dex/arena_bit_vector.h
+++ b/compiler/utils/arena_bit_vector.h
@@ -14,51 +14,42 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DEX_ARENA_BIT_VECTOR_H_
-#define ART_COMPILER_DEX_ARENA_BIT_VECTOR_H_
+#ifndef ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
+#define ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
#include "base/bit_vector.h"
-#include "compiler_enums.h"
#include "utils/arena_allocator.h"
-#include "compiler_ir.h"
namespace art {
-// Forward declaration
-class MIRGraph;
+// Type of growable bitmap for memory tuning.
+enum OatBitMapKind {
+ kBitMapMisc = 0,
+ kBitMapUse,
+ kBitMapDef,
+ kBitMapLiveIn,
+ kBitMapBMatrix,
+ kBitMapDominators,
+ kBitMapIDominated,
+ kBitMapDomFrontier,
+ kBitMapPhi,
+ kBitMapTmpBlocks,
+ kBitMapInputBlocks,
+ kBitMapRegisterV,
+ kBitMapTempSSARegisterV,
+ kBitMapNullCheck,
+ kBitMapTmpBlockV,
+ kBitMapPredecessors,
+ kNumBitMapKinds
+};
+
+std::ostream& operator<<(std::ostream& os, const OatBitMapKind& kind);
/*
* A BitVector implementation that uses Arena allocation.
*/
class ArenaBitVector : public BitVector {
public:
- /**
- * @class BasicBlockIterator
- * @brief Helper class to get the BasicBlocks when iterating through the ArenaBitVector.
- */
- class BasicBlockIterator {
- public:
- explicit BasicBlockIterator(ArenaBitVector* bv, MIRGraph* mir_graph)
- : mir_graph_(mir_graph),
- internal_iterator_(bv) {}
-
- explicit BasicBlockIterator(ArenaBitVector* bv, CompilationUnit* c_unit)
- : mir_graph_(c_unit->mir_graph.get()),
- internal_iterator_(bv) {}
-
- BasicBlock* Next();
-
- static void* operator new(size_t size, ArenaAllocator* arena) {
- return arena->Alloc(sizeof(ArenaBitVector::BasicBlockIterator),
- ArenaAllocator::kAllocGrowableArray);
- };
- static void operator delete(void* p) {} // Nop.
-
- private:
- MIRGraph* const mir_graph_;
- Iterator internal_iterator_;
- };
-
ArenaBitVector(ArenaAllocator* arena, uint32_t start_bits, bool expandable,
OatBitMapKind kind = kBitMapMisc);
~ArenaBitVector() {}
@@ -75,4 +66,4 @@ class ArenaBitVector : public BitVector {
} // namespace art
-#endif // ART_COMPILER_DEX_ARENA_BIT_VECTOR_H_
+#endif // ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
diff --git a/compiler/utils/arm/managed_register_arm.cc b/compiler/utils/arm/managed_register_arm.cc
index 57c23059de..1fdc110dcf 100644
--- a/compiler/utils/arm/managed_register_arm.cc
+++ b/compiler/utils/arm/managed_register_arm.cc
@@ -21,16 +21,6 @@
namespace art {
namespace arm {
-// We need all registers for caching of locals.
-// Register R9 .. R15 are reserved.
-static const int kNumberOfAvailableCoreRegisters = (R8 - R0) + 1;
-static const int kNumberOfAvailableSRegisters = kNumberOfSRegisters;
-static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
-static const int kNumberOfAvailableOverlappingDRegisters =
- kNumberOfOverlappingDRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
-
// Returns true if this managed-register overlaps the other managed-register.
bool ArmManagedRegister::Overlaps(const ArmManagedRegister& other) const {
if (IsNoRegister() || other.IsNoRegister()) return false;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index c9be4edbf8..296254d140 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -282,7 +282,9 @@ class AssemblerBuffer {
byte* cursor_;
byte* limit_;
AssemblerFixup* fixup_;
+#ifndef NDEBUG
bool fixups_processed_;
+#endif
// Head of linked list of slow paths
SlowPath* slow_path_;
diff --git a/compiler/utils/growable_array.h b/compiler/utils/growable_array.h
index b59187032e..82b6a607e7 100644
--- a/compiler/utils/growable_array.h
+++ b/compiler/utils/growable_array.h
@@ -161,6 +161,18 @@ class GrowableArray {
size_t Size() const { return num_used_; }
+ bool IsEmpty() const { return num_used_ == 0; }
+
+ T Pop() {
+ DCHECK_GE(num_used_, (size_t)0);
+ return elem_list_[--num_used_];
+ }
+
+ T Peek() const {
+ DCHECK_GE(num_used_, (size_t)0);
+ return elem_list_[num_used_ - 1];
+ }
+
void SetSize(size_t new_size) {
Resize(new_size);
num_used_ = new_size;
diff --git a/compiler/utils/mips/managed_register_mips.cc b/compiler/utils/mips/managed_register_mips.cc
index 195dafb0a1..5a8c0481a5 100644
--- a/compiler/utils/mips/managed_register_mips.cc
+++ b/compiler/utils/mips/managed_register_mips.cc
@@ -21,17 +21,6 @@
namespace art {
namespace mips {
-// These core registers are never available for allocation.
-static const Register kReservedCoreRegistersArray[] = { S0, S1 };
-
-// We need all registers for caching.
-static const int kNumberOfAvailableCoreRegisters = (S7 - T0) + 1;
-static const int kNumberOfAvailableFRegisters = kNumberOfFRegisters;
-static const int kNumberOfAvailableDRegisters = kNumberOfDRegisters;
-static const int kNumberOfAvailableOverlappingDRegisters =
- kNumberOfOverlappingDRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
bool MipsManagedRegister::Overlaps(const MipsManagedRegister& other) const {
if (IsNoRegister() || other.IsNoRegister()) return false;
CHECK(IsValidManagedRegister());
diff --git a/compiler/utils/scoped_hashtable_test.cc b/compiler/utils/scoped_hashtable_test.cc
index 68608f01d1..1c843ebef1 100644
--- a/compiler/utils/scoped_hashtable_test.cc
+++ b/compiler/utils/scoped_hashtable_test.cc
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include "common_test.h"
-#include "utils/scoped_hashtable.h"
+#include "scoped_hashtable.h"
+
+#include "common_runtime_test.h"
using utils::ScopedHashtable;
@@ -27,8 +28,7 @@ class Value {
int value_;
};
-class ScopedHashtableTest : public CommonTest {
-};
+class ScopedHashtableTest : public testing::Test {};
TEST_F(ScopedHashtableTest, Basics) {
ScopedHashtable<int, Value*> sht;
diff --git a/compiler/utils/x86/managed_register_x86.cc b/compiler/utils/x86/managed_register_x86.cc
index 4697d06136..7fae7a8b6f 100644
--- a/compiler/utils/x86/managed_register_x86.cc
+++ b/compiler/utils/x86/managed_register_x86.cc
@@ -21,19 +21,6 @@
namespace art {
namespace x86 {
-// These cpu registers are never available for allocation.
-static const Register kReservedCpuRegistersArray[] = { ESP };
-
-
-// We reduce the number of available registers for allocation in debug-code
-// mode in order to increase register pressure.
-
-// We need all registers for caching.
-static const int kNumberOfAvailableCpuRegisters = kNumberOfCpuRegisters;
-static const int kNumberOfAvailableXmmRegisters = kNumberOfXmmRegisters;
-static const int kNumberOfAvailableRegisterPairs = kNumberOfRegisterPairs;
-
-
// Define register pairs.
// This list must be kept in sync with the RegisterPair enum.
#define REGISTER_PAIR_LIST(P) \