diff options
-rw-r--r-- | compiler/buffered_output_stream.cc | 20 | ||||
-rw-r--r-- | compiler/buffered_output_stream.h | 19 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 17 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 7 | ||||
-rw-r--r-- | compiler/dwarf/method_debug_info.h | 41 | ||||
-rw-r--r-- | compiler/elf_builder.h | 23 | ||||
-rw-r--r-- | compiler/elf_writer.h | 33 | ||||
-rw-r--r-- | compiler/elf_writer_debug.cc | 33 | ||||
-rw-r--r-- | compiler/elf_writer_debug.h | 7 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 190 | ||||
-rw-r--r-- | compiler/elf_writer_quick.h | 45 | ||||
-rw-r--r-- | compiler/elf_writer_test.cc | 3 | ||||
-rw-r--r-- | compiler/file_output_stream.cc | 4 | ||||
-rw-r--r-- | compiler/file_output_stream.h | 8 | ||||
-rw-r--r-- | compiler/image_test.cc | 39 | ||||
-rw-r--r-- | compiler/oat_test.cc | 38 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 3 | ||||
-rw-r--r-- | compiler/oat_writer.h | 20 | ||||
-rw-r--r-- | compiler/output_stream.h | 8 | ||||
-rw-r--r-- | compiler/output_stream_test.cc | 41 | ||||
-rw-r--r-- | compiler/vector_output_stream.h | 10 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 35 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 5 |
23 files changed, 431 insertions, 218 deletions
diff --git a/compiler/buffered_output_stream.cc b/compiler/buffered_output_stream.cc index 3ca518b686..4c66c764a9 100644 --- a/compiler/buffered_output_stream.cc +++ b/compiler/buffered_output_stream.cc @@ -20,18 +20,24 @@ namespace art { -BufferedOutputStream::BufferedOutputStream(OutputStream* out) - : OutputStream(out->GetLocation()), out_(out), used_(0) {} +BufferedOutputStream::BufferedOutputStream(std::unique_ptr<OutputStream> out) + : OutputStream(out->GetLocation()), // Before out is moved to out_. + out_(std::move(out)), + used_(0) {} + +BufferedOutputStream::~BufferedOutputStream() { + FlushBuffer(); +} bool BufferedOutputStream::WriteFully(const void* buffer, size_t byte_count) { if (byte_count > kBufferSize) { - if (!Flush()) { + if (!FlushBuffer()) { return false; } return out_->WriteFully(buffer, byte_count); } if (used_ + byte_count > kBufferSize) { - if (!Flush()) { + if (!FlushBuffer()) { return false; } } @@ -42,6 +48,10 @@ bool BufferedOutputStream::WriteFully(const void* buffer, size_t byte_count) { } bool BufferedOutputStream::Flush() { + return FlushBuffer() && out_->Flush(); +} + +bool BufferedOutputStream::FlushBuffer() { bool success = true; if (used_ > 0) { success = out_->WriteFully(&buffer_[0], used_); @@ -51,7 +61,7 @@ bool BufferedOutputStream::Flush() { } off_t BufferedOutputStream::Seek(off_t offset, Whence whence) { - if (!Flush()) { + if (!FlushBuffer()) { return -1; } return out_->Seek(offset, whence); diff --git a/compiler/buffered_output_stream.h b/compiler/buffered_output_stream.h index b447f41e21..1da3a6932f 100644 --- a/compiler/buffered_output_stream.h +++ b/compiler/buffered_output_stream.h @@ -17,6 +17,8 @@ #ifndef ART_COMPILER_BUFFERED_OUTPUT_STREAM_H_ #define ART_COMPILER_BUFFERED_OUTPUT_STREAM_H_ +#include <memory> + #include "output_stream.h" #include "globals.h" @@ -25,26 +27,23 @@ namespace art { class BufferedOutputStream FINAL : public OutputStream { public: - explicit BufferedOutputStream(OutputStream* out); + explicit BufferedOutputStream(std::unique_ptr<OutputStream> out); - virtual ~BufferedOutputStream() { - Flush(); - delete out_; - } + ~BufferedOutputStream() OVERRIDE; - virtual bool WriteFully(const void* buffer, size_t byte_count); + bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE; - virtual off_t Seek(off_t offset, Whence whence); + off_t Seek(off_t offset, Whence whence) OVERRIDE; - bool Flush(); + bool Flush() OVERRIDE; private: static const size_t kBufferSize = 8 * KB; - OutputStream* const out_; + bool FlushBuffer(); + std::unique_ptr<OutputStream> const out_; uint8_t buffer_[kBufferSize]; - size_t used_; DISALLOW_COPY_AND_ASSIGN(BufferedOutputStream); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index d67087edd9..9d3af1681a 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -45,7 +45,6 @@ #include "dex/quick/dex_file_method_inliner.h" #include "dex/quick/dex_file_to_method_inliner_map.h" #include "driver/compiler_options.h" -#include "elf_writer_quick.h" #include "jni_internal.h" #include "object_lock.h" #include "profiler.h" @@ -77,9 +76,6 @@ namespace art { static constexpr bool kTimeCompileMethod = !kIsDebugBuild; -// Whether to produce 64-bit ELF files for 64-bit targets. -static constexpr bool kProduce64BitELFFiles = true; - // Whether classes-to-compile and methods-to-compile are only applied to the boot image, or, when // given, too all compilations. static constexpr bool kRestrictCompilationFiltersToImage = true; @@ -2514,19 +2510,6 @@ bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0; } -bool CompilerDriver::WriteElf(const std::string& android_root, - bool is_host, - const std::vector<const art::DexFile*>& dex_files, - OatWriter* oat_writer, - art::File* file) - SHARED_REQUIRES(Locks::mutator_lock_) { - if (kProduce64BitELFFiles && Is64BitInstructionSet(GetInstructionSet())) { - return art::ElfWriterQuick64::Create(file, oat_writer, dex_files, android_root, is_host, *this); - } else { - return art::ElfWriterQuick32::Create(file, oat_writer, dex_files, android_root, is_host, *this); - } -} - bool CompilerDriver::SkipCompilation(const std::string& method_name) { if (!profile_present_) { return false; diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index d90d6100b9..1347b37fa0 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -59,7 +59,6 @@ class DexCompilationUnit; class DexFileToMethodInlinerMap; struct InlineIGetIPutData; class InstructionSetFeatures; -class OatWriter; class ParallelCompilationManager; class ScopedObjectAccess; template <class Allocator> class SrcMap; @@ -398,12 +397,6 @@ class CompilerDriver { support_boot_image_fixup_ = support_boot_image_fixup; } - bool WriteElf(const std::string& android_root, - bool is_host, - const std::vector<const DexFile*>& dex_files, - OatWriter* oat_writer, - File* file); - void SetCompilerContext(void* compiler_context) { compiler_context_ = compiler_context; } diff --git a/compiler/dwarf/method_debug_info.h b/compiler/dwarf/method_debug_info.h new file mode 100644 index 0000000000..a391e4d08a --- /dev/null +++ b/compiler/dwarf/method_debug_info.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_ +#define ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_ + +#include "dex_file.h" + +namespace art { +class CompiledMethod; +namespace dwarf { + +struct MethodDebugInfo { + const DexFile* dex_file_; + size_t class_def_index_; + uint32_t dex_method_index_; + uint32_t access_flags_; + const DexFile::CodeItem* code_item_; + bool deduped_; + uint32_t low_pc_; + uint32_t high_pc_; + CompiledMethod* compiled_method_; +}; + +} // namespace dwarf +} // namespace art + +#endif // ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_ diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 6e8dfd60fb..c19bc3db5c 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -27,6 +27,7 @@ #include "elf_utils.h" #include "file_output_stream.h" #include "leb128.h" +#include "utils/array_ref.h" namespace art { @@ -100,7 +101,7 @@ class ElfBuilder FINAL { header_.sh_entsize = entsize; } - virtual ~Section() { + ~Section() OVERRIDE { if (started_) { CHECK(finished_); } @@ -187,6 +188,12 @@ class ElfBuilder FINAL { return owner_->Seek(offset, whence); } + // This function flushes the output and returns whether it succeeded. + // If there was a previous failure, this does nothing and returns false, i.e. failed. + bool Flush() OVERRIDE { + return owner_->Flush(); + } + Elf_Word GetSectionIndex() const { DCHECK(started_); DCHECK_NE(section_index_, 0u); @@ -312,7 +319,7 @@ class ElfBuilder FINAL { // Encode patch locations as LEB128 list of deltas between consecutive addresses. // (exposed publicly for tests) - static void EncodeOatPatches(const std::vector<uintptr_t>& locations, + static void EncodeOatPatches(const ArrayRef<const uintptr_t>& locations, std::vector<uint8_t>* buffer) { buffer->reserve(buffer->size() + locations.size() * 2); // guess 2 bytes per ULEB128. uintptr_t address = 0; // relative to start of section. @@ -323,9 +330,9 @@ class ElfBuilder FINAL { } } - void WritePatches(const char* name, const std::vector<uintptr_t>* patch_locations) { + void WritePatches(const char* name, const ArrayRef<const uintptr_t>& patch_locations) { std::vector<uint8_t> buffer; - EncodeOatPatches(*patch_locations, &buffer); + EncodeOatPatches(patch_locations, &buffer); std::unique_ptr<Section> s(new Section(this, name, SHT_OAT_PATCH, 0, nullptr, 0, 1, 0)); s->Start(); s->WriteFully(buffer.data(), buffer.size()); @@ -385,6 +392,7 @@ class ElfBuilder FINAL { Seek(0, kSeekSet); WriteFully(&elf_header, sizeof(elf_header)); WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0])); + Flush(); } // The running program does not have access to section headers @@ -509,6 +517,13 @@ class ElfBuilder FINAL { return new_offset; } + bool Flush() { + if (output_good_) { + output_good_ = output_->Flush(); + } + return output_good_; + } + static Elf_Ehdr MakeElfHeader(InstructionSet isa) { Elf_Ehdr elf_header = Elf_Ehdr(); switch (isa) { diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index 03f8ceb306..357d5f624e 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -25,13 +25,16 @@ #include "base/macros.h" #include "base/mutex.h" #include "os.h" +#include "utils/array_ref.h" namespace art { -class CompilerDriver; -class DexFile; class ElfFile; -class OatWriter; +class OutputStream; + +namespace dwarf { +struct MethodDebugInfo; +} // namespace dwarf class ElfWriter { public: @@ -46,21 +49,21 @@ class ElfWriter { static bool Fixup(File* file, uintptr_t oat_data_begin); - protected: - ElfWriter(const CompilerDriver& driver, File* elf_file) - : compiler_driver_(&driver), elf_file_(elf_file) { - } - virtual ~ElfWriter() {} - virtual bool Write(OatWriter* oat_writer, - const std::vector<const DexFile*>& dex_files, - const std::string& android_root, - bool is_host) - SHARED_REQUIRES(Locks::mutator_lock_) = 0; + virtual void Start() = 0; + virtual OutputStream* StartRoData() = 0; + virtual void EndRoData(OutputStream* rodata) = 0; + virtual OutputStream* StartText() = 0; + virtual void EndText(OutputStream* text) = 0; + virtual void SetBssSize(size_t bss_size) = 0; + virtual void WriteDynamicSection() = 0; + virtual void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0; + virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0; + virtual bool End() = 0; - const CompilerDriver* const compiler_driver_; - File* const elf_file_; + protected: + ElfWriter() = default; }; } // namespace art diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index ee557fc8c3..5738779609 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -17,6 +17,7 @@ #include "elf_writer_debug.h" #include <unordered_set> +#include <vector> #include "base/casts.h" #include "base/stl_util.h" @@ -25,6 +26,7 @@ #include "dex_file-inl.h" #include "dwarf/dedup_vector.h" #include "dwarf/headers.h" +#include "dwarf/method_debug_info.h" #include "dwarf/register.h" #include "elf_builder.h" #include "oat_writer.h" @@ -203,7 +205,7 @@ static void WriteCIE(InstructionSet isa, template<typename ElfTypes> void WriteCFISection(ElfBuilder<ElfTypes>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos, + const ArrayRef<const MethodDebugInfo>& method_infos, CFIFormat format) { CHECK(format == dwarf::DW_DEBUG_FRAME_FORMAT || format == dwarf::DW_EH_FRAME_FORMAT); @@ -233,7 +235,7 @@ void WriteCFISection(ElfBuilder<ElfTypes>* builder, cfi_section->WriteFully(buffer.data(), buffer.size()); buffer_address += buffer.size(); buffer.clear(); - for (const OatWriter::DebugInfo& mi : method_infos) { + for (const MethodDebugInfo& mi : method_infos) { if (!mi.deduped_) { // Only one FDE per unique address. ArrayRef<const uint8_t> opcodes = mi.compiled_method_->GetCFIInfo(); if (!opcodes.empty()) { @@ -286,12 +288,13 @@ void WriteCFISection(ElfBuilder<ElfTypes>* builder, header_section->WriteFully(binary_search_table.data(), binary_search_table.size()); header_section->End(); } else { - builder->WritePatches(".debug_frame.oat_patches", &patch_locations); + builder->WritePatches(".debug_frame.oat_patches", + ArrayRef<const uintptr_t>(patch_locations)); } } struct CompilationUnit { - std::vector<const OatWriter::DebugInfo*> methods_; + std::vector<const MethodDebugInfo*> methods_; size_t debug_line_offset_ = 0; uint32_t low_pc_ = 0xFFFFFFFFU; uint32_t high_pc_ = 0; @@ -417,7 +420,7 @@ class DebugInfoWriter { // Write table into .debug_loc which describes location of dex register. // The dex register might be valid only at some points and it might // move between machine registers and stack. - void WriteRegLocation(const OatWriter::DebugInfo* method_info, uint16_t vreg, + void WriteRegLocation(const MethodDebugInfo* method_info, uint16_t vreg, bool is64bitValue, uint32_t compilation_unit_low_pc) { using Kind = DexRegisterLocation::Kind; bool is_optimizing = method_info->compiled_method_->GetQuickCode().size() > 0 && @@ -736,7 +739,8 @@ class DebugInfoWriter { void End() { builder_->GetDebugInfo()->End(); - builder_->WritePatches(".debug_info.oat_patches", &debug_info_patches_); + builder_->WritePatches(".debug_info.oat_patches", + ArrayRef<const uintptr_t>(debug_info_patches_)); builder_->WriteSection(".debug_abbrev", &debug_abbrev_.Data()); builder_->WriteSection(".debug_str", &debug_str_.Data()); builder_->WriteSection(".debug_loc", &debug_loc_); @@ -803,7 +807,7 @@ class DebugLineWriter { if (dwarf_isa != -1) { opcodes.SetISA(dwarf_isa); } - for (const OatWriter::DebugInfo* mi : compilation_unit.methods_) { + for (const MethodDebugInfo* mi : compilation_unit.methods_) { // Ignore function if we have already generated line table for the same address. // It would confuse the debugger and the DWARF specification forbids it. if (mi->deduped_) { @@ -920,7 +924,8 @@ class DebugLineWriter { void End() { builder_->GetDebugLine()->End(); - builder_->WritePatches(".debug_line.oat_patches", &debug_line_patches); + builder_->WritePatches(".debug_line.oat_patches", + ArrayRef<const uintptr_t>(debug_line_patches)); } private: @@ -930,11 +935,11 @@ class DebugLineWriter { template<typename ElfTypes> void WriteDebugSections(ElfBuilder<ElfTypes>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos) { + const ArrayRef<const MethodDebugInfo>& method_infos) { // Group the methods into compilation units based on source file. std::vector<CompilationUnit> compilation_units; const char* last_source_file = nullptr; - for (const OatWriter::DebugInfo& mi : method_infos) { + for (const MethodDebugInfo& mi : method_infos) { auto& dex_class_def = mi.dex_file_->GetClassDef(mi.class_def_index_); const char* source_file = mi.dex_file_->GetSourceFile(dex_class_def); if (compilation_units.empty() || source_file != last_source_file) { @@ -971,18 +976,18 @@ void WriteDebugSections(ElfBuilder<ElfTypes>* builder, // Explicit instantiations template void WriteCFISection<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos, + const ArrayRef<const MethodDebugInfo>& method_infos, CFIFormat format); template void WriteCFISection<ElfTypes64>( ElfBuilder<ElfTypes64>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos, + const ArrayRef<const MethodDebugInfo>& method_infos, CFIFormat format); template void WriteDebugSections<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos); + const ArrayRef<const MethodDebugInfo>& method_infos); template void WriteDebugSections<ElfTypes64>( ElfBuilder<ElfTypes64>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos); + const ArrayRef<const MethodDebugInfo>& method_infos); } // namespace dwarf } // namespace art diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h index e58fd0a390..9ed102f91b 100644 --- a/compiler/elf_writer_debug.h +++ b/compiler/elf_writer_debug.h @@ -17,23 +17,22 @@ #ifndef ART_COMPILER_ELF_WRITER_DEBUG_H_ #define ART_COMPILER_ELF_WRITER_DEBUG_H_ -#include <vector> - #include "elf_builder.h" #include "dwarf/dwarf_constants.h" #include "oat_writer.h" +#include "utils/array_ref.h" namespace art { namespace dwarf { template<typename ElfTypes> void WriteCFISection(ElfBuilder<ElfTypes>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos, + const ArrayRef<const MethodDebugInfo>& method_infos, CFIFormat format); template<typename ElfTypes> void WriteDebugSections(ElfBuilder<ElfTypes>* builder, - const std::vector<OatWriter::DebugInfo>& method_infos); + const ArrayRef<const MethodDebugInfo>& method_infos); } // namespace dwarf } // namespace art diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 5c059e1e82..9da2af8d3e 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -21,19 +21,16 @@ #include "base/casts.h" #include "base/logging.h" -#include "base/unix_file/fd_file.h" +#include "base/stl_util.h" #include "compiled_method.h" -#include "dex_file-inl.h" -#include "driver/compiler_driver.h" #include "driver/compiler_options.h" +#include "dwarf/method_debug_info.h" +#include "elf.h" #include "elf_builder.h" -#include "elf_file.h" #include "elf_utils.h" #include "elf_writer_debug.h" #include "globals.h" #include "leb128.h" -#include "oat.h" -#include "oat_writer.h" #include "utils.h" namespace art { @@ -57,125 +54,186 @@ constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT; constexpr bool kGenerateSingleArmMappingSymbol = true; template <typename ElfTypes> -bool ElfWriterQuick<ElfTypes>::Create(File* elf_file, - 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_writer, dex_files, android_root, is_host); +class ElfWriterQuick FINAL : public ElfWriter { + public: + ElfWriterQuick(InstructionSet instruction_set, + const CompilerOptions* compiler_options, + File* elf_file); + ~ElfWriterQuick(); + + void Start() OVERRIDE; + OutputStream* StartRoData() OVERRIDE; + void EndRoData(OutputStream* rodata) OVERRIDE; + OutputStream* StartText() OVERRIDE; + void EndText(OutputStream* text) OVERRIDE; + void SetBssSize(size_t bss_size) OVERRIDE; + void WriteDynamicSection() OVERRIDE; + void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE; + void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE; + bool End() OVERRIDE; + + static void EncodeOatPatches(const std::vector<uintptr_t>& locations, + std::vector<uint8_t>* buffer); + + private: + const CompilerOptions* const compiler_options_; + File* const elf_file_; + std::unique_ptr<BufferedOutputStream> output_stream_; + std::unique_ptr<ElfBuilder<ElfTypes>> builder_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); +}; + +std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set, + const CompilerOptions* compiler_options, + File* elf_file) { + if (Is64BitInstructionSet(instruction_set)) { + return MakeUnique<ElfWriterQuick<ElfTypes64>>(instruction_set, compiler_options, elf_file); + } else { + return MakeUnique<ElfWriterQuick<ElfTypes32>>(instruction_set, compiler_options, elf_file); + } } template <typename ElfTypes> -static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer); +static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos); + +template <typename ElfTypes> +ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set, + const CompilerOptions* compiler_options, + File* elf_file) + : ElfWriter(), + compiler_options_(compiler_options), + elf_file_(elf_file), + output_stream_(MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(elf_file))), + builder_(new ElfBuilder<ElfTypes>(instruction_set, output_stream_.get())) {} template <typename ElfTypes> -bool ElfWriterQuick<ElfTypes>::Write( - OatWriter* oat_writer, - const std::vector<const DexFile*>& dex_files_unused ATTRIBUTE_UNUSED, - const std::string& android_root_unused ATTRIBUTE_UNUSED, - bool is_host_unused ATTRIBUTE_UNUSED) { - const InstructionSet isa = compiler_driver_->GetInstructionSet(); - std::unique_ptr<BufferedOutputStream> output_stream( - new BufferedOutputStream(new FileOutputStream(elf_file_))); - std::unique_ptr<ElfBuilder<ElfTypes>> builder( - new ElfBuilder<ElfTypes>(isa, output_stream.get())); - - builder->Start(); - - auto* rodata = builder->GetRoData(); - auto* text = builder->GetText(); - auto* bss = builder->GetBss(); +ElfWriterQuick<ElfTypes>::~ElfWriterQuick() {} +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::Start() { + builder_->Start(); +} + +template <typename ElfTypes> +OutputStream* ElfWriterQuick<ElfTypes>::StartRoData() { + auto* rodata = builder_->GetRoData(); rodata->Start(); - if (!oat_writer->WriteRodata(rodata)) { - return false; - } - rodata->End(); + return rodata; +} +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::EndRoData(OutputStream* rodata) { + CHECK_EQ(builder_->GetRoData(), rodata); + builder_->GetRoData()->End(); +} + +template <typename ElfTypes> +OutputStream* ElfWriterQuick<ElfTypes>::StartText() { + auto* text = builder_->GetText(); text->Start(); - if (!oat_writer->WriteCode(text)) { - return false; - } - text->End(); + return text; +} + +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::EndText(OutputStream* text) { + CHECK_EQ(builder_->GetText(), text); + builder_->GetText()->End(); +} - if (oat_writer->GetBssSize() != 0) { +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::SetBssSize(size_t bss_size) { + auto* bss = builder_->GetBss(); + if (bss_size != 0u) { bss->Start(); - bss->SetSize(oat_writer->GetBssSize()); + bss->SetSize(bss_size); bss->End(); } +} - builder->WriteDynamicSection(elf_file_->GetPath()); +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::WriteDynamicSection() { + builder_->WriteDynamicSection(elf_file_->GetPath()); +} - if (compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) { - const auto& method_infos = oat_writer->GetMethodDebugInfo(); +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::WriteDebugInfo( + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { + if (compiler_options_->GetGenerateDebugInfo()) { if (!method_infos.empty()) { // Add methods to .symtab. - WriteDebugSymbols(builder.get(), oat_writer); + WriteDebugSymbols(builder_.get(), method_infos); // Generate CFI (stack unwinding information). - dwarf::WriteCFISection(builder.get(), method_infos, kCFIFormat); + dwarf::WriteCFISection(builder_.get(), method_infos, kCFIFormat); // Write DWARF .debug_* sections. - dwarf::WriteDebugSections(builder.get(), method_infos); + dwarf::WriteDebugSections(builder_.get(), method_infos); } } +} +template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::WritePatchLocations( + const ArrayRef<const uintptr_t>& patch_locations) { // Add relocation section for .text. - if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) { + if (compiler_options_->GetIncludePatchInformation()) { // Note that ElfWriter::Fixup will be called regardless and therefore // we need to include oat_patches for debug sections unconditionally. - builder->WritePatches(".text.oat_patches", &oat_writer->GetAbsolutePatchLocations()); + builder_->WritePatches(".text.oat_patches", patch_locations); } +} - builder->End(); +template <typename ElfTypes> +bool ElfWriterQuick<ElfTypes>::End() { + builder_->End(); - return builder->Good() && output_stream->Flush(); + return builder_->Good(); } template <typename ElfTypes> -static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer) { - const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetMethodDebugInfo(); +static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { bool generated_mapping_symbol = false; auto* strtab = builder->GetStrTab(); auto* symtab = builder->GetSymTab(); - if (method_info.empty()) { + if (method_infos.empty()) { return; } // Find all addresses (low_pc) which contain deduped methods. // The first instance of method is not marked deduped_, but the rest is. std::unordered_set<uint32_t> deduped_addresses; - for (auto it = method_info.begin(); it != method_info.end(); ++it) { - if (it->deduped_) { - deduped_addresses.insert(it->low_pc_); + for (const dwarf::MethodDebugInfo& info : method_infos) { + if (info.deduped_) { + deduped_addresses.insert(info.low_pc_); } } strtab->Start(); strtab->Write(""); // strtab should start with empty string. - for (auto it = method_info.begin(); it != method_info.end(); ++it) { - if (it->deduped_) { + for (const dwarf::MethodDebugInfo& info : method_infos) { + if (info.deduped_) { continue; // Add symbol only for the first instance. } - std::string name = PrettyMethod(it->dex_method_index_, *it->dex_file_, true); - if (deduped_addresses.find(it->low_pc_) != deduped_addresses.end()) { + std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, true); + if (deduped_addresses.find(info.low_pc_) != deduped_addresses.end()) { name += " [DEDUPED]"; } - uint32_t low_pc = it->low_pc_; + uint32_t low_pc = info.low_pc_; // Add in code delta, e.g., thumb bit 0 for Thumb2 code. - low_pc += it->compiled_method_->CodeDelta(); + low_pc += info.compiled_method_->CodeDelta(); symtab->Add(strtab->Write(name), builder->GetText(), low_pc, - true, it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC); + true, info.high_pc_ - info.low_pc_, STB_GLOBAL, STT_FUNC); // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2 // instructions, so that disassembler tools can correctly disassemble. // Note that even if we generate just a single mapping symbol, ARM's Streamline // requires it to match function symbol. Just address 0 does not work. - if (it->compiled_method_->GetInstructionSet() == kThumb2) { + if (info.compiled_method_->GetInstructionSet() == kThumb2) { if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) { - symtab->Add(strtab->Write("$t"), builder->GetText(), it->low_pc_ & ~1, + symtab->Add(strtab->Write("$t"), builder->GetText(), info.low_pc_ & ~1, true, 0, STB_LOCAL, STT_NOTYPE); generated_mapping_symbol = true; } diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h index 83781abeff..347d372fe2 100644 --- a/compiler/elf_writer_quick.h +++ b/compiler/elf_writer_quick.h @@ -17,46 +17,19 @@ #ifndef ART_COMPILER_ELF_WRITER_QUICK_H_ #define ART_COMPILER_ELF_WRITER_QUICK_H_ -#include "elf_utils.h" +#include <memory> + +#include "arch/instruction_set.h" #include "elf_writer.h" -#include "oat_writer.h" +#include "os.h" namespace art { -template <typename ElfTypes> -class ElfWriterQuick FINAL : public ElfWriter { - public: - // Write an ELF file. Returns true on success, false on failure. - static bool Create(File* file, - OatWriter* oat_writer, - const std::vector<const DexFile*>& dex_files, - const std::string& android_root, - bool is_host, - const CompilerDriver& driver) - SHARED_REQUIRES(Locks::mutator_lock_); - - static void EncodeOatPatches(const std::vector<uintptr_t>& locations, - std::vector<uint8_t>* buffer); - - protected: - bool Write(OatWriter* oat_writer, - const std::vector<const DexFile*>& dex_files, - const std::string& android_root, - bool is_host) - OVERRIDE - SHARED_REQUIRES(Locks::mutator_lock_); - - private: - ElfWriterQuick(const CompilerDriver& driver, File* elf_file) - : ElfWriter(driver, elf_file) {} - ~ElfWriterQuick() {} - - DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); -}; - -// Explicitly instantiated in elf_writer_quick.cc -typedef ElfWriterQuick<ElfTypes32> ElfWriterQuick32; -typedef ElfWriterQuick<ElfTypes64> ElfWriterQuick64; +class CompilerOptions; + +std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set, + const CompilerOptions* compiler_options, + File* elf_file); } // namespace art diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index b413a9eb7b..7cf774e95f 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -101,7 +101,8 @@ TEST_F(ElfWriterTest, EncodeDecodeOatPatches) { // Encode patch locations. std::vector<uint8_t> oat_patches; - ElfBuilder<ElfTypes32>::EncodeOatPatches(patch_locations, &oat_patches); + ElfBuilder<ElfTypes32>::EncodeOatPatches(ArrayRef<const uintptr_t>(patch_locations), + &oat_patches); // Create buffer to be patched. std::vector<uint8_t> initial_data(256); diff --git a/compiler/file_output_stream.cc b/compiler/file_output_stream.cc index 3ee16f53e8..bbfbdfdca8 100644 --- a/compiler/file_output_stream.cc +++ b/compiler/file_output_stream.cc @@ -33,4 +33,8 @@ off_t FileOutputStream::Seek(off_t offset, Whence whence) { return lseek(file_->Fd(), offset, static_cast<int>(whence)); } +bool FileOutputStream::Flush() { + return file_->Flush() == 0; +} + } // namespace art diff --git a/compiler/file_output_stream.h b/compiler/file_output_stream.h index 9dfbd7fcef..6917d83f29 100644 --- a/compiler/file_output_stream.h +++ b/compiler/file_output_stream.h @@ -27,11 +27,13 @@ class FileOutputStream FINAL : public OutputStream { public: explicit FileOutputStream(File* file); - virtual ~FileOutputStream() {} + ~FileOutputStream() OVERRIDE {} - virtual bool WriteFully(const void* buffer, size_t byte_count); + bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE; - virtual off_t Seek(off_t offset, Whence whence); + off_t Seek(off_t offset, Whence whence) OVERRIDE; + + bool Flush() OVERRIDE; private: File* const file_; diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 6df15279a0..5f4a92299b 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -23,7 +23,9 @@ #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" #include "common_compiler_test.h" +#include "dwarf/method_debug_info.h" #include "elf_writer.h" +#include "elf_writer_quick.h" #include "gc/space/image_space.h" #include "image_writer.h" #include "lock_word.h" @@ -92,12 +94,37 @@ TEST_F(ImageTest, WriteRead) { /*compiling_boot_image*/true, &timings, &key_value_store); - bool success = writer->PrepareImageAddressSpace() && - compiler_driver_->WriteElf(GetTestAndroidRoot(), - !kIsTargetBuild, - class_linker->GetBootClassPath(), - &oat_writer, - oat_file.GetFile()); + std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick( + compiler_driver_->GetInstructionSet(), + &compiler_driver_->GetCompilerOptions(), + oat_file.GetFile()); + bool success = writer->PrepareImageAddressSpace(); + ASSERT_TRUE(success); + + elf_writer->Start(); + + OutputStream* rodata = elf_writer->StartRoData(); + bool rodata_ok = oat_writer.WriteRodata(rodata); + ASSERT_TRUE(rodata_ok); + elf_writer->EndRoData(rodata); + + OutputStream* text = elf_writer->StartText(); + bool text_ok = oat_writer.WriteCode(text); + ASSERT_TRUE(text_ok); + elf_writer->EndText(text); + + elf_writer->SetBssSize(oat_writer.GetBssSize()); + + elf_writer->WriteDynamicSection(); + + ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer.GetMethodDebugInfo()); + elf_writer->WriteDebugInfo(method_infos); + + ArrayRef<const uintptr_t> patch_locations(oat_writer.GetAbsolutePatchLocations()); + elf_writer->WritePatchLocations(patch_locations); + + success = elf_writer->End(); + ASSERT_TRUE(success); } } diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 030451c1cb..c305b120cb 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -27,6 +27,9 @@ #include "dex/verification_results.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" +#include "dwarf/method_debug_info.h" +#include "elf_writer.h" +#include "elf_writer_quick.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" @@ -134,11 +137,36 @@ class OatTest : public CommonCompilerTest { /*compiling_boot_image*/false, &timings, &key_value_store); - return compiler_driver_->WriteElf(GetTestAndroidRoot(), - !kIsTargetBuild, - dex_files, - &oat_writer, - file); + std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick( + compiler_driver_->GetInstructionSet(), + &compiler_driver_->GetCompilerOptions(), + file); + + elf_writer->Start(); + + OutputStream* rodata = elf_writer->StartRoData(); + if (!oat_writer.WriteRodata(rodata)) { + return false; + } + elf_writer->EndRoData(rodata); + + OutputStream* text = elf_writer->StartText(); + if (!oat_writer.WriteCode(text)) { + return false; + } + elf_writer->EndText(text); + + elf_writer->SetBssSize(oat_writer.GetBssSize()); + + elf_writer->WriteDynamicSection(); + + ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer.GetMethodDebugInfo()); + elf_writer->WriteDebugInfo(method_infos); + + ArrayRef<const uintptr_t> patch_locations(oat_writer.GetAbsolutePatchLocations()); + elf_writer->WritePatchLocations(patch_locations); + + return elf_writer->End(); } std::unique_ptr<const InstructionSetFeatures> insn_features_; diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 40a3f14f93..a6a49f901a 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -31,6 +31,7 @@ #include "dex/verification_results.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" +#include "dwarf/method_debug_info.h" #include "gc/space/image_space.h" #include "gc/space/space.h" #include "handle_scope-inl.h" @@ -485,7 +486,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { // Record debug information for this function if we are doing that. const uint32_t quick_code_start = quick_code_offset - writer_->oat_header_->GetExecutableOffset() - thumb_offset; - writer_->method_info_.push_back(DebugInfo { + writer_->method_info_.push_back(dwarf::MethodDebugInfo { dex_file_, class_def_index_, it.GetMemberIndex(), diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 7027434cca..6c46ebc4ec 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -38,6 +38,10 @@ class OutputStream; class TimingLogger; class TypeLookupTable; +namespace dwarf { +struct MethodDebugInfo; +} // namespace dwarf + // OatHeader variable length with count of D OatDexFiles // // OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses @@ -129,19 +133,7 @@ class OatWriter { ~OatWriter(); - struct DebugInfo { - const DexFile* dex_file_; - size_t class_def_index_; - uint32_t dex_method_index_; - uint32_t access_flags_; - const DexFile::CodeItem *code_item_; - bool deduped_; - uint32_t low_pc_; - uint32_t high_pc_; - CompiledMethod* compiled_method_; - }; - - const std::vector<DebugInfo>& GetMethodDebugInfo() const { + const std::vector<dwarf::MethodDebugInfo>& GetMethodDebugInfo() const { return method_info_; } @@ -280,7 +272,7 @@ class OatWriter { DISALLOW_COPY_AND_ASSIGN(OatClass); }; - std::vector<DebugInfo> method_info_; + std::vector<dwarf::MethodDebugInfo> method_info_; const CompilerDriver* const compiler_driver_; ImageWriter* const image_writer_; diff --git a/compiler/output_stream.h b/compiler/output_stream.h index 4d30b83234..8f6b6d8235 100644 --- a/compiler/output_stream.h +++ b/compiler/output_stream.h @@ -45,6 +45,14 @@ class OutputStream { virtual off_t Seek(off_t offset, Whence whence) = 0; + /* + * Flushes the stream. Returns whether the operation was successful. + * + * An OutputStream may delay reporting errors from WriteFully() or + * Seek(). In that case, Flush() shall report any pending error. + */ + virtual bool Flush() = 0; + private: const std::string location_; diff --git a/compiler/output_stream_test.cc b/compiler/output_stream_test.cc index 6104ccd758..84c76f2c6c 100644 --- a/compiler/output_stream_test.cc +++ b/compiler/output_stream_test.cc @@ -19,6 +19,7 @@ #include "base/unix_file/fd_file.h" #include "base/logging.h" +#include "base/stl_util.h" #include "buffered_output_stream.h" #include "common_runtime_test.h" @@ -48,6 +49,7 @@ class OutputStreamTest : public CommonRuntimeTest { EXPECT_TRUE(output_stream_->WriteFully(buf, 4)); CheckOffset(10); EXPECT_TRUE(output_stream_->WriteFully(buf, 6)); + EXPECT_TRUE(output_stream_->Flush()); } void CheckTestOutput(const std::vector<uint8_t>& actual) { @@ -77,9 +79,7 @@ TEST_F(OutputStreamTest, File) { TEST_F(OutputStreamTest, Buffered) { ScratchFile tmp; { - std::unique_ptr<FileOutputStream> file_output_stream(new FileOutputStream(tmp.GetFile())); - CHECK(file_output_stream.get() != nullptr); - BufferedOutputStream buffered_output_stream(file_output_stream.release()); + BufferedOutputStream buffered_output_stream(MakeUnique<FileOutputStream>(tmp.GetFile())); SetOutputStream(buffered_output_stream); GenerateTestOutput(); } @@ -99,4 +99,39 @@ TEST_F(OutputStreamTest, Vector) { CheckTestOutput(output); } +TEST_F(OutputStreamTest, BufferedFlush) { + struct CheckingOutputStream : OutputStream { + CheckingOutputStream() + : OutputStream("dummy"), + flush_called(false) { } + ~CheckingOutputStream() OVERRIDE {} + + bool WriteFully(const void* buffer ATTRIBUTE_UNUSED, + size_t byte_count ATTRIBUTE_UNUSED) OVERRIDE { + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); + } + + off_t Seek(off_t offset ATTRIBUTE_UNUSED, Whence whence ATTRIBUTE_UNUSED) OVERRIDE { + LOG(FATAL) << "UNREACHABLE"; + UNREACHABLE(); + } + + bool Flush() OVERRIDE { + flush_called = true; + return true; + } + + bool flush_called; + }; + + std::unique_ptr<CheckingOutputStream> cos = MakeUnique<CheckingOutputStream>(); + CheckingOutputStream* checking_output_stream = cos.get(); + BufferedOutputStream buffered(std::move(cos)); + ASSERT_FALSE(checking_output_stream->flush_called); + bool flush_result = buffered.Flush(); + ASSERT_TRUE(flush_result); + ASSERT_TRUE(checking_output_stream->flush_called); +} + } // namespace art diff --git a/compiler/vector_output_stream.h b/compiler/vector_output_stream.h index 3c5877c0bd..a3c58d0800 100644 --- a/compiler/vector_output_stream.h +++ b/compiler/vector_output_stream.h @@ -29,9 +29,9 @@ class VectorOutputStream FINAL : public OutputStream { public: VectorOutputStream(const std::string& location, std::vector<uint8_t>* vector); - virtual ~VectorOutputStream() {} + ~VectorOutputStream() OVERRIDE {} - bool WriteFully(const void* buffer, size_t byte_count) { + bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE { if (static_cast<size_t>(offset_) == vector_->size()) { const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer); vector_->insert(vector_->end(), &start[0], &start[byte_count]); @@ -45,7 +45,11 @@ class VectorOutputStream FINAL : public OutputStream { return true; } - off_t Seek(off_t offset, Whence whence); + off_t Seek(off_t offset, Whence whence) OVERRIDE; + + bool Flush() OVERRIDE { + return true; + } private: void EnsureCapacity(off_t new_offset) { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 89c2a7cbdf..77211ce059 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -55,8 +55,10 @@ #include "dex/quick/dex_file_to_method_inliner_map.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" +#include "dwarf/method_debug_info.h" #include "elf_file.h" #include "elf_writer.h" +#include "elf_writer_quick.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "image_writer.h" @@ -494,6 +496,7 @@ class Dex2Oat FINAL { app_image_(false), boot_image_(false), is_host_(false), + image_writer_(nullptr), driver_(nullptr), dump_stats_(false), dump_passes_(false), @@ -1408,8 +1411,36 @@ class Dex2Oat FINAL { { TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_); - if (!driver_->WriteElf(android_root_, is_host_, dex_files_, oat_writer.get(), - oat_file_.get())) { + std::unique_ptr<ElfWriter> elf_writer = + CreateElfWriterQuick(instruction_set_, compiler_options_.get(), oat_file_.get()); + + elf_writer->Start(); + + OutputStream* rodata = elf_writer->StartRoData(); + if (!oat_writer->WriteRodata(rodata)) { + LOG(ERROR) << "Failed to write .rodata section to the ELF file " << oat_file_->GetPath(); + return false; + } + elf_writer->EndRoData(rodata); + + OutputStream* text = elf_writer->StartText(); + if (!oat_writer->WriteCode(text)) { + LOG(ERROR) << "Failed to write .text section to the ELF file " << oat_file_->GetPath(); + return false; + } + elf_writer->EndText(text); + + elf_writer->SetBssSize(oat_writer->GetBssSize()); + + elf_writer->WriteDynamicSection(); + + ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer->GetMethodDebugInfo()); + elf_writer->WriteDebugInfo(method_infos); + + ArrayRef<const uintptr_t> patch_locations(oat_writer->GetAbsolutePatchLocations()); + elf_writer->WritePatchLocations(patch_locations); + + if (!elf_writer->End()) { LOG(ERROR) << "Failed to write ELF file " << oat_file_->GetPath(); return false; } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 94eb82b054..d20f7d53de 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -28,6 +28,7 @@ #include "arch/instruction_set_features.h" #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "class_linker-inl.h" @@ -116,7 +117,7 @@ class OatSymbolizer FINAL { File* elf_file = OS::CreateEmptyFile(output_name_.c_str()); std::unique_ptr<BufferedOutputStream> output_stream( - new BufferedOutputStream(new FileOutputStream(elf_file))); + MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(elf_file))); builder_.reset(new ElfBuilder<ElfTypes32>(isa, output_stream.get())); builder_->Start(); @@ -162,7 +163,7 @@ class OatSymbolizer FINAL { builder_->End(); - return builder_->Good() && output_stream->Flush(); + return builder_->Good(); } void Walk(Callback callback) { |