Add --image-classes to dex2oat
Change-Id: Ia88f9d302e0f9cd72be2199ee46d212d99864c67
diff --git a/Android.mk b/Android.mk
index 3d50015..809ee85 100644
--- a/Android.mk
+++ b/Android.mk
@@ -199,7 +199,7 @@
$(eval $(call build-art-cache-oat,system/app/MusicFX.apk))
$(eval $(call build-art-cache-oat,system/app/NetSpeed.apk))
$(eval $(call build-art-cache-oat,system/app/NetworkLocation.apk))
-$(eval $(call build-art-cache-oat,system/app/NfcGoogle.apk))
+$(eval $(call build-art-cache-oat,system/app/Nfc.apk))
$(eval $(call build-art-cache-oat,system/app/OneTimeInitializer.apk))
$(eval $(call build-art-cache-oat,system/app/PackageInstaller.apk))
$(eval $(call build-art-cache-oat,system/app/Phone.apk))
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 4b0cdfe..2001c06 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -169,6 +169,7 @@
src/org_apache_harmony_dalvik_ddmc_DdmServer.cc \
src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \
src/os_linux.cc \
+ src/primitive.cc \
src/reference_table.cc \
src/reflection.cc \
src/runtime.cc \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 6d72ded..9ea9e81 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -32,6 +32,8 @@
IMG_HOST_BASE_ADDRESS := 0x60000000
IMG_TARGET_BASE_ADDRESS := 0x60000000
+PRELOADED_CLASSES := frameworks/base/preloaded-classes
+
########################################################################
# A smaller libcore only oat file
HOST_CORE_JARS := core-hostdex
@@ -50,13 +52,13 @@
@echo "host dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
@rm -f $@
- $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
+ $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
$(TARGET_CORE_OAT): $(TARGET_CORE_DEX) $(DEX2OAT_DEPENDENCY)
@echo "target dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
@rm -f $@
- $(hide) $(DEX2OAT) --runtime-arg -Xms32m --runtime-arg -Xmx32m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
+ $(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
$(HOST_CORE_IMG): $(HOST_CORE_OAT)
@@ -73,6 +75,6 @@
@echo "target dex2oat: $@ ($?)"
@mkdir -p $(dir $@)
@rm -f $@
- $(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
+ $(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
$(TARGET_BOOT_IMG): $(TARGET_BOOT_OAT)
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 4598ae9..266c1f0 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -184,22 +184,24 @@
DISALLOW_COPY_AND_ASSIGN(ObjectLock);
};
-ClassLinker* ClassLinker::Create(const std::string& boot_class_path,
+ClassLinker* ClassLinker::Create(bool verbose,
+ const std::string& boot_class_path,
InternTable* intern_table) {
CHECK_NE(boot_class_path.size(), 0U);
- UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
+ UniquePtr<ClassLinker> class_linker(new ClassLinker(verbose, intern_table));
class_linker->Init(boot_class_path);
return class_linker.release();
}
-ClassLinker* ClassLinker::Create(InternTable* intern_table) {
- UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
+ClassLinker* ClassLinker::Create(bool verbose, InternTable* intern_table) {
+ UniquePtr<ClassLinker> class_linker(new ClassLinker(verbose, intern_table));
class_linker->InitFromImage();
return class_linker.release();
}
-ClassLinker::ClassLinker(InternTable* intern_table)
- : dex_lock_("ClassLinker dex lock"),
+ClassLinker::ClassLinker(bool verbose, InternTable* intern_table)
+ : verbose_(verbose),
+ dex_lock_("ClassLinker dex lock"),
classes_lock_("ClassLinker classes lock"),
class_roots_(NULL),
array_interfaces_(NULL),
@@ -633,9 +635,25 @@
return oat_file;
}
-const OatFile* ClassLinker::FindOatFile(const DexFile& dex_file) {
+const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
+ for (size_t i = 0; i < oat_files_.size(); i++) {
+ const OatFile* oat_file = oat_files_[i];
+ DCHECK(oat_file != NULL);
+ if (oat_file->GetOatDexFile(dex_file.GetLocation())) {
+ return oat_file;
+ }
+ }
+ return NULL;
+}
+
+const OatFile* ClassLinker::FindOatFileForDexFile(const DexFile& dex_file) {
MutexLock mu(dex_lock_);
- const OatFile* oat_file = FindOatFile(OatFile::DexFilenameToOatFilename(dex_file.GetLocation()));
+ const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+ if (oat_file != NULL) {
+ return oat_file;
+ }
+
+ oat_file = FindOatFileFromOatLocation(OatFile::DexFilenameToOatFilename(dex_file.GetLocation()));
if (oat_file != NULL) {
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
if (dex_file.GetHeader().checksum_ == oat_dex_file->GetDexFileChecksum()) {
@@ -658,44 +676,44 @@
return oat_file;
}
-const OatFile* ClassLinker::FindOpenedOatFile(const std::string& location) {
+const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {
for (size_t i = 0; i < oat_files_.size(); i++) {
const OatFile* oat_file = oat_files_[i];
DCHECK(oat_file != NULL);
- if (oat_file->GetLocation() == location) {
+ if (oat_file->GetLocation() == oat_location) {
return oat_file;
}
}
return NULL;
}
-const OatFile* ClassLinker::FindOatFile(const std::string& location) {
- const OatFile* oat_file = FindOpenedOatFile(location);
+const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) {
+ const OatFile* oat_file = FindOpenedOatFileFromOatLocation(oat_location);
if (oat_file != NULL) {
return oat_file;
}
- oat_file = OatFile::Open(location, "", NULL);
+ oat_file = OatFile::Open(oat_location, "", NULL);
if (oat_file == NULL) {
- if (location.empty() || location[0] != '/') {
- LOG(ERROR) << "Failed to open oat file from " << location;
+ if (oat_location.empty() || oat_location[0] != '/') {
+ LOG(ERROR) << "Failed to open oat file from " << oat_location;
return NULL;
}
// not found in /foo/bar/baz.oat? try /data/art-cache/foo@bar@baz.oat
- std::string cache_location = GetArtCacheFilenameOrDie(location);
- oat_file = FindOpenedOatFile(cache_location);
+ std::string cache_location = GetArtCacheFilenameOrDie(oat_location);
+ oat_file = FindOpenedOatFileFromOatLocation(cache_location);
if (oat_file != NULL) {
return oat_file;
}
oat_file = OatFile::Open(cache_location, "", NULL);
if (oat_file == NULL) {
- LOG(INFO) << "Failed to open oat file from " << location << " or " << cache_location << ".";
+ LOG(INFO) << "Failed to open oat file from " << oat_location << " or " << cache_location << ".";
return NULL;
}
}
- CHECK(oat_file != NULL) << location;
+ CHECK(oat_file != NULL) << oat_location;
oat_files_.push_back(oat_file);
return oat_file;
}
@@ -1137,7 +1155,7 @@
// Every kind of method should at least get an invoke stub from the oat_method.
// non-abstract methods also get their code pointers.
const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
- oat_method.LinkMethod(method.get());
+ oat_method.LinkMethodPointers(method.get());
if (method->IsAbstract()) {
method->SetCode(Runtime::Current()->GetAbstractMethodErrorStubArray()->GetData());
@@ -1218,7 +1236,7 @@
UniquePtr<const OatFile::OatClass> oat_class;
if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
- const OatFile* oat_file = FindOatFile(dex_file);
+ const OatFile* oat_file = FindOatFileForDexFile(dex_file);
if (oat_file != NULL) {
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
if (oat_dex_file != NULL) {
@@ -1632,6 +1650,15 @@
}
bool ClassLinker::InsertClass(const std::string& descriptor, Class* klass, bool image_class) {
+ if (verbose_) {
+ DexCache* dex_cache = klass->GetDexCache();
+ std::string source;
+ if (dex_cache != NULL) {
+ source += " from ";
+ source += dex_cache->GetLocation()->ToModifiedUtf8();
+ }
+ LOG(INFO) << "Loaded class " << descriptor << source;
+ }
size_t hash = StringPieceHash()(descriptor);
MutexLock mu(classes_lock_);
Table::iterator it;
@@ -1645,6 +1672,28 @@
return ((*it).second == klass);
}
+bool ClassLinker::RemoveClass(const std::string& descriptor, const ClassLoader* class_loader) {
+ size_t hash = StringPieceHash()(descriptor);
+ MutexLock mu(classes_lock_);
+ typedef Table::const_iterator It; // TODO: C++0x auto
+ // TODO: determine if its better to search classes_ or image_classes_ first
+ for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
+ Class* klass = it->second;
+ if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+ classes_.erase(it);
+ return true;
+ }
+ }
+ for (It it = image_classes_.find(hash), end = image_classes_.end(); it != end; ++it) {
+ Class* klass = it->second;
+ if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+ image_classes_.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
Class* ClassLinker::LookupClass(const std::string& descriptor, const ClassLoader* class_loader) {
size_t hash = StringPieceHash()(descriptor);
MutexLock mu(classes_lock_);
@@ -1858,6 +1907,10 @@
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
klass->SetStatus(Class::kStatusInitialized);
+ if (verbose_) {
+ LOG(INFO) << "Initialized class " << klass->GetDescriptor()->ToModifiedUtf8()
+ << " from " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
+ }
}
lock.NotifyAll();
}
diff --git a/src/class_linker.h b/src/class_linker.h
index 5032d9f..d212c59 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -45,10 +45,10 @@
class ClassLinker {
public:
// Creates the class linker by boot strapping from dex files.
- static ClassLinker* Create(const std::string& boot_class_path, InternTable* intern_table);
+ static ClassLinker* Create(bool verbose, const std::string& boot_class_path, InternTable* intern_table);
// Creates the class linker from one or more images.
- static ClassLinker* Create(InternTable* intern_table);
+ static ClassLinker* Create(bool verbose, InternTable* intern_table);
~ClassLinker();
@@ -70,6 +70,10 @@
Class* FindPrimitiveClass(char type);
+ // General class unloading is not supported, this is used to prune
+ // unwanted classes during image writing.
+ bool RemoveClass(const std::string& descriptor, const ClassLoader* class_loader);
+
void DumpAllClasses(int flags) const;
void DumpForSigQuit(std::ostream& os) const;
@@ -219,8 +223,8 @@
const OatFile* GenerateOatFile(const std::string& filename);
// Find, possibily opening, an OatFile corresponding to a DexFile
- const OatFile* FindOatFile(const DexFile& dex_file);
- const OatFile* FindOatFile(const std::string& location);
+ const OatFile* FindOatFileForDexFile(const DexFile& dex_file);
+ const OatFile* FindOatFileFromOatLocation(const std::string& location);
// TODO: replace this with multiple methods that allocate the correct managed type.
template <class T>
@@ -243,7 +247,7 @@
pid_t GetDexLockOwner(); // For SignalCatcher.
private:
- explicit ClassLinker(InternTable*);
+ explicit ClassLinker(bool verbose, InternTable*);
// Initialize class linker by bootstraping from dex files
void Init(const std::string& boot_class_path);
@@ -354,11 +358,14 @@
return dex_caches_;
}
- const OatFile* FindOpenedOatFile(const std::string& location);
+ const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file);
+ const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location);
Method* CreateProxyConstructor(SirtRef<Class>& klass);
Method* CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype, ObjectArray<Class>* throws);
+ const bool verbose_;
+
std::vector<const DexFile*> boot_class_path_;
std::vector<const DexFile*> dex_files_;
@@ -457,11 +464,11 @@
InternTable* intern_table_;
friend class CommonTest;
- FRIEND_TEST(DexCacheTest, Open);
- friend class ObjectTest;
- FRIEND_TEST(ObjectTest, AllocObjectArray);
- FRIEND_TEST(ExceptionTest, FindExceptionHandler);
friend class ImageWriter; // for GetClassRoots
+ friend class ObjectTest;
+ FRIEND_TEST(DexCacheTest, Open);
+ FRIEND_TEST(ExceptionTest, FindExceptionHandler);
+ FRIEND_TEST(ObjectTest, AllocObjectArray);
DISALLOW_COPY_AND_ASSIGN(ClassLinker);
};
diff --git a/src/common_test.h b/src/common_test.h
index f2a18e5..d140d40 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -97,6 +97,24 @@
MakeExecutable(&code[0], code.size());
}
+ // Create an OatMethod based on pointers (for unit tests)
+ OatFile::OatMethod CreateOatMethod(const void* code,
+ const size_t frame_size_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const uint32_t* mapping_table,
+ const uint16_t* vmap_table,
+ const Method::InvokeStub* invoke_stub) {
+ return OatFile::OatMethod(NULL,
+ reinterpret_cast<uint32_t>(code),
+ frame_size_in_bytes,
+ core_spill_mask,
+ fp_spill_mask,
+ reinterpret_cast<uint32_t>(mapping_table),
+ reinterpret_cast<uint32_t>(vmap_table),
+ reinterpret_cast<uint32_t>(invoke_stub));
+ }
+
void MakeExecutable(Method* method) {
CHECK(method != NULL);
@@ -123,26 +141,26 @@
const void* method_code
= CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
- OatFile::OatMethod oat_method(method_code,
- compiled_method->GetFrameSizeInBytes(),
- compiled_method->GetCoreSpillMask(),
- compiled_method->GetFpSpillMask(),
- &compiled_method->GetMappingTable()[0],
- &compiled_method->GetVmapTable()[0],
- method_invoke_stub);
- oat_method.LinkMethod(method);
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code,
+ compiled_method->GetFrameSizeInBytes(),
+ compiled_method->GetCoreSpillMask(),
+ compiled_method->GetFpSpillMask(),
+ &compiled_method->GetMappingTable()[0],
+ &compiled_method->GetVmapTable()[0],
+ method_invoke_stub);
+ oat_method.LinkMethodPointers(method);
} else {
MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
- OatFile::OatMethod oat_method(method_code,
- kStackAlignment,
- 0,
- 0,
- NULL,
- NULL,
- method_invoke_stub);
- oat_method.LinkMethod(method);
+ OatFile::OatMethod oat_method = CreateOatMethod(method_code,
+ kStackAlignment,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ method_invoke_stub);
+ oat_method.LinkMethodPointers(method);
}
}
@@ -221,7 +239,7 @@
runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
}
}
- compiler_.reset(new Compiler(instruction_set, false));
+ compiler_.reset(new Compiler(instruction_set, false, NULL));
Heap::VerifyHeap(); // Check for heap corruption before the test
}
diff --git a/src/compiler.cc b/src/compiler.cc
index a3655c6..fba767d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -35,12 +35,18 @@
ByteArray* CreateJniDlysmLookupStub();
}
-Compiler::Compiler(InstructionSet instruction_set, bool image)
+Compiler::Compiler(InstructionSet instruction_set,
+ bool image,
+ const std::set<std::string>* image_classes)
: instruction_set_(instruction_set),
jni_compiler_(instruction_set),
image_(image),
+ image_classes_(image_classes),
verbose_(false) {
CHECK(!Runtime::Current()->IsStarted());
+ if (!image_) {
+ CHECK(image_classes_ == NULL);
+ }
}
Compiler::~Compiler() {
@@ -83,50 +89,62 @@
}
void Compiler::CompileAll(const ClassLoader* class_loader,
- const std::vector<const DexFile*>& dex_files) {
+ const std::vector<const DexFile*>& dex_files) {
DCHECK(!Runtime::Current()->IsStarted());
- for (size_t i = 0; i != dex_files.size(); ++i) {
- ResolveDexFile(class_loader, *dex_files[i]);
- }
- for (size_t i = 0; i != dex_files.size(); ++i) {
- VerifyDexFile(class_loader, *dex_files[i]);
- }
- for (size_t i = 0; i != dex_files.size(); ++i) {
- InitializeClassesWithoutClinit(class_loader, *dex_files[i]);
- }
- for (size_t i = 0; i != dex_files.size(); ++i) {
- CompileDexFile(class_loader, *dex_files[i]);
- }
- for (size_t i = 0; i != dex_files.size(); ++i) {
- SetCodeAndDirectMethodsDexFile(*dex_files[i]);
- }
+
+ PreCompile(class_loader, dex_files);
+ Compile(class_loader, dex_files);
+ PostCompile(class_loader, dex_files);
}
void Compiler::CompileOne(const Method* method) {
DCHECK(!Runtime::Current()->IsStarted());
+
const ClassLoader* class_loader = method->GetDeclaringClass()->GetClassLoader();
- Resolve(class_loader);
- Verify(class_loader);
- InitializeClassesWithoutClinit(class_loader);
+
// Find the dex_file
const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
const DexFile& dex_file = Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache);
+ std::vector<const DexFile*> dex_files;
+ dex_files.push_back(&dex_file);
+
+ PreCompile(class_loader, dex_files);
+
uint32_t method_idx = method->GetDexMethodIndex();
const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
CompileMethod(code_item, method->GetAccessFlags(), method_idx, class_loader, dex_file);
- SetCodeAndDirectMethods(class_loader);
+
+ PostCompile(class_loader, dex_files);
}
-void Compiler::Resolve(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path
- = ClassLoader::GetCompileTimeClassPath(class_loader);
- for (size_t i = 0; i != class_path.size(); ++i) {
- const DexFile* dex_file = class_path[i];
+void Compiler::Resolve(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files) {
+ for (size_t i = 0; i != dex_files.size(); ++i) {
+ const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
ResolveDexFile(class_loader, *dex_file);
}
}
+void Compiler::PreCompile(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files) {
+ Resolve(class_loader, dex_files);
+ Verify(class_loader, dex_files);
+ InitializeClassesWithoutClinit(class_loader, dex_files);
+}
+
+void Compiler::PostCompile(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files) {
+ SetCodeAndDirectMethods(dex_files);
+}
+
+bool Compiler::IsImageClass(const std::string& descriptor) const {
+ if (image_classes_ == NULL) {
+ return true;
+ }
+ return image_classes_->find(descriptor) != image_classes_->end();
+}
+
// Return true if the class should be skipped during compilation. We
// never skip classes in the boot class loader. However, if we have a
// non-boot class loader and we can resolve the class in the boot
@@ -157,8 +175,10 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
DexCache* dex_cache = class_linker->FindDexCache(dex_file);
- // Strings are easy, they always are simply resolved to literals in the same file
- if (IsImage()) { // Only resolve when we'll have an image, so compiler won't choose fast path
+ // Strings are easy in that they always are simply resolved to literals in the same file
+ if (image_ && image_classes_ == NULL) {
+ // TODO: Add support for loading strings referenced by image_classes_
+ // See also Compiler::CanAssumeTypeIsPresentInDexCache.
for (size_t string_idx = 0; string_idx < dex_cache->NumStrings(); string_idx++) {
class_linker->ResolveString(dex_file, string_idx, dex_cache);
}
@@ -235,11 +255,10 @@
}
}
-void Compiler::Verify(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path
- = ClassLoader::GetCompileTimeClassPath(class_loader);
- for (size_t i = 0; i != class_path.size(); ++i) {
- const DexFile* dex_file = class_path[i];
+void Compiler::Verify(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files) {
+ for (size_t i = 0; i != dex_files.size(); ++i) {
+ const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
VerifyDexFile(class_loader, *dex_file);
}
@@ -275,11 +294,10 @@
dex_file.ChangePermissions(PROT_READ);
}
-void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path
- = ClassLoader::GetCompileTimeClassPath(class_loader);
- for (size_t i = 0; i != class_path.size(); ++i) {
- const DexFile* dex_file = class_path[i];
+void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files) {
+ for (size_t i = 0; i != dex_files.size(); ++i) {
+ const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
InitializeClassesWithoutClinit(class_loader, *dex_file);
}
@@ -309,11 +327,10 @@
}
}
-void Compiler::Compile(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path
- = ClassLoader::GetCompileTimeClassPath(class_loader);
- for (size_t i = 0; i != class_path.size(); ++i) {
- const DexFile* dex_file = class_path[i];
+void Compiler::Compile(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files) {
+ for (size_t i = 0; i != dex_files.size(); ++i) {
+ const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
CompileDexFile(class_loader, *dex_file);
}
@@ -410,7 +427,7 @@
}
const CompiledInvokeStub* Compiler::FindInvokeStub(bool is_static, const char* shorty) const {
- std::string key = MakeInvokeStubKey(is_static, shorty);
+ const std::string key = MakeInvokeStubKey(is_static, shorty);
InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key);
if (it == compiled_invoke_stubs_.end()) {
return NULL;
@@ -435,11 +452,9 @@
return it->second;
}
-void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path
- = ClassLoader::GetCompileTimeClassPath(class_loader);
- for (size_t i = 0; i != class_path.size(); ++i) {
- const DexFile* dex_file = class_path[i];
+void Compiler::SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files) {
+ for (size_t i = 0; i != dex_files.size(); ++i) {
+ const DexFile* dex_file = dex_files[i];
CHECK(dex_file != NULL);
SetCodeAndDirectMethodsDexFile(*dex_file);
}
diff --git a/src/compiler.h b/src/compiler.h
index a8ea205..5203ffb 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -13,6 +13,7 @@
#include "runtime.h"
#include "unordered_map.h"
+#include <set>
#include <string>
namespace art {
@@ -20,13 +21,18 @@
class Compiler {
public:
// Create a compiler targeting the requested "instruction_set".
- // "image" should be true if image specific optimizations should be enabled.
- explicit Compiler(InstructionSet instruction_set, bool image);
+ // "image" should be true if image specific optimizations should be
+ // enabled. "image_classes" lets the compiler know what classes it
+ // can assume will be in the image, with NULL implying all available
+ // classes.
+ explicit Compiler(InstructionSet instruction_set,
+ bool image,
+ const std::set<std::string>* image_classes);
~Compiler();
void CompileAll(const ClassLoader* class_loader,
- const std::vector<const DexFile*>& class_path);
+ const std::vector<const DexFile*>& dex_files);
// Compile a single Method
void CompileOne(const Method* method);
@@ -65,20 +71,29 @@
// Callbacks from OAT/ART compiler to see what runtime checks must be generated
bool CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache, uint32_t type_idx) const {
- return IsImage() && dex_cache->GetResolvedTypes()->Get(type_idx) != NULL;
+ if (!IsImage()) {
+ return false;
+ }
+ Class* resolved_class = dex_cache->GetResolvedTypes()->Get(type_idx);
+ if (resolved_class == NULL) {
+ return false;
+ }
+ return IsImageClass(resolved_class->GetDescriptor()->ToModifiedUtf8());
}
bool CanAssumeStringIsPresentInDexCache(const DexCache* dex_cache, uint32_t string_idx) const {
- return IsImage() && dex_cache->GetStrings()->Get(string_idx) != NULL;
+ // TODO: Add support for loading strings referenced by image_classes_
+ // See also Compiler::ResolveDexFile
+ return IsImage() && image_classes_ == NULL && dex_cache->GetResolvedString(string_idx) != NULL;
}
bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexCache* dex_cache,
const DexFile& dex_file, uint32_t type_idx) const {
- Class* resolved_class = dex_cache->GetResolvedTypes()->Get(type_idx);
+ Class* resolved_class = dex_cache->GetResolvedType(type_idx);
// We should never ask whether a type needs access checks to raise a verification error,
// all other cases where this following test could fail should have been rewritten by the
// verifier to verification errors. Also need to handle a lack of knowledge at compile time.
#ifndef NDEBUG
- Class* referrer_class = dex_cache->GetResolvedTypes()
- ->Get(dex_file.GetMethodId(referrer_idx).class_idx_);
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
+ Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
DCHECK(resolved_class == NULL || referrer_class == NULL ||
referrer_class->CanAccess(resolved_class));
#endif
@@ -86,19 +101,27 @@
}
private:
+
+ // Checks if class specified by type_idx is one of the image_classes_
+ bool IsImageClass(const std::string& descriptor) const;
+
+ void PreCompile(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
+ void PostCompile(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
+
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
// ordering semantics.
- void Resolve(const ClassLoader* class_loader);
+ void Resolve(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
void ResolveDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
- void Verify(const ClassLoader* class_loader);
+ void Verify(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
void VerifyDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
- void InitializeClassesWithoutClinit(const ClassLoader* class_loader);
+ void InitializeClassesWithoutClinit(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
void InitializeClassesWithoutClinit(const ClassLoader* class_loader, const DexFile& dex_file);
- void Compile(const ClassLoader* class_loader);
+ void Compile(const ClassLoader* class_loader,
+ const std::vector<const DexFile*>& dex_files);
void CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
void CompileClass(const DexFile::ClassDef& class_def, const ClassLoader* class_loader,
const DexFile& dex_file);
@@ -107,7 +130,7 @@
// After compiling, walk all the DexCaches and set the code and
// method pointers of CodeAndDirectMethods entries in the DexCaches.
- void SetCodeAndDirectMethods(const ClassLoader* class_loader);
+ void SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files);
void SetCodeAndDirectMethodsDexFile(const DexFile& dex_file);
void InsertInvokeStub(bool is_static, const char* shorty,
@@ -139,6 +162,8 @@
bool image_;
+ const std::set<std::string>* image_classes_;
+
bool verbose_;
DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 6ad92ba..cf4443b 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -222,7 +222,7 @@
return JNI_TRUE;
}
- const OatFile* oat_file = class_linker->FindOatFile(*dex_file.get());
+ const OatFile* oat_file = class_linker->FindOatFileForDexFile(*dex_file.get());
if (oat_file == NULL) {
return JNI_TRUE;
}
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 231ca9c..0e4c224 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -4,6 +4,8 @@
#include <stdlib.h>
#include <sys/file.h>
+#include <iostream>
+#include <fstream>
#include <string>
#include <vector>
@@ -29,13 +31,16 @@
" Example: --dex-file=/system/framework/core.jar\n"
"\n");
fprintf(stderr,
- " --image=<file.art>: specifies the required output image filename.\n"
+ " --oat=<file.oat>: specifies the required oat filename.\n"
+ " Example: --oat=/data/art-cache/boot.oat\n"
+ "\n");
+ fprintf(stderr,
+ " --image=<file.art>: specifies the output image filename.\n"
" Example: --image=/data/art-cache/boot.art\n"
"\n");
- // TODO: remove this by inferring from --image
fprintf(stderr,
- " --oat=<file.oat>: specifies the required oat filename.\n"
- " Example: --image=/data/art-cache/boot.oat\n"
+ " --image-classes=<classname-file>: specifies classes to include in an image.\n"
+ " Example: --image=frameworks/base/preloaded-classes\n"
"\n");
fprintf(stderr,
" --base=<hex-address>: specifies the base address when creating a boot image.\n"
@@ -46,10 +51,6 @@
" Example: --boot-image=/data/art-cache/boot.art\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");
- fprintf(stderr,
" --host-prefix may be used to translate host paths to target paths during\n"
" cross compilation.\n"
" Example: --host-prefix=out/target/product/crespo\n"
@@ -94,33 +95,190 @@
bool do_unlink_;
};
-// Returns true if dex_files has a dex with the named location.
-bool DexFilesContains(const std::vector<const DexFile*>& dex_files, const std::string& location) {
- for (size_t i = 0; i < dex_files.size(); ++i) {
- if (dex_files[i]->GetLocation() == location) {
+class Dex2Oat {
+ public:
+
+ static Dex2Oat* Create(Runtime::Options& options) {
+ UniquePtr<Runtime> runtime(CreateRuntime(options));
+ if (runtime.get() == NULL) {
+ return NULL;
+ }
+ return new Dex2Oat(runtime.release());
+ }
+
+ ~Dex2Oat() {
+ delete runtime_;
+ }
+
+ // Make a list of descriptors for classes to include in the image
+ const std::set<std::string>* GetImageClassDescriptors(const char* image_classes_filename) {
+ UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
+ if (image_classes_file.get() == NULL) {
+ LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
+ return NULL;
+ }
+
+ // Load all the classes specifed in the file
+ ClassLinker* class_linker = runtime_->GetClassLinker();
+ while (image_classes_file->good()) {
+ std::string dot;
+ std::getline(*image_classes_file.get(), dot);
+ if (StringPiece(dot).starts_with("#") || dot.empty()) {
+ continue;
+ }
+ std::string descriptor = DotToDescriptor(dot.c_str());
+ SirtRef<Class> klass(class_linker->FindSystemClass(descriptor));
+ if (klass.get() == NULL) {
+ LOG(WARNING) << "Failed to find class " << descriptor;
+ Thread::Current()->ClearException();
+ }
+ }
+ image_classes_file->close();
+
+ // We walk the roots looking for classes so that we'll pick up the
+ // above classes plus any classes them depend on such super
+ // classes, interfaces, and the required ClassLinker roots.
+ UniquePtr<std::set<std::string> > image_classes(new std::set<std::string>());
+ class_linker->VisitClasses(ClassVisitor, image_classes.get());
+ CHECK_NE(image_classes->size(), 0U);
+ return image_classes.release();
+ }
+
+ bool CreateOatFile(const std::string& boot_image_option,
+ const std::vector<const char*>& dex_filenames,
+ const std::string& host_prefix,
+ File* oat_file,
+ bool image,
+ const std::set<std::string>* image_classes) {
+ // SirtRef and ClassLoader creation needs to come after Runtime::Create
+ UniquePtr<SirtRef<ClassLoader> > class_loader(new SirtRef<ClassLoader>(NULL));
+ if (class_loader.get() == NULL) {
+ LOG(ERROR) << "Failed to create SirtRef for class loader";
+ return false;
+ }
+
+ std::vector<const DexFile*> dex_files;
+ if (!boot_image_option.empty()) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
+ std::vector<const DexFile*> class_path_files(dex_files);
+ OpenClassPathFiles(runtime_->GetClassPath(), class_path_files);
+ for (size_t i = 0; i < class_path_files.size(); i++) {
+ class_linker->RegisterDexFile(*class_path_files[i]);
+ }
+ class_loader.get()->reset(PathClassLoader::AllocCompileTime(class_path_files));
+ } else {
+ dex_files = runtime_->GetClassLinker()->GetBootClassPath();
+ }
+
+ Compiler compiler(instruction_set_, image, image_classes);
+ compiler.CompileAll(class_loader->get(), dex_files);
+
+ if (!OatWriter::Create(oat_file, class_loader->get(), compiler)) {
+ LOG(ERROR) << "Failed to create oat file " << oat_file->name();
+ return false;
+ }
+ return true;
+ }
+
+ bool CreateImageFile(const char* image_filename,
+ uintptr_t image_base,
+ const std::set<std::string>* image_classes,
+ const std::string& oat_filename,
+ const std::string& host_prefix) {
+ // If we have an existing boot image, position new space after its oat file
+ if (Heap::GetSpaces().size() > 1) {
+ Space* last_image_space = Heap::GetSpaces()[Heap::GetSpaces().size()-2];
+ CHECK(last_image_space != NULL);
+ CHECK(last_image_space->IsImageSpace());
+ CHECK(!Heap::GetSpaces()[Heap::GetSpaces().size()-1]->IsImageSpace());
+ byte* oat_limit_addr = last_image_space->GetImageHeader().GetOatLimitAddr();
+ image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize);
+ }
+
+ ImageWriter image_writer(image_classes);
+ if (!image_writer.Write(image_filename, image_base, oat_filename, host_prefix)) {
+ LOG(ERROR) << "Failed to create image file " << image_filename;
+ return false;
+ }
+ return true;
+ }
+
+ private:
+
+ Dex2Oat(Runtime* runtime) : runtime_(runtime) {}
+
+ static Runtime* CreateRuntime(Runtime::Options& options) {
+ Runtime* runtime = Runtime::Create(options, false);
+ if (runtime == NULL) {
+ LOG(ERROR) << "Failed to create runtime";
+ return NULL;
+ }
+
+ // if we loaded an existing image, we will reuse values from the image roots.
+ if (!runtime->HasJniDlsymLookupStub()) {
+ runtime->SetJniDlsymLookupStub(Compiler::CreateJniDlysmLookupStub(instruction_set_));
+ }
+ if (!runtime->HasAbstractMethodErrorStubArray()) {
+ runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(instruction_set_));
+ }
+ for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
+ Runtime::TrampolineType type = Runtime::TrampolineType(i);
+ if (!runtime->HasResolutionStubArray(type)) {
+ runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(instruction_set_, type), type);
+ }
+ }
+ for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+ Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+ if (!runtime->HasCalleeSaveMethod(type)) {
+ runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(instruction_set_, type), type);
+ }
+ }
+ return runtime;
+ }
+
+ static bool ClassVisitor(Class* klass, void* arg) {
+ std::set<std::string>* image_classes = reinterpret_cast<std::set<std::string>*>(arg);
+ if (klass->IsArrayClass() || klass->IsPrimitive()) {
return true;
}
+ image_classes->insert(klass->GetDescriptor()->ToModifiedUtf8());
+ return true;
}
- return false;
-}
-// Appends to dex_files any elements of class_path that it doesn't already
-// contain. This will open those dex files as necessary.
-void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
- std::vector<std::string> parsed;
- Split(class_path, ':', parsed);
- for (size_t i = 0; i < parsed.size(); ++i) {
- if (DexFilesContains(dex_files, parsed[i])) {
- continue;
- }
- const DexFile* dex_file = DexFile::Open(parsed[i], Runtime::Current()->GetHostPrefix());
- if (dex_file == NULL) {
- LOG(WARNING) << "Failed to open dex file " << parsed[i];
- } else {
- dex_files.push_back(dex_file);
+ // Appends to dex_files any elements of class_path that it doesn't already
+ // contain. This will open those dex files as necessary.
+ static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
+ std::vector<std::string> parsed;
+ Split(class_path, ':', parsed);
+ for (size_t i = 0; i < parsed.size(); ++i) {
+ if (DexFilesContains(dex_files, parsed[i])) {
+ continue;
+ }
+ const DexFile* dex_file = DexFile::Open(parsed[i], Runtime::Current()->GetHostPrefix());
+ if (dex_file == NULL) {
+ LOG(WARNING) << "Failed to open dex file " << parsed[i];
+ } else {
+ dex_files.push_back(dex_file);
+ }
}
}
-}
+
+ // Returns true if dex_files has a dex with the named location.
+ static bool DexFilesContains(const std::vector<const DexFile*>& dex_files, const std::string& location) {
+ for (size_t i = 0; i < dex_files.size(); ++i) {
+ if (dex_files[i]->GetLocation() == location) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Runtime* runtime_;
+ static const InstructionSet instruction_set_ = kThumb2;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
+};
int dex2oat(int argc, char** argv) {
// Skip over argv[0].
@@ -133,9 +291,9 @@
}
std::vector<const char*> dex_filenames;
- std::vector<const char*> method_names;
std::string oat_filename;
const char* image_filename = NULL;
+ const char* image_classes_filename = NULL;
std::string boot_image_option;
uintptr_t image_base = 0;
std::string host_prefix;
@@ -148,12 +306,12 @@
}
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("--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("--image-classes=")) {
+ image_classes_filename = option.substr(strlen("--image-classes=")).data();
} else if (option.starts_with("--base=")) {
const char* image_base_str = option.substr(strlen("--base=")).data();
char* end;
@@ -181,18 +339,24 @@
}
}
- if (oat_filename == NULL) {
+ if (oat_filename.empty()) {
fprintf(stderr, "--oat file name not specified\n");
return EXIT_FAILURE;
}
- if (image_filename == NULL && boot_image_option.empty()) {
+ bool image = (image_filename != NULL);
+ if (!image && boot_image_option.empty()) {
fprintf(stderr, "Either --image or --boot-image must be specified\n");
return EXIT_FAILURE;
}
- if (dex_filenames.empty()) {
- fprintf(stderr, "no --dex-file values specified\n");
+ if (image_classes_filename != NULL && !image) {
+ fprintf(stderr, "--image-classes should only be used with --image\n");
+ return EXIT_FAILURE;
+ }
+
+ if (image_classes_filename != NULL && !boot_image_option.empty()) {
+ fprintf(stderr, "--image-classes should not be used with --boot-image\n");
return EXIT_FAILURE;
}
@@ -220,7 +384,7 @@
}
// Handles removing the file on failure and unlocking on both failure and success.
- FileJanitor file_janitor(oat_filename, fd);
+ FileJanitor oat_file_janitor(oat_filename, fd);
// If we won the creation race, block trying to take the lock (since we're going to be doing
// the work, we need the lock). If we lost the creation race, spin trying to take the lock
@@ -252,7 +416,7 @@
// TODO: check the creator did a good job by checking the header.
LOG(INFO) << "Another process finished working on " << oat_filename;
// Job done.
- file_janitor.KeepFile();
+ oat_file_janitor.KeepFile();
return EXIT_SUCCESS;
}
@@ -281,122 +445,47 @@
for (size_t i = 0; i < runtime_args.size(); i++) {
options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
}
- UniquePtr<Runtime> runtime(Runtime::Create(options, false));
- if (runtime.get() == NULL) {
- LOG(ERROR) << "Could not create runtime";
- return EXIT_FAILURE;
- }
- ClassLinker* class_linker = runtime->GetClassLinker();
- // If we have an existing boot image, position new space after its oat file
- if (Heap::GetSpaces().size() > 1) {
- Space* last_image_space = Heap::GetSpaces()[Heap::GetSpaces().size()-2];
- CHECK(last_image_space != NULL);
- CHECK(last_image_space->IsImageSpace());
- CHECK(!Heap::GetSpaces()[Heap::GetSpaces().size()-1]->IsImageSpace());
- byte* oat_limit_addr = last_image_space->GetImageHeader().GetOatLimitAddr();
- image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize);
- }
+ UniquePtr<Dex2Oat> dex2oat(Dex2Oat::Create(options));
- // ClassLoader creation needs to come after Runtime::Create
- SirtRef<ClassLoader> class_loader(NULL);
- std::vector<const DexFile*> dex_files;
- if (!boot_image_option.empty()) {
- DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
- std::vector<const DexFile*> class_path_files(dex_files);
- OpenClassPathFiles(runtime->GetClassPath(), class_path_files);
- for (size_t i = 0; i < class_path_files.size(); i++) {
- class_linker->RegisterDexFile(*class_path_files[i]);
- }
- class_loader.reset(PathClassLoader::AllocCompileTime(class_path_files));
- } else {
- dex_files = runtime->GetClassLinker()->GetBootClassPath();
- }
-
- // if we loaded an existing image, we will reuse values from the image roots.
- if (!runtime->HasJniDlsymLookupStub()) {
- runtime->SetJniDlsymLookupStub(Compiler::CreateJniDlysmLookupStub(kThumb2));
- }
- if (!runtime->HasAbstractMethodErrorStubArray()) {
- runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
- }
- for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
- Runtime::TrampolineType type = Runtime::TrampolineType(i);
- if (!runtime->HasResolutionStubArray(type)) {
- runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, type), type);
- }
- }
- for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
- Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
- if (!runtime->HasCalleeSaveMethod(type)) {
- runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2, type), type);
- }
- }
- Compiler compiler(kThumb2, image_filename != NULL);
- if (method_names.empty()) {
- compiler.CompileAll(class_loader.get(), dex_files);
- } 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) {
- LOG(ERROR) << "Could not find class descriptor in method " << method_name << "'";
- 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) {
- LOG(ERROR) << "Could not find start of method signature in method '" << method_name << "'";
- 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.get());
- if (klass == NULL) {
- LOG(ERROR) << "Could not find class for descriptor '" << class_descriptor
- << "' in method '" << method_name << "'";
- return EXIT_FAILURE;
- }
- Method* method = klass->FindDirectMethod(name, signature);
- if (method == NULL) {
- method = klass->FindVirtualMethod(name, signature);
- }
- if (method == NULL) {
- LOG(ERROR) << "Could not find method '" << method_name << "' with signature '"
- << signature << "' in class '" << class_descriptor << "' for method argument '"
- << method_name << "'";
- return EXIT_FAILURE;
- }
- compiler.CompileOne(method);
+ // If --image-classes was specified, calculate the full list classes to include in the image
+ UniquePtr<const std::set<std::string> > image_classes(NULL);
+ if (image_classes_filename != NULL) {
+ image_classes.reset(dex2oat->GetImageClassDescriptors(image_classes_filename));
+ if (image_classes.get() == NULL) {
+ LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
+ return EXIT_FAILURE;
}
}
- if (!OatWriter::Create(oat_file.get(), class_loader.get(), compiler)) {
- LOG(ERROR) << "Failed to create oat file " << oat_file->name();
+ if (!dex2oat->CreateOatFile(boot_image_option,
+ dex_filenames,
+ host_prefix,
+ oat_file.get(),
+ image,
+ image_classes.get())) {
+ LOG(ERROR) << "Failed to create oat file" << oat_filename;
return EXIT_FAILURE;
}
- if (image_filename == NULL) {
- file_janitor.KeepFile();
- LOG(INFO) << "Oat file written successfully " << oat_file->name();
+ if (!image) {
+ oat_file_janitor.KeepFile();
+ LOG(INFO) << "Oat file written successfully " << oat_filename;
return EXIT_SUCCESS;
}
- CHECK(compiler.IsImage());
- ImageWriter image_writer;
- if (!image_writer.Write(image_filename, image_base, oat_file->name(), host_prefix)) {
- LOG(ERROR) << "Failed to create image file " << image_filename;
+ if (!dex2oat->CreateImageFile(image_filename,
+ image_base,
+ image_classes.get(),
+ oat_filename,
+ host_prefix)) {
return EXIT_FAILURE;
}
- // We wrote the file successfully, and want to keep it.
+ // We wrote the oat file successfully, and want to keep it.
+ oat_file_janitor.KeepFile();
+ LOG(INFO) << "Oat file written successfully " << oat_filename;
LOG(INFO) << "Image written successfully " << image_filename;
- file_janitor.KeepFile();
return EXIT_SUCCESS;
}
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 208479e..d7517c4 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -45,7 +45,7 @@
reinterpret_cast<const DexFile::ClassDef*>(NULL));
}
-void DexFile::OpenDexFiles(std::vector<const char*>& dex_filenames,
+void DexFile::OpenDexFiles(const std::vector<const char*>& dex_filenames,
std::vector<const DexFile*>& dex_files,
const std::string& strip_location_prefix) {
for (size_t i = 0; i < dex_filenames.size(); i++) {
diff --git a/src/dex_file.h b/src/dex_file.h
index 92aa794..a7026d6 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -176,7 +176,7 @@
const ClassPath& class_path);
// Opens a collection of .dex files
- static void OpenDexFiles(std::vector<const char*>& dex_filenames,
+ static void OpenDexFiles(const std::vector<const char*>& dex_filenames,
std::vector<const DexFile*>& dex_files,
const std::string& strip_location_prefix);
diff --git a/src/image_test.cc b/src/image_test.cc
index 812b281..6901482 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -29,7 +29,7 @@
EXPECT_TRUE(klass != NULL) << descriptor;
}
- ImageWriter writer;
+ ImageWriter writer(NULL);
ScratchFile tmp_image;
const uintptr_t requested_image_base = 0x60000000;
bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index cdb7bd0..adc7b78 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -9,6 +9,7 @@
#include "UniquePtr.h"
#include "class_linker.h"
#include "class_loader.h"
+#include "compiled_method.h"
#include "dex_cache.h"
#include "file.h"
#include "globals.h"
@@ -23,8 +24,10 @@
namespace art {
-bool ImageWriter::Write(const char* image_filename, uintptr_t image_base,
- const std::string& oat_filename, const std::string& strip_location_prefix) {
+bool ImageWriter::Write(const char* image_filename,
+ uintptr_t image_base,
+ const std::string& oat_filename,
+ const std::string& strip_location_prefix) {
CHECK(image_filename != NULL);
CHECK_NE(image_base, 0U);
@@ -36,16 +39,29 @@
source_space_ = spaces[spaces.size()-1];
CHECK(!source_space_->IsImageSpace());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
+ for (size_t i = 0; i < all_dex_caches.size(); i++) {
+ DexCache* dex_cache = all_dex_caches[i];
+ if (InSourceSpace(dex_cache)) {
+ dex_caches_.insert(dex_cache);
+ }
+ }
+
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()) {
+ if (!AllocMemory()) {
return false;
}
+ PruneNonImageClasses();
Heap::CollectGarbage();
+#ifndef NDEBUG
+ CheckNonImageClassesRemoved();
+#endif
Heap::DisableCardMarking();
CalculateNewObjectOffsets();
CopyAndFixupObjects();
@@ -63,7 +79,7 @@
return true;
}
-bool ImageWriter::Init() {
+bool ImageWriter::AllocMemory() {
size_t size = source_space_->Size();
int prot = PROT_READ | PROT_WRITE;
size_t length = RoundUp(size, kPageSize);
@@ -75,6 +91,96 @@
return true;
}
+bool ImageWriter::IsImageClass(const Class* klass) {
+ if (image_classes_ == NULL) {
+ return true;
+ }
+ while (klass->IsArrayClass()) {
+ klass = klass->GetComponentType();
+ }
+ if (klass->IsPrimitive()) {
+ return true;
+ }
+ const std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+ return image_classes_->find(descriptor) != image_classes_->end();
+}
+
+
+struct NonImageClasses {
+ ImageWriter* image_writer;
+ std::set<std::string>* non_image_classes;
+};
+
+void ImageWriter::PruneNonImageClasses() {
+ if (image_classes_ == NULL) {
+ return;
+ }
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+
+ std::set<std::string> non_image_classes;
+ NonImageClasses context;
+ context.image_writer = this;
+ context.non_image_classes = &non_image_classes;
+ class_linker->VisitClasses(NonImageClassesVisitor, &context);
+
+ typedef std::set<std::string>::const_iterator ClassIt; // TODO: C++0x auto
+ for (ClassIt it = non_image_classes.begin(), end = non_image_classes.end(); it != end; ++it) {
+ class_linker->RemoveClass(*it, NULL);
+ }
+
+ typedef Set::const_iterator CacheIt; // TODO: C++0x auto
+ for (CacheIt it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) {
+ DexCache* dex_cache = *it;
+ for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
+ Class* klass = dex_cache->GetResolvedType(i);
+ if (klass != NULL && !IsImageClass(klass)) {
+ dex_cache->SetResolvedType(i, NULL);
+ dex_cache->GetInitializedStaticStorage()->Set(i, NULL);
+ }
+ }
+ for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
+ Method* method = dex_cache->GetResolvedMethod(i);
+ if (method != NULL && !IsImageClass(method->GetDeclaringClass())) {
+ dex_cache->SetResolvedMethod(i, NULL);
+ Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
+ ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
+ dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethodTrampoline(i, res_trampoline);
+ }
+ }
+ for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
+ Field* field = dex_cache->GetResolvedField(i);
+ if (field != NULL && !IsImageClass(field->GetDeclaringClass())) {
+ dex_cache->SetResolvedField(i, NULL);
+ }
+ }
+ }
+}
+
+bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
+ NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
+ if (!context->image_writer->IsImageClass(klass)) {
+ context->non_image_classes->insert(klass->GetDescriptor()->ToModifiedUtf8());
+ }
+ return true;
+}
+
+void ImageWriter::CheckNonImageClassesRemoved() {
+ if (image_classes_ == NULL) {
+ return;
+ }
+ Heap::GetLiveBits()->Walk(CheckNonImageClassesRemovedCallback, this);
+}
+
+void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) {
+ ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+ if (!obj->IsClass()) {
+ return;
+ }
+ Class* klass = obj->AsClass();
+ CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor()->ToModifiedUtf8();
+}
+
void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void* arg) {
DCHECK(obj != NULL);
DCHECK(arg != NULL);
@@ -104,17 +210,6 @@
}
image_writer->AssignImageOffset(obj);
-
- // 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()) << PrettyClass(klass);
- }
- }
}
ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
@@ -123,18 +218,12 @@
Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
// build an Object[] of all the DexCaches used in the source_space_
- const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
- std::vector<DexCache*> source_space_dex_caches;
- for (size_t i = 0; i < all_dex_caches.size(); i++) {
- DexCache* dex_cache = all_dex_caches[i];
- if (InSourceSpace(dex_cache)) {
- source_space_dex_caches.push_back(dex_cache);
- }
- }
ObjectArray<Object>* dex_caches = ObjectArray<Object>::Alloc(object_array_class,
- source_space_dex_caches.size());
- for (size_t i = 0; i < source_space_dex_caches.size(); i++) {
- dex_caches->Set(i, source_space_dex_caches[i]);
+ dex_caches_.size());
+ int i = 0;
+ typedef Set::const_iterator It; // TODO: C++0x auto
+ for (It it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it, ++i) {
+ dex_caches->Set(i, *it);
}
// build an Object[] of the roots needed to restore the runtime
@@ -245,15 +334,15 @@
FixupStaticFields(orig, copy);
}
-const void* FixupCode(const ByteArray* copy_code_array, const void* orig_code) {
+static uint32_t FixupCode(const ByteArray* copy_code_array, uint32_t orig_code) {
// TODO: change to DCHECK when all code compiling
if (copy_code_array == NULL) {
- return NULL;
+ return 0;
}
- const void* copy_code = copy_code_array->GetData();
+ uint32_t copy_code = reinterpret_cast<uint32_t>(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);
+ if ((orig_code % 2) == 1) {
+ return copy_code + 1;
}
return copy_code;
}
@@ -266,7 +355,7 @@
// Every type of method can have an invoke stub
uint32_t invoke_stub_offset = orig->GetOatInvokeStubOffset();
- const byte* invoke_stub = (invoke_stub_offset != 0) ? (oat_base_ + invoke_stub_offset) : 0;
+ const byte* invoke_stub = GetOatAddress(invoke_stub_offset);
copy->invoke_stub_ = reinterpret_cast<const Method::InvokeStub*>(invoke_stub);
if (orig->IsAbstract()) {
@@ -279,7 +368,7 @@
// Non-abstract methods typically have code
uint32_t code_offset = orig->GetOatCodeOffset();
- const byte* code = (code_offset != 0) ? (oat_base_ + code_offset) : 0;
+ const byte* code = GetOatAddress(code_offset);
copy->code_ = code;
if (orig->IsNative()) {
@@ -291,11 +380,11 @@
} else {
// normal (non-abstract non-native) methods have mapping tables to relocate
uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
- const byte* mapping_table = (mapping_table_off != 0) ? (oat_base_ + mapping_table_off) : 0;
+ const byte* mapping_table = GetOatAddress(mapping_table_off);
copy->mapping_table_ = reinterpret_cast<const uint32_t*>(mapping_table);
uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
- const byte* vmap_table = (vmap_table_offset != 0) ? (oat_base_ + vmap_table_offset) : 0;
+ const byte* vmap_table = GetOatAddress(vmap_table_offset);
copy->vmap_table_ = reinterpret_cast<const uint16_t*>(vmap_table);
}
}
@@ -387,9 +476,10 @@
if (orig_method != NULL && !InSourceSpace(orig_method)) {
continue;
}
- // if it was resolved in the original, resolve it in the copy
- if (orig_method == NULL || (orig_method->IsStatic() &&
- !orig_method->GetDeclaringClass()->IsInitialized())) {
+ // if it was unresolved or a resolved static method in an uninit class, use a resolution stub
+ // we need to use the stub in the static method case to ensure <clinit> is run.
+ if (orig_method == NULL
+ || (orig_method->IsStatic() && !orig_method->GetDeclaringClass()->IsInitialized())) {
uint32_t orig_res_stub_code = orig_cadms->Get(CodeAndDirectMethods::CodeIndex(i));
if (orig_res_stub_code == 0) {
continue; // NULL maps the same in the image and the original
@@ -400,22 +490,13 @@
if (!InSourceSpace(orig_res_stub_array)) {
continue;
}
- // Compute the delta from the start of the resolution stub to its starting code.
- // For ARM and X86 this is 0, for Thumb2 it is 1.
- static size_t res_stub_delta = 0xFFFF;
- if (res_stub_delta == 0xFFFF) {
- uint32_t orig_res_stub_array_data =
- reinterpret_cast<uint32_t>(orig_res_stub_array->GetData());
- res_stub_delta = orig_res_stub_code - orig_res_stub_array_data;
- DCHECK(res_stub_delta == 0 || res_stub_delta == 1);
- }
// Compute address in image of resolution stub and the code address
ByteArray* image_res_stub_array = down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array));
- int32_t image_res_stub_code =
- reinterpret_cast<int32_t>(image_res_stub_array->GetData()) + res_stub_delta;
+ uint32_t image_res_stub_code = FixupCode(image_res_stub_array, orig_res_stub_code);
// Put the image code address in the array
copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), image_res_stub_code);
} else if (orig_method->IsDirect()) {
+ // if it was resolved in the original, resolve it in the copy
Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method));
copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i),
reinterpret_cast<int32_t>(copy_method->code_));
diff --git a/src/image_writer.h b/src/image_writer.h
index ec17ebf..4e95ee4 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -6,6 +6,8 @@
#include <stdint.h>
#include <cstddef>
+#include <set>
+#include <string>
#include "UniquePtr.h"
#include "dex_cache.h"
@@ -20,14 +22,18 @@
// Write a Space built during compilation for use during execution.
class ImageWriter {
public:
- ImageWriter() : source_space_(NULL), image_top_(0), image_base_(NULL) {}
- bool Write(const char* image_filename, uintptr_t image_base,
- const std::string& oat_filename, const std::string& strip_location_prefix);
+ ImageWriter(const std::set<std::string>* image_classes)
+ : source_space_(NULL), image_top_(0), image_base_(NULL), image_classes_(image_classes) {}
+
~ImageWriter() {}
+ bool Write(const char* image_filename,
+ uintptr_t image_base,
+ const std::string& oat_filename,
+ const std::string& strip_location_prefix);
private:
- bool Init();
+ bool AllocMemory();
// we use the lock word to store the offset of the object in the image
void AssignImageOffset(Object* object) {
@@ -82,6 +88,22 @@
return reinterpret_cast<Object*>(dst);
}
+ const byte* GetOatAddress(uint32_t offset) const {
+ DCHECK_LT(offset, oat_file_->GetSize());
+ if (offset == 0) {
+ return NULL;
+ }
+ return oat_base_ + offset;
+ }
+
+ bool IsImageClass(const Class* klass);
+
+ void PruneNonImageClasses();
+ static bool NonImageClassesVisitor(Class* c, void* arg);
+
+ void CheckNonImageClassesRemoved();
+ static void CheckNonImageClassesRemovedCallback(Object* obj, void* arg);
+
void CalculateNewObjectOffsets();
ObjectArray<Object>* CreateImageRoots() const;
static void CalculateNewObjectOffsetsCallback(Object* obj, void* arg);
@@ -114,6 +136,9 @@
// Target image base address for the output image
byte* image_base_;
+ // Set of classes to be include in the image, or NULL for all.
+ const std::set<std::string>* image_classes_;
+
// Target oat base address for the pointers from the output image to its oat file
const byte* oat_base_;
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 383bc2a..55493e8 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -173,54 +173,69 @@
const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
return OatMethod(
- GetOatPointer<const void*>(oat_method_offsets.code_offset_),
+ oat_file_->GetBase(),
+ oat_method_offsets.code_offset_,
oat_method_offsets.frame_size_in_bytes_,
oat_method_offsets.core_spill_mask_,
oat_method_offsets.fp_spill_mask_,
- GetOatPointer<const uint32_t*>(oat_method_offsets.mapping_table_offset_),
- GetOatPointer<const uint16_t*>(oat_method_offsets.vmap_table_offset_),
- GetOatPointer<const Method::InvokeStub*>(oat_method_offsets.invoke_stub_offset_));
+ oat_method_offsets.mapping_table_offset_,
+ oat_method_offsets.vmap_table_offset_,
+ oat_method_offsets.invoke_stub_offset_);
}
-OatFile::OatMethod::OatMethod(const void* code,
+OatFile::OatMethod::OatMethod(const byte* base,
+ const uint32_t code_offset,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask,
- const uint32_t* mapping_table,
- const uint16_t* vmap_table,
- const Method::InvokeStub* invoke_stub)
- : code_(code),
+ const uint32_t mapping_table_offset,
+ const uint32_t vmap_table_offset,
+ const uint32_t invoke_stub_offset)
+ : base_(base),
+ code_offset_(code_offset),
frame_size_in_bytes_(frame_size_in_bytes),
core_spill_mask_(core_spill_mask),
fp_spill_mask_(fp_spill_mask),
- mapping_table_(mapping_table),
- vmap_table_(vmap_table),
- invoke_stub_(invoke_stub) {
+ mapping_table_offset_(mapping_table_offset),
+ vmap_table_offset_(vmap_table_offset),
+ invoke_stub_offset_(invoke_stub_offset) {
#ifndef NDEBUG
- if (mapping_table != NULL) { // implies non-native, non-stub code
- if (vmap_table_ == NULL) {
+ if (mapping_table_offset_ != 0) { // implies non-native, non-stub code
+ if (vmap_table_offset_ == 0) {
DCHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
} else {
+ const uint16_t* vmap_table_ = reinterpret_cast<const uint16_t*>(base_ + vmap_table_offset_);
DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
}
} else {
- DCHECK(vmap_table_ == NULL);
+ DCHECK(vmap_table_offset_ == 0);
}
#endif
}
OatFile::OatMethod::~OatMethod() {}
-void OatFile::OatMethod::LinkMethod(Method* method) const {
+void OatFile::OatMethod::LinkMethodPointers(Method* method) const {
CHECK(method != NULL);
- method->SetCode(code_);
+ method->SetCode(GetCode());
method->SetFrameSizeInBytes(frame_size_in_bytes_);
method->SetCoreSpillMask(core_spill_mask_);
method->SetFpSpillMask(fp_spill_mask_);
- method->SetMappingTable(mapping_table_);
- method->SetVmapTable(vmap_table_);
- method->SetInvokeStub(invoke_stub_);
+ method->SetMappingTable(GetMappingTable());
+ method->SetVmapTable(GetVmapTable());
+ method->SetInvokeStub(GetInvokeStub());
+}
+
+void OatFile::OatMethod::LinkMethodOffsets(Method* method) const {
+ CHECK(method != NULL);
+ method->SetOatCodeOffset(GetCodeOffset());
+ method->SetFrameSizeInBytes(GetFrameSizeInBytes());
+ method->SetCoreSpillMask(GetCoreSpillMask());
+ method->SetFpSpillMask(GetFpSpillMask());
+ method->SetOatMappingTableOffset(GetMappingTableOffset());
+ method->SetOatVmapTableOffset(GetVmapTableOffset());
+ method->SetOatInvokeStubOffset(GetInvokeStubOffset());
}
} // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
index 2c39e9d..0e22719 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -37,27 +37,79 @@
class OatMethod {
public:
- // Create an OatMethod backed by an OatFile
- OatMethod(const void* code,
- const size_t frame_size_in_bytes,
- const uint32_t core_spill_mask,
- const uint32_t fp_spill_mask,
- const uint32_t* mapping_table,
- const uint16_t* vmap_table,
- const Method::InvokeStub* invoke_stub);
+ // Link Method for execution using the contents of this OatMethod
+ void LinkMethodPointers(Method* method) const;
+
+ // Link Method for image writing using the contents of this OatMethod
+ void LinkMethodOffsets(Method* method) const;
+
+ uint32_t GetCodeOffset() const {
+ return code_offset_;
+ }
+ size_t GetFrameSizeInBytes() const {
+ return frame_size_in_bytes_;
+ }
+ uint32_t GetCoreSpillMask() const {
+ return core_spill_mask_;
+ }
+ uint32_t GetFpSpillMask() const {
+ return fp_spill_mask_;
+ }
+ uint32_t GetMappingTableOffset() const {
+ return mapping_table_offset_;
+ }
+ uint32_t GetVmapTableOffset() const {
+ return vmap_table_offset_;
+ }
+ uint32_t GetInvokeStubOffset() const {
+ return invoke_stub_offset_;
+ }
+
+ const void* GetCode() const {
+ return GetOatPointer<const void*>(code_offset_);
+ }
+ const uint32_t* GetMappingTable() const {
+ return GetOatPointer<const uint32_t*>(mapping_table_offset_);
+ }
+ const uint16_t* GetVmapTable() const {
+ return GetOatPointer<const uint16_t*>(vmap_table_offset_);
+ }
+ const Method::InvokeStub* GetInvokeStub() const {
+ return GetOatPointer<const Method::InvokeStub*>(invoke_stub_offset_);
+ }
~OatMethod();
- // Link Method using the contents of this OatMethod
- void LinkMethod(Method* method) const;
+ // Create an OatMethod with offsets relative to the given base address
+ OatMethod(const byte* base,
+ const uint32_t code_offset,
+ const size_t frame_size_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const uint32_t mapping_table_offset,
+ const uint32_t vmap_table_offset,
+ const uint32_t invoke_stub_offset);
- const void* code_;
+ private:
+ template<class T>
+ T GetOatPointer(uint32_t offset) const {
+ if (offset == 0) {
+ return NULL;
+ }
+ return reinterpret_cast<T>(base_ + offset);
+ }
+
+ const byte* base_;
+
+ uint32_t code_offset_;
size_t frame_size_in_bytes_;
uint32_t core_spill_mask_;
uint32_t fp_spill_mask_;
- const uint32_t* mapping_table_;
- const uint16_t* vmap_table_;
- const Method::InvokeStub* invoke_stub_;
+ uint32_t mapping_table_offset_;
+ uint32_t vmap_table_offset_;
+ uint32_t invoke_stub_offset_;
+
+ friend class OatClass;
};
class OatClass {
@@ -72,16 +124,6 @@
private:
OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer);
- template<class T>
- T GetOatPointer(uint32_t offset) const {
- if (offset == 0) {
- return NULL;
- }
- T pointer = reinterpret_cast<T>(oat_file_->GetBase() + offset);
- CHECK_LT(pointer, reinterpret_cast<T>(oat_file_->GetLimit()));
- return pointer;
- }
-
const OatFile* oat_file_;
const OatMethodOffsets* methods_pointer_;
diff --git a/src/oat_test.cc b/src/oat_test.cc
index 17a00e4..e4af31e 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -15,7 +15,7 @@
SirtRef<ClassLoader> class_loader(NULL);
if (compile) {
- compiler_.reset(new Compiler(kThumb2, false));
+ compiler_.reset(new Compiler(kThumb2, false, NULL));
compiler_->CompileAll(class_loader.get(), class_linker->GetBootClassPath());
}
@@ -56,12 +56,12 @@
method->GetDexMethodIndex()));
if (compiled_method == NULL) {
- EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
- EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
- EXPECT_EQ(oat_method.core_spill_mask_, 0U);
- EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
+ EXPECT_TRUE(oat_method.GetCode() == NULL) << PrettyMethod(method) << " " << oat_method.GetCode();
+ EXPECT_EQ(oat_method.GetFrameSizeInBytes(), static_cast<uint32_t>(kStackAlignment));
+ EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
+ EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
} else {
- const void* oat_code = oat_method.code_;
+ const void* oat_code = oat_method.GetCode();
uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
oat_code = reinterpret_cast<const void*>(oat_code_aligned);
@@ -70,9 +70,9 @@
EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
<< PrettyMethod(method) << " " << code_size;
CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
- EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
- EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
- EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
+ EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
+ EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
+ EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
}
}
for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
@@ -83,12 +83,12 @@
method->GetDexMethodIndex()));
if (compiled_method == NULL) {
- EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
- EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
- EXPECT_EQ(oat_method.core_spill_mask_, 0U);
- EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
+ EXPECT_TRUE(oat_method.GetCode() == NULL) << PrettyMethod(method) << " " << oat_method.GetCode();
+ EXPECT_EQ(oat_method.GetFrameSizeInBytes(), static_cast<uint32_t>(kStackAlignment));
+ EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
+ EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
} else {
- const void* oat_code = oat_method.code_;
+ const void* oat_code = oat_method.GetCode();
EXPECT_TRUE(oat_code != NULL) << PrettyMethod(method);
uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
oat_code = reinterpret_cast<const void*>(oat_code_aligned);
@@ -98,9 +98,9 @@
EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
<< PrettyMethod(method) << " " << code_size;
CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
- EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
- EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
- EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
+ EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
+ EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
+ EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
}
}
}
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 2d5732f..ac9449f 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -177,23 +177,19 @@
os << StringPrintf("\t%d: %s %s (method_idx=%d)\n",
method_index, name, signature.c_str(), method_idx);
os << StringPrintf("\t\tcode: %p (offset=%08x)\n",
- oat_method.code_,
- reinterpret_cast<const byte*>(oat_method.code_) - oat_file.GetBase());
+ oat_method.GetCode(), oat_method.GetCodeOffset());
os << StringPrintf("\t\tframe_size_in_bytes: %d\n",
- oat_method.frame_size_in_bytes_);
+ oat_method.GetFrameSizeInBytes());
os << StringPrintf("\t\tcore_spill_mask: %08x\n",
- oat_method.core_spill_mask_);
+ oat_method.GetCoreSpillMask());
os << StringPrintf("\t\tfp_spill_mask: %08x\n",
- oat_method.fp_spill_mask_);
+ oat_method.GetFpSpillMask());
os << StringPrintf("\t\tmapping_table: %p (offset=%08x)\n",
- oat_method.mapping_table_,
- reinterpret_cast<const byte*>(oat_method.mapping_table_) - oat_file.GetBase());
+ oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
- oat_method.vmap_table_,
- reinterpret_cast<const byte*>(oat_method.vmap_table_) - oat_file.GetBase());
+ oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
- oat_method.invoke_stub_,
- reinterpret_cast<const byte*>(oat_method.invoke_stub_) - oat_file.GetBase());
+ oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
}
};
@@ -268,7 +264,7 @@
os << " (" << oat_location << ")";
}
os << "\n";
- const OatFile* oat_file = class_linker->FindOatFile(oat_location);
+ const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location);
if (oat_file == NULL) {
os << "NOT FOUND\n";
os << std::flush;
@@ -353,8 +349,10 @@
DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
} else {
- size_t register_map_bytes = method->GetGcMap()->SizeOf();
- state->stats_.register_map_bytes += register_map_bytes;
+ if (method->GetGcMap() != NULL) {
+ size_t register_map_bytes = method->GetGcMap()->SizeOf();
+ state->stats_.register_map_bytes += register_map_bytes;
+ }
if (method->GetMappingTable() != NULL) {
size_t pc_mapping_table_bytes = method->GetMappingTableLength();
diff --git a/src/object.cc b/src/object.cc
index 8cf79c2..abf8310 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -209,100 +209,100 @@
}
bool Field::GetBoolean(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimBoolean) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimBoolean) << PrettyField(this);
return Get32(object);
}
void Field::SetBoolean(Object* object, bool z) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimBoolean) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimBoolean) << PrettyField(this);
Set32(object, z);
}
int8_t Field::GetByte(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimByte) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimByte) << PrettyField(this);
return Get32(object);
}
void Field::SetByte(Object* object, int8_t b) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimByte) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimByte) << PrettyField(this);
Set32(object, b);
}
uint16_t Field::GetChar(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimChar) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimChar) << PrettyField(this);
return Get32(object);
}
void Field::SetChar(Object* object, uint16_t c) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimChar) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimChar) << PrettyField(this);
Set32(object, c);
}
int16_t Field::GetShort(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimShort) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimShort) << PrettyField(this);
return Get32(object);
}
void Field::SetShort(Object* object, int16_t s) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimShort) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimShort) << PrettyField(this);
Set32(object, s);
}
int32_t Field::GetInt(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimInt) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimInt) << PrettyField(this);
return Get32(object);
}
void Field::SetInt(Object* object, int32_t i) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimInt) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimInt) << PrettyField(this);
Set32(object, i);
}
int64_t Field::GetLong(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimLong) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimLong) << PrettyField(this);
return Get64(object);
}
void Field::SetLong(Object* object, int64_t j) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimLong) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimLong) << PrettyField(this);
Set64(object, j);
}
float Field::GetFloat(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimFloat) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimFloat) << PrettyField(this);
JValue float_bits;
float_bits.i = Get32(object);
return float_bits.f;
}
void Field::SetFloat(Object* object, float f) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimFloat) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimFloat) << PrettyField(this);
JValue float_bits;
float_bits.f = f;
Set32(object, float_bits.i);
}
double Field::GetDouble(const Object* object) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimDouble) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimDouble) << PrettyField(this);
JValue double_bits;
double_bits.j = Get64(object);
return double_bits.d;
}
void Field::SetDouble(Object* object, double d) const {
- DCHECK(GetPrimitiveType() == Primitive::kPrimDouble) << PrettyField(this);
+ DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimDouble) << PrettyField(this);
JValue double_bits;
double_bits.d = d;
Set64(object, double_bits.j);
}
Object* Field::GetObject(const Object* object) const {
- CHECK(GetPrimitiveType() == Primitive::kPrimNot) << PrettyField(this);
+ CHECK_EQ(GetPrimitiveType(), Primitive::kPrimNot) << PrettyField(this);
return GetObj(object);
}
void Field::SetObject(Object* object, const Object* l) const {
- CHECK(GetPrimitiveType() == Primitive::kPrimNot) << PrettyField(this);
+ CHECK_EQ(GetPrimitiveType(), Primitive::kPrimNot) << PrettyField(this);
SetObj(object, l);
}
diff --git a/src/primitive.cc b/src/primitive.cc
new file mode 100644
index 0000000..16ca0fe
--- /dev/null
+++ b/src/primitive.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "primitive.h"
+
+namespace art {
+
+static const char* kTypeNames[] = {
+ "PrimNot",
+ "PrimBoolean",
+ "PrimByte",
+ "PrimChar",
+ "PrimShort",
+ "PrimInt",
+ "PrimLong",
+ "PrimFloat",
+ "PrimDouble",
+ "PrimVoid",
+};
+std::ostream& operator<<(std::ostream& os, const Primitive::Type& type) {
+ int32_t int_type = static_cast<int32_t>(type);
+ if (type >= Primitive::kPrimNot && type <= Primitive::kPrimVoid) {
+ os << kTypeNames[int_type];
+ } else {
+ os << "Type[" << int_type << "]";
+ }
+ return os;
+}
+
+} // namespace art
diff --git a/src/primitive.h b/src/primitive.h
index 240892f..5d41966 100644
--- a/src/primitive.h
+++ b/src/primitive.h
@@ -116,6 +116,8 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
};
+std::ostream& operator<<(std::ostream& os, const Primitive::Type& state);
+
} // namespace art
#endif // ART_SRC_PRIMITIVE_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 656fdb8..f52bca8 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -446,10 +446,12 @@
// Restore main thread state to kNative as expected by native code
Thread::Current()->SetState(Thread::kNative);
- InitNativeMethods();
-
started_ = true;
+ // InitNativeMethods needs to be after started_ so that the classes
+ // it touches will have methods linked to the oat file if necessary.
+ InitNativeMethods();
+
Thread::FinishStartup();
if (!is_zygote_) {
@@ -564,9 +566,10 @@
Thread::Current()->SetState(Thread::kRunnable);
CHECK_GE(Heap::GetSpaces().size(), 1U);
+ bool verbose_class = options->IsVerbose("class");
class_linker_ = ((Heap::GetSpaces()[0]->IsImageSpace())
- ? ClassLinker::Create(intern_table_)
- : ClassLinker::Create(options->boot_class_path_, intern_table_));
+ ? ClassLinker::Create(verbose_class, intern_table_)
+ : ClassLinker::Create(verbose_class, options->boot_class_path_, intern_table_));
if (IsVerboseStartup()) {
LOG(INFO) << "Runtime::Init exiting";
@@ -793,7 +796,7 @@
resolution_stub_array_[type] = resolution_stub_array;
}
-Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns, CalleeSaveType type) {
+Method* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type) {
Class* method_class = Method::GetMethodClass();
SirtRef<Method> method(down_cast<Method*>(method_class->AllocObject()));
method->SetDeclaringClass(method_class);
@@ -811,7 +814,7 @@
method->SetSignature(intern_table_->InternStrong("()V"));
CHECK(method->GetSignature() != NULL);
method->SetCode(NULL);
- if ((insns == kThumb2) || (insns == kArm)) {
+ if ((instruction_set == kThumb2) || (instruction_set == kArm)) {
uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) |
(1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11);
uint32_t arg_spills = (1 << art::arm::R1) | (1 << art::arm::R2) | (1 << art::arm::R3);
@@ -836,7 +839,7 @@
method->SetFrameSizeInBytes(frame_size);
method->SetCoreSpillMask(core_spills);
method->SetFpSpillMask(fp_spills);
- } else if (insns == kX86) {
+ } else if (instruction_set == kX86) {
method->SetFrameSizeInBytes(32);
method->SetCoreSpillMask((1 << art::x86::EBX) | (1 << art::x86::EBP) | (1 << art::x86::ESI) |
(1 << art::x86::EDI));
diff --git a/src/runtime.h b/src/runtime.h
index 50f9ed1..1d9a3d1 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -190,13 +190,13 @@
kRefsAndArgs,
kLastCalleeSaveType // Value used for iteration
};
- Method* CreateCalleeSaveMethod(InstructionSet insns, CalleeSaveType type);
+ Method* CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type);
bool HasCalleeSaveMethod(CalleeSaveType type) const;
Method* GetCalleeSaveMethod(CalleeSaveType type) const;
void SetCalleeSaveMethod(Method* method, CalleeSaveType type);
- Method* CreateRefOnlyCalleeSaveMethod(InstructionSet insns);
- Method* CreateRefAndArgsCalleeSaveMethod(InstructionSet insns);
+ Method* CreateRefOnlyCalleeSaveMethod(InstructionSet instruction_set);
+ Method* CreateRefAndArgsCalleeSaveMethod(InstructionSet instruction_set);
int32_t GetStat(int kind);