diff options
author | 2011-09-03 12:25:21 -0700 | |
---|---|---|
committer | 2011-09-06 15:28:47 -0700 | |
commit | 69b15fb098162f19a4c20e6dccdcead04d9c77f0 (patch) | |
tree | 84fdfc26f560fb618b652a0aff98347f875a2653 | |
parent | 109bd6a38d0cd7c4b7797a9f2db8324c797d1368 (diff) |
Working dex2oat and oatexec
adb shell dex2oatd --dex-file=/system/framework/core.jar --image=/system/framework/boot.oat --base=0x50000000 "'--method=Ljava/lang/System;logI(Ljava/lang/String;)V'" "'--method=Ljava/lang/System;log(CLjava/lang/String;Ljava/lang/Throwable;)V'"
adb shell dex2oatd --boot-dex-file=/system/framework/core.jar --boot=/system/framework/boot.oat --dex-file=/system/framework/art-test-dex-HelloWorld.jar --image=/system/framework/art-test-dex-HelloWorld.oat
adb shell oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-HelloWorld.jar -Ximage:/system/framework/art-test-dex-HelloWorld.oat HelloWorld
09-05 17:58:18.912 2385 2385 I System : Hello, world!
Change-Id: I53e534068584f0c3a837313e4d517a0e4a7154fc
-rw-r--r-- | Android.mk | 6 | ||||
-rw-r--r-- | build/Android.aexec.mk | 58 | ||||
-rw-r--r-- | build/Android.common.mk | 8 | ||||
-rw-r--r-- | build/Android.executable.mk | 76 | ||||
-rw-r--r-- | build/Android.libart.mk | 2 | ||||
-rw-r--r-- | src/check_jni.cc | 2 | ||||
-rw-r--r-- | src/class_linker.cc | 63 | ||||
-rw-r--r-- | src/class_linker.h | 10 | ||||
-rw-r--r-- | src/class_loader.cc | 1 | ||||
-rw-r--r-- | src/common_test.h | 17 | ||||
-rw-r--r-- | src/dex2oat.cc | 224 | ||||
-rw-r--r-- | src/dex_cache.h | 40 | ||||
-rw-r--r-- | src/dex_file.cc | 30 | ||||
-rw-r--r-- | src/dex_file.h | 3 | ||||
-rw-r--r-- | src/exception_test.cc | 2 | ||||
-rw-r--r-- | src/heap.cc | 23 | ||||
-rw-r--r-- | src/heap.h | 8 | ||||
-rw-r--r-- | src/image.cc | 2 | ||||
-rw-r--r-- | src/image.h | 1 | ||||
-rw-r--r-- | src/image_test.cc | 16 | ||||
-rw-r--r-- | src/image_writer.cc | 91 | ||||
-rw-r--r-- | src/image_writer.h | 41 | ||||
-rw-r--r-- | src/jni_internal.cc | 9 | ||||
-rw-r--r-- | src/oatexec.cc (renamed from src/main.cc) | 2 | ||||
-rw-r--r-- | src/object.cc | 3 | ||||
-rw-r--r-- | src/object.h | 7 | ||||
-rw-r--r-- | src/runtime.cc | 104 | ||||
-rw-r--r-- | src/runtime.h | 9 | ||||
-rw-r--r-- | src/runtime_test.cc | 23 | ||||
-rw-r--r-- | src/space.cc | 20 | ||||
-rw-r--r-- | test/HelloWorld/HelloWorld.java | 21 | ||||
-rwxr-xr-x | tools/art | 6 |
32 files changed, 731 insertions, 197 deletions
diff --git a/Android.mk b/Android.mk index d23b75ed8d..d6c8eb3c1d 100644 --- a/Android.mk +++ b/Android.mk @@ -21,7 +21,7 @@ build_path := $(LOCAL_PATH)/build include $(build_path)/Android.common.mk include $(build_path)/Android.libart.mk -include $(build_path)/Android.aexec.mk +include $(build_path)/Android.executable.mk include $(build_path)/Android.libarttest.mk include $(build_path)/Android.test.mk @@ -29,9 +29,9 @@ include $(build_path)/Android.test.mk # "m build-art" for quick minimal build .PHONY: build-art build-art: \ - $(TARGET_OUT_EXECUTABLES)/aexec \ + $(ART_TARGET_EXECUTABLES) \ $(ART_TARGET_TEST_EXECUTABLES) \ - $(HOST_OUT_EXECUTABLES)/aexec \ + $(ART_HOST_EXECUTABLES) \ $(ART_HOST_TEST_EXECUTABLES) # "mm test-art" to build and run all tests on host and device diff --git a/build/Android.aexec.mk b/build/Android.aexec.mk deleted file mode 100644 index 6d6177c81d..0000000000 --- a/build/Android.aexec.mk +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (C) 2011 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# $(1): target or host -# $(2): ndebug or debug -define build-aexec - include $(CLEAR_VARS) - ifeq ($(1),target) - include external/stlport/libstlport.mk - endif - LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) - ifeq ($(2),ndebug) - LOCAL_MODULE := aexec - else - LOCAL_MODULE := aexecd - endif - LOCAL_MODULE_TAGS := optional - LOCAL_SRC_FILES := $(AEXEC_SRC_FILES) - LOCAL_CFLAGS := $(ART_CFLAGS) - ifeq ($(2),debug) - LOCAL_CFLAGS += -UNDEBUG - endif - LOCAL_SHARED_LIBRARIES := libnativehelper - ifeq ($(2),ndebug) - LOCAL_SHARED_LIBRARIES += libart - else - LOCAL_SHARED_LIBRARIES += libartd - endif - ifeq ($(1),target) - LOCAL_SHARED_LIBRARIES += libstlport - endif - ifeq ($(1),target) - include $(BUILD_EXECUTABLE) - else - include $(BUILD_HOST_EXECUTABLE) - endif -endef - -$(eval $(call build-aexec,target,ndebug)) -$(eval $(call build-aexec,target,debug)) -ifeq ($(WITH_HOST_DALVIK),true) - $(eval $(call build-aexec,host,ndebug)) - $(eval $(call build-aexec,host,debug)) -endif - diff --git a/build/Android.common.mk b/build/Android.common.mk index aa9b71930f..d7346dbfd1 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -35,8 +35,11 @@ ART_CFLAGS := \ -fno-align-jumps \ -fstrict-aliasing -AEXEC_SRC_FILES := \ - src/main.cc +DEX2OAT_SRC_FILES := \ + src/dex2oat.cc + +OATEXEC_SRC_FILES := \ + src/oatexec.cc LIBART_COMMON_SRC_FILES := \ src/assembler.cc \ @@ -156,6 +159,7 @@ TEST_DEX_DIRECTORIES := \ AllFields \ CreateMethodDescriptor \ Fibonacci \ + HelloWorld \ IntMath \ Interfaces \ Main \ diff --git a/build/Android.executable.mk b/build/Android.executable.mk new file mode 100644 index 0000000000..328f60a375 --- /dev/null +++ b/build/Android.executable.mk @@ -0,0 +1,76 @@ +# +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ART_HOST_EXECUTABLES := +ART_TARGET_EXECUTABLES := + +# $(1): executable ("d" will be appended for debug version) +# $(2): source +# $(3): target or host +# $(4): ndebug or debug +define build-art-executable + include $(CLEAR_VARS) + ifeq ($(3),target) + include external/stlport/libstlport.mk + endif + LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) + ifeq ($(4),ndebug) + LOCAL_MODULE := $(1) + else + LOCAL_MODULE := $(1)d + endif + LOCAL_MODULE_TAGS := optional + LOCAL_SRC_FILES := $(2) + LOCAL_CFLAGS := $(ART_CFLAGS) + ifeq ($(4),debug) + LOCAL_CFLAGS += -UNDEBUG + endif + LOCAL_C_INCLUDES += $(ART_C_INCLUDES) + LOCAL_SHARED_LIBRARIES := libnativehelper + ifeq ($(4),ndebug) + LOCAL_SHARED_LIBRARIES += libart + else + LOCAL_SHARED_LIBRARIES += libartd + endif + ifeq ($(3),target) + LOCAL_SHARED_LIBRARIES += libstlport + endif + ifeq ($(3),target) + include $(BUILD_EXECUTABLE) + else + include $(BUILD_HOST_EXECUTABLE) + endif + ifeq ($(1),target) + ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$$(LOCAL_MODULE) + else + ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$$(LOCAL_MODULE) + endif +endef + +$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),target,ndebug)) +$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),target,debug)) +ifeq ($(WITH_HOST_DALVIK),true) + $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,ndebug)) + $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug)) +endif + +$(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,ndebug)) +$(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,debug)) +ifeq ($(WITH_HOST_DALVIK),true) + $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,ndebug)) + $(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,debug)) +endif + diff --git a/build/Android.libart.mk b/build/Android.libart.mk index 5877e2fcc4..3218a4215a 100644 --- a/build/Android.libart.mk +++ b/build/Android.libart.mk @@ -37,7 +37,7 @@ define build-libart ifeq ($(2),debug) LOCAL_CFLAGS += -UNDEBUG endif - LOCAL_C_INCLUDES += src $(ART_C_INCLUDES) + LOCAL_C_INCLUDES += $(ART_C_INCLUDES) LOCAL_SHARED_LIBRARIES := liblog libnativehelper ifeq ($(1),target) LOCAL_SHARED_LIBRARIES += libcutils libstlport libz libdl diff --git a/src/check_jni.cc b/src/check_jni.cc index dc58565c68..0486284f82 100644 --- a/src/check_jni.cc +++ b/src/check_jni.cc @@ -447,7 +447,7 @@ public: ScopedJniThreadState ts(mEnv); const Method* m = DecodeMethod(ts, mid); if (*expectedType != m->GetShorty()[0]) { - LOG(ERROR) << "JNI ERROR: expected return type '%s' calling " << PrettyMethod(m); + LOG(ERROR) << "JNI ERROR: expected return type '" << *expectedType << "' calling " << PrettyMethod(m); JniAbort(); } else if (isStatic && !m->IsStatic()) { if (isStatic) { diff --git a/src/class_linker.cc b/src/class_linker.cc index 7cd320e739..211b87df05 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -56,12 +56,14 @@ const char* ClassLinker::class_roots_descriptors_[kClassRootsMax] = { }; ClassLinker* ClassLinker::Create(const std::vector<const DexFile*>& boot_class_path, - InternTable* intern_table, Space* space) { + const std::vector<const DexFile*>& class_path, + InternTable* intern_table, Space* space) { + CHECK_NE(boot_class_path.size(), 0U); UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table)); if (space == NULL) { - class_linker->Init(boot_class_path); + class_linker->Init(boot_class_path, class_path); } else { - class_linker->Init(boot_class_path, space); + class_linker->Init(boot_class_path, class_path, space); } // TODO: check for failure during initialization return class_linker.release(); @@ -76,7 +78,8 @@ ClassLinker::ClassLinker(InternTable* intern_table) intern_table_(intern_table) { } -void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) { +void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, + const std::vector<const DexFile*>& class_path) { CHECK(!init_done_); // java_lang_Class comes first, its needed for AllocClass @@ -160,13 +163,18 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) { // now that these are registered, we can use AllocClass() and AllocObjectArray - // setup boot_class_path_ now that we can use AllocObjectArray to - // create DexCache instances + // setup boot_class_path_ and register class_path now that we can + // use AllocObjectArray to create DexCache instances for (size_t i = 0; i != boot_class_path.size(); ++i) { const DexFile* dex_file = boot_class_path[i]; CHECK(dex_file != NULL); AppendToBootClassPath(*dex_file); } + for (size_t i = 0; i != class_path.size(); ++i) { + const DexFile* dex_file = class_path[i]; + CHECK(dex_file != NULL); + RegisterDexFile(*dex_file); + } // Field and Method are necessary so that FindClass can link members Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass)); @@ -366,16 +374,13 @@ struct ClassLinker::InitCallbackState { typedef std::tr1::unordered_map<std::string, ClassRoot> Table; Table descriptor_to_class_root; - struct DexCacheHash { - size_t operator()(art::DexCache* const& obj) const { - return reinterpret_cast<size_t>(&obj); - } - }; typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set; Set dex_caches; }; -void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space* space) { +void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, + const std::vector<const DexFile*>& class_path, + Space* space) { CHECK(!init_done_); HeapBitmap* heap_bitmap = Heap::GetLiveBits(); @@ -400,6 +405,7 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space } // reinit intern table + // TODO: remove interned_array, make all strings in image interned (and remove space argument) ObjectArray<Object>* interned_array = space->GetImageHeader().GetInternedArray(); for (int32_t i = 0; i < interned_array->GetLength(); i++) { String* string = interned_array->Get(i)->AsString(); @@ -418,14 +424,27 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space std::string location = dex_cache->GetLocation()->ToModifiedUtf8(); location_to_dex_cache[location] = dex_cache; } + CHECK_EQ(boot_class_path.size() + class_path.size(), + location_to_dex_cache.size()); // reinit boot_class_path with DexFile arguments and found DexCaches for (size_t i = 0; i != boot_class_path.size(); ++i) { const DexFile* dex_file = boot_class_path[i]; CHECK(dex_file != NULL); DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()]; + CHECK(dex_cache != NULL) << dex_file->GetLocation(); AppendToBootClassPath(*dex_file, dex_cache); } + + // register class_path with DexFile arguments and found DexCaches + for (size_t i = 0; i != class_path.size(); ++i) { + const DexFile* dex_file = class_path[i]; + CHECK(dex_file != NULL); + DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()]; + CHECK(dex_cache != NULL) << dex_file->GetLocation(); + RegisterDexFile(*dex_file, dex_cache); + } + String::SetClass(GetClassRoot(kJavaLangString)); Field::SetClass(GetClassRoot(kJavaLangReflectField)); Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); @@ -452,10 +471,15 @@ void ClassLinker::InitCallback(Object* obj, void *arg) { return; } Class* klass = obj->AsClass(); - CHECK(klass->GetClassLoader() == NULL); + // TODO: restore ClassLoader's list of DexFiles after image load + // CHECK(klass->GetClassLoader() == NULL); + const ClassLoader* class_loader = klass->GetClassLoader(); + if (class_loader != NULL) { + // TODO: replace this hack with something based on command line arguments + Thread::Current()->SetClassLoaderOverride(class_loader); + } std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8(); - // restore class to ClassLinker::classes_ table state->class_linker->InsertClass(descriptor, klass); @@ -900,7 +924,7 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) { } void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, DexCache* dex_cache) { - CHECK(dex_cache != NULL); + CHECK(dex_cache != NULL) << dex_file.GetLocation(); boot_class_path_.push_back(&dex_file); RegisterDexFile(dex_file, dex_cache); } @@ -910,7 +934,8 @@ void ClassLinker::RegisterDexFile(const DexFile& dex_file) { } void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) { - CHECK(dex_cache != NULL); + CHECK(dex_cache != NULL) << dex_file.GetLocation(); + CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation())); dex_files_.push_back(&dex_file); dex_caches_.push_back(dex_cache); } @@ -921,7 +946,7 @@ const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const { return *dex_files_[i]; } } - CHECK(false) << "Could not find DexFile"; + CHECK(false) << "Failed to find DexFile for DexCache " << dex_cache->GetLocation()->ToModifiedUtf8(); return *dex_files_[-1]; } @@ -931,7 +956,7 @@ DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const { return dex_caches_[i]; } } - CHECK(false) << "Could not find DexCache"; + CHECK(false) << "Failed to find DexCache for DexFile " << dex_file.GetLocation(); return NULL; } @@ -1544,7 +1569,7 @@ bool ClassLinker::LinkSuperClass(Class* klass) { return false; } if (!klass->CanAccess(super)) { - LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError + LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError return false; } #ifndef NDEBUG diff --git a/src/class_linker.h b/src/class_linker.h index f63ab3c90b..4f4ffc79c9 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -26,7 +26,8 @@ class ClassLinker { public: // Initializes the class linker using DexFile and an optional boot Space. static ClassLinker* Create(const std::vector<const DexFile*>& boot_class_path, - InternTable* intern_table, Space* boot_space); + const std::vector<const DexFile*>& class_path, + InternTable* intern_table, Space* boot_space); ~ClassLinker(); @@ -149,10 +150,13 @@ class ClassLinker { ClassLinker(InternTable*); // Initialize class linker from DexFile instances. - void Init(const std::vector<const DexFile*>& boot_class_path_); + void Init(const std::vector<const DexFile*>& boot_class_path_, + const std::vector<const DexFile*>& class_path_); // Initialize class linker from pre-initialized space. - void Init(const std::vector<const DexFile*>& boot_class_path_, Space* space); + void Init(const std::vector<const DexFile*>& boot_class_path_, + const std::vector<const DexFile*>& class_path_, + Space* space); static void InitCallback(Object* obj, void *arg); struct InitCallbackState; diff --git a/src/class_loader.cc b/src/class_loader.cc index 97691362c4..8f8e829761 100644 --- a/src/class_loader.cc +++ b/src/class_loader.cc @@ -18,6 +18,7 @@ const std::vector<const DexFile*>& ClassLoader::GetClassPath(const ClassLoader* Class* PathClassLoader::dalvik_system_PathClassLoader_ = NULL; const PathClassLoader* PathClassLoader::Alloc(std::vector<const DexFile*> dex_files) { + DCHECK(dalvik_system_PathClassLoader_ != NULL); PathClassLoader* p = down_cast<PathClassLoader*>(dalvik_system_PathClassLoader_->AllocObject()); p->SetClassPath(dex_files); return p; diff --git a/src/common_test.h b/src/common_test.h index 7916640663..98d9127516 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -85,7 +85,8 @@ class CommonTest : public testing::Test { setenv("ANDROID_ROOT", root.c_str(), 1); } - android_data_ = (is_host_ ? "/tmp/art-data-XXXXXX" : "/mnt/sdcard/art-data-XXXXXX"); + // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of art-cache + android_data_ = (is_host_ ? "/tmp/art-data-XXXXXX" : "/data/art-cache/art-data-XXXXXX"); if (mkdtemp(&android_data_[0]) == NULL) { PLOG(FATAL) << "mkdtemp(\"" << &android_data_[0] << "\") failed"; } @@ -99,8 +100,12 @@ class CommonTest : public testing::Test { boot_class_path_.push_back(java_lang_dex_file_.get()); - runtime_.reset(Runtime::Create(boot_class_path_)); + 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))); + runtime_.reset(Runtime::Create(options, false)); ASSERT_TRUE(runtime_.get() != NULL); + runtime_->Start(); class_linker_ = runtime_->GetClassLinker(); Heap::VerifyHeap(); // Check for heap corruption before the test @@ -167,7 +172,7 @@ class CommonTest : public testing::Test { return i; } } - CHECK(false) << "Could not find type index for " << descriptor; + CHECK(false) << "Failed to find type index for " << descriptor; return 0; } @@ -181,11 +186,11 @@ class CommonTest : public testing::Test { return i; } } - CHECK(false) << "Could not find field index for " << class_descriptor << " " << field_name; + CHECK(false) << "Failed to find field index for " << class_descriptor << " " << field_name; return 0; } - const PathClassLoader* AllocPathClassLoader(const DexFile* dex_file) { + const ClassLoader* AllocPathClassLoader(const DexFile* dex_file) { CHECK(dex_file != NULL); class_linker_->RegisterDexFile(*dex_file); std::vector<const DexFile*> dex_files; @@ -204,7 +209,7 @@ class CommonTest : public testing::Test { filename += name; filename += ".jar"; const DexFile* dex_file = DexFile::OpenZip(filename); - CHECK(dex_file != NULL) << "Could not open " << filename; + CHECK(dex_file != NULL) << "Failed to open " << filename; return dex_file; } diff --git a/src/dex2oat.cc b/src/dex2oat.cc new file mode 100644 index 0000000000..4d071a78c3 --- /dev/null +++ b/src/dex2oat.cc @@ -0,0 +1,224 @@ +// Copyright 2011 Google Inc. All Rights Reserved. + +#include <stdio.h> +#include <stdlib.h> + +#include <string> +#include <vector> + +#include "class_linker.h" +#include "class_loader.h" +#include "compiler.h" +#include "image_writer.h" +#include "runtime.h" +#include "stringpiece.h" + +namespace art { + +static void usage() { + fprintf(stderr, + "Usage: dex2oat [options]...\n" + "\n"); + fprintf(stderr, + " --dex-file=<dex-file>: specifies a .dex files to compile. At least one .dex\n" + " but more than one may be included. \n" + " Example: --dex-file=/system/framework/core.jar\n" + "\n"); + fprintf(stderr, + " --image=<file>: specifies the required output image filename.\n" + " Example: --image=/system/framework/boot.oat\n" + "\n"); + fprintf(stderr, + " --base=<hex-address>: specifies the base address when creating a boot image.\n" + " 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" + "\n"); + // TODO: remove this by making boot image contain boot DexFile information? + fprintf(stderr, + " --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n" + " image specified with --boot. \n" + " Example: --boot-dex-file=/system/framework/core.jar\n" + "\n"); + fprintf(stderr, + " --method may be used to limit compilation to a subset of methods.\n" + " Example: --method=Ljava/lang/Object;<init>()V\n" + "\n"); + exit(EXIT_FAILURE); +} + +static void OpenDexFiles(std::vector<const char*>& dex_filenames, + std::vector<const DexFile*>& dex_files) { + for (size_t i = 0; i < dex_filenames.size(); i++) { + const char* dex_filename = dex_filenames[i]; + const DexFile* dex_file = DexFile::Open(dex_filename); + if (dex_file == NULL) { + fprintf(stderr, "could not open .dex from file %s\n", dex_filename); + exit(EXIT_FAILURE); + } + dex_files.push_back(dex_file); + } +} + +int dex2oat(int argc, char** argv) { + // Skip over argv[0]. + argv++; + argc--; + + if (argc == 0) { + fprintf(stderr, "no arguments specified\n"); + usage(); + } + + std::vector<const char*> dex_filenames; + std::vector<const char*> method_names; + const char* image_filename = NULL; + std::string boot_image_option; + std::vector<const char*> boot_dex_filenames; + uintptr_t image_base = 0; + for (int i = 0; i < argc; i++) { + const StringPiece option(argv[i]); + if (option.starts_with("--dex-file=")) { + 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("--image=")) { + image_filename = option.substr(strlen("--image=")).data(); + } else if (option.starts_with("--base=")) { + const char* image_base_str = option.substr(strlen("--base=")).data(); + char* end; + image_base = strtoul(image_base_str, &end, 16); + if (end == image_base_str || *end != '\0') { + fprintf(stderr, "could not 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(); + boot_image_option.clear(); + boot_image_option += "-Xbootimage:"; + boot_image_option += boot_image_filename; + } else if (option.starts_with("--boot-dex-file=")) { + boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data()); + } else { + fprintf(stderr, "unknown argument %s\n", option.data()); + usage(); + } + } + + if (image_filename == NULL) { + fprintf(stderr, "--image file name not specified\n"); + return EXIT_FAILURE; + } + + if (boot_image_option.empty()) { + if (image_base == 0) { + fprintf(stderr, "non-zero --base not specified\n"); + return EXIT_FAILURE; + } + } else { + if (boot_dex_filenames.empty()) { + fprintf(stderr, "no --boot-dex-file specified with --boot\n"); + return EXIT_FAILURE; + } + } + + std::vector<const DexFile*> dex_files; + OpenDexFiles(dex_filenames, dex_files); + + std::vector<const DexFile*> boot_dex_files; + OpenDexFiles(boot_dex_filenames, boot_dex_files); + + Runtime::Options options; + if (boot_image_option.empty()) { + options.push_back(std::make_pair("bootclasspath", &dex_files)); + } 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))); + } + UniquePtr<Runtime> runtime(Runtime::Create(options, false)); + if (runtime.get() == NULL) { + fprintf(stderr, "could not create runtime\n"); + return EXIT_FAILURE; + } + ClassLinker* class_linker = runtime->GetClassLinker(); + + // If we have an existing boot image, position new space after it + 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); + } + + // ClassLoader creation needs to come after Runtime::Create + const ClassLoader* class_loader; + if (boot_image_option.empty()) { + class_loader = NULL; + } else { + for (size_t i = 0; i < dex_files.size(); i++) { + class_linker->RegisterDexFile(*dex_files[i]); + } + class_loader = PathClassLoader::Alloc(dex_files); + } + + Compiler compiler; + if (method_names.empty()) { + compiler.CompileAll(class_loader); + } else { + for (size_t i = 0; i < method_names.size(); i++) { + // names are actually class_descriptor + name + signature. + // example: Ljava/lang/Object;<init>()V + StringPiece method_name = method_names[i]; + size_t end_of_class_descriptor = method_name.find(';'); + if (end_of_class_descriptor == method_name.npos) { + fprintf(stderr, "could not find class descriptor in method %s\n", method_name.data()); + return EXIT_FAILURE; + } + end_of_class_descriptor++; // want to include ; + std::string class_descriptor = method_name.substr(0, end_of_class_descriptor).ToString(); + size_t end_of_name = method_name.find('(', end_of_class_descriptor); + if (end_of_name == method_name.npos) { + fprintf(stderr, "could not find start of method signature in method %s\n", method_name.data()); + return EXIT_FAILURE; + } + std::string name = method_name.substr(end_of_class_descriptor, + end_of_name - end_of_class_descriptor).ToString(); + std::string signature = method_name.substr(end_of_name).ToString(); + + Class* klass = class_linker->FindClass(class_descriptor, class_loader); + if (klass == NULL) { + fprintf(stderr, "could not find class for descriptor %s in method %s\n", + class_descriptor.c_str(), method_name.data()); + return EXIT_FAILURE; + } + Method* method = klass->FindDirectMethod(name, signature); + if (method == NULL) { + method = klass->FindVirtualMethod(name, signature); + } + if (method == NULL) { + fprintf(stderr, "could not find method %s with signature %s in class %s for method argument %s\n", + name.c_str(), + signature.c_str(), + class_descriptor.c_str(), + method_name.data()); + return EXIT_FAILURE; + } + compiler.CompileOne(method); + } + } + + ImageWriter writer; + if (!writer.Write(image_filename, image_base)) { + fprintf(stderr, "could not write image %s\n", image_filename); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +} // namespace art + +int main(int argc, char** argv) { + return art::dex2oat(argc, argv); +} diff --git a/src/dex_cache.h b/src/dex_cache.h index 804f68064a..22dae24ddf 100644 --- a/src/dex_cache.h +++ b/src/dex_cache.h @@ -12,31 +12,32 @@ namespace art { class Class; class Field; +class ImageWriter; class Method; class String; union JValue; class CodeAndDirectMethods : public IntArray { public: - Method* GetResolvedCode(uint32_t method_idx) const { - return reinterpret_cast<Method*>(Get(method_idx * kMax + kCode)); + void* GetResolvedCode(uint32_t method_idx) const { + return reinterpret_cast<byte*>(Get(CodeIndex(method_idx))); } - void* GetResolvedMethod(uint32_t method_idx) const { - return reinterpret_cast<byte*>(Get(method_idx * kMax + kMethod)); + Method* GetResolvedMethod(uint32_t method_idx) const { + return reinterpret_cast<Method*>(Get(MethodIndex(method_idx))); } void SetResolvedDirectMethodTrampoline(uint32_t method_idx) { UNIMPLEMENTED(WARNING) << "need to install a trampoline to resolve the method_idx at runtime"; - Set(method_idx * kMax + kCode, 0xffffffff); - Set(method_idx * kMax + kMethod, method_idx); + Set(CodeIndex(method_idx), 0xffffffff); + Set(MethodIndex(method_idx), method_idx); } void SetResolvedDirectMethod(uint32_t method_idx, Method* method) { CHECK(method != NULL); CHECK(method->IsDirect()); // CHECK(method->GetCode() != NULL); // TODO enable when all code is compiling - Set(method_idx * kMax + kCode, reinterpret_cast<int32_t>(method->GetCode())); - Set(method_idx * kMax + kMethod, reinterpret_cast<int32_t>(method)); + Set(CodeIndex(method_idx), reinterpret_cast<int32_t>(method->GetCode())); + Set(MethodIndex(method_idx), reinterpret_cast<int32_t>(method)); } static size_t LengthAsArray(size_t elements) { @@ -45,14 +46,12 @@ class CodeAndDirectMethods : public IntArray { // Offset of resolved method entry from start of code_and_direct_methods_ static size_t MethodOffsetInBytes(uint32_t method_idx) { - return ((method_idx * kMax + kMethod) * sizeof(ElementType) + - Array::DataOffset().Int32Value()); + return (MethodIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value()); } // Offset of resolved method's code_ from start of code_and_direct_methods_ static size_t CodeOffsetInBytes(uint32_t method_idx) { - return ((method_idx * kMax + kCode) * sizeof(ElementType) + - Array::DataOffset().Int32Value()); + return (CodeIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value()); } size_t NumCodeAndDirectMethods() const { @@ -66,6 +65,17 @@ class CodeAndDirectMethods : public IntArray { kMax = 2, }; + static size_t CodeIndex(uint32_t method_idx) { + return method_idx * kMax + kCode; + } + static size_t MethodIndex(uint32_t method_idx) { + return method_idx * kMax + kMethod; + } + + // grant friend status to ImageWriter fixup code that needs to know internal layout + friend class ImageWriter; + + DISALLOW_IMPLICIT_CONSTRUCTORS(CodeAndDirectMethods); }; class DexCache : public ObjectArray<Object> { @@ -197,6 +207,12 @@ class DexCache : public ObjectArray<Object> { DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache); }; +struct DexCacheHash { + size_t operator()(art::DexCache* const& obj) const { + return reinterpret_cast<size_t>(&obj); + } +}; + } // namespace art #endif // ART_SRC_DEX_CACHE_H_ diff --git a/src/dex_file.cc b/src/dex_file.cc index ad0b3b967b..b982291362 100644 --- a/src/dex_file.cc +++ b/src/dex_file.cc @@ -42,6 +42,19 @@ DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor, reinterpret_cast<const DexFile::ClassDef*>(NULL)); } +const DexFile* DexFile::Open(const std::string& filename) { + if (filename.size() < 4) { + LOG(WARNING) << "Ignoring short classpath entry '" << filename << "'"; + return NULL; + } + std::string suffix(filename.substr(filename.size() - 4)); + if (suffix == ".zip" || suffix == ".jar" || suffix == ".apk") { + return DexFile::OpenZip(filename); + } else { + return DexFile::OpenFile(filename); + } +} + DexFile::Closer::~Closer() {} DexFile::MmapCloser::MmapCloser(void* addr, size_t length) : addr_(addr), length_(length) { @@ -89,7 +102,7 @@ class LockedFd { static LockedFd* CreateAndLock(std::string& name, mode_t mode) { int fd = open(name.c_str(), O_CREAT | O_RDWR, mode); if (fd == -1) { - PLOG(ERROR) << "Can't open file '" << name << "'"; + PLOG(ERROR) << "Failed to open file '" << name << "'"; return NULL; } fchmod(fd, mode); @@ -101,7 +114,7 @@ class LockedFd { result = flock(fd, LOCK_EX); } if (result == -1 ) { - PLOG(ERROR) << "Can't lock file '" << name << "'"; + PLOG(ERROR) << "Failed to lock file '" << name << "'"; close(fd); return NULL; } @@ -149,6 +162,7 @@ const DexFile* DexFile::OpenZip(const std::string& filename) { size_t found = adjacent_dex_filename.find_last_of("."); if (found == std::string::npos) { LOG(WARNING) << "No . in filename" << filename; + return NULL; } adjacent_dex_filename.replace(adjacent_dex_filename.begin() + found, adjacent_dex_filename.end(), @@ -168,7 +182,7 @@ const DexFile* DexFile::OpenZip(const std::string& filename) { char resolved[PATH_MAX]; char* absolute_path = realpath(filename.c_str(), resolved); if (absolute_path == NULL) { - LOG(WARNING) << "Could not create absolute path for " << filename + LOG(WARNING) << "Failed to create absolute path for " << filename << " when looking for classes.dex"; return NULL; } @@ -180,7 +194,7 @@ const DexFile* DexFile::OpenZip(const std::string& filename) { const char* data_root = getenv("ANDROID_DATA"); if (data_root == NULL) { - data_root = "/data"; + data_root = "/data"; } std::string cache_path_tmp = StringPrintf("%s/art-cache/%s", data_root, cache_file.c_str()); @@ -188,12 +202,12 @@ const DexFile* DexFile::OpenZip(const std::string& filename) { UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename)); if (zip_archive.get() == NULL) { - LOG(WARNING) << "Could not open " << filename << " when looking for classes.dex"; + LOG(WARNING) << "Failed to open " << filename << " when looking for classes.dex"; return NULL; } UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex)); if (zip_entry.get() == NULL) { - LOG(WARNING) << "Could not find classes.dex within " << filename; + LOG(WARNING) << "Failed to find classes.dex within " << filename; return NULL; } @@ -235,7 +249,7 @@ const DexFile* DexFile::OpenZip(const std::string& filename) { struct stat fd_stat; int fd_stat_result = fstat(fd->GetFd(), &fd_stat); if (fd_stat_result == -1) { - PLOG(ERROR) << "Can't stat open file '" << cache_path_tmp << "'"; + PLOG(ERROR) << "Failed to stat open file '" << cache_path_tmp << "'"; return NULL; } struct stat file_stat; @@ -287,7 +301,7 @@ const DexFile* DexFile::OpenZip(const std::string& filename) { } int rename_result = rename(cache_path_tmp.c_str(), cache_path.c_str()); if (rename_result == -1) { - PLOG(ERROR) << "Can't install dex cache file '" << cache_path << "'" + PLOG(ERROR) << "Failed to install dex cache file '" << cache_path << "'" << " from '" << cache_path_tmp << "'"; unlink(cache_path.c_str()); } diff --git a/src/dex_file.h b/src/dex_file.h index 73e6954746..98e79a7ed5 100644 --- a/src/dex_file.h +++ b/src/dex_file.h @@ -316,6 +316,9 @@ class DexFile { static ClassPathEntry FindInClassPath(const StringPiece& descriptor, const ClassPath& class_path); + // Opens .dex file, guessing the format based on file extension + static const DexFile* Open(const std::string& filename); + // Opens a .dex file from the file system. static const DexFile* OpenFile(const std::string& filename); diff --git a/src/exception_test.cc b/src/exception_test.cc index 439e7edd54..5283697d21 100644 --- a/src/exception_test.cc +++ b/src/exception_test.cc @@ -68,7 +68,7 @@ class ExceptionTest : public CommonTest { dex_.reset(OpenDexFileBase64(kMyClassExceptionHandleDex, "kMyClassExceptionHandleDex")); ASSERT_TRUE(dex_.get() != NULL); - const PathClassLoader* class_loader = AllocPathClassLoader(dex_.get()); + const ClassLoader* class_loader = AllocPathClassLoader(dex_.get()); ASSERT_TRUE(class_loader != NULL); my_klass_ = class_linker_->FindClass("Ljava/lang/MyClass;", class_loader); ASSERT_TRUE(my_klass_ != NULL); diff --git a/src/heap.cc b/src/heap.cc index be3d154408..86d19a8170 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -37,7 +37,9 @@ MemberOffset Heap::reference_queueNext_offset_ = MemberOffset(0); MemberOffset Heap::reference_pendingNext_offset_ = MemberOffset(0); MemberOffset Heap::finalizer_reference_zombie_offset_ = MemberOffset(0); -bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image_file_name) { +bool Heap::Init(size_t initial_size, size_t maximum_size, + const char* boot_image_file_name, + std::vector<const char*>& image_file_names) { Space* boot_space; byte* requested_base; if (boot_image_file_name == NULL) { @@ -46,14 +48,28 @@ bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image } else { boot_space = Space::Create(boot_image_file_name); if (boot_space == NULL) { + LOG(WARNING) << "Failed to create space from " << boot_image_file_name; return false; } spaces_.push_back(boot_space); requested_base = boot_space->GetBase() + RoundUp(boot_space->Size(), kPageSize); } + std::vector<Space*> image_spaces; + for (size_t i = 0; i < image_file_names.size(); i++) { + Space* space = Space::Create(image_file_names[i]); + if (space == NULL) { + LOG(WARNING) << "Failed to create space from " << image_file_names[i]; + return false; + } + image_spaces.push_back(space); + spaces_.push_back(space); + requested_base = space->GetBase() + RoundUp(space->Size(), kPageSize); + } + Space* space = Space::Create(initial_size, maximum_size, requested_base); if (space == NULL) { + LOG(WARNING) << "Failed to create alloc space"; return false; } @@ -68,12 +84,14 @@ bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image // Allocate the initial live bitmap. UniquePtr<HeapBitmap> live_bitmap(HeapBitmap::Create(base, num_bytes)); if (live_bitmap.get() == NULL) { + LOG(WARNING) << "Failed to create live bitmap"; return false; } // Allocate the initial mark bitmap. UniquePtr<HeapBitmap> mark_bitmap(HeapBitmap::Create(base, num_bytes)); if (mark_bitmap.get() == NULL) { + LOG(WARNING) << "Failed to create mark bitmap"; return false; } @@ -93,6 +111,9 @@ bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image boot_space_ = boot_space; RecordImageAllocations(boot_space); } + for (size_t i = 0; i < image_spaces.size(); i++) { + RecordImageAllocations(image_spaces[i]); + } return true; } diff --git a/src/heap.h b/src/heap.h index 30133b7fb4..492220743a 100644 --- a/src/heap.h +++ b/src/heap.h @@ -27,9 +27,12 @@ class Heap { typedef void (RootVisitor)(const Object* root, void* arg); - // Create a heap with the requested sizes. optional boot image may + // Create a heap with the requested sizes. The optional boot image may // be NULL, otherwise it is an image filename created by ImageWriter. - static bool Init(size_t starting_size, size_t maximum_size, const char* boot_image_file_name); + // image_file_names specifies application images to load. + static bool Init(size_t starting_size, size_t maximum_size, + const char* boot_image_file_name, + std::vector<const char*>& image_file_names); static void Destroy(); @@ -149,6 +152,7 @@ class Heap { static std::vector<Space*> spaces_; // Space loaded from an image + // TODO: remove after intern_addr is removed static Space* boot_space_; // default Space for allocations diff --git a/src/image.cc b/src/image.cc index a41bf5ba14..5bf7b10fcb 100644 --- a/src/image.cc +++ b/src/image.cc @@ -4,7 +4,7 @@ namespace art { -const byte ImageHeader::kImageMagic[] = { 'i', 'm', 'g', '\n' }; +const byte ImageHeader::kImageMagic[] = { 'o', 'a', 't', '\n' }; const byte ImageHeader::kImageVersion[] = { '0', '0', '1', '\0' }; } // namespace art diff --git a/src/image.h b/src/image.h index 94824d799c..00f72bad20 100644 --- a/src/image.h +++ b/src/image.h @@ -50,6 +50,7 @@ class ImageHeader { uint32_t base_addr_; // absolute address of an Object[] of Strings to InternTable::RegisterStrong. + // TODO: remove after interning all Strings in image uint32_t intern_addr_; }; diff --git a/src/image_test.cc b/src/image_test.cc index db09021322..f07588a78a 100644 --- a/src/image_test.cc +++ b/src/image_test.cc @@ -25,15 +25,10 @@ TEST_F(ImageTest, WriteRead) { } // TODO: Heap::CollectGarbage before writing - const std::vector<Space*>& spaces = Heap::GetSpaces(); - // can't currently deal with writing a space that might have pointers between spaces - ASSERT_EQ(1U, spaces.size()); - Space* space = spaces[0]; - ImageWriter writer; ScratchFile tmp; - const int image_base = 0x50000000; - bool success = writer.Write(space, tmp.GetFilename(), reinterpret_cast<byte*>(image_base)); + const uintptr_t image_base = 0x50000000; + bool success = writer.Write(tmp.GetFilename(), image_base); ASSERT_TRUE(success); { @@ -42,6 +37,10 @@ TEST_F(ImageTest, WriteRead) { ImageHeader image_header; file->ReadFully(&image_header, sizeof(image_header)); ASSERT_TRUE(image_header.IsValid()); + + ASSERT_EQ(1U, Heap::GetSpaces().size()); + Space* space = Heap::GetSpaces()[0]; + ASSERT_TRUE(space != NULL); ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length())); } @@ -69,7 +68,7 @@ TEST_F(ImageTest, WriteRead) { class_linker_ = runtime_->GetClassLinker(); ASSERT_EQ(2U, Heap::GetSpaces().size()); - Space* boot_space = Heap::GetSpaces()[0]; + Space* boot_space = Heap::GetBootSpace(); ASSERT_TRUE(boot_space != NULL); // enable to display maps to debug boot_base and boot_limit checking problems below @@ -87,6 +86,7 @@ TEST_F(ImageTest, WriteRead) { EXPECT_TRUE(klass != NULL) << descriptor; EXPECT_LT(boot_base, reinterpret_cast<byte*>(klass)) << descriptor; EXPECT_LT(reinterpret_cast<byte*>(klass), boot_limit) << descriptor; + EXPECT_TRUE(klass->GetMonitor() == NULL); // address should have been removed from monitor } } diff --git a/src/image_writer.cc b/src/image_writer.cc index e0e77c70d3..a49b261834 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc @@ -23,9 +23,16 @@ namespace art { -bool ImageWriter::Write(Space* space, const char* filename, byte* image_base) { - image_base_ = image_base; - if (!Init(space)) { +bool ImageWriter::Write(const char* filename, uintptr_t image_base) { + CHECK_NE(image_base, 0U); + image_base_ = reinterpret_cast<byte*>(image_base); + + const std::vector<Space*>& spaces = Heap::GetSpaces(); + // currently just write the last space, assuming it is the space that was being used for allocation + CHECK_GE(spaces.size(), 1U); + source_space_ = spaces[spaces.size()-1]; + + if (!Init()) { return false; } CalculateNewObjectOffsets(); @@ -38,8 +45,8 @@ bool ImageWriter::Write(Space* space, const char* filename, byte* image_base) { return file->WriteFully(image_->GetAddress(), image_top_); } -bool ImageWriter::Init(Space* space) { - size_t size = space->Size(); +bool ImageWriter::Init() { + size_t size = source_space_->Size(); int prot = PROT_READ | PROT_WRITE; size_t length = RoundUp(size, kPageSize); image_.reset(MemMap::Map(length, prot)); @@ -88,9 +95,23 @@ void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void *arg) { DCHECK(obj != NULL); DCHECK(arg != NULL); ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg); + if (!image_writer->InSourceSpace(obj)) { + return; + } image_writer->SetImageOffset(obj, image_writer->image_top_); image_writer->image_top_ += RoundUp(obj->SizeOf(), 8); // 64-bit alignment DCHECK_LT(image_writer->image_top_, image_writer->image_->GetLength()); + + // sniff out the DexCaches on this pass for use on the next pass + if (obj->IsClass()) { + Class* klass = obj->AsClass(); + DexCache* dex_cache = klass->GetDexCache(); + if (dex_cache != NULL) { + image_writer->dex_caches_.insert(dex_cache); + } else { + DCHECK(klass->IsArrayClass() || klass->IsPrimitive()); + } + } } void ImageWriter::CalculateNewObjectOffsets() { @@ -104,7 +125,7 @@ void ImageWriter::CalculateNewObjectOffsets() { // know where interned_array is going to end up image_top_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment - heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this); + heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this); // TODO: add Space-limited Walk DCHECK_LT(image_top_, image_->GetLength()); // return to write header at start of image with future location of interned_array @@ -120,7 +141,8 @@ void ImageWriter::CopyAndFixupObjects() { DCHECK(heap_bitmap != NULL); // TODO: heap validation can't handle this fix up pass Heap::DisableObjectValidation(); - heap_bitmap->Walk(CopyAndFixupObjectsCallback, this); + heap_bitmap->Walk(CopyAndFixupObjectsCallback, this); // TODO: add Space-limited Walk + FixupDexCaches(); } void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void *arg) { @@ -128,7 +150,11 @@ void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void *arg) { DCHECK(arg != NULL); const Object* obj = object; ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg); + if (!image_writer->InSourceSpace(object)) { + return; + } + // see GetLocalAddress for similar computation size_t offset = image_writer->GetImageOffset(obj); byte* dst = image_writer->image_->GetAddress() + offset; const byte* src = reinterpret_cast<const byte*>(obj); @@ -136,6 +162,7 @@ void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void *arg) { DCHECK_LT(offset + n, image_writer->image_->GetLength()); memcpy(dst, src, n); Object* copy = reinterpret_cast<Object*>(dst); + ResetImageOffset(copy); image_writer->FixupObject(obj, copy); } @@ -178,20 +205,36 @@ void ImageWriter::FixupClass(const Class* orig, Class* copy) { FixupStaticFields(orig, copy); } +const void* FixupCode(const ByteArray* copy_code_array, const void* orig_code) { + // TODO: change to DCHECK when all code compiling + if (copy_code_array == NULL) { + return NULL; + } + const void* copy_code = copy_code_array->GetData(); + // TODO: remember InstructionSet with each code array so we know if we need to do thumb fixup? + if ((reinterpret_cast<uintptr_t>(orig_code) % 2) == 1) { + return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(copy_code) + 1); + } + return copy_code; +} + // TODO: remove this slow path void ImageWriter::FixupMethod(const Method* orig, Method* copy) { FixupInstanceFields(orig, copy); // TODO: remove need for this by adding "signature" to java.lang.reflect.Method copy->signature_ = down_cast<String*>(GetImageAddress(orig->signature_)); DCHECK(copy->signature_ != NULL); + // TODO: convert shorty_ to heap allocated storage copy->dex_cache_strings_ = down_cast<ObjectArray<String>*>(GetImageAddress(orig->dex_cache_strings_)); copy->dex_cache_resolved_types_ = down_cast<ObjectArray<Class>*>(GetImageAddress(orig->dex_cache_resolved_types_)); copy->dex_cache_resolved_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->dex_cache_resolved_methods_)); copy->dex_cache_resolved_fields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->dex_cache_resolved_fields_)); copy->dex_cache_code_and_direct_methods_ = down_cast<CodeAndDirectMethods*>(GetImageAddress(orig->dex_cache_code_and_direct_methods_)); copy->dex_cache_initialized_static_storage_ = down_cast<ObjectArray<StaticStorageBase>*>(GetImageAddress(orig->dex_cache_initialized_static_storage_)); - - // TODO: convert shorty_ to heap allocated storage + copy->code_array_ = down_cast<ByteArray*>(GetImageAddress(orig->code_array_)); + copy->code_ = FixupCode(copy->code_array_, orig->code_); + copy->invoke_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig->invoke_stub_array_)); + copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_))); } void ImageWriter::FixupField(const Field* orig, Field* copy) { @@ -262,4 +305,34 @@ void ImageWriter::FixupFields(const Object* orig, } } +void ImageWriter::FixupDexCaches() { + typedef Set::const_iterator It; // TODO: C++0x auto + for (It it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) { + DexCache* orig = *it; + DexCache* copy = down_cast<DexCache*>(GetLocalAddress(orig)); + FixupDexCache(orig, copy); + } +} + +void ImageWriter::FixupDexCache(const DexCache* orig, DexCache* copy) { + CHECK(orig != NULL); + CHECK(copy != NULL); + + CodeAndDirectMethods* orig_cadms = orig->GetCodeAndDirectMethods(); + CodeAndDirectMethods* copy_cadms = down_cast<CodeAndDirectMethods*>(GetLocalAddress(orig_cadms)); + for (size_t i = 0; i < orig->NumResolvedMethods(); i++) { + Method* orig_method = orig->GetResolvedMethod(i); + // if it was resolved in the original, resolve it in the copy + if (orig_method != NULL + && InSourceSpace(orig_method) + && orig_method == orig_cadms->GetResolvedMethod(i)) { + Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method)); + copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), + reinterpret_cast<int32_t>(copy_method->code_)); + copy_cadms->Set(CodeAndDirectMethods::MethodIndex(i), + reinterpret_cast<int32_t>(GetImageAddress(orig_method))); + } + } +} + } // namespace art diff --git a/src/image_writer.h b/src/image_writer.h index b63effeb36..3352adbde9 100644 --- a/src/image_writer.h +++ b/src/image_writer.h @@ -8,6 +8,7 @@ #include <cstddef> #include "UniquePtr.h" +#include "dex_cache.h" #include "mem_map.h" #include "object.h" #include "os.h" @@ -19,33 +20,53 @@ namespace art { class ImageWriter { public: - ImageWriter() : image_top_(0), image_base_(NULL) {}; - bool Write(Space* space, const char* filename, byte* image_base); + ImageWriter() : source_space_(NULL), image_top_(0), image_base_(NULL) {}; + bool Write(const char* filename, uintptr_t image_base); ~ImageWriter() {}; private: - bool Init(Space* space); + bool Init(); // we use the lock word to store the offset of the object in the image - void SetImageOffset(Object* object, size_t offset) { + static void SetImageOffset(Object* object, size_t offset) { DCHECK(object != NULL); DCHECK(object->GetMonitor() == NULL); // should be no lock DCHECK_NE(0U, offset); object->SetMonitor(reinterpret_cast<Monitor*>(offset)); } - size_t GetImageOffset(const Object* object) { + static size_t GetImageOffset(const Object* object) { DCHECK(object != NULL); size_t offset = reinterpret_cast<size_t>(object->GetMonitor()); DCHECK_NE(0U, offset); return offset; } + static void ResetImageOffset(Object* object) { + DCHECK(object != NULL); + DCHECK(object->GetMonitor() != NULL); // should be an offset + object->SetMonitor(reinterpret_cast<Monitor*>(0)); + } + + bool InSourceSpace(const Object* object) { + DCHECK(source_space_ != NULL); + const byte* o = reinterpret_cast<const byte*>(object); + return (o >= source_space_->GetBase() && o < source_space_->GetLimit()); + } Object* GetImageAddress(const Object* object) { if (object == NULL) { return NULL; } + // if object outside the relocating source_space_, assume unchanged + if (!InSourceSpace(object)) { + return const_cast<Object*>(object); + } return reinterpret_cast<Object*>(image_base_ + GetImageOffset(object)); } + Object* GetLocalAddress(const Object* object) { + size_t offset = GetImageOffset(object); + byte* dst = image_->GetAddress() + offset; + return reinterpret_cast<Object*>(dst); + } void CalculateNewObjectOffsets(); static void CalculateNewObjectOffsetsCallback(Object* obj, void *arg); @@ -61,6 +82,12 @@ class ImageWriter { void FixupStaticFields(const Class* orig, Class* copy); void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static); + void FixupDexCaches(); + void FixupDexCache(const DexCache* orig, DexCache* copy); + + // Space we are writing objects from + const Space* source_space_; + // memory mapped for generating the image UniquePtr<MemMap> image_; @@ -69,6 +96,10 @@ class ImageWriter { // Target base address for the output image byte* image_base_; + + // DexCaches seen while scanning for fixing up CodeAndDirectMethods + typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set; + Set dex_caches_; }; } // namespace art diff --git a/src/jni_internal.cc b/src/jni_internal.cc index a75a365e6a..bd1ccecdb2 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -207,6 +207,7 @@ JValue InvokeWithArgArray(ScopedJniThreadState& ts, Object* receiver, // Pass everything as arguments const Method::InvokeStub* stub = method->GetInvokeStub(); JValue result; + if (method->HasCode() && stub != NULL) { (*stub)(method, receiver, self, args, &result); } else { @@ -2566,11 +2567,11 @@ extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, void** p_env, void* vm_args) { Runtime* runtime = Runtime::Create(options, ignore_unrecognized); if (runtime == NULL) { return JNI_ERR; - } else { - *p_env = Thread::Current()->GetJniEnv(); - *p_vm = runtime->GetJavaVM(); - return JNI_OK; } + runtime->Start(); + *p_env = Thread::Current()->GetJniEnv(); + *p_vm = runtime->GetJavaVM(); + return JNI_OK; } extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize, jsize* vm_count) { diff --git a/src/main.cc b/src/oatexec.cc index 229135c5c5..ca976afbf6 100644 --- a/src/main.cc +++ b/src/oatexec.cc @@ -29,6 +29,7 @@ static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) { fprintf(stderr, "Unable to find class Method\n"); return false; } +#if 0 // TODO: try restoring once iftable_ moved to managed heap jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I"); @@ -36,6 +37,7 @@ static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) { fprintf(stderr, "Unable to find reflect.Method.getModifiers\n"); return false; } +#endif static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC #if 0 // CallIntMethod not yet implemented int modifiers = env->CallIntMethod(reflected.get(), get_modifiers); diff --git a/src/object.cc b/src/object.cc index 5d99cb6a74..f92f746a7a 100644 --- a/src/object.cc +++ b/src/object.cc @@ -1047,7 +1047,8 @@ bool String::Equals(const char* modified_utf8) const { } bool String::Equals(const StringPiece& modified_utf8) const { - // TODO: do not assume C-string representation. + // TODO: do not assume C-string representation. For now DCHECK. + DCHECK_EQ(modified_utf8.data()[modified_utf8.size()], 0); return Equals(modified_utf8.data()); } diff --git a/src/object.h b/src/object.h index fa09782e23..9b3bf88528 100644 --- a/src/object.h +++ b/src/object.h @@ -2494,7 +2494,6 @@ inline const String* Field::GetName() const { inline void Field::SetName(String* new_name) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, name_), new_name, false); - } inline uint32_t Field::GetAccessFlags() const { @@ -2602,6 +2601,12 @@ inline uint32_t Method::GetProtoIdx() const { // C++ mirror of java.lang.Throwable class Throwable : public Object { + public: + void SetDetailMessage(String* new_detail_message) { + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), + new_detail_message, false); + } + private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". Throwable* cause_; diff --git a/src/runtime.cc b/src/runtime.cc index 2891e56f0b..2c2c5e2750 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -149,42 +149,35 @@ void LoadJniLibrary(JavaVMExt* vm, const char* name) { } } -const DexFile* Open(const std::string& filename) { - if (filename.size() < 4) { - LOG(WARNING) << "Ignoring short classpath entry '" << filename << "'"; - return NULL; - } - std::string suffix(filename.substr(filename.size() - 4)); - if (suffix == ".zip" || suffix == ".jar" || suffix == ".apk") { - return DexFile::OpenZip(filename); - } else { - return DexFile::OpenFile(filename); - } -} - -void CreateBootClassPath(const char* boot_class_path_cstr, - std::vector<const DexFile*>& boot_class_path_vector) { - CHECK(boot_class_path_cstr != NULL); +void CreateClassPath(const char* class_path_cstr, + std::vector<const DexFile*>& class_path_vector) { + CHECK(class_path_cstr != NULL); std::vector<std::string> parsed; - Split(boot_class_path_cstr, ':', parsed); + Split(class_path_cstr, ':', parsed); for (size_t i = 0; i < parsed.size(); ++i) { - const DexFile* dex_file = Open(parsed[i]); + const DexFile* dex_file = DexFile::Open(parsed[i]); if (dex_file != NULL) { - boot_class_path_vector.push_back(dex_file); + class_path_vector.push_back(dex_file); } } } Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, bool ignore_unrecognized) { UniquePtr<ParsedOptions> parsed(new ParsedOptions()); - const char* boot_class_path = getenv("BOOTCLASSPATH"); + const char* boot_class_path = NULL; + const char* class_path = NULL; parsed->boot_image_ = NULL; #ifdef NDEBUG // -Xcheck:jni is off by default for regular builds... parsed->check_jni_ = false; #else // ...but on by default in debug builds. +#if 0 // TODO: disabled for oatexec until the shorty's used by check_jni are managed heap allocated. + // Instead we turn on -Xcheck_jni in common_test. parsed->check_jni_ = true; +#else + parsed->check_jni_ = false; +#endif #endif parsed->heap_initial_size_ = Heap::kInitialSize; parsed->heap_maximum_size_ = Heap::kMaximumSize; @@ -207,12 +200,25 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b continue; } // TODO: usage - LOG(FATAL) << "Could not parse " << option; + LOG(FATAL) << "Failed to parse " << option; return NULL; } parsed->boot_class_path_ = *v; + } else if (option == "-classpath" || option == "-cp") { + // TODO: support -Djava.class.path + i++; + if (i == options.size()) { + // TODO: usage + LOG(FATAL) << "Missing required class path value for " << option; + return NULL; + } + const StringPiece& value = options[i].first; + class_path = value.data(); } else if (option.starts_with("-Xbootimage:")) { + // TODO: remove when intern_addr_ is removed, just use -Ximage: parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data(); + } else if (option.starts_with("-Ximage:")) { + parsed->images_.push_back(option.substr(strlen("-Ximage:")).data()); } else if (option.starts_with("-Xcheck:jni")) { parsed->check_jni_ = true; } else if (option.starts_with("-Xms")) { @@ -222,7 +228,7 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b continue; } // TODO: usage - LOG(FATAL) << "Could not parse " << option; + LOG(FATAL) << "Failed to parse " << option; return NULL; } parsed->heap_initial_size_ = size; @@ -233,7 +239,7 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b continue; } // TODO: usage - LOG(FATAL) << "Could not parse " << option; + LOG(FATAL) << "Failed to parse " << option; return NULL; } parsed->heap_maximum_size_ = size; @@ -244,7 +250,7 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b continue; } // TODO: usage - LOG(FATAL) << "Could not parse " << option; + LOG(FATAL) << "Failed to parse " << option; return NULL; } parsed->stack_size_ = size; @@ -273,19 +279,33 @@ Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, b } } - if (boot_class_path == NULL) { - boot_class_path = ""; + // consider it an error if both bootclasspath and -Xbootclasspath: are supplied. + // TODO: remove bootclasspath which is only mostly just used by tests? + if (!parsed->boot_class_path_.empty() && boot_class_path != NULL) { + // TODO: usage + LOG(FATAL) << "bootclasspath and -Xbootclasspath: are mutually exclusive options."; + return NULL; } - if (parsed->boot_class_path_.size() == 0) { - CreateBootClassPath(boot_class_path, parsed->boot_class_path_); + if (parsed->boot_class_path_.empty()) { + if (boot_class_path == NULL) { + boot_class_path = getenv("BOOTCLASSPATH"); + if (boot_class_path == NULL) { + boot_class_path = ""; + } + } + CreateClassPath(boot_class_path, parsed->boot_class_path_); } - return parsed.release(); -} -Runtime* Runtime::Create(const std::vector<const DexFile*>& boot_class_path) { - Runtime::Options options; - options.push_back(std::make_pair("bootclasspath", &boot_class_path)); - return Runtime::Create(options, false); + if (class_path == NULL) { + class_path = getenv("CLASSPATH"); + if (class_path == NULL) { + class_path = ""; + } + } + CHECK_EQ(parsed->class_path_.size(), 0U); + CreateClassPath(class_path, parsed->class_path_); + + return parsed.release(); } Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) { @@ -299,11 +319,12 @@ Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) { return NULL; } instance_ = runtime.release(); + return instance_; +} +void Runtime::Start() { instance_->InitLibraries(); instance_->signal_catcher_ = new SignalCatcher; - - return instance_; } bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { @@ -311,6 +332,7 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { UniquePtr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized)); if (options.get() == NULL) { + LOG(WARNING) << "Failed to parse options"; return false; } vfprintf_ = options->hook_vfprintf_; @@ -324,7 +346,9 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { if (!Heap::Init(options->heap_initial_size_, options->heap_maximum_size_, - options->boot_image_)) { + options->boot_image_, + options->images_)) { + LOG(WARNING) << "Failed to create heap"; return false; } @@ -333,12 +357,16 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { java_vm_ = new JavaVMExt(this, options.get()); if (!Thread::Startup()) { + LOG(WARNING) << "Failed to startup threads"; return false; } thread_list_->Register(Thread::Attach(this)); - class_linker_ = ClassLinker::Create(options->boot_class_path_, intern_table_, Heap::GetBootSpace()); + class_linker_ = ClassLinker::Create(options->boot_class_path_, + options->class_path_, + intern_table_, + Heap::GetBootSpace()); return true; } diff --git a/src/runtime.h b/src/runtime.h index 4e00ec161d..8a6ffe3b51 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -40,7 +40,9 @@ class Runtime { static ParsedOptions* Create(const Options& options, bool ignore_unrecognized); std::vector<const DexFile*> boot_class_path_; + std::vector<const DexFile*> class_path_; const char* boot_image_; + std::vector<const char*> images_; bool check_jni_; std::string jni_trace_; size_t heap_initial_size_; @@ -62,7 +64,9 @@ class Runtime { // Creates and initializes a new runtime. static Runtime* Create(const Options& options, bool ignore_unrecognized); - static Runtime* Create(const std::vector<const DexFile*>& boot_class_path); + + // Starts a runtime, which may cause threads to be started and code to run. + void Start(); static Runtime* Current() { return instance_; @@ -115,7 +119,8 @@ class Runtime { private: static void PlatformAbort(const char*, int); - Runtime() : stack_size_(0), thread_list_(NULL), intern_table_(NULL), class_linker_(NULL) {} + Runtime() : stack_size_(0), thread_list_(NULL), intern_table_(NULL), class_linker_(NULL), + signal_catcher_(NULL) {} void BlockSignals(); diff --git a/src/runtime_test.cc b/src/runtime_test.cc index 65792c992f..66c181b72d 100644 --- a/src/runtime_test.cc +++ b/src/runtime_test.cc @@ -14,13 +14,22 @@ TEST_F(RuntimeTest, ParsedOptions) { void* test_abort = reinterpret_cast<void*>(0xb); void* test_exit = reinterpret_cast<void*>(0xc); void* null = reinterpret_cast<void*>(NULL); - std::vector<const DexFile*> boot_class_path; - boot_class_path.push_back(java_lang_dex_file_.get()); + + std::string lib_core = GetLibCoreDexFileName(); + + std::string boot_class_path; + boot_class_path += "-Xbootclasspath:"; + boot_class_path += lib_core; Runtime::Options options; - options.push_back(std::make_pair("-Xbootclasspath:class_path_foo:class_path_bar", null)); - options.push_back(std::make_pair("bootclasspath", &boot_class_path)); + options.push_back(std::make_pair(boot_class_path.c_str(), null)); + options.push_back(std::make_pair("-classpath", null)); + options.push_back(std::make_pair(lib_core.c_str(), null)); + options.push_back(std::make_pair("-cp", null)); + options.push_back(std::make_pair(lib_core.c_str(), null)); options.push_back(std::make_pair("-Xbootimage:boot_image", null)); + options.push_back(std::make_pair("-Ximage:image_1", null)); + options.push_back(std::make_pair("-Ximage:image_2", null)); options.push_back(std::make_pair("-Xcheck:jni", null)); options.push_back(std::make_pair("-Xms2048", null)); options.push_back(std::make_pair("-Xmx4k", null)); @@ -34,8 +43,12 @@ TEST_F(RuntimeTest, ParsedOptions) { UniquePtr<Runtime::ParsedOptions> parsed(Runtime::ParsedOptions::Create(options, false)); ASSERT_TRUE(parsed.get() != NULL); - EXPECT_EQ(1U, parsed->boot_class_path_.size()); // bootclasspath overrides -Xbootclasspath + EXPECT_EQ(1U, parsed->boot_class_path_.size()); + EXPECT_EQ(1U, parsed->class_path_.size()); EXPECT_STREQ("boot_image", parsed->boot_image_); + EXPECT_EQ(2U, parsed->images_.size()); + EXPECT_STREQ("image_1", parsed->images_[0]); + EXPECT_STREQ("image_2", parsed->images_[1]); EXPECT_EQ(true, parsed->check_jni_); EXPECT_EQ(2048U, parsed->heap_initial_size_); EXPECT_EQ(4 * KB, parsed->heap_maximum_size_); diff --git a/src/space.cc b/src/space.cc index 36eb1f6203..36e3cf2984 100644 --- a/src/space.cc +++ b/src/space.cc @@ -59,18 +59,25 @@ void* Space::CreateMallocSpace(void* base, bool Space::Init(size_t initial_size, size_t maximum_size, byte* requested_base) { if (!(initial_size <= maximum_size)) { + LOG(WARNING) << "Failed to create space with initial size > maximum size (" + << initial_size << ">" << maximum_size << ")"; return false; } size_t length = RoundUp(maximum_size, kPageSize); int prot = PROT_READ | PROT_WRITE; UniquePtr<MemMap> mem_map(MemMap::Map(requested_base, length, prot)); if (mem_map.get() == NULL) { + LOG(WARNING) << "Failed to allocate " << length << " bytes for space"; return false; } Init(mem_map.release()); maximum_size_ = maximum_size; mspace_ = CreateMallocSpace(base_, initial_size, maximum_size); - return (mspace_ != NULL); + if (mspace_ == NULL) { + LOG(WARNING) << "Failed to create mspace for space"; + return false; + } + return true; } void Space::Init(MemMap* mem_map) { @@ -83,17 +90,24 @@ void Space::Init(MemMap* mem_map) { bool Space::Init(const char* image_file_name) { UniquePtr<File> file(OS::OpenFile(image_file_name, false)); if (file.get() == NULL) { + LOG(WARNING) << "Failed to open " << image_file_name; return false; } ImageHeader image_header; bool success = file->ReadFully(&image_header, sizeof(image_header)); if (!success || !image_header.IsValid()) { + LOG(WARNING) << "Invalid image header " << image_file_name; return false; } UniquePtr<MemMap> map(MemMap::Map(image_header.GetBaseAddr(), - file->Length(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, - file->Fd(), 0)); + file->Length(), + // TODO: selectively PROT_EXEC when image contains a code space + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_FIXED, + file->Fd(), + 0)); if (map.get() == NULL) { + LOG(WARNING) << "Failed to map " << image_file_name; return false; } CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress()); diff --git a/test/HelloWorld/HelloWorld.java b/test/HelloWorld/HelloWorld.java new file mode 100644 index 0000000000..c6861ced7a --- /dev/null +++ b/test/HelloWorld/HelloWorld.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class HelloWorld { + public static void main(String[] args) { + System.logI("Hello, world!"); + } +} @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -aexec=aexec +oatexec=oatexec invoke_with= while true; do @@ -23,7 +23,7 @@ while true; do invoke_with="$1" shift elif [ "$1" = "-d" ]; then - aexec="aexecd" + oatexec="oatexecd" shift elif expr "$1" : "--" >/dev/null 2>&1; then echo "unknown option: $1" 1>&2 @@ -37,7 +37,7 @@ mkdir -p /tmp/android-data/art-cache ANDROID_DATA=/tmp/android-data \ ANDROID_ROOT=$ANDROID_BUILD_TOP/out/host/linux-x86 \ LD_LIBRARY_PATH=$ANDROID_BUILD_TOP/out/host/linux-x86/lib \ -$invoke_with $ANDROID_BUILD_TOP/out/host/linux-x86/bin/$aexec \ +$invoke_with $ANDROID_BUILD_TOP/out/host/linux-x86/bin/$oatexec \ -Xbootclasspath\ :$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-hostdex.jar\ :$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-junit-hostdex.jar\ |