Merge "Fixed class linker ResolveType for multi-dimensional arrays." into dalvik-dev
diff --git a/Android.mk b/Android.mk
index f141d51..bd37967 100644
--- a/Android.mk
+++ b/Android.mk
@@ -57,8 +57,8 @@
$(foreach file,$(sort $(ART_HOST_TEST_EXECUTABLES)),$(1) $(file) &&) true
endef
-ART_HOST_TEST_DEPENDENCIES := $(ART_HOST_TEST_EXECUTABLES) $(ANDROID_HOST_OUT)/framework/core-hostdex.jar $(ART_TEST_OAT_FILES)
-ART_TARGET_TEST_DEPENDENCIES := $(ART_TARGET_TEST_EXECUTABLES) $(ANDROID_PRODUCT_OUT)/system/framework/core.jar $(ART_TEST_OAT_FILES)
+ART_HOST_TEST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(ART_HOST_TEST_EXECUTABLES) $(ANDROID_HOST_OUT)/framework/core-hostdex.jar $(ART_TEST_OAT_FILES)
+ART_TARGET_TEST_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(ART_TARGET_TEST_EXECUTABLES) $(ANDROID_PRODUCT_OUT)/system/framework/core.jar $(ART_TEST_OAT_FILES)
ART_TARGET_TEST_DEPENDENCIES += $(TARGET_OUT_EXECUTABLES)/oat_process $(TARGET_OUT_EXECUTABLES)/oat_processd
@@ -88,7 +88,7 @@
# "mm test-art-target" to build and run all target tests
.PHONY: test-art-target
-test-art-target: test-art-target-gtest test-art-target-oat
+test-art-target: test-art-target-gtest test-art-target-oat test-art-target-run-test
@echo test-art-target PASSED
.PHONY: test-art-target-sync
@@ -108,6 +108,15 @@
test-art-target-oat: $(ART_TEST_OAT_TARGETS)
@echo test-art-target-oat PASSED
+.PHONY: test-art-target-run-test
+test-art-target-run-test: test-art-target-run-test-002
+ @echo test-art-target-run-test PASSED
+
+.PHONY: test-art-target-run-test-002
+test-art-target-run-test-002:
+ art/test/run-test 002
+ @echo test-art-target-run-test-002 PASSED
+
########################################################################
# oat_process test targets
@@ -125,7 +134,7 @@
test-art-target-oat-process-am: $(TARGET_OUT_JAVA_LIBRARIES)/am.oat test-art-target-sync
adb remount
adb sync
- adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Xbootimage:/system/framework/boot.oat -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am start http://android.com && touch /sdcard/test-art-target-process-am"
+ adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Xbootimage:/system/framework/boot.art -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am start http://android.com && touch /sdcard/test-art-target-process-am"
$(hide) (adb pull /sdcard/test-art-target-process-am /tmp/ && echo test-art-target-process-am PASSED) || echo test-art-target-process-am FAILED
$(hide) rm /tmp/test-art-target-process-am
@@ -149,7 +158,7 @@
sleep 30; \
fi
adb shell kill `adb shell ps | fgrep com.android.calculator2 | sed -e 's/[^ ]* *\([0-9]*\).*/\1/'`
- adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Xbootimage:/system/framework/boot.oat -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am start -a android.intent.action.MAIN -n com.android.calculator2/.Calculator && touch /sdcard/test-art-target-process-Calculator"
+ adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_processd /system/bin/app_process -Xbootimage:/system/framework/boot.art -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am start -a android.intent.action.MAIN -n com.android.calculator2/.Calculator && touch /sdcard/test-art-target-process-Calculator"
$(hide) (adb pull /sdcard/test-art-target-process-Calculator /tmp/ && echo test-art-target-process-Calculator PASSED) || echo test-art-target-process-Calculator FAILED
$(hide) rm /tmp/test-art-target-process-Calculator
@@ -161,17 +170,17 @@
.PHONY: dump-oat-core
dump-oat-core: $(TARGET_CORE_OAT) $(OATDUMP)
- $(OATDUMP) $(addprefix --dex-file=,$(TARGET_CORE_DEX)) --image=$< --strip-prefix=$(PRODUCT_OUT) --output=/tmp/core.oatdump.txt
+ $(OATDUMP) $(addprefix --dex-file=,$(TARGET_CORE_DEX)) --oat=$(TARGET_CORE_OAT) --image=$(TARGET_CORE_IMG) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/core.oatdump.txt
@echo Output in /tmp/core.oatdump.txt
.PHONY: dump-oat-boot
dump-oat-boot: $(TARGET_BOOT_OAT) $(OATDUMP)
- $(OATDUMP) $(addprefix --dex-file=,$(TARGET_BOOT_DEX)) --image=$< --strip-prefix=$(PRODUCT_OUT) --output=/tmp/boot.oatdump.txt
+ $(OATDUMP) $(addprefix --dex-file=,$(TARGET_BOOT_DEX)) --oat=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/boot.oatdump.txt
@echo Output in /tmp/boot.oatdump.txt
.PHONY: dump-oat-Calculator
dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.oat $(TARGET_BOOT_OAT) $(OATDUMP)
- $(OATDUMP) --dex-file=$(TARGET_OUT_APPS)/Calculator.apk --image=$< $(addprefix --boot-dex-file=,$(TARGET_BOOT_DEX)) --boot=$(TARGET_BOOT_OAT) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/Calculator.oatdump.txt
+ $(OATDUMP) --dex-file=$(TARGET_OUT_APPS)/Calculator.apk --oat=$< --image=$(patsubst %.oat,%.art,$<) $(addprefix --boot-dex-file=,$(TARGET_BOOT_DEX)) --boot-oat=$(TARGET_BOOT_OAT) --boot-image=$(TARGET_BOOT_IMG) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/Calculator.oatdump.txt
@echo Output in /tmp/Calculator.oatdump.txt
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 1b65971..69580cc 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -129,6 +129,9 @@
src/monitor.cc \
src/mspace.c \
src/mutex.cc \
+ src/oat.cc \
+ src/oat_file.cc \
+ src/oat_writer.cc \
src/object.cc \
src/object_bitmap.cc \
src/offsets.cc \
@@ -187,6 +190,7 @@
src/jni_compiler_test.cc \
src/managed_register_arm_test.cc \
src/managed_register_x86_test.cc \
+ src/oat_test.cc \
src/object_test.cc \
src/reference_table_test.cc \
src/runtime_test.cc \
@@ -207,6 +211,7 @@
AbstractMethod \
AllFields \
CreateMethodDescriptor \
+ ExceptionHandle \
ExceptionTest \
Fibonacci \
HelloWorld \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 2ea132d..52d5621 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -24,9 +24,9 @@
# TODO: for now, override with debug version for better error reporting
OATDUMP := $(OATDUMPD)
-# start of oat reserved address space
-OAT_HOST_BASE_ADDRESS := 0x60000000
-OAT_TARGET_BASE_ADDRESS := 0x60000000
+# start of image reserved address space
+IMG_HOST_BASE_ADDRESS := 0x60000000
+IMG_TARGET_BASE_ADDRESS := 0x60000000
########################################################################
# A smaller libcore only oat file
@@ -39,23 +39,27 @@
HOST_CORE_OAT := $(HOST_OUT_JAVA_LIBRARIES)/core.oat
TARGET_CORE_OAT := $(TARGET_OUT_JAVA_LIBRARIES)/core.oat
+HOST_CORE_IMG := $(HOST_OUT_JAVA_LIBRARIES)/core.art
+TARGET_CORE_IMG := $(TARGET_OUT_JAVA_LIBRARIES)/core.art
+
# TODO: change DEX2OATD to order-only prerequisite when output is stable
$(HOST_CORE_OAT): $(HOST_CORE_DEX) $(DEX2OAT)
@echo "host dex2oat: $@ ($<)"
- $(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_HOST_BASE_ADDRESS)
+ $(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
# TODO: change DEX2OATD to order-only prerequisite when output is stable
$(TARGET_CORE_OAT): $(TARGET_CORE_DEX) $(DEX2OAT)
@echo "target dex2oat: $@ ($<)"
- $(hide) $(DEX2OAT) -Xms32m -Xmx32m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
+ $(hide) $(DEX2OAT) -Xms32m -Xmx32m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
########################################################################
# The full system boot classpath
TARGET_BOOT_JARS := $(subst :, ,$(DEXPREOPT_BOOT_JARS))
TARGET_BOOT_DEX := $(foreach jar,$(TARGET_BOOT_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
TARGET_BOOT_OAT := $(TARGET_OUT_JAVA_LIBRARIES)/boot.oat
+TARGET_BOOT_IMG := $(TARGET_OUT_JAVA_LIBRARIES)/boot.art
# TODO: change DEX2OATD to order-only prerequisite when output is stable
$(TARGET_BOOT_OAT): $(TARGET_BOOT_DEX) $(DEX2OAT)
@echo "target dex2oat: $@ ($<)"
- $(hide) $(DEX2OAT) -Xms256m -Xmx256m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
+ $(hide) $(DEX2OAT) -Xms256m -Xmx256m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index fe26a9b..ce615b2 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -40,7 +40,7 @@
# TODO: change DEX2OATD (and perhaps $(2) boot oat) to order-only prerequisite when output is stable
$(patsubst %.apk,%.oat,$(patsubst %.jar,%.oat,$(1))): $(1) $(2) $(DEX2OAT)
@echo "target dex2oat: $$@ ($$<)"
- $(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --boot-dex-file=,$(3)) --boot=$(2) $(addprefix --dex-file=,$$<) --image=$$@ --strip-prefix=$(PRODUCT_OUT)
+ $(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --boot-dex-file=,$(3)) --boot-oat=$(2) --boot-image=$(patsubst %.oat,%.art,$(2)) $(addprefix --dex-file=,$$<) --oat=$$@ --image=$$(patsubst %.oat,%.art,$$@) --strip-prefix=$(PRODUCT_OUT)
endef
########################################################################
@@ -64,7 +64,7 @@
test-art-target-oat-$(1): test-art-target-sync
adb shell touch /sdcard/test-art-target-oat-$(1)
adb shell rm /sdcard/test-art-target-oat-$(1)
- adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/core.oat -classpath /system/framework/art-test-dex-$(1).jar -Ximage:/system/framework/art-test-dex-$(1).oat $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
+ adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootoat:/system/framework/core.oat -Xbootimage:/system/framework/core.art -classpath /system/framework/art-test-dex-$(1).jar -Xoat:/system/framework/art-test-dex-$(1).oat -Ximage:/system/framework/art-test-dex-$(1).art $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
$(hide) (adb pull /sdcard/test-art-target-oat-$(1) /tmp/ && echo test-art-target-oat-$(1) PASSED) || (echo test-art-target-oat-$(1) FAILED && exit 1)
$(hide) rm /tmp/test-art-target-oat-$(1)
diff --git a/src/common_test.h b/src/common_test.h
index bbf2e2f..a7c5ea8 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -13,8 +13,10 @@
#include "compiler.h"
#include "constants.h"
#include "dex_file.h"
+#include "file.h"
#include "gtest/gtest.h"
#include "heap.h"
+#include "os.h"
#include "runtime.h"
#include "stl_util.h"
#include "stringprintf.h"
@@ -26,11 +28,22 @@
static inline const DexFile* OpenDexFileBase64(const char* base64,
const std::string& location) {
+ // decode base64
CHECK(base64 != NULL);
size_t length;
byte* dex_bytes = DecodeBase64(base64, &length);
CHECK(dex_bytes != NULL);
- const DexFile* dex_file = DexFile::OpenPtr(dex_bytes, length, location);
+
+ // write to provided file
+ UniquePtr<File> file(OS::OpenFile(location.c_str(), true));
+ CHECK(file.get() != NULL);
+ if (!file->WriteFully(dex_bytes, length)) {
+ PLOG(FATAL) << "Failed to write base64 as dex file";
+ }
+ file.reset();
+
+ // read dex file
+ const DexFile* dex_file = DexFile::OpenFile(location, location, "");
CHECK(dex_file != NULL);
return dex_file;
}
@@ -106,19 +119,21 @@
Runtime::Options options;
options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
- options.push_back(std::make_pair("-Xms16m", reinterpret_cast<void*>(NULL)));
- options.push_back(std::make_pair("-Xmx16m", reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair("-Xms64m", reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair("-Xmx64m", reinterpret_cast<void*>(NULL)));
runtime_.reset(Runtime::Create(options, false));
ASSERT_TRUE(runtime_.get() != NULL);
class_linker_ = runtime_->GetClassLinker();
#if defined(__i386__)
runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kX86));
+ runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kX86));
runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kX86));
compiler_.reset(new Compiler(kX86));
#elif defined(__arm__)
runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kThumb2));
+ runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
compiler_.reset(new Compiler(kThumb2));
#endif
diff --git a/src/compiler.cc b/src/compiler.cc
index 34263da..af5cdd6 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -24,14 +24,22 @@
ByteArray* CreateAbstractMethodErrorStub();
}
+ByteArray* Compiler::CreateAbstractMethodErrorStub(InstructionSet instruction_set) {
+ switch (instruction_set) {
+ case kArm:
+ case kThumb2:
+ return arm::CreateAbstractMethodErrorStub();
+ case kX86:
+ return x86::CreateAbstractMethodErrorStub();
+ default:
+ LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set;
+ return NULL;
+ }
+}
+
Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler_(insns),
verbose_(false) {
CHECK(!Runtime::Current()->IsStarted());
- if (insns == kArm || insns == kThumb2) {
- abstract_method_error_stub_ = arm::CreateAbstractMethodErrorStub();
- } else if (insns == kX86) {
- abstract_method_error_stub_ = x86::CreateAbstractMethodErrorStub();
- }
}
void Compiler::CompileAll(const ClassLoader* class_loader) {
@@ -273,17 +281,17 @@
method->UnregisterNative();
}
} else if (method->IsAbstract()) {
- DCHECK(abstract_method_error_stub_ != NULL);
+ ByteArray* abstract_method_error_stub = Runtime::Current()->GetAbstractMethodErrorStubArray();
if (instruction_set_ == kX86) {
- method->SetCode(abstract_method_error_stub_, kX86);
+ method->SetCodeArray(abstract_method_error_stub, kX86);
} else {
CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
- method->SetCode(abstract_method_error_stub_, kArm);
+ method->SetCodeArray(abstract_method_error_stub, kArm);
}
} else {
oatCompileMethod(*this, method, kThumb2);
}
- CHECK(method->GetCode() != NULL);
+ CHECK(method->GetCode() != NULL) << PrettyMethod(method);
if (instruction_set_ == kX86) {
art::x86::X86CreateInvokeStub(method);
diff --git a/src/compiler.h b/src/compiler.h
index 563bbde..f9a5c29 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -30,6 +30,10 @@
return verbose_;
}
+ // Stub to throw AbstractMethodError
+ // TODO: remove from Compiler
+ static ByteArray* CreateAbstractMethodErrorStub(InstructionSet instruction_set);
+
private:
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
@@ -55,7 +59,6 @@
InstructionSet instruction_set_;
JniCompiler jni_compiler_;
- ByteArray* abstract_method_error_stub_;
bool verbose_;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index eef6888..cb83143 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -904,7 +904,9 @@
memcpy(vmap_table->GetData(),
reinterpret_cast<const int16_t*>(&cUnit.coreVmapTable[0]),
vmap_table->GetLength() * sizeof(cUnit.coreVmapTable[0]));
- method->SetCode(managed_code, art::kThumb2, mapping_table, vmap_table);
+ method->SetCodeArray(managed_code, art::kThumb2);
+ method->SetMappingTable(mapping_table);
+ method->SetVMapTable(vmap_table);
method->SetFrameSizeInBytes(cUnit.frameSize);
method->SetReturnPcOffsetInBytes(cUnit.frameSize - sizeof(intptr_t));
method->SetCoreSpillMask(cUnit.coreSpillMask);
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 6c967ed..78d3628 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -10,6 +10,7 @@
#include "class_loader.h"
#include "compiler.h"
#include "image_writer.h"
+#include "oat_writer.h"
#include "runtime.h"
#include "stringpiece.h"
@@ -25,7 +26,12 @@
" Example: --dex-file=/system/framework/core.jar\n"
"\n");
fprintf(stderr,
- " --image=<file>: specifies the required output image filename.\n"
+ " --image=<file.art>: specifies the required output image filename.\n"
+ " Example: --image=/system/framework/boot.art\n"
+ "\n");
+ // TODO: remove this by inferring from --image
+ fprintf(stderr,
+ " --oat=<file.oat>: specifies the required oat filename.\n"
" Example: --image=/system/framework/boot.oat\n"
"\n");
fprintf(stderr,
@@ -33,10 +39,15 @@
" Example: --base=0x50000000\n"
"\n");
fprintf(stderr,
- " --boot=<oat-file>: provide the oat file for the boot class path.\n"
- " Example: --boot=/system/framework/boot.oat\n"
+ " --boot-image=<file.art>: provide the image file for the boot class path.\n"
+ " Example: --boot-image=/system/framework/boot.art\n"
"\n");
- // TODO: remove this by making boot image contain boot DexFile information?
+ // TODO: remove this by inferring from --boot-image
+ fprintf(stderr,
+ " --boot-oat=<file.oat>: provide the oat file for the boot class path.\n"
+ " Example: --boot-oat=/system/framework/boot.oat\n"
+ "\n");
+ // TODO: remove this by inderring from --boot-image or --boot-oat
fprintf(stderr,
" --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
" image specified with --boot. \n"
@@ -76,8 +87,10 @@
std::vector<const char*> dex_filenames;
std::vector<const char*> method_names;
+ std::string oat_filename;
const char* image_filename = NULL;
std::string boot_image_option;
+ std::string boot_oat_option;
std::vector<const char*> boot_dex_filenames;
uintptr_t image_base = 0;
std::string strip_location_prefix;
@@ -90,6 +103,8 @@
dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
} else if (option.starts_with("--method=")) {
method_names.push_back(option.substr(strlen("--method=")).data());
+ } else if (option.starts_with("--oat=")) {
+ oat_filename = option.substr(strlen("--oat=")).data();
} else if (option.starts_with("--image=")) {
image_filename = option.substr(strlen("--image=")).data();
} else if (option.starts_with("--base=")) {
@@ -100,11 +115,16 @@
fprintf(stderr, "Failed to parse hexadecimal value for option %s\n", option.data());
usage();
}
- } else if (option.starts_with("--boot=")) {
- const char* boot_image_filename = option.substr(strlen("--boot=")).data();
+ } else if (option.starts_with("--boot-image=")) {
+ const char* boot_image_filename = option.substr(strlen("--boot-image=")).data();
boot_image_option.clear();
boot_image_option += "-Xbootimage:";
boot_image_option += boot_image_filename;
+ } else if (option.starts_with("--boot-oat=")) {
+ const char* boot_oat_filename = option.substr(strlen("--boot-oat=")).data();
+ boot_oat_option.clear();
+ boot_oat_option += "-Xbootoat:";
+ boot_oat_option += boot_oat_filename;
} else if (option.starts_with("--boot-dex-file=")) {
boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
} else if (option.starts_with("--strip-prefix=")) {
@@ -119,6 +139,11 @@
}
}
+ if (oat_filename == NULL) {
+ fprintf(stderr, "--oat file name not specified\n");
+ return EXIT_FAILURE;
+ }
+
if (image_filename == NULL) {
fprintf(stderr, "--image file name not specified\n");
return EXIT_FAILURE;
@@ -129,6 +154,11 @@
return EXIT_FAILURE;
}
+ if (boot_image_option.empty() != boot_oat_option.empty()) {
+ fprintf(stderr, "--boot-image and --boat-oat must be specified together or not at all\n");
+ return EXIT_FAILURE;
+ }
+
if (boot_image_option.empty()) {
if (image_base == 0) {
fprintf(stderr, "non-zero --base not specified\n");
@@ -136,7 +166,7 @@
}
} else {
if (boot_dex_filenames.empty()) {
- fprintf(stderr, "no --boot-dex-file values specified with --boot\n");
+ fprintf(stderr, "no --boot-dex-file values specified with --boot-image\n");
return EXIT_FAILURE;
}
}
@@ -153,6 +183,7 @@
} else {
options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair(boot_oat_option.c_str(), reinterpret_cast<void*>(NULL)));
}
if (Xms != NULL) {
options.push_back(std::make_pair(Xms, reinterpret_cast<void*>(NULL)));
@@ -167,11 +198,12 @@
}
ClassLinker* class_linker = runtime->GetClassLinker();
- // If we have an existing boot image, position new space after it
+ // If we have an existing boot image, position new space after its oat file
if (!boot_image_option.empty()) {
Space* boot_space = Heap::GetBootSpace();
CHECK(boot_space != NULL);
- image_base = RoundUp(reinterpret_cast<uintptr_t>(boot_space->GetLimit()), kPageSize);
+ byte* oat_limit_addr = boot_space->GetImageHeader().GetOatLimitAddr();
+ image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize);
}
// ClassLoader creation needs to come after Runtime::Create
@@ -185,11 +217,13 @@
class_loader = PathClassLoader::Alloc(dex_files);
}
- // if we loaded an existing image, we will reuse its stub array.
+ // if we loaded an existing image, we will reuse values from the image roots.
if (!runtime->HasJniStubArray()) {
runtime->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
}
- // similarly for the callee save method
+ if (!runtime->HasAbstractMethodErrorStubArray()) {
+ runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
+ }
if (!runtime->HasCalleeSaveMethod()) {
runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2));
}
@@ -239,9 +273,14 @@
}
}
- ImageWriter writer;
- if (!writer.Write(image_filename, image_base)) {
- fprintf(stderr, "could not write image %s\n", image_filename);
+ if (!OatWriter::Create(oat_filename, class_loader)) {
+ fprintf(stderr, "Failed to create oat file %s\n", oat_filename.c_str());
+ return EXIT_FAILURE;
+ }
+
+ ImageWriter image_writer;
+ if (!image_writer.Write(image_filename, image_base, oat_filename, strip_location_prefix)) {
+ fprintf(stderr, "Failed to create image file %s\n", image_filename);
return EXIT_FAILURE;
}
diff --git a/src/dex_file.cc b/src/dex_file.cc
index c532134..b4cf837 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -71,29 +71,11 @@
}
void DexFile::ChangePermissions(int prot) const {
- closer_->ChangePermissions(prot);
-}
-
-DexFile::Closer::~Closer() {}
-
-DexFile::MmapCloser::MmapCloser(void* addr, size_t length) : addr_(addr), length_(length) {
- CHECK(addr != NULL);
-}
-DexFile::MmapCloser::~MmapCloser() {
- if (munmap(addr_, length_) == -1) {
- PLOG(INFO) << "munmap failed";
- }
-}
-void DexFile::MmapCloser::ChangePermissions(int prot) {
- if (mprotect(addr_, length_, prot) != 0) {
+ if (mprotect(mem_map_->GetAddress(), mem_map_->GetLength(), prot) != 0) {
PLOG(FATAL) << "Failed to change dex file permissions to " << prot;
}
}
-DexFile::PtrCloser::PtrCloser(byte* addr) : addr_(addr) {}
-DexFile::PtrCloser::~PtrCloser() { delete[] addr_; }
-void DexFile::PtrCloser::ChangePermissions(int prot) {}
-
const DexFile* DexFile::OpenFile(const std::string& filename,
const std::string& original_location,
const std::string& strip_location_prefix) {
@@ -116,16 +98,15 @@
return NULL;
}
size_t length = sbuf.st_size;
- void* addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
- if (addr == MAP_FAILED) {
- PLOG(ERROR) << "mmap \"" << filename << "\" failed";
+ UniquePtr<MemMap> map(MemMap::Map(length, PROT_READ, MAP_PRIVATE, fd, 0));
+ if (map.get() == NULL) {
+ LOG(ERROR) << "mmap \"" << filename << "\" failed";
close(fd);
return NULL;
}
close(fd);
- byte* dex_file = reinterpret_cast<byte*>(addr);
- Closer* closer = new MmapCloser(addr, length);
- return Open(dex_file, length, location.ToString(), closer);
+ byte* dex_file = map->GetAddress();
+ return Open(dex_file, length, location.ToString(), map.release());
}
static const char* kClassesDex = "classes.dex";
@@ -368,15 +349,9 @@
// NOTREACHED
}
-const DexFile* DexFile::OpenPtr(byte* ptr, size_t length, const std::string& location) {
- CHECK(ptr != NULL);
- DexFile::Closer* closer = new PtrCloser(ptr);
- return Open(ptr, length, location, closer);
-}
-
const DexFile* DexFile::Open(const byte* dex_bytes, size_t length,
- const std::string& location, Closer* closer) {
- UniquePtr<DexFile> dex_file(new DexFile(dex_bytes, length, location, closer));
+ const std::string& location, MemMap* mem_map) {
+ UniquePtr<DexFile> dex_file(new DexFile(dex_bytes, length, location, mem_map));
if (!dex_file->Init()) {
return NULL;
} else {
@@ -475,17 +450,25 @@
for (size_t i = 0; i < NumClassDefs(); ++i) {
const ClassDef& class_def = GetClassDef(i);
const char* descriptor = GetClassDescriptor(class_def);
- index_[descriptor] = &class_def;
+ index_[descriptor] = i;
}
}
-const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) const {
+bool DexFile::FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const {
Index::const_iterator it = index_.find(descriptor);
if (it == index_.end()) {
- return NULL;
- } else {
- return it->second;
+ return false;
}
+ idx = it->second;
+ return true;
+}
+
+const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) const {
+ uint32_t idx;
+ if (FindClassDefIndex(descriptor, idx)) {
+ return &GetClassDef(idx);
+ }
+ return NULL;
}
// Materializes the method descriptor for a method prototype. Method
diff --git a/src/dex_file.h b/src/dex_file.h
index 4ad701f..cb979ae 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -12,6 +12,7 @@
#include "jni.h"
#include "leb128.h"
#include "logging.h"
+#include "mem_map.h"
#include "mutex.h"
#include "stringpiece.h"
#include "strutil.h"
@@ -336,13 +337,6 @@
static const DexFile* OpenZip(const std::string& filename,
const std::string& strip_location_prefix);
- // Opens a .dex file from a new allocated pointer. location is used
- // to identify the source, for example "/system/framework/core.jar"
- // or "contrived-test-42". When initializing a ClassLinker from an
- // image, the location is used to match DexCaches the image to their
- // corresponding DexFiles.N
- static const DexFile* OpenPtr(byte* ptr, size_t length, const std::string& location);
-
// Closes a .dex file.
virtual ~DexFile();
@@ -359,6 +353,9 @@
return *header_;
}
+ // Looks up a class definition index by its class descriptor.
+ bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const;
+
// Looks up a class definition by its class descriptor.
const ClassDef* FindClassDef(const StringPiece& descriptor) const;
@@ -841,45 +838,17 @@
void ChangePermissions(int prot) const;
private:
- // Helper class to deallocate underlying storage.
- class Closer {
- public:
- virtual ~Closer();
- virtual void ChangePermissions(int prot) = 0;
- };
-
- // Helper class to deallocate mmap-backed .dex files.
- class MmapCloser : public Closer {
- public:
- MmapCloser(void* addr, size_t length);
- virtual ~MmapCloser();
- virtual void ChangePermissions(int prot);
- private:
- void* addr_;
- size_t length_;
- };
-
- // Helper class for deallocating new/delete-backed .dex files.
- class PtrCloser : public Closer {
- public:
- PtrCloser(byte* addr);
- virtual ~PtrCloser();
- virtual void ChangePermissions(int prot);
- private:
- byte* addr_;
- };
-
// Opens a .dex file at the given address.
static const DexFile* Open(const byte* dex_file,
size_t length,
const std::string& location,
- Closer* closer);
+ MemMap* mem_map);
- DexFile(const byte* addr, size_t length, const std::string& location, Closer* closer)
+ DexFile(const byte* addr, size_t length, const std::string& location, MemMap* mem_map)
: base_(addr),
length_(length),
location_(location),
- closer_(closer),
+ mem_map_(mem_map),
dex_object_lock_("a dex_object_lock_"),
dex_object_(NULL),
header_(0),
@@ -891,7 +860,7 @@
class_defs_(0) {
CHECK(addr != NULL);
CHECK_GT(length, 0U);
- CHECK(closer != NULL);
+ CHECK(mem_map != NULL);
}
// Top-level initializer that calls other Init methods.
@@ -909,8 +878,8 @@
// Returns true if the header magic is of the expected value.
bool IsMagicValid();
- // The index of descriptors to class definitions.
- typedef std::map<const StringPiece, const DexFile::ClassDef*> Index;
+ // The index of descriptors to class definition indexes.
+ typedef std::map<const StringPiece, uint32_t> Index;
Index index_;
// The base address of the memory mapping.
@@ -925,8 +894,8 @@
// path to DexCache::GetLocation when loading from an image.
const std::string location_;
- // Helper object to free the underlying allocation.
- UniquePtr<Closer> closer_;
+ // Manages the underlying memory allocation.
+ UniquePtr<MemMap> mem_map_;
// A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject.
mutable Mutex dex_object_lock_;
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index 4271d0c..ad3b17b 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -2,8 +2,6 @@
#include "dex_file.h"
-#include <stdio.h>
-
#include "UniquePtr.h"
#include "common_test.h"
@@ -43,7 +41,8 @@
"AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
TEST_F(DexFileTest, Header) {
- UniquePtr<const DexFile> raw(OpenDexFileBase64(kRawDex, "kRawDex"));
+ ScratchFile tmp;
+ UniquePtr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename()));
ASSERT_TRUE(raw.get() != NULL);
const DexFile::Header& header = raw->GetHeader();
diff --git a/src/exception_test.cc b/src/exception_test.cc
index ee6c1a0d..7acc584 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -14,83 +14,40 @@
namespace art {
-// package java.lang;
-// import java.io.IOException;
-// class Object {};
-// public class MyClass {
-// int f() throws Exception {
-// try {
-// g(1);
-// } catch (IOException e) {
-// return 1;
-// } catch (Exception e) {
-// return 2;
-// }
-// try {
-// g(2);
-// } catch (IOException e) {
-// return 3;
-// }
-// return 0;
-// }
-// void g(int doThrow) throws Exception {
-// if (doThrow == 1)
-// throw new Exception();
-// else if (doThrow == 2)
-// throw new IOException();
-// }
-// }
-
-static const char kMyClassExceptionHandleDex[] =
- "ZGV4CjAzNQC/bXXtLZJLN1GzLr+ncrvPSl70n8t0yAjgAwAAcAAAAHhWNBIAAAAAAAAAACgDAAAN"
- "AAAAcAAAAAcAAACkAAAAAwAAAMAAAAAAAAAAAAAAAAYAAADkAAAAAgAAABQBAACMAgAAVAEAAD4C"
- "AABGAgAASQIAAGUCAAB8AgAAkwIAAKgCAAC8AgAAygIAAM0CAADRAgAA1AIAANcCAAABAAAAAgAA"
- "AAMAAAAEAAAABQAAAAYAAAAIAAAAAQAAAAAAAAAAAAAACAAAAAYAAAAAAAAACQAAAAYAAAA4AgAA"
- "AgABAAAAAAADAAEAAAAAAAQAAQAAAAAABAAAAAoAAAAEAAIACwAAAAUAAQAAAAAABQAAAAAAAAD/"
- "////AAAAAAcAAAAAAAAACQMAAAAAAAAEAAAAAQAAAAUAAAAAAAAABwAAABgCAAATAwAAAAAAAAEA"
- "AAABAwAAAQABAAAAAADeAgAAAQAAAA4AAAABAAEAAQAAAOMCAAAEAAAAcBAFAAAADgAEAAEAAgAC"
- "AOgCAAAVAAAAEiISERIQbiAEAAMAEiBuIAQAAwASAA8ADQABECj9DQABICj6DQASMCj3AAADAAAA"
- "AwABAAcAAAADAAYAAgICDAMPAQISAAAAAwACAAEAAAD3AgAAEwAAABIQMwIIACIAAwBwEAEAAAAn"
- "ABIgMwIIACIAAgBwEAAAAAAnAA4AAAAAAAAAAAAAAAIAAAAAAAAAAwAAAFQBAAAEAAAAVAEAAAEA"
- "AAAAAAY8aW5pdD4AAUkAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ABVMamF2YS9pby9JT0V4"
- "Y2VwdGlvbjsAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwATTGphdmEvbGFuZy9NeUNsYXNzOwASTGph"
- "dmEvbGFuZy9PYmplY3Q7AAxNeUNsYXNzLmphdmEAAVYAAlZJAAFmAAFnAAV2YWx1ZQADAAcOAAQA"
- "Bw4ABwAHLFFOAnYsLR4tIR4AFQEABw48aTxpAAIBAQwcARgDAAABAAWAgATcAgAAAQICgYAE8AID"
- "AIgDAQDgAwAAAA8AAAAAAAAAAQAAAAAAAAABAAAADQAAAHAAAAACAAAABwAAAKQAAAADAAAAAwAA"
- "AMAAAAAFAAAABgAAAOQAAAAGAAAAAgAAABQBAAADEAAAAQAAAFQBAAABIAAABAAAAFwBAAAGIAAA"
- "AQAAABgCAAABEAAAAQAAADgCAAACIAAADQAAAD4CAAADIAAABAAAAN4CAAAEIAAAAQAAAAEDAAAA"
- "IAAAAgAAAAkDAAAAEAAAAQAAACgDAAA=";
-
class ExceptionTest : public CommonTest {
protected:
virtual void SetUp() {
CommonTest::SetUp();
- dex_.reset(OpenDexFileBase64(kMyClassExceptionHandleDex, "kMyClassExceptionHandleDex"));
- ASSERT_TRUE(dex_.get() != NULL);
- const ClassLoader* class_loader = AllocPathClassLoader(dex_.get());
- ASSERT_TRUE(class_loader != NULL);
- my_klass_ = class_linker_->FindClass("Ljava/lang/MyClass;", class_loader);
+ const ClassLoader* class_loader = LoadDex("ExceptionHandle");
+ my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader);
ASSERT_TRUE(my_klass_ != NULL);
+
+ dex_ = &Runtime::Current()->GetClassLinker()->FindDexFile(my_klass_->GetDexCache());
+
ByteArray* fake_code = ByteArray::Alloc(12);
ASSERT_TRUE(fake_code != NULL);
IntArray* fake_mapping_data = IntArray::Alloc(2);
- ASSERT_TRUE(fake_mapping_data!= NULL);
+ ASSERT_TRUE(fake_mapping_data != NULL);
fake_mapping_data->Set(0, 3); // offset 3
fake_mapping_data->Set(1, 3); // maps to dex offset 3
+
method_f_ = my_klass_->FindVirtualMethod("f", "()I");
ASSERT_TRUE(method_f_ != NULL);
method_f_->SetFrameSizeInBytes(kStackAlignment);
method_f_->SetReturnPcOffsetInBytes(kStackAlignment-kPointerSize);
- method_f_->SetCode(fake_code, kThumb2, fake_mapping_data);
+ method_f_->SetCodeArray(fake_code, kThumb2);
+ method_f_->SetMappingTable(fake_mapping_data);
+
method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
ASSERT_TRUE(method_g_ != NULL);
method_g_->SetFrameSizeInBytes(kStackAlignment);
method_g_->SetReturnPcOffsetInBytes(kStackAlignment-kPointerSize);
- method_g_->SetCode(fake_code, kThumb2, fake_mapping_data);
+ method_g_->SetCodeArray(fake_code, kThumb2);
+ method_g_->SetMappingTable(fake_mapping_data);
}
- UniquePtr<const DexFile> dex_;
+ const DexFile* dex_;
Method* method_f_;
Method* method_g_;
@@ -100,7 +57,7 @@
};
TEST_F(ExceptionTest, FindCatchHandler) {
- const DexFile::CodeItem *code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset());
+ const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset());
ASSERT_TRUE(code_item != NULL);
@@ -167,16 +124,16 @@
Decode<ObjectArray<StackTraceElement>*>(env, ste_array);
ASSERT_TRUE(trace_array->Get(0) != NULL);
- EXPECT_STREQ("java.lang.MyClass",
+ EXPECT_STREQ("ExceptionHandle",
trace_array->Get(0)->GetDeclaringClass()->ToModifiedUtf8().c_str());
- EXPECT_STREQ("MyClass.java", trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str());
+ EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(0)->GetFileName()->ToModifiedUtf8().c_str());
EXPECT_STREQ("g", trace_array->Get(0)->GetMethodName()->ToModifiedUtf8().c_str());
EXPECT_EQ(22, trace_array->Get(0)->GetLineNumber());
ASSERT_TRUE(trace_array->Get(1) != NULL);
- EXPECT_STREQ("java.lang.MyClass",
+ EXPECT_STREQ("ExceptionHandle",
trace_array->Get(1)->GetDeclaringClass()->ToModifiedUtf8().c_str());
- EXPECT_STREQ("MyClass.java", trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str());
+ EXPECT_STREQ("ExceptionHandle.java", trace_array->Get(1)->GetFileName()->ToModifiedUtf8().c_str());
EXPECT_STREQ("f", trace_array->Get(1)->GetMethodName()->ToModifiedUtf8().c_str());
EXPECT_EQ(7, trace_array->Get(1)->GetLineNumber());
}
diff --git a/src/globals.h b/src/globals.h
index 2fb0225..e5fead6 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -38,6 +38,9 @@
// Required object alignment
const int kObjectAlignment = 8;
+// Required ARM instruction alignment
+const int kArmAlignment = 4;
+
// System page size. Normally you're expected to get this from
// sysconf(_SC_PAGESIZE) or some system-specific define (usually
// PAGESIZE or PAGE_SIZE). If we use a simple compile-time constant
diff --git a/src/heap.cc b/src/heap.cc
index 015f638..2051051 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -74,7 +74,9 @@
LOG(FATAL) << "Failed to create space from " << boot_image_file_name;
}
spaces_.push_back(boot_space);
- requested_base = boot_space->GetBase() + RoundUp(boot_space->Size(), kPageSize);
+ byte* oat_limit_addr = boot_space->GetImageHeader().GetOatLimitAddr();
+ requested_base = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr),
+ kPageSize));
}
std::vector<Space*> image_spaces;
@@ -85,7 +87,9 @@
}
image_spaces.push_back(space);
spaces_.push_back(space);
- requested_base = space->GetBase() + RoundUp(space->Size(), kPageSize);
+ byte* oat_limit_addr = space->GetImageHeader().GetOatLimitAddr();
+ requested_base = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr),
+ kPageSize));
}
Space* space = Space::Create(initial_size, maximum_size, requested_base);
diff --git a/src/image.cc b/src/image.cc
index 5bf7b10..c610c8a 100644
--- a/src/image.cc
+++ b/src/image.cc
@@ -4,7 +4,7 @@
namespace art {
-const byte ImageHeader::kImageMagic[] = { 'o', 'a', 't', '\n' };
+const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
const byte ImageHeader::kImageVersion[] = { '0', '0', '1', '\0' };
} // namespace art
diff --git a/src/image.h b/src/image.h
index fdf6443..3d2f5f4 100644
--- a/src/image.h
+++ b/src/image.h
@@ -11,12 +11,25 @@
namespace art {
// header of image files written by ImageWriter, read and validated by Space.
-class ImageHeader {
+class PACKED ImageHeader {
public:
ImageHeader() {}
- ImageHeader(uint32_t base_addr, uint32_t image_roots)
- : base_addr_(base_addr), image_roots_(image_roots) {
+ ImageHeader(uint32_t image_base_addr,
+ uint32_t image_roots,
+ uint32_t oat_checksum,
+ uint32_t oat_base_addr,
+ uint32_t oat_limit_addr)
+ : image_base_addr_(image_base_addr),
+ oat_checksum_(oat_checksum),
+ oat_base_addr_(oat_base_addr),
+ oat_limit_addr_(oat_limit_addr),
+ image_roots_(image_roots) {
+ CHECK_EQ(image_base_addr, RoundUp(image_base_addr, kPageSize));
+ CHECK_EQ(oat_base_addr, RoundUp(oat_base_addr, kPageSize));
+ CHECK_LT(image_base_addr, image_roots);
+ CHECK_LT(image_roots, oat_base_addr);
+ CHECK_LT(oat_base_addr, oat_limit_addr);
memcpy(magic_, kImageMagic, sizeof(kImageMagic));
memcpy(version_, kImageVersion, sizeof(kImageVersion));
}
@@ -36,13 +49,27 @@
return reinterpret_cast<const char*>(magic_);
}
- byte* GetBaseAddr() const {
- return reinterpret_cast<byte*>(base_addr_);
+ byte* GetImageBaseAddr() const {
+ return reinterpret_cast<byte*>(image_base_addr_);
+ }
+
+ uint32_t GetOatChecksum() const {
+ return oat_checksum_;
+ }
+
+ byte* GetOatBaseAddr() const {
+ return reinterpret_cast<byte*>(oat_base_addr_);
+ }
+
+ byte* GetOatLimitAddr() const {
+ return reinterpret_cast<byte*>(oat_limit_addr_);
}
enum ImageRoot {
kJniStubArray,
+ kAbstractMethodErrorStubArray,
kCalleeSaveMethod,
+ kOatLocation,
kImageRootsMax,
};
@@ -58,7 +85,16 @@
byte version_[4];
// required base address for mapping the image.
- uint32_t base_addr_;
+ uint32_t image_base_addr_;
+
+ // checksum of the oat file we link to for load time sanity check
+ uint32_t oat_checksum_;
+
+ // required oat address expected by image Method::GetCode() pointers.
+ uint32_t oat_base_addr_;
+
+ // end of oat address range for this image file, used for positioning a following image
+ uint32_t oat_limit_addr_;
// absolute address of an Object[] of objects needed to reinitialize from an image
uint32_t image_roots_;
diff --git a/src/image_test.cc b/src/image_test.cc
index 7ecdf3c..2fd5c34 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -7,6 +7,7 @@
#include "file.h"
#include "image.h"
#include "image_writer.h"
+#include "oat_writer.h"
#include "signal_catcher.h"
#include "space.h"
#include "utils.h"
@@ -16,22 +17,19 @@
class ImageTest : public CommonTest {};
TEST_F(ImageTest, WriteRead) {
- // TODO: remove the touching of classes, call Compiler instead
- for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) {
- const DexFile::ClassDef& class_def = java_lang_dex_file_->GetClassDef(i);
- const char* descriptor = java_lang_dex_file_->GetClassDescriptor(class_def);
- Class* klass = class_linker_->FindSystemClass(descriptor);
- ASSERT_TRUE(klass != NULL) << descriptor;
- }
+ ScratchFile tmp_oat;
+ bool success_oat = OatWriter::Create(tmp_oat.GetFilename(), NULL);
+ ASSERT_TRUE(success_oat);
ImageWriter writer;
- ScratchFile tmp;
+ ScratchFile tmp_image;
const uintptr_t image_base = 0x50000000;
- bool success = writer.Write(tmp.GetFilename(), image_base);
- ASSERT_TRUE(success);
+ bool success_image = writer.Write(tmp_image.GetFilename(), image_base,
+ std::string(tmp_oat.GetFilename()), "");
+ ASSERT_TRUE(success_image);
{
- UniquePtr<File> file(OS::OpenFile(tmp.GetFilename(), false));
+ UniquePtr<File> file(OS::OpenFile(tmp_image.GetFilename(), false));
ASSERT_TRUE(file.get() != NULL);
ImageHeader image_header;
file->ReadFully(&image_header, sizeof(image_header));
@@ -58,8 +56,11 @@
Runtime::Options options;
options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+ std::string boot_oat("-Xbootoat:");
+ boot_oat.append(tmp_oat.GetFilename());
+ options.push_back(std::make_pair(boot_oat.c_str(), reinterpret_cast<void*>(NULL)));
std::string boot_image("-Xbootimage:");
- boot_image.append(tmp.GetFilename());
+ boot_image.append(tmp_image.GetFilename());
options.push_back(std::make_pair(boot_image.c_str(), reinterpret_cast<void*>(NULL)));
runtime_.reset(Runtime::Create(options, false));
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 23bc6cf..37eac2e 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -23,7 +23,8 @@
namespace art {
-bool ImageWriter::Write(const char* filename, uintptr_t image_base) {
+bool ImageWriter::Write(const char* image_filename, uintptr_t image_base,
+ const std::string& oat_filename, const std::string& strip_location_prefix) {
CHECK_NE(image_base, 0U);
image_base_ = reinterpret_cast<byte*>(image_base);
@@ -32,6 +33,12 @@
CHECK_GE(spaces.size(), 1U);
source_space_ = spaces[spaces.size()-1];
+ oat_file_.reset(OatFile::Open(oat_filename, strip_location_prefix, NULL));
+ if (oat_file_.get() == NULL) {
+ LOG(ERROR) << "Failed to open oat file " << oat_filename;
+ return false;
+ }
+
if (!Init()) {
return false;
}
@@ -39,11 +46,17 @@
CalculateNewObjectOffsets();
CopyAndFixupObjects();
- UniquePtr<File> file(OS::OpenFile(filename, true));
+ UniquePtr<File> file(OS::OpenFile(image_filename, true));
if (file.get() == NULL) {
+ LOG(ERROR) << "Failed to open image file " << image_filename;
return false;
}
- return file->WriteFully(image_->GetAddress(), image_top_);
+ bool success = file->WriteFully(image_->GetAddress(), image_top_);
+ if (!success) {
+ PLOG(ERROR) << "Failed to write image file " << image_filename;
+ return false;
+ }
+ return true;
}
bool ImageWriter::Init() {
@@ -52,6 +65,7 @@
size_t length = RoundUp(size, kPageSize);
image_.reset(MemMap::Map(length, prot));
if (image_.get() == NULL) {
+ LOG(ERROR) << "Failed to allocate memory for image file generation";
return false;
}
return true;
@@ -94,20 +108,29 @@
if (dex_cache != NULL) {
image_writer->dex_caches_.insert(dex_cache);
} else {
- DCHECK(klass->IsArrayClass() || klass->IsPrimitive());
+ DCHECK(klass->IsArrayClass() || klass->IsPrimitive()) << PrettyClass(klass);
}
}
}
-ObjectArray<Object>* CreateImageRoots() {
+ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
// build a Object[] of the roots needed to restore the runtime
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
ObjectArray<Object>* image_roots = ObjectArray<Object>::Alloc(object_array_class,
ImageHeader::kImageRootsMax);
- image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniStubArray());
- image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod());
+ image_roots->Set(ImageHeader::kJniStubArray,
+ runtime->GetJniStubArray());
+ image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray,
+ runtime->GetAbstractMethodErrorStubArray());
+ image_roots->Set(ImageHeader::kCalleeSaveMethod,
+ runtime->GetCalleeSaveMethod());
+ image_roots->Set(ImageHeader::kOatLocation,
+ String::AllocFromModifiedUtf8(oat_file_->GetLocation().c_str()));
+ for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
+ CHECK(image_roots->Get(i) != NULL);
+ }
return image_roots;
}
@@ -125,12 +148,17 @@
heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this); // TODO: add Space-limited Walk
DCHECK_LT(image_top_, image_->GetLength());
+ // Note that image_top_ is left at end of used space
+ oat_base_ = image_base_ + RoundUp(image_top_, kPageSize);
+ byte* oat_limit = oat_base_ + oat_file_->GetSize();
+
// return to write header at start of image with future location of image_roots
ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_),
- reinterpret_cast<uint32_t>(GetImageAddress(image_roots)));
+ reinterpret_cast<uint32_t>(GetImageAddress(image_roots)),
+ oat_file_->GetOatHeader().GetChecksum(),
+ reinterpret_cast<uint32_t>(oat_base_),
+ reinterpret_cast<uint32_t>(oat_limit));
memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
-
- // Note that top_ is left at end of used space
}
void ImageWriter::CopyAndFixupObjects() {
@@ -199,14 +227,30 @@
void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
FixupInstanceFields(orig, copy);
- copy->code_ = FixupCode(copy->code_array_, orig->code_);
+
+ // OatWriter clears the code_array_ after writing the code.
+ // It replaces the code_ with an offset value we now adjust to be a pointer.
+ DCHECK(copy->code_array_ == NULL)
+ << PrettyMethod(orig)
+ << " orig_code_array_=" << orig->GetCodeArray() << " orig_code_=" << orig->GetCode()
+ << " copy_code_array_=" << copy->code_array_ << " orig_code_=" << copy->code_
+ << " jni_stub=" << Runtime::Current()->GetJniStubArray()
+ << " ame_stub=" << Runtime::Current()->GetAbstractMethodErrorStubArray();
copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_)));
if (orig->IsNative()) {
ByteArray* orig_jni_stub_array_ = Runtime::Current()->GetJniStubArray();
ByteArray* copy_jni_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_jni_stub_array_));
copy->native_method_ = copy_jni_stub_array_->GetData();
+ copy->code_ = oat_base_ + orig->GetOatCodeOffset();
} else {
- DCHECK(copy->native_method_ == NULL);
+ DCHECK(copy->native_method_ == NULL) << copy->native_method_;
+ if (orig->IsAbstract()) {
+ ByteArray* orig_ame_stub_array_ = Runtime::Current()->GetAbstractMethodErrorStubArray();
+ ByteArray* copy_ame_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_ame_stub_array_));
+ copy->code_ = copy_ame_stub_array_->GetData();
+ } else {
+ copy->code_ = oat_base_ + orig->GetOatCodeOffset();
+ }
}
}
diff --git a/src/image_writer.h b/src/image_writer.h
index c1480ff..8c4b308 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -10,6 +10,7 @@
#include "UniquePtr.h"
#include "dex_cache.h"
#include "mem_map.h"
+#include "oat_file.h"
#include "object.h"
#include "os.h"
#include "space.h"
@@ -21,7 +22,8 @@
public:
ImageWriter() : source_space_(NULL), image_top_(0), image_base_(NULL) {};
- bool Write(const char* filename, uintptr_t image_base);
+ bool Write(const char* image_filename, uintptr_t image_base,
+ const std::string& oat_filename, const std::string& strip_location_prefix);
~ImageWriter() {};
private:
@@ -82,6 +84,7 @@
}
void CalculateNewObjectOffsets();
+ ObjectArray<Object>* CreateImageRoots() const;
static void CalculateNewObjectOffsetsCallback(Object* obj, void* arg);
void CopyAndFixupObjects();
@@ -97,6 +100,9 @@
void FixupDexCaches();
void FixupDexCache(const DexCache* orig, DexCache* copy);
+ // oat file with code for this image
+ UniquePtr<OatFile> oat_file_;
+
// Space we are writing objects from
const Space* source_space_;
@@ -106,9 +112,12 @@
// Offset to the free space in image_
size_t image_top_;
- // Target base address for the output image
+ // Target image base address for the output image
byte* image_base_;
+ // Target oat base address for the pointers from the output image to its oat file
+ byte* oat_base_;
+
// DexCaches seen while scanning for fixing up CodeAndDirectMethods
typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
Set dex_caches_;
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index 6c09f58..c8cfc66 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -430,7 +430,7 @@
CHECK(managed_code != NULL);
MemoryRegion code(managed_code->GetData(), managed_code->GetLength());
__ FinalizeInstructions(code);
- native_method->SetCode(managed_code, instruction_set_);
+ native_method->SetCodeArray(managed_code, instruction_set_);
native_method->SetFrameSizeInBytes(frame_size);
native_method->SetReturnPcOffsetInBytes(jni_conv->ReturnPcOffset());
native_method->SetCoreSpillMask(jni_conv->CoreSpillMask());
diff --git a/src/mem_map.cc b/src/mem_map.cc
index e44a894..2bd7bd0 100644
--- a/src/mem_map.cc
+++ b/src/mem_map.cc
@@ -87,9 +87,9 @@
std::string end_str = maps.substr(i+1+8, 8);
uint32_t start = ParseHex(start_str);
uint32_t end = ParseHex(end_str);
- CHECK(!(base >= start && base < end)
- && !(limit >= start && limit < end)
- && !(base <= start && limit > end))
+ CHECK(!(base >= start && base < end) // start of new within old
+ && !(limit > start && limit < end) // end of new within old
+ && !(base <= start && limit > end)) // start/end of new includes all of old
<< StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n",
base, limit, start, end)
<< maps;
diff --git a/src/oat.cc b/src/oat.cc
new file mode 100644
index 0000000..191f26f
--- /dev/null
+++ b/src/oat.cc
@@ -0,0 +1,68 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "oat.h"
+
+#include <zlib.h>
+
+namespace art {
+
+const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '0', '1', '\0' };
+
+OatHeader::OatHeader(const std::vector<const DexFile*>* dex_files) {
+ memcpy(magic_, kOatMagic, sizeof(kOatMagic));
+ memcpy(version_, kOatVersion, sizeof(kOatVersion));
+ adler32_checksum_ = adler32(0L, Z_NULL, 0);
+ dex_file_count_ = dex_files->size();
+ UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
+ executable_offset_ = 0;
+}
+
+bool OatHeader::IsValid() const {
+ if (memcmp(magic_, kOatMagic, sizeof(kOatMagic) != 0)) {
+ return false;
+ }
+ if (memcmp(version_, kOatVersion, sizeof(kOatVersion) != 0)) {
+ return false;
+ }
+ return true;
+}
+
+const char* OatHeader::GetMagic() const {
+ CHECK(IsValid());
+ return reinterpret_cast<const char*>(magic_);
+}
+
+uint32_t OatHeader::GetDexFileCount() const {
+ DCHECK(IsValid());
+ return dex_file_count_;
+}
+
+uint32_t OatHeader::GetChecksum() const {
+ CHECK(IsValid());
+ return adler32_checksum_;
+}
+
+void OatHeader::UpdateChecksum(const void* data, size_t length) {
+ DCHECK(IsValid());
+ const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
+ adler32_checksum_ = adler32(adler32_checksum_, bytes, length);
+}
+
+uint32_t OatHeader::GetExecutableOffset() const {
+ DCHECK(IsValid());
+ DCHECK(IsAligned(executable_offset_, kPageSize));
+ CHECK_GT(executable_offset_, sizeof(OatHeader));
+ return executable_offset_;
+}
+
+void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
+ DCHECK(IsAligned(executable_offset, kPageSize));
+ CHECK_GT(executable_offset, sizeof(OatHeader));
+ DCHECK(IsValid());
+ DCHECK_EQ(executable_offset_, 0U);
+ executable_offset_ = executable_offset;
+ UpdateChecksum(&executable_offset_, sizeof(executable_offset));
+}
+
+} // namespace art
diff --git a/src/oat.h b/src/oat.h
new file mode 100644
index 0000000..ca3e9e0
--- /dev/null
+++ b/src/oat.h
@@ -0,0 +1,41 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_OAT_H_
+#define ART_SRC_OAT_H_
+
+#include <vector>
+
+#include "dex_file.h"
+#include "macros.h"
+
+namespace art {
+
+class PACKED OatHeader {
+ public:
+ OatHeader() {}
+ OatHeader(const std::vector<const DexFile*>* dex_files);
+
+ bool IsValid() const;
+ const char* GetMagic() const;
+ uint32_t GetChecksum() const;
+ void UpdateChecksum(const void* data, size_t length);
+ uint32_t GetDexFileCount() const;
+ uint32_t GetExecutableOffset() const;
+ void SetExecutableOffset(uint32_t executable_offset);
+
+ private:
+ static const uint8_t kOatMagic[4];
+ static const uint8_t kOatVersion[4];
+
+ uint8_t magic_[4];
+ uint8_t version_[4];
+ uint32_t adler32_checksum_;
+ uint32_t dex_file_count_;
+ uint32_t executable_offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(OatHeader);
+};
+
+} // namespace art
+
+#endif // ART_SRC_OAT_H_
diff --git a/src/oat_file.cc b/src/oat_file.cc
new file mode 100644
index 0000000..6266494
--- /dev/null
+++ b/src/oat_file.cc
@@ -0,0 +1,167 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "oat_file.h"
+
+#include <sys/mman.h>
+
+#include "file.h"
+#include "os.h"
+#include "stl_util.h"
+
+namespace art {
+
+OatFile* OatFile::Open(const std::string& filename,
+ const std::string& strip_location_prefix,
+ byte* requested_base) {
+ StringPiece location = filename;
+ if (!location.starts_with(strip_location_prefix)) {
+ LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
+ return NULL;
+ }
+ location.remove_prefix(strip_location_prefix.size());
+
+ UniquePtr<OatFile> oat_file(new OatFile(location.ToString()));
+ bool success = oat_file->Read(filename, requested_base);
+ if (!success) {
+ return NULL;
+ }
+ return oat_file.release();
+}
+
+OatFile::OatFile(const std::string& filename) : location_(filename) {}
+
+OatFile::~OatFile() {
+ STLDeleteValues(&oat_dex_files_);
+}
+
+bool OatFile::Read(const std::string& filename, byte* requested_base) {
+ UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
+ if (file.get() == NULL) {
+ return false;
+ }
+
+ OatHeader oat_header;
+ bool success = file->ReadFully(&oat_header, sizeof(oat_header));
+ if (!success || !oat_header.IsValid()) {
+ LOG(WARNING) << "Invalid oat header " << filename;
+ return false;
+ }
+
+ UniquePtr<MemMap> map(MemMap::Map(requested_base,
+ file->Length(),
+ PROT_READ,
+ MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0),
+ file->Fd(),
+ 0));
+ if (map.get() == NULL) {
+ LOG(WARNING) << "Failed to map oat file " << filename;
+ return false;
+ }
+ CHECK(requested_base == 0 || requested_base == map->GetAddress()) << map->GetAddress();
+ DCHECK_EQ(0, memcmp(&oat_header, map->GetAddress(), sizeof(OatHeader)));
+
+ off_t code_offset = oat_header.GetExecutableOffset();
+ if (code_offset < file->Length()) {
+ byte* code_address = map->GetAddress() + code_offset;
+ size_t code_length = file->Length() - code_offset;
+ if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
+ PLOG(ERROR) << "Failed to make oat code executable.";
+ return false;
+ }
+ } else {
+ // its possible to have no code if all the methods were abstract, native, etc
+ DCHECK_EQ(code_offset, RoundUp(file->Length(), kPageSize));
+ }
+
+ const byte* oat = map->GetAddress();
+ oat += sizeof(OatHeader);
+ CHECK_LT(oat, map->GetLimit());
+ for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) {
+ size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
+ oat += sizeof(dex_file_location_size);
+ CHECK_LT(oat, map->GetLimit());
+
+ const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
+ oat += dex_file_location_size;
+ CHECK_LT(oat, map->GetLimit());
+
+ std::string dex_file_location(dex_file_location_data, dex_file_location_size);
+
+ uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
+ oat += sizeof(dex_file_checksum);
+ CHECK_LT(oat, map->GetLimit());
+
+ uint32_t classes_offset = *reinterpret_cast<const uint32_t*>(oat);
+ CHECK_GT(classes_offset, 0U);
+ CHECK_LT(classes_offset, static_cast<uint32_t>(file->Length()));
+ oat += sizeof(classes_offset);
+ CHECK_LT(oat, map->GetLimit());
+
+ uint32_t* classes_pointer = reinterpret_cast<uint32_t*>(map->GetAddress() + classes_offset);
+
+ oat_dex_files_[dex_file_location] = new OatDexFile(this,
+ dex_file_location,
+ dex_file_checksum,
+ classes_pointer);
+ }
+
+ mem_map_.reset(map.release());
+ return true;
+}
+
+const OatHeader& OatFile::GetOatHeader() const {
+ return *reinterpret_cast<const OatHeader*>(GetBase());
+}
+
+const byte* OatFile::GetBase() const {
+ CHECK(mem_map_->GetAddress() != NULL);
+ return mem_map_->GetAddress();
+}
+
+const byte* OatFile::GetLimit() const {
+ CHECK(mem_map_->GetLimit() != NULL);
+ return mem_map_->GetLimit();
+}
+
+const OatFile::OatDexFile& OatFile::GetOatDexFile(const DexFile& dex_file) {
+ Table::const_iterator it = oat_dex_files_.find(dex_file.GetLocation());
+ if (it == oat_dex_files_.end()) {
+ LOG(FATAL) << "Failed to find OatDexFile for DexFile " << dex_file.GetLocation();
+ }
+ return *it->second;
+}
+
+OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
+ std::string dex_file_location,
+ uint32_t dex_file_checksum,
+ uint32_t* classes_pointer)
+ : oat_file_(oat_file),
+ dex_file_location_(dex_file_location),
+ dex_file_checksum_(dex_file_checksum),
+ classes_pointer_(classes_pointer) {}
+
+OatFile::OatDexFile::~OatDexFile() {}
+
+const OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
+ uint32_t methods_offset = classes_pointer_[class_def_index];
+ const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
+ CHECK_LT(methods_pointer, oat_file_->GetLimit());
+ return OatClass(oat_file_, reinterpret_cast<const uint32_t*>(methods_pointer));
+}
+
+OatFile::OatClass::OatClass(const OatFile* oat_file, const uint32_t* methods_pointer)
+ : oat_file_(oat_file), methods_pointer_(methods_pointer) {}
+
+OatFile::OatClass::~OatClass() {}
+
+const void* OatFile::OatClass::GetMethodCode(uint32_t method_index) const {
+ uint32_t code_offset = methods_pointer_[method_index];
+ if (code_offset == 0) {
+ return NULL;
+ }
+ const void* code_pointer = reinterpret_cast<const void*>(oat_file_->GetBase() + code_offset);
+ CHECK_LT(code_pointer, oat_file_->GetLimit());
+ return code_pointer;
+}
+
+} // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
new file mode 100644
index 0000000..2528a6c
--- /dev/null
+++ b/src/oat_file.h
@@ -0,0 +1,101 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_OAT_FILE_H_
+#define ART_SRC_OAT_FILE_H_
+
+#include <vector>
+
+#include "dex_file.h"
+#include "mem_map.h"
+#include "oat.h"
+
+namespace art {
+
+class OatFile {
+ public:
+
+ // Open an oat file. Returns NULL on failure. Requested base can
+ // optionally be used to request where the file should be loaded.
+ static OatFile* Open(const std::string& filename,
+ const std::string& strip_location_prefix,
+ byte* requested_base);
+
+ ~OatFile();
+
+ const std::string& GetLocation() const {
+ return location_;
+ }
+
+ const OatHeader& GetOatHeader() const;
+
+ class OatDexFile;
+
+ class OatClass {
+ public:
+ // get the code for the method based on its index into the class
+ // defintion. direct methods come first, followed by virtual
+ // methods. note that runtime created methods such as miranda
+ // methods are not included.
+ const void* GetMethodCode(uint32_t method_index) const;
+ ~OatClass();
+
+ private:
+ OatClass(const OatFile* oat_file, const uint32_t* methods_pointer);
+
+ const OatFile* oat_file_;
+ const uint32_t* methods_pointer_;
+
+ friend class OatDexFile;
+ };
+
+ class OatDexFile {
+ public:
+ const OatClass GetOatClass(uint32_t class_def_index) const;
+ ~OatDexFile();
+ private:
+ OatDexFile(const OatFile* oat_file,
+ std::string dex_file_location,
+ uint32_t dex_file_checksum,
+ uint32_t* classes_pointer);
+
+ const OatFile* oat_file_;
+ std::string dex_file_location_;
+ uint32_t dex_file_checksum_;
+ const uint32_t* classes_pointer_;
+
+ friend class OatFile;
+ DISALLOW_COPY_AND_ASSIGN(OatDexFile);
+ };
+
+ const OatDexFile& GetOatDexFile(const DexFile& dex_file);
+
+ size_t GetSize() const {
+ return GetLimit() - GetBase();
+ }
+
+ private:
+ OatFile(const std::string& filename);
+ bool Read(const std::string& filename, byte* requested_base);
+
+ const byte* GetBase() const;
+ const byte* GetLimit() const;
+
+ // The oat file name.
+ //
+ // The image will embed this to link its associated oat file.
+ const std::string location_;
+
+ // backing memory map for oat file
+ UniquePtr<MemMap> mem_map_;
+
+ typedef std::map<std::string, const OatDexFile*> Table;
+ Table oat_dex_files_;
+
+ friend class OatClass;
+ friend class OatDexFile;
+ DISALLOW_COPY_AND_ASSIGN(OatFile);
+};
+
+} // namespace art
+
+#endif // ART_SRC_OAT_WRITER_H_
diff --git a/src/oat_test.cc b/src/oat_test.cc
new file mode 100644
index 0000000..b1453b3
--- /dev/null
+++ b/src/oat_test.cc
@@ -0,0 +1,79 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "oat_file.h"
+#include "oat_writer.h"
+
+#include "common_test.h"
+
+namespace art {
+
+class OatTest : public CommonTest {};
+
+TEST_F(OatTest, WriteRead) {
+ const bool compile = false; // DISABLED_ due to the time to compile libcore
+
+ const ClassLoader* class_loader = NULL;
+ if (compile) {
+ compiler_->CompileAll(class_loader);
+ }
+
+ ScratchFile tmp;
+ bool success = OatWriter::Create(tmp.GetFilename(), class_loader);
+ ASSERT_TRUE(success);
+
+ if (compile) { // OatWriter strips the code, regenerate to compare
+ compiler_->CompileAll(class_loader);
+ }
+ UniquePtr<OatFile> oat_file(OatFile::Open(std::string(tmp.GetFilename()), "", NULL));
+ ASSERT_TRUE(oat_file.get() != NULL);
+ const OatHeader& oat_header = oat_file->GetOatHeader();
+ ASSERT_EQ(1U, oat_header.GetDexFileCount());
+
+ const Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ ByteArray* jni_stub_array = runtime->GetJniStubArray();
+ ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+
+ const DexFile& dex_file = *java_lang_dex_file_.get();
+ const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file);
+ for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
+ const byte* class_data = dex_file.GetClassData(class_def);
+ DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+ size_t num_virtual_methods = header.virtual_methods_size_;
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+
+ const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(i);
+
+ Class* klass = class_linker->FindClass(descriptor, class_loader);
+
+ size_t method_index = 0;
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
+ Method* method = klass->GetDirectMethod(i);
+ const void* oat_code = oat_class.GetMethodCode(method_index);
+ uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
+ oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+ const ByteArray* code_array = method->GetCodeArray();
+ if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
+ ASSERT_TRUE(oat_code == NULL);
+ } else {
+ ASSERT_EQ(0, memcmp(oat_code, code_array->GetData(), code_array->GetLength()));
+ }
+ }
+ for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
+ Method* method = klass->GetVirtualMethod(i);
+ const void* oat_code = oat_class.GetMethodCode(method_index);
+ uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
+ oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+ const ByteArray* code_array = method->GetCodeArray();
+ if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
+ ASSERT_TRUE(oat_code == NULL);
+ } else {
+ ASSERT_TRUE(oat_code != NULL);
+ ASSERT_EQ(0, memcmp(oat_code, code_array->GetData(), code_array->GetLength()));
+ }
+ }
+ }
+}
+
+} // namespace art
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
new file mode 100644
index 0000000..b8232d9
--- /dev/null
+++ b/src/oat_writer.cc
@@ -0,0 +1,438 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "oat_writer.h"
+
+#include "class_linker.h"
+#include "class_loader.h"
+#include "file.h"
+#include "os.h"
+#include "stl_util.h"
+
+namespace art {
+
+bool OatWriter::Create(const std::string& filename, const ClassLoader* class_loader) {
+ const std::vector<const DexFile*>& dex_files = ClassLoader::GetClassPath(class_loader);
+ OatWriter oat_writer(dex_files, class_loader);
+ return oat_writer.Write(filename);
+}
+
+OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader) {
+ class_loader_ = class_loader;
+ dex_files_ = &dex_files;
+
+ size_t offset = InitOatHeader();
+ offset = InitOatDexFiles(offset);
+ offset = InitOatClasses(offset);
+ offset = InitOatMethods(offset);
+ offset = InitOatCode(offset);
+ offset = InitOatCodeDexFiles(offset);
+
+ CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
+ CHECK_EQ(dex_files_->size(), oat_classes_.size());
+}
+
+size_t OatWriter::InitOatHeader() {
+ // create the OatHeader
+ oat_header_ = new OatHeader(dex_files_);
+ size_t offset = sizeof(*oat_header_);
+ return offset;
+}
+
+size_t OatWriter::InitOatDexFiles(size_t offset) {
+ // create the OatDexFiles
+ 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);
+ oat_dex_files_.push_back(oat_dex_file);
+ offset += oat_dex_file->SizeOf();
+ }
+ return offset;
+}
+
+size_t OatWriter::InitOatClasses(size_t offset) {
+ // create the OatClasses
+ // calculate the offsets within OatDexFiles to OatClasses
+ for (size_t i = 0; i != dex_files_->size(); ++i) {
+ // set offset in OatDexFile to OatClasses
+ oat_dex_files_[i]->classes_offset_ = offset;
+ oat_dex_files_[i]->UpdateChecksum(*oat_header_);
+
+ const DexFile* dex_file = (*dex_files_)[i];
+ OatClasses* oat_classes = new OatClasses(*dex_file);
+ oat_classes_.push_back(oat_classes);
+ offset += oat_classes->SizeOf();
+ }
+ return offset;
+}
+
+size_t OatWriter::InitOatMethods(size_t offset) {
+ // create the OatMethods
+ // calculate the offsets within OatClasses to OatMethods
+ size_t class_index = 0;
+ for (size_t i = 0; i != dex_files_->size(); ++i) {
+ const DexFile* dex_file = (*dex_files_)[i];
+ for (size_t class_def_index = 0;
+ class_def_index < dex_file->NumClassDefs();
+ class_def_index++, class_index++) {
+ oat_classes_[i]->methods_offsets_[class_def_index] = offset;
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+ const byte* class_data = dex_file->GetClassData(class_def);
+ DexFile::ClassDataHeader header = dex_file->ReadClassDataHeader(&class_data);
+ size_t num_direct_methods = header.direct_methods_size_;
+ size_t num_virtual_methods = header.virtual_methods_size_;
+ uint32_t num_methods = num_direct_methods + num_virtual_methods;
+ OatMethods* oat_methods = new OatMethods(num_methods);
+ oat_methods_.push_back(oat_methods);
+ offset += oat_methods->SizeOf();
+ }
+ oat_classes_[i]->UpdateChecksum(*oat_header_);
+ }
+ return offset;
+}
+
+size_t OatWriter::InitOatCode(size_t offset) {
+ // calculate the offsets within OatHeader to executable code
+ size_t old_offset = offset;
+ // required to be on a new page boundary
+ offset = RoundUp(offset, kPageSize);
+ oat_header_->SetExecutableOffset(offset);
+ executable_offset_padding_length_ = offset - old_offset;
+ return offset;
+}
+
+size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
+ // calculate the offsets within OatMethods
+ size_t oat_class_index = 0;
+ for (size_t i = 0; i != dex_files_->size(); ++i) {
+ const DexFile* dex_file = (*dex_files_)[i];
+ CHECK(dex_file != NULL);
+ offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
+ }
+ return offset;
+}
+
+size_t OatWriter::InitOatCodeDexFile(size_t offset,
+ size_t& oat_class_index,
+ const DexFile& dex_file) {
+ for (size_t class_def_index = 0;
+ class_def_index < dex_file.NumClassDefs();
+ class_def_index++, oat_class_index++) {
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+ offset = InitOatCodeClassDef(offset, oat_class_index, dex_file, class_def);
+ oat_methods_[oat_class_index]->UpdateChecksum(*oat_header_);
+ }
+ return offset;
+}
+
+size_t OatWriter::InitOatCodeClassDef(size_t offset,
+ size_t oat_class_index,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def) {
+ const byte* class_data = dex_file.GetClassData(class_def);
+ DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+ size_t num_virtual_methods = header.virtual_methods_size_;
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+
+ // TODO: remove code ByteArrays from Class/Method (and therefore ClassLoader)
+ // TODO: don't write code for shared stubs
+ Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, class_loader_);
+ CHECK(klass != NULL) << descriptor;
+ CHECK_EQ(klass->GetClassLoader(), class_loader_);
+ CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
+ klass->NumDirectMethods() + num_virtual_methods);
+ // Note that we leave the offset to the code in Method::code_
+ size_t class_def_method_index = 0;
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++, class_def_method_index++) {
+ Method* method = klass->GetDirectMethod(i);
+ CHECK(method != NULL) << descriptor << " direct " << i;
+ offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method);
+ }
+ // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods
+ for (size_t i = 0; i < num_virtual_methods; i++, class_def_method_index++) {
+ Method* method = klass->GetVirtualMethod(i);
+ CHECK(method != NULL) << descriptor << " virtual " << i;
+ offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method);
+ }
+ return offset;
+}
+
+size_t OatWriter::InitOatCodeMethod(size_t offset,
+ size_t oat_class_index,
+ size_t class_def_method_index,
+ Method* method) {
+ Runtime* runtime = Runtime::Current();
+ ByteArray* jni_stub_array = runtime->GetJniStubArray();
+ ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+
+ const ByteArray* code_array = method->GetCodeArray();
+ if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
+ oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = 0;
+ method->SetOatCodeOffset(0);
+ } else {
+ offset = RoundUp(offset, kArmAlignment);
+ uint32_t thumb_offset = (reinterpret_cast<const int8_t*>(method->GetCode())
+ - code_array->GetData());
+ uint32_t code_offset = offset + thumb_offset;
+ oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = code_offset;
+ method->SetOatCodeOffset(code_offset);
+ offset += code_array->GetLength();
+ oat_header_->UpdateChecksum(code_array->GetData(), code_array->GetLength());
+ }
+ return offset;
+}
+
+bool OatWriter::Write(const std::string& filename) {
+
+ UniquePtr<File> file(OS::OpenFile(filename.c_str(), true));
+ if (file.get() == NULL) {
+ return false;
+ }
+
+ if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
+ PLOG(ERROR) << "Failed to write oat header to " << filename;
+ return false;
+ }
+
+ if (!WriteTables(file.get())) {
+ LOG(ERROR) << "Failed to write oat tables to " << filename;
+ return false;
+ }
+
+ size_t code_offset = WriteCode(file.get());
+ if (code_offset == 0) {
+ LOG(ERROR) << "Failed to write oat code to " << filename;
+ return false;
+ }
+
+ code_offset = WriteCodeDexFiles(file.get(), code_offset);
+ if (code_offset == 0) {
+ LOG(ERROR) << "Failed to write oat code for dex files to " << filename;
+ return false;
+ }
+
+ return true;
+}
+
+bool OatWriter::WriteTables(File* file) {
+ for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
+ if (!oat_dex_files_[i]->Write(file)) {
+ PLOG(ERROR) << "Failed to write oat dex information";
+ return false;
+ }
+ }
+ for (size_t i = 0; i != oat_classes_.size(); ++i) {
+ if (!oat_classes_[i]->Write(file)) {
+ PLOG(ERROR) << "Failed to write oat classes information";
+ return false;
+ }
+ }
+ for (size_t i = 0; i != oat_methods_.size(); ++i) {
+ if (!oat_methods_[i]->Write(file)) {
+ PLOG(ERROR) << "Failed to write oat methods information";
+ return false;
+ }
+ }
+ return true;
+}
+
+size_t OatWriter::WriteCode(File* file) {
+ uint32_t code_offset = oat_header_->GetExecutableOffset();
+ off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
+ if (static_cast<uint32_t>(new_offset) != code_offset) {
+ PLOG(ERROR) << "Failed to seek to oat code section";
+ return 0;
+ }
+ return code_offset;
+}
+
+size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) {
+ for (size_t i = 0; i != oat_classes_.size(); ++i) {
+ const DexFile* dex_file = (*dex_files_)[i];
+ CHECK(dex_file != NULL);
+ code_offset = WriteCodeDexFile(file, code_offset, *dex_file);
+ if (code_offset == 0) {
+ return 0;
+ }
+ }
+ return code_offset;
+}
+
+size_t OatWriter::WriteCodeDexFile(File* file,
+ size_t code_offset,
+ const DexFile& dex_file) {
+ for (size_t class_def_index = 0;
+ class_def_index < dex_file.NumClassDefs();
+ class_def_index++) {
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+ code_offset = WriteCodeClassDef(file, code_offset, dex_file, class_def);
+ if (code_offset == 0) {
+ return 0;
+ }
+ }
+ return code_offset;
+}
+
+size_t OatWriter::WriteCodeClassDef(File* file,
+ size_t code_offset,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def) {
+ const Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+
+ const byte* class_data = dex_file.GetClassData(class_def);
+ DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+ size_t num_virtual_methods = header.virtual_methods_size_;
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+ Class* klass = class_linker->FindClass(descriptor, class_loader_);
+
+ // TODO: deduplicate code arrays
+ // Note that we clear the code array here, image_writer will use GetCodeOffset to find it
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+ Method* method = klass->GetDirectMethod(i);
+ code_offset = WriteCodeMethod(file, code_offset, method);
+ if (code_offset == 0) {
+ return 0;
+ }
+ }
+ // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods
+ for (size_t i = 0; i < num_virtual_methods; i++) {
+ Method* method = klass->GetVirtualMethod(i);
+ code_offset = WriteCodeMethod(file, code_offset, method);
+ if (code_offset == 0) {
+ return 0;
+ }
+ }
+ for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) {
+ Method* method = klass->GetVirtualMethod(i);
+ const ByteArray* code_array = method->GetCodeArray();
+ CHECK(code_array == NULL // if compiler not run
+ || code_array == ame_stub_array) // otherwise
+ << PrettyMethod(method) << " " << code_array;
+ method->SetCodeArray(NULL, kNone);
+ }
+ return code_offset;
+}
+
+size_t OatWriter::WriteCodeMethod(File* file,
+ size_t code_offset,
+ Method* method) {
+ const Runtime* runtime = Runtime::Current();
+ ByteArray* jni_stub_array = runtime->GetJniStubArray();
+ ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+
+ const ByteArray* code_array = method->GetCodeArray();
+ if (code_array != NULL && code_array != jni_stub_array && code_array != ame_stub_array) {
+ uint32_t aligned_code_offset = RoundUp(code_offset, kArmAlignment);
+ uint32_t aligned_code_delta = aligned_code_offset - code_offset;
+ if (aligned_code_delta != 0) {
+ off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
+ PLOG(ERROR) << "Failed to seek to align oat code";
+ return false;
+ }
+ code_offset += aligned_code_delta;
+ }
+ if (!file->WriteFully(code_array->GetData(), code_array->GetLength())) {
+ PLOG(ERROR) << "Failed to write method code for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += code_array->GetLength();
+ }
+ // preserve code offset around code clearing
+ uint32_t offset = method->GetOatCodeOffset();
+ method->SetCodeArray(NULL, kNone);
+ method->SetOatCodeOffset(offset);
+ return code_offset;
+}
+
+OatWriter::~OatWriter() {
+ delete oat_header_;
+ STLDeleteElements(&oat_dex_files_);
+ STLDeleteElements(&oat_classes_);
+ STLDeleteElements(&oat_methods_);
+}
+
+OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) {
+ const std::string& location = dex_file.GetLocation();
+ dex_file_location_size_ = location.size();
+ dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
+ dex_file_checksum_ = dex_file.GetHeader().checksum_;
+}
+
+size_t OatWriter::OatDexFile::SizeOf() const {
+ return sizeof(dex_file_location_size_)
+ + dex_file_location_size_
+ + sizeof(dex_file_checksum_)
+ + sizeof(classes_offset_);
+}
+
+void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
+ oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
+ oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
+ oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
+ oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
+}
+
+bool OatWriter::OatDexFile::Write(File* file) const {
+ if (!file->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
+ PLOG(ERROR) << "Failed to write dex file location length";
+ return false;
+ }
+ if (!file->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
+ PLOG(ERROR) << "Failed to write dex file location data";
+ return false;
+ }
+ if (!file->WriteFully(&dex_file_checksum_, sizeof(dex_file_checksum_))) {
+ PLOG(ERROR) << "Failed to write dex file checksum";
+ return false;
+ }
+ if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
+ PLOG(ERROR) << "Failed to write classes offset";
+ return false;
+ }
+ return true;
+}
+
+OatWriter::OatClasses::OatClasses(const DexFile& dex_file) {
+ methods_offsets_.resize(dex_file.NumClassDefs());
+}
+
+size_t OatWriter::OatClasses::SizeOf() const {
+ return (sizeof(methods_offsets_[0]) * methods_offsets_.size());
+}
+
+void OatWriter::OatClasses::UpdateChecksum(OatHeader& oat_header) const {
+ oat_header.UpdateChecksum(&methods_offsets_[0], SizeOf());
+}
+
+bool OatWriter::OatClasses::Write(File* file) const {
+ if (!file->WriteFully(&methods_offsets_[0], SizeOf())) {
+ PLOG(ERROR) << "Failed to methods offsets";
+ return false;
+ }
+ return true;
+}
+
+OatWriter::OatMethods::OatMethods(uint32_t methods_count) {
+ method_offsets_.resize(methods_count);
+}
+
+size_t OatWriter::OatMethods::SizeOf() const {
+ return (sizeof(method_offsets_[0]) * method_offsets_.size());
+}
+
+void OatWriter::OatMethods::UpdateChecksum(OatHeader& oat_header) const {
+ oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
+}
+
+bool OatWriter::OatMethods::Write(File* file) const {
+ if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
+ PLOG(ERROR) << "Failed to method offsets";
+ return false;
+ }
+ return true;
+}
+
+} // namespace art
diff --git a/src/oat_writer.h b/src/oat_writer.h
new file mode 100644
index 0000000..7cef892
--- /dev/null
+++ b/src/oat_writer.h
@@ -0,0 +1,155 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_OAT_WRITER_H_
+#define ART_SRC_OAT_WRITER_H_
+
+#include <stdint.h>
+
+#include <cstddef>
+
+#include "UniquePtr.h"
+#include "dex_cache.h"
+#include "mem_map.h"
+#include "oat.h"
+#include "object.h"
+#include "os.h"
+#include "space.h"
+
+namespace art {
+
+// OatHeader fixed length with count of D OatDexFiles
+//
+// OatDexFile[0] each fixed length with offset to variable sized OatClasses
+// OatDexFile[1]
+// ...
+// OatDexFile[D]
+//
+// OatClasses[0] one variable sized OatClasses for each OatDexFile
+// OatClasses[1] contains DexFile::NumClassDefs offsets to OatMethods for each ClassDef
+// ...
+// OatClasses[D]
+//
+// OatMethods[0] one variable sized OatMethods for each of C DexFile::ClassDefs
+// OatMethods[1] contains offsets to code
+// ...
+// OatMethods[C]
+//
+// padding if necessary so that the follow code will be page aligned
+//
+// Method::GetCode() one variable sized code blob for each Method::GetCode() value
+// Method::GetCode()
+// Method::GetCode()
+// Method::GetCode()
+// Method::GetCode()
+// Method::GetCode()
+// ...
+// Method::GetCode()
+//
+class OatWriter {
+ public:
+ // Write an oat file. Returns true on success, false on failure.
+ static bool Create(const std::string& filename, const ClassLoader* class_loader);
+
+ private:
+
+ OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader);
+ ~OatWriter();
+
+ size_t InitOatHeader();
+ size_t InitOatDexFiles(size_t offset);
+ size_t InitOatClasses(size_t offset);
+ size_t InitOatMethods(size_t offset);
+ size_t InitOatCode(size_t offset);
+ size_t InitOatCodeDexFiles(size_t offset);
+ size_t InitOatCodeDexFile(size_t offset,
+ size_t& oat_class_index,
+ const DexFile& dex_file);
+ size_t InitOatCodeClassDef(size_t offset,
+ size_t oat_class_index,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def);
+ size_t InitOatCodeMethod(size_t offset,
+ size_t oat_class_index,
+ size_t class_def_method_index,
+ Method* method);
+
+ bool Write(const std::string& filename);
+ bool WriteTables(File* file);
+ size_t WriteCode(File* file);
+ size_t WriteCodeDexFiles(File* file,
+ size_t offset);
+ size_t WriteCodeDexFile(File* file,
+ size_t offset,
+ const DexFile& dex_file);
+ size_t WriteCodeClassDef(File* file,
+ size_t offset,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def);
+ size_t WriteCodeMethod(File* file,
+ size_t offset,
+ Method* method);
+
+ class OatDexFile {
+ public:
+ OatDexFile(const DexFile& dex_file);
+ size_t SizeOf() const;
+ void UpdateChecksum(OatHeader& oat_header) const;
+ bool Write(File* file) const;
+
+ // data to write
+ uint32_t dex_file_location_size_;
+ const uint8_t* dex_file_location_data_;
+ uint32_t dex_file_checksum_;
+ uint32_t classes_offset_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OatDexFile);
+ };
+
+ class OatClasses {
+ public:
+ OatClasses(const DexFile& dex_file);
+ size_t SizeOf() const;
+ void UpdateChecksum(OatHeader& oat_header) const;
+ bool Write(File* file) const;
+
+ // data to write
+ std::vector<uint32_t> methods_offsets_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OatClasses);
+ };
+
+ class OatMethods {
+ public:
+ OatMethods(uint32_t methods_count);
+ size_t SizeOf() const;
+ void UpdateChecksum(OatHeader& oat_header) const;
+ bool Write(File* file) const;
+
+ // data to write
+ std::vector<uint32_t> method_offsets_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OatMethods);
+ };
+
+ // TODO: remove the ClassLoader when the code storage moves out of Method
+ const ClassLoader* class_loader_;
+
+ // note OatFile does not take ownership of the DexFiles
+ const std::vector<const DexFile*>* dex_files_;
+
+ // data to write
+ OatHeader* oat_header_;
+ std::vector<OatDexFile*> oat_dex_files_;
+ std::vector<OatClasses*> oat_classes_;
+ std::vector<OatMethods*> oat_methods_;
+ uint32_t executable_offset_padding_length_;
+
+ DISALLOW_COPY_AND_ASSIGN(OatWriter);
+};
+
+} // namespace art
+
+#endif // ART_SRC_OAT_WRITER_H_
diff --git a/src/oatdump.cc b/src/oatdump.cc
index fe3cf61..bec8d10 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -22,24 +22,34 @@
static void usage() {
fprintf(stderr,
"Usage: oatdump [options] ...\n"
- " Example: oatdump --dex-file=$ANDROID_PRODUCT_OUT/system/framework/core.jar --image=$ANDROID_PRODUCT_OUT/system/framework/boot.oat --strip-prefix=$ANDROID_PRODUCT_OUT\n"
- " Example: adb shell oatdump --dex-file=/system/framework/core.jar --image=/system/framework/boot.oat\n"
+ " Example: oatdump --dex-file=$ANDROID_PRODUCT_OUT/system/framework/core.jar --oat=$ANDROID_PRODUCT_OUT/system/framework/boot.oat --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art --strip-prefix=$ANDROID_PRODUCT_OUT\n"
+ " Example: adb shell oatdump --dex-file=/system/framework/core.jar --oat=/system/framework/boot.oat --image=/system/framework/boot.art\n"
"\n");
- // TODO: remove this by making image contain boot DexFile information?
+ // TODO: remove this by inferring from --image or --oat
fprintf(stderr,
" --dex-file=<dex-file>: specifies a .dex file location. At least one .dex\n"
" file must be specified. \n"
" Example: --dex-file=/system/framework/core.jar\n"
"\n");
fprintf(stderr,
- " --image=<file>: specifies the required input image filename.\n"
+ " --image=<file.art>: specifies the required input image filename.\n"
+ " Example: --image=/system/framework/boot.art\n"
+ "\n");
+ // TODO: remove this by inferring from --image
+ fprintf(stderr,
+ " --oat=<file.oat>: specifies the required input oat filename.\n"
" Example: --image=/system/framework/boot.oat\n"
"\n");
fprintf(stderr,
- " --boot=<oat-file>: provide the oat file for the boot class path.\n"
- " Example: --boot=/system/framework/boot.oat\n"
+ " --boot-image=<file.art>: provide the image file for the boot class path.\n"
+ " Example: --boot-image=/system/framework/boot.art\n"
"\n");
- // TODO: remove this by making boot image contain boot DexFile information?
+ // TODO: remove this by inferring from --boot-image
+ fprintf(stderr,
+ " --boot-oat=<file.oat>: provide the oat file for the boot class path.\n"
+ " Example: --boot-oat=/system/framework/boot.oat\n"
+ "\n");
+ // TODO: remove this by inderring from --boot-image or --boot-oat
fprintf(stderr,
" --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
" image specified with --boot. \n"
@@ -59,7 +69,9 @@
const char* image_roots_descriptions_[] = {
"kJniStubArray",
- "kCalleeSaveMethod"
+ "kAbstractMethodErrorStubArray",
+ "kCalleeSaveMethod",
+ "kOatLocation",
};
class OatDump {
@@ -72,8 +84,11 @@
os << "MAGIC:\n";
os << image_header.GetMagic() << "\n\n";
- os << "BASE:\n";
- os << reinterpret_cast<void*>(image_header.GetBaseAddr()) << "\n\n";
+ os << "IMAGE BASE:\n";
+ os << reinterpret_cast<void*>(image_header.GetImageBaseAddr()) << "\n\n";
+
+ os << "OAT BASE:\n";
+ os << reinterpret_cast<void*>(image_header.GetOatBaseAddr()) << "\n\n";
os << "ROOTS:\n";
CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
@@ -94,7 +109,10 @@
os << "STATS:\n" << std::flush;
UniquePtr<File> file(OS::OpenFile(image_filename.c_str(), false));
state.stats_.file_bytes = file->Length();
- state.stats_.header_bytes = sizeof(ImageHeader);
+ size_t header_bytes = sizeof(ImageHeader);
+ state.stats_.header_bytes = header_bytes;
+ size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
+ state.stats_.alignment_bytes += alignment_bytes;
state.stats_.Dump(os);
os << std::flush;
@@ -167,6 +185,8 @@
} else {
state->stats_.managed_code_bytes += code_bytes;
}
+ } else {
+ code_base = reinterpret_cast<const int8_t*>(method->GetCode());
}
StringAppendF(&summary, "\tCODE %p-%p\n", code_base, code_limit);
@@ -351,7 +371,9 @@
std::vector<const char*> dex_filenames;
const char* image_filename = NULL;
+ const char* oat_filename = NULL;
const char* boot_image_filename = NULL;
+ const char* boot_oat_filename = NULL;
std::vector<const char*> boot_dex_filenames;
std::string strip_location_prefix;
std::ostream* os = &std::cout;
@@ -363,8 +385,12 @@
dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
} else if (option.starts_with("--image=")) {
image_filename = option.substr(strlen("--image=")).data();
- } else if (option.starts_with("--boot=")) {
- boot_image_filename = option.substr(strlen("--boot=")).data();
+ } else if (option.starts_with("--oat=")) {
+ oat_filename = option.substr(strlen("--oat=")).data();
+ } else if (option.starts_with("--boot-image=")) {
+ boot_image_filename = option.substr(strlen("--boot-image=")).data();
+ } else if (option.starts_with("--boot-oat=")) {
+ boot_oat_filename = option.substr(strlen("--boot-oat=")).data();
} else if (option.starts_with("--boot-dex-file=")) {
boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
} else if (option.starts_with("--strip-prefix=")) {
@@ -388,11 +414,21 @@
return EXIT_FAILURE;
}
+ if (oat_filename == NULL) {
+ fprintf(stderr, "--oat file name not specified\n");
+ return EXIT_FAILURE;
+ }
+
if (dex_filenames.empty()) {
fprintf(stderr, "no --dex-file values specified\n");
return EXIT_FAILURE;
}
+ if ((boot_image_filename != NULL) != (boot_oat_filename != NULL)) {
+ fprintf(stderr, "--boot-image and --boat-oat must be specified together or not at all\n");
+ return EXIT_FAILURE;
+ }
+
if (boot_image_filename != NULL && boot_dex_filenames.empty()) {
fprintf(stderr, "no --boot-dex-file values specified with --boot\n");
return EXIT_FAILURE;
@@ -406,22 +442,31 @@
Runtime::Options options;
std::string image_option;
+ std::string oat_option;
std::string boot_image_option;
+ std::string boot_oat_option;
if (boot_image_filename == NULL) {
// if we don't have multiple images, pass the main one as the boot to match dex2oat
boot_image_filename = image_filename;
+ boot_oat_filename = oat_filename;
boot_dex_files = dex_files;
dex_files.clear();
} else {
image_option += "-Ximage:";
image_option += image_filename;
+ oat_option += "-Xoat:";
+ oat_option += oat_filename;
options.push_back(std::make_pair("classpath", &dex_files));
options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair(oat_option.c_str(), reinterpret_cast<void*>(NULL)));
}
boot_image_option += "-Xbootimage:";
boot_image_option += boot_image_filename;
+ boot_oat_option += "-Xbootoat:";
+ boot_oat_option += boot_oat_filename;
options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair(boot_oat_option.c_str(), reinterpret_cast<void*>(NULL)));
UniquePtr<Runtime> runtime(Runtime::Create(options, false));
if (runtime.get() == NULL) {
diff --git a/src/object.cc b/src/object.cc
index 4a6e649..8fc4108 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -623,7 +623,9 @@
}
size_t mapping_table_length = mapping_table->GetLength();
uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(GetCode());
- CHECK_LT(sought_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
+ if (GetCodeArray() != NULL) {
+ CHECK_LT(sought_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
+ }
uint32_t best_offset = 0;
uint32_t best_dex_offset = 0;
for (size_t i = 0; i < mapping_table_length; i += 2) {
@@ -653,7 +655,9 @@
uint32_t map_offset = mapping_table->Get(i);
uint32_t map_dex_offset = mapping_table->Get(i + 1);
if (map_dex_offset == dex_pc) {
- DCHECK_LT(map_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
+ if (GetCodeArray() != NULL) {
+ DCHECK_LT(map_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
+ }
return reinterpret_cast<uintptr_t>(GetCode()) + map_offset;
}
}
@@ -686,25 +690,27 @@
return DexFile::kDexNoIndex;
}
-void Method::SetCode(ByteArray* code_array, InstructionSet instruction_set,
- IntArray* mapping_table, ShortArray* vmap_table) {
+void Method::SetCodeArray(ByteArray* code_array, InstructionSet instruction_set) {
+// TODO: restore this check or warning when compile time code storage is moved out of Method
// CHECK(GetCode() == NULL || IsNative()) << PrettyMethod(this);
- if (GetCode() != NULL && !IsNative()) {
- LOG(WARNING) << "Calling SetCode more than once for " << PrettyMethod(this);
- }
+// if (GetCode() != NULL && !IsNative()) {
+// LOG(WARNING) << "Calling SetCode more than once for " << PrettyMethod(this);
+// }
SetFieldPtr<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), code_array, false);
- SetFieldPtr<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_),
- mapping_table, false);
- SetFieldPtr<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_),
- vmap_table, false);
- int8_t* code = code_array->GetData();
- uintptr_t address = reinterpret_cast<uintptr_t>(code);
- if (instruction_set == kThumb2) {
- // Set the low-order bit so a BLX will switch to Thumb mode
- address |= 0x1;
+
+ void* code;
+ if (code_array != NULL) {
+ code = code_array->GetData();
+ if (instruction_set == kThumb2) {
+ uintptr_t address = reinterpret_cast<uintptr_t>(code);
+ // Set the low-order bit so a BLX will switch to Thumb mode
+ address |= 0x1;
+ code = reinterpret_cast<void*>(address);
+ }
+ } else {
+ code = NULL;
}
- SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_),
- reinterpret_cast<const void*>(address), false);
+ SetCode(code);
}
bool Method::IsWithinCode(uintptr_t pc) const {
@@ -717,6 +723,9 @@
#if defined(__arm__)
pc &= ~0x1; // clear any possible thumb instruction mode bit
#endif
+ if (GetCodeArray() == NULL) {
+ return true;
+ }
uint32_t rel_offset = pc - reinterpret_cast<uintptr_t>(GetCodeArray()->GetData());
// Strictly the following test should be a less-than, however, if the last
// instruction is a call to an exception throw we may see return addresses
diff --git a/src/object.h b/src/object.h
index 51d7b84..7634807 100644
--- a/src/object.h
+++ b/src/object.h
@@ -817,8 +817,21 @@
return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), false);
}
- void SetCode(ByteArray* code_array, InstructionSet instruction_set,
- IntArray* mapping_table = NULL, ShortArray* vmap_table = NULL);
+ void SetCode(void* code) {
+ SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), code, false);
+ }
+
+ uint32_t GetOatCodeOffset() const {
+ CHECK(!Runtime::Current()->IsStarted());
+ return reinterpret_cast<uint32_t>(GetCode());
+ }
+
+ void SetOatCodeOffset(uint32_t code_offset) {
+ CHECK(!Runtime::Current()->IsStarted());
+ SetCode(reinterpret_cast<void*>(code_offset));
+ }
+
+ void SetCodeArray(ByteArray* code_array, InstructionSet instruction_set);
static MemberOffset GetCodeOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, code_);
@@ -828,14 +841,21 @@
bool IsWithinCode(uintptr_t pc) const;
IntArray* GetMappingTable() const {
- return GetFieldObject<IntArray*>(
- OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
+ return GetFieldObject<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
+ }
+
+ void SetMappingTable(IntArray* mapping_table) {
+ SetFieldPtr<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), mapping_table, false);
}
ShortArray* GetVMapTable() const {
return GetFieldObject<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
}
+ void SetVMapTable(ShortArray* vmap_table) {
+ SetFieldPtr<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), vmap_table, false);
+ }
+
size_t GetFrameSizeInBytes() const {
DCHECK(sizeof(size_t) == sizeof(uint32_t));
size_t result = GetField32(
@@ -1300,8 +1320,7 @@
uint32_t GetAccessFlags() const;
void SetAccessFlags(uint32_t new_access_flags) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags,
- false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, false);
}
// Returns true if the class is an interface.
@@ -1362,8 +1381,7 @@
void SetPrimitiveType(PrimitiveType new_type) {
CHECK(sizeof(PrimitiveType) == sizeof(int32_t));
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type,
- false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false);
}
// Returns true if the class is a primitive type.
@@ -1421,8 +1439,7 @@
void SetComponentType(Class* new_component_type) {
DCHECK(GetComponentType() == NULL);
DCHECK(new_component_type != NULL);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, component_type_),
- new_component_type, false);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, component_type_), new_component_type, false);
}
size_t GetComponentSize() const {
@@ -1483,15 +1500,13 @@
void SetObjectSize(size_t new_object_size) {
DCHECK(!IsVariableSize());
CHECK(sizeof(size_t) == sizeof(int32_t));
- return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_),
- new_object_size, false);
+ return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size, false);
}
// Returns true if this class is in the same packages as that class.
bool IsInSamePackage(const Class* that) const;
- static bool IsInSamePackage(const String* descriptor1,
- const String* descriptor2);
+ static bool IsInSamePackage(const String* descriptor1, const String* descriptor2);
// Returns true if this class can access that class.
bool CanAccess(const Class* that) const {
@@ -1572,8 +1587,7 @@
OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
DCHECK(old_super_class == NULL || old_super_class == new_super_class);
DCHECK(new_super_class != NULL);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_),
- new_super_class, false);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class, false);
}
bool HasSuperClass() const {
@@ -1587,8 +1601,7 @@
}
void SetSuperClassTypeIdx(int32_t new_super_class_idx) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
- new_super_class_idx, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_), new_super_class_idx, false);
}
const ClassLoader* GetClassLoader() const;
@@ -1761,8 +1774,7 @@
void SetInterfaces(ObjectArray<Class>* new_interfaces) {
DCHECK(NULL == GetFieldObject<Object*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false));
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_),
- new_interfaces, false);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), new_interfaces, false);
}
void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t
@@ -1799,15 +1811,13 @@
// Get instance fields
ObjectArray<Field>* GetIFields() const {
DCHECK(IsLoaded() || IsErroneous());
- return GetFieldObject<ObjectArray<Field>*>(
- OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
+ return GetFieldObject<ObjectArray<Field>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
}
void SetIFields(ObjectArray<Field>* new_ifields) {
DCHECK(NULL == GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false));
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_),
- new_ifields, false);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields, false);
}
size_t NumInstanceFields() const {
@@ -1829,27 +1839,23 @@
size_t NumReferenceInstanceFields() const {
DCHECK(IsResolved() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
- return GetField32(
- OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
}
size_t NumReferenceInstanceFieldsDuringLinking() const {
DCHECK(IsLoaded() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
- return GetField32(
- OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
}
void SetNumReferenceInstanceFields(size_t new_num) {
DCHECK(sizeof(size_t) == sizeof(int32_t));
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_),
- new_num, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), new_num, false);
}
uint32_t GetReferenceInstanceOffsets() const {
DCHECK(IsResolved() || IsErroneous());
- return GetField32(
- OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false);
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false);
}
void SetReferenceInstanceOffsets(uint32_t new_reference_offsets);
@@ -1863,34 +1869,29 @@
size_t NumReferenceStaticFields() const {
DCHECK(IsResolved() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
- return GetField32(
- OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
}
size_t NumReferenceStaticFieldsDuringLinking() const {
DCHECK(IsLoaded() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
- return GetField32(
- OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
}
void SetNumReferenceStaticFields(size_t new_num) {
DCHECK(sizeof(size_t) == sizeof(int32_t));
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_),
- new_num, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false);
}
ObjectArray<Field>* GetSFields() const {
DCHECK(IsLoaded() || IsErroneous());
- return GetFieldObject<ObjectArray<Field>*>(
- OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
+ return GetFieldObject<ObjectArray<Field>*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
}
void SetSFields(ObjectArray<Field>* new_sfields) {
DCHECK(NULL == GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false));
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_),
- new_sfields, false);
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields, false);
}
size_t NumStaticFields() const {
@@ -1908,8 +1909,7 @@
}
uint32_t GetReferenceStaticOffsets() const {
- return GetField32(
- OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_), false);
+ return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_), false);
}
void SetReferenceStaticOffsets(uint32_t new_reference_offsets);
@@ -1930,19 +1930,16 @@
}
void SetClinitThreadId(pid_t new_clinit_thread_id) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_),
- new_clinit_thread_id, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id, false);
}
Class* GetVerifyErrorClass() const {
// DCHECK(IsErroneous());
- return GetFieldObject<Class*>(
- OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false);
+ return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false);
}
void SetVerifyErrorClass(Class* klass) {
- klass->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_),
- klass, false);
+ klass->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
}
String* GetSourceFile() const;
diff --git a/src/runtime.cc b/src/runtime.cc
index 0dc5229..6cde082 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -10,9 +10,13 @@
#include "UniquePtr.h"
#include "class_linker.h"
#include "heap.h"
+#include "image.h"
#include "intern_table.h"
#include "jni_internal.h"
+#include "oat_file.h"
#include "signal_catcher.h"
+#include "space.h"
+#include "stl_util.h"
#include "thread.h"
#include "thread_list.h"
@@ -32,6 +36,7 @@
signal_catcher_(NULL),
java_vm_(NULL),
jni_stub_array_(NULL),
+ abstract_method_error_stub_array_(NULL),
callee_save_method_(NULL),
started_(false),
vfprintf_(NULL),
@@ -48,6 +53,7 @@
// Make sure all other non-daemon threads have terminated, and all daemon threads are suspended.
delete thread_list_;
+ STLDeleteElements(&oat_files_);
delete class_linker_;
Heap::Destroy();
delete intern_table_;
@@ -186,6 +192,7 @@
Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, bool ignore_unrecognized) {
UniquePtr<ParsedOptions> parsed(new ParsedOptions());
parsed->boot_image_ = NULL;
+ parsed->boot_oat_ = NULL;
#ifdef NDEBUG
// -Xcheck:jni is off by default for regular builds...
parsed->check_jni_ = false;
@@ -244,10 +251,15 @@
const StringPiece& value = options[i].first;
parsed->class_path_string_ = value.data();
} else if (option.starts_with("-Xbootimage:")) {
- // TODO: remove when intern_addr_ is removed, just use -Ximage:
+ // TODO: remove and just use -Ximage:
parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data();
+ } else if (option.starts_with("-Xbootoat:")) {
+ // TODO: remove and just use -Xoat:
+ parsed->boot_oat_ = option.substr(strlen("-Xbootoat:")).data();
} else if (option.starts_with("-Ximage:")) {
parsed->images_.push_back(option.substr(strlen("-Ximage:")).data());
+ } else if (option.starts_with("-Xoat:")) {
+ parsed->oats_.push_back(option.substr(strlen("-Xoat:")).data());
} else if (option.starts_with("-Xcheck:jni")) {
parsed->check_jni_ = true;
} else if (option.starts_with("-Xms")) {
@@ -402,7 +414,7 @@
UniquePtr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
if (options.get() == NULL) {
- LOG(WARNING) << "Failed to parse options";
+ LOG(ERROR) << "Failed to parse options";
return false;
}
verbose_startup_ = options->IsVerbose("startup");
@@ -424,7 +436,7 @@
intern_table_ = new InternTable;
Heap::Init(options->heap_initial_size_, options->heap_maximum_size_,
- options->boot_image_, options->images_);
+ options->boot_image_, options->images_);
BlockSignals();
@@ -439,7 +451,19 @@
class_linker_ = ClassLinker::Create(options->boot_class_path_,
options->class_path_,
intern_table_,
- Heap::GetBootSpace());
+ Heap::GetBootSpace() != NULL);
+ if (Heap::GetBootSpace() != NULL) {
+ if (!OpenOat(Heap::GetBootSpace(), options->boot_oat_)) {
+ LOG(ERROR) << "Failed to open boot oat " << options->boot_oat_;
+ return false;
+ }
+ }
+ for (size_t i = 0; i < options->oats_.size(); i++) {
+ if (!OpenOat(Heap::GetSpaces()[i+1], options->oats_[i])) {
+ LOG(ERROR) << "Failed to open oat " << options->oats_[i];
+ return false;
+ }
+ }
if (IsVerboseStartup()) {
LOG(INFO) << "Runtime::Init exiting";
@@ -447,6 +471,49 @@
return true;
}
+bool Runtime::OpenOat(const Space* space, const char* oat) {
+ if (IsVerboseStartup()) {
+ LOG(INFO) << "Runtime::OpenOat entering " << oat;
+ }
+ // TODO: check in ParsedOptions?
+ if (space == NULL) {
+ LOG(ERROR) << "oat specified without image";
+ return false;
+ }
+ if (oat == NULL) {
+ LOG(ERROR) << "image specified without oat";
+ return false;
+ }
+ const ImageHeader& image_header = space->GetImageHeader();
+ String* oat_location = image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString();
+ std::string oat_filename = oat_location->ToModifiedUtf8();
+ if (!StringPiece(oat).ends_with(oat_filename)) {
+ LOG(ERROR) << "oat file name " << oat
+ << " does not match value found in image: " << oat_filename;
+ return false;
+ }
+ // TODO: we should be able to just use oat_filename instead of oat
+ // if we passed the prefix argument to find it on the host during cross compilation.
+ OatFile* oat_file = OatFile::Open(std::string(oat), "", image_header.GetOatBaseAddr());
+ if (oat_file == NULL) {
+ LOG(ERROR) << "Failed to open oat file " << oat_filename << " referenced from image";
+ return false;
+ }
+ uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
+ uint32_t image_oat_checksum = image_header.GetOatChecksum();
+ if (oat_checksum != image_oat_checksum) {
+ LOG(ERROR) << "Failed to match oat filechecksum " << std::hex << oat_checksum
+ << " to expected oat checksum " << std::hex << oat_checksum
+ << " in image";
+ return false;
+ }
+ oat_files_.push_back(oat_file);
+ if (IsVerboseStartup()) {
+ LOG(INFO) << "Runtime::OpenOat exiting";
+ }
+ return true;
+}
+
void Runtime::InitNativeMethods() {
if (IsVerboseStartup()) {
LOG(INFO) << "Runtime::InitNativeMethods entering";
@@ -598,13 +665,58 @@
thread_list_->Unregister();
}
+void Runtime::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
+ class_linker_->VisitRoots(visitor, arg);
+ intern_table_->VisitRoots(visitor, arg);
+ java_vm_->VisitRoots(visitor, arg);
+ thread_list_->VisitRoots(visitor, arg);
+ visitor(jni_stub_array_, arg);
+ visitor(abstract_method_error_stub_array_, arg);
+ visitor(callee_save_method_, arg);
+
+ //(*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
+ //(*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
+ //(*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg);
+ UNIMPLEMENTED(WARNING) << "some roots not marked";
+}
+
+bool Runtime::HasJniStubArray() const {
+ return jni_stub_array_ != NULL;
+}
+
+ByteArray* Runtime::GetJniStubArray() const {
+ CHECK(jni_stub_array_ != NULL);
+ return jni_stub_array_;
+}
+
+void Runtime::SetJniStubArray(ByteArray* jni_stub_array) {
+ CHECK(jni_stub_array != NULL);
+ CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array);
+ jni_stub_array_ = jni_stub_array;
+}
+
+bool Runtime::HasAbstractMethodErrorStubArray() const {
+ return abstract_method_error_stub_array_ != NULL;
+}
+
+ByteArray* Runtime::GetAbstractMethodErrorStubArray() const {
+ CHECK(abstract_method_error_stub_array_ != NULL);
+ return abstract_method_error_stub_array_;
+}
+
+void Runtime::SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array) {
+ CHECK(abstract_method_error_stub_array != NULL);
+ CHECK(abstract_method_error_stub_array_ == NULL || abstract_method_error_stub_array_ == abstract_method_error_stub_array);
+ abstract_method_error_stub_array_ = abstract_method_error_stub_array;
+}
+
Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns) {
Class* method_class = Method::GetMethodClass();
Method* method = down_cast<Method*>(method_class->AllocObject());
method->SetDeclaringClass(method_class);
method->SetName(intern_table_->InternStrong("$$$callee_save_method$$$"));
method->SetSignature(intern_table_->InternStrong("()V"));
- method->SetCode(NULL, insns, NULL);
+ method->SetCodeArray(NULL, insns);
if ((insns == kThumb2) || (insns == kArm)) {
size_t frame_size = (12 /* gprs */ + 32 /* fprs */ + 4 /* data */) * kPointerSize;
method->SetFrameSizeInBytes(frame_size);
@@ -667,18 +779,19 @@
return method;
}
-void Runtime::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
- class_linker_->VisitRoots(visitor, arg);
- intern_table_->VisitRoots(visitor, arg);
- java_vm_->VisitRoots(visitor, arg);
- thread_list_->VisitRoots(visitor, arg);
- visitor(jni_stub_array_, arg);
- visitor(callee_save_method_, arg);
-
- //(*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
- //(*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
- //(*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg);
- UNIMPLEMENTED(WARNING) << "some roots not marked";
+bool Runtime::HasCalleeSaveMethod() const {
+ return callee_save_method_ != NULL;
}
+// Returns a special method that describes all callee saves being spilled to the stack.
+Method* Runtime::GetCalleeSaveMethod() const {
+ CHECK(callee_save_method_ != NULL);
+ return callee_save_method_;
+}
+
+void Runtime::SetCalleeSaveMethod(Method* method) {
+ callee_save_method_ = method;
+}
+
+
} // namespace art
diff --git a/src/runtime.h b/src/runtime.h
index ca0496c..bae5643 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -30,6 +30,7 @@
class InternTable;
class JavaVMExt;
class Method;
+class OatFile;
class SignalCatcher;
class String;
class ThreadList;
@@ -49,7 +50,9 @@
std::string class_path_string_;
std::vector<const DexFile*> class_path_;
const char* boot_image_;
+ const char* boot_oat_;
std::vector<const char*> images_;
+ std::vector<const char*> oats_;
bool check_jni_;
std::string jni_trace_;
size_t heap_initial_size_;
@@ -145,35 +148,19 @@
void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
- bool HasJniStubArray() const {
- return jni_stub_array_ != NULL;
- }
+ bool HasJniStubArray() const;
+ ByteArray* GetJniStubArray() const;
+ void SetJniStubArray(ByteArray* jni_stub_array);
- ByteArray* GetJniStubArray() const {
- CHECK(jni_stub_array_ != NULL);
- return jni_stub_array_;
- }
-
- void SetJniStubArray(ByteArray* jni_stub_array) {
- CHECK(jni_stub_array != NULL);
- CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array);
- jni_stub_array_ = jni_stub_array;
- }
-
- Method* CreateCalleeSaveMethod(InstructionSet insns);
-
- bool HasCalleeSaveMethod() const {
- return callee_save_method_ != NULL;
- }
+ bool HasAbstractMethodErrorStubArray() const;
+ ByteArray* GetAbstractMethodErrorStubArray() const;
+ void SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array);
// Returns a special method that describes all callee saves being spilled to the stack.
- Method* GetCalleeSaveMethod() const {
- return callee_save_method_;
- }
-
- void SetCalleeSaveMethod(Method* method) {
- callee_save_method_ = method;
- }
+ Method* CreateCalleeSaveMethod(InstructionSet insns);
+ bool HasCalleeSaveMethod() const;
+ Method* GetCalleeSaveMethod() const;
+ void SetCalleeSaveMethod(Method* method);
int32_t GetStat(int kind);
@@ -195,6 +182,7 @@
void BlockSignals();
bool Init(const Options& options, bool ignore_unrecognized);
+ bool OpenOat(const Space* space, const char* boot_oat_);
void InitNativeMethods();
void RegisterRuntimeNativeMethods(JNIEnv*);
void StartDaemonThreads();
@@ -214,12 +202,16 @@
ClassLinker* class_linker_;
+ std::vector<const OatFile*> oat_files_;
+
SignalCatcher* signal_catcher_;
JavaVMExt* java_vm_;
ByteArray* jni_stub_array_;
+ ByteArray* abstract_method_error_stub_array_;
+
Method* callee_save_method_;
bool started_;
diff --git a/src/space.cc b/src/space.cc
index 9efe599..09eb0c9 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -114,7 +114,7 @@
LOG(WARNING) << "Invalid image header " << image_file_name;
return false;
}
- UniquePtr<MemMap> map(MemMap::Map(image_header.GetBaseAddr(),
+ UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
file->Length(),
// TODO: selectively PROT_EXEC when image contains a code space
PROT_READ | PROT_WRITE | PROT_EXEC,
@@ -125,13 +125,16 @@
LOG(WARNING) << "Failed to map " << image_file_name;
return false;
}
- CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());
+ CHECK_EQ(image_header.GetImageBaseAddr(), map->GetAddress());
image_header_ = reinterpret_cast<ImageHeader*>(map->GetAddress());
DCHECK_EQ(0, memcmp(&image_header, image_header_, sizeof(ImageHeader)));
Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
Runtime::Current()->SetJniStubArray(down_cast<ByteArray*>(jni_stub_array));
+ Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
+ Runtime::Current()->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
+
Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
diff --git a/src/stack_walk.cc b/src/stack_walk.cc
index bc7b3a3..2c29e75 100644
--- a/src/stack_walk.cc
+++ b/src/stack_walk.cc
@@ -6,7 +6,6 @@
#include "class_linker.h"
#include "common_test.h"
#include "dex_verifier.h"
-// #include "heap.h"
#include "object.h"
#include "jni.h"
diff --git a/src/stub_arm.cc b/src/stub_arm.cc
index a35bfe2..75d60f5 100644
--- a/src/stub_arm.cc
+++ b/src/stub_arm.cc
@@ -36,6 +36,7 @@
size_t cs = assembler->CodeSize();
ByteArray* abstract_stub = ByteArray::Alloc(cs);
CHECK(abstract_stub != NULL);
+ CHECK(abstract_stub->GetClass()->GetDescriptor());
MemoryRegion code(abstract_stub->GetData(), abstract_stub->GetLength());
assembler->FinalizeInstructions(code);
diff --git a/src/utils.cc b/src/utils.cc
index b47ee2c..b5063ff 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -48,6 +48,9 @@
}
std::string PrettyDescriptor(const String* java_descriptor) {
+ if (java_descriptor == NULL) {
+ return "null";
+ }
std::string descriptor(java_descriptor->ToModifiedUtf8());
// Count the number of '['s to get the dimensionality.
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index 5a8a1a0..bbd392f 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -27,7 +27,9 @@
dex2oatd -Xms16m -Xmx16m \
--boot-dex-file=${ANDROID_PRODUCT_OUT}/system/framework/core.jar \
- --boot=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-oat=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/test.jar \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --oat=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --image=${ANDROID_PRODUCT_OUT}/system/framework/test.art \
--strip-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index a2b7eea..118e178 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -29,7 +29,9 @@
dex2oatd -Xms16m -Xmx16m \
--boot-dex-file=${ANDROID_PRODUCT_OUT}/system/framework/core.jar \
- --boot=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-oat=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/test.jar \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --oat=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --image=${ANDROID_PRODUCT_OUT}/system/framework/test.art \
--strip-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index 98f27b8..c39779b 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -48,7 +48,9 @@
dex2oatd -Xms16m -Xmx16m \
--boot-dex-file=${ANDROID_PRODUCT_OUT}/system/framework/core.jar \
- --boot=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-oat=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/test.jar \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --oat=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --image=${ANDROID_PRODUCT_OUT}/system/framework/test.art \
--strip-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index 6f41a0d..5a1b04c 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -30,7 +30,9 @@
dex2oatd -Xms16m -Xmx16m \
--boot-dex-file=${ANDROID_PRODUCT_OUT}/system/framework/core.jar \
- --boot=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-oat=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/test.jar \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --oat=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --image=${ANDROID_PRODUCT_OUT}/system/framework/test.art \
--strip-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/ExceptionHandle/ExceptionHandle.java b/test/ExceptionHandle/ExceptionHandle.java
new file mode 100644
index 0000000..94c6f5b
--- /dev/null
+++ b/test/ExceptionHandle/ExceptionHandle.java
@@ -0,0 +1,27 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+import java.io.IOException;
+
+public class ExceptionHandle {
+ int f() throws Exception {
+ try {
+ g(1);
+ } catch (IOException e) {
+ return 1;
+ } catch (Exception e) {
+ return 2;
+ }
+ try {
+ g(2);
+ } catch (IOException e) {
+ return 3;
+ }
+ return 0;
+ }
+ void g(int doThrow) throws Exception {
+ if (doThrow == 1) {
+ throw new Exception();
+ } else if (doThrow == 2) {
+ throw new IOException();
+ }
+ }
+}
diff --git a/test/etc/default-build b/test/etc/default-build
index dcc372a..e31e0ea 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -30,9 +30,11 @@
dex2oatd -Xms16m -Xmx16m \
--boot-dex-file=${ANDROID_PRODUCT_OUT}/system/framework/core.jar \
- --boot=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-oat=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/test.jar \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --oat=${ANDROID_PRODUCT_OUT}/system/framework/test.oat \
+ --image=${ANDROID_PRODUCT_OUT}/system/framework/test.art \
--strip-prefix=${ANDROID_PRODUCT_OUT}
if [ -r src-ex ]; then
@@ -50,8 +52,10 @@
dex2oatd -Xms16m -Xmx16m \
--boot-dex-file=${ANDROID_PRODUCT_OUT}/system/framework/core.jar \
- --boot=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-oat=${ANDROID_PRODUCT_OUT}/system/framework/core.oat \
+ --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/test-ex.jar \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/test-ex.oat \
+ --oat=${ANDROID_PRODUCT_OUT}/system/framework/test-ex.oat \
+ --image=${ANDROID_PRODUCT_OUT}/system/framework/test-ex.art \
--strip-prefix=${ANDROID_PRODUCT_OUT}
fi
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
index 8b490cd..fd96b6b 100755
--- a/test/etc/push-and-run-test-jar
+++ b/test/etc/push-and-run-test-jar
@@ -108,13 +108,17 @@
if [ "$QUIET" = "n" ]; then
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test.jar /system/framework
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test.oat /system/framework
+ adb push ${ANDROID_PRODUCT_OUT}/system/framework/test.art /system/framework
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test-ex.jar /system/framework
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test-ex.oat /system/framework
+ adb push ${ANDROID_PRODUCT_OUT}/system/framework/test-ex.art /system/framework
else
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test.jar /system/framework >/dev/null 2>&1
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test.oat /system/framework >/dev/null 2>&1
+ adb push ${ANDROID_PRODUCT_OUT}/system/framework/test.art /system/framework >/dev/null 2>&1
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test-ex.jar /system/framework >/dev/null 2>&1
adb push ${ANDROID_PRODUCT_OUT}/system/framework/test-ex.oat /system/framework >/dev/null 2>&1
+ adb push ${ANDROID_PRODUCT_OUT}/system/framework/test-ex.art /system/framework >/dev/null 2>&1
fi
if [ "$DEBUG" = "y" ]; then
@@ -130,10 +134,13 @@
if [ "$ZYGOTE" = "y" ]; then
adb shell cd /data \; dvz -classpath test.jar Main "$@"
else
- cmdline="cd /data; oatexecd -Xbootclasspath:/system/framework/core.jar \
- -Xbootimage:/system/framework/core.oat \
+ cmdline="cd /data; oatexecd \
+ -Xbootclasspath:/system/framework/core.jar \
+ -Xbootoat:/system/framework/core.oat \
+ -Xbootimage:/system/framework/core.art \
-classpath /system/framework/test.jar \
- -Ximage:/system/framework/test.oat Main"
+ -Xoat:/system/framework/test.oat \
+ -Ximage:/system/framework/test.art Main"
#cmdline="cd /data; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
# $GC_OPTS -cp test.jar -Xint:${INTERP} -ea Main"
if [ "$DEV_MODE" = "y" ]; then