summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2013-07-23 22:35:16 -0700
committerBrian Carlstrom <bdc@google.com>2013-07-24 09:19:30 -0700
commitc50d8e11a098cc5c6239aa86b47d4fcf8cbb4899 (patch)
tree4273347ed7aa19c6edbe70e986f588007ec8f5e0
parenta3d6b8cb884fce2fe34258e9d582b11ea9545fd9 (diff)
downloadart-c50d8e11a098cc5c6239aa86b47d4fcf8cbb4899.zip
art-c50d8e11a098cc5c6239aa86b47d4fcf8cbb4899.tar.gz
art-c50d8e11a098cc5c6239aa86b47d4fcf8cbb4899.tar.bz2
Remove OatWriter buffering to memory for ElfWriterQuick
This allows the oat contents to be directly written to the file. Change-Id: Ibc7ddf57477b152f07784b52f7334be73fd22833
-rw-r--r--compiler/driver/compiler_driver.cc6
-rw-r--r--compiler/driver/compiler_driver.h3
-rw-r--r--compiler/elf_writer.h3
-rw-r--r--compiler/elf_writer_mclinker.cc15
-rw-r--r--compiler/elf_writer_mclinker.h4
-rw-r--r--compiler/elf_writer_quick.cc23
-rw-r--r--compiler/elf_writer_quick.h4
-rw-r--r--compiler/image_writer.cc4
-rw-r--r--compiler/oat_writer.cc215
-rw-r--r--compiler/oat_writer.h51
-rw-r--r--dex2oat/dex2oat.cc27
-rw-r--r--runtime/image_test.cc20
-rw-r--r--runtime/oat_test.cc26
13 files changed, 211 insertions, 190 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1f66730..ea2291c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2343,13 +2343,13 @@ bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex
bool CompilerDriver::WriteElf(const std::string& android_root,
bool is_host,
const std::vector<const art::DexFile*>& dex_files,
- std::vector<uint8_t>& oat_contents,
+ OatWriter& oat_writer,
art::File* file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
#if defined(ART_USE_PORTABLE_COMPILER)
- return art::ElfWriterMclinker::Create(file, oat_contents, dex_files, android_root, is_host, *this);
+ return art::ElfWriterMclinker::Create(file, oat_writer, dex_files, android_root, is_host, *this);
#else
- return art::ElfWriterQuick::Create(file, oat_contents, dex_files, android_root, is_host, *this);
+ return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, *this);
#endif
}
void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 1799057..f3f72dd 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -39,6 +39,7 @@ namespace art {
class AOTCompilationStats;
class ParallelCompilationManager;
class DexCompilationUnit;
+class OatWriter;
class TimingLogger;
enum CompilerBackend {
@@ -192,7 +193,7 @@ class CompilerDriver {
bool WriteElf(const std::string& android_root,
bool is_host,
const std::vector<const DexFile*>& dex_files,
- std::vector<uint8_t>& oat_contents,
+ OatWriter& oat_writer,
File* file);
// TODO: move to a common home for llvm helpers once quick/portable are merged
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 0dfce6e..0ef4185 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -33,6 +33,7 @@ namespace art {
class CompilerDriver;
class DexFile;
class ElfFile;
+class OatWriter;
class ElfWriter {
public:
@@ -49,7 +50,7 @@ class ElfWriter {
ElfWriter(const CompilerDriver& driver, File* elf_file);
virtual ~ElfWriter();
- virtual bool Write(std::vector<uint8_t>& oat_contents,
+ virtual bool Write(OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host)
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index 05f3b02..2a9bc35 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -36,7 +36,9 @@
#include "mirror/abstract_method.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object-inl.h"
+#include "oat_writer.h"
#include "scoped_thread_state_change.h"
+#include "vector_output_stream.h"
namespace art {
@@ -46,19 +48,25 @@ ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_fil
ElfWriterMclinker::~ElfWriterMclinker() {}
bool ElfWriterMclinker::Create(File* elf_file,
- std::vector<uint8_t>& oat_contents,
+ OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
const CompilerDriver& driver) {
ElfWriterMclinker elf_writer(driver, elf_file);
- return elf_writer.Write(oat_contents, dex_files, android_root, is_host);
+ return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-bool ElfWriterMclinker::Write(std::vector<uint8_t>& oat_contents,
+bool ElfWriterMclinker::Write(OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host) {
+ std::vector<uint8_t> oat_contents;
+ oat_contents.reserve(oat_writer.GetSize());
+ VectorOutputStream output_stream("oat contents", oat_contents);
+ CHECK(oat_writer.Write(output_stream));
+ CHECK_EQ(oat_writer.GetSize(), oat_contents.size());
+
Init();
AddOatInput(oat_contents);
#if defined(ART_USE_PORTABLE_COMPILER)
@@ -68,6 +76,7 @@ bool ElfWriterMclinker::Write(std::vector<uint8_t>& oat_contents,
if (!Link()) {
return false;
}
+ oat_contents.clear();
#if defined(ART_USE_PORTABLE_COMPILER)
FixupOatMethodOffsets(dex_files);
#endif
diff --git a/compiler/elf_writer_mclinker.h b/compiler/elf_writer_mclinker.h
index 3b33bc4..bdadf8f 100644
--- a/compiler/elf_writer_mclinker.h
+++ b/compiler/elf_writer_mclinker.h
@@ -40,7 +40,7 @@ class ElfWriterMclinker : public ElfWriter {
public:
// Write an ELF file. Returns true on success, false on failure.
static bool Create(File* file,
- std::vector<uint8_t>& oat_contents,
+ OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -48,7 +48,7 @@ class ElfWriterMclinker : public ElfWriter {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual bool Write(std::vector<uint8_t>& oat_contents,
+ virtual bool Write(OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host)
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 9de96d2..f2db5d8 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -19,8 +19,10 @@
#include "base/logging.h"
#include "base/unix_file/fd_file.h"
#include "driver/compiler_driver.h"
+#include "file_output_stream.h"
#include "globals.h"
#include "oat.h"
+#include "oat_writer.h"
#include "utils.h"
namespace art {
@@ -31,16 +33,16 @@ ElfWriterQuick::ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
ElfWriterQuick::~ElfWriterQuick() {}
bool ElfWriterQuick::Create(File* elf_file,
- std::vector<uint8_t>& oat_contents,
+ OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
const CompilerDriver& driver) {
ElfWriterQuick elf_writer(driver, elf_file);
- return elf_writer.Write(oat_contents, dex_files, android_root, is_host);
+ return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-bool ElfWriterQuick::Write(std::vector<uint8_t>& oat_contents,
+bool ElfWriterQuick::Write(OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files_unused,
const std::string& android_root_unused,
bool is_host_unused) {
@@ -193,9 +195,9 @@ bool ElfWriterQuick::Write(std::vector<uint8_t>& oat_contents,
// .rodata
uint32_t oat_data_alignment = kPageSize;
uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment);
- const OatHeader* oat_header = reinterpret_cast<OatHeader*>(&oat_contents[0]);
- CHECK(oat_header->IsValid());
- uint32_t oat_data_size = oat_header->GetExecutableOffset();
+ const OatHeader& oat_header = oat_writer.GetOatHeader();
+ CHECK(oat_header.IsValid());
+ uint32_t oat_data_size = oat_header.GetExecutableOffset();
expected_offset += oat_data_size;
if (debug) {
LOG(INFO) << "oat_data_offset=" << oat_data_offset << std::hex << " " << oat_data_offset;
@@ -206,9 +208,9 @@ bool ElfWriterQuick::Write(std::vector<uint8_t>& oat_contents,
uint32_t oat_exec_alignment = kPageSize;
CHECK_ALIGNED(expected_offset, kPageSize);
uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment);
- uint32_t oat_exec_size = oat_contents.size() - oat_data_size;
+ uint32_t oat_exec_size = oat_writer.GetSize() - oat_data_size;
expected_offset += oat_exec_size;
- CHECK_EQ(oat_data_offset + oat_contents.size(), expected_offset);
+ CHECK_EQ(oat_data_offset + oat_writer.GetSize(), expected_offset);
if (debug) {
LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset;
LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size;
@@ -617,13 +619,14 @@ bool ElfWriterQuick::Write(std::vector<uint8_t>& oat_contents,
<< " for " << elf_file_->GetPath();
return false;
}
- if (!elf_file_->WriteFully(&oat_contents[0], oat_contents.size())) {
+ FileOutputStream output_stream(elf_file_);
+ if (!oat_writer.Write(output_stream)) {
PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath();
return false;
}
// .dynamic
- DCHECK_LE(oat_data_offset + oat_contents.size(), dynamic_offset);
+ DCHECK_LE(oat_data_offset + oat_writer.GetSize(), dynamic_offset);
if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) {
PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset
<< " for " << elf_file_->GetPath();
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index a15c239..f36d06f 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -25,7 +25,7 @@ class ElfWriterQuick : public ElfWriter {
public:
// Write an ELF file. Returns true on success, false on failure.
static bool Create(File* file,
- std::vector<uint8_t>& oat_contents,
+ OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host,
@@ -33,7 +33,7 @@ class ElfWriterQuick : public ElfWriter {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
protected:
- virtual bool Write(std::vector<uint8_t>& oat_contents,
+ virtual bool Write(OatWriter& oat_writer,
const std::vector<const DexFile*>& dex_files,
const std::string& android_root,
bool is_host)
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index f395428..1612f7e 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -85,6 +85,10 @@ bool ImageWriter::Write(const std::string& image_filename,
return false;
}
oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
+ if (oat_file_ == NULL) {
+ LOG(ERROR) << "Failed to open writable oat file " << oat_filename << " for " << oat_location;
+ return false;
+ }
class_linker->RegisterOatFile(*oat_file_);
interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset();
interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset();
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index da05c49..5eb837b 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -35,20 +35,6 @@
namespace art {
-bool OatWriter::Create(OutputStream& output_stream,
- const std::vector<const DexFile*>& dex_files,
- uint32_t image_file_location_oat_checksum,
- uint32_t image_file_location_oat_begin,
- const std::string& image_file_location,
- const CompilerDriver& driver) {
- OatWriter oat_writer(dex_files,
- image_file_location_oat_checksum,
- image_file_location_oat_begin,
- image_file_location,
- &driver);
- return oat_writer.Write(output_stream);
-}
-
OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_begin,
@@ -89,6 +75,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
offset = InitOatClasses(offset);
offset = InitOatCode(offset);
offset = InitOatCodeDexFiles(offset);
+ size_ = offset;
CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
CHECK(image_file_location.empty() == compiler->IsImage());
@@ -190,7 +177,8 @@ size_t OatWriter::InitOatCode(size_t offset) {
if (compiler_driver_->IsImage()) {
InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
- interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+ interpreter_to_interpreter_entry_.reset(
+ compiler_driver_->CreateInterpreterToInterpreterEntry());
offset += interpreter_to_interpreter_entry_->size();
offset = CompiledCode::AlignCode(offset, instruction_set);
@@ -336,7 +324,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
// Deduplicate mapping tables
- SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
+ SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
+ mapping_table_offsets_.find(&mapping_table);
if (mapping_iter != mapping_table_offsets_.end()) {
mapping_table_offset = mapping_iter->second;
} else {
@@ -350,7 +339,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
// Deduplicate vmap tables
- SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
+ SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
+ vmap_table_offsets_.find(&vmap_table);
if (vmap_iter != vmap_table_offsets_.end()) {
vmap_table_offset = vmap_iter->second;
} else {
@@ -382,7 +372,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
#endif
// Deduplicate GC maps
- SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
+ SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
+ gc_map_offsets_.find(&gc_map);
if (gc_map_iter != gc_map_offsets_.end()) {
gc_map_offset = gc_map_iter->second;
} else {
@@ -392,14 +383,14 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
}
}
- oat_class->method_offsets_[class_def_method_index]
- = OatMethodOffsets(code_offset,
- frame_size_in_bytes,
- core_spill_mask,
- fp_spill_mask,
- mapping_table_offset,
- vmap_table_offset,
- gc_map_offset);
+ oat_class->method_offsets_[class_def_method_index] =
+ OatMethodOffsets(code_offset,
+ frame_size_in_bytes,
+ core_spill_mask,
+ fp_spill_mask,
+ mapping_table_offset,
+ vmap_table_offset,
+ gc_map_offset);
if (compiler_driver_->IsImage()) {
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -428,12 +419,16 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
}
#define DCHECK_OFFSET() \
- DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent))
+ DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
+ << "file_offset=" << file_offset << " relative_offset=" << relative_offset
#define DCHECK_OFFSET_() \
- DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent))
+ DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
+ << "file_offset=" << file_offset << " offset_=" << offset_
bool OatWriter::Write(OutputStream& out) {
+ const size_t file_offset = out.Seek(0, kSeekCurrent);
+
if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
return false;
@@ -446,19 +441,19 @@ bool OatWriter::Write(OutputStream& out) {
}
size_oat_header_image_file_location_ += image_file_location_.size();
- if (!WriteTables(out)) {
+ if (!WriteTables(out, file_offset)) {
LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
return false;
}
- size_t code_offset = WriteCode(out);
- if (code_offset == 0) {
+ size_t relative_offset = WriteCode(out, file_offset);
+ if (relative_offset == 0) {
LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
return false;
}
- code_offset = WriteCodeDexFiles(out, code_offset);
- if (code_offset == 0) {
+ relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
+ if (relative_offset == 0) {
LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
return false;
}
@@ -495,21 +490,25 @@ bool OatWriter::Write(OutputStream& out) {
#undef DO_STAT
LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
- CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(size_, size_total);
}
+ CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+ CHECK_EQ(size_, relative_offset);
+
return true;
}
-bool OatWriter::WriteTables(OutputStream& out) {
+bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
- if (!oat_dex_files_[i]->Write(this, out)) {
+ if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
return false;
}
}
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
- uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
+ uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
off_t actual_offset = out.Seek(expected_offset, kSeekSet);
if (static_cast<uint32_t>(actual_offset) != expected_offset) {
const DexFile* dex_file = (*dex_files_)[i];
@@ -519,13 +518,14 @@ bool OatWriter::WriteTables(OutputStream& out) {
}
const DexFile* dex_file = (*dex_files_)[i];
if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
- PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
+ PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
+ << " to " << out.GetLocation();
return false;
}
size_dex_file_ += dex_file->GetHeader().file_size_;
}
for (size_t i = 0; i != oat_classes_.size(); ++i) {
- if (!oat_classes_[i]->Write(this, out)) {
+ if (!oat_classes_[i]->Write(this, out, file_offset)) {
PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
return false;
}
@@ -533,27 +533,29 @@ bool OatWriter::WriteTables(OutputStream& out) {
return true;
}
-size_t OatWriter::WriteCode(OutputStream& out) {
- uint32_t offset = oat_header_->GetExecutableOffset();
+size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
+ size_t relative_offset = oat_header_->GetExecutableOffset();
off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
- if (static_cast<uint32_t>(new_offset) != offset) {
+ size_t expected_file_offset = file_offset + relative_offset;
+ if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
- << " Expected: " << offset << " File: " << out.GetLocation();
+ << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
return 0;
}
DCHECK_OFFSET();
if (compiler_driver_->IsImage()) {
InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
- if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) {
+ if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0],
+ interpreter_to_interpreter_entry_->size())) {
PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation();
return false;
}
size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size();
- offset += interpreter_to_interpreter_entry_->size();
+ relative_offset += interpreter_to_interpreter_entry_->size();
DCHECK_OFFSET();
- uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
- uint32_t alignment_padding = aligned_offset - offset;
+ uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set);
+ uint32_t alignment_padding = aligned_offset - relative_offset;
out.Seek(alignment_padding, kSeekCurrent);
size_stubs_alignment_ += alignment_padding;
if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
@@ -561,60 +563,67 @@ size_t OatWriter::WriteCode(OutputStream& out) {
return false;
}
size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
- offset += alignment_padding + interpreter_to_quick_entry_->size();
+ relative_offset += alignment_padding + interpreter_to_quick_entry_->size();
DCHECK_OFFSET();
- aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
- alignment_padding = aligned_offset - offset;
+ aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set);
+ alignment_padding = aligned_offset - relative_offset;
out.Seek(alignment_padding, kSeekCurrent);
size_stubs_alignment_ += alignment_padding;
- if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) {
+ if (!out.WriteFully(&(*portable_resolution_trampoline_)[0],
+ portable_resolution_trampoline_->size())) {
PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation();
return false;
}
size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size();
- offset += alignment_padding + portable_resolution_trampoline_->size();
+ relative_offset += alignment_padding + portable_resolution_trampoline_->size();
DCHECK_OFFSET();
- aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
- alignment_padding = aligned_offset - offset;
+ aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set);
+ alignment_padding = aligned_offset - relative_offset;
out.Seek(alignment_padding, kSeekCurrent);
size_stubs_alignment_ += alignment_padding;
- if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) {
+ if (!out.WriteFully(&(*quick_resolution_trampoline_)[0],
+ quick_resolution_trampoline_->size())) {
PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation();
return false;
}
size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size();
- offset += alignment_padding + quick_resolution_trampoline_->size();
+ relative_offset += alignment_padding + quick_resolution_trampoline_->size();
DCHECK_OFFSET();
}
- return offset;
+ return relative_offset;
}
-size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) {
+size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
+ const size_t file_offset,
+ size_t relative_offset) {
size_t oat_class_index = 0;
for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
const DexFile* dex_file = (*dex_files_)[i];
CHECK(dex_file != NULL);
- code_offset = WriteCodeDexFile(out, code_offset, oat_class_index, *dex_file);
- if (code_offset == 0) {
+ relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, oat_class_index,
+ *dex_file);
+ if (relative_offset == 0) {
return 0;
}
}
- return code_offset;
+ return relative_offset;
}
-size_t OatWriter::WriteCodeDexFile(OutputStream& out, size_t code_offset, size_t& oat_class_index,
+size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
+ size_t relative_offset, size_t& oat_class_index,
const DexFile& dex_file) {
for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
class_def_index++, oat_class_index++) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- code_offset = WriteCodeClassDef(out, code_offset, oat_class_index, dex_file, class_def);
- if (code_offset == 0) {
+ relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, oat_class_index,
+ dex_file, class_def);
+ if (relative_offset == 0) {
return 0;
}
}
- return code_offset;
+ return relative_offset;
}
void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
@@ -624,13 +633,15 @@ void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
}
size_t OatWriter::WriteCodeClassDef(OutputStream& out,
- size_t code_offset, size_t oat_class_index,
+ const size_t file_offset,
+ size_t relative_offset,
+ size_t oat_class_index,
const DexFile& dex_file,
const DexFile::ClassDef& class_def) {
const byte* class_data = dex_file.GetClassData(class_def);
if (class_data == NULL) {
// ie. an empty class such as a marker interface
- return code_offset;
+ return relative_offset;
}
ClassDataItemIterator it(dex_file, class_data);
// Skip fields
@@ -644,27 +655,29 @@ size_t OatWriter::WriteCodeClassDef(OutputStream& out,
size_t class_def_method_index = 0;
while (it.HasNextDirectMethod()) {
bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
- code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
- is_static, it.GetMemberIndex(), dex_file);
- if (code_offset == 0) {
+ relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
+ class_def_method_index, is_static, it.GetMemberIndex(),
+ dex_file);
+ if (relative_offset == 0) {
return 0;
}
class_def_method_index++;
it.Next();
}
while (it.HasNextVirtualMethod()) {
- code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
- false, it.GetMemberIndex(), dex_file);
- if (code_offset == 0) {
+ relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
+ class_def_method_index, false, it.GetMemberIndex(), dex_file);
+ if (relative_offset == 0) {
return 0;
}
class_def_method_index++;
it.Next();
}
- return code_offset;
+ return relative_offset;
}
-size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
+size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
+ size_t relative_offset, size_t oat_class_index,
size_t class_def_method_index, bool is_static,
uint32_t method_idx, const DexFile& dex_file) {
const CompiledMethod* compiled_method =
@@ -676,26 +689,27 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
if (compiled_method != NULL) { // ie. not an abstract method
#if !defined(ART_USE_PORTABLE_COMPILER)
- uint32_t aligned_offset = compiled_method->AlignCode(offset);
- uint32_t aligned_code_delta = aligned_offset - offset;
+ uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
+ uint32_t aligned_code_delta = aligned_offset - relative_offset;
if (aligned_code_delta != 0) {
off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
size_code_alignment_ += aligned_code_delta;
- if (static_cast<uint32_t>(new_offset) != aligned_offset) {
+ uint32_t expected_offset = file_offset + aligned_offset;
+ if (static_cast<uint32_t>(new_offset) != expected_offset) {
PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
- << " Expected: " << aligned_offset << " File: " << out.GetLocation();
+ << " Expected: " << expected_offset << " File: " << out.GetLocation();
return 0;
}
- offset += aligned_code_delta;
+ relative_offset += aligned_code_delta;
DCHECK_OFFSET();
}
- DCHECK_ALIGNED(offset, kArmAlignment);
+ DCHECK_ALIGNED(relative_offset, kArmAlignment);
const std::vector<uint8_t>& code = compiled_method->GetCode();
uint32_t code_size = code.size() * sizeof(code[0]);
CHECK_NE(code_size, 0U);
// Deduplicate code arrays
- size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta();
+ size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta();
SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
DCHECK(code_iter->second == method_offsets.code_offset_)
@@ -707,14 +721,14 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
return 0;
}
size_code_size_ += sizeof(code_size);
- offset += sizeof(code_size);
+ relative_offset += sizeof(code_size);
DCHECK_OFFSET();
if (!out.WriteFully(&code[0], code_size)) {
ReportWriteFailure("method code", method_idx, dex_file, out);
return 0;
}
size_code_ += code_size;
- offset += code_size;
+ relative_offset += code_size;
}
DCHECK_OFFSET();
#endif
@@ -726,20 +740,20 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
mapping_table_offsets_.find(&mapping_table);
if (mapping_iter != mapping_table_offsets_.end() &&
- offset != method_offsets.mapping_table_offset_) {
+ relative_offset != method_offsets.mapping_table_offset_) {
DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
|| mapping_iter->second == method_offsets.mapping_table_offset_)
<< PrettyMethod(method_idx, dex_file);
} else {
DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
- || offset == method_offsets.mapping_table_offset_)
+ || relative_offset == method_offsets.mapping_table_offset_)
<< PrettyMethod(method_idx, dex_file);
if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
ReportWriteFailure("mapping table", method_idx, dex_file, out);
return 0;
}
size_mapping_table_ += mapping_table_size;
- offset += mapping_table_size;
+ relative_offset += mapping_table_size;
}
DCHECK_OFFSET();
@@ -750,20 +764,20 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
vmap_table_offsets_.find(&vmap_table);
if (vmap_iter != vmap_table_offsets_.end() &&
- offset != method_offsets.vmap_table_offset_) {
+ relative_offset != method_offsets.vmap_table_offset_) {
DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
|| vmap_iter->second == method_offsets.vmap_table_offset_)
<< PrettyMethod(method_idx, dex_file);
} else {
DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
- || offset == method_offsets.vmap_table_offset_)
+ || relative_offset == method_offsets.vmap_table_offset_)
<< PrettyMethod(method_idx, dex_file);
if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
ReportWriteFailure("vmap table", method_idx, dex_file, out);
return 0;
}
size_vmap_table_ += vmap_table_size;
- offset += vmap_table_size;
+ relative_offset += vmap_table_size;
}
DCHECK_OFFSET();
@@ -774,25 +788,25 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c
SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
gc_map_offsets_.find(&gc_map);
if (gc_map_iter != gc_map_offsets_.end() &&
- offset != method_offsets.gc_map_offset_) {
+ relative_offset != method_offsets.gc_map_offset_) {
DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
|| gc_map_iter->second == method_offsets.gc_map_offset_)
<< PrettyMethod(method_idx, dex_file);
} else {
DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
- || offset == method_offsets.gc_map_offset_)
+ || relative_offset == method_offsets.gc_map_offset_)
<< PrettyMethod(method_idx, dex_file);
if (!out.WriteFully(&gc_map[0], gc_map_size)) {
ReportWriteFailure("GC map", method_idx, dex_file, out);
return 0;
}
size_gc_map_ += gc_map_size;
- offset += gc_map_size;
+ relative_offset += gc_map_size;
}
DCHECK_OFFSET();
}
- return offset;
+ return relative_offset;
}
OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
@@ -822,7 +836,9 @@ void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
sizeof(methods_offsets_[0]) * methods_offsets_.size());
}
-bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const {
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
+ OutputStream& out,
+ const size_t file_offset) const {
DCHECK_OFFSET_();
if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
@@ -881,14 +897,16 @@ void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
sizeof(method_offsets_[0]) * method_offsets_.size());
}
-bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const {
+bool OatWriter::OatClass::Write(OatWriter* oat_writer,
+ OutputStream& out,
+ const size_t file_offset) const {
DCHECK_OFFSET_();
if (!out.WriteFully(&status_, sizeof(status_))) {
PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
return false;
}
oat_writer->size_oat_class_status_ += sizeof(status_);
- DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
+ DCHECK_EQ(static_cast<off_t>(file_offset + GetOatMethodOffsetsOffsetFromOatHeader(0)),
out.Seek(0, kSeekCurrent));
if (!out.WriteFully(&method_offsets_[0],
sizeof(method_offsets_[0]) * method_offsets_.size())) {
@@ -896,7 +914,8 @@ bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const
return false;
}
oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
- DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
+ DCHECK_EQ(static_cast<off_t>(file_offset +
+ GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
out.Seek(0, kSeekCurrent));
return true;
}
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index ea7156e..f2c5626 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -62,23 +62,25 @@ class OutputStream;
//
class OatWriter {
public:
- // Write an oat file. Returns true on success, false on failure.
- static bool Create(OutputStream& out,
- const std::vector<const DexFile*>& dex_files,
- uint32_t image_file_location_oat_checksum,
- uint32_t image_file_location_oat_begin,
- const std::string& image_file_location,
- const CompilerDriver& compiler)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- private:
OatWriter(const std::vector<const DexFile*>& dex_files,
uint32_t image_file_location_oat_checksum,
uint32_t image_file_location_oat_begin,
const std::string& image_file_location,
const CompilerDriver* compiler) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ const OatHeader& GetOatHeader() const {
+ return *oat_header_;
+ }
+
+ size_t GetSize() const {
+ return size_;
+ }
+
+ bool Write(OutputStream& out);
+
~OatWriter();
+ private:
size_t InitOatHeader();
size_t InitOatDexFiles(size_t offset);
size_t InitDexFiles(size_t offset);
@@ -101,17 +103,17 @@ class OatWriter {
uint32_t method_idx, const DexFile*)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool Write(OutputStream& out);
- bool WriteTables(OutputStream& out);
- size_t WriteCode(OutputStream& out);
- size_t WriteCodeDexFiles(OutputStream& out, size_t offset);
- size_t WriteCodeDexFile(OutputStream& out, size_t offset, size_t& oat_class_index,
- const DexFile& dex_file);
- size_t WriteCodeClassDef(OutputStream& out, size_t offset, size_t oat_class_index,
- const DexFile& dex_file, const DexFile::ClassDef& class_def);
- size_t WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
- size_t class_def_method_index, bool is_static, uint32_t method_idx,
- const DexFile& dex_file);
+ bool WriteTables(OutputStream& out, const size_t file_offset);
+ size_t WriteCode(OutputStream& out, const size_t file_offset);
+ size_t WriteCodeDexFiles(OutputStream& out, const size_t file_offset, size_t relative_offset);
+ size_t WriteCodeDexFile(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t& oat_class_index, const DexFile& dex_file);
+ size_t WriteCodeClassDef(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t oat_class_index, const DexFile& dex_file,
+ const DexFile::ClassDef& class_def);
+ size_t WriteCodeMethod(OutputStream& out, const size_t file_offset, size_t relative_offset,
+ size_t oat_class_index, size_t class_def_method_index, bool is_static,
+ uint32_t method_idx, const DexFile& dex_file);
void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
OutputStream& out) const;
@@ -121,7 +123,7 @@ class OatWriter {
explicit OatDexFile(size_t offset, const DexFile& dex_file);
size_t SizeOf() const;
void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OatWriter* oat_writer, OutputStream& out) const;
+ bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
// Offset of start of OatDexFile from beginning of OatHeader. It is
// used to validate file position when writing.
@@ -145,7 +147,7 @@ class OatWriter {
size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
size_t SizeOf() const;
void UpdateChecksum(OatHeader& oat_header) const;
- bool Write(OatWriter* oat_writer, OutputStream& out) const;
+ bool Write(OatWriter* oat_writer, OutputStream& out, const size_t file_offset) const;
// Offset of start of OatClass from beginning of OatHeader. It is
// used to validate file position when writing. For Portable, it
@@ -167,6 +169,9 @@ class OatWriter {
// note OatFile does not take ownership of the DexFiles
const std::vector<const DexFile*>* dex_files_;
+ // Size required for Oat data structures.
+ size_t size_;
+
// dependencies on the image.
uint32_t image_file_location_oat_checksum_;
uint32_t image_file_location_oat_begin_;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 0e32f0b..1a6a98a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -282,27 +282,14 @@ class Dex2Oat {
}
}
- std::vector<uint8_t> oat_contents;
- // TODO: change ElfWriterQuick to not require the creation of oat_contents. The old pre-mclinker
- // OatWriter streamed directly to disk. The new could can be adapted to do it as follows:
- // 1.) use first pass of OatWriter to calculate size of oat structure,
- // 2.) call ElfWriterQuick with pointer to OatWriter instead of contents,
- // 3.) have ElfWriterQuick call back to OatWriter to stream generate the output directly in
- // place in the elf file.
- oat_contents.reserve(5 * MB);
- VectorOutputStream vector_output_stream(oat_file->GetPath(), oat_contents);
- if (!OatWriter::Create(vector_output_stream,
- dex_files,
- image_file_location_oat_checksum,
- image_file_location_oat_data_begin,
- image_file_location,
- *driver.get())) {
- LOG(ERROR) << "Failed to create oat file " << oat_file->GetPath();
- return NULL;
- }
+ OatWriter oat_writer(dex_files,
+ image_file_location_oat_checksum,
+ image_file_location_oat_data_begin,
+ image_file_location,
+ driver.get());
timings.AddSplit("dex2oat OatWriter");
- if (!driver->WriteElf(android_root, is_host, dex_files, oat_contents, 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 NULL;
}
@@ -1019,10 +1006,10 @@ static int dex2oat(int argc, char** argv) {
*compiler.get());
timings.AddSplit("dex2oat ImageWriter");
Thread::Current()->TransitionFromSuspendedToRunnable();
- LOG(INFO) << "Image written successfully: " << image_filename;
if (!image_creation_success) {
return EXIT_FAILURE;
}
+ LOG(INFO) << "Image written successfully: " << image_filename;
}
if (is_host) {
diff --git a/runtime/image_test.cc b/runtime/image_test.cc
index 11218ad..75eead4 100644
--- a/runtime/image_test.cc
+++ b/runtime/image_test.cc
@@ -41,7 +41,6 @@ class ImageTest : public CommonTest {
TEST_F(ImageTest, WriteRead) {
ScratchFile tmp_elf;
{
- std::vector<uint8_t> oat_contents;
{
jobject class_loader = NULL;
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -49,17 +48,14 @@ TEST_F(ImageTest, WriteRead) {
compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
ScopedObjectAccess soa(Thread::Current());
- VectorOutputStream output_stream(tmp_elf.GetFilename(), oat_contents);
- bool success_oat = OatWriter::Create(output_stream, class_linker->GetBootClassPath(),
- 0, 0, "", *compiler_driver_.get());
- ASSERT_TRUE(success_oat);
-
- bool success_elf = compiler_driver_->WriteElf(GetTestAndroidRoot(),
- !kIsTargetBuild,
- class_linker->GetBootClassPath(),
- oat_contents,
- tmp_elf.GetFile());
- ASSERT_TRUE(success_elf);
+ OatWriter oat_writer(class_linker->GetBootClassPath(),
+ 0, 0, "", compiler_driver_.get());
+ bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
+ !kIsTargetBuild,
+ class_linker->GetBootClassPath(),
+ oat_writer,
+ tmp_elf.GetFile());
+ ASSERT_TRUE(success);
}
}
// Workound bug that mcld::Linker::emit closes tmp_elf by reopening as tmp_oat.
diff --git a/runtime/oat_test.cc b/runtime/oat_test.cc
index 9a6bc19..3f2e43e 100644
--- a/runtime/oat_test.cc
+++ b/runtime/oat_test.cc
@@ -83,21 +83,17 @@ TEST_F(OatTest, WriteRead) {
ScopedObjectAccess soa(Thread::Current());
ScratchFile tmp;
- std::vector<uint8_t> oat_contents;
- VectorOutputStream output_stream(tmp.GetFilename(), oat_contents);
- bool success_oat = OatWriter::Create(output_stream,
- class_linker->GetBootClassPath(),
- 42U,
- 4096U,
- "lue.art",
- *compiler_driver_.get());
- ASSERT_TRUE(success_oat);
- bool success_elf = compiler_driver_->WriteElf(GetTestAndroidRoot(),
- !kIsTargetBuild,
- class_linker->GetBootClassPath(),
- oat_contents,
- tmp.GetFile());
- ASSERT_TRUE(success_elf);
+ OatWriter oat_writer(class_linker->GetBootClassPath(),
+ 42U,
+ 4096U,
+ "lue.art",
+ compiler_driver_.get());
+ bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
+ !kIsTargetBuild,
+ class_linker->GetBootClassPath(),
+ oat_writer,
+ tmp.GetFile());
+ ASSERT_TRUE(success);
if (compile) { // OatWriter strips the code, regenerate to compare
TimingLogger timings("CommonTest::WriteRead", false);