Remove ExtractCodeAndPrelink and switch Portable to MCLinker
Change-Id: Ia2459c7da6b79e0a1c0f1148c6e28ad9cbbe27a2
diff --git a/Android.mk b/Android.mk
index 38c0419..16a2c12 100644
--- a/Android.mk
+++ b/Android.mk
@@ -313,25 +313,32 @@
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 f30cf01..43755b4 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -141,7 +141,6 @@
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 @@
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 @@
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 730c980..afb335e 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -112,13 +112,20 @@
$(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 9e11e22..8f0ccf8 100644
--- a/build/Android.libart-compiler.mk
+++ b/build/Android.libart-compiler.mk
@@ -48,6 +48,7 @@
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 @@
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 630f05a..67461be 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -120,9 +120,11 @@
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 b4e1266..feeede5 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 @@
$(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_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_OUT): $(TARGET_BOOT_IMG_OUT)
+$(TARGET_BOOT_OAT_UNSTRIPPED_OUT): $(TARGET_BOOT_IMG_OUT)
-ifeq ($(ART_BUILD_TARGET),true)
+$(TARGET_BOOT_OAT_OUT): $(TARGET_BOOT_OAT_UNSTRIPPED_OUT)
+
+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 744a01d..c2163bd 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -23,27 +23,31 @@
# $(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 @@
$(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 ca7cc00..4a07eba 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -659,6 +659,9 @@
<< " --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 @@
"--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 @@
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 @@
// 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 893e7a4..e9ba70a 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -368,7 +368,7 @@
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 @@
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 @@
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 @@
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 0d3795e..0167424 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -246,7 +246,7 @@
&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 @@
NULL,
NULL,
method_invoke_stub);
- oat_method.LinkMethodPointers(method);
+ oat_method.LinkMethod(method);
}
}
@@ -434,12 +434,16 @@
}
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 @@
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 4de2a3f..36c4eea 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 @@
}
}
+#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 @@
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 @@
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 @@
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 b7a2f9c..c05aba1 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 @@
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 @@
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 @@
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 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 4ab98a6..f8cdd34 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 @@
struct ArenaBitVector;
struct LIR;
class LLVMInfo;
+namespace llvm {
+class LlvmCompilationUnit;
+} // namespace llvm
struct PromotionMap {
RegLocationType core_location:3;
@@ -348,6 +354,7 @@
mstats(NULL),
checkstats(NULL),
gen_bitcode(false),
+ llvm_compilation_unit(NULL),
llvm_info(NULL),
context(NULL),
module(NULL),
@@ -507,7 +514,11 @@
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 @@
::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 ac3116e..f0f177a 100644
--- a/src/compiler/dex/dataflow.cc
+++ b/src/compiler/dex/dataflow.cc
@@ -2491,10 +2491,7 @@
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 482804c..5b8faf4 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 @@
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 @@
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 @@
}
+#if defined(ART_USE_PORTABLE_COMPILER)
/* Go the LLVM path? */
if (cu->gen_bitcode) {
// MIR->Bitcode
@@ -1148,7 +1159,9 @@
}
// 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 @@
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 8319b4d..e6900df 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 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 63c8460..21290ca 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 @@
#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 5f8f6ef..110146f 100644
--- a/src/compiler/dex/quick/codegen_util.cc
+++ b/src/compiler/dex/quick/codegen_util.cc
@@ -54,10 +54,7 @@
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 f14d6cf..a289252 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 @@
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 @@
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 2c01c19..1ae29be 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 @@
// 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 b945e31..a7baea4 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 a782264..5b7de2c 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 a78d98e..7e3d512 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 @@
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 a28ba18..8856a00 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -1678,7 +1678,7 @@
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 @@
}
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 @@
}
}
-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 @@
}
}
-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 @@
}
}
-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 @@
}
}
-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 @@
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 @@
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 49bc473..7f67c21 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -123,11 +123,11 @@
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 @@
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 @@
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 @@
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 19ccb35..dee448d 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -132,6 +132,7 @@
}
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 0000000..67987fa
--- /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 6a0218d..0fc1123 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 @@
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 @@
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 5c314e6..ec6dc30 100644
--- a/src/compiler/invoke_stubs/portable/stub_compiler.cc
+++ b/src/compiler/invoke_stubs/portable/stub_compiler.cc
@@ -52,7 +52,7 @@
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 @@
// 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 @@
cunit_->Materialize();
return new CompiledInvokeStub(cunit_->GetInstructionSet(),
- cunit_->GetCompiledCode());
+ cunit_->GetElfObject(),
+ func_name);
}
@@ -194,7 +195,7 @@
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 @@
// 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 @@
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 4ed7898..5176752 100644
--- a/src/compiler/jni/jni_compiler_test.cc
+++ b/src/compiler/jni/jni_compiler_test.cc
@@ -130,6 +130,7 @@
}
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, 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, CompileAndRunStaticIntMethodThroughStub) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(true, "sbar", "(I)I",
NULL /* calling through stub will link with &Java_MyClassNatives_sbar */);
@@ -181,6 +184,7 @@
}
TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(false, "fooI", "(I)I",
reinterpret_cast<void*>(&Java_MyClassNatives_fooI));
@@ -206,6 +210,7 @@
}
TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(false, "fooII", "(II)I",
reinterpret_cast<void*>(&Java_MyClassNatives_fooII));
@@ -232,6 +237,7 @@
}
TEST_F(JniCompilerTest, CompileAndRunLongLongMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(false, "fooJJ", "(JJ)J",
reinterpret_cast<void*>(&Java_MyClassNatives_fooJJ));
@@ -259,6 +265,7 @@
}
TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(false, "fooDD", "(DD)D",
reinterpret_cast<void*>(&Java_MyClassNatives_fooDD));
@@ -287,6 +294,7 @@
}
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 @@
}
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 @@
}
TEST_F(JniCompilerTest, CompileAndRunStaticIntIntMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(true, "fooSII", "(II)I",
reinterpret_cast<void*>(&Java_MyClassNatives_fooSII));
@@ -384,6 +394,7 @@
}
TEST_F(JniCompilerTest, CompileAndRunStaticDoubleDoubleMethod) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(true, "fooSDD", "(DD)D",
reinterpret_cast<void*>(&Java_MyClassNatives_fooSDD));
@@ -420,6 +431,7 @@
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 @@
}
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 @@
}
TEST_F(JniCompilerTest, ExceptionHandling) {
+ TEST_DISABLED_FOR_PORTABLE();
{
ASSERT_FALSE(runtime_->IsStarted());
ScopedObjectAccess soa(Thread::Current());
@@ -585,6 +599,7 @@
}
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 @@
}
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 @@
}
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 @@
}
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 @@
}
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 @@
}
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, 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 @@
}
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_Static) {
+ TEST_DISABLED_FOR_PORTABLE();
SetUpForTest(true, "staticMethodThatShouldReturnClass", "()Ljava/lang/Class;",
reinterpret_cast<void*>(&Java_MyClassNatives_staticMethodThatShouldReturnClass));
@@ -727,6 +750,7 @@
}
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_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 1a4ad95..8495150 100644
--- a/src/compiler/jni/portable/jni_compiler.cc
+++ b/src/compiler/jni/portable/jni_compiler.cc
@@ -64,7 +64,10 @@
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 @@
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 @@
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 3df81a5..a04277c 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 @@
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 1c9a494..be1730f 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 870a541..cbee115 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 @@
CompiledInvokeStub* CreateProxyStub(const char *shorty);
- const ProcedureLinkageTable& GetProcedureLinkageTable() const {
- return plt_;
- }
-
private:
LlvmCompilationUnit* AllocateCompilationUnit();
@@ -98,13 +93,11 @@
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 ffbae85..0000000
--- 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 4e1a91d..9de2e41 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -326,7 +326,7 @@
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 @@
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 @@
::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 aad18fb..3783ae9 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 @@
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 @@
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 9ca9e3f..96d019c 100644
--- a/src/compiler/llvm/llvm_compilation_unit.h
+++ b/src/compiler/llvm/llvm_compilation_unit.h
@@ -53,8 +53,8 @@
public:
~LlvmCompilationUnit();
- size_t GetIndex() const {
- return cunit_idx_;
+ uint32_t GetCompilationUnitId() const {
+ return cunit_id_;
}
InstructionSet GetInstructionSet() const;
@@ -81,27 +81,30 @@
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 @@
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 @@
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 47ba9bd..0000000
--- 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 1c89d29..0000000
--- 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 ae8bb4a..b18eefe 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 @@
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_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 e06e113..2e273f4 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 @@
#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 6b94dc0..6892bb3 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -81,13 +81,19 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
} 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 @@
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 @@
}
}
+ 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 @@
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 @@
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 @@
// 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 0000000..dc2e712
--- /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 0000000..e4a42db
--- /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 8d6e630..6f9d53c 100644
--- a/src/elf_file.cc
+++ b/src/elf_file.cc
@@ -36,7 +36,9 @@
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 @@
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 @@
// 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 @@
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 @@
ElfFile::~ElfFile() {
STLDeleteElements(&segments_);
+ delete symtab_symbol_table_;
+ delete dynsym_symbol_table_;
}
bool ElfFile::SetMap(MemMap* map) {
@@ -247,9 +257,9 @@
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 @@
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 @@
}
// 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 @@
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_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 @@
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 @@
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 @@
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 @@
}
case llvm::ELF::DT_NULL: {
CHECK_EQ(GetDynamicNum(), i+1);
+ break;
}
}
}
diff --git a/src/elf_file.h b/src/elf_file.h
index b1d787e..59ce7f5 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 @@
::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);
- ::llvm::ELF::Elf32_Sym* FindSymbolByName(::llvm::ELF::Elf32_Word section_type,
- const std::string& symbol_name);
- ::llvm::ELF::Elf32_Addr FindSymbolAddress(::llvm::ELF::Elf32_Word section_type,
- const std::string& symbol_name);
- char* GetString(::llvm::ELF::Elf32_Shdr&, ::llvm::ELF::Elf32_Word);
+ // 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,
+ 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,
+ bool build_map);
+
+ // 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 @@
::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 @@
::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 106ad44..88b3543 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 @@
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();
+ // 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);
- }
- 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);
- }
+ 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());
- // 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());
+ // error on undefined symbols.
+ // TODO: should this just be set if kIsDebugBuild?
+ linker_config_->options().setNoUndefined(true);
-
- // 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;
- }
-
- // emited linked output
- if (!linker->emit(elf_file->Fd())) {
- LOG(ERROR) << "problem emitting " << elf_file->GetPath();
- return false;
- }
- // TODO: mcld::Linker::emit closed the file descriptor. It probably shouldn't.
- // For now, close our File to match.
- elf_file->Close();
- mcld::Finalize();
+ // 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);
}
- LOG(INFO) << "ELF file written successfully: " << elf_file->GetPath();
+
+ // 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);
+ }
+ const CompiledInvokeStub* compiled_invoke_stub = compiler_driver_->FindInvokeStub(invoke_type == kStatic,
+ shorty);
+ if (compiled_invoke_stub != NULL) {
+ AddCompiledCodeInput(*compiled_invoke_stub);
+ }
+
+ 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();
+}
+
+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();
+ }
+ }
+
+ 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 @@
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 @@
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 @@
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 f55003f..6f22db1 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 @@
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 @@
// 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 0be624d..a47bc71 100644
--- a/src/elf_writer_test.cc
+++ b/src/elf_writer_test.cc
@@ -30,9 +30,9 @@
}
};
-#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 @@
{
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 c8df031..64df6b8 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -104,6 +104,10 @@
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 6d22cad..dc16a6c 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -57,9 +57,13 @@
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 d9ac61b..ad2c9b7 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -78,7 +78,7 @@
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 ee02ec4..46d134f 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -98,7 +98,12 @@
}
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 801e7c9..deff290 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -1406,6 +1406,7 @@
}
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, 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 5fd95be..62fc740 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -44,8 +44,8 @@
}
}
-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 @@
* 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 @@
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 @@
}
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 @@
// 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 @@
}
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 @@
// 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 @@
}
#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 @@
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 8efdf9f..4aa18ba 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -46,14 +46,15 @@
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 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 69ce48b..ace52f4 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -90,7 +90,11 @@
"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 1a269e9..e299a27 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -93,7 +93,7 @@
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 @@
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 __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 @@
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 @@
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 @@
}
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 @@
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 @@
// 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
}
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 f67a3b0..e1d76f4 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -117,11 +117,15 @@
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 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 c74757f..414bef4 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 @@
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 411d618..696f231 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 @@
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 c130521..c0c5e12 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -88,7 +88,7 @@
if [ "$GDB" = "y" ]; then
gdb=gdb
- gdbargs="--args $exe"
+ gdbargs="--annotate=3 --args $exe"
fi
if [ "$INTERPRETER" = "y" ]; then