summaryrefslogtreecommitdiffstats
path: root/dex2oat
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2014-08-01 19:04:18 +0100
committerVladimir Marko <vmarko@google.com>2014-09-25 18:56:34 +0100
commitf4da675bbc4615c5f854c81964cac9dd1153baea (patch)
treeea78bafc7ee543e11e7bd824ab40d5f5f3d82f9d /dex2oat
parentf2476d524281c6d649f5deb6d1ccccc92380c1ed (diff)
downloadandroid_art-f4da675bbc4615c5f854c81964cac9dd1153baea.tar.gz
android_art-f4da675bbc4615c5f854c81964cac9dd1153baea.tar.bz2
android_art-f4da675bbc4615c5f854c81964cac9dd1153baea.zip
Implement method calls using relative BL on ARM.
Store the linker patches with each CompiledMethod instead of keeping them in CompilerDriver. Reorganize oat file creation to apply the patches as we're writing the method code. Add framework for platform-specific relative call patches in the OatWriter. Implement relative call patches for ARM. Change-Id: Ie2effb3d92b61ac8f356140eba09dc37d62290f8
Diffstat (limited to 'dex2oat')
-rw-r--r--dex2oat/dex2oat.cc256
1 files changed, 133 insertions, 123 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 9e6e95855b..09825e2cd0 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -45,7 +45,6 @@
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "elf_fixup.h"
-#include "elf_patcher.h"
#include "elf_stripper.h"
#include "gc/space/image_space.h"
#include "gc/space/space-inl.h"
@@ -261,12 +260,12 @@ class Dex2Oat {
CHECK(verification_results != nullptr);
CHECK(method_inliner_map != nullptr);
std::unique_ptr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
- compiler_kind,
- instruction_set,
- instruction_set_features,
- verification_results,
- method_inliner_map,
- thread_count));
+ compiler_kind,
+ instruction_set,
+ instruction_set_features,
+ verification_results,
+ method_inliner_map,
+ thread_count));
if (!dex2oat->CreateRuntime(runtime_options, instruction_set)) {
*p_dex2oat = nullptr;
return false;
@@ -341,39 +340,16 @@ class Dex2Oat {
return ReadImageClasses(image_classes_stream);
}
- bool PatchOatCode(const CompilerDriver* compiler_driver, File* oat_file,
- const std::string& oat_location, std::string* error_msg) {
- // We asked to include patch information but we are not making an image. We need to fix
- // everything up manually.
- std::unique_ptr<ElfFile> elf_file(ElfFile::Open(oat_file, PROT_READ|PROT_WRITE,
- MAP_SHARED, error_msg));
- if (elf_file.get() == NULL) {
- LOG(ERROR) << error_msg;
- return false;
- }
- {
- ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
- return ElfPatcher::Patch(compiler_driver, elf_file.get(), oat_location, error_msg);
- }
- }
-
- const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
- const std::string& android_root,
- bool is_host,
- const std::vector<const DexFile*>& dex_files,
- File* oat_file,
- const std::string& oat_location,
- const std::string& bitcode_filename,
- bool image,
- std::unique_ptr<std::set<std::string>>& image_classes,
- bool dump_stats,
- bool dump_passes,
- TimingLogger& timings,
- CumulativeLogger& compiler_phases_timings,
- std::string profile_file,
- SafeMap<std::string, std::string>* key_value_store) {
- CHECK(key_value_store != nullptr);
-
+ void Compile(const std::string& boot_image_option,
+ const std::vector<const DexFile*>& dex_files,
+ const std::string& bitcode_filename,
+ bool image,
+ std::unique_ptr<std::set<std::string>>& image_classes,
+ bool dump_stats,
+ bool dump_passes,
+ TimingLogger* timings,
+ CumulativeLogger* compiler_phases_timings,
+ const std::string& profile_file) {
// Handle and ClassLoader creation needs to come after Runtime::Create
jobject class_loader = nullptr;
Thread* self = Thread::Current();
@@ -392,31 +368,45 @@ class Dex2Oat {
Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
}
- std::unique_ptr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
- verification_results_,
- method_inliner_map_,
- compiler_kind_,
- instruction_set_,
- instruction_set_features_,
- image,
- image_classes.release(),
- thread_count_,
- dump_stats,
- dump_passes,
- &compiler_phases_timings,
- profile_file));
-
- driver->GetCompiler()->SetBitcodeFileName(*driver.get(), bitcode_filename);
-
- driver->CompileAll(class_loader, dex_files, &timings);
-
- TimingLogger::ScopedTiming t2("dex2oat OatWriter", &timings);
+ driver_.reset(new CompilerDriver(compiler_options_,
+ verification_results_,
+ method_inliner_map_,
+ compiler_kind_,
+ instruction_set_,
+ instruction_set_features_,
+ image,
+ image_classes.release(),
+ thread_count_,
+ dump_stats,
+ dump_passes,
+ compiler_phases_timings,
+ profile_file));
+
+ driver_->GetCompiler()->SetBitcodeFileName(*driver_, bitcode_filename);
+
+ driver_->CompileAll(class_loader, dex_files, timings);
+ }
+
+ void PrepareImageWriter(uintptr_t image_base) {
+ image_writer_.reset(new ImageWriter(*driver_, image_base));
+ }
+
+ bool CreateOatFile(const std::vector<const DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host,
+ File* oat_file,
+ const std::string& oat_location,
+ TimingLogger* timings,
+ SafeMap<std::string, std::string>* key_value_store) {
+ CHECK(key_value_store != nullptr);
+
+ TimingLogger::ScopedTiming t2("dex2oat OatWriter", timings);
std::string image_file_location;
uint32_t image_file_location_oat_checksum = 0;
uintptr_t image_file_location_oat_data_begin = 0;
int32_t image_patch_delta = 0;
- if (!driver->IsImage()) {
- TimingLogger::ScopedTiming t3("Loading image checksum", &timings);
+ if (!driver_->IsImage()) {
+ TimingLogger::ScopedTiming t3("Loading image checksum", timings);
gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
image_file_location_oat_data_begin =
@@ -432,49 +422,50 @@ class Dex2Oat {
OatWriter oat_writer(dex_files, image_file_location_oat_checksum,
image_file_location_oat_data_begin,
image_patch_delta,
- driver.get(),
- &timings,
+ driver_.get(),
+ image_writer_.get(),
+ timings,
key_value_store);
+ if (driver_->IsImage()) {
+ // The OatWriter constructor has already updated offsets in methods and we need to
+ // prepare method offsets in the image address space for direct method patching.
+ t2.NewTiming("Preparing image address space");
+ if (!image_writer_->PrepareImageAddressSpace()) {
+ LOG(ERROR) << "Failed to prepare image address space.";
+ return false;
+ }
+ }
+
t2.NewTiming("Writing ELF");
- if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
+ if (!driver_->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
- return nullptr;
+ return false;
}
- // Flush result to disk. Patching code will re-open the file (mmap), so ensure that our view
- // of the file already made it there and won't be re-ordered with writes from PatchOat or
- // image patching.
- oat_file->Flush();
-
- if (!driver->IsImage() && driver->GetCompilerOptions().GetIncludePatchInformation()) {
- t2.NewTiming("Patching ELF");
- std::string error_msg;
- if (!PatchOatCode(driver.get(), oat_file, oat_location, &error_msg)) {
- LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath() << ": " << error_msg;
- return nullptr;
- }
+ // Flush result to disk.
+ t2.NewTiming("Flushing ELF");
+ if (oat_file->Flush() != 0) {
+ LOG(ERROR) << "Failed to flush ELF file " << oat_file->GetPath();
+ return false;
}
- return driver.release();
+ return true;
}
bool CreateImageFile(const std::string& image_filename,
- uintptr_t image_base,
const std::string& oat_filename,
- const std::string& oat_location,
- const CompilerDriver& compiler)
+ const std::string& oat_location)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
- uintptr_t oat_data_begin;
- {
- // ImageWriter is scoped so it can free memory before doing FixupElf
- ImageWriter image_writer(compiler);
- if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
- LOG(ERROR) << "Failed to create image file " << image_filename;
- return false;
- }
- oat_data_begin = image_writer.GetOatDataBegin();
+ CHECK(image_writer_ != nullptr);
+ if (!image_writer_->Write(image_filename, oat_filename, oat_location)) {
+ LOG(ERROR) << "Failed to create image file " << image_filename;
+ return false;
}
+ uintptr_t oat_data_begin = image_writer_->GetOatDataBegin();
+
+ // Destroy ImageWriter before doing FixupElf.
+ image_writer_.reset();
std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
if (oat_file.get() == nullptr) {
@@ -504,7 +495,9 @@ class Dex2Oat {
method_inliner_map_(method_inliner_map),
runtime_(nullptr),
thread_count_(thread_count),
- start_ns_(NanoTime()) {
+ start_ns_(NanoTime()),
+ driver_(nullptr),
+ image_writer_(nullptr) {
CHECK(compiler_options != nullptr);
CHECK(verification_results != nullptr);
CHECK(method_inliner_map != nullptr);
@@ -571,6 +564,8 @@ class Dex2Oat {
Runtime* runtime_;
size_t thread_count_;
uint64_t start_ns_;
+ std::unique_ptr<CompilerDriver> driver_;
+ std::unique_ptr<ImageWriter> image_writer_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
};
@@ -1421,22 +1416,28 @@ static int dex2oat(int argc, char** argv) {
oss << kRuntimeISA;
key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str());
- std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
- android_root,
- is_host,
- dex_files,
- oat_file.get(),
- oat_location,
- bitcode_filename,
- image,
- image_classes,
- dump_stats,
- dump_passes,
- timings,
- compiler_phases_timings,
- profile_file,
- key_value_store.get()));
- if (compiler.get() == nullptr) {
+ dex2oat->Compile(boot_image_option,
+ dex_files,
+ bitcode_filename,
+ image,
+ image_classes,
+ dump_stats,
+ dump_passes,
+ &timings,
+ &compiler_phases_timings,
+ profile_file);
+
+ if (image) {
+ dex2oat->PrepareImageWriter(image_base);
+ }
+
+ if (!dex2oat->CreateOatFile(dex_files,
+ android_root,
+ is_host,
+ oat_file.get(),
+ oat_location,
+ &timings,
+ key_value_store.get())) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
return EXIT_FAILURE;
}
@@ -1472,34 +1473,43 @@ static int dex2oat(int argc, char** argv) {
//
// To get this all correct, we go through several steps.
//
- // 1. We have already created that oat file above with
- // CreateOatFile. Originally this was just our own proprietary file
- // but now it is contained within an ELF dynamic object (aka an .so
- // file). The Compiler returned by CreateOatFile provides
- // PatchInformation for references to oat code and Methods that need
- // to be update once we know where the oat file will be located
- // after the image.
+ // 1. We prepare offsets for all data in the oat file and calculate
+ // the oat data size and code size. During this stage, we also set
+ // oat code offsets in methods for use by the image writer.
+ //
+ // 2. We prepare offsets for the objects in the image and calculate
+ // the image size.
//
- // 2. We create the image file. It needs to know where the oat file
+ // 3. We create the oat file. Originally this was just our own proprietary
+ // file but now it is contained within an ELF dynamic object (aka an .so
+ // file). Since we know the image size and oat data size and code size we
+ // can prepare the ELF headers and we then know the ELF memory segment
+ // layout and we can now resolve all references. The compiler provides
+ // LinkerPatch information in each CompiledMethod and we resolve these,
+ // using the layout information and image object locations provided by
+ // image writer, as we're writing the method code.
+ //
+ // 4. We create the image file. It needs to know where the oat file
// will be loaded after itself. Originally when oat file was simply
// memory mapped so we could predict where its contents were based
// on the file size. Now that it is an ELF file, we need to inspect
// the ELF file to understand the in memory segment layout including
- // where the oat header is located within. ElfPatcher's Patch method
- // uses the PatchInformation from the Compiler to touch up absolute
- // references in the oat file.
+ // where the oat header is located within.
+ // TODO: We could just remember this information from step 3.
//
- // 3. We fixup the ELF program headers so that dlopen will try to
+ // 5. We fixup the ELF program headers so that dlopen will try to
// load the .so at the desired location at runtime by offsetting the
// Elf32_Phdr.p_vaddr values by the desired base address.
+ // TODO: Do this in step 3. We already know the layout there.
+ //
+ // Steps 1.-3. are done by the CreateOatFile() above, steps 4.-5.
+ // are done by the CreateImageFile() below.
//
if (image) {
TimingLogger::ScopedTiming t("dex2oat ImageWriter", &timings);
bool image_creation_success = dex2oat->CreateImageFile(image_filename,
- image_base,
oat_unstripped,
- oat_location,
- *compiler.get());
+ oat_location);
if (!image_creation_success) {
return EXIT_FAILURE;
}
@@ -1512,7 +1522,7 @@ static int dex2oat(int argc, char** argv) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
if (dump_passes) {
- LOG(INFO) << Dumpable<CumulativeLogger>(*compiler.get()->GetTimingsLogger());
+ LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
}
return EXIT_SUCCESS;
}