diff options
author | 2013-01-30 14:08:26 -0800 | |
---|---|---|
committer | 2013-03-06 14:08:46 -0800 | |
commit | 265091e581c9f643b37e7966890911f09e223269 (patch) | |
tree | ae493ce6c3537aebc3a85f59a73500fa819a7baf | |
parent | 4c1c283a7410784e9cab309f868248690b788a9c (diff) |
Remove ExtractCodeAndPrelink and switch Portable to MCLinker
Change-Id: Ia2459c7da6b79e0a1c0f1148c6e28ad9cbbe27a2
63 files changed, 1813 insertions, 1532 deletions
diff --git a/Android.mk b/Android.mk index 38c0419fc2..16a2c12b64 100644 --- a/Android.mk +++ b/Android.mk @@ -313,25 +313,32 @@ dump-oat: dump-oat-core dump-oat-boot dump-oat-Calculator dump-oat-core: dump-oat-core-host dump-oat-core-target .PHONY: dump-oat-core-host +ifeq ($(ART_BUILD_HOST),true) dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(OATDUMP) $(OATDUMP) --image=$(HOST_CORE_IMG_OUT) --output=/tmp/core.host.oatdump.txt --host-prefix="" @echo Output in /tmp/core.host.oatdump.txt +endif .PHONY: dump-oat-core-target +ifeq ($(ART_BUILD_TARGET),true) dump-oat-core-target: $(TARGET_CORE_IMG_OUT) $(OATDUMP) $(OATDUMP) --image=$(TARGET_CORE_IMG_OUT) --output=/tmp/core.target.oatdump.txt @echo Output in /tmp/core.target.oatdump.txt +endif .PHONY: dump-oat-boot +ifeq ($(ART_BUILD_TARGET_NDEBUG),true) dump-oat-boot: $(TARGET_BOOT_IMG_OUT) $(OATDUMP) $(OATDUMP) --image=$(TARGET_BOOT_IMG_OUT) --output=/tmp/boot.oatdump.txt @echo Output in /tmp/boot.oatdump.txt +endif .PHONY: dump-oat-Calculator +ifeq ($(ART_BUILD_TARGET_NDEBUG),true) dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.apk.oat $(TARGET_BOOT_IMG_OUT) $(OATDUMP) $(OATDUMP) --oat-file=$< --output=/tmp/Calculator.oatdump.txt @echo Output in /tmp/Calculator.oatdump.txt - +endif ######################################################################## # cpplint target diff --git a/build/Android.common.mk b/build/Android.common.mk index f30cf013d3..43755b4309 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -141,7 +141,6 @@ LIBART_COMMON_SRC_FILES := \ src/common_throws.cc \ src/compiled_method.cc \ src/compiler/driver/compiler_driver.cc \ - src/compiler/llvm/procedure_linkage_table.cc \ src/compiler/llvm/runtime_support_llvm.cc \ src/debugger.cc \ src/dex_file.cc \ @@ -379,6 +378,7 @@ TEST_COMMON_SRC_FILES := \ src/compiler/jni/jni_compiler_test.cc \ src/dex_file_test.cc \ src/dex_instruction_visitor_test.cc \ + src/dex_method_iterator_test.cc \ src/elf_writer_test.cc \ src/exception_test.cc \ src/gc/space_bitmap_test.cc \ @@ -447,15 +447,21 @@ TEST_OAT_DIRECTORIES := \ ART_BUILD_TARGET := false ART_BUILD_HOST := false +ART_BUILD_NDEBUG := false +ART_BUILD_DEBUG := false ifeq ($(ART_BUILD_TARGET_NDEBUG),true) ART_BUILD_TARGET := true + ART_BUILD_NDEBUG := true endif ifeq ($(ART_BUILD_TARGET_DEBUG),true) ART_BUILD_TARGET := true + ART_BUILD_DEBUG := true endif ifeq ($(ART_BUILD_HOST_NDEBUG),true) ART_BUILD_HOST := true + ART_BUILD_NDEBUG := true endif ifeq ($(ART_BUILD_HOST_DEBUG),true) ART_BUILD_HOST := true + ART_BUILD_DEBUG := true endif diff --git a/build/Android.executable.mk b/build/Android.executable.mk index 730c9801c0..afb335eab5 100644 --- a/build/Android.executable.mk +++ b/build/Android.executable.mk @@ -112,13 +112,20 @@ ifeq ($(ART_BUILD_TARGET_DEBUG),true) $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),target,debug)) $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,debug)) endif -ifeq ($(ART_BUILD_HOST_NDEBUG),true) + +# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target. +ifeq ($(ART_BUILD_NDEBUG),true) $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,ndebug)) +endif +ifeq ($(ART_BUILD_NDEBUG),true) + $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug)) +endif + +ifeq ($(ART_BUILD_HOST_NDEBUG),true) $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,ndebug)) $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,ndebug)) endif ifeq ($(ART_BUILD_HOST_DEBUG),true) - $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug)) $(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,debug)) $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,debug)) endif diff --git a/build/Android.libart-compiler.mk b/build/Android.libart-compiler.mk index 9e11e22ba2..8f0ccf83d7 100644 --- a/build/Android.libart-compiler.mk +++ b/build/Android.libart-compiler.mk @@ -48,6 +48,7 @@ LIBART_COMPILER_SRC_FILES := \ src/compiler/dex/ralloc.cc \ src/compiler/dex/ssa_transformation.cc \ src/compiler/dex/write_elf.cc \ + src/compiler/driver/dex_compilation_unit.cc \ src/compiler/invoke_stubs/portable/stub_compiler.cc \ src/compiler/invoke_stubs/quick/jni_internal_arm.cc \ src/compiler/invoke_stubs/quick/jni_internal_mips.cc \ @@ -184,9 +185,22 @@ endif ifeq ($(ART_BUILD_TARGET_DEBUG),true) $(eval $(call build-libart-compiler,target,debug)) endif -ifeq ($(ART_BUILD_HOST_NDEBUG),true) +# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target. +ifeq ($(ART_BUILD_NDEBUG),true) $(eval $(call build-libart-compiler,host,ndebug)) endif -ifeq ($(ART_BUILD_HOST_DEBUG),true) +ifeq ($(ART_BUILD_DEBUG),true) $(eval $(call build-libart-compiler,host,debug)) endif + +# Rule to build /system/lib/libcompiler-rt.a +# Usually static libraries are not installed on the device. +ifeq ($(ART_USE_PORTABLE_COMPILER),true) +ifeq ($(ART_BUILD_TARGET),true) +# TODO: Move to external/compiler-rt +$(eval $(call copy-one-file, $(call intermediates-dir-for,STATIC_LIBRARIES,libcompiler-rt,,)/libcompiler-rt.a, $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler-rt.a)) + +$(DEX2OAT): $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler-rt.a + +endif +endif diff --git a/build/Android.libart.mk b/build/Android.libart.mk index 630f05a7e7..67461be907 100644 --- a/build/Android.libart.mk +++ b/build/Android.libart.mk @@ -120,9 +120,11 @@ endif ifeq ($(ART_BUILD_TARGET_DEBUG),true) $(eval $(call build-libart,target,debug)) endif -ifeq ($(ART_BUILD_HOST_NDEBUG),true) + +# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target. +ifeq ($(ART_BUILD_NDEBUG),true) $(eval $(call build-libart,host,ndebug)) endif -ifeq ($(ART_BUILD_HOST_DEBUG),true) +ifeq ($(ART_BUILD_DEBUG),true) $(eval $(call build-libart,host,debug)) endif diff --git a/build/Android.oat.mk b/build/Android.oat.mk index b4e1266495..feeede54c8 100644 --- a/build/Android.oat.mk +++ b/build/Android.oat.mk @@ -16,11 +16,19 @@ # DEX2OAT defined in build/core/config.mk DEX2OATD := $(HOST_OUT_EXECUTABLES)/dex2oatd$(HOST_EXECUTABLE_SUFFIX) + +LIBART_COMPILER := $(HOST_OUT_SHARED_LIBRARIES)/libart-compiler$(HOST_SHLIB_SUFFIX) +LIBARTD_COMPILER := $(HOST_OUT_SHARED_LIBRARIES)/libartd-compiler$(HOST_SHLIB_SUFFIX) + # TODO: for now, override with debug version for better error reporting DEX2OAT := $(DEX2OATD) +LIBART_COMPILER := $(LIBARTD_COMPILER) -DEX2OAT_DEPENDENCY := | $(DEX2OAT) # by default, do not run rerun dex2oat if the tool changes -# DEX2OAT_DEPENDENCY := $(DEX2OAT) # uncomment to force dex2oat to rerun on after all changes +# By default, do not run rerun dex2oat if the tool changes. +# Comment out the | to force dex2oat to rerun on after all changes. +DEX2OAT_DEPENDENCY := | +DEX2OAT_DEPENDENCY += $(DEX2OAT) +DEX2OAT_DEPENDENCY += $(LIBART_COMPILER) OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX) OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX) @@ -52,7 +60,7 @@ TARGET_CORE_IMG_OUT := $(ART_TEST_OUT)/core.art $(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY) @echo "host dex2oat: $@ ($?)" @mkdir -p $(dir $@) - $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=$(HOST_ARCH) + $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=$(HOST_ARCH) --host $(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY) @echo "target dex2oat: $@ ($?)" @@ -80,18 +88,22 @@ TARGET_BOOT_DEX_FILES := $(foreach jar,$(TARGET_BOOT_JARS),$(call intermediates- TARGET_BOOT_IMG_OUT := $(DEFAULT_DEX_PREOPT_IMAGE) TARGET_BOOT_OAT_OUT := $(patsubst %.art,%.oat,$(TARGET_BOOT_IMG_OUT)) TARGET_BOOT_OAT := $(subst $(PRODUCT_OUT),,$(TARGET_BOOT_OAT_OUT)) +TARGET_BOOT_OAT_UNSTRIPPED_OUT := $(TARGET_OUT_UNSTRIPPED)$(TARGET_BOOT_OAT) $(TARGET_BOOT_IMG_OUT): $(TARGET_BOOT_DEX_FILES) $(DEX2OAT_DEPENDENCY) @echo "target dex2oat: $@ ($?)" @mkdir -p $(dir $@) - $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --instruction-set=$(TARGET_ARCH) --host-prefix=$(PRODUCT_OUT) + @mkdir -p $(dir $(TARGET_BOOT_OAT_UNSTRIPPED_OUT)) + $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-symbols=$(TARGET_BOOT_OAT_UNSTRIPPED_OUT) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --instruction-set=$(TARGET_ARCH) --host-prefix=$(PRODUCT_OUT) + +$(TARGET_BOOT_OAT_UNSTRIPPED_OUT): $(TARGET_BOOT_IMG_OUT) -$(TARGET_BOOT_OAT_OUT): $(TARGET_BOOT_IMG_OUT) +$(TARGET_BOOT_OAT_OUT): $(TARGET_BOOT_OAT_UNSTRIPPED_OUT) -ifeq ($(ART_BUILD_TARGET),true) +ifeq ($(ART_BUILD_TARGET_NDEBUG),true) include $(CLEAR_VARS) LOCAL_MODULE := boot.art LOCAL_MODULE_TAGS := optional -LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_BOOT_IMG_OUT) +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_BOOT_IMG_OUT) $(TARGET_BOOT_OAT_OUT) include $(BUILD_PHONY_PACKAGE) endif diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk index 744a01d4a6..c2163bde58 100644 --- a/build/Android.oattest.mk +++ b/build/Android.oattest.mk @@ -23,27 +23,31 @@ ART_TEST_HOST_DEX_FILES := # $(2): input test directory # $(3): target output module path (default module path is used on host) define build-art-test-dex - include $(CLEAR_VARS) - LOCAL_MODULE := $(1)-$(2) - LOCAL_MODULE_TAGS := tests - LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2)) - LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS) - LOCAL_NO_STANDARD_LIBRARIES := true - LOCAL_MODULE_PATH := $(3) - LOCAL_DEX_PREOPT_IMAGE := $(TARGET_CORE_IMG_OUT) - LOCAL_DEX_PREOPT := false - include $(BUILD_JAVA_LIBRARY) - ART_TEST_TARGET_DEX_FILES += $(3)/$$(LOCAL_MODULE).jar + ifeq ($(ART_BUILD_TARGET),true) + include $(CLEAR_VARS) + LOCAL_MODULE := $(1)-$(2) + LOCAL_MODULE_TAGS := tests + LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2)) + LOCAL_JAVA_LIBRARIES := $(TARGET_CORE_JARS) + LOCAL_NO_STANDARD_LIBRARIES := true + LOCAL_MODULE_PATH := $(3) + LOCAL_DEX_PREOPT_IMAGE := $(TARGET_CORE_IMG_OUT) + LOCAL_DEX_PREOPT := false + include $(BUILD_JAVA_LIBRARY) + ART_TEST_TARGET_DEX_FILES += $(3)/$$(LOCAL_MODULE).jar + endif - include $(CLEAR_VARS) - LOCAL_MODULE := $(1)-$(2) - LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2)) - LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS) - LOCAL_NO_STANDARD_LIBRARIES := true - LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_OUT) - LOCAL_BUILD_HOST_DEX := true - include $(BUILD_HOST_JAVA_LIBRARY) - ART_TEST_HOST_DEX_FILES += $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE).jar + ifeq ($(ART_BUILD_HOST),true) + include $(CLEAR_VARS) + LOCAL_MODULE := $(1)-$(2) + LOCAL_SRC_FILES := $(call all-java-files-under, test/$(2)) + LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS) + LOCAL_NO_STANDARD_LIBRARIES := true + LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_OUT) + LOCAL_BUILD_HOST_DEX := true + include $(BUILD_HOST_JAVA_LIBRARY) + ART_TEST_HOST_DEX_FILES += $$(LOCAL_MODULE_PATH)/$$(LOCAL_MODULE).jar + endif endef $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT)))) $(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT)))) @@ -66,7 +70,7 @@ test-art-target-oat-$(1): $(ART_TEST_OUT)/oat-test-dex-$(1).jar test-art-target- $(hide) rm /tmp/test-art-target-oat-$(1) $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar.oat: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OAT) - $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$< --oat-file=$$@ --instruction-set=$(HOST_ARCH) --host-prefix="" + $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$< --oat-file=$$@ --instruction-set=$(HOST_ARCH) --host --host-prefix="" .PHONY: test-art-host-oat-$(1) test-art-host-oat-$(1): $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar.oat test-art-host-dependencies diff --git a/src/class_linker.cc b/src/class_linker.cc index ca7cc00290..4a07ebab2f 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -659,6 +659,9 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename, << " --runtime-arg -Xmx64m" << " --runtime-arg -classpath" << " --runtime-arg " << class_path +#if !defined(ART_TARGET) + << " --host" +#endif << " " << boot_image_option << " " << dex_file_option << " " << oat_fd_option @@ -669,6 +672,9 @@ bool ClassLinker::GenerateOatFile(const std::string& dex_filename, "--runtime-arg", "-Xmx64m", "--runtime-arg", "-classpath", "--runtime-arg", class_path, +#if !defined(ART_TARGET) + "--host", +#endif boot_image_option, dex_file_option, oat_fd_option, @@ -815,12 +821,7 @@ const DexFile* ClassLinker::FindOrCreateOatFileForDexLocationLocked(const std::s LOG(ERROR) << "Failed to generate oat file: " << oat_location; return NULL; } - // Open the oat from file descriptor we passed to GenerateOatFile - if (lseek(file->Fd(), 0, SEEK_SET) != 0) { - LOG(ERROR) << "Failed to seek to start of generated oat file: " << oat_location; - return NULL; - } - const OatFile* oat_file = OatFile::Open(file.get(), oat_location, NULL, false); + const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL); if (oat_file == NULL) { LOG(ERROR) << "Failed to open generated oat file: " << oat_location; return NULL; @@ -1624,7 +1625,7 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat // Every kind of method should at least get an invoke stub from the oat_method. // non-abstract methods also get their code pointers. const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index); - oat_method.LinkMethodPointers(method.get()); + oat_method.LinkMethod(method.get()); Runtime* runtime = Runtime::Current(); if (method->IsAbstract()) { diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc index 893e7a4a6b..e9ba70a1d4 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc @@ -368,7 +368,7 @@ struct CheckOffsets { if (!klass->IsClassClass() && !is_static) { size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize(); if (sizeof(T) != expected_size) { - LG << "Class size mismatch:" + LOG(ERROR) << "Class size mismatch:" << " class=" << class_descriptor << " Java=" << expected_size << " C++=" << sizeof(T); @@ -378,7 +378,7 @@ struct CheckOffsets { size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields(); if (offsets.size() != num_fields) { - LG << "Field count mismatch:" + LOG(ERROR) << "Field count mismatch:" << " class=" << class_descriptor << " Java=" << num_fields << " C++=" << offsets.size(); @@ -401,9 +401,9 @@ struct CheckOffsets { fh.ChangeField(field); StringPiece field_name(fh.GetName()); if (field_name != offsets[i].java_name) { - LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:"; + LOG(ERROR) << "JAVA FIELD ORDER MISMATCH NEXT LINE:"; } - LG << "Java field order:" + LOG(ERROR) << "Java field order:" << " i=" << i << " class=" << class_descriptor << " Java=" << field_name << " CheckOffsets=" << offset.java_name; @@ -422,9 +422,9 @@ struct CheckOffsets { CheckOffset& offset = offsets[i]; Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i); if (field->GetOffset().Uint32Value() != offset.cpp_offset) { - LG << "OFFSET MISMATCH NEXT LINE:"; + LOG(ERROR) << "OFFSET MISMATCH NEXT LINE:"; } - LG << "Offset: class=" << class_descriptor << " field=" << offset.java_name + LOG(ERROR) << "Offset: class=" << class_descriptor << " field=" << offset.java_name << " Java=" << field->GetOffset().Uint32Value() << " C++=" << offset.cpp_offset; } } diff --git a/src/common_test.h b/src/common_test.h index 0d3795e1e6..0167424092 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -246,7 +246,7 @@ class CommonTest : public testing::Test { &compiled_method->GetVmapTable()[0], NULL, method_invoke_stub); - oat_method.LinkMethodPointers(method); + oat_method.LinkMethod(method); } else { MakeExecutable(runtime_->GetAbstractMethodErrorStubArray()); const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData(); @@ -259,7 +259,7 @@ class CommonTest : public testing::Test { NULL, NULL, method_invoke_stub); - oat_method.LinkMethodPointers(method); + oat_method.LinkMethod(method); } } @@ -434,12 +434,16 @@ class CommonTest : public testing::Test { } std::string GetLibCoreDexFileName() { + return GetDexFileName("core"); + } + + std::string GetDexFileName(const std::string& jar_prefix) { if (IsHost()) { const char* host_dir = getenv("ANDROID_HOST_OUT"); CHECK(host_dir != NULL); - return StringPrintf("%s/framework/core-hostdex.jar", host_dir); + return StringPrintf("%s/framework/%s-hostdex.jar", host_dir, jar_prefix.c_str()); } - return StringPrintf("%s/framework/core.jar", GetAndroidRoot()); + return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str()); } const DexFile* OpenTestDexFile(const char* name) { @@ -585,6 +589,16 @@ class CheckJniAbortCatcher { DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher); }; +// TODO: These tests were disabled for portable when we went to having +// MCLinker link LLVM ELF output because we no longer just have code +// blobs in memory. We'll need to dlopen to load and relocate +// temporary output to resurrect these tests. +#if defined(ART_USE_PORTABLE_COMPILER) +#define TEST_DISABLED_FOR_PORTABLE() printf("WARNING: TEST DISABLED FOR PORTABLE\n"); return +#else +#define TEST_DISABLED_FOR_PORTABLE() +#endif + } // namespace art namespace std { diff --git a/src/compiled_method.cc b/src/compiled_method.cc index 4de2a3f5fd..36c4eeac57 100644 --- a/src/compiled_method.cc +++ b/src/compiled_method.cc @@ -18,6 +18,26 @@ namespace art { +CompiledCode::CompiledCode(InstructionSet instruction_set, const std::vector<uint8_t>& code) + : instruction_set_(instruction_set), code_(code) +{ + CHECK_NE(code.size(), 0U); +} + +CompiledCode::CompiledCode(InstructionSet instruction_set, + const std::string& elf_object, + const std::string& symbol) + : instruction_set_(instruction_set), symbol_(symbol) { + CHECK_NE(elf_object.size(), 0U); + CHECK_NE(symbol.size(), 0U); + // TODO: we shouldn't just shove ELF objects in as "code" but + // change to have different kinds of compiled methods. This is + // being deferred until we work on hybrid execution or at least + // until we work on batch compilation. + code_.resize(elf_object.size()); + memcpy(&code_[0], &elf_object[0], elf_object.size()); +} + uint32_t CompiledCode::AlignCode(uint32_t offset) const { return AlignCode(offset, instruction_set_); } @@ -72,6 +92,22 @@ const void* CompiledCode::CodePointer(const void* code_pointer, } } +#if defined(ART_USE_PORTABLE_COMPILER) +const std::string& CompiledCode::GetSymbol() const { + CHECK_NE(0U, symbol_.size()); + return symbol_; +} + +const std::vector<uint32_t>& CompiledCode::GetOatdataOffsetsToCompliledCodeOffset() const { + CHECK_NE(0U, oatdata_offsets_to_compiled_code_offset_.size()) << symbol_; + return oatdata_offsets_to_compiled_code_offset_; +} + +void CompiledCode::AddOatdataOffsetToCompliledCodeOffset(uint32_t offset) { + oatdata_offsets_to_compiled_code_offset_.push_back(offset); +} +#endif + CompiledMethod::CompiledMethod(InstructionSet instruction_set, const std::vector<uint8_t>& code, const size_t frame_size_in_bytes, @@ -80,20 +116,15 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, const std::vector<uint32_t>& mapping_table, const std::vector<uint16_t>& vmap_table, const std::vector<uint8_t>& native_gc_map) - : CompiledCode(instruction_set), frame_size_in_bytes_(frame_size_in_bytes), + : CompiledCode(instruction_set, code), frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), native_gc_map_(native_gc_map) { - CHECK_NE(code.size(), 0U); DCHECK_EQ(vmap_table.size(), static_cast<uint32_t>(__builtin_popcount(core_spill_mask) + __builtin_popcount(fp_spill_mask))); CHECK_LE(vmap_table.size(), (1U << 16) - 1); // length must fit in 2^16-1 - size_t code_byte_count = code.size() * sizeof(code[0]); - std::vector<uint8_t> byte_code(code_byte_count); - memcpy(&byte_code[0], &code[0], code_byte_count); - std::vector<uint32_t> length_prefixed_mapping_table; length_prefixed_mapping_table.push_back(mapping_table.size()); length_prefixed_mapping_table.insert(length_prefixed_mapping_table.end(), @@ -109,7 +140,6 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, DCHECK_EQ(vmap_table.size() + 1, length_prefixed_vmap_table.size()); DCHECK_EQ(vmap_table.size(), length_prefixed_vmap_table[0]); - SetCode(byte_code); mapping_table_ = length_prefixed_mapping_table; vmap_table_ = length_prefixed_vmap_table; DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask) + __builtin_popcount(fp_spill_mask))); @@ -122,16 +152,15 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, const uint32_t fp_spill_mask) : CompiledCode(instruction_set, code), frame_size_in_bytes_(frame_size_in_bytes), - core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) { -} - -CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set) - : CompiledCode(instruction_set) { -} + core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask) {} CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set, const std::vector<uint8_t>& code) - : CompiledCode(instruction_set, code) { -} + : CompiledCode(instruction_set, code) {} + +CompiledInvokeStub::CompiledInvokeStub(InstructionSet instruction_set, + const std::string& elf_object, + const std::string& symbol) + : CompiledCode(instruction_set, elf_object, symbol) {} } // namespace art diff --git a/src/compiled_method.h b/src/compiled_method.h index b7a2f9c629..c05aba149c 100644 --- a/src/compiled_method.h +++ b/src/compiled_method.h @@ -17,6 +17,7 @@ #ifndef ART_SRC_COMPILED_METHOD_H_ #define ART_SRC_COMPILED_METHOD_H_ +#include <string> #include <vector> #include "instruction_set.h" @@ -31,14 +32,13 @@ namespace art { class CompiledCode { public: - CompiledCode(InstructionSet instruction_set) - : instruction_set_(instruction_set) { - } + // For Quick to supply an code blob + CompiledCode(InstructionSet instruction_set, const std::vector<uint8_t>& code); - CompiledCode(InstructionSet instruction_set, const std::vector<uint8_t>& code) - : instruction_set_(instruction_set), code_(code) { - CHECK_NE(code.size(), 0U); - } + // For Portable to supply an ELF object + CompiledCode(InstructionSet instruction_set, + const std::string& elf_object, + const std::string &symbol); InstructionSet GetInstructionSet() const { return instruction_set_; @@ -73,9 +73,26 @@ class CompiledCode { static const void* CodePointer(const void* code_pointer, InstructionSet instruction_set); +#if defined(ART_USE_PORTABLE_COMPILER) + const std::string& GetSymbol() const; + const std::vector<uint32_t>& GetOatdataOffsetsToCompliledCodeOffset() const; + void AddOatdataOffsetToCompliledCodeOffset(uint32_t offset); +#endif + private: const InstructionSet instruction_set_; + + // Used to store the PIC code for Quick and an ELF image for portable. std::vector<uint8_t> code_; + + // Used for the Portable ELF symbol name. + std::string symbol_; + + // There are offsets from the oatdata symbol to where the offset to + // the compiled method will be found. These are computed by the + // OatWriter and then used by the ElfWriter to add relocations so + // that MCLinker can update the values to the location in the linked .so. + std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_; }; class CompiledMethod : public CompiledCode { @@ -97,19 +114,21 @@ class CompiledMethod : public CompiledCode { const uint32_t core_spill_mask, const uint32_t fp_spill_mask); - // Constructs a CompiledMethod for the LLVM compiler. + // Constructs a CompiledMethod for the Portable compiler. CompiledMethod(InstructionSet instruction_set, - const std::vector<uint8_t>& code, - const std::vector<uint8_t>& gc_map) - : CompiledCode(instruction_set, code), + const std::string& code, + const std::vector<uint8_t>& gc_map, + const std::string& symbol) + : CompiledCode(instruction_set, code, symbol), frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0), fp_spill_mask_(0), native_gc_map_(gc_map) { } - // Constructs a CompiledMethod for the LLVM JniCompiler. + // Constructs a CompiledMethod for the Portable JniCompiler. CompiledMethod(InstructionSet instruction_set, - const std::vector<uint8_t>& code) - : CompiledCode(instruction_set, code), + const std::string& code, + const std::string& symbol) + : CompiledCode(instruction_set, code, symbol), frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0), fp_spill_mask_(0) { } @@ -151,11 +170,15 @@ class CompiledMethod : public CompiledCode { class CompiledInvokeStub : public CompiledCode { public: - explicit CompiledInvokeStub(InstructionSet instruction_set); - + // Used by Quick to provide a blob of code. explicit CompiledInvokeStub(InstructionSet instruction_set, const std::vector<uint8_t>& code); + // Used by Portable to provide ELF object. + explicit CompiledInvokeStub(InstructionSet instruction_set, + const std::string& elf_object, + const std::string& symbol); + ~CompiledInvokeStub() {} }; diff --git a/src/compiler/dex/compiler_ir.h b/src/compiler/dex/compiler_ir.h index 4ab98a6dc7..f8cdd34b60 100644 --- a/src/compiler/dex/compiler_ir.h +++ b/src/compiler/dex/compiler_ir.h @@ -18,15 +18,18 @@ #define ART_SRC_COMPILER_DEX_COMPILER_IR_H_ #include <vector> -#include "dex_instruction.h" + +#include <llvm/Module.h> + +#include "compiler/dex/quick/codegen.h" #include "compiler/driver/compiler_driver.h" #include "compiler/driver/dex_compilation_unit.h" -#include "compiler_utility.h" -#include "safe_map.h" -#include "compiler/llvm/ir_builder.h" #include "compiler/llvm/intrinsic_helper.h" -#include "llvm/Module.h" +#include "compiler/llvm/ir_builder.h" #include "compiler_enums.h" +#include "compiler_utility.h" +#include "dex_instruction.h" +#include "safe_map.h" namespace art { @@ -43,6 +46,9 @@ namespace art { struct ArenaBitVector; struct LIR; class LLVMInfo; +namespace llvm { +class LlvmCompilationUnit; +} // namespace llvm struct PromotionMap { RegLocationType core_location:3; @@ -348,6 +354,7 @@ struct CompilationUnit { mstats(NULL), checkstats(NULL), gen_bitcode(false), + llvm_compilation_unit(NULL), llvm_info(NULL), context(NULL), module(NULL), @@ -507,7 +514,11 @@ struct CompilationUnit { Memstats* mstats; Checkstats* checkstats; bool gen_bitcode; + + // Fields for Portable + llvm::LlvmCompilationUnit* llvm_compilation_unit; LLVMInfo* llvm_info; + std::string symbol; ::llvm::LLVMContext* context; ::llvm::Module* module; ::llvm::Function* func; @@ -516,6 +527,7 @@ struct CompilationUnit { ::llvm::BasicBlock* placeholder_bb; ::llvm::BasicBlock* entry_bb; ::llvm::BasicBlock* entryTarget_bb; + std::string bitcode_filename; GrowableList llvm_values; int32_t temp_name; diff --git a/src/compiler/dex/dataflow.cc b/src/compiler/dex/dataflow.cc index ac3116ecea..f0f177a45b 100644 --- a/src/compiler/dex/dataflow.cc +++ b/src/compiler/dex/dataflow.cc @@ -2491,10 +2491,7 @@ static bool InvokeUsesMethodStar(CompilationUnit* cu, MIR* mir) LOG(WARNING) << "Unexpected invoke op: " << opcode; return false; } - DexCompilationUnit m_unit(cu->class_loader, cu->class_linker, - *cu->dex_file, cu->code_item, - cu->class_def_idx, cu->method_idx, - cu->access_flags); + DexCompilationUnit m_unit(cu); // TODO: add a flag so we don't counts the stats for this twice uint32_t dex_method_idx = mir->dalvikInsn.vB; int vtable_idx; diff --git a/src/compiler/dex/frontend.cc b/src/compiler/dex/frontend.cc index 482804c5ee..5b8faf4551 100644 --- a/src/compiler/dex/frontend.cc +++ b/src/compiler/dex/frontend.cc @@ -14,8 +14,13 @@ * limitations under the License. */ +#include <llvm/Support/Threading.h> + #include "compiler/driver/compiler_driver.h" #include "compiler_internals.h" +#if defined(ART_USE_PORTABLE_COMPILER) +#include "compiler/llvm/llvm_compilation_unit.h" +#endif #include "dataflow.h" #include "ssa_transformation.h" #include "leb128.h" @@ -25,8 +30,6 @@ #include "portable/mir_to_gbc.h" #include "quick/mir_to_lir.h" -#include <llvm/Support/Threading.h> - namespace { #if !defined(ART_USE_PORTABLE_COMPILER) pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT; @@ -782,8 +785,11 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, - jobject class_loader, const DexFile& dex_file, - LLVMInfo* llvm_info) + jobject class_loader, const DexFile& dex_file +#if defined(ART_USE_PORTABLE_COMPILER) + , llvm::LlvmCompilationUnit* llvm_compilation_unit +#endif +) { VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; @@ -818,7 +824,11 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, if ((compiler_backend == kQuickGBC) || (compiler_backend == kPortable)) { cu->gen_bitcode = true; } - cu->llvm_info = llvm_info; +#if defined(ART_USE_PORTABLE_COMPILER) + cu->llvm_compilation_unit = llvm_compilation_unit; + cu->llvm_info = llvm_compilation_unit->GetQuickContext(); + cu->symbol = llvm_compilation_unit->GetDexCompilationUnit()->GetSymbol(); +#endif /* Adjust this value accordingly once inlining is performed */ cu->num_dalvik_registers = code_item->registers_size_; // TODO: set this from command line @@ -1137,6 +1147,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, } +#if defined(ART_USE_PORTABLE_COMPILER) /* Go the LLVM path? */ if (cu->gen_bitcode) { // MIR->Bitcode @@ -1148,7 +1159,9 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, } // Bitcode->LIR MethodBitcode2LIR(cu.get()); - } else { + } else +#endif + { if (special_case != kNoHandler) { /* * Custom codegen for special cases. If for any reason the @@ -1231,13 +1244,20 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, CompiledMethod* CompileOneMethod(CompilerDriver& compiler, const CompilerBackend backend, const DexFile::CodeItem* code_item, - uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint32_t access_flags, + InvokeType invoke_type, + uint32_t class_def_idx, + uint32_t method_idx, + jobject class_loader, const DexFile& dex_file, - LLVMInfo* llvm_info) + llvm::LlvmCompilationUnit* llvm_compilation_unit) { return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx, - method_idx, class_loader, dex_file, llvm_info); + method_idx, class_loader, dex_file +#if defined(ART_USE_PORTABLE_COMPILER) + , llvm_compilation_unit +#endif + ); } } // namespace art diff --git a/src/compiler/dex/portable/mir_to_gbc.cc b/src/compiler/dex/portable/mir_to_gbc.cc index 8319b4d7ac..e6900df2ea 100644 --- a/src/compiler/dex/portable/mir_to_gbc.cc +++ b/src/compiler/dex/portable/mir_to_gbc.cc @@ -33,6 +33,8 @@ #include "compiler/dex/quick/codegen_util.h" #include "compiler/dex/quick/local_optimizations.h" #include "compiler/dex/quick/ralloc_util.h" +#include "compiler/llvm/llvm_compilation_unit.h" +#include "compiler/llvm/utils_llvm.h" static const char* kLabelFormat = "%c0x%x_%d"; static const char kInvalidBlock = 0xff; @@ -1982,17 +1984,14 @@ static ::llvm::FunctionType* GetFunctionType(CompilationUnit* cu) { } static bool CreateFunction(CompilationUnit* cu) { - std::string func_name(PrettyMethod(cu->method_idx, *cu->dex_file, - /* with_signature */ false)); ::llvm::FunctionType* func_type = GetFunctionType(cu); - if (func_type == NULL) { return false; } cu->func = ::llvm::Function::Create(func_type, - ::llvm::Function::ExternalLinkage, - func_name, cu->module); + ::llvm::Function::InternalLinkage, + cu->symbol, cu->module); ::llvm::Function::arg_iterator arg_iter(cu->func->arg_begin()); ::llvm::Function::arg_iterator arg_end(cu->func->arg_end()); diff --git a/src/compiler/dex/quick/codegen.h b/src/compiler/dex/quick/codegen.h index 63c8460b2b..21290caed0 100644 --- a/src/compiler/dex/quick/codegen.h +++ b/src/compiler/dex/quick/codegen.h @@ -17,6 +17,8 @@ #ifndef ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_ #define ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_ +#include "invoke_type.h" +#include "compiler/dex/compiler_enums.h" #include "compiler/dex/compiler_ir.h" namespace art { @@ -82,6 +84,14 @@ namespace art { #define REG_USE12 (REG_USE1 | REG_USE2) #define REG_USE23 (REG_USE2 | REG_USE3) +struct BasicBlock; +struct CallInfo; +struct CompilationUnit; +struct LIR; +struct MIR; +struct RegLocation; +struct RegisterInfo; + typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method, InvokeType type); diff --git a/src/compiler/dex/quick/codegen_util.cc b/src/compiler/dex/quick/codegen_util.cc index 5f8f6efb85..110146fbb4 100644 --- a/src/compiler/dex/quick/codegen_util.cc +++ b/src/compiler/dex/quick/codegen_util.cc @@ -54,10 +54,7 @@ void MarkSafepointPC(CompilationUnit* cu, LIR* inst) bool FastInstance(CompilationUnit* cu, uint32_t field_idx, int& field_offset, bool& is_volatile, bool is_put) { - DexCompilationUnit m_unit(cu->class_loader, cu->class_linker, - *cu->dex_file, cu->code_item, - cu->class_def_idx, cu->method_idx, - cu->access_flags); + DexCompilationUnit m_unit(cu); return cu->compiler_driver->ComputeInstanceFieldInfo(field_idx, &m_unit, field_offset, is_volatile, is_put); } diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc index f14d6cfe0a..a289252dee 100644 --- a/src/compiler/dex/quick/gen_common.cc +++ b/src/compiler/dex/quick/gen_common.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "codegen_util.h" +#include "compiler/dex/quick/codegen_util.h" #include "compiler/dex/compiler_ir.h" #include "oat/runtime/oat_support_entrypoints.h" #include "ralloc_util.h" @@ -354,8 +354,7 @@ void Codegen::GenSput(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_sr bool is_volatile; bool is_referrers_class; - DexCompilationUnit m_unit(cu->class_loader, cu->class_linker, *cu->dex_file, cu->code_item, - cu->class_def_idx, cu->method_idx, cu->access_flags); + DexCompilationUnit m_unit(cu); bool fast_path = cu->compiler_driver->ComputeStaticFieldInfo(field_idx, &m_unit, @@ -446,10 +445,7 @@ void Codegen::GenSget(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_de bool is_volatile; bool is_referrers_class; - DexCompilationUnit m_unit(cu->class_loader, cu->class_linker, - *cu->dex_file, cu->code_item, - cu->class_def_idx, cu->method_idx, - cu->access_flags); + DexCompilationUnit m_unit(cu); bool fast_path = cu->compiler_driver->ComputeStaticFieldInfo(field_idx, &m_unit, diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc index 2c01c19cf6..1ae29be1d9 100644 --- a/src/compiler/dex/quick/gen_invoke.cc +++ b/src/compiler/dex/quick/gen_invoke.cc @@ -16,6 +16,7 @@ #include "codegen_util.h" #include "compiler/dex/compiler_ir.h" +#include "invoke_type.h" #include "oat/runtime/oat_support_entrypoints.h" #include "ralloc_util.h" #include "x86/codegen_x86.h" @@ -1335,10 +1336,7 @@ void Codegen::GenInvoke(CompilationUnit* cu, CallInfo* info) // Explicit register usage LockCallTemps(cu); - DexCompilationUnit m_unit(cu->class_loader, cu->class_linker, - *cu->dex_file, cu->code_item, - cu->class_def_idx, cu->method_idx, - cu->access_flags); + DexCompilationUnit m_unit(cu); uint32_t dex_method_idx = info->index; int vtable_idx; diff --git a/src/compiler/dex/quick/gen_loadstore.cc b/src/compiler/dex/quick/gen_loadstore.cc index b945e3173f..a7baea4980 100644 --- a/src/compiler/dex/quick/gen_loadstore.cc +++ b/src/compiler/dex/quick/gen_loadstore.cc @@ -14,8 +14,9 @@ * limitations under the License. */ -#include "codegen_util.h" +#include "compiler/dex/quick/codegen_util.h" #include "compiler/dex/compiler_ir.h" +#include "invoke_type.h" #include "ralloc_util.h" namespace art { diff --git a/src/compiler/dex/quick/ralloc_util.cc b/src/compiler/dex/quick/ralloc_util.cc index a782264ecd..5b7de2c9ac 100644 --- a/src/compiler/dex/quick/ralloc_util.cc +++ b/src/compiler/dex/quick/ralloc_util.cc @@ -16,10 +16,10 @@ /* This file contains register alloction support. */ -#include "codegen_util.h" #include "compiler/dex/compiler_ir.h" #include "compiler/dex/compiler_utility.h" #include "compiler/dex/dataflow.h" +#include "compiler/dex/quick/codegen_util.h" #include "ralloc_util.h" namespace art { diff --git a/src/compiler/dex/write_elf.cc b/src/compiler/dex/write_elf.cc index a78d98e8cb..7e3d51283a 100644 --- a/src/compiler/dex/write_elf.cc +++ b/src/compiler/dex/write_elf.cc @@ -19,12 +19,17 @@ namespace art { class CompilerDriver; +class DexFile; } // namespace art extern "C" bool WriteElf(art::CompilerDriver& driver, + const std::string* host_prefix, + bool is_host, + const std::vector<const art::DexFile*>& dex_files, std::vector<uint8_t>& oat_contents, - art::File* file) { - return art::ElfWriter::Create(file, oat_contents, driver); + art::File* file) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return art::ElfWriter::Create(file, oat_contents, dex_files, host_prefix, is_host, driver); } extern "C" bool FixupElf(art::File* file, uintptr_t oat_data_begin) { return art::ElfWriter::Fixup(file, oat_data_begin); @@ -34,3 +39,6 @@ extern "C" void GetOatElfInformation(art::File* file, size_t& oat_data_offset) { art::ElfWriter::GetOatElfInformation(file, oat_loaded_size, oat_data_offset); } +extern "C" bool StripElf(art::File* file) { + return art::ElfWriter::Strip(file); +} diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index a28ba18a6b..8856a00597 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -1678,7 +1678,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx), &shorty_len); bool is_static = (access_flags & kAccStatic) != 0; std::string key(MakeInvokeStubKey(is_static, shorty)); - const CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(key); + CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(key); if (compiled_invoke_stub == NULL) { compiled_invoke_stub = (*create_invoke_stub_)(*this, is_static, shorty, shorty_len); CHECK(compiled_invoke_stub != NULL); @@ -1686,7 +1686,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } if ((compiler_backend_ == kPortable) && !is_static) { - const CompiledInvokeStub* compiled_proxy_stub = FindProxyStub(shorty); + CompiledInvokeStub* compiled_proxy_stub = FindProxyStub(shorty); if (compiled_proxy_stub == NULL) { compiled_proxy_stub = (*create_proxy_stub_)(*this, shorty, shorty_len); CHECK(compiled_proxy_stub != NULL); @@ -1701,12 +1701,12 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } } -const CompiledInvokeStub* CompilerDriver::FindInvokeStub(bool is_static, const char* shorty) const { +CompiledInvokeStub* CompilerDriver::FindInvokeStub(bool is_static, const char* shorty) const { const std::string key(MakeInvokeStubKey(is_static, shorty)); return FindInvokeStub(key); } -const CompiledInvokeStub* CompilerDriver::FindInvokeStub(const std::string& key) const { +CompiledInvokeStub* CompilerDriver::FindInvokeStub(const std::string& key) const { MutexLock mu(Thread::Current(), compiled_invoke_stubs_lock_); InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key); if (it == compiled_invoke_stubs_.end()) { @@ -1717,8 +1717,7 @@ const CompiledInvokeStub* CompilerDriver::FindInvokeStub(const std::string& key) } } -void CompilerDriver::InsertInvokeStub(const std::string& key, - const CompiledInvokeStub* compiled_invoke_stub) { +void CompilerDriver::InsertInvokeStub(const std::string& key, CompiledInvokeStub* compiled_invoke_stub) { MutexLock mu(Thread::Current(), compiled_invoke_stubs_lock_); InvokeStubTable::iterator it = compiled_invoke_stubs_.find(key); if (it != compiled_invoke_stubs_.end()) { @@ -1729,7 +1728,7 @@ void CompilerDriver::InsertInvokeStub(const std::string& key, } } -const CompiledInvokeStub* CompilerDriver::FindProxyStub(const char* shorty) const { +CompiledInvokeStub* CompilerDriver::FindProxyStub(const char* shorty) const { MutexLock mu(Thread::Current(), compiled_proxy_stubs_lock_); ProxyStubTable::const_iterator it = compiled_proxy_stubs_.find(shorty); if (it == compiled_proxy_stubs_.end()) { @@ -1740,8 +1739,7 @@ const CompiledInvokeStub* CompilerDriver::FindProxyStub(const char* shorty) cons } } -void CompilerDriver::InsertProxyStub(const char* shorty, - const CompiledInvokeStub* compiled_proxy_stub) { +void CompilerDriver::InsertProxyStub(const char* shorty, CompiledInvokeStub* compiled_proxy_stub) { MutexLock mu(Thread::Current(), compiled_proxy_stubs_lock_); InvokeStubTable::iterator it = compiled_proxy_stubs_.find(shorty); if (it != compiled_proxy_stubs_.end()) { @@ -1795,11 +1793,21 @@ bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0; } -bool CompilerDriver::WriteElf(std::vector<uint8_t>& oat_contents, File* file) { - typedef bool (*WriteElfFn)(CompilerDriver&, std::vector<uint8_t>&, File*); +bool CompilerDriver::WriteElf(const std::string* host_prefix, + bool is_host, + const std::vector<const DexFile*>& dex_files, + std::vector<uint8_t>& oat_contents, + File* file) { + typedef bool (*WriteElfFn)(CompilerDriver&, + const std::string* host_prefix, + bool is_host, + const std::vector<const DexFile*>& dex_files, + std::vector<uint8_t>&, + File*); WriteElfFn WriteElf = FindFunction<WriteElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "WriteElf"); - return WriteElf(*this, oat_contents, file); + Locks::mutator_lock_->AssertSharedHeld(Thread::Current()); + return WriteElf(*this, host_prefix, is_host, dex_files, oat_contents, file); } bool CompilerDriver::FixupElf(File* file, uintptr_t oat_data_begin) const { @@ -1819,11 +1827,18 @@ void CompilerDriver::GetOatElfInformation(File* file, GetOatElfInformation(file, oat_loaded_size, oat_data_offset); } +bool CompilerDriver::StripElf(File* file) const { + typedef bool (*StripElfFn)(File*); + StripElfFn StripElf = + FindFunction<StripElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "StripElf"); + return StripElf(file); +} + void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set, std::string& target_triple, std::string& target_cpu, std::string& target_attr) { - switch (instruction_set) { + switch (instruction_set) { case kThumb2: target_triple = "thumb-none-linux-gnueabi"; target_cpu = "cortex-a9"; diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h index 49bc4739af..7f67c212e9 100644 --- a/src/compiler/driver/compiler_driver.h +++ b/src/compiler/driver/compiler_driver.h @@ -123,11 +123,11 @@ class CompilerDriver { CompiledMethod* GetCompiledMethod(MethodReference ref) const LOCKS_EXCLUDED(compiled_methods_lock_); - const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const; - const CompiledInvokeStub* FindInvokeStub(const std::string& key) const + CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const; + CompiledInvokeStub* FindInvokeStub(const std::string& key) const LOCKS_EXCLUDED(compiled_invoke_stubs_lock_); - const CompiledInvokeStub* FindProxyStub(const char* shorty) const; + CompiledInvokeStub* FindProxyStub(const char* shorty) const; void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); @@ -186,10 +186,15 @@ class CompilerDriver { void SetBitcodeFileName(std::string const& filename); - // TODO: remove when libart links against LLVM (when separate compiler library is gone) - bool WriteElf(std::vector<uint8_t>& oat_contents, File* file); + // TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone) + bool WriteElf(const std::string* host_prefix, + bool is_host, + const std::vector<const DexFile*>& dex_files, + std::vector<uint8_t>& oat_contents, + File* file); bool FixupElf(File* file, uintptr_t oat_data_begin) const; void GetOatElfInformation(File* file, size_t& oat_loaded_size, size_t& oat_data_offset) const; + bool StripElf(File* file) const; // TODO: move to a common home for llvm helpers once quick/portable are merged static void InstructionSetToLLVMTarget(InstructionSet instruction_set, @@ -316,10 +321,10 @@ class CompilerDriver { static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_); - void InsertInvokeStub(const std::string& key, const CompiledInvokeStub* compiled_invoke_stub) + void InsertInvokeStub(const std::string& key, CompiledInvokeStub* compiled_invoke_stub) LOCKS_EXCLUDED(compiled_invoke_stubs_lock_); - void InsertProxyStub(const char* shorty, const CompiledInvokeStub* compiled_proxy_stub); + void InsertProxyStub(const char* shorty, CompiledInvokeStub* compiled_proxy_stub); std::vector<const PatchInformation*> code_to_patch_; std::vector<const PatchInformation*> methods_to_patch_; @@ -342,12 +347,12 @@ class CompilerDriver { mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_); - typedef SafeMap<std::string, const CompiledInvokeStub*> InvokeStubTable; + typedef SafeMap<std::string, CompiledInvokeStub*> InvokeStubTable; // Invocation stubs created to allow invocation of the compiled methods. mutable Mutex compiled_invoke_stubs_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; InvokeStubTable compiled_invoke_stubs_ GUARDED_BY(compiled_invoke_stubs_lock_); - typedef SafeMap<std::string, const CompiledInvokeStub*> ProxyStubTable; + typedef SafeMap<std::string, CompiledInvokeStub*> ProxyStubTable; // Proxy stubs created for proxy invocation delegation mutable Mutex compiled_proxy_stubs_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; ProxyStubTable compiled_proxy_stubs_ GUARDED_BY(compiled_proxy_stubs_lock_); diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc index 19ccb358e8..dee448d33f 100644 --- a/src/compiler/driver/compiler_driver_test.cc +++ b/src/compiler/driver/compiler_driver_test.cc @@ -132,6 +132,7 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { } TEST_F(CompilerDriverTest, AbstractMethodErrorStub) { + TEST_DISABLED_FOR_PORTABLE(); jobject class_loader; { ScopedObjectAccess soa(Thread::Current()); diff --git a/src/compiler/driver/dex_compilation_unit.cc b/src/compiler/driver/dex_compilation_unit.cc new file mode 100644 index 0000000000..67987fa626 --- /dev/null +++ b/src/compiler/driver/dex_compilation_unit.cc @@ -0,0 +1,56 @@ +/* + * 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 "dex_compilation_unit.h" + +#include "base/stringprintf.h" +#include "compiler/dex/compiler_ir.h" +#include "utils.h" + +namespace art { + +DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu) + : cu_(cu), + class_loader_(cu->class_loader), + class_linker_(cu->class_linker), + dex_file_(cu->dex_file), + code_item_(cu->code_item), + class_def_idx_(cu->class_def_idx), + dex_method_idx_(cu->method_idx), + access_flags_(cu->access_flags), + symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) { +} + +DexCompilationUnit:: DexCompilationUnit(CompilationUnit* cu, + jobject class_loader, + ClassLinker* class_linker, + const DexFile& dex_file, + const DexFile::CodeItem* code_item, + uint32_t class_def_idx, + uint32_t method_idx, + uint32_t access_flags) + : cu_(cu), + class_loader_(class_loader), + class_linker_(class_linker), + dex_file_(&dex_file), + code_item_(code_item), + class_def_idx_(class_def_idx), + dex_method_idx_(method_idx), + access_flags_(access_flags), + symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) { +} + +} // namespace art diff --git a/src/compiler/driver/dex_compilation_unit.h b/src/compiler/driver/dex_compilation_unit.h index 6a0218d038..0fc112304c 100644 --- a/src/compiler/driver/dex_compilation_unit.h +++ b/src/compiler/driver/dex_compilation_unit.h @@ -17,26 +17,29 @@ #ifndef ART_SRC_COMPILER_DEX_DEX_COMPILATION_UNIT_H_ #define ART_SRC_COMPILER_DEX_DEX_COMPILATION_UNIT_H_ -#include "dex_file.h" - #include <stdint.h> +#include "dex_file.h" +#include "jni.h" + namespace art { namespace mirror { class ClassLoader; class DexCache; } // namespace mirror class ClassLinker; -class DexFile; +class CompilationUnit; class DexCompilationUnit { public: - DexCompilationUnit(jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file, - const DexFile::CodeItem* code_item, uint32_t class_def_idx, - uint32_t method_idx, uint32_t access_flags) - : class_loader_(class_loader), class_linker_(class_linker), dex_file_(&dex_file), - code_item_(code_item), class_def_idx_(class_def_idx), dex_method_idx_(method_idx), - access_flags_(access_flags) { + DexCompilationUnit(CompilationUnit* cu); + + DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker, + const DexFile& dex_file, const DexFile::CodeItem* code_item, + uint32_t class_def_idx, uint32_t method_idx, uint32_t access_flags); + + CompilationUnit* GetCompilationUnit() const { + return cu_; } jobject GetClassLoader() const { @@ -89,8 +92,15 @@ class DexCompilationUnit { return ((access_flags_ & kAccSynchronized) != 0); } + const std::string& GetSymbol() const { + return symbol_; + } + private: + CompilationUnit* cu_; + const jobject class_loader_; + ClassLinker* const class_linker_; const DexFile* const dex_file_; @@ -99,6 +109,8 @@ class DexCompilationUnit { const uint32_t class_def_idx_; const uint32_t dex_method_idx_; const uint32_t access_flags_; + + const std::string symbol_; }; } // namespace art diff --git a/src/compiler/invoke_stubs/portable/stub_compiler.cc b/src/compiler/invoke_stubs/portable/stub_compiler.cc index 5c314e6fb8..ec6dc308aa 100644 --- a/src/compiler/invoke_stubs/portable/stub_compiler.cc +++ b/src/compiler/invoke_stubs/portable/stub_compiler.cc @@ -52,7 +52,7 @@ CompiledInvokeStub* StubCompiler::CreateInvokeStub(bool is_static, size_t shorty_size = strlen(shorty); // Function name - std::string func_name(ElfFuncName(cunit_->GetIndex())); + std::string func_name(StringPrintf("invoke_stub_%s%s", shorty, is_static ? "_static" : "")); // Get argument types ::llvm::Type* arg_types[] = { @@ -69,8 +69,8 @@ CompiledInvokeStub* StubCompiler::CreateInvokeStub(bool is_static, // Create function ::llvm::Function* func = - ::llvm::Function::Create(func_type, ::llvm::Function::ExternalLinkage, - func_name, module_); + ::llvm::Function::Create(func_type, ::llvm::Function::InternalLinkage, + func_name, module_); // Create basic block for the body of this function @@ -185,7 +185,8 @@ CompiledInvokeStub* StubCompiler::CreateInvokeStub(bool is_static, cunit_->Materialize(); return new CompiledInvokeStub(cunit_->GetInstructionSet(), - cunit_->GetCompiledCode()); + cunit_->GetElfObject(), + func_name); } @@ -194,7 +195,7 @@ CompiledInvokeStub* StubCompiler::CreateProxyStub(const char* shorty) { size_t shorty_size = strlen(shorty); // Function name - std::string func_name(ElfFuncName(cunit_->GetIndex())); + std::string func_name(StringPrintf("proxy_stub_%s", shorty)); // Accurate function type ::llvm::Type* accurate_ret_type = irb_.getJType(shorty[0]); @@ -212,7 +213,7 @@ CompiledInvokeStub* StubCompiler::CreateProxyStub(const char* shorty) { // Create function ::llvm::Function* func = - ::llvm::Function::Create(accurate_func_type, ::llvm::Function::ExternalLinkage, + ::llvm::Function::Create(accurate_func_type, ::llvm::Function::InternalLinkage, func_name, module_); switch(shorty[0]) { case 'Z': @@ -271,7 +272,8 @@ CompiledInvokeStub* StubCompiler::CreateProxyStub(const char* shorty) { cunit_->Materialize(); return new CompiledInvokeStub(cunit_->GetInstructionSet(), - cunit_->GetCompiledCode()); + cunit_->GetElfObject(), + func_name); } diff --git a/src/compiler/jni/jni_compiler_test.cc b/src/compiler/jni/jni_compiler_test.cc index 4ed789817f..5176752a9d 100644 --- a/src/compiler/jni/jni_compiler_test.cc +++ b/src/compiler/jni/jni_compiler_test.cc @@ -130,6 +130,7 @@ void Java_MyClassNatives_foo(JNIEnv* env, jobject thisObj) { } TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClassNatives_foo)); @@ -141,6 +142,7 @@ TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) { } TEST_F(JniCompilerTest, CompileAndRunIntMethodThroughStub) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "bar", "(I)I", NULL /* calling through stub will link with &Java_MyClassNatives_bar */); @@ -155,6 +157,7 @@ TEST_F(JniCompilerTest, CompileAndRunIntMethodThroughStub) { } TEST_F(JniCompilerTest, CompileAndRunStaticIntMethodThroughStub) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "sbar", "(I)I", NULL /* calling through stub will link with &Java_MyClassNatives_sbar */); @@ -181,6 +184,7 @@ jint Java_MyClassNatives_fooI(JNIEnv* env, jobject thisObj, jint x) { } TEST_F(JniCompilerTest, CompileAndRunIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&Java_MyClassNatives_fooI)); @@ -206,6 +210,7 @@ jint Java_MyClassNatives_fooII(JNIEnv* env, jobject thisObj, jint x, jint y) { } TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooII", "(II)I", reinterpret_cast<void*>(&Java_MyClassNatives_fooII)); @@ -232,6 +237,7 @@ jlong Java_MyClassNatives_fooJJ(JNIEnv* env, jobject thisObj, jlong x, jlong y) } TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooJJ", "(JJ)J", reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ)); @@ -259,6 +265,7 @@ jdouble Java_MyClassNatives_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdoub } TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooDD", "(DD)D", reinterpret_cast<void*>(&Java_MyClassNatives_fooDD)); @@ -287,6 +294,7 @@ jlong Java_MyClassNatives_fooJJ_synchronized(JNIEnv* env, jobject thisObj, jlong } TEST_F(JniCompilerTest, CompileAndRun_fooJJ_synchronized) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooJJ_synchronized", "(JJ)J", reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ_synchronized)); @@ -319,6 +327,7 @@ jobject Java_MyClassNatives_fooIOO(JNIEnv* env, jobject thisObj, jint x, jobject } TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooIOO", "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", reinterpret_cast<void*>(&Java_MyClassNatives_fooIOO)); @@ -362,6 +371,7 @@ jint Java_MyClassNatives_fooSII(JNIEnv* env, jclass klass, jint x, jint y) { } TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "fooSII", "(II)I", reinterpret_cast<void*>(&Java_MyClassNatives_fooSII)); @@ -384,6 +394,7 @@ jdouble Java_MyClassNatives_fooSDD(JNIEnv* env, jclass klass, jdouble x, jdouble } TEST_F(JniCompilerTest, CompileAndRunStaticDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "fooSDD", "(DD)D", reinterpret_cast<void*>(&Java_MyClassNatives_fooSDD)); @@ -420,6 +431,7 @@ jobject Java_MyClassNatives_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "fooSIOO", "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", reinterpret_cast<void*>(&Java_MyClassNatives_fooSIOO)); @@ -470,6 +482,7 @@ jobject Java_MyClassNatives_fooSSIOO(JNIEnv* env, jclass klass, jint x, jobject } TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "fooSSIOO", "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", reinterpret_cast<void*>(&Java_MyClassNatives_fooSSIOO)); @@ -506,6 +519,7 @@ void Java_MyClassNatives_throwException(JNIEnv* env, jobject) { } TEST_F(JniCompilerTest, ExceptionHandling) { + TEST_DISABLED_FOR_PORTABLE(); { ASSERT_FALSE(runtime_->IsStarted()); ScopedObjectAccess soa(Thread::Current()); @@ -585,6 +599,7 @@ jint Java_MyClassNatives_nativeUpCall(JNIEnv* env, jobject thisObj, jint i) { } TEST_F(JniCompilerTest, NativeStackTraceElement) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&Java_MyClassNatives_nativeUpCall)); jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 10); @@ -596,6 +611,7 @@ jobject Java_MyClassNatives_fooO(JNIEnv* env, jobject, jobject x) { } TEST_F(JniCompilerTest, ReturnGlobalRef) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooO", "(Ljava/lang/Object;)Ljava/lang/Object;", reinterpret_cast<void*>(&Java_MyClassNatives_fooO)); jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, jobj_); @@ -613,6 +629,7 @@ jint local_ref_test(JNIEnv* env, jobject thisObj, jint x) { } TEST_F(JniCompilerTest, LocalReferenceTableClearingTest) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "fooI", "(I)I", reinterpret_cast<void*>(&local_ref_test)); // 1000 invocations of a method that adds 10 local references for (int i = 0; i < 1000; i++) { @@ -631,6 +648,7 @@ void my_arraycopy(JNIEnv* env, jclass klass, jobject src, jint src_pos, jobject } TEST_F(JniCompilerTest, JavaLangSystemArrayCopy) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V", reinterpret_cast<void*>(&my_arraycopy)); env_->CallStaticVoidMethod(jklass_, jmethod_, jobj_, 1234, jklass_, 5678, 9876); @@ -646,6 +664,7 @@ jboolean my_casi(JNIEnv* env, jobject unsafe, jobject obj, jlong offset, jint ex } TEST_F(JniCompilerTest, CompareAndSwapInt) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "compareAndSwapInt", "(Ljava/lang/Object;JII)Z", reinterpret_cast<void*>(&my_casi)); jboolean result = env_->CallBooleanMethod(jobj_, jmethod_, jobj_, 0x12345678ABCDEF88ll, 0xCAFEF00D, 0xEBADF00D); @@ -662,6 +681,7 @@ jint my_gettext(JNIEnv* env, jclass klass, jlong val1, jobject obj1, jlong val2, } TEST_F(JniCompilerTest, GetText) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "getText", "(JLjava/lang/Object;JLjava/lang/Object;)I", reinterpret_cast<void*>(&my_gettext)); jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 0x12345678ABCDEF88ll, jobj_, @@ -670,6 +690,7 @@ TEST_F(JniCompilerTest, GetText) { } TEST_F(JniCompilerTest, GetSinkPropertiesNative) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", NULL); // This space intentionally left blank. Just testing compilation succeeds. } @@ -685,6 +706,7 @@ jobject Java_MyClassNatives_staticMethodThatShouldReturnClass(JNIEnv* env, jclas } TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Instance) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "instanceMethodThatShouldReturnClass", "()Ljava/lang/Class;", reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldReturnClass)); @@ -702,6 +724,7 @@ TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Instance) { } TEST_F(JniCompilerTest, UpcallReturnTypeChecking_Static) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "staticMethodThatShouldReturnClass", "()Ljava/lang/Class;", reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldReturnClass)); @@ -727,6 +750,7 @@ void Java_MyClassNatives_staticMethodThatShouldTakeClass(JNIEnv*, jclass, jclass } TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Instance) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(false, "instanceMethodThatShouldTakeClass", "(ILjava/lang/Class;)V", reinterpret_cast<void*>(&Java_MyClassNatives_instanceMethodThatShouldTakeClass)); @@ -737,6 +761,7 @@ TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Instance) { } TEST_F(JniCompilerTest, UpcallArgumentTypeChecking_Static) { + TEST_DISABLED_FOR_PORTABLE(); SetUpForTest(true, "staticMethodThatShouldTakeClass", "(ILjava/lang/Class;)V", reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldTakeClass)); diff --git a/src/compiler/jni/portable/jni_compiler.cc b/src/compiler/jni/portable/jni_compiler.cc index 1a4ad95c96..8495150c1e 100644 --- a/src/compiler/jni/portable/jni_compiler.cc +++ b/src/compiler/jni/portable/jni_compiler.cc @@ -64,7 +64,10 @@ CompiledMethod* JniCompiler::Compile() { char const return_shorty = dex_file->GetMethodShorty(method_id)[0]; ::llvm::Value* this_object_or_class_object; - CreateFunction(); + uint32_t method_idx = dex_compilation_unit_->GetDexMethodIndex(); + std::string func_name(StringPrintf("jni_%s", + MangleForJni(PrettyMethod(method_idx, *dex_file)).c_str())); + CreateFunction(func_name); // Set argument name ::llvm::Function::arg_iterator arg_begin(func_->arg_begin()); @@ -233,13 +236,13 @@ CompiledMethod* JniCompiler::Compile() { cunit_->Materialize(); return new CompiledMethod(cunit_->GetInstructionSet(), - cunit_->GetCompiledCode()); + cunit_->GetElfObject(), + func_name); } -void JniCompiler::CreateFunction() { - // LLVM function name - std::string func_name(ElfFuncName(cunit_->GetIndex())); +void JniCompiler::CreateFunction(const std::string& func_name) { + CHECK_NE(0U, func_name.size()); const bool is_static = dex_compilation_unit_->IsStatic(); @@ -248,8 +251,8 @@ void JniCompiler::CreateFunction() { GetFunctionType(dex_compilation_unit_->GetDexMethodIndex(), is_static, false); // Create function - func_ = ::llvm::Function::Create(func_type, ::llvm::Function::ExternalLinkage, - func_name, module_); + func_ = ::llvm::Function::Create(func_type, ::llvm::Function::InternalLinkage, + func_name, module_); // Create basic block ::llvm::BasicBlock* basic_block = ::llvm::BasicBlock::Create(*context_, "B0", func_); diff --git a/src/compiler/jni/portable/jni_compiler.h b/src/compiler/jni/portable/jni_compiler.h index 3df81a5ad1..a04277c9e6 100644 --- a/src/compiler/jni/portable/jni_compiler.h +++ b/src/compiler/jni/portable/jni_compiler.h @@ -19,6 +19,8 @@ #include <stdint.h> +#include <string> + namespace art { class ClassLinker; class CompiledMethod; @@ -58,10 +60,10 @@ class JniCompiler { CompiledMethod* Compile(); private: - void CreateFunction(); + void CreateFunction(const std::string& symbol); ::llvm::FunctionType* GetFunctionType(uint32_t method_idx, - bool is_static, bool is_target_function); + bool is_static, bool is_target_function); private: LlvmCompilationUnit* cunit_; diff --git a/src/compiler/llvm/compiler_llvm.cc b/src/compiler/llvm/compiler_llvm.cc index 1c9a4948cd..be1730f736 100644 --- a/src/compiler/llvm/compiler_llvm.cc +++ b/src/compiler/llvm/compiler_llvm.cc @@ -16,14 +16,15 @@ #include "compiler_llvm.h" -#include "base/stl_util.h" #include "backend_options.h" +#include "base/stl_util.h" #include "class_linker.h" #include "compiled_method.h" #include "compiler/driver/compiler_driver.h" #include "compiler/driver/dex_compilation_unit.h" #include "compiler/invoke_stubs/portable/stub_compiler.h" #include "compiler/jni/portable/jni_compiler.h" +#include "globals.h" #include "ir_builder.h" #include "llvm_compilation_unit.h" #include "oat_file.h" @@ -43,7 +44,7 @@ void CompileOneMethod(CompilerDriver& driver, uint32_t access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, - LLVMInfo* llvm_info); + llvm::LlvmCompilationUnit* llvm_info); } namespace llvm { @@ -65,17 +66,17 @@ void InitializeLLVM() { art::llvm::InitialBackendOptions(); // Initialize LLVM target, MC subsystem, asm printer, and asm parser. -#if defined(ART_TARGET) - // Don't initialize all targets on device. Just initialize the device's native target - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - llvm::InitializeNativeTargetAsmParser(); -#else - llvm::InitializeAllTargets(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmPrinters(); - llvm::InitializeAllAsmParsers(); -#endif + if (art::kIsTargetBuild) { + // Don't initialize all targets on device. Just initialize the device's native target + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + } else { + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + } // Initialize LLVM optimization passes llvm::PassRegistry ®istry = *llvm::PassRegistry::getPassRegistry(); @@ -110,8 +111,7 @@ namespace llvm { CompilerLLVM::CompilerLLVM(CompilerDriver* driver, InstructionSet insn_set) : compiler_driver_(driver), insn_set_(insn_set), - num_cunits_lock_("compilation unit counter lock"), num_cunits_(0), - plt_(insn_set) { + next_cunit_id_lock_("compilation unit id lock"), next_cunit_id_(1) { // Initialize LLVM libraries pthread_once(&llvm_initialized, InitializeLLVM); @@ -123,10 +123,12 @@ CompilerLLVM::~CompilerLLVM() { LlvmCompilationUnit* CompilerLLVM::AllocateCompilationUnit() { - MutexLock GUARD(Thread::Current(), num_cunits_lock_); - LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, ++num_cunits_); + MutexLock GUARD(Thread::Current(), next_cunit_id_lock_); + LlvmCompilationUnit* cunit = new LlvmCompilationUnit(this, next_cunit_id_++); if (!bitcode_filename_.empty()) { - cunit->SetBitcodeFileName(StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit->GetIndex())); + cunit->SetBitcodeFileName(StringPrintf("%s-%zu", + bitcode_filename_.c_str(), + cunit->GetCompilationUnitId())); } return cunit; } @@ -136,8 +138,8 @@ CompiledMethod* CompilerLLVM:: CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_type) { UniquePtr<LlvmCompilationUnit> cunit(AllocateCompilationUnit()); - std::string methodName(PrettyMethod(dex_compilation_unit->GetDexMethodIndex(), - *dex_compilation_unit->GetDexFile())); + cunit->SetDexCompilationUnit(dex_compilation_unit); + cunit->SetCompiler(compiler_driver_); // TODO: consolidate ArtCompileMethods CompileOneMethod(*compiler_driver_, kPortable, @@ -148,19 +150,16 @@ CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_typ dex_compilation_unit->GetDexMethodIndex(), dex_compilation_unit->GetClassLoader(), *dex_compilation_unit->GetDexFile(), - cunit->GetQuickContext() - ); - - cunit->SetCompiler(compiler_driver_); - cunit->SetDexCompilationUnit(dex_compilation_unit); + cunit.get()); cunit->Materialize(); CompilerDriver::MethodReference mref(dex_compilation_unit->GetDexFile(), dex_compilation_unit->GetDexMethodIndex()); return new CompiledMethod(compiler_driver_->GetInstructionSet(), - cunit->GetCompiledCode(), - *verifier::MethodVerifier::GetDexGcMap(mref)); + cunit->GetElfObject(), + *verifier::MethodVerifier::GetDexGcMap(mref), + cunit->GetDexCompilationUnit()->GetSymbol()); } @@ -235,7 +234,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker(); art::DexCompilationUnit dex_compilation_unit( - class_loader, class_linker, dex_file, code_item, + NULL, class_loader, class_linker, dex_file, code_item, class_def_idx, method_idx, access_flags); art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver); art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type); @@ -248,7 +247,7 @@ extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& dri art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker(); art::DexCompilationUnit dex_compilation_unit( - NULL, class_linker, dex_file, NULL, + NULL, NULL, class_linker, dex_file, NULL, 0, method_idx, access_flags); art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver); diff --git a/src/compiler/llvm/compiler_llvm.h b/src/compiler/llvm/compiler_llvm.h index 870a541f8d..cbee115fee 100644 --- a/src/compiler/llvm/compiler_llvm.h +++ b/src/compiler/llvm/compiler_llvm.h @@ -22,7 +22,6 @@ #include "dex_file.h" #include "instruction_set.h" #include "mirror/object.h" -#include "procedure_linkage_table.h" #include <UniquePtr.h> @@ -87,10 +86,6 @@ class CompilerLLVM { CompiledInvokeStub* CreateProxyStub(const char *shorty); - const ProcedureLinkageTable& GetProcedureLinkageTable() const { - return plt_; - } - private: LlvmCompilationUnit* AllocateCompilationUnit(); @@ -98,13 +93,11 @@ class CompilerLLVM { InstructionSet insn_set_; - Mutex num_cunits_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - size_t num_cunits_ GUARDED_BY(num_cunits_lock_); + Mutex next_cunit_id_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + size_t next_cunit_id_ GUARDED_BY(next_cunit_id_lock_); std::string bitcode_filename_; - ProcedureLinkageTable plt_; - DISALLOW_COPY_AND_ASSIGN(CompilerLLVM); }; diff --git a/src/compiler/llvm/compiler_runtime_func_list.h b/src/compiler/llvm/compiler_runtime_func_list.h deleted file mode 100644 index ffbae85f15..0000000000 --- a/src/compiler/llvm/compiler_runtime_func_list.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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_SRC_COMPILER_LLVM_COMPILER_RUNTIME_FUNC_LIST_H_ -#define ART_SRC_COMPILER_LLVM_COMPILER_RUNTIME_FUNC_LIST_H_ - -// NOTE: COMPILER_RUNTIME_FUNC_LIST_* should be sorted! - -#define COMPILER_RUNTIME_FUNC_LIST_X86(V) \ - V(__ashldi3, long long, long long, int) \ - V(__ashrdi3, long long, long long, int) \ - V(__divdi3, long long, long long, long long) \ - V(__fixdfdi, long long, double) \ - V(__fixsfdi, long long, float) \ - V(__fixtfdi, long long, long double) \ - V(__fixtfsi, int, long double) \ - V(__fixunsdfdi, unsigned long long, double) \ - V(__fixunsdfsi, unsigned int, double) \ - V(__fixunssfdi, unsigned long long, float) \ - V(__fixunssfsi, unsigned int, float) \ - V(__fixunstfdi, unsigned long long, long double) \ - V(__fixunstfsi, unsigned int, long double) \ - V(__fixunsxfdi, unsigned long long, long double) \ - V(__fixunsxfsi, unsigned int, long double) \ - V(__fixxfdi, long long, long double) \ - V(__floatdidf, double, long long) \ - V(__floatdisf, float, long long) \ - V(__floatditf, long double, long long) \ - V(__floatdixf, long double, long long) \ - V(__floatsitf, long double, int) \ - V(__floatundidf, double, unsigned long long) \ - V(__floatundisf, float, unsigned long long) \ - V(__floatunditf, long double, unsigned long long) \ - V(__floatundixf, long double, unsigned long long) \ - V(__floatunsitf, long double, int) \ - V(__lshrdi3, long long, long long, int) \ - V(__moddi3, long long, long long, long long) \ - V(__muldi3, long long, long long, long long) \ - V(__negdi2, long long, long long) \ - V(__powidf2, double, double, int) \ - V(__powisf2, float, float, int) \ - V(__powitf2, long double, long double, int) \ - V(__powixf2, long double, long double, int) \ - V(__trunctfdf2, double, long double) \ - V(__trunctfsf2, float, long double) \ - V(__udivdi3, unsigned long long, unsigned long long, unsigned long long) \ - V(__umoddi3, unsigned long long, unsigned long long, unsigned long long) \ - V(ceil, double, double) \ - V(ceilf, float, float) \ - V(ceill, long double, long double) \ - V(copysign, double, double, double) \ - V(copysignf, float, float, float) \ - V(copysignl, long double, long double, long double) \ - V(cos, double, double) \ - V(cosf, float, float) \ - V(exp, double, double) \ - V(exp2, double, double) \ - V(exp2f, float, float) \ - V(expf, float, float) \ - V(floor, double, double) \ - V(floorf, float, float) \ - V(floorl, long double, long double) \ - V(fma, double, double, double, double) \ - V(fmaf, float, float, float, float) \ - V(fmod, double, double, double) \ - V(fmodf, float, float, float) \ - V(log, double, double) \ - V(log10, double, double) \ - V(log10f, float, float) \ - V(logf, float, float) \ - V(memcpy, void *, void *, const void *, size_t) \ - V(memmove, void *, void *, const void *, size_t) \ - V(memset, void *, void *, int, size_t) \ - V(nearbyint, double, double) \ - V(nearbyintf, float, float) \ - V(pow, double, double, double) \ - V(powf, float, float, float) \ - V(rint, double, double) \ - V(rintf, float, float) \ - V(sin, double, double) \ - V(sinf, float, float) \ - V(sqrt, double, double) \ - V(sqrtf, float, float) \ - V(trunc, double, double) \ - V(truncf, float, float) \ - V(truncl, long double, long double) - -#define COMPILER_RUNTIME_FUNC_LIST_MIPS(V) \ - V(__ashldi3, long long, long long, int) \ - V(__ashrdi3, long long, long long, int) \ - V(__divdi3, long long, long long, long long) \ - V(__fixdfdi, long long, double) \ - V(__fixsfdi, long long, float) \ - V(__fixunsdfdi, unsigned long long, double) \ - V(__fixunsdfsi, unsigned int, double) \ - V(__fixunssfdi, unsigned long long, float) \ - V(__fixunssfsi, unsigned int, float) \ - V(__floatdidf, double, long long) \ - V(__floatdisf, float, long long) \ - V(__floatundidf, double, unsigned long long) \ - V(__floatundisf, float, unsigned long long) \ - V(__lshrdi3, long long, long long, int) \ - V(__moddi3, long long, long long, long long) \ - V(__muldi3, long long, long long, long long) \ - V(__negdi2, long long, long long) \ - V(__powidf2, double, double, int) \ - V(__powisf2, float, float, int) \ - V(__udivdi3, unsigned long long, unsigned long long, unsigned long long) \ - V(__umoddi3, unsigned long long, unsigned long long, unsigned long long) \ - V(ceil, double, double) \ - V(ceilf, float, float) \ - V(ceill, long double, long double) \ - V(copysign, double, double, double) \ - V(copysignf, float, float, float) \ - V(copysignl, long double, long double, long double) \ - V(cos, double, double) \ - V(cosf, float, float) \ - V(exp, double, double) \ - V(exp2, double, double) \ - V(exp2f, float, float) \ - V(expf, float, float) \ - V(floor, double, double) \ - V(floorf, float, float) \ - V(floorl, long double, long double) \ - V(fma, double, double, double, double) \ - V(fmaf, float, float, float, float) \ - V(fmod, double, double, double) \ - V(fmodf, float, float, float) \ - V(log, double, double) \ - V(log10, double, double) \ - V(log10f, float, float) \ - V(logf, float, float) \ - V(memcpy, void *, void *, const void *, size_t) \ - V(memmove, void *, void *, const void *, size_t) \ - V(memset, void *, void *, int, size_t) \ - V(nearbyint, double, double) \ - V(nearbyintf, float, float) \ - V(pow, double, double, double) \ - V(powf, float, float, float) \ - V(rint, double, double) \ - V(rintf, float, float) \ - V(sin, double, double) \ - V(sinf, float, float) \ - V(sqrt, double, double) \ - V(sqrtf, float, float) \ - V(trunc, double, double) \ - V(truncf, float, float) \ - V(truncl, long double, long double) - -#define COMPILER_RUNTIME_FUNC_LIST_ARM(V) \ - V(__aeabi_d2f, float, double) \ - V(__aeabi_d2iz, int, double) \ - V(__aeabi_d2lz, long long, double) \ - V(__aeabi_d2uiz, unsigned, double) \ - V(__aeabi_d2ulz, unsigned long long, double) \ - V(__aeabi_dadd, double, double, double) \ - V(__aeabi_dcmpeq, int, double, double) \ - V(__aeabi_dcmpge, int, double, double) \ - V(__aeabi_dcmpgt, int, double, double) \ - V(__aeabi_dcmple, int, double, double) \ - V(__aeabi_dcmplt, int, double, double) \ - V(__aeabi_dcmpun, int, double, double) \ - V(__aeabi_ddiv, double, double, double) \ - V(__aeabi_dmul, double, double, double) \ - V(__aeabi_dsub, double, double, double) \ - V(__aeabi_f2d, double, float) \ - V(__aeabi_f2iz, int, float) \ - V(__aeabi_f2lz, long long, float) \ - V(__aeabi_f2uiz, unsigned int, float) \ - V(__aeabi_f2ulz, unsigned long long, float) \ - V(__aeabi_fadd, float, float, float) \ - V(__aeabi_fcmpeq, int, float, float) \ - V(__aeabi_fcmpge, int, float, float) \ - V(__aeabi_fcmpgt, int, float, float) \ - V(__aeabi_fcmple, int, float, float) \ - V(__aeabi_fcmplt, int, float, float) \ - V(__aeabi_fcmpun, int, float, float) \ - V(__aeabi_fdiv, float, float, float) \ - V(__aeabi_fmul, float, float, float) \ - V(__aeabi_fsub, float, float, float) \ - V(__aeabi_i2d, double, int) \ - V(__aeabi_i2f, float, int) \ - V(__aeabi_idiv, int, int, int) \ - V(__aeabi_l2d, double, long long) \ - V(__aeabi_l2f, float, long long) \ - V(__aeabi_lasr, long long, long long, int) \ - V(__aeabi_ldivmod, /* value in regs */ void, long long, long long) \ - V(__aeabi_llsl, long long, long long, int) \ - V(__aeabi_llsr, long long, long long, int) \ - V(__aeabi_lmul, long long, long long, long long) \ - V(__aeabi_memcpy, void, void *, const void *, size_t) \ - V(__aeabi_memmove, void, void *, const void *, size_t) \ - V(__aeabi_memset, void, void *, size_t, int) /* different from stdlib */ \ - V(__aeabi_ui2d, double, unsigned int) \ - V(__aeabi_ui2f, float, unsigned int) \ - V(__aeabi_uidiv, unsigned int, unsigned int, unsigned int) \ - V(__aeabi_ul2d, double, unsigned long long) \ - V(__aeabi_ul2f, float, unsigned long long) \ - V(__aeabi_uldivmod, /* value in regs */ void, unsigned long long, unsigned long long) \ - V(__moddi3, long long, long long, long long) \ - V(__modsi3, int, int, int) \ - V(__umoddi3, unsigned long long, unsigned long long, unsigned long long) \ - V(__umodsi3, unsigned int, unsigned int, unsigned int) \ - V(fmod, double, double, double) \ - V(fmodf, float, float, float) \ - V(memcpy, void *, void *, const void *, size_t) \ - V(memmove, void *, void *, const void *, size_t) \ - V(memset, void *, void *, int, size_t) - - -#if defined(__arm__) -#define COMPILER_RUNTIME_FUNC_LIST_NATIVE(V) COMPILER_RUNTIME_FUNC_LIST_ARM(V) -#elif defined(__mips__) -#define COMPILER_RUNTIME_FUNC_LIST_NATIVE(V) COMPILER_RUNTIME_FUNC_LIST_MIPS(V) -#elif defined(__i386__) -#define COMPILER_RUNTIME_FUNC_LIST_NATIVE(V) COMPILER_RUNTIME_FUNC_LIST_X86(V) -#else -#error "Unknown target platform" -#endif - -#endif // ART_SRC_COMPILER_LLVM_COMPILER_RUNTIME_FUNC_LIST_H_ diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc index 4e1a91d35f..9de2e41325 100644 --- a/src/compiler/llvm/gbc_expander.cc +++ b/src/compiler/llvm/gbc_expander.cc @@ -326,7 +326,7 @@ class GBCExpanderPass : public llvm::FunctionPass { static char ID; GBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb, - art::CompilerDriver* compiler, art::DexCompilationUnit* dex_compilation_unit) + art::CompilerDriver* compiler, const art::DexCompilationUnit* dex_compilation_unit) : llvm::FunctionPass(ID), intrinsic_helper_(intrinsic_helper), irb_(irb), context_(irb.getContext()), rtb_(irb.Runtime()), shadow_frame_(NULL), old_shadow_frame_(NULL), @@ -350,7 +350,7 @@ bool GBCExpanderPass::runOnFunction(llvm::Function& func) { VLOG(compiler) << "GBC expansion on " << func.getName().str(); // Runtime support or stub - if (func.getName().startswith("art_") || func.getName().startswith("Art")) { + if (dex_compilation_unit_ == NULL) { return false; } @@ -3634,7 +3634,7 @@ namespace llvm { ::llvm::FunctionPass* CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb, - CompilerDriver* driver, DexCompilationUnit* dex_compilation_unit) { + CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit) { return new GBCExpanderPass(intrinsic_helper, irb, driver, dex_compilation_unit); } diff --git a/src/compiler/llvm/llvm_compilation_unit.cc b/src/compiler/llvm/llvm_compilation_unit.cc index aad18fba17..3783ae99e0 100644 --- a/src/compiler/llvm/llvm_compilation_unit.cc +++ b/src/compiler/llvm/llvm_compilation_unit.cc @@ -16,16 +16,11 @@ #include "llvm_compilation_unit.h" -#include "base/logging.h" -#include "compiled_method.h" -#include "compiler_llvm.h" -#include "instruction_set.h" -#include "ir_builder.h" -#include "os.h" +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> -#include "runtime_support_builder_arm.h" -#include "runtime_support_builder_thumb2.h" -#include "runtime_support_builder_x86.h" +#include <string> #include <llvm/ADT/OwningPtr.h> #include <llvm/ADT/StringSet.h> @@ -71,24 +66,30 @@ #include <llvm/Transforms/IPO/PassManagerBuilder.h> #include <llvm/Transforms/Scalar.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <string> +#include "base/logging.h" +#include "base/unix_file/fd_file.h" +#include "compiled_method.h" +#include "compiler_llvm.h" +#include "instruction_set.h" +#include "ir_builder.h" +#include "os.h" +#include "runtime_support_builder_arm.h" +#include "runtime_support_builder_thumb2.h" +#include "runtime_support_builder_x86.h" +#include "utils_llvm.h" namespace art { namespace llvm { ::llvm::FunctionPass* CreateGBCExpanderPass(const IntrinsicHelper& intrinsic_helper, IRBuilder& irb, - CompilerDriver* compiler, DexCompilationUnit* dex_compilation_unit); + CompilerDriver* compiler, const DexCompilationUnit* dex_compilation_unit); ::llvm::Module* makeLLVMModuleContents(::llvm::Module* module); -LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size_t cunit_idx) - : compiler_llvm_(compiler_llvm), cunit_idx_(cunit_idx) { +LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size_t cunit_id) + : compiler_llvm_(compiler_llvm), cunit_id_(cunit_id) { driver_ = NULL; dex_compilation_unit_ = NULL; llvm_info_.reset(new LLVMInfo()); @@ -136,27 +137,24 @@ InstructionSet LlvmCompilationUnit::GetInstructionSet() const { bool LlvmCompilationUnit::Materialize() { - std::string elf_image; - // Compile and prelink ::llvm::Module - if (!MaterializeToString(elf_image)) { - LOG(ERROR) << "Failed to materialize compilation unit " << cunit_idx_; + if (!MaterializeToString(elf_object_)) { + LOG(ERROR) << "Failed to materialize compilation unit " << cunit_id_; return false; } -#if 0 - // Dump the ELF image for debugging - std::string filename(StringPrintf("%s/Art%zu.elf", - GetArtCacheOrDie(GetAndroidData()).c_str(), - cunit_idx_)); - UniquePtr<File> output(OS::OpenFile(filename.c_str(), true)); - output->WriteFully(elf_image.data(), elf_image.size()); -#endif - - // Extract the .text section and prelink the code - if (!ExtractCodeAndPrelink(elf_image)) { - LOG(ERROR) << "Failed to extract code from compilation unit " << cunit_idx_; - return false; + if (false) { + // Dump the ELF image for debugging + std::string directory; + if (kIsTargetBuild) { + directory += GetArtCacheOrDie(GetAndroidData()); + } else { + directory += "/tmp"; + } + std::string filename(StringPrintf("%s/Art%u.o", directory.c_str(), cunit_id_)); + UniquePtr<File> output(OS::OpenFile(filename.c_str(), true)); + output->WriteFully(elf_object_.data(), elf_object_.size()); + LOG(INFO) << ".o file written successfully: " << filename; } return true; @@ -284,112 +282,6 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea return true; } -bool LlvmCompilationUnit::ExtractCodeAndPrelink(const std::string& elf_image) { - if (GetInstructionSet() == kX86) { - compiled_code_.push_back(0xccU); - compiled_code_.push_back(0xccU); - compiled_code_.push_back(0xccU); - compiled_code_.push_back(0xccU); - return true; - } - - ::llvm::OwningPtr< ::llvm::MemoryBuffer> elf_image_buff( - ::llvm::MemoryBuffer::getMemBuffer(::llvm::StringRef(elf_image.data(), - elf_image.size()))); - - ::llvm::OwningPtr< ::llvm::object::ObjectFile> elf_file( - ::llvm::object::ObjectFile::createELFObjectFile(elf_image_buff.take())); - - ::llvm::error_code ec; - - const ProcedureLinkageTable& plt = compiler_llvm_->GetProcedureLinkageTable(); - - for (::llvm::object::section_iterator - sec_iter = elf_file->begin_sections(), - sec_end = elf_file->end_sections(); - sec_iter != sec_end; sec_iter.increment(ec)) { - - CHECK(ec == 0) << "Failed to read section because " << ec.message(); - - // Read the section information - ::llvm::StringRef name; - uint64_t alignment = 0u; - uint64_t size = 0u; - - CHECK(sec_iter->getName(name) == 0); - CHECK(sec_iter->getSize(size) == 0); - CHECK(sec_iter->getAlignment(alignment) == 0); - - if (name == ".data" || name == ".bss" || name == ".rodata") { - if (size > 0) { - LOG(FATAL) << "Compilation unit " << cunit_idx_ << " has non-empty " - << name.str() << " section"; - } - - } else if (name == "" || name == ".rel.text" || - name == ".ARM.attributes" || name == ".symtab" || - name == ".strtab" || name == ".shstrtab") { - // We can ignore these sections. We don't have to copy them into - // the result Oat file. - - } else if (name == ".text") { - // Ensure the alignment requirement is less than or equal to - // kArchAlignment - CheckCodeAlign(alignment); - - // Copy the compiled code - ::llvm::StringRef contents; - CHECK(sec_iter->getContents(contents) == 0); - - copy(contents.data(), - contents.data() + contents.size(), - back_inserter(compiled_code_)); - - // Prelink the compiled code - for (::llvm::object::relocation_iterator - rel_iter = sec_iter->begin_relocations(), - rel_end = sec_iter->end_relocations(); rel_iter != rel_end; - rel_iter.increment(ec)) { - - CHECK(ec == 0) << "Failed to read relocation because " << ec.message(); - - // Read the relocation information - ::llvm::object::SymbolRef sym_ref; - uint64_t rel_offset = 0; - uint64_t rel_type = 0; - int64_t rel_addend = 0; - - CHECK(rel_iter->getSymbol(sym_ref) == 0); - CHECK(rel_iter->getOffset(rel_offset) == 0); - CHECK(rel_iter->getType(rel_type) == 0); - CHECK(rel_iter->getAdditionalInfo(rel_addend) == 0); - - // Read the symbol related to this relocation fixup - ::llvm::StringRef sym_name; - CHECK(sym_ref.getName(sym_name) == 0); - - // Relocate the fixup. - // TODO: Support more relocation type. - CHECK(rel_type == ::llvm::ELF::R_ARM_ABS32); - CHECK_LE(rel_offset + 4, compiled_code_.size()); - - uintptr_t dest_addr = plt.GetEntryAddress(sym_name.str().c_str()); - uintptr_t final_addr = dest_addr + rel_addend; - compiled_code_[rel_offset] = final_addr & 0xff; - compiled_code_[rel_offset + 1] = (final_addr >> 8) & 0xff; - compiled_code_[rel_offset + 2] = (final_addr >> 16) & 0xff; - compiled_code_[rel_offset + 3] = (final_addr >> 24) & 0xff; - } - - } else { - LOG(WARNING) << "Unexpected section: " << name.str(); - } - } - - return true; -} - - // Check whether the align is less than or equal to the code alignment of // that architecture. Since the Oat writer only guarantee that the compiled // method being aligned to kArchAlignment, we have no way to align the ELf diff --git a/src/compiler/llvm/llvm_compilation_unit.h b/src/compiler/llvm/llvm_compilation_unit.h index 9ca9e3f4c3..96d019c928 100644 --- a/src/compiler/llvm/llvm_compilation_unit.h +++ b/src/compiler/llvm/llvm_compilation_unit.h @@ -53,8 +53,8 @@ class LlvmCompilationUnit { public: ~LlvmCompilationUnit(); - size_t GetIndex() const { - return cunit_idx_; + uint32_t GetCompilationUnitId() const { + return cunit_id_; } InstructionSet GetInstructionSet() const; @@ -81,27 +81,30 @@ class LlvmCompilationUnit { void SetCompiler(CompilerDriver* driver) { driver_ = driver; } - void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) { + const DexCompilationUnit* GetDexCompilationUnit() { + return dex_compilation_unit_; + } + void SetDexCompilationUnit(const DexCompilationUnit* dex_compilation_unit) { dex_compilation_unit_ = dex_compilation_unit; } bool Materialize(); bool IsMaterialized() const { - return !compiled_code_.empty(); + return !elf_object_.empty(); } - const std::vector<uint8_t>& GetCompiledCode() const { + const std::string& GetElfObject() const { DCHECK(IsMaterialized()); - return compiled_code_; + return elf_object_; } private: LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, - size_t cunit_idx); + uint32_t cunit_id); const CompilerLLVM* compiler_llvm_; - const size_t cunit_idx_; + const uint32_t cunit_id_; UniquePtr< ::llvm::LLVMContext> context_; UniquePtr<IRBuilder> irb_; @@ -110,11 +113,11 @@ class LlvmCompilationUnit { UniquePtr<IntrinsicHelper> intrinsic_helper_; UniquePtr<LLVMInfo> llvm_info_; CompilerDriver* driver_; - DexCompilationUnit* dex_compilation_unit_; + const DexCompilationUnit* dex_compilation_unit_; std::string bitcode_filename_; - std::vector<uint8_t> compiled_code_; + std::string elf_object_; SafeMap<const ::llvm::Function*, CompiledMethod*> compiled_methods_map_; @@ -123,8 +126,6 @@ class LlvmCompilationUnit { bool MaterializeToString(std::string& str_buffer); bool MaterializeToRawOStream(::llvm::raw_ostream& out_stream); - bool ExtractCodeAndPrelink(const std::string& elf_image); - friend class CompilerLLVM; // For LlvmCompilationUnit constructor }; diff --git a/src/compiler/llvm/procedure_linkage_table.cc b/src/compiler/llvm/procedure_linkage_table.cc deleted file mode 100644 index 47ba9bd176..0000000000 --- a/src/compiler/llvm/procedure_linkage_table.cc +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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. - */ - -#include "procedure_linkage_table.h" - -#include "base/logging.h" -#include "compiler_runtime_func_list.h" -#include "globals.h" -#include "instruction_set.h" -#include "runtime_support_func_list.h" -#include "runtime_support_llvm.h" -#include "utils_llvm.h" - -#include <algorithm> - -#include <UniquePtr.h> - -#include <stddef.h> -#include <stdint.h> -#include <sys/mman.h> -#include <unistd.h> - - -namespace { - const char* const art_runtime_func_name_list[] = { -#define DEFINE_ENTRY(ID, NAME) #NAME, - RUNTIME_SUPPORT_FUNC_LIST(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - const char* const compiler_runtime_func_name_list_arm[] = { -#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME, - COMPILER_RUNTIME_FUNC_LIST_ARM(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - const char* const compiler_runtime_func_name_list_mips[] = { -#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME, - COMPILER_RUNTIME_FUNC_LIST_MIPS(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - const char* const compiler_runtime_func_name_list_x86[] = { -#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME, - COMPILER_RUNTIME_FUNC_LIST_X86(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - const size_t art_runtime_func_count = - sizeof(art_runtime_func_name_list) / sizeof(const char*); - - const size_t compiler_runtime_func_count_arm = - sizeof(compiler_runtime_func_name_list_arm) / sizeof(const char*); - - const size_t compiler_runtime_func_count_mips = - sizeof(compiler_runtime_func_name_list_mips) / sizeof(const char*); - - const size_t compiler_runtime_func_count_x86 = - sizeof(compiler_runtime_func_name_list_x86) / sizeof(const char*); -} - - -namespace art { -namespace llvm { - - -ProcedureLinkageTable::ProcedureLinkageTable(InstructionSet insn_set) - : insn_set_(insn_set) { -} - - -ProcedureLinkageTable::~ProcedureLinkageTable() { -} - - -bool ProcedureLinkageTable::AllocateTable() { - if (table_mmap_.get()) { - return true; - } - - // Allocate the PLT - byte* suggested_table_addr = reinterpret_cast<byte*>(kTableAddress); - - UniquePtr<MemMap> table_mmap( - MemMap::MapAnonymous(".plt", suggested_table_addr, - GetTableSizeInBytes(), PROT_READ | PROT_WRITE)); - - if (!table_mmap.get()) { - return false; - } - - if (table_mmap->Begin() != suggested_table_addr) { - // Our PLT should be allocated at the FIXED address - return false; - } - - // Create the stubs in the PLT - byte* stub_ptr = table_mmap->Begin(); - size_t stub_size = GetStubSizeInBytes(); - - for (size_t i = 0; i < art_runtime_func_count; ++i, stub_ptr += stub_size) { - const char* name = art_runtime_func_name_list[i]; - void* func = art_portable_find_runtime_support_func(NULL, name); - DCHECK(func != NULL); - CreateStub(stub_ptr, func); - } - - const char* const* crt_name_list = NULL; - size_t crt_count = 0u; - - switch (insn_set_) { - case kArm: - case kThumb2: - crt_name_list = compiler_runtime_func_name_list_arm; - crt_count = compiler_runtime_func_count_arm; - break; - - case kMips: - crt_name_list = compiler_runtime_func_name_list_mips; - crt_count = compiler_runtime_func_count_mips; - break; - - case kX86: - crt_name_list = compiler_runtime_func_name_list_x86; - crt_count = compiler_runtime_func_count_x86; - break; - - default: - LOG(FATAL) << "Unknown instruction set: " << insn_set_; - return false; - } - - for (size_t i = 0; i < crt_count; ++i, stub_ptr += stub_size) { - void* func = art_portable_find_runtime_support_func(NULL, crt_name_list[i]); - DCHECK(func != NULL); - CreateStub(stub_ptr, func); - } - - // Protect the procedure linkage table - table_mmap->Protect(PROT_READ | PROT_EXEC); - - // Flush the instruction cache on specific architecture -#if defined(__arm__) || defined(__mips__) - cacheflush(reinterpret_cast<long int>(table_mmap->Begin()), - reinterpret_cast<long int>(table_mmap->End()), 0); -#endif - - // Transfer the ownership - table_mmap_.reset(table_mmap.release()); - - return true; -} - - -uintptr_t ProcedureLinkageTable::GetEntryAddress(const char* name) const { - int func_idx = IndexOfRuntimeFunc(name); - if (func_idx == -1) { - return 0u; - } - - return (kTableAddress + func_idx * GetStubSizeInBytes()); -} - - - -int ProcedureLinkageTable::IndexOfRuntimeFunc(const char* name) const { - int result = IndexOfCompilerRuntimeFunc(name); - if (result != -1) { - return art_runtime_func_count + result; - } - - return IndexOfArtRuntimeFunc(name); -} - - -int ProcedureLinkageTable::IndexOfArtRuntimeFunc(const char* name) { - for (size_t i = 0; i < art_runtime_func_count; ++i) { - if (strcmp(name, art_runtime_func_name_list[i]) == 0) { - return static_cast<int>(i); - } - } - return -1; -} - -int ProcedureLinkageTable::IndexOfCompilerRuntimeFunc(InstructionSet insn_set, - const char* name) { - const char* const* rt_begin = NULL; - const char* const* rt_end = NULL; - - switch (insn_set) { - case kArm: - case kThumb2: - rt_begin = compiler_runtime_func_name_list_arm; - rt_end = compiler_runtime_func_name_list_arm + - compiler_runtime_func_count_arm; - break; - - case kMips: - rt_begin = compiler_runtime_func_name_list_mips; - rt_end = compiler_runtime_func_name_list_mips + - compiler_runtime_func_count_mips; - break; - - case kX86: - rt_begin = compiler_runtime_func_name_list_x86; - rt_end = compiler_runtime_func_name_list_x86 + - compiler_runtime_func_count_x86; - break; - - default: - LOG(FATAL) << "Unknown instruction set: " << insn_set; - return -1; - } - - const char* const* name_lbound_ptr = - std::lower_bound(rt_begin, rt_end, name, CStringLessThanComparator()); - - if (name_lbound_ptr < rt_end && strcmp(*name_lbound_ptr, name) == 0) { - return (name_lbound_ptr - rt_begin); - } else { - return -1; - } -} - - -size_t ProcedureLinkageTable::GetStubCount(InstructionSet insn_set) { - switch (insn_set) { - case kArm: - case kThumb2: - return art_runtime_func_count + compiler_runtime_func_count_arm; - - case kMips: - return art_runtime_func_count + compiler_runtime_func_count_mips; - - case kX86: - return art_runtime_func_count + compiler_runtime_func_count_x86; - - default: - LOG(FATAL) << "Unknown instruction set: " << insn_set; - return 0u; - } -} - - -size_t ProcedureLinkageTable::GetStubSizeInBytes(InstructionSet insn_set) { - switch (insn_set) { - case kArm: - case kThumb2: - return 8u; - - case kMips: - return 16u; - - case kX86: - return 8u; - - default: - LOG(FATAL) << "Unknown instruction set: " << insn_set; - return 0u; - } -} - - -void ProcedureLinkageTable::CreateStub(InstructionSet insn_set, - byte* stub, void* dest_) { - switch (insn_set) { - case kArm: - case kThumb2: - { - uint32_t dest = static_cast<uint32_t>( - reinterpret_cast<uintptr_t>(dest_) & 0xfffffffful); - uint32_t* stub_w = reinterpret_cast<uint32_t*>(stub); - - stub_w[0] = 0xe51ff004ul; // ldr pc, [pc #-4] - stub_w[1] = dest; - } - break; - - case kMips: - { - uint32_t dest = static_cast<uint32_t>( - reinterpret_cast<uintptr_t>(dest_) & 0xfffffffful); - uint32_t* stub_w = reinterpret_cast<uint32_t*>(stub); - - stub_w[0] = 0x3c190000ul | ((dest >> 16) & 0xfffful); // lui - stub_w[1] = 0x37390000ul | (dest & 0xfffful);; // ori - stub_w[2] = 0x03200008ul; // jr (jump register) - stub_w[3] = 0x00000000ul; // nop - } - break; - - case kX86: - { - uint32_t off = static_cast<uint32_t>( - reinterpret_cast<uintptr_t>(dest_) - - reinterpret_cast<uintptr_t>(stub + 1) - 4); - // jmp (32-bit offset) - stub[0] = 0xe9u; - stub[1] = off & 0xffu; - stub[2] = (off >> 8) & 0xffu; - stub[2] = (off >> 16) & 0xffu; - stub[2] = (off >> 24) & 0xffu; - } - break; - - default: - LOG(FATAL) << "Unknown instruction set: " << insn_set; - } -} - - -} // namespace llvm -} // namespace art diff --git a/src/compiler/llvm/procedure_linkage_table.h b/src/compiler/llvm/procedure_linkage_table.h deleted file mode 100644 index 1c89d29fdb..0000000000 --- a/src/compiler/llvm/procedure_linkage_table.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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_SRC_COMPILER_LLVM_PROCEDURE_LINKAGE_TABLE_H_ -#define ART_SRC_COMPILER_LLVM_PROCEDURE_LINKAGE_TABLE_H_ - -#include "globals.h" -#include "instruction_set.h" -#include "mem_map.h" - -#include <UniquePtr.h> - -#include <stddef.h> -#include <stdint.h> - -namespace art { -namespace llvm { - - -class ProcedureLinkageTable { - public: - ProcedureLinkageTable(InstructionSet insn_set); - - ~ProcedureLinkageTable(); - - bool AllocateTable(); - - uintptr_t GetEntryAddress(const char* func_name) const; - - private: - static size_t GetStubCount(InstructionSet insn_set); - static size_t GetStubSizeInBytes(InstructionSet insn_set); - static void CreateStub(InstructionSet insn_set, - byte* stub, void* branch_dest); - - int IndexOfRuntimeFunc(const char* name) const; - static int IndexOfArtRuntimeFunc(const char* name); - static int IndexOfCompilerRuntimeFunc(InstructionSet insn_set, - const char* name); - - size_t GetStubCount() const { - return GetStubCount(insn_set_); - } - - size_t GetStubSizeInBytes() const { - return GetStubSizeInBytes(insn_set_); - } - - size_t GetTableSizeInBytes() const { - return GetStubSizeInBytes() * GetStubCount(); - } - - void CreateStub(byte* stub, void* branch_dest) { - return CreateStub(insn_set_, stub, branch_dest); - } - - int IndexOfCompilerRuntimeFunc(const char* name) const { - return IndexOfCompilerRuntimeFunc(insn_set_, name); - } - - InstructionSet insn_set_; - UniquePtr<MemMap> table_mmap_; - - static const size_t kTableSizeInBytes = 1024u; - static const uintptr_t kTableAddress = 0x5fffc000u; -}; - - -} // namespace llvm -} // namespace art - -#endif // ART_SRC_COMPILER_LLVM_PROCEDURE_LINKAGE_TABLE_H_ diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc index ae8bb4a8a5..b18eefe562 100644 --- a/src/compiler/llvm/runtime_support_llvm.cc +++ b/src/compiler/llvm/runtime_support_llvm.cc @@ -20,7 +20,6 @@ #include "asm_support.h" #include "class_linker.h" #include "class_linker-inl.h" -#include "compiler_runtime_func_list.h" #include "dex_file.h" #include "dex_instruction.h" #include "mirror/abstract_method-inl.h" @@ -743,46 +742,6 @@ mirror::Object* art_portable_jni_method_end_with_reference_synchronized(jobject return o; } -//---------------------------------------------------------------------------- -// Runtime Support Function Lookup Callback -//---------------------------------------------------------------------------- - -#define EXTERNAL_LINKAGE(NAME, RETURN_TYPE, ...) \ -extern "C" RETURN_TYPE NAME(__VA_ARGS__); -COMPILER_RUNTIME_FUNC_LIST_NATIVE(EXTERNAL_LINKAGE) -#undef EXTERNAL_LINKAGE - -static void* art_portable_find_compiler_runtime_func(const char* name) { -// TODO: If target support some math func, use the target's version. (e.g. art_portable_d2i -> __aeabi_d2iz) - static const char* const names[] = { -#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) #NAME , - COMPILER_RUNTIME_FUNC_LIST_NATIVE(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - static void* const funcs[] = { -#define DEFINE_ENTRY(NAME, RETURN_TYPE, ...) \ - reinterpret_cast<void*>(static_cast<RETURN_TYPE (*)(__VA_ARGS__)>(NAME)) , - COMPILER_RUNTIME_FUNC_LIST_NATIVE(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - static const size_t num_entries = sizeof(names) / sizeof(const char* const); - - const char* const* const names_begin = names; - const char* const* const names_end = names + num_entries; - - const char* const* name_lbound_ptr = - std::lower_bound(names_begin, names_end, name, - CStringLessThanComparator()); - - if (name_lbound_ptr < names_end && strcmp(*name_lbound_ptr, name) == 0) { - return funcs[name_lbound_ptr - names_begin]; - } else { - return NULL; - } -} - // Handler for invocation on proxy methods. Create a boxed argument array and invoke the invocation // handler which is a field within the proxy object receiver. The var args encode the arguments // with the last argument being a pointer to a JValue to store the result in. @@ -860,43 +819,6 @@ void art_portable_proxy_invoke_handler_from_code(mirror::AbstractMethod* proxy_m } } -void* art_portable_find_runtime_support_func(void* context, const char* name) { - struct func_entry_t { - const char* name; - size_t name_len; - void* addr; - }; - - static struct func_entry_t const tab[] = { -#define DEFINE_ENTRY(ID, NAME) \ - { #NAME, sizeof(#NAME) - 1, reinterpret_cast<void*>(NAME) }, - RUNTIME_SUPPORT_FUNC_LIST(DEFINE_ENTRY) -#undef DEFINE_ENTRY - }; - - static size_t const tab_size = sizeof(tab) / sizeof(struct func_entry_t); - - // Search the compiler runtime (such as __divdi3) - void* result = art_portable_find_compiler_runtime_func(name); - if (result != NULL) { - return result; - } - - // Note: Since our table is small, we are using trivial O(n) searching - // function. For bigger table, it will be better to use a binary - // search or hash function. - size_t i; - size_t name_len = strlen(name); - for (i = 0; i < tab_size; ++i) { - if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) { - return tab[i].addr; - } - } - - LOG(FATAL) << "Error: Can't find symbol " << name; - return 0; -} - //---------------------------------------------------------------------------- // Memory barrier //---------------------------------------------------------------------------- diff --git a/src/compiler/llvm/utils_llvm.h b/src/compiler/llvm/utils_llvm.h index e06e113aa7..2e273f4fe9 100644 --- a/src/compiler/llvm/utils_llvm.h +++ b/src/compiler/llvm/utils_llvm.h @@ -17,13 +17,8 @@ #ifndef ART_SRC_UTILS_LLVM_H_ #define ART_SRC_UTILS_LLVM_H_ -#include "base/stringprintf.h" - #include <llvm/Analysis/Verifier.h> -#include <stdint.h> -#include <string> - namespace art { #ifndef NDEBUG @@ -32,17 +27,6 @@ namespace art { #define VERIFY_LLVM_FUNCTION(func) #endif -inline static std::string ElfFuncName(uint32_t idx) { - return StringPrintf("Art%u", static_cast<unsigned int>(idx)); -} - -class CStringLessThanComparator { - public: - bool operator()(const char* lhs, const char* rhs) const { - return (strcmp(lhs, rhs) < 0); - } -}; - } // namespace art #endif // ART_SRC_UTILS_LLVM_H_ diff --git a/src/dex2oat.cc b/src/dex2oat.cc index 6b94dc01d4..6892bb3623 100644 --- a/src/dex2oat.cc +++ b/src/dex2oat.cc @@ -81,13 +81,19 @@ static void Usage(const char* fmt, ...) { UsageError(" to the file descriptor specified by --zip-fd."); UsageError(" Example: --zip-location=/system/app/Calculator.apk"); UsageError(""); - UsageError(" --oat-file=<file.oat>: specifies the required oat filename."); + UsageError(" --oat-file=<file.oat>: specifies the oat output destination via a filename."); + UsageError(" Example: --oat-file=/system/framework/boot.oat"); + UsageError(""); + UsageError(" --oat-fd=<number>: specifies the oat output destination via a file descriptor."); UsageError(" Example: --oat-file=/system/framework/boot.oat"); UsageError(""); UsageError(" --oat-location=<oat-name>: specifies a symbolic name for the file corresponding"); UsageError(" to the file descriptor specified by --oat-fd."); UsageError(" Example: --oat-location=/data/art-cache/system@app@Calculator.apk.oat"); UsageError(""); + UsageError(" --oat-symbols=<file.oat>: specifies the oat output destination with full symbols."); + UsageError(" Example: --oat-symbols=/symbols/system/framework/boot.oat"); + UsageError(""); UsageError(" --bitcode=<file.bc>: specifies the optional bitcode filename."); UsageError(" Example: --bitcode=/system/framework/boot.bc"); UsageError(""); @@ -104,7 +110,7 @@ static void Usage(const char* fmt, ...) { UsageError(" Example: --boot-image=/system/framework/boot.art"); UsageError(" Default: <host-prefix>/system/framework/boot.art"); UsageError(""); - UsageError(" --host-prefix may be used to translate host paths to target paths during"); + UsageError(" --host-prefix=<path>: used to translate host paths to target paths during"); UsageError(" cross compilation."); UsageError(" Example: --host-prefix=out/target/product/crespo"); UsageError(" Default: $ANDROID_PRODUCT_OUT"); @@ -118,6 +124,9 @@ static void Usage(const char* fmt, ...) { UsageError(" set."); UsageError(" Example: --instruction-set=Portable"); UsageError(" Default: Quick"); + UsageError(""); + UsageError(" --host: used with Portable backend to link against host runtime libraries"); + UsageError(""); UsageError(" --runtime-arg <argument>: used to specify various arguments for the runtime,"); UsageError(" such as initial heap size, maximum heap size, and verbose output."); UsageError(" Use a separate --runtime-arg switch for each argument."); @@ -215,6 +224,7 @@ class Dex2Oat { const CompilerDriver* CreateOatFile(const std::string& boot_image_option, const std::string* host_prefix, + bool is_host, const std::vector<const DexFile*>& dex_files, File* oat_file, const std::string& bitcode_filename, @@ -285,7 +295,7 @@ class Dex2Oat { return NULL; } - if (!driver->WriteElf(oat_contents, oat_file)) { + if (!driver->WriteElf(host_prefix, is_host, dex_files, oat_contents, oat_file)) { LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath(); return NULL; } @@ -311,9 +321,7 @@ class Dex2Oat { oat_data_begin = image_writer.GetOatDataBegin(); } - LG << "dex2oat CreateImageFile opening : " << oat_filename; UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true, false)); - LG << "dex2oat CreateImageFile opened : " << oat_filename; if (oat_file.get() == NULL) { PLOG(ERROR) << "Failed to open ELF file: " << oat_filename; return false; @@ -322,7 +330,6 @@ class Dex2Oat { LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath(); return false; } - LOG(ERROR) << "ELF file fixed up successfully: " << oat_file->GetPath(); return true; } @@ -634,6 +641,7 @@ static int dex2oat(int argc, char** argv) { int zip_fd = -1; std::string zip_location; std::string oat_filename; + std::string oat_symbols; std::string oat_location; int oat_fd = -1; std::string bitcode_filename; @@ -659,6 +667,7 @@ static int dex2oat(int argc, char** argv) { #else #error "Unsupported architecture" #endif + bool is_host = false; bool dump_stats = kIsDebugBuild; bool dump_timings = kIsDebugBuild; bool watch_dog_enabled = !kIsTargetBuild; @@ -682,6 +691,8 @@ static int dex2oat(int argc, char** argv) { zip_location = option.substr(strlen("--zip-location=")).data(); } else if (option.starts_with("--oat-file=")) { oat_filename = option.substr(strlen("--oat-file=")).data(); + } else if (option.starts_with("--oat-symbols=")) { + oat_symbols = option.substr(strlen("--oat-symbols=")).data(); } else if (option.starts_with("--oat-fd=")) { const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data(); if (!ParseInt(oat_fd_str, &oat_fd)) { @@ -735,6 +746,8 @@ static int dex2oat(int argc, char** argv) { } else if (backend_str == "Portable") { compiler_backend = kPortable; } + } else if (option == "--host") { + is_host = true; } else if (option == "--runtime-arg") { if (++i >= argc) { Usage("Missing required argument for --runtime-arg"); @@ -756,8 +769,12 @@ static int dex2oat(int argc, char** argv) { Usage("--oat-file should not be used with --oat-fd"); } - if (!oat_filename.empty() && oat_fd != -1) { - Usage("--oat-file should not be used with --oat-fd"); + if (!oat_symbols.empty() && oat_fd != -1) { + Usage("--oat-symbols should not be used with --oat-fd"); + } + + if (!oat_symbols.empty() && is_host) { + Usage("--oat-symbols should not be used with --host"); } if (oat_fd != -1 && !image_filename.empty()) { @@ -825,14 +842,22 @@ static int dex2oat(int argc, char** argv) { } } + std::string oat_stripped(oat_filename); + std::string oat_unstripped; + if (!oat_symbols.empty()) { + oat_unstripped += oat_symbols; + } else { + oat_unstripped += oat_filename; + } + // Done with usage checks, enable watchdog if requested WatchDog watch_dog(watch_dog_enabled); // Check early that the result of compilation can be written UniquePtr<File> oat_file; - bool create_file = !oat_filename.empty(); // as opposed to using open file descriptor + bool create_file = !oat_unstripped.empty(); // as opposed to using open file descriptor if (create_file) { - oat_file.reset(OS::OpenFile(oat_filename.c_str(), true)); + oat_file.reset(OS::OpenFile(oat_unstripped.c_str(), true)); if (oat_location.empty()) { oat_location = oat_filename; } @@ -921,6 +946,7 @@ static int dex2oat(int argc, char** argv) { UniquePtr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option, host_prefix.get(), + is_host, dex_files, oat_file.get(), bitcode_filename, @@ -934,10 +960,7 @@ static int dex2oat(int argc, char** argv) { return EXIT_FAILURE; } - if (!image) { - LOG(INFO) << "Oat file written successfully: " << oat_location; - return EXIT_SUCCESS; - } + LOG(INFO) << "Oat file written successfully (unstripped): " << oat_location; // Notes on the interleaving of creating the image and oat file to // ensure the references between the two are correct. @@ -989,21 +1012,52 @@ static int dex2oat(int argc, char** argv) { // load the .so at the desired location at runtime by offsetting the // Elf32_Phdr.p_vaddr values by the desired base address. // - Thread::Current()->TransitionFromRunnableToSuspended(kNative); - bool image_creation_success = dex2oat->CreateImageFile(image_filename, - image_base, - image_classes.get(), - oat_filename, - oat_location, - *compiler.get()); - Thread::Current()->TransitionFromSuspendedToRunnable(); - if (!image_creation_success) { - return EXIT_FAILURE; + if (image) { + Thread::Current()->TransitionFromRunnableToSuspended(kNative); + bool image_creation_success = dex2oat->CreateImageFile(image_filename, + image_base, + image_classes.get(), + oat_unstripped, + oat_location, + *compiler.get()); + Thread::Current()->TransitionFromSuspendedToRunnable(); + LOG(INFO) << "Image written successfully: " << image_filename; + if (!image_creation_success) { + return EXIT_FAILURE; + } + } + + if (is_host) { + return EXIT_SUCCESS; } + // If we don't want to strip in place, copy from unstripped location to stripped location. + // We need to strip after image creation because FixupElf needs to use .strtab. + if (oat_unstripped != oat_stripped) { + oat_file.reset(); + UniquePtr<File> in(OS::OpenFile(oat_unstripped.c_str(), false)); + UniquePtr<File> out(OS::OpenFile(oat_stripped.c_str(), true)); + size_t buffer_size = 8192; + UniquePtr<uint8_t> buffer(new uint8_t[buffer_size]); + while (true) { + int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size)); + if (bytes_read <= 0) { + break; + } + bool write_ok = out->WriteFully(buffer.get(), bytes_read); + CHECK(write_ok); + } + oat_file.reset(out.release()); + LOG(INFO) << "Oat file copied successfully (stripped): " << oat_stripped; + } + + // Strip unneeded sections for target + off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET); + CHECK_EQ(0, seek_actual); + compiler->StripElf(oat_file.get()); + // We wrote the oat file successfully, and want to keep it. - LOG(INFO) << "Oat file written successfully: " << oat_filename; - LOG(INFO) << "Image written successfully: " << image_filename; + LOG(INFO) << "Oat file written successfully (stripped): " << oat_stripped; return EXIT_SUCCESS; } diff --git a/src/dex_method_iterator.h b/src/dex_method_iterator.h new file mode 100644 index 0000000000..dc2e712681 --- /dev/null +++ b/src/dex_method_iterator.h @@ -0,0 +1,150 @@ +/* + * 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_SRC_DEX_METHOD_ITERATOR_H_ +#define ART_SRC_DEX_METHOD_ITERATOR_H_ + +#include <vector> + +#include "dex_file.h" + +namespace art { + +class DexMethodIterator { + public: + DexMethodIterator(const std::vector<const DexFile*>& dex_files) + : dex_files_(dex_files), + found_next_(false), + dex_file_index_(0), + class_def_index_(0), + class_def_(NULL), + class_data_(NULL), + direct_method_(false) { + CHECK_NE(0U, dex_files_.size()); + } + + bool HasNext() { + if (found_next_) { + return true; + } + while (true) { + // End of DexFiles, we are done. + if (dex_file_index_ == dex_files_.size()) { + return false; + } + if (class_def_index_ == GetDexFileInternal().NumClassDefs()) { + // End of this DexFile, advance and retry. + class_def_index_ = 0; + dex_file_index_++; + continue; + } + if (class_def_ == NULL) { + class_def_ = &GetDexFileInternal().GetClassDef(class_def_index_); + } + if (class_data_ == NULL) { + class_data_ = GetDexFileInternal().GetClassData(*class_def_); + if (class_data_ == NULL) { + // empty class, such as a marker interface + // End of this class, advance and retry. + class_def_ = NULL; + class_def_index_++; + continue; + } + } + if (it_.get() == NULL) { + it_.reset(new ClassDataItemIterator(GetDexFileInternal(), class_data_)); + // Skip fields + while (GetIterator().HasNextStaticField()) { + GetIterator().Next(); + } + while (GetIterator().HasNextInstanceField()) { + GetIterator().Next(); + } + direct_method_ = true; + } + if (direct_method_ && GetIterator().HasNextDirectMethod()) { + // Found method + found_next_ = true; + return true; + } + direct_method_ = false; + if (GetIterator().HasNextVirtualMethod()) { + // Found method + found_next_ = true; + return true; + } + // End of this class, advance and retry. + DCHECK(!GetIterator().HasNext()); + it_.reset(NULL); + class_data_ = NULL; + class_def_ = NULL; + class_def_index_++; + } + } + + void Next() { + found_next_ = false; + if (it_.get() != NULL) { + // Advance to next method if we currently are looking at a class. + GetIterator().Next(); + } + } + + const DexFile& GetDexFile() { + CHECK(HasNext()); + return GetDexFileInternal(); + } + + uint32_t GetMemberIndex() { + CHECK(HasNext()); + return GetIterator().GetMemberIndex(); + } + + InvokeType GetInvokeType() { + CHECK(HasNext()); + CHECK(class_def_ != NULL); + return GetIterator().GetMethodInvokeType(*class_def_); + } + + private: + + ClassDataItemIterator& GetIterator() const { + CHECK(it_.get() != NULL); + return *it_.get(); + } + + const DexFile& GetDexFileInternal() const { + CHECK_LT(dex_file_index_, dex_files_.size()); + const DexFile* dex_file = dex_files_[dex_file_index_]; + CHECK(dex_file != NULL); + return *dex_file; + } + + const std::vector<const DexFile*>& dex_files_; + + bool found_next_; + + uint32_t dex_file_index_; + uint32_t class_def_index_; + const DexFile::ClassDef* class_def_; + const byte* class_data_; + UniquePtr<ClassDataItemIterator> it_; + bool direct_method_; +}; + +} // namespace art + +#endif // ART_SRC_DEX_METHOD_ITERATOR_H_ diff --git a/src/dex_method_iterator_test.cc b/src/dex_method_iterator_test.cc new file mode 100644 index 0000000000..e4a42db792 --- /dev/null +++ b/src/dex_method_iterator_test.cc @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex_method_iterator.h" + +#include "common_test.h" + +namespace art { + +class DexMethodIteratorTest : public CommonTest {}; + +TEST_F(DexMethodIteratorTest, Basic) { + ScopedObjectAccess soa(Thread::Current()); + std::vector<const DexFile*> dex_files; + dex_files.push_back(DexFile::Open(GetDexFileName("core"), GetDexFileName("core"))); + dex_files.push_back(DexFile::Open(GetDexFileName("core-junit"), GetDexFileName("core-junit"))); + dex_files.push_back(DexFile::Open(GetDexFileName("bouncycastle"), GetDexFileName("bouncycastle"))); + DexMethodIterator it(dex_files); + while (it.HasNext()) { + const DexFile& dex_file = it.GetDexFile(); + InvokeType invoke_type = it.GetInvokeType(); + uint32_t method_idx = it.GetMemberIndex(); + if (false) { + LG << invoke_type << " " << PrettyMethod(method_idx, dex_file); + } + it.Next(); + } + STLDeleteElements(&dex_files); +} + +} // namespace art diff --git a/src/elf_file.cc b/src/elf_file.cc index 8d6e630c1f..6f9d53c839 100644 --- a/src/elf_file.cc +++ b/src/elf_file.cc @@ -36,7 +36,9 @@ ElfFile::ElfFile() : dynsym_section_start_(NULL), strtab_section_start_(NULL), dynstr_section_start_(NULL), - hash_section_start_(NULL) {} + hash_section_start_(NULL), + symtab_symbol_table_(NULL), + dynsym_symbol_table_(NULL) {} ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only) { UniquePtr<ElfFile> elf_file(new ElfFile()); @@ -61,28 +63,34 @@ bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { prot = PROT_READ; flags = MAP_PRIVATE; } - if (file->GetLength() < sizeof(llvm::ELF::Elf32_Ehdr)) { - LOG(WARNING) << "File not large enough to contain ELF header: " << file->GetPath(); + int64_t file_length = file_->GetLength(); + if (file_length < 0) { + errno = -file_length; + PLOG(WARNING) << "Failed to get length of file: " << file_->GetPath() << " fd=" << file_->Fd(); + return false; + } + if (file_length < sizeof(llvm::ELF::Elf32_Ehdr)) { + LOG(WARNING) << "File not large enough to contain ELF header: " << file_->GetPath(); return false; } if (program_header_only) { // first just map ELF header to get program header size information size_t elf_header_size = sizeof(llvm::ELF::Elf32_Ehdr); - if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file->Fd(), 0))) { - LOG(WARNING) << "Failed to map ELF header: " << file->GetPath(); + if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0))) { + LOG(WARNING) << "Failed to map ELF header: " << file_->GetPath(); return false; } // then remap to cover program header size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum); - if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file->Fd(), 0))) { - LOG(WARNING) << "Failed to map ELF program headers: " << file->GetPath(); + if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0))) { + LOG(WARNING) << "Failed to map ELF program headers: " << file_->GetPath(); return false; } } else { // otherwise map entire file - if (!SetMap(MemMap::MapFile(file->GetLength(), prot, flags, file->Fd(), 0))) { - LOG(WARNING) << "Failed to map ELF file: " << file->GetPath(); + if (!SetMap(MemMap::MapFile(file_->GetLength(), prot, flags, file_->Fd(), 0))) { + LOG(WARNING) << "Failed to map ELF file: " << file_->GetPath(); return false; } } @@ -97,7 +105,7 @@ bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { // Find .dynamic section info from program header dynamic_program_header_ = FindProgamHeaderByType(llvm::ELF::PT_DYNAMIC); if (dynamic_program_header_ == NULL) { - LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file->GetPath(); + LOG(WARNING) << "Failed to find PT_DYNAMIC program header in ELF file: " << file_->GetPath(); return false; } @@ -129,7 +137,7 @@ bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { case llvm::ELF::SHT_DYNAMIC: { if (reinterpret_cast<byte*>(dynamic_section_start_) != section_addr) { LOG(WARNING) << "Failed to find matching SHT_DYNAMIC for PT_DYNAMIC in " - << file->GetPath() << ": " << std::hex + << file_->GetPath() << ": " << std::hex << reinterpret_cast<void*>(dynamic_section_start_) << " != " << reinterpret_cast<void*>(section_addr); return false; @@ -148,6 +156,8 @@ bool ElfFile::Setup(File* file, bool writable, bool program_header_only) { ElfFile::~ElfFile() { STLDeleteElements(&segments_); + delete symtab_symbol_table_; + delete dynsym_symbol_table_; } bool ElfFile::SetMap(MemMap* map) { @@ -247,9 +257,9 @@ llvm::ELF::Elf32_Sym* ElfFile::GetSymbolSectionStart(llvm::ELF::Elf32_Word secti return symbol_section_start; } -char* ElfFile::GetSymbolStringSectionStart(llvm::ELF::Elf32_Word section_type) { +const char* ElfFile::GetStringSectionStart(llvm::ELF::Elf32_Word section_type) { CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; - char* string_section_start; + const char* string_section_start; switch (section_type) { case llvm::ELF::SHT_SYMTAB: { string_section_start = strtab_section_start_; @@ -268,6 +278,16 @@ char* ElfFile::GetSymbolStringSectionStart(llvm::ELF::Elf32_Word section_type) { return string_section_start; } +const char* ElfFile::GetString(llvm::ELF::Elf32_Word section_type, llvm::ELF::Elf32_Word i) { + CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; + if (i == 0) { + return NULL; + } + const char* string_section_start = GetStringSectionStart(section_type); + const char* string = string_section_start + i; + return string; +} + llvm::ELF::Elf32_Word* ElfFile::GetHashSectionStart() { CHECK(hash_section_start_ != NULL); return hash_section_start_; @@ -342,28 +362,30 @@ llvm::ELF::Elf32_Shdr* ElfFile::FindSectionByType(llvm::ELF::Elf32_Word type) { } // from bionic -static unsigned elfhash(const char *_name) -{ - const unsigned char *name = (const unsigned char *) _name; - unsigned h = 0, g; +static unsigned elfhash(const char *_name) { + const unsigned char *name = (const unsigned char *) _name; + unsigned h = 0, g; + + while(*name) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + h ^= g; + h ^= g >> 24; + } + return h; +} - while(*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - h ^= g; - h ^= g >> 24; - } - return h; +llvm::ELF::Elf32_Shdr& ElfFile::GetSectionNameStringSection() { + return GetSectionHeader(GetHeader().e_shstrndx); } byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) { llvm::ELF::Elf32_Word hash = elfhash(symbol_name.c_str()); llvm::ELF::Elf32_Word bucket_index = hash % GetHashBucketNum(); llvm::ELF::Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index); - char* symbol_string_section_start = GetSymbolStringSectionStart(llvm::ELF::SHT_DYNSYM); while (symbol_and_chain_index != 0 /* STN_UNDEF */) { llvm::ELF::Elf32_Sym& symbol = GetSymbol(llvm::ELF::SHT_DYNSYM, symbol_and_chain_index); - char* name = symbol_string_section_start + symbol.st_name; + const char* name = GetString(llvm::ELF::SHT_DYNSYM, symbol.st_name); if (symbol_name == name) { return base_address_ + symbol.st_value; } @@ -387,10 +409,66 @@ llvm::ELF::Elf32_Sym& ElfFile::GetSymbol(llvm::ELF::Elf32_Word section_type, return *(GetSymbolSectionStart(section_type) + i); } +ElfFile::SymbolTable** ElfFile::GetSymbolTable(llvm::ELF::Elf32_Word section_type) { + CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; + switch (section_type) { + case llvm::ELF::SHT_SYMTAB: { + return &symtab_symbol_table_; + } + case llvm::ELF::SHT_DYNSYM: { + return &dynsym_symbol_table_; + } + default: { + LOG(FATAL) << section_type; + return NULL; + } + } +} + llvm::ELF::Elf32_Sym* ElfFile::FindSymbolByName(llvm::ELF::Elf32_Word section_type, - const std::string& symbol_name) { + const std::string& symbol_name, + bool build_map) { CHECK(!program_header_only_) << file_->GetPath(); CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; + + SymbolTable** symbol_table = GetSymbolTable(section_type); + if (*symbol_table != NULL || build_map) { + if (*symbol_table == NULL) { + DCHECK(build_map); + *symbol_table = new SymbolTable; + llvm::ELF::Elf32_Shdr* symbol_section = FindSectionByType(section_type); + CHECK(symbol_section != NULL) << file_->GetPath(); + llvm::ELF::Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link); + for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) { + llvm::ELF::Elf32_Sym& symbol = GetSymbol(section_type, i); + unsigned char type = symbol.getType(); + if (type == llvm::ELF::STT_NOTYPE) { + continue; + } + const char* name = GetString(string_section, symbol.st_name); + if (name == NULL) { + continue; + } + std::pair<SymbolTable::iterator, bool> result = (*symbol_table)->insert(std::make_pair(name, &symbol)); + if (!result.second) { + // If a duplicate, make sure it has the same logical value. Seen on x86. + CHECK_EQ(symbol.st_value, result.first->second->st_value); + CHECK_EQ(symbol.st_size, result.first->second->st_size); + CHECK_EQ(symbol.st_info, result.first->second->st_info); + CHECK_EQ(symbol.st_other, result.first->second->st_other); + CHECK_EQ(symbol.st_shndx, result.first->second->st_shndx); + } + } + } + CHECK(*symbol_table != NULL); + SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name); + if (it == (*symbol_table)->end()) { + return NULL; + } + return it->second; + } + + // Fall back to linear search llvm::ELF::Elf32_Shdr* symbol_section = FindSectionByType(section_type); CHECK(symbol_section != NULL) << file_->GetPath(); llvm::ELF::Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link); @@ -408,15 +486,16 @@ llvm::ELF::Elf32_Sym* ElfFile::FindSymbolByName(llvm::ELF::Elf32_Word section_ty } llvm::ELF::Elf32_Addr ElfFile::FindSymbolAddress(llvm::ELF::Elf32_Word section_type, - const std::string& symbol_name) { - llvm::ELF::Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name); + const std::string& symbol_name, + bool build_map) { + llvm::ELF::Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map); if (symbol == NULL) { return 0; } return symbol->st_value; } -char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32_Word i) { +const char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32_Word i) { CHECK(!program_header_only_) << file_->GetPath(); // TODO: remove this static_cast from enum when using -std=gnu++0x CHECK_EQ(static_cast<llvm::ELF::Elf32_Word>(llvm::ELF::SHT_STRTAB), string_section.sh_type) << file_->GetPath(); @@ -427,7 +506,7 @@ char* ElfFile::GetString(llvm::ELF::Elf32_Shdr& string_section, llvm::ELF::Elf32 byte* strings = Begin() + string_section.sh_offset; byte* string = strings + i; CHECK_LT(string, End()) << file_->GetPath(); - return reinterpret_cast<char*>(string); + return reinterpret_cast<const char*>(string); } llvm::ELF::Elf32_Word ElfFile::GetDynamicNum() { @@ -439,6 +518,50 @@ llvm::ELF::Elf32_Dyn& ElfFile::GetDynamic(llvm::ELF::Elf32_Word i) { return *(GetDynamicSectionStart() + i); } +llvm::ELF::Elf32_Word ElfFile::FindDynamicValueByType(llvm::ELF::Elf32_Sword type) { + for (llvm::ELF::Elf32_Word i = 0; i < GetDynamicNum(); i++) { + llvm::ELF::Elf32_Dyn& elf_dyn = GetDynamic(i); + if (elf_dyn.d_tag == type) { + return elf_dyn.d_un.d_val; + } + } + return 0; +} + +llvm::ELF::Elf32_Rel* ElfFile::GetRelSectionStart(llvm::ELF::Elf32_Shdr& section_header) { + CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; + return reinterpret_cast<llvm::ELF::Elf32_Rel*>(Begin() + section_header.sh_offset); +} + +llvm::ELF::Elf32_Word ElfFile::GetRelNum(llvm::ELF::Elf32_Shdr& section_header) { + CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; + CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath(); + return section_header.sh_size / section_header.sh_entsize; +} + +llvm::ELF::Elf32_Rel& ElfFile::GetRel(llvm::ELF::Elf32_Shdr& section_header, llvm::ELF::Elf32_Word i) { + CHECK(llvm::ELF::SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; + CHECK_LT(i, GetRelNum(section_header)) << file_->GetPath(); + return *(GetRelSectionStart(section_header) + i); +} + +llvm::ELF::Elf32_Rela* ElfFile::GetRelaSectionStart(llvm::ELF::Elf32_Shdr& section_header) { + CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; + return reinterpret_cast<llvm::ELF::Elf32_Rela*>(Begin() + section_header.sh_offset); +} + +llvm::ELF::Elf32_Word ElfFile::GetRelaNum(llvm::ELF::Elf32_Shdr& section_header) { + CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; + return section_header.sh_size / section_header.sh_entsize; +} + +llvm::ELF::Elf32_Rela& ElfFile::GetRela(llvm::ELF::Elf32_Shdr& section_header, + llvm::ELF::Elf32_Word i) { + CHECK(llvm::ELF::SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; + CHECK_LT(i, GetRelaNum(section_header)) << file_->GetPath(); + return *(GetRelaSectionStart(section_header) + i); +} + // Base on bionic phdr_table_get_load_size size_t ElfFile::GetLoadedSize() { llvm::ELF::Elf32_Addr min_vaddr = 0xFFFFFFFFu; @@ -528,6 +651,7 @@ bool ElfFile::Load() { CHECK_EQ(segment->Begin(), p_vaddr) << file_->GetPath(); segments_.push_back(segment.release()); } + // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash dynamic_section_start_ = reinterpret_cast<llvm::ELF::Elf32_Dyn*>(base_address_ + GetDynamicProgramHeader().p_vaddr); @@ -549,6 +673,7 @@ bool ElfFile::Load() { } case llvm::ELF::DT_NULL: { CHECK_EQ(GetDynamicNum(), i+1); + break; } } } diff --git a/src/elf_file.h b/src/elf_file.h index b1d787e931..59ce7f5bfd 100644 --- a/src/elf_file.h +++ b/src/elf_file.h @@ -17,6 +17,7 @@ #ifndef ART_SRC_ELF_FILE_H_ #define ART_SRC_ELF_FILE_H_ +#include <map> #include <vector> #include <llvm/Support/ELF.h> @@ -65,20 +66,49 @@ class ElfFile { ::llvm::ELF::Elf32_Shdr& GetSectionHeader(::llvm::ELF::Elf32_Word); ::llvm::ELF::Elf32_Shdr* FindSectionByType(::llvm::ELF::Elf32_Word type); + ::llvm::ELF::Elf32_Shdr& GetSectionNameStringSection(); + + // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress. byte* FindDynamicSymbolAddress(const std::string& symbol_name); static bool IsSymbolSectionType(::llvm::ELF::Elf32_Word section_type); ::llvm::ELF::Elf32_Word GetSymbolNum(::llvm::ELF::Elf32_Shdr&); ::llvm::ELF::Elf32_Sym& GetSymbol(::llvm::ELF::Elf32_Word section_type, ::llvm::ELF::Elf32_Word i); + + // Find symbol in specified table, returning NULL if it is not found. + // + // If build_map is true, builds a map to speed repeated access. The + // map does not included untyped symbol values (aka STT_NOTYPE) + // since they can contain duplicates. If build_map is false, the map + // will be used if it was already created. Typically build_map + // should be set unless only a small number of symbols will be + // looked up. ::llvm::ELF::Elf32_Sym* FindSymbolByName(::llvm::ELF::Elf32_Word section_type, - const std::string& symbol_name); + const std::string& symbol_name, + bool build_map); + + // Find address of symbol in specified table, returning 0 if it is + // not found. See FindSymbolByName for an explanation of build_map. ::llvm::ELF::Elf32_Addr FindSymbolAddress(::llvm::ELF::Elf32_Word section_type, - const std::string& symbol_name); + const std::string& symbol_name, + bool build_map); - char* GetString(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word); + // Lookup a string given string section and offset. Returns NULL for + // special 0 offset. + const char* GetString(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word); + + // Lookup a string by section type. Returns NULL for special 0 offset. + const char* GetString(::llvm::ELF::Elf32_Word section_type, ::llvm::ELF::Elf32_Word); ::llvm::ELF::Elf32_Word GetDynamicNum(); ::llvm::ELF::Elf32_Dyn& GetDynamic(::llvm::ELF::Elf32_Word); + ::llvm::ELF::Elf32_Word FindDynamicValueByType(::llvm::ELF::Elf32_Sword type); + + ::llvm::ELF::Elf32_Word GetRelNum(::llvm::ELF::Elf32_Shdr&); + ::llvm::ELF::Elf32_Rel& GetRel(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word); + + ::llvm::ELF::Elf32_Word GetRelaNum(::llvm::ELF::Elf32_Shdr&); + ::llvm::ELF::Elf32_Rela& GetRela(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word); // Returns the expected size when the file is loaded at runtime size_t GetLoadedSize(); @@ -98,19 +128,28 @@ class ElfFile { ::llvm::ELF::Elf32_Phdr& GetDynamicProgramHeader(); ::llvm::ELF::Elf32_Dyn* GetDynamicSectionStart(); ::llvm::ELF::Elf32_Sym* GetSymbolSectionStart(::llvm::ELF::Elf32_Word section_type); - char* GetSymbolStringSectionStart(::llvm::ELF::Elf32_Word section_type); + const char* GetStringSectionStart(::llvm::ELF::Elf32_Word section_type); + ::llvm::ELF::Elf32_Rel* GetRelSectionStart(::llvm::ELF::Elf32_Shdr&); + ::llvm::ELF::Elf32_Rela* GetRelaSectionStart(::llvm::ELF::Elf32_Shdr&); ::llvm::ELF::Elf32_Word* GetHashSectionStart(); ::llvm::ELF::Elf32_Word GetHashBucketNum(); ::llvm::ELF::Elf32_Word GetHashChainNum(); ::llvm::ELF::Elf32_Word GetHashBucket(size_t i); ::llvm::ELF::Elf32_Word GetHashChain(size_t i); + typedef std::map<std::string, ::llvm::ELF::Elf32_Sym*> SymbolTable; + SymbolTable** GetSymbolTable(::llvm::ELF::Elf32_Word section_type); + File* file_; bool writable_; bool program_header_only_; + + // ELF header mapping. If program_header_only_ is false, will actually point to the entire elf file. UniquePtr<MemMap> map_; ::llvm::ELF::Elf32_Ehdr* header_; std::vector<MemMap*> segments_; + + // Pointer to start of first PT_LOAD program segment after Load() when program_header_only_ is true. byte* base_address_; // The program header should always available but use GetProgramHeadersStart() to be sure. @@ -122,10 +161,12 @@ class ElfFile { ::llvm::ELF::Elf32_Dyn* dynamic_section_start_; ::llvm::ELF::Elf32_Sym* symtab_section_start_; ::llvm::ELF::Elf32_Sym* dynsym_section_start_; - char* strtab_section_start_; - char* dynstr_section_start_; + const char* strtab_section_start_; + const char* dynstr_section_start_; ::llvm::ELF::Elf32_Word* hash_section_start_; + SymbolTable* symtab_symbol_table_; + SymbolTable* dynsym_symbol_table_; }; } // namespace art diff --git a/src/elf_writer.cc b/src/elf_writer.cc index 106ad44a1e..88b35435c5 100644 --- a/src/elf_writer.cc +++ b/src/elf_writer.cc @@ -16,12 +16,6 @@ #include "elf_writer.h" -#include "base/unix_file/fd_file.h" -#include "compiler/driver/compiler_driver.h" -#include "elf_file.h" -#include "oat.h" -#include "oat_file.h" - #include <llvm/Support/TargetSelect.h> #include <mcld/Environment.h> @@ -33,30 +27,66 @@ #include <mcld/Support/Path.h> #include <mcld/Support/TargetSelect.h> +#include "base/unix_file/fd_file.h" +#include "class_linker.h" +#include "compiler/driver/compiler_driver.h" +#include "compiler/llvm/utils_llvm.h" +#include "dex_method_iterator.h" +#include "elf_file.h" +#include "invoke_type.h" +#include "mirror/abstract_method-inl.h" +#include "oat.h" +#include "oat_file.h" +#include "scoped_thread_state_change.h" + namespace art { -bool ElfWriter::Create(File* file, std::vector<uint8_t>& oat_contents, const CompilerDriver& compiler) { - ElfWriter elf_writer(&compiler); - return elf_writer.Write(oat_contents, file); +bool ElfWriter::Create(File* elf_file, + std::vector<uint8_t>& oat_contents, + const std::vector<const DexFile*>& dex_files, + const std::string* host_prefix, + bool is_host, + const CompilerDriver& driver) { + ElfWriter elf_writer(driver, elf_file); + return elf_writer.Write(oat_contents, dex_files, host_prefix, is_host); } -ElfWriter::ElfWriter(const CompilerDriver* driver) : compiler_driver_(driver) {} +ElfWriter::ElfWriter(const CompilerDriver& driver, File* elf_file) + : compiler_driver_(&driver), elf_file_(elf_file), oat_input_(NULL) {} ElfWriter::~ElfWriter() {} -static void InitializeLLVM() { - // TODO: this is lifted from art's compiler_llvm.cc, should be factored out -#if defined(ART_TARGET) - ::llvm::InitializeNativeTarget(); - // TODO: odd that there is no InitializeNativeTargetMC? -#else - ::llvm::InitializeAllTargets(); - ::llvm::InitializeAllTargetMCs(); +bool ElfWriter::Write(std::vector<uint8_t>& oat_contents, + const std::vector<const DexFile*>& dex_files, + const std::string* host_prefix, + bool is_host) { + Init(); + AddOatInput(oat_contents); +#if defined(ART_USE_PORTABLE_COMPILER) + AddMethodInputs(dex_files); + AddRuntimeInputs(host_prefix, is_host); +#endif + if (!Link()) { + return false; + } +#if defined(ART_USE_PORTABLE_COMPILER) + FixupOatMethodOffsets(dex_files); #endif + return true; } -bool ElfWriter::Write(std::vector<uint8_t>& oat_contents, File* elf_file) { +static void InitializeLLVM() { + // TODO: this is lifted from art's compiler_llvm.cc, should be factored out + if (kIsTargetBuild) { + llvm::InitializeNativeTarget(); + // TODO: odd that there is no InitializeNativeTargetMC? + } else { + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + } +} +void ElfWriter::Init() { std::string target_triple; std::string target_cpu; std::string target_attr; @@ -65,154 +95,358 @@ bool ElfWriter::Write(std::vector<uint8_t>& oat_contents, File* elf_file) { target_cpu, target_attr); - { - // Based on mclinker's llvm-mcld.cpp main() and LinkerTest - // - // TODO: LinkerTest uses mcld::Initialize(), but it does an - // llvm::InitializeAllTargets, which we don't want. Basically we - // want mcld::InitializeNative, but it doesn't exist yet, so we - // inline the minimal we need here. - InitializeLLVM(); - mcld::InitializeAllTargets(); - mcld::InitializeAllLinkers(); - mcld::InitializeAllEmulations(); - mcld::InitializeAllDiagnostics(); - - UniquePtr<mcld::LinkerConfig> linker_config(new mcld::LinkerConfig(target_triple)); - CHECK(linker_config.get() != NULL); - linker_config->setCodeGenType(mcld::LinkerConfig::DynObj); - if (compiler_driver_->GetInstructionSet() == kMips) { - // MCLinker defaults MIPS section alignment to 0x10000, not 0x1000 - mcld::ZOption z_option; - z_option.setKind(mcld::ZOption::MaxPageSize); - z_option.setPageSize(kPageSize); - linker_config->options().addZOption(z_option); + // Based on mclinker's llvm-mcld.cpp main() and LinkerTest + // + // TODO: LinkerTest uses mcld::Initialize(), but it does an + // llvm::InitializeAllTargets, which we don't want. Basically we + // want mcld::InitializeNative, but it doesn't exist yet, so we + // inline the minimal we need here. + InitializeLLVM(); + mcld::InitializeAllTargets(); + mcld::InitializeAllLinkers(); + mcld::InitializeAllEmulations(); + mcld::InitializeAllDiagnostics(); + + linker_config_.reset(new mcld::LinkerConfig(target_triple)); + CHECK(linker_config_.get() != NULL); + linker_config_->setCodeGenType(mcld::LinkerConfig::DynObj); + linker_config_->options().setSOName(elf_file_->GetPath()); + + // error on undefined symbols. + // TODO: should this just be set if kIsDebugBuild? + linker_config_->options().setNoUndefined(true); + + // TODO: Wire up mcld DiagnosticEngine to LOG? + linker_config_->options().setColor(false); + if (false) { + // enables some tracing of input file processing + linker_config_->options().setTrace(true); + } + + // Based on alone::Linker::config + module_.reset(new mcld::Module(linker_config_->options().soname())); + CHECK(module_.get() != NULL); + ir_builder_.reset(new mcld::IRBuilder(*module_.get(), *linker_config_.get())); + CHECK(ir_builder_.get() != NULL); + linker_.reset(new mcld::Linker()); + CHECK(linker_.get() != NULL); + linker_->config(*linker_config_.get()); +} + +void ElfWriter::AddOatInput(std::vector<uint8_t>& oat_contents) { + // Add an artificial memory input. Based on LinkerTest. + UniquePtr<OatFile> oat_file(OatFile::OpenMemory(oat_contents, elf_file_->GetPath())); + CHECK(oat_file.get() != NULL) << elf_file_->GetPath(); + + const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader()); + const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset(); + const char* oat_code_start = oat_data_start + oat_data_length; + const size_t oat_code_length = oat_file->Size() - oat_data_length; + + // TODO: ownership of oat_input? + oat_input_ = ir_builder_->CreateInput("oat contents", + mcld::sys::fs::Path("oat contents path"), + mcld::Input::Object); + CHECK(oat_input_ != NULL); + + // TODO: ownership of null_section? + mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_, + "", + mcld::LDFileFormat::Null, + llvm::ELF::SHT_NULL, + 0); + CHECK(null_section != NULL); + + // TODO: we should split readonly data from readonly executable + // code like .oat does. We need to control section layout with + // linker script like functionality to guarantee references + // between sections maintain relative position which isn't + // possible right now with the mclinker APIs. + CHECK(oat_code_start != NULL); + + // we need to ensure that oatdata is page aligned so when we + // fixup the segment load addresses, they remain page aligned. + uint32_t alignment = kPageSize; + + // TODO: ownership of text_section? + mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_, + ".text", + llvm::ELF::SHT_PROGBITS, + llvm::ELF::SHF_EXECINSTR + | llvm::ELF::SHF_ALLOC, + alignment); + CHECK(text_section != NULL); + + mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section); + CHECK(text_sectiondata != NULL); + + // TODO: why does IRBuilder::CreateRegion take a non-const pointer? + mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start), + oat_file->Size()); + CHECK(text_fragment != NULL); + ir_builder_->AppendFragment(*text_fragment, *text_sectiondata); + + ir_builder_->AddSymbol(*oat_input_, + "oatdata", + mcld::ResolveInfo::Object, + mcld::ResolveInfo::Define, + mcld::ResolveInfo::Global, + oat_data_length, // size + 0, // offset + text_section); + + ir_builder_->AddSymbol(*oat_input_, + "oatexec", + mcld::ResolveInfo::Function, + mcld::ResolveInfo::Define, + mcld::ResolveInfo::Global, + oat_code_length, // size + oat_data_length, // offset + text_section); + + ir_builder_->AddSymbol(*oat_input_, + "oatlastword", + mcld::ResolveInfo::Object, + mcld::ResolveInfo::Define, + mcld::ResolveInfo::Global, + 0, // size + // subtract a word so symbol is within section + (oat_data_length + oat_code_length) - sizeof(uint32_t), // offset + text_section); +} + +#if defined(ART_USE_PORTABLE_COMPILER) +void ElfWriter::AddMethodInputs(const std::vector<const DexFile*>& dex_files) { + DCHECK(oat_input_ != NULL); + + DexMethodIterator it(dex_files); + while (it.HasNext()) { + const DexFile& dex_file = it.GetDexFile(); + uint32_t method_idx = it.GetMemberIndex(); + InvokeType invoke_type = it.GetInvokeType(); + const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); + const CompiledMethod* compiled_method = + compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx)); + if (compiled_method != NULL) { + AddCompiledCodeInput(*compiled_method); } - linker_config->options().setSOName(elf_file->GetPath()); - // TODO: Wire up mcld DiagnosticEngine to LOG? - if (false) { - // enables some tracing of input file processing - linker_config->options().setTrace(true); + const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic, + shorty); + if (compiled_invoke_stub != NULL) { + AddCompiledCodeInput(*compiled_invoke_stub); } - // Based on alone::Linker::config - UniquePtr<mcld::Module> module(new mcld::Module(linker_config->options().soname())); - CHECK(module.get() != NULL); - UniquePtr<mcld::IRBuilder> ir_builder(new mcld::IRBuilder(*module.get(), *linker_config.get())); - CHECK(ir_builder.get() != NULL); - UniquePtr<mcld::Linker> linker(new mcld::Linker()); - CHECK(linker.get() != NULL); - linker->config(*linker_config.get()); - - - // Add an artificial memory input. Based on LinkerTest. - UniquePtr<OatFile> oat_file(OatFile::Open(oat_contents, elf_file->GetPath())); - CHECK(oat_file.get() != NULL) << elf_file->GetPath(); - - const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader()); - const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset(); - const char* oat_code_start = oat_data_start + oat_data_length; - const size_t oat_code_length = oat_file->Size() - oat_data_length; - - // TODO: ownership of input? - mcld::Input* input = ir_builder->CreateInput("oat contents", - mcld::sys::fs::Path("oat contents path"), - mcld::Input::Object); - CHECK(input != NULL); - - // TODO: ownership of null_section? - mcld::LDSection* null_section = ir_builder->CreateELFHeader(*input, - "", - mcld::LDFileFormat::Null, - ::llvm::ELF::SHT_NULL, - 0); - CHECK(null_section != NULL); - - // TODO: we should split readonly data from readonly executable - // code like .oat does. We need to control section layout with - // linker script like functionality to guarantee references - // between sections maintain relative position which isn't - // possible right now with the mclinker APIs. - CHECK(oat_code_start); - - // we need to ensure that oatdata is page aligned so when we - // fixup the segment load addresses, they remain page aligned. - uint32_t alignment = kPageSize; - - // TODO: ownership of text_section? - mcld::LDSection* text_section = ir_builder->CreateELFHeader(*input, - ".text", - ::llvm::ELF::SHT_PROGBITS, - ::llvm::ELF::SHF_EXECINSTR - | ::llvm::ELF::SHF_ALLOC, - alignment); - CHECK(text_section != NULL); - - mcld::SectionData* text_section_data = ir_builder->CreateSectionData(*text_section); - CHECK(text_section_data != NULL); - - // TODO: why does IRBuilder::CreateRegion take a non-const pointer? - mcld::Fragment* text_fragment = ir_builder->CreateRegion(const_cast<char*>(oat_data_start), - oat_file->Size()); - CHECK(text_fragment != NULL); - ir_builder->AppendFragment(*text_fragment, *text_section_data); - - ir_builder->AddSymbol(*input, - "oatdata", - mcld::ResolveInfo::Object, - mcld::ResolveInfo::Define, - mcld::ResolveInfo::Global, - oat_data_length, // size - 0, // offset - text_section); - - ir_builder->AddSymbol(*input, - "oatexec", - mcld::ResolveInfo::Function, - mcld::ResolveInfo::Define, - mcld::ResolveInfo::Global, - oat_code_length, // size - oat_data_length, // offset - text_section); - - ir_builder->AddSymbol(*input, - "oatlastword", - mcld::ResolveInfo::Object, - mcld::ResolveInfo::Define, - mcld::ResolveInfo::Global, - 0, // size - // subtract a word so symbol is within section - (oat_data_length + oat_code_length) - sizeof(uint32_t), // offset - text_section); - - // link inputs - if (!linker->link(*module.get(), *ir_builder.get())) { - LOG(ERROR) << "problem linking " << elf_file->GetPath(); - return false; + if (invoke_type != kStatic) { + const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty); + if (compiled_proxy_stub != NULL) { + AddCompiledCodeInput(*compiled_proxy_stub); + } } + it.Next(); + } + added_symbols_.clear(); +} - // emited linked output - if (!linker->emit(elf_file->Fd())) { - LOG(ERROR) << "problem emitting " << elf_file->GetPath(); - return false; +void ElfWriter::AddCompiledCodeInput(const CompiledCode& compiled_code) { + // Check if we've seen this compiled code before. If so skip + // it. This can happen for reused code such as invoke stubs. + const std::string& symbol = compiled_code.GetSymbol(); + SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol); + if (it != added_symbols_.end()) { + return; + } + added_symbols_.Put(&symbol, &symbol); + + // Add input to supply code for symbol + const std::vector<uint8_t>& code = compiled_code.GetCode(); + // TODO: ownership of code_input? + // TODO: why does IRBuilder::ReadInput take a non-const pointer? + mcld::Input* code_input = ir_builder_->ReadInput(symbol, + const_cast<uint8_t*>(&code[0]), + code.size()); + CHECK(code_input != NULL); +} + +void ElfWriter::AddRuntimeInputs(const std::string* host_prefix, bool is_host) { + std::string android_root; + if (is_host) { + const char* android_host_out = getenv("ANDROID_HOST_OUT"); + CHECK(android_host_out != NULL) << "ANDROID_HOST_OUT environment variable not set"; + android_root += android_host_out; + } else { + if (host_prefix != NULL) { + android_root += *host_prefix; + android_root += "/system"; + } else { + android_root += GetAndroidRoot(); } - // TODO: mcld::Linker::emit closed the file descriptor. It probably shouldn't. - // For now, close our File to match. - elf_file->Close(); - mcld::Finalize(); } - LOG(INFO) << "ELF file written successfully: " << elf_file->GetPath(); + + std::string libart_so(android_root); + libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so"; + // TODO: ownership of libart_so_input? + mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so); + CHECK(libart_so_input != NULL); + + std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6"); + + std::string compiler_runtime_lib; + if (is_host) { + compiler_runtime_lib += host_prebuilt_dir; + compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a"; + } else { + compiler_runtime_lib += android_root; + compiler_runtime_lib += "/lib/libcompiler-rt.a"; + } + // TODO: ownership of compiler_runtime_lib_input? + mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib, + compiler_runtime_lib); + CHECK(compiler_runtime_lib_input != NULL); + + std::string libc_lib; + if (is_host) { + libc_lib += host_prebuilt_dir; + libc_lib += "/sysroot/usr/lib/libc.so.6"; + } else { + libc_lib += android_root; + libc_lib += "/lib/libc.so"; + } + // TODO: ownership of libc_lib_input? + mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib); + CHECK(libc_lib_input_input != NULL); + + std::string libm_lib; + if (is_host) { + libm_lib += host_prebuilt_dir; + libm_lib += "/sysroot/usr/lib/libm.so"; + } else { + libm_lib += android_root; + libm_lib += "/lib/libm.so"; + } + // TODO: ownership of libm_lib_input? + mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib); + CHECK(libm_lib_input_input != NULL); + +} +#endif + +bool ElfWriter::Link() { + // link inputs + if (!linker_->link(*module_.get(), *ir_builder_.get())) { + LOG(ERROR) << "Failed to link " << elf_file_->GetPath(); + return false; + } + + // emit linked output + // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd. + int fd = dup(elf_file_->Fd()); + if (fd == -1) { + PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath(); + return false; + } + if (!linker_->emit(fd)) { + LOG(ERROR) << "Failed to emit " << elf_file_->GetPath(); + return false; + } + mcld::Finalize(); + LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath(); return true; } +static llvm::ELF::Elf32_Addr GetOatDataAddress(ElfFile* elf_file) { + llvm::ELF::Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(llvm::ELF::SHT_DYNSYM, + "oatdata", + false); + CHECK_NE(0U, oatdata_address); + return oatdata_address; +} + +#if defined(ART_USE_PORTABLE_COMPILER) +void ElfWriter::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) { + UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false)); + CHECK(elf_file.get() != NULL) << elf_file_->GetPath(); + + llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get()); + DexMethodIterator it(dex_files); + while (it.HasNext()) { + const DexFile& dex_file = it.GetDexFile(); + uint32_t method_idx = it.GetMemberIndex(); + InvokeType invoke_type = it.GetInvokeType(); + const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); + mirror::AbstractMethod* method = NULL; + if (compiler_driver_->IsImage()) { + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + mirror::DexCache* dex_cache = linker->FindDexCache(dex_file); + // Unchecked as we hold mutator_lock_ on entry. + ScopedObjectAccessUnchecked soa(Thread::Current()); + method = linker->ResolveMethod(dex_file, method_idx, dex_cache, NULL, NULL, invoke_type); + CHECK(method != NULL); + } + const CompiledMethod* compiled_method = + compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx)); + if (compiled_method != NULL) { + uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method); + // Don't overwrite static method trampoline + if (method != NULL && + (!method->IsStatic() || + method->IsConstructor() || + method->GetDeclaringClass()->IsInitialized())) { + method->SetOatCodeOffset(offset); + } + } + const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic, + shorty); + if (compiled_invoke_stub != NULL) { + uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_invoke_stub); + if (method != NULL) { + method->SetOatInvokeStubOffset(offset); + } + } + + if (invoke_type != kStatic) { + const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty); + if (compiled_proxy_stub != NULL) { + FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_proxy_stub); + } + } + it.Next(); + } + symbol_to_compiled_code_offset_.clear(); +} + +uint32_t ElfWriter::FixupCompiledCodeOffset(ElfFile& elf_file, + llvm::ELF::Elf32_Addr oatdata_address, + const CompiledCode& compiled_code) { + const std::string& symbol = compiled_code.GetSymbol(); + SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol); + if (it != symbol_to_compiled_code_offset_.end()) { + return it->second; + } + + llvm::ELF::Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(llvm::ELF::SHT_SYMTAB, + symbol, + true); + CHECK_NE(0U, compiled_code_address) << symbol; + CHECK_LT(oatdata_address, compiled_code_address) << symbol; + uint32_t compiled_code_offset = compiled_code_address - oatdata_address; + symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset); + + const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset(); + for (uint32_t i = 0; i < offsets.size(); i++) { + uint32_t oatdata_offset = oatdata_address + offsets[i]; + uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset); + *addr = compiled_code_offset; + } + return compiled_code_offset; +} +#endif + bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) { UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false)); CHECK(elf_file.get() != NULL); // Lookup "oatdata" symbol address. - ::llvm::ELF::Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, - "oatdata"); - CHECK_NE(0U, oatdata_address); + ::llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get()); ::llvm::ELF::Elf32_Off base_address = oat_data_begin - oatdata_address; if (!FixupDynamic(*elf_file.get(), base_address)) { @@ -235,6 +469,10 @@ bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) { LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath(); return false; } + if (!FixupRelocations(*elf_file.get(), base_address)) { + LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath(); + return false; + } return true; } @@ -314,6 +552,123 @@ bool ElfWriter::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dyn return true; } +bool ElfWriter::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) { + for (llvm::ELF::Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) { + llvm::ELF::Elf32_Shdr& sh = elf_file.GetSectionHeader(i); + if (sh.sh_type == llvm::ELF::SHT_REL) { + for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) { + llvm::ELF::Elf32_Rel& rel = elf_file.GetRel(sh, i); + rel.r_offset += base_address; + } + } else if (sh.sh_type == llvm::ELF::SHT_RELA) { + for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) { + llvm::ELF::Elf32_Rela& rela = elf_file.GetRela(sh, i); + rela.r_offset += base_address; + } + } + } + return true; +} + +bool ElfWriter::Strip(File* file) { + UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false)); + CHECK(elf_file.get() != NULL); + + // ELF files produced by MCLinker look roughly like this + // + // +------------+ + // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first + // +------------+ + // | Elf32_Phdr | program headers + // | Elf32_Phdr | + // | ... | + // | Elf32_Phdr | + // +------------+ + // | section | mixture of needed and unneeded sections + // +------------+ + // | section | + // +------------+ + // | ... | + // +------------+ + // | section | + // +------------+ + // | Elf32_Shdr | section headers + // | Elf32_Shdr | + // | ... | contains offset to section start + // | Elf32_Shdr | + // +------------+ + // + // To strip: + // - leave the Elf32_Ehdr and Elf32_Phdr values in place. + // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep + // - move the sections are keeping up to fill in gaps of sections we want to strip + // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr + // - truncate rest of file + // + + std::vector<llvm::ELF::Elf32_Shdr> section_headers; + std::vector<llvm::ELF::Elf32_Word> section_headers_original_indexes; + section_headers.reserve(elf_file->GetSectionHeaderNum()); + + + llvm::ELF::Elf32_Shdr& string_section = elf_file->GetSectionNameStringSection(); + for (llvm::ELF::Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) { + llvm::ELF::Elf32_Shdr& sh = elf_file->GetSectionHeader(i); + const char* name = elf_file->GetString(string_section, sh.sh_name); + if (name == NULL) { + CHECK_EQ(0U, i); + section_headers.push_back(sh); + section_headers_original_indexes.push_back(0); + continue; + } + if (StartsWith(name, ".debug") + || (strcmp(name, ".strtab") == 0) + || (strcmp(name, ".symtab") == 0)) { + continue; + } + section_headers.push_back(sh); + section_headers_original_indexes.push_back(i); + } + CHECK_NE(0U, section_headers.size()); + CHECK_EQ(section_headers.size(), section_headers_original_indexes.size()); + + // section 0 is the NULL section, sections start at offset of first section + llvm::ELF::Elf32_Off offset = elf_file->GetSectionHeader(1).sh_offset; + for (size_t i = 1; i < section_headers.size(); i++) { + llvm::ELF::Elf32_Shdr& new_sh = section_headers[i]; + llvm::ELF::Elf32_Shdr& old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]); + CHECK_EQ(new_sh.sh_name, old_sh.sh_name); + if (old_sh.sh_addralign > 1) { + offset = RoundUp(offset, old_sh.sh_addralign); + } + if (old_sh.sh_offset == offset) { + // already in place + offset += old_sh.sh_size; + continue; + } + // shift section earlier + memmove(elf_file->Begin() + offset, + elf_file->Begin() + old_sh.sh_offset, + old_sh.sh_size); + new_sh.sh_offset = offset; + offset += old_sh.sh_size; + } + + llvm::ELF::Elf32_Off shoff = offset; + size_t section_headers_size_in_bytes = section_headers.size() * sizeof(llvm::ELF::Elf32_Shdr); + memcpy(elf_file->Begin() + offset, §ion_headers[0], section_headers_size_in_bytes); + offset += section_headers_size_in_bytes; + + elf_file->GetHeader().e_shnum = section_headers.size(); + elf_file->GetHeader().e_shoff = shoff; + int result = ftruncate(file->Fd(), offset); + if (result != 0) { + PLOG(ERROR) << "Failed to truncate while stripping ELF file: " << file->GetPath(); + return false; + } + return true; +} + void ElfWriter::GetOatElfInformation(File* file, size_t& oat_loaded_size, size_t& oat_data_offset) { @@ -322,7 +677,7 @@ void ElfWriter::GetOatElfInformation(File* file, oat_loaded_size = elf_file->GetLoadedSize(); CHECK_NE(0U, oat_loaded_size); - oat_data_offset = elf_file->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, "oatdata"); + oat_data_offset = GetOatDataAddress(elf_file.get()); CHECK_NE(0U, oat_data_offset); } diff --git a/src/elf_writer.h b/src/elf_writer.h index f55003f36e..6f22db146e 100644 --- a/src/elf_writer.h +++ b/src/elf_writer.h @@ -17,23 +17,52 @@ #ifndef ART_SRC_ELF_WRITER_H_ #define ART_SRC_ELF_WRITER_H_ -#include "elf_file.h" -#include "os.h" +#include <stdint.h> +#include <cstddef> #include <vector> +#include <llvm/Support/ELF.h> + +#include "UniquePtr.h" +#include "dex_file.h" +#include "os.h" + +namespace mcld { +class IRBuilder; +class Input; +class LDSection; +class LDSymbol; +class Linker; +class LinkerConfig; +class Module; +} // namespace mcld + namespace art { + +class CompiledCode; class CompilerDriver; +class ElfFile; class ElfWriter { public: // Write an ELF file. Returns true on success, false on failure. - static bool Create(File* file, std::vector<uint8_t>& oat_contents, const CompilerDriver& compiler); + static bool Create(File* file, + std::vector<uint8_t>& oat_contents, + const std::vector<const DexFile*>& dex_files, + const std::string* host_prefix, + bool is_host, + const CompilerDriver& driver) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Fixup an ELF file so that that oat header will be loaded at oat_begin. // Returns true on success, false on failure. static bool Fixup(File* file, uintptr_t oat_data_begin); + // Strip an ELF file of unneeded debugging information. + // Returns true on success, false on failure. + static bool Strip(File* file); + // Looks up information about location of oat file in elf file container. // Used for ImageWriter to perform memory layout. static void GetOatElfInformation(File* file, @@ -41,10 +70,28 @@ class ElfWriter { size_t& oat_data_offset); private: - ElfWriter(const CompilerDriver* driver); + ElfWriter(const CompilerDriver& driver, File* elf_file); ~ElfWriter(); - bool Write(std::vector<uint8_t>& oat_contents, File* elf_file); + bool Write(std::vector<uint8_t>& oat_contents, + const std::vector<const DexFile*>& dex_files, + const std::string* host_prefix, + bool is_host) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void Init(); + void AddOatInput(std::vector<uint8_t>& oat_contents); + void AddMethodInputs(const std::vector<const DexFile*>& dex_files); + void AddCompiledCodeInput(const CompiledCode& compiled_code); + void AddRuntimeInputs(const std::string* host_prefix, 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, + const CompiledCode& compiled_code); +#endif // Fixup .dynamic d_ptr values for the expected base_address. static bool FixupDynamic(ElfFile& elf_file, uintptr_t base_address); @@ -58,7 +105,31 @@ class ElfWriter { // Fixup symbol table static bool FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic); - const CompilerDriver* const compiler_driver_; + // Fixup dynamic relocations + static bool FixupRelocations(ElfFile& elf_file, uintptr_t base_address); + + // Setup by constructor + const CompilerDriver* compiler_driver_; + File* elf_file_; + + // Setup by Init() + UniquePtr<mcld::LinkerConfig> linker_config_; + UniquePtr<mcld::Module> module_; + UniquePtr<mcld::IRBuilder> ir_builder_; + UniquePtr<mcld::Linker> linker_; + + // Setup by AddOatInput() + // TODO: ownership of oat_input_? + mcld::Input* oat_input_; + + // Setup by AddCompiledCodeInput + // set of symbols for already added mcld::Inputs + SafeMap<const std::string*, const std::string*> added_symbols_; + + // Setup by FixupCompiledCodeOffset + // map of symbol names to oatdata offset + SafeMap<const std::string*, uint32_t> symbol_to_compiled_code_offset_; + }; } // namespace art diff --git a/src/elf_writer_test.cc b/src/elf_writer_test.cc index 0be624df9c..a47bc7175a 100644 --- a/src/elf_writer_test.cc +++ b/src/elf_writer_test.cc @@ -30,9 +30,9 @@ class ElfWriterTest : public CommonTest { } }; -#define EXPECT_ELF_FILE_ADDRESS(ef, value, name) \ - EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_SYMTAB, name))); \ - EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, name))); \ +#define EXPECT_ELF_FILE_ADDRESS(ef, value, name, build_map) \ + EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_SYMTAB, name, build_map))); \ + EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, name, build_map))); \ EXPECT_EQ(value, ef->FindDynamicSymbolAddress(name)); \ /* @@ -79,9 +79,16 @@ TEST_F(ElfWriterTest, DISABLED_dlsym) { { UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false)); CHECK(ef.get() != NULL); - EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata"); - EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec"); - EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword"); + EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false); + EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false); + EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", false); + } + { + UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false)); + CHECK(ef.get() != NULL); + EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true); + EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true); + EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", true); } { UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true)); diff --git a/src/heap.cc b/src/heap.cc index c8df031ec7..64df6b8807 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -104,6 +104,10 @@ static bool GenerateImage(const std::string& image_file_name) { std::string base_option_string(StringPrintf("--base=0x%x", ART_BASE_ADDRESS)); arg_vector.push_back(strdup(base_option_string.c_str())); + if (!kIsTargetBuild) { + arg_vector.push_back(strdup("--host")); + } + std::string command_line(Join(arg_vector, ' ')); LOG(INFO) << command_line; diff --git a/src/image_test.cc b/src/image_test.cc index 6d22cada4c..dc16a6c2e7 100644 --- a/src/image_test.cc +++ b/src/image_test.cc @@ -57,9 +57,13 @@ TEST_F(ImageTest, WriteRead) { mirror::Class* klass = class_linker_->FindSystemClass(descriptor); EXPECT_TRUE(klass != NULL) << descriptor; } + bool success_elf = compiler_driver_->WriteElf(NULL, + !kIsTargetBuild, + dex_files, + oat_contents, + tmp_elf.GetFile()); + ASSERT_TRUE(success_elf); } - bool success_elf = compiler_driver_->WriteElf(oat_contents, tmp_elf.GetFile()); - ASSERT_TRUE(success_elf); } // Workound bug that mcld::Linker::emit closes tmp_elf by reopening as tmp_oat. UniquePtr<File> tmp_oat(OS::OpenFile(tmp_elf.GetFilename().c_str(), true, false)); diff --git a/src/image_writer.cc b/src/image_writer.cc index d9ac61b112..ad2c9b727d 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc @@ -78,7 +78,7 @@ bool ImageWriter::Write(const std::string& image_filename, LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location; return false; } - oat_file_ = OatFile::Open(oat_file.get(), oat_location, NULL, true); + oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location); class_linker->RegisterOatFile(*oat_file_); { diff --git a/src/image_writer.h b/src/image_writer.h index ee02ec43f0..46d134f41a 100644 --- a/src/image_writer.h +++ b/src/image_writer.h @@ -98,7 +98,12 @@ class ImageWriter { } const byte* GetOatAddress(uint32_t offset) const { +#if !defined(ART_USE_PORTABLE_COMPILER) + // With Quick, code is within the OatFile, as there are all in one + // .o ELF object. However with Portable, the code is always in + // different .o ELF objects. DCHECK_LT(offset, oat_file_->Size()); +#endif if (offset == 0) { return NULL; } diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc index 801e7c9d80..deff290c33 100644 --- a/src/jni_internal_test.cc +++ b/src/jni_internal_test.cc @@ -1406,6 +1406,7 @@ TEST_F(JniInternalTest, DeleteWeakGlobalRef) { } TEST_F(JniInternalTest, StaticMainMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); jobject jclass_loader = LoadDex("Main"); SirtRef<mirror::ClassLoader> @@ -1427,121 +1428,145 @@ TEST_F(JniInternalTest, StaticMainMethod) { } TEST_F(JniInternalTest, StaticNopMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeNopMethod(true); } TEST_F(JniInternalTest, NonStaticNopMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeNopMethod(false); } TEST_F(JniInternalTest, StaticIdentityByteMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeIdentityByteMethod(true); } TEST_F(JniInternalTest, NonStaticIdentityByteMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeIdentityByteMethod(false); } TEST_F(JniInternalTest, StaticIdentityIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeIdentityIntMethod(true); } TEST_F(JniInternalTest, NonStaticIdentityIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeIdentityIntMethod(false); } TEST_F(JniInternalTest, StaticIdentityDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeIdentityDoubleMethod(true); } TEST_F(JniInternalTest, NonStaticIdentityDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeIdentityDoubleMethod(false); } TEST_F(JniInternalTest, StaticSumIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntMethod(true); } TEST_F(JniInternalTest, NonStaticSumIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntMethod(false); } TEST_F(JniInternalTest, StaticSumIntIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntIntMethod(true); } TEST_F(JniInternalTest, NonStaticSumIntIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntIntMethod(false); } TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntIntIntMethod(true); } TEST_F(JniInternalTest, NonStaticSumIntIntIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntIntIntMethod(false); } TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntIntIntIntMethod(true); } TEST_F(JniInternalTest, NonStaticSumIntIntIntIntIntMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumIntIntIntIntIntMethod(false); } TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleMethod(true); } TEST_F(JniInternalTest, NonStaticSumDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleMethod(false); } TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleDoubleMethod(true); } TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleDoubleMethod(false); } TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleDoubleDoubleMethod(true); } TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleDoubleDoubleMethod(false); } TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(true); } TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleDoubleMethod) { + TEST_DISABLED_FOR_PORTABLE(); ScopedObjectAccess soa(Thread::Current()); InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(false); } diff --git a/src/oat_file.cc b/src/oat_file.cc index 5fd95be0dc..62fc740043 100644 --- a/src/oat_file.cc +++ b/src/oat_file.cc @@ -44,8 +44,8 @@ void OatFile::CheckLocation(const std::string& location) { } } -OatFile* OatFile::Open(std::vector<uint8_t>& oat_contents, - const std::string& location) { +OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents, + const std::string& location) { CHECK(!oat_contents.empty()) << location; CheckLocation(location); UniquePtr<OatFile> oat_file(new OatFile(location)); @@ -69,11 +69,17 @@ OatFile* OatFile::Open(const std::string& filename, * Fix MIPS to use standard kPageSize=0x1000 section alignment for ELF sections * * Change-Id: I905f0c5f75921a65bd7426a54d6258c780d85d0e + */ OatFile* result = OpenDlopen(filename, location, requested_base); if (result != NULL) { return result; } - */ + // On target, only used dlopen to load. + if (kIsTargetBuild) { + return NULL; + } + // On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile. + // This won't work for portable runtime execution because it doesn't process relocations. UniquePtr<File> file(OS::OpenFile(filename.c_str(), false, false)); if (file.get() == NULL) { return NULL; @@ -81,12 +87,9 @@ OatFile* OatFile::Open(const std::string& filename, return OpenElfFile(file.get(), location, requested_base, false); } -OatFile* OatFile::Open(File* file, - const std::string& location, - byte* requested_base, - bool writable) { +OatFile* OatFile::OpenWritable(File* file, const std::string& location) { CheckLocation(location); - return OpenElfFile(file, location, requested_base, writable); + return OpenElfFile(file, location, NULL, true); } OatFile* OatFile::OpenDlopen(const std::string& elf_filename, @@ -396,6 +399,13 @@ const void* OatFile::OatMethod::GetCode() const { } uint32_t OatFile::OatMethod::GetCodeSize() const { +#if defined(ART_USE_PORTABLE_COMPILER) + // TODO: With Quick, we store the size before the code. With + // Portable, the code is in a .o file we don't manage ourselves. ELF + // symbols do have a concept of size, so we could capture that and + // store it somewhere, such as the OatMethod. + return 0; +#else uintptr_t code = reinterpret_cast<uint32_t>(GetCode()); if (code == 0) { @@ -404,6 +414,7 @@ uint32_t OatFile::OatMethod::GetCodeSize() const { // TODO: make this Thumb2 specific code &= ~0x1; return reinterpret_cast<uint32_t*>(code)[-1]; +#endif } mirror::AbstractMethod::InvokeStub* OatFile::OatMethod::GetInvokeStub() const { @@ -412,6 +423,9 @@ mirror::AbstractMethod::InvokeStub* OatFile::OatMethod::GetInvokeStub() const { } uint32_t OatFile::OatMethod::GetInvokeStubSize() const { +#if defined(ART_USE_PORTABLE_COMPILER) + return 0; +#else uintptr_t code = reinterpret_cast<uint32_t>(GetInvokeStub()); if (code == 0) { return 0; @@ -419,6 +433,7 @@ uint32_t OatFile::OatMethod::GetInvokeStubSize() const { // TODO: make this Thumb2 specific code &= ~0x1; return reinterpret_cast<uint32_t*>(code)[-1]; +#endif } #if defined(ART_USE_PORTABLE_COMPILER) @@ -427,7 +442,7 @@ const void* OatFile::OatMethod::GetProxyStub() const { } #endif -void OatFile::OatMethod::LinkMethodPointers(mirror::AbstractMethod* method) const { +void OatFile::OatMethod::LinkMethod(mirror::AbstractMethod* method) const { CHECK(method != NULL); method->SetCode(GetCode()); method->SetFrameSizeInBytes(frame_size_in_bytes_); @@ -439,16 +454,4 @@ void OatFile::OatMethod::LinkMethodPointers(mirror::AbstractMethod* method) cons method->SetInvokeStub(GetInvokeStub()); } -void OatFile::OatMethod::LinkMethodOffsets(mirror::AbstractMethod* method) const { - CHECK(method != NULL); - method->SetOatCodeOffset(GetCodeOffset()); - method->SetFrameSizeInBytes(GetFrameSizeInBytes()); - method->SetCoreSpillMask(GetCoreSpillMask()); - method->SetFpSpillMask(GetFpSpillMask()); - method->SetOatMappingTableOffset(GetMappingTableOffset()); - method->SetOatVmapTableOffset(GetVmapTableOffset()); - method->SetOatNativeGcMapOffset(GetNativeGcMapOffset()); - method->SetOatInvokeStubOffset(GetInvokeStubOffset()); -} - } // namespace art diff --git a/src/oat_file.h b/src/oat_file.h index 8efdf9f51f..4aa18bab42 100644 --- a/src/oat_file.h +++ b/src/oat_file.h @@ -46,14 +46,15 @@ class OatFile { byte* requested_base); // Open an oat file from an already opened File. - static OatFile* Open(File* file, - const std::string& location, - byte* requested_base, - bool writable); + // Does not use dlopen underneath so cannot be used for runtime use + // where relocations may be required. Currently used from + // ImageWriter which wants to open a writable version from an existing + // file descriptor for patching. + static OatFile* OpenWritable(File* file, const std::string& location); // Open an oat file backed by a std::vector with the given location. - static OatFile* Open(std::vector<uint8_t>& oat_contents, - const std::string& location); + static OatFile* OpenMemory(std::vector<uint8_t>& oat_contents, + const std::string& location); ~OatFile(); @@ -67,11 +68,7 @@ class OatFile { class OatMethod { public: - // Link Method for execution using the contents of this OatMethod - void LinkMethodPointers(mirror::AbstractMethod* method) const; - - // Link Method for image writing using the contents of this OatMethod - void LinkMethodOffsets(mirror::AbstractMethod* method) const; + void LinkMethod(mirror::AbstractMethod* method) const; uint32_t GetCodeOffset() const { return code_offset_; diff --git a/src/oat_test.cc b/src/oat_test.cc index 69ce48bab9..ace52f4a26 100644 --- a/src/oat_test.cc +++ b/src/oat_test.cc @@ -90,7 +90,11 @@ TEST_F(OatTest, WriteRead) { "lue.art", *compiler_driver_.get()); ASSERT_TRUE(success_oat); - bool success_elf = compiler_driver_->WriteElf(oat_contents, tmp.GetFile()); + bool success_elf = compiler_driver_->WriteElf(NULL, + !kIsTargetBuild, + class_linker->GetBootClassPath(), + oat_contents, + tmp.GetFile()); ASSERT_TRUE(success_elf); if (compile) { // OatWriter strips the code, regenerate to compare diff --git a/src/oat_writer.cc b/src/oat_writer.cc index 1a269e98a6..e299a2757b 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc @@ -93,7 +93,7 @@ size_t OatWriter::InitOatDexFiles(size_t offset) { for (size_t i = 0; i != dex_files_->size(); ++i) { const DexFile* dex_file = (*dex_files_)[i]; CHECK(dex_file != NULL); - OatDexFile* oat_dex_file = new OatDexFile(*dex_file); + OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file); oat_dex_files_.push_back(oat_dex_file); offset += oat_dex_file->SizeOf(); } @@ -145,7 +145,7 @@ size_t OatWriter::InitOatClasses(size_t offset) { status = mirror::Class::kStatusNotReady; } - OatClass* oat_class = new OatClass(status, num_methods); + OatClass* oat_class = new OatClass(offset, status, num_methods); oat_classes_.push_back(oat_class); offset += oat_class->SizeOf(); } @@ -232,7 +232,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t __attribute__((unused)) class_def_index, size_t class_def_method_index, bool __attribute__((unused)) is_native, - InvokeType type, + InvokeType invoke_type, uint32_t method_idx, const DexFile* dex_file) { // derived from CompiledMethod if available uint32_t code_offset = 0; @@ -248,12 +248,22 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, uint32_t proxy_stub_offset = 0; #endif + OatClass* oat_class = oat_classes_[oat_class_index]; +#if defined(ART_USE_PORTABLE_COMPILER) + size_t oat_method_offsets_offset = + oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); +#endif + CompiledMethod* compiled_method = compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(dex_file, method_idx)); if (compiled_method != NULL) { +#if defined(ART_USE_PORTABLE_COMPILER) + compiled_method->AddOatdataOffsetToCompliledCodeOffset( + oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_)); +#else + const std::vector<uint8_t>& code = compiled_method->GetCode(); offset = compiled_method->AlignCode(offset); DCHECK_ALIGNED(offset, kArmAlignment); - const std::vector<uint8_t>& code = compiled_method->GetCode(); uint32_t code_size = code.size() * sizeof(code[0]); CHECK_NE(code_size, 0U); uint32_t thumb_offset = compiled_method->CodeDelta(); @@ -269,6 +279,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, offset += code_size; oat_header_->UpdateChecksum(&code[0], code_size); } +#endif frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); core_spill_mask = compiled_method->GetCoreSpillMask(); fp_spill_mask = compiled_method->GetFpSpillMask(); @@ -335,12 +346,16 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, } const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx)); - const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(type == kStatic, - shorty); + CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic, + shorty); if (compiled_invoke_stub != NULL) { +#if defined(ART_USE_PORTABLE_COMPILER) + compiled_invoke_stub->AddOatdataOffsetToCompliledCodeOffset( + oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, invoke_stub_offset_)); +#else + const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); offset = CompiledMethod::AlignCode(offset, compiler_driver_->GetInstructionSet()); DCHECK_ALIGNED(offset, kArmAlignment); - const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]); CHECK_NE(invoke_stub_size, 0U); uint32_t thumb_offset = compiled_invoke_stub->CodeDelta(); @@ -356,35 +371,20 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, offset += invoke_stub_size; oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size); } +#endif } #if defined(ART_USE_PORTABLE_COMPILER) - if (type != kStatic) { - const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty); + if (invoke_type != kStatic) { + CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty); if (compiled_proxy_stub != NULL) { - offset = CompiledMethod::AlignCode(offset, compiler_driver_->GetInstructionSet()); - DCHECK_ALIGNED(offset, kArmAlignment); - const std::vector<uint8_t>& proxy_stub = compiled_proxy_stub->GetCode(); - uint32_t proxy_stub_size = proxy_stub.size() * sizeof(proxy_stub[0]); - CHECK_NE(proxy_stub_size, 0U); - uint32_t thumb_offset = compiled_proxy_stub->CodeDelta(); - proxy_stub_offset = offset + sizeof(proxy_stub_size) + thumb_offset; - - // Deduplicate proxy stubs - SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&proxy_stub); - if (stub_iter != code_offsets_.end()) { - proxy_stub_offset = stub_iter->second; - } else { - code_offsets_.Put(&proxy_stub, proxy_stub_offset); - offset += sizeof(proxy_stub_size); // proxy stub size is prepended before code - offset += proxy_stub_size; - oat_header_->UpdateChecksum(&proxy_stub[0], proxy_stub_size); - } + compiled_proxy_stub->AddOatdataOffsetToCompliledCodeOffset( + oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, proxy_stub_offset_)); } } #endif - oat_classes_[oat_class_index]->method_offsets_[class_def_method_index] + oat_class->method_offsets_[class_def_method_index] = OatMethodOffsets(code_offset, frame_size_in_bytes, core_spill_mask, @@ -404,7 +404,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, // Unchecked as we hold mutator_lock_ on entry. ScopedObjectAccessUnchecked soa(Thread::Current()); mirror::AbstractMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, - NULL, NULL, type); + NULL, NULL, invoke_type); CHECK(method != NULL); method->SetFrameSizeInBytes(frame_size_in_bytes); method->SetCoreSpillMask(core_spill_mask); @@ -425,8 +425,11 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, return offset; } -#define DCHECK_CODE_OFFSET() \ - DCHECK_EQ(static_cast<off_t>(code_offset), out.Seek(0, kSeekCurrent)) +#define DCHECK_OFFSET() \ + DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent)) + +#define DCHECK_OFFSET_() \ + DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent)) bool OatWriter::Write(OutputStream& out) { if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) { @@ -491,15 +494,15 @@ bool OatWriter::WriteTables(OutputStream& out) { } size_t OatWriter::WriteCode(OutputStream& out) { - uint32_t code_offset = oat_header_->GetExecutableOffset(); + uint32_t offset = oat_header_->GetExecutableOffset(); off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent); - if (static_cast<uint32_t>(new_offset) != code_offset) { + if (static_cast<uint32_t>(new_offset) != offset) { PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset - << " Expected: " << code_offset << " File: " << out.GetLocation(); + << " Expected: " << offset << " File: " << out.GetLocation(); return 0; } - DCHECK_CODE_OFFSET(); - return code_offset; + DCHECK_OFFSET(); + return offset; } size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) { @@ -575,7 +578,7 @@ size_t OatWriter::WriteCodeClassDef(OutputStream& out, return code_offset; } -size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t oat_class_index, +size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index, size_t class_def_method_index, bool is_static, uint32_t method_idx, const DexFile& dex_file) { const CompiledMethod* compiled_method = @@ -586,43 +589,46 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t if (compiled_method != NULL) { // ie. not an abstract method - uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset); - uint32_t aligned_code_delta = aligned_code_offset - code_offset; +#if !defined(ART_USE_PORTABLE_COMPILER) + uint32_t aligned_offset = compiled_method->AlignCode(offset); + uint32_t aligned_code_delta = aligned_offset - offset; if (aligned_code_delta != 0) { off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); - if (static_cast<uint32_t>(new_offset) != aligned_code_offset) { + if (static_cast<uint32_t>(new_offset) != aligned_offset) { PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset - << " Expected: " << aligned_code_offset << " File: " << out.GetLocation(); + << " Expected: " << aligned_offset << " File: " << out.GetLocation(); return 0; } - code_offset += aligned_code_delta; - DCHECK_CODE_OFFSET(); + offset += aligned_code_delta; + DCHECK_OFFSET(); } - DCHECK_ALIGNED(code_offset, kArmAlignment); + DCHECK_ALIGNED(offset, kArmAlignment); const std::vector<uint8_t>& code = compiled_method->GetCode(); uint32_t code_size = code.size() * sizeof(code[0]); CHECK_NE(code_size, 0U); // Deduplicate code arrays - size_t offset = code_offset + sizeof(code_size) + compiled_method->CodeDelta(); + size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta(); SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); - if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) { - DCHECK(code_iter->second == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file); + if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) { + DCHECK(code_iter->second == method_offsets.code_offset_) + << PrettyMethod(method_idx, dex_file); } else { - DCHECK(offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file); + 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); return 0; } - code_offset += sizeof(code_size); - DCHECK_CODE_OFFSET(); + offset += sizeof(code_size); + DCHECK_OFFSET(); if (!out.WriteFully(&code[0], code_size)) { ReportWriteFailure("method code", method_idx, dex_file, out); return 0; } - code_offset += code_size; + offset += code_size; } - DCHECK_CODE_OFFSET(); + DCHECK_OFFSET(); +#endif const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable(); size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); @@ -631,21 +637,21 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table); if (mapping_iter != mapping_table_offsets_.end() && - code_offset != method_offsets.mapping_table_offset_) { + offset != method_offsets.mapping_table_offset_) { DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) || mapping_iter->second == method_offsets.mapping_table_offset_) << PrettyMethod(method_idx, dex_file); } else { DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) - || code_offset == method_offsets.mapping_table_offset_) + || 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); return 0; } - code_offset += mapping_table_size; + offset += mapping_table_size; } - DCHECK_CODE_OFFSET(); + DCHECK_OFFSET(); const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable(); size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); @@ -654,21 +660,21 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table); if (vmap_iter != vmap_table_offsets_.end() && - code_offset != method_offsets.vmap_table_offset_) { + offset != method_offsets.vmap_table_offset_) { DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) || vmap_iter->second == method_offsets.vmap_table_offset_) << PrettyMethod(method_idx, dex_file); } else { DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) - || code_offset == method_offsets.vmap_table_offset_) + || 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); return 0; } - code_offset += vmap_table_size; + offset += vmap_table_size; } - DCHECK_CODE_OFFSET(); + DCHECK_OFFSET(); const std::vector<uint8_t>& gc_map = compiled_method->GetNativeGcMap(); size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); @@ -677,119 +683,76 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t code_offset, size_t SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map); if (gc_map_iter != gc_map_offsets_.end() && - code_offset != method_offsets.gc_map_offset_) { + offset != method_offsets.gc_map_offset_) { DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0) || gc_map_iter->second == method_offsets.gc_map_offset_) << PrettyMethod(method_idx, dex_file); } else { DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0) - || code_offset == method_offsets.gc_map_offset_) + || 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); return 0; } - code_offset += gc_map_size; + offset += gc_map_size; } - DCHECK_CODE_OFFSET(); + DCHECK_OFFSET(); } + +#if !defined(ART_USE_PORTABLE_COMPILER) const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(is_static, shorty); if (compiled_invoke_stub != NULL) { - uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset, - compiler_driver_->GetInstructionSet()); - uint32_t aligned_code_delta = aligned_code_offset - code_offset; + uint32_t aligned_offset = CompiledMethod::AlignCode(offset, + compiler_driver_->GetInstructionSet()); + uint32_t aligned_code_delta = aligned_offset - offset; if (aligned_code_delta != 0) { off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); - if (static_cast<uint32_t>(new_offset) != aligned_code_offset) { + if (static_cast<uint32_t>(new_offset) != aligned_offset) { PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset - << " Expected: " << aligned_code_offset; + << " Expected: " << aligned_offset; return 0; } - code_offset += aligned_code_delta; - DCHECK_CODE_OFFSET(); + offset += aligned_code_delta; + DCHECK_OFFSET(); } - DCHECK_ALIGNED(code_offset, kArmAlignment); + DCHECK_ALIGNED(offset, kArmAlignment); const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]); CHECK_NE(invoke_stub_size, 0U); // Deduplicate invoke stubs - size_t offset = code_offset + sizeof(invoke_stub_size) + compiled_invoke_stub->CodeDelta(); + size_t invoke_stub_offset = offset + sizeof(invoke_stub_size) + compiled_invoke_stub->CodeDelta(); SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub); - if (stub_iter != code_offsets_.end() && offset != method_offsets.invoke_stub_offset_) { - DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file); + if (stub_iter != code_offsets_.end() + && invoke_stub_offset != method_offsets.invoke_stub_offset_) { + DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_) + << PrettyMethod(method_idx, dex_file); } else { - DCHECK(offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file); + DCHECK(invoke_stub_offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file); if (!out.WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) { ReportWriteFailure("invoke stub code size", method_idx, dex_file, out); return 0; } - code_offset += sizeof(invoke_stub_size); - DCHECK_CODE_OFFSET(); + offset += sizeof(invoke_stub_size); + DCHECK_OFFSET(); if (!out.WriteFully(&invoke_stub[0], invoke_stub_size)) { ReportWriteFailure("invoke stub code", method_idx, dex_file, out); return 0; } - code_offset += invoke_stub_size; - DCHECK_CODE_OFFSET(); - } - } - -#if defined(ART_USE_PORTABLE_COMPILER) - if (!is_static) { - const CompiledInvokeStub* compiled_proxy_stub = compiler_driver_->FindProxyStub(shorty); - if (compiled_proxy_stub != NULL) { - uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset, - compiler_driver_->GetInstructionSet()); - uint32_t aligned_code_delta = aligned_code_offset - code_offset; - CHECK(aligned_code_delta < 48u); - if (aligned_code_delta != 0) { - off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); - if (static_cast<uint32_t>(new_offset) != aligned_code_offset) { - PLOG(ERROR) << "Failed to seek to align proxy stub code. Actual: " << new_offset - << " Expected: " << aligned_code_offset; - return 0; - } - code_offset += aligned_code_delta; - DCHECK_CODE_OFFSET(); - } - DCHECK_ALIGNED(code_offset, kArmAlignment); - const std::vector<uint8_t>& proxy_stub = compiled_proxy_stub->GetCode(); - uint32_t proxy_stub_size = proxy_stub.size() * sizeof(proxy_stub[0]); - CHECK_NE(proxy_stub_size, 0U); - - // Deduplicate proxy stubs - size_t offset = code_offset + sizeof(proxy_stub_size) + compiled_proxy_stub->CodeDelta(); - SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = - code_offsets_.find(&proxy_stub); - if (stub_iter != code_offsets_.end() && offset != method_offsets.proxy_stub_offset_) { - DCHECK(stub_iter->second == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file); - } else { - DCHECK(offset == method_offsets.proxy_stub_offset_) << PrettyMethod(method_idx, dex_file); - if (!out.WriteFully(&proxy_stub_size, sizeof(proxy_stub_size))) { - ReportWriteFailure("proxy stub code size", method_idx, dex_file, out); - return 0; - } - code_offset += sizeof(proxy_stub_size); - DCHECK_CODE_OFFSET(); - if (!out.WriteFully(&proxy_stub[0], proxy_stub_size)) { - ReportWriteFailure("proxy stub code", method_idx, dex_file, out); - return 0; - } - code_offset += proxy_stub_size; - DCHECK_CODE_OFFSET(); - } - DCHECK_CODE_OFFSET(); + offset += invoke_stub_size; + DCHECK_OFFSET(); } } #endif - return code_offset; + return offset; } -OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) { +OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) { + offset_ = offset; const std::string& location(dex_file.GetLocation()); dex_file_location_size_ = location.size(); dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data()); @@ -816,6 +779,7 @@ void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const { } bool OatWriter::OatDexFile::Write(OutputStream& out) 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(); return false; @@ -840,14 +804,25 @@ bool OatWriter::OatDexFile::Write(OutputStream& out) const { return true; } -OatWriter::OatClass::OatClass(mirror::Class::Status status, uint32_t methods_count) { +OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) { + offset_ = offset; status_ = status; method_offsets_.resize(methods_count); } -size_t OatWriter::OatClass::SizeOf() const { +size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader( + size_t class_def_method_index_) const { + return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_); +} + +size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass( + size_t class_def_method_index_) const { return sizeof(status_) - + (sizeof(method_offsets_[0]) * method_offsets_.size()); + + (sizeof(method_offsets_[0]) * class_def_method_index_); +} + +size_t OatWriter::OatClass::SizeOf() const { + return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size()); } void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { @@ -857,15 +832,20 @@ void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { } bool OatWriter::OatClass::Write(OutputStream& out) const { + DCHECK_OFFSET_(); if (!out.WriteFully(&status_, sizeof(status_))) { PLOG(ERROR) << "Failed to write class status to " << out.GetLocation(); return false; } + DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)), + out.Seek(0, kSeekCurrent)); if (!out.WriteFully(&method_offsets_[0], sizeof(method_offsets_[0]) * method_offsets_.size())) { PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation(); return false; } + DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())), + out.Seek(0, kSeekCurrent)); return true; } diff --git a/src/oat_writer.h b/src/oat_writer.h index f67a3b029a..e1d76f459f 100644 --- a/src/oat_writer.h +++ b/src/oat_writer.h @@ -117,11 +117,15 @@ class OatWriter { class OatDexFile { public: - explicit OatDexFile(const DexFile& dex_file); + explicit OatDexFile(size_t offset, const DexFile& dex_file); size_t SizeOf() const; void UpdateChecksum(OatHeader& oat_header) const; bool Write(OutputStream& out) const; + // Offset of start of OatDexFile from beginning of OatHeader. It is + // used to validate file position when writing. + size_t offset_; + // data to write uint32_t dex_file_location_size_; const uint8_t* dex_file_location_data_; @@ -135,11 +139,20 @@ class OatWriter { class OatClass { public: - explicit OatClass(mirror::Class::Status status, uint32_t methods_count); + explicit OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count); + 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(OutputStream& out) const; + // Offset of start of OatClass from beginning of OatHeader. It is + // used to validate file position when writing. For Portable, it + // is also used to calculate the position of the OatMethodOffsets + // so that code pointers within the OatMethodOffsets can be + // patched to point to code in the Portable .o ELF objects. + size_t offset_; + // data to write mirror::Class::Status status_; std::vector<OatMethodOffsets> method_offsets_; diff --git a/src/runtime.cc b/src/runtime.cc index c74757f376..414bef4093 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -57,10 +57,6 @@ #include "verifier/method_verifier.h" #include "well_known_classes.h" -#if defined(ART_USE_PORTABLE_COMPILER) -#include "compiler/llvm/procedure_linkage_table.h" -#endif - #include "JniConstants.h" // Last to avoid LOG redefinition in ics-mr1-plus-art. namespace art { @@ -99,27 +95,13 @@ Runtime::Runtime() instrumentation_(NULL), use_compile_time_class_path_(false), main_thread_group_(NULL), - system_thread_group_(NULL) -#if defined(ART_USE_PORTABLE_COMPILER) -#if defined(__arm__) - , plt_(kArm) -#elif defined(__mips__) - , plt_(kMips) -#elif defined(__i386__) - , plt_(kX86) -#endif -#endif - { + system_thread_group_(NULL) { for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) { resolution_stub_array_[i] = NULL; } for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { callee_save_methods_[i] = NULL; } - -#if defined(ART_USE_PORTABLE_COMPILER) - CHECK(plt_.AllocateTable()) << "Failed to allocate PLT"; -#endif } Runtime::~Runtime() { diff --git a/src/runtime.h b/src/runtime.h index 411d618e49..696f2317e9 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -36,10 +36,6 @@ #include "runtime_stats.h" #include "safe_map.h" -#if defined(ART_USE_PORTABLE_COMPILER) -#include "compiler/llvm/procedure_linkage_table.h" -#endif - namespace art { namespace mirror { @@ -477,9 +473,6 @@ class Runtime { jobject main_thread_group_; jobject system_thread_group_; -#if defined(ART_USE_PORTABLE_COMPILER) - art::llvm::ProcedureLinkageTable plt_; -#endif DISALLOW_COPY_AND_ASSIGN(Runtime); }; diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar index c130521d2c..c0c5e12bdb 100755 --- a/test/etc/host-run-test-jar +++ b/test/etc/host-run-test-jar @@ -88,7 +88,7 @@ fi if [ "$GDB" = "y" ]; then gdb=gdb - gdbargs="--args $exe" + gdbargs="--annotate=3 --args $exe" fi if [ "$INTERPRETER" = "y" ]; then |