diff options
| -rw-r--r-- | compiler/Android.bp | 10 | ||||
| -rw-r--r-- | compiler/image_test.cc | 4 | ||||
| -rw-r--r-- | compiler/oat_test.cc | 12 | ||||
| -rw-r--r-- | compiler/oat_writer.cc | 45 | ||||
| -rw-r--r-- | compiler/oat_writer.h | 7 | ||||
| -rw-r--r-- | dex2oat/Android.bp | 2 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 9 | ||||
| -rw-r--r-- | dex2oat/dex2oat_test.cc | 104 | ||||
| -rw-r--r-- | dexlayout/Android.bp | 32 | ||||
| -rw-r--r-- | dexlayout/dex_ir.cc | 79 | ||||
| -rw-r--r-- | dexlayout/dex_ir.h | 122 | ||||
| -rw-r--r-- | dexlayout/dex_ir_builder.cc | 2 | ||||
| -rw-r--r-- | dexlayout/dex_visualize.cc | 21 | ||||
| -rw-r--r-- | dexlayout/dex_visualize.h | 6 | ||||
| -rw-r--r-- | dexlayout/dex_writer.cc | 92 | ||||
| -rw-r--r-- | dexlayout/dex_writer.h | 13 | ||||
| -rw-r--r-- | dexlayout/dexlayout.cc | 688 | ||||
| -rw-r--r-- | dexlayout/dexlayout.h | 107 | ||||
| -rw-r--r-- | dexlayout/dexlayout_main.cc | 72 | ||||
| -rw-r--r-- | dexlayout/dexlayout_test.cc | 97 | ||||
| -rw-r--r-- | runtime/compiler_filter.cc | 8 | ||||
| -rw-r--r-- | runtime/compiler_filter.h | 1 | ||||
| -rw-r--r-- | runtime/dex_file_verifier.cc | 2 |
23 files changed, 1058 insertions, 477 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index e2a450d171..17373767c1 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -254,7 +254,10 @@ art_cc_library { }, }, }, - shared_libs: ["libart"], + shared_libs: [ + "libart", + "libart-dexlayout", + ], } art_cc_library { @@ -291,7 +294,10 @@ art_cc_library { }, }, }, - shared_libs: ["libartd"], + shared_libs: [ + "libartd", + "libartd-dexlayout" + ], } art_cc_library { diff --git a/compiler/image_test.cc b/compiler/image_test.cc index fcb8979459..5629dffce5 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -211,7 +211,9 @@ void CompilationHelper::Compile(CompilerDriver* driver, &driver->GetCompilerOptions(), oat_file.GetFile())); elf_writers.back()->Start(); - oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, &timings)); + oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, + &timings, + /*profile_compilation_info*/nullptr)); } std::vector<OutputStream*> rodata; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 102637f01b..94585769b4 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -125,7 +125,9 @@ class OatTest : public CommonCompilerTest { SafeMap<std::string, std::string>& key_value_store, bool verify) { TimingLogger timings("WriteElf", false, false); - OatWriter oat_writer(/*compiling_boot_image*/false, &timings); + OatWriter oat_writer(/*compiling_boot_image*/false, + &timings, + /*profile_compilation_info*/nullptr); for (const DexFile* dex_file : dex_files) { ArrayRef<const uint8_t> raw_dex_file( reinterpret_cast<const uint8_t*>(&dex_file->GetHeader()), @@ -145,7 +147,9 @@ class OatTest : public CommonCompilerTest { SafeMap<std::string, std::string>& key_value_store, bool verify) { TimingLogger timings("WriteElf", false, false); - OatWriter oat_writer(/*compiling_boot_image*/false, &timings); + OatWriter oat_writer(/*compiling_boot_image*/false, + &timings, + /*profile_compilation_info*/nullptr); for (const char* dex_filename : dex_filenames) { if (!oat_writer.AddDexFileSource(dex_filename, dex_filename)) { return false; @@ -161,7 +165,9 @@ class OatTest : public CommonCompilerTest { SafeMap<std::string, std::string>& key_value_store, bool verify) { TimingLogger timings("WriteElf", false, false); - OatWriter oat_writer(/*compiling_boot_image*/false, &timings); + OatWriter oat_writer(/*compiling_boot_image*/false, + &timings, + /*profile_compilation_info*/nullptr); if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) { return false; } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index bde00cf886..eed9d117ae 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -33,6 +33,7 @@ #include "debug/method_debug_info.h" #include "dex/verification_results.h" #include "dex_file-inl.h" +#include "dexlayout.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "gc/space/image_space.h" @@ -276,7 +277,7 @@ class OatWriter::OatDexFile { DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \ << "file_offset=" << file_offset << " offset_=" << offset_ -OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings) +OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info) : write_state_(WriteState::kAddingDexFileSources), timings_(timings), raw_dex_files_(), @@ -337,7 +338,8 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings) size_oat_class_method_bitmaps_(0), size_oat_class_method_offsets_(0), relative_patcher_(nullptr), - absolute_patch_locations_() { + absolute_patch_locations_(), + profile_compilation_info_(info) { } bool OatWriter::AddDexFileSource(const char* filename, @@ -2081,7 +2083,11 @@ bool OatWriter::WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_ if (!SeekToDexFile(out, file, oat_dex_file)) { return false; } - if (oat_dex_file->source_.IsZipEntry()) { + if (profile_compilation_info_ != nullptr) { + if (!LayoutAndWriteDexFile(out, oat_dex_file)) { + return false; + } + } else if (oat_dex_file->source_.IsZipEntry()) { if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) { return false; } @@ -2146,6 +2152,39 @@ bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex return true; } +bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) { + TimingLogger::ScopedTiming split("Dex Layout", timings_); + std::string error_msg; + std::string location(oat_dex_file->GetLocation()); + std::unique_ptr<const DexFile> dex_file; + if (oat_dex_file->source_.IsZipEntry()) { + ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry(); + std::unique_ptr<MemMap> mem_map( + zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg)); + dex_file = DexFile::Open(location, + zip_entry->GetCrc32(), + std::move(mem_map), + /* verify */ true, + /* verify_checksum */ true, + &error_msg); + } else { + DCHECK(oat_dex_file->source_.IsRawFile()); + File* raw_file = oat_dex_file->source_.GetRawFile(); + dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg); + } + Options options; + options.output_to_memmap_ = true; + DexLayout dex_layout(options, profile_compilation_info_, nullptr); + dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0); + std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap()); + if (!WriteDexFile(out, oat_dex_file, mem_map->Begin())) { + return false; + } + // Set the checksum of the new oat dex file to be the original file's checksum. + oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum(); + return true; +} + bool OatWriter::WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file, diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index b92ba769a8..f9671d7c59 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -38,6 +38,7 @@ class BitVector; class CompiledMethod; class CompilerDriver; class ImageWriter; +class ProfileCompilationInfo; class OutputStream; class TimingLogger; class TypeLookupTable; @@ -110,7 +111,7 @@ class OatWriter { kDefault = kCreate }; - OatWriter(bool compiling_boot_image, TimingLogger* timings); + OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info); // To produce a valid oat file, the user must first add sources with any combination of // - AddDexFileSource(), @@ -258,6 +259,7 @@ class OatWriter { bool WriteDexFiles(OutputStream* out, File* file); bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file); bool SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file); + bool LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file); bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file, @@ -422,6 +424,9 @@ class OatWriter { // The locations of absolute patches relative to the start of the executable section. dchecked_vector<uintptr_t> absolute_patch_locations_; + // Profile info used to generate new layout of files. + ProfileCompilationInfo* profile_compilation_info_; + DISALLOW_COPY_AND_ASSIGN(OatWriter); }; diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp index 05a5d0fa2c..0924aec7f1 100644 --- a/dex2oat/Android.bp +++ b/dex2oat/Android.bp @@ -89,6 +89,7 @@ art_cc_binary { ], static_libs: [ "libart-compiler", + "libart-dexlayout", "libart", "libvixl-arm", "libvixl-arm64", @@ -118,6 +119,7 @@ art_cc_binary { ], static_libs: [ "libartd-compiler", + "libartd-dexlayout", "libartd", "libvixld-arm", "libvixld-arm64", diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 65703a23fc..20b5bba0ed 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -270,6 +270,7 @@ NO_RETURN static void Usage(const char* fmt, ...) { "|balanced" "|speed-profile" "|speed" + "|layout-profile" "|everything-profile" "|everything):"); UsageError(" select compiler filter."); @@ -1479,13 +1480,15 @@ class Dex2Oat FINAL { // Unzip or copy dex files straight to the oat file. std::unique_ptr<MemMap> opened_dex_files_map; std::vector<std::unique_ptr<const DexFile>> opened_dex_files; + // Dexlayout verifies the dex file, so disable dex file verification in that case. + bool verify = compiler_options_->GetCompilerFilter() != CompilerFilter::kLayoutProfile; if (!oat_writers_[i]->WriteAndOpenDexFiles( kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(), rodata_.back(), instruction_set_, instruction_set_features_.get(), key_value_store_.get(), - /* verify */ true, + verify, &opened_dex_files_map, &opened_dex_files)) { return false; @@ -2273,7 +2276,9 @@ class Dex2Oat FINAL { compiler_options_.get(), oat_file.get())); elf_writers_.back()->Start(); - oat_writers_.emplace_back(new OatWriter(IsBootImage(), timings_)); + bool do_dexlayout = compiler_options_->GetCompilerFilter() == CompilerFilter::kLayoutProfile; + oat_writers_.emplace_back(new OatWriter( + IsBootImage(), timings_, do_dexlayout ? profile_compilation_info_.get() : nullptr)); } } diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index fa32178796..714a58c8e5 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -24,6 +24,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/stringprintf.h" +#include "dex_file-inl.h" #include "dex2oat_environment_test.h" #include "oat.h" #include "oat_file.h" @@ -551,4 +552,107 @@ TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) { RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" }); } +static const char kDexFileLayoutInputProfile[] = "cHJvADAwMgABAAwAAQABAOqMEeFEZXhOb09hdC5qYXIBAAEA"; + +static void WriteFileBase64(const char* base64, const char* location) { + // Decode base64. + CHECK(base64 != nullptr); + size_t length; + std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length)); + CHECK(bytes.get() != nullptr); + + // Write to provided file. + std::unique_ptr<File> file(OS::CreateEmptyFile(location)); + CHECK(file.get() != nullptr); + if (!file->WriteFully(bytes.get(), length)) { + PLOG(FATAL) << "Failed to write base64 as file"; + } + if (file->FlushCloseOrErase() != 0) { + PLOG(FATAL) << "Could not flush and close test file."; + } +} + +class Dex2oatLayoutTest : public Dex2oatTest { + protected: + void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED, + CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE { + // Ignore, we'll do our own checks. + } + + void RunTest() { + std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; + std::string profile_location = GetScratchDir() + "/primary.prof"; + std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; + + Copy(GetDexSrc2(), dex_location); + WriteFileBase64(kDexFileLayoutInputProfile, profile_location.c_str()); + + const std::vector<std::string>& extra_args = { "--profile-file=" + profile_location }; + GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kLayoutProfile, extra_args); + + CheckValidity(); + ASSERT_TRUE(success_); + CheckResult(dex_location, odex_location); + } + void CheckResult(const std::string& dex_location, const std::string& odex_location) { + // Host/target independent checks. + std::string error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; + + const char* location = dex_location.c_str(); + std::vector<std::unique_ptr<const DexFile>> dex_files; + ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files)); + EXPECT_EQ(dex_files.size(), 1U); + std::unique_ptr<const DexFile>& old_dex_file = dex_files[0]; + + for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { + std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg); + ASSERT_TRUE(new_dex_file != nullptr); + uint32_t class_def_count = new_dex_file->NumClassDefs(); + ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max()); + ASSERT_GE(class_def_count, 2U); + + // The new layout swaps the classes at indexes 0 and 1. + std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_); + std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_); + std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_); + std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_); + EXPECT_EQ(old_class0, new_class1); + EXPECT_EQ(old_class1, new_class0); + } + + EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kLayoutProfile); + } + + // Check whether the dex2oat run was really successful. + void CheckValidity() { + if (kIsTargetBuild) { + CheckTargetValidity(); + } else { + CheckHostValidity(); + } + } + + void CheckTargetValidity() { + // TODO: Ignore for now. + } + + // On the host, we can get the dex2oat output. Here, look for "dex2oat took." + void CheckHostValidity() { + EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; + } + }; + +TEST_F(Dex2oatLayoutTest, TestLayout) { + RunTest(); +} + } // namespace art diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index b9266f75bf..9ee9ebd3d4 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -12,28 +12,46 @@ // See the License for the specific language governing permissions and // limitations under the License. -art_cc_binary { - name: "dexlayout", +art_cc_defaults { + name: "libart-dexlayout-defaults", host_supported: true, srcs: [ - "dexlayout_main.cc", "dexlayout.cc", "dex_ir.cc", "dex_ir_builder.cc", "dex_visualize.cc", "dex_writer.cc", ], + export_include_dirs: ["."], + shared_libs: ["libbase"], + static_libs: ["libz"], +} + +art_cc_library { + name: "libart-dexlayout", + defaults: ["libart-dexlayout-defaults"], + shared_libs: ["libart"], +} + +art_cc_library { + name: "libartd-dexlayout", + defaults: ["libart-dexlayout-defaults"], + shared_libs: ["libartd"], +} + +art_cc_binary { + name: "dexlayout", + host_supported: true, + srcs: ["dexlayout_main.cc"], cflags: ["-Wall"], shared_libs: [ "libart", - "libbase", + "libart-dexlayout", ], } art_cc_test { name: "art_dexlayout_tests", - defaults: [ - "art_gtest_defaults", - ], + defaults: ["art_gtest_defaults"], srcs: ["dexlayout_test.cc"], } diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 67f3e09567..fe2bcce843 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -56,6 +56,36 @@ static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) { entry.end_address_, entry.reg_))); } +static uint32_t GetCodeItemSize(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item) { + uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&disk_code_item); + uint32_t insns_size = disk_code_item.insns_size_in_code_units_; + uint32_t tries_size = disk_code_item.tries_size_; + if (tries_size == 0) { + uintptr_t insns_end = reinterpret_cast<uintptr_t>(&disk_code_item.insns_[insns_size]); + return insns_end - code_item_start; + } else { + uint32_t last_handler_off = 0; + for (uint32_t i = 0; i < tries_size; ++i) { + // Iterate over the try items to find the last catch handler. + const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i); + uint16_t handler_off = disk_try_item->handler_off_; + if (handler_off > last_handler_off) { + last_handler_off = handler_off; + } + } + // Decode the final handler to see where it ends. + const uint8_t* handler_data = DexFile::GetCatchHandlerData(disk_code_item, last_handler_off); + int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2; + if (uleb128_count <= 0) { + uleb128_count = -uleb128_count + 1; + } + for (int32_t i = 0; i < uleb128_count; ++i) { + DecodeUnsignedLeb128(&handler_data); + } + return reinterpret_cast<uintptr_t>(handler_data) - code_item_start; + } +} + static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) { const uint8_t* stream = debug_info_stream; DecodeUnsignedLeb128(&stream); // line_start @@ -384,11 +414,9 @@ TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, ui if (dex_type_list == nullptr) { return nullptr; } - // TODO: Create more efficient lookup for existing type lists. - for (std::unique_ptr<TypeList>& type_list : TypeLists()) { - if (type_list->GetOffset() == offset) { - return type_list.get(); - } + auto found_type_list = TypeLists().find(offset); + if (found_type_list != TypeLists().end()) { + return found_type_list->second.get(); } TypeIdVector* type_vector = new TypeIdVector(); uint32_t size = dex_type_list->Size(); @@ -404,10 +432,9 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data if (static_data == nullptr) { return nullptr; } - for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) { - if (existing_array_item->GetOffset() == offset) { - return existing_array_item.get(); - } + auto found_encoded_array_item = EncodedArrayItems().find(offset); + if (found_encoded_array_item != EncodedArrayItems().end()) { + return found_encoded_array_item->second.get(); } uint32_t size = DecodeUnsignedLeb128(&static_data); EncodedValueVector* values = new EncodedValueVector(); @@ -422,10 +449,9 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset) { - for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) { - if (existing_annotation_item->GetOffset() == offset) { - return existing_annotation_item.get(); - } + auto found_annotation_item = AnnotationItems().find(offset); + if (found_annotation_item != AnnotationItems().end()) { + return found_annotation_item->second.get(); } uint8_t visibility = annotation->visibility_; const uint8_t* annotation_data = annotation->annotation_; @@ -444,10 +470,9 @@ AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file, if (disk_annotations_item.size_ == 0 && offset == 0) { return nullptr; } - for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) { - if (existing_anno_set_item->GetOffset() == offset) { - return existing_anno_set_item.get(); - } + auto found_anno_set_item = AnnotationSetItems().find(offset); + if (found_anno_set_item != AnnotationSetItems().end()) { + return found_anno_set_item->second.get(); } std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>(); for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) { @@ -467,10 +492,9 @@ AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file, AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file, const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) { - for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) { - if (anno_dir_item->GetOffset() == offset) { - return anno_dir_item.get(); - } + auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset); + if (found_anno_dir_item != AnnotationsDirectoryItems().end()) { + return found_anno_dir_item->second.get(); } const DexFile::AnnotationSetItem* class_set_item = dex_file.GetClassAnnotationSet(disk_annotations_item); @@ -535,11 +559,9 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation( const DexFile& dex_file, MethodId* method_id, const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) { AnnotationSetRefList* set_ref_list = nullptr; - for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) { - if (existing_set_ref_list->GetOffset() == offset) { - set_ref_list = existing_set_ref_list.get(); - break; - } + auto found_set_ref_list = AnnotationSetRefLists().find(offset); + if (found_set_ref_list != AnnotationSetRefLists().end()) { + set_ref_list = found_set_ref_list->second.get(); } if (set_ref_list == nullptr) { std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>(); @@ -610,9 +632,10 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, tries->push_back(std::unique_ptr<const TryItem>(try_item)); } } - // TODO: Calculate the size of the code item. + uint32_t size = GetCodeItemSize(dex_file, disk_code_item); CodeItem* code_item = new CodeItem( registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list); + code_item->SetSize(size); code_items_.AddItem(code_item, offset); // Add "fixup" references to types, strings, methods, and fields. // This is temporary, as we will probably want more detailed parsing of the @@ -690,8 +713,8 @@ ClassData* Collections::CreateClassData( virtual_methods->push_back( std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii))); } - // TODO: Calculate the size of the class data. class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods); + class_data->SetSize(cdii.EndDataPointer() - encoded_data); class_datas_.AddItem(class_data, offset); } return class_data; diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 38eb0b1b4b..a2d1190d03 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -19,6 +19,7 @@ #ifndef ART_DEXLAYOUT_DEX_IR_H_ #define ART_DEXLAYOUT_DEX_IR_H_ +#include <map> #include <vector> #include <stdint.h> @@ -98,34 +99,52 @@ class AbstractDispatcher { }; // Collections become owners of the objects added by moving them into unique pointers. -template<class T> class CollectionWithOffset { +template<class T> class CollectionBase { public: - CollectionWithOffset() = default; - std::vector<std::unique_ptr<T>>& Collection() { return collection_; } - // Read-time support methods - void AddItem(T* object, uint32_t offset) { - object->SetOffset(offset); - collection_.push_back(std::unique_ptr<T>(object)); - } + CollectionBase() = default; + + uint32_t GetOffset() const { return offset_; } + void SetOffset(uint32_t new_offset) { offset_ = new_offset; } + + private: + uint32_t offset_ = 0; + + DISALLOW_COPY_AND_ASSIGN(CollectionBase); +}; + +template<class T> class CollectionVector : public CollectionBase<T> { + public: + CollectionVector() = default; + void AddIndexedItem(T* object, uint32_t offset, uint32_t index) { object->SetOffset(offset); object->SetIndex(index); collection_.push_back(std::unique_ptr<T>(object)); } - // Ordinary object insertion into collection. - void Insert(T object ATTRIBUTE_UNUSED) { - // TODO(sehr): add ordered insertion support. - UNIMPLEMENTED(FATAL) << "Insertion not ready"; - } - uint32_t GetOffset() const { return offset_; } - void SetOffset(uint32_t new_offset) { offset_ = new_offset; } uint32_t Size() const { return collection_.size(); } + std::vector<std::unique_ptr<T>>& Collection() { return collection_; } private: std::vector<std::unique_ptr<T>> collection_; - uint32_t offset_ = 0; - DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset); + DISALLOW_COPY_AND_ASSIGN(CollectionVector); +}; + +template<class T> class CollectionMap : public CollectionBase<T> { + public: + CollectionMap() = default; + + void AddItem(T* object, uint32_t offset) { + object->SetOffset(offset); + collection_.emplace(offset, std::unique_ptr<T>(object)); + } + uint32_t Size() const { return collection_.size(); } + std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; } + + private: + std::map<uint32_t, std::unique_ptr<T>> collection_; + + DISALLOW_COPY_AND_ASSIGN(CollectionMap); }; class Collections { @@ -138,22 +157,23 @@ class Collections { std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); } std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); } std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); } - std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); } - std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); } - std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems() + std::map<uint32_t, std::unique_ptr<StringData>>& StringDatas() + { return string_datas_.Collection(); } + std::map<uint32_t, std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); } + std::map<uint32_t, std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems() { return encoded_array_items_.Collection(); } - std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems() + std::map<uint32_t, std::unique_ptr<AnnotationItem>>& AnnotationItems() { return annotation_items_.Collection(); } - std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems() + std::map<uint32_t, std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems() { return annotation_set_items_.Collection(); } - std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists() + std::map<uint32_t, std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists() { return annotation_set_ref_lists_.Collection(); } - std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems() + std::map<uint32_t, std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems() { return annotations_directory_items_.Collection(); } - std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems() + std::map<uint32_t, std::unique_ptr<DebugInfoItem>>& DebugInfoItems() { return debug_info_items_.Collection(); } - std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); } - std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); } + std::map<uint32_t, std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); } + std::map<uint32_t, std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); } void CreateStringId(const DexFile& dex_file, uint32_t i); void CreateTypeId(const DexFile& dex_file, uint32_t i); @@ -204,7 +224,7 @@ class Collections { uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); } uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); } uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); } - uint32_t MapItemOffset() const { return map_item_offset_; } + uint32_t MapListOffset() const { return map_list_offset_; } void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); } void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); } @@ -226,7 +246,7 @@ class Collections { void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); } void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); } void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); } - void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; } + void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; } uint32_t StringIdsSize() const { return string_ids_.Size(); } uint32_t TypeIdsSize() const { return type_ids_.Size(); } @@ -254,25 +274,25 @@ class Collections { const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset); MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii); - CollectionWithOffset<StringId> string_ids_; - CollectionWithOffset<TypeId> type_ids_; - CollectionWithOffset<ProtoId> proto_ids_; - CollectionWithOffset<FieldId> field_ids_; - CollectionWithOffset<MethodId> method_ids_; - CollectionWithOffset<ClassDef> class_defs_; - - CollectionWithOffset<StringData> string_datas_; - CollectionWithOffset<TypeList> type_lists_; - CollectionWithOffset<EncodedArrayItem> encoded_array_items_; - CollectionWithOffset<AnnotationItem> annotation_items_; - CollectionWithOffset<AnnotationSetItem> annotation_set_items_; - CollectionWithOffset<AnnotationSetRefList> annotation_set_ref_lists_; - CollectionWithOffset<AnnotationsDirectoryItem> annotations_directory_items_; - CollectionWithOffset<DebugInfoItem> debug_info_items_; - CollectionWithOffset<CodeItem> code_items_; - CollectionWithOffset<ClassData> class_datas_; - - uint32_t map_item_offset_ = 0; + CollectionVector<StringId> string_ids_; + CollectionVector<TypeId> type_ids_; + CollectionVector<ProtoId> proto_ids_; + CollectionVector<FieldId> field_ids_; + CollectionVector<MethodId> method_ids_; + CollectionVector<ClassDef> class_defs_; + + CollectionMap<StringData> string_datas_; + CollectionMap<TypeList> type_lists_; + CollectionMap<EncodedArrayItem> encoded_array_items_; + CollectionMap<AnnotationItem> annotation_items_; + CollectionMap<AnnotationSetItem> annotation_set_items_; + CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_; + CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_; + CollectionMap<DebugInfoItem> debug_info_items_; + CollectionMap<CodeItem> code_items_; + CollectionMap<ClassData> class_datas_; + + uint32_t map_list_offset_ = 0; DISALLOW_COPY_AND_ASSIGN(Collections); }; @@ -539,20 +559,20 @@ using FieldItemVector = std::vector<std::unique_ptr<FieldItem>>; class MethodItem : public Item { public: - MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code) + MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code) : access_flags_(access_flags), method_id_(method_id), code_(code) { } ~MethodItem() OVERRIDE { } uint32_t GetAccessFlags() const { return access_flags_; } const MethodId* GetMethodId() const { return method_id_; } - const CodeItem* GetCodeItem() const { return code_; } + CodeItem* GetCodeItem() { return code_; } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: uint32_t access_flags_; const MethodId* method_id_; - const CodeItem* code_; // This can be nullptr. + CodeItem* code_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(MethodItem); }; diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc index 68ff2a253d..d0c5bf964e 100644 --- a/dexlayout/dex_ir_builder.cc +++ b/dexlayout/dex_ir_builder.cc @@ -71,7 +71,7 @@ Header* DexIrBuilder(const DexFile& dex_file) { collections.CreateClassDef(dex_file, i); } // MapItem. - collections.SetMapItemOffset(disk_header.map_off_); + collections.SetMapListOffset(disk_header.map_off_); CheckAndSetRemainingOffsets(dex_file, &collections); diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc index 05ad98fe02..02274b25a3 100644 --- a/dexlayout/dex_visualize.cc +++ b/dexlayout/dex_visualize.cc @@ -263,11 +263,13 @@ class Dumper { DumpStringId(method_id->Name(), class_index); } - void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) { - if (profile_info_ != nullptr) { + void DumpMethodItem(dex_ir::MethodItem* method, + const DexFile* dex_file, + int class_index, + ProfileCompilationInfo* profile_info) { + if (profile_info != nullptr) { uint32_t method_idx = method->GetMethodId()->GetIndex(); - MethodReference mr(dex_file, method_idx); - if (!profile_info_->ContainsMethod(mr)) { + if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) { return; } } @@ -344,14 +346,17 @@ class Dumper { * Dumps a gnuplot data file showing the parts of the dex_file that belong to each class. * If profiling information is present, it dumps only those classes that are marked as hot. */ -void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) { +void VisualizeDexLayout(dex_ir::Header* header, + const DexFile* dex_file, + size_t dex_file_index, + ProfileCompilationInfo* profile_info) { std::unique_ptr<Dumper> dumper(new Dumper(header->GetCollections(), dex_file_index)); const uint32_t class_defs_size = header->GetCollections().ClassDefsSize(); for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) { dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index); dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); - if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) { + if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) { continue; } dumper->DumpAddressRange(class_def, class_index); @@ -384,12 +389,12 @@ void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t } if (class_data->DirectMethods()) { for (auto& method_item : *class_data->DirectMethods()) { - dumper->DumpMethodItem(method_item.get(), dex_file, class_index); + dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info); } } if (class_data->VirtualMethods()) { for (auto& method_item : *class_data->VirtualMethods()) { - dumper->DumpMethodItem(method_item.get(), dex_file, class_index); + dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info); } } } diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h index b1d2ed79aa..09f830681b 100644 --- a/dexlayout/dex_visualize.h +++ b/dexlayout/dex_visualize.h @@ -28,11 +28,15 @@ namespace art { class DexFile; +class ProfileCompilationInfo; namespace dex_ir { class Header; } // namespace dex_ir -void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index); +void VisualizeDexLayout(dex_ir::Header* header, + const DexFile* dex_file, + size_t dex_file_index, + ProfileCompilationInfo* profile_info); } // namespace art diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index dba5da0fb1..7ffa38bfd4 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -104,7 +104,9 @@ size_t EncodeDoubleValue(double value, uint8_t* buffer) { } size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) { - return dex_file_->PwriteFully(buffer, length, offset) ? length : 0; + DCHECK_LE(offset + length, mem_map_->Size()); + memcpy(mem_map_->Begin() + offset, buffer, length); + return length; } size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { @@ -236,12 +238,13 @@ size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t void DexWriter::WriteStrings() { uint32_t string_data_off[1]; - for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) { + for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) { string_data_off[0] = string_id->DataItem()->GetOffset(); Write(string_data_off, string_id->GetSize(), string_id->GetOffset()); } - for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) { + for (auto& string_data_pair : header_->GetCollections().StringDatas()) { + std::unique_ptr<dex_ir::StringData>& string_data = string_data_pair.second; uint32_t offset = string_data->GetOffset(); offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); Write(string_data->Data(), strlen(string_data->Data()), offset); @@ -250,7 +253,7 @@ void DexWriter::WriteStrings() { void DexWriter::WriteTypes() { uint32_t descriptor_idx[1]; - for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) { + for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) { descriptor_idx[0] = type_id->GetStringId()->GetIndex(); Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset()); } @@ -259,7 +262,8 @@ void DexWriter::WriteTypes() { void DexWriter::WriteTypeLists() { uint32_t size[1]; uint16_t list[1]; - for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) { + for (auto& type_list_pair : header_->GetCollections().TypeLists()) { + std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second; size[0] = type_list->GetTypeList()->size(); uint32_t offset = type_list->GetOffset(); offset += Write(size, sizeof(uint32_t), offset); @@ -272,7 +276,7 @@ void DexWriter::WriteTypeLists() { void DexWriter::WriteProtos() { uint32_t buffer[3]; - for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) { + for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) { buffer[0] = proto_id->Shorty()->GetIndex(); buffer[1] = proto_id->ReturnType()->GetIndex(); buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); @@ -282,7 +286,7 @@ void DexWriter::WriteProtos() { void DexWriter::WriteFields() { uint16_t buffer[4]; - for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) { + for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) { buffer[0] = field_id->Class()->GetIndex(); buffer[1] = field_id->Type()->GetIndex(); buffer[2] = field_id->Name()->GetIndex(); @@ -293,7 +297,7 @@ void DexWriter::WriteFields() { void DexWriter::WriteMethods() { uint16_t buffer[4]; - for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) { + for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) { buffer[0] = method_id->Class()->GetIndex(); buffer[1] = method_id->Proto()->GetIndex(); buffer[2] = method_id->Name()->GetIndex(); @@ -303,16 +307,16 @@ void DexWriter::WriteMethods() { } void DexWriter::WriteEncodedArrays() { - for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array : - header_.GetCollections().EncodedArrayItems()) { + for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) { + std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array = encoded_array_pair.second; WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset()); } } void DexWriter::WriteAnnotations() { uint8_t visibility[1]; - for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : - header_.GetCollections().AnnotationItems()) { + for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) { + std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second; visibility[0] = annotation->GetVisibility(); size_t offset = annotation->GetOffset(); offset += Write(visibility, sizeof(uint8_t), offset); @@ -323,8 +327,8 @@ void DexWriter::WriteAnnotations() { void DexWriter::WriteAnnotationSets() { uint32_t size[1]; uint32_t annotation_off[1]; - for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set : - header_.GetCollections().AnnotationSetItems()) { + for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) { + std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second; size[0] = annotation_set->GetItems()->size(); size_t offset = annotation_set->GetOffset(); offset += Write(size, sizeof(uint32_t), offset); @@ -338,8 +342,8 @@ void DexWriter::WriteAnnotationSets() { void DexWriter::WriteAnnotationSetRefs() { uint32_t size[1]; uint32_t annotations_off[1]; - for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref : - header_.GetCollections().AnnotationSetRefLists()) { + for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) { + std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second; size[0] = annotation_set_ref->GetItems()->size(); size_t offset = annotation_set_ref->GetOffset(); offset += Write(size, sizeof(uint32_t), offset); @@ -353,8 +357,9 @@ void DexWriter::WriteAnnotationSetRefs() { void DexWriter::WriteAnnotationsDirectories() { uint32_t directory_buffer[4]; uint32_t annotation_buffer[2]; - for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory : - header_.GetCollections().AnnotationsDirectoryItems()) { + for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) { + std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory = + annotations_directory_pair.second; directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : annotations_directory->GetClassAnnotation()->GetOffset(); directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : @@ -393,15 +398,17 @@ void DexWriter::WriteAnnotationsDirectories() { } void DexWriter::WriteDebugInfoItems() { - for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) { - Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset()); + for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) { + std::unique_ptr<dex_ir::DebugInfoItem>& debug_info = debug_info_pair.second; + Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset()); } } void DexWriter::WriteCodeItems() { uint16_t uint16_buffer[4]; uint32_t uint32_buffer[2]; - for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) { + for (auto& code_item_pair : header_->GetCollections().CodeItems()) { + std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second; uint16_buffer[0] = code_item->RegistersSize(); uint16_buffer[1] = code_item->InsSize(); uint16_buffer[2] = code_item->OutsSize(); @@ -446,7 +453,7 @@ void DexWriter::WriteCodeItems() { void DexWriter::WriteClasses() { uint32_t class_def_buffer[8]; - for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) { + for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { class_def_buffer[0] = class_def->ClassType()->GetIndex(); class_def_buffer[1] = class_def->GetAccessFlags(); class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex : @@ -464,7 +471,8 @@ void DexWriter::WriteClasses() { Write(class_def_buffer, class_def->GetSize(), offset); } - for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) { + for (auto& class_data_pair : header_->GetCollections().ClassDatas()) { + std::unique_ptr<dex_ir::ClassData>& class_data = class_data_pair.second; size_t offset = class_data->GetOffset(); offset += WriteUleb128(class_data->StaticFields()->size(), offset); offset += WriteUleb128(class_data->InstanceFields()->size(), offset); @@ -491,7 +499,7 @@ struct MapItemContainer { }; void DexWriter::WriteMapItem() { - dex_ir::Collections& collection = header_.GetCollections(); + dex_ir::Collections& collection = header_->GetCollections(); std::priority_queue<MapItemContainer> queue; // Header and index section. @@ -522,7 +530,7 @@ void DexWriter::WriteMapItem() { } // Data section. - queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset())); + queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset())); if (collection.TypeListsSize() != 0) { queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(), collection.TypeListsOffset())); @@ -564,7 +572,7 @@ void DexWriter::WriteMapItem() { collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset())); } - uint32_t offset = collection.MapItemOffset(); + uint32_t offset = collection.MapListOffset(); uint16_t uint16_buffer[2]; uint32_t uint32_buffer[2]; uint16_buffer[1] = 0; @@ -583,19 +591,19 @@ void DexWriter::WriteMapItem() { void DexWriter::WriteHeader() { uint32_t buffer[20]; - dex_ir::Collections& collections = header_.GetCollections(); + dex_ir::Collections& collections = header_->GetCollections(); size_t offset = 0; - offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset); - buffer[0] = header_.Checksum(); + offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset); + buffer[0] = header_->Checksum(); offset += Write(buffer, sizeof(uint32_t), offset); - offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset); - uint32_t file_size = header_.FileSize(); + offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset); + uint32_t file_size = header_->FileSize(); buffer[0] = file_size; - buffer[1] = header_.GetSize(); - buffer[2] = header_.EndianTag(); - buffer[3] = header_.LinkSize(); - buffer[4] = header_.LinkOffset(); - buffer[5] = collections.MapItemOffset(); + buffer[1] = header_->GetSize(); + buffer[2] = header_->EndianTag(); + buffer[3] = header_->LinkSize(); + buffer[4] = header_->LinkOffset(); + buffer[5] = collections.MapListOffset(); buffer[6] = collections.StringIdsSize(); buffer[7] = collections.StringIdsOffset(); buffer[8] = collections.TypeIdsSize(); @@ -617,12 +625,7 @@ void DexWriter::WriteHeader() { Write(buffer, 20 * sizeof(uint32_t), offset); } -void DexWriter::WriteFile() { - if (dex_file_.get() == nullptr) { - fprintf(stderr, "Can't open output dex file\n"); - return; - } - +void DexWriter::WriteMemMap() { WriteStrings(); WriteTypes(); WriteTypeLists(); @@ -641,8 +644,9 @@ void DexWriter::WriteFile() { WriteHeader(); } -void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) { - (new DexWriter(header, file_name))->WriteFile(); +void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) { + DexWriter dex_writer(header, mem_map); + dex_writer.WriteMemMap(); } } // namespace art diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index 9104295472..fb76e5ccfc 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -21,19 +21,19 @@ #include "base/unix_file/fd_file.h" #include "dex_ir.h" +#include "mem_map.h" #include "os.h" namespace art { class DexWriter { public: - DexWriter(dex_ir::Header& header, const char* file_name) : header_(header), - dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { } + DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { } - static void OutputDexFile(dex_ir::Header& header, const char* file_name); + static void Output(dex_ir::Header* header, MemMap* mem_map); private: - void WriteFile(); + void WriteMemMap(); size_t Write(const void* buffer, size_t length, size_t offset); size_t WriteSleb128(uint32_t value, size_t offset); @@ -62,13 +62,12 @@ class DexWriter { void WriteMapItem(); void WriteHeader(); - dex_ir::Header& header_; - std::unique_ptr<File> dex_file_; + dex_ir::Header* const header_; + MemMap* const mem_map_; DISALLOW_COPY_AND_ASSIGN(DexWriter); }; - } // namespace art #endif // ART_DEXLAYOUT_DEX_WRITER_H_ diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index aa806557c2..cfe48378ae 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -37,27 +37,13 @@ #include "dex_visualize.h" #include "dex_writer.h" #include "jit/offline_profiling_info.h" +#include "mem_map.h" #include "os.h" #include "utils.h" namespace art { /* - * Options parsed in main driver. - */ -struct Options options_; - -/* - * Output file. Defaults to stdout. - */ -FILE* out_file_ = stdout; - -/* - * Profile information file. - */ -ProfileCompilationInfo* profile_info_ = nullptr; - -/* * Flags for use with createAccessFlagStr(). */ enum AccessFor { @@ -301,72 +287,209 @@ static void Asciify(char* out, const unsigned char* data, size_t len) { /* * Dumps a string value with some escape characters. */ -static void DumpEscapedString(const char* p) { - fputs("\"", out_file_); +static void DumpEscapedString(const char* p, FILE* out_file) { + fputs("\"", out_file); for (; *p; p++) { switch (*p) { case '\\': - fputs("\\\\", out_file_); + fputs("\\\\", out_file); break; case '\"': - fputs("\\\"", out_file_); + fputs("\\\"", out_file); break; case '\t': - fputs("\\t", out_file_); + fputs("\\t", out_file); break; case '\n': - fputs("\\n", out_file_); + fputs("\\n", out_file); break; case '\r': - fputs("\\r", out_file_); + fputs("\\r", out_file); break; default: - putc(*p, out_file_); + putc(*p, out_file); } // switch } // for - fputs("\"", out_file_); + fputs("\"", out_file); } /* * Dumps a string as an XML attribute value. */ -static void DumpXmlAttribute(const char* p) { +static void DumpXmlAttribute(const char* p, FILE* out_file) { for (; *p; p++) { switch (*p) { case '&': - fputs("&", out_file_); + fputs("&", out_file); break; case '<': - fputs("<", out_file_); + fputs("<", out_file); break; case '>': - fputs(">", out_file_); + fputs(">", out_file); break; case '"': - fputs(""", out_file_); + fputs(""", out_file); break; case '\t': - fputs("	", out_file_); + fputs("	", out_file); break; case '\n': - fputs("
", out_file_); + fputs("
", out_file); break; case '\r': - fputs("
", out_file_); + fputs("
", out_file); break; default: - putc(*p, out_file_); + putc(*p, out_file); } // switch } // for } -// Forward declare to resolve circular dependence. -static void DumpEncodedValue(const dex_ir::EncodedValue* data); +/* + * Helper for dumpInstruction(), which builds the string + * representation for the index in the given instruction. + * Returns a pointer to a buffer of sufficient size. + */ +static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, + const Instruction* dec_insn, + size_t buf_size) { + std::unique_ptr<char[]> buf(new char[buf_size]); + // Determine index and width of the string. + uint32_t index = 0; + uint32_t secondary_index = DexFile::kDexNoIndex; + uint32_t width = 4; + switch (Instruction::FormatOf(dec_insn->Opcode())) { + // SOME NOT SUPPORTED: + // case Instruction::k20bc: + case Instruction::k21c: + case Instruction::k35c: + // case Instruction::k35ms: + case Instruction::k3rc: + // case Instruction::k3rms: + // case Instruction::k35mi: + // case Instruction::k3rmi: + index = dec_insn->VRegB(); + width = 4; + break; + case Instruction::k31c: + index = dec_insn->VRegB(); + width = 8; + break; + case Instruction::k22c: + // case Instruction::k22cs: + index = dec_insn->VRegC(); + width = 4; + break; + case Instruction::k45cc: + case Instruction::k4rcc: + index = dec_insn->VRegB(); + secondary_index = dec_insn->VRegH(); + width = 4; + default: + break; + } // switch + + // Determine index type. + size_t outSize = 0; + switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { + case Instruction::kIndexUnknown: + // This function should never get called for this type, but do + // something sensible here, just to help with debugging. + outSize = snprintf(buf.get(), buf_size, "<unknown-index>"); + break; + case Instruction::kIndexNone: + // This function should never get called for this type, but do + // something sensible here, just to help with debugging. + outSize = snprintf(buf.get(), buf_size, "<no-index>"); + break; + case Instruction::kIndexTypeRef: + if (index < header->GetCollections().TypeIdsSize()) { + const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); + outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); + } else { + outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index); + } + break; + case Instruction::kIndexStringRef: + if (index < header->GetCollections().StringIdsSize()) { + const char* st = header->GetCollections().GetStringId(index)->Data(); + outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); + } else { + outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index); + } + break; + case Instruction::kIndexMethodRef: + if (index < header->GetCollections().MethodIdsSize()) { + dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); + const char* name = method_id->Name()->Data(); + std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); + const char* back_descriptor = method_id->Class()->GetStringId()->Data(); + outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", + back_descriptor, name, type_descriptor.c_str(), width, index); + } else { + outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index); + } + break; + case Instruction::kIndexFieldRef: + if (index < header->GetCollections().FieldIdsSize()) { + dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); + const char* name = field_id->Name()->Data(); + const char* type_descriptor = field_id->Type()->GetStringId()->Data(); + const char* back_descriptor = field_id->Class()->GetStringId()->Data(); + outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x", + back_descriptor, name, type_descriptor, width, index); + } else { + outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index); + } + break; + case Instruction::kIndexVtableOffset: + outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x", + width, index, width, index); + break; + case Instruction::kIndexFieldOffset: + outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index); + break; + case Instruction::kIndexMethodAndProtoRef: { + std::string method("<method?>"); + std::string proto("<proto?>"); + if (index < header->GetCollections().MethodIdsSize()) { + dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); + const char* name = method_id->Name()->Data(); + std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); + const char* back_descriptor = method_id->Class()->GetStringId()->Data(); + method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str()); + } + if (secondary_index < header->GetCollections().ProtoIdsSize()) { + dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index); + proto = GetSignatureForProtoId(proto_id); + } + outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x", + method.c_str(), proto.c_str(), width, index, width, secondary_index); + } + break; + // SOME NOT SUPPORTED: + // case Instruction::kIndexVaries: + // case Instruction::kIndexInlineMethod: + default: + outSize = snprintf(buf.get(), buf_size, "<?>"); + break; + } // switch + + // Determine success of string construction. + if (outSize >= buf_size) { + // The buffer wasn't big enough; retry with computed size. Note: snprintf() + // doesn't count/ the '\0' as part of its returned size, so we add explicit + // space for it here. + return IndexString(header, dec_insn, outSize + 1); + } + return buf; +} /* * Dumps encoded annotation. */ -static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { +void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { fputs(annotation->GetType()->GetStringId()->Data(), out_file_); // Display all name=value pairs. for (auto& subannotation : *annotation->GetAnnotationElements()) { @@ -379,7 +502,7 @@ static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { /* * Dumps encoded value. */ -static void DumpEncodedValue(const dex_ir::EncodedValue* data) { +void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) { switch (data->Type()) { case DexFile::kDexAnnotationByte: fprintf(out_file_, "%" PRId8, data->GetByte()); @@ -407,9 +530,9 @@ static void DumpEncodedValue(const dex_ir::EncodedValue* data) { case DexFile::kDexAnnotationString: { dex_ir::StringId* string_id = data->GetStringId(); if (options_.output_format_ == kOutputPlain) { - DumpEscapedString(string_id->Data()); + DumpEscapedString(string_id->Data(), out_file_); } else { - DumpXmlAttribute(string_id->Data()); + DumpXmlAttribute(string_id->Data(), out_file_); } break; } @@ -458,22 +581,22 @@ static void DumpEncodedValue(const dex_ir::EncodedValue* data) { /* * Dumps the file header. */ -static void DumpFileHeader(dex_ir::Header* header) { +void DexLayout::DumpFileHeader() { char sanitized[8 * 2 + 1]; - dex_ir::Collections& collections = header->GetCollections(); + dex_ir::Collections& collections = header_->GetCollections(); fprintf(out_file_, "DEX file header:\n"); - Asciify(sanitized, header->Magic(), 8); + Asciify(sanitized, header_->Magic(), 8); fprintf(out_file_, "magic : '%s'\n", sanitized); - fprintf(out_file_, "checksum : %08x\n", header->Checksum()); + fprintf(out_file_, "checksum : %08x\n", header_->Checksum()); fprintf(out_file_, "signature : %02x%02x...%02x%02x\n", - header->Signature()[0], header->Signature()[1], - header->Signature()[DexFile::kSha1DigestSize - 2], - header->Signature()[DexFile::kSha1DigestSize - 1]); - fprintf(out_file_, "file_size : %d\n", header->FileSize()); - fprintf(out_file_, "header_size : %d\n", header->HeaderSize()); - fprintf(out_file_, "link_size : %d\n", header->LinkSize()); + header_->Signature()[0], header_->Signature()[1], + header_->Signature()[DexFile::kSha1DigestSize - 2], + header_->Signature()[DexFile::kSha1DigestSize - 1]); + fprintf(out_file_, "file_size : %d\n", header_->FileSize()); + fprintf(out_file_, "header_size : %d\n", header_->HeaderSize()); + fprintf(out_file_, "link_size : %d\n", header_->LinkSize()); fprintf(out_file_, "link_off : %d (0x%06x)\n", - header->LinkOffset(), header->LinkOffset()); + header_->LinkOffset(), header_->LinkOffset()); fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize()); fprintf(out_file_, "string_ids_off : %d (0x%06x)\n", collections.StringIdsOffset(), collections.StringIdsOffset()); @@ -492,17 +615,17 @@ static void DumpFileHeader(dex_ir::Header* header) { fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize()); fprintf(out_file_, "class_defs_off : %d (0x%06x)\n", collections.ClassDefsOffset(), collections.ClassDefsOffset()); - fprintf(out_file_, "data_size : %d\n", header->DataSize()); + fprintf(out_file_, "data_size : %d\n", header_->DataSize()); fprintf(out_file_, "data_off : %d (0x%06x)\n\n", - header->DataOffset(), header->DataOffset()); + header_->DataOffset(), header_->DataOffset()); } /* * Dumps a class_def_item. */ -static void DumpClassDef(dex_ir::Header* header, int idx) { +void DexLayout::DumpClassDef(int idx) { // General class information. - dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); + dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); fprintf(out_file_, "Class #%d header:\n", idx); fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex()); fprintf(out_file_, "access_flags : %d (0x%04x)\n", @@ -558,7 +681,7 @@ static void DumpClassDef(dex_ir::Header* header, int idx) { /** * Dumps an annotation set item. */ -static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { +void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { if (set_item == nullptr || set_item->GetItems()->size() == 0) { fputs(" empty-annotation-set\n", out_file_); return; @@ -582,8 +705,8 @@ static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { /* * Dumps class annotations. */ -static void DumpClassAnnotations(dex_ir::Header* header, int idx) { - dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); +void DexLayout::DumpClassAnnotations(int idx) { + dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations(); if (annotations_directory == nullptr) { return; // none @@ -646,7 +769,7 @@ static void DumpClassAnnotations(dex_ir::Header* header, int idx) { /* * Dumps an interface that a class declares to implement. */ -static void DumpInterface(const dex_ir::TypeId* type_item, int i) { +void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) { const char* interface_name = type_item->GetStringId()->Data(); if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " #%d : '%s'\n", i, interface_name); @@ -659,7 +782,7 @@ static void DumpInterface(const dex_ir::TypeId* type_item, int i) { /* * Dumps the catches table associated with the code. */ -static void DumpCatches(const dex_ir::CodeItem* code) { +void DexLayout::DumpCatches(const dex_ir::CodeItem* code) { const uint16_t tries_size = code->TriesSize(); // No catch table. @@ -687,7 +810,7 @@ static void DumpCatches(const dex_ir::CodeItem* code) { /* * Dumps all positions table entries associated with the code. */ -static void DumpPositionInfo(const dex_ir::CodeItem* code) { +void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) { dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); if (debug_info == nullptr) { return; @@ -701,7 +824,7 @@ static void DumpPositionInfo(const dex_ir::CodeItem* code) { /* * Dumps all locals table entries associated with the code. */ -static void DumpLocalInfo(const dex_ir::CodeItem* code) { +void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) { dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); if (debug_info == nullptr) { return; @@ -716,153 +839,13 @@ static void DumpLocalInfo(const dex_ir::CodeItem* code) { } /* - * Helper for dumpInstruction(), which builds the string - * representation for the index in the given instruction. - * Returns a pointer to a buffer of sufficient size. - */ -static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, - const Instruction* dec_insn, - size_t buf_size) { - static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max(); - std::unique_ptr<char[]> buf(new char[buf_size]); - // Determine index and width of the string. - uint32_t index = 0; - uint32_t secondary_index = kInvalidIndex; - uint32_t width = 4; - switch (Instruction::FormatOf(dec_insn->Opcode())) { - // SOME NOT SUPPORTED: - // case Instruction::k20bc: - case Instruction::k21c: - case Instruction::k35c: - // case Instruction::k35ms: - case Instruction::k3rc: - // case Instruction::k3rms: - // case Instruction::k35mi: - // case Instruction::k3rmi: - index = dec_insn->VRegB(); - width = 4; - break; - case Instruction::k31c: - index = dec_insn->VRegB(); - width = 8; - break; - case Instruction::k22c: - // case Instruction::k22cs: - index = dec_insn->VRegC(); - width = 4; - break; - case Instruction::k45cc: - case Instruction::k4rcc: - index = dec_insn->VRegB(); - secondary_index = dec_insn->VRegH(); - width = 4; - break; - default: - break; - } // switch - - // Determine index type. - size_t outSize = 0; - switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { - case Instruction::kIndexUnknown: - // This function should never get called for this type, but do - // something sensible here, just to help with debugging. - outSize = snprintf(buf.get(), buf_size, "<unknown-index>"); - break; - case Instruction::kIndexNone: - // This function should never get called for this type, but do - // something sensible here, just to help with debugging. - outSize = snprintf(buf.get(), buf_size, "<no-index>"); - break; - case Instruction::kIndexTypeRef: - if (index < header->GetCollections().TypeIdsSize()) { - const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index); - } - break; - case Instruction::kIndexStringRef: - if (index < header->GetCollections().StringIdsSize()) { - const char* st = header->GetCollections().GetStringId(index)->Data(); - outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index); - } - break; - case Instruction::kIndexMethodRef: - if (index < header->GetCollections().MethodIdsSize()) { - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); - const char* name = method_id->Name()->Data(); - std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); - const char* back_descriptor = method_id->Class()->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", - back_descriptor, name, type_descriptor.c_str(), width, index); - } else { - outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index); - } - break; - case Instruction::kIndexFieldRef: - if (index < header->GetCollections().FieldIdsSize()) { - dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); - const char* name = field_id->Name()->Data(); - const char* type_descriptor = field_id->Type()->GetStringId()->Data(); - const char* back_descriptor = field_id->Class()->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x", - back_descriptor, name, type_descriptor, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index); - } - break; - case Instruction::kIndexVtableOffset: - outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x", - width, index, width, index); - break; - case Instruction::kIndexFieldOffset: - outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index); - break; - // SOME NOT SUPPORTED: - // case Instruction::kIndexVaries: - // case Instruction::kIndexInlineMethod: - case Instruction::kIndexMethodAndProtoRef: { - std::string method("<method?>"); - std::string proto("<proto?>"); - if (index < header->GetCollections().MethodIdsSize()) { - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); - const char* name = method_id->Name()->Data(); - std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); - const char* back_descriptor = method_id->Class()->GetStringId()->Data(); - method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str()); - } - if (secondary_index < header->GetCollections().ProtoIdsSize()) { - dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index); - proto = GetSignatureForProtoId(proto_id); - } - outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x", - method.c_str(), proto.c_str(), width, index, width, secondary_index); - } - break; - default: - outSize = snprintf(buf.get(), buf_size, "<?>"); - break; - } // switch - - // Determine success of string construction. - if (outSize >= buf_size) { - // The buffer wasn't big enough; retry with computed size. Note: snprintf() - // doesn't count/ the '\0' as part of its returned size, so we add explicit - // space for it here. - return IndexString(header, dec_insn, outSize + 1); - } - return buf; -} - -/* * Dumps a single instruction. */ -static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code, - uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width, - const Instruction* dec_insn) { +void DexLayout::DumpInstruction(const dex_ir::CodeItem* code, + uint32_t code_offset, + uint32_t insn_idx, + uint32_t insn_width, + const Instruction* dec_insn) { // Address of instruction (expressed as byte offset). fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2); @@ -901,7 +884,7 @@ static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code // Set up additional argument. std::unique_ptr<char[]> index_buf; if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) { - index_buf = IndexString(header, dec_insn, 200); + index_buf = IndexString(header_, dec_insn, 200); } // Dump the instruction. @@ -1073,9 +1056,8 @@ static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code /* * Dumps a bytecode disassembly. */ -static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, - const dex_ir::CodeItem* code, uint32_t code_offset) { - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx); +void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { + dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); const char* name = method_id->Name()->Data(); std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); @@ -1094,7 +1076,7 @@ static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx); break; } - DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction); + DumpInstruction(code, code_offset, insn_idx, insn_width, instruction); insn_idx += insn_width; } // for } @@ -1102,8 +1084,7 @@ static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, /* * Dumps code of a method. */ -static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code, - uint32_t code_offset) { +void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { fprintf(out_file_, " registers : %d\n", code->RegistersSize()); fprintf(out_file_, " ins : %d\n", code->InsSize()); fprintf(out_file_, " outs : %d\n", code->OutsSize()); @@ -1112,7 +1093,7 @@ static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeIte // Bytecode disassembly, if requested. if (options_.disassemble_) { - DumpBytecodes(header, idx, code, code_offset); + DumpBytecodes(idx, code, code_offset); } // Try-catch blocks. @@ -1128,14 +1109,13 @@ static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeIte /* * Dumps a method. */ -static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags, - const dex_ir::CodeItem* code, int i) { +void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) { // Bail for anything private if export only requested. if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { return; } - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx); + dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); const char* name = method_id->Name()->Data(); char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); @@ -1150,7 +1130,7 @@ static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags, fprintf(out_file_, " code : (none)\n"); } else { fprintf(out_file_, " code -\n"); - DumpCode(header, idx, code, code->GetOffset()); + DumpCode(idx, code, code->GetOffset()); } if (options_.disassemble_) { fputc('\n', out_file_); @@ -1233,14 +1213,13 @@ static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags, /* * Dumps a static (class) field. */ -static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags, - int i, dex_ir::EncodedValue* init) { +void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) { // Bail for anything private if export only requested. if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { return; } - dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx); + dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx); const char* name = field_id->Name()->Data(); const char* type_descriptor = field_id->Type()->GetStringId()->Data(); const char* back_descriptor = field_id->Class()->GetStringId()->Data(); @@ -1281,8 +1260,8 @@ static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags, /* * Dumps an instance field. */ -static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) { - DumpSField(header, idx, flags, i, nullptr); +void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) { + DumpSField(idx, flags, i, nullptr); } /* @@ -1293,19 +1272,19 @@ static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int * If "*last_package" is nullptr or does not match the current class' package, * the value will be replaced with a newly-allocated string. */ -static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { - dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); +void DexLayout::DumpClass(int idx, char** last_package) { + dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); // Omitting non-public class. if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) { return; } if (options_.show_section_headers_) { - DumpClassDef(header, idx); + DumpClassDef(idx); } if (options_.show_annotations_) { - DumpClassAnnotations(header, idx); + DumpClassAnnotations(idx); } // For the XML output, show the package name. Ideally we'd gather @@ -1313,7 +1292,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { // package name wouldn't jump around, but that's not a great plan // for something that needs to run on the device. const char* class_descriptor = - header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); + header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); if (!(class_descriptor[0] == 'L' && class_descriptor[strlen(class_descriptor)-1] == ';')) { // Arrays and primitives should not be defined explicitly. Keep going? @@ -1406,8 +1385,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); if (static_fields != nullptr) { for (uint32_t i = 0; i < static_fields->size(); i++) { - DumpSField(header, - (*static_fields)[i]->GetFieldId()->GetIndex(), + DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(), (*static_fields)[i]->GetAccessFlags(), i, i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); @@ -1423,8 +1401,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); if (instance_fields != nullptr) { for (uint32_t i = 0; i < instance_fields->size(); i++) { - DumpIField(header, - (*instance_fields)[i]->GetFieldId()->GetIndex(), + DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(), (*instance_fields)[i]->GetAccessFlags(), i); } // for @@ -1439,8 +1416,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); if (direct_methods != nullptr) { for (uint32_t i = 0; i < direct_methods->size(); i++) { - DumpMethod(header, - (*direct_methods)[i]->GetMethodId()->GetIndex(), + DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(), (*direct_methods)[i]->GetAccessFlags(), (*direct_methods)[i]->GetCodeItem(), i); @@ -1456,8 +1432,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); if (virtual_methods != nullptr) { for (uint32_t i = 0; i < virtual_methods->size(); i++) { - DumpMethod(header, - (*virtual_methods)[i]->GetMethodId()->GetIndex(), + DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(), (*virtual_methods)[i]->GetAccessFlags(), (*virtual_methods)[i]->GetCodeItem(), i); @@ -1481,24 +1456,10 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { free(access_str); } -/* - * Dumps the requested sections of the file. - */ -static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) { - if (options_.verbose_) { - fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", - file_name, dex_file->GetHeader().magic_ + 4); - } - std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file)); - - if (options_.visualize_pattern_) { - VisualizeDexLayout(header.get(), dex_file, dex_file_index); - return; - } - +void DexLayout::DumpDexFile() { // Headers. if (options_.show_file_headers_) { - DumpFileHeader(header.get()); + DumpFileHeader(); } // Open XML context. @@ -1508,9 +1469,9 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_ // Iterate over all classes. char* package = nullptr; - const uint32_t class_defs_size = header->GetCollections().ClassDefsSize(); + const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize(); for (uint32_t i = 0; i < class_defs_size; i++) { - DumpClass(header.get(), i, &package); + DumpClass(i, &package); } // for // Free the last package allocated. @@ -1523,20 +1484,227 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_ if (options_.output_format_ == kOutputXml) { fprintf(out_file_, "</api>\n"); } +} - // Output dex file. - if (options_.output_dex_directory_ != nullptr) { +std::vector<dex_ir::ClassDef*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { + std::vector<dex_ir::ClassDef*> new_class_def_order; + for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { + dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); + if (info_->ContainsClass(*dex_file, type_idx)) { + new_class_def_order.push_back(class_def.get()); + } + } + for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { + dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); + if (!info_->ContainsClass(*dex_file, type_idx)) { + new_class_def_order.push_back(class_def.get()); + } + } + uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset(); + uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset(); + for (uint32_t i = 0; i < new_class_def_order.size(); ++i) { + dex_ir::ClassDef* class_def = new_class_def_order[i]; + class_def->SetIndex(i); + class_def->SetOffset(class_defs_offset); + class_defs_offset += dex_ir::ClassDef::ItemSize(); + if (class_def->GetClassData() != nullptr) { + class_def->GetClassData()->SetOffset(class_data_offset); + class_data_offset += class_def->GetClassData()->GetSize(); + } + } + return new_class_def_order; +} + +int32_t DexLayout::LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order) { + int32_t diff = 0; + uint32_t offset = header_->GetCollections().CodeItemsOffset(); + for (dex_ir::ClassDef* class_def : new_class_def_order) { + dex_ir::ClassData* class_data = class_def->GetClassData(); + if (class_data != nullptr) { + class_data->SetOffset(class_data->GetOffset() + diff); + for (auto& method : *class_data->DirectMethods()) { + dex_ir::CodeItem* code_item = method->GetCodeItem(); + if (code_item != nullptr) { + diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset()); + code_item->SetOffset(offset); + offset += RoundUp(code_item->GetSize(), 4); + } + } + for (auto& method : *class_data->VirtualMethods()) { + dex_ir::CodeItem* code_item = method->GetCodeItem(); + if (code_item != nullptr) { + diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset()); + code_item->SetOffset(offset); + offset += RoundUp(code_item->GetSize(), 4); + } + } + } + } + + return diff; +} + +// Adjust offsets of every item in the specified section by diff bytes. +template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, + uint32_t diff) { + for (auto& pair : map) { + std::unique_ptr<T>& item = pair.second; + item->SetOffset(item->GetOffset() + diff); + } +} + +// Adjust offsets of all sections with an address after the specified offset by diff bytes. +void DexLayout::FixupSections(uint32_t offset, uint32_t diff) { + dex_ir::Collections& collections = header_->GetCollections(); + uint32_t map_list_offset = collections.MapListOffset(); + if (map_list_offset > offset) { + collections.SetMapListOffset(map_list_offset + diff); + } + + uint32_t type_lists_offset = collections.TypeListsOffset(); + if (type_lists_offset > offset) { + collections.SetTypeListsOffset(type_lists_offset + diff); + FixupSection(collections.TypeLists(), diff); + } + + uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset(); + if (annotation_set_ref_lists_offset > offset) { + collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff); + FixupSection(collections.AnnotationSetRefLists(), diff); + } + + uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset(); + if (annotation_set_items_offset > offset) { + collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff); + FixupSection(collections.AnnotationSetItems(), diff); + } + + uint32_t class_datas_offset = collections.ClassDatasOffset(); + if (class_datas_offset > offset) { + collections.SetClassDatasOffset(class_datas_offset + diff); + FixupSection(collections.ClassDatas(), diff); + } + + uint32_t code_items_offset = collections.CodeItemsOffset(); + if (code_items_offset > offset) { + collections.SetCodeItemsOffset(code_items_offset + diff); + FixupSection(collections.CodeItems(), diff); + } + + uint32_t string_datas_offset = collections.StringDatasOffset(); + if (string_datas_offset > offset) { + collections.SetStringDatasOffset(string_datas_offset + diff); + FixupSection(collections.StringDatas(), diff); + } + + uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset(); + if (debug_info_items_offset > offset) { + collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff); + FixupSection(collections.DebugInfoItems(), diff); + } + + uint32_t annotation_items_offset = collections.AnnotationItemsOffset(); + if (annotation_items_offset > offset) { + collections.SetAnnotationItemsOffset(annotation_items_offset + diff); + FixupSection(collections.AnnotationItems(), diff); + } + + uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset(); + if (encoded_array_items_offset > offset) { + collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff); + FixupSection(collections.EncodedArrayItems(), diff); + } + + uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset(); + if (annotations_directory_items_offset > offset) { + collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff); + FixupSection(collections.AnnotationsDirectoryItems(), diff); + } +} + +void DexLayout::LayoutOutputFile(const DexFile* dex_file) { + std::vector<dex_ir::ClassDef*> new_class_def_order = LayoutClassDefsAndClassData(dex_file); + int32_t diff = LayoutCodeItems(new_class_def_order); + // Adjust diff to be 4-byte aligned. + diff = RoundUp(diff, 4); + // Move sections after ClassData by diff bytes. + FixupSections(header_->GetCollections().ClassDatasOffset(), diff); + // Update file size. + header_->SetFileSize(header_->FileSize() + diff); +} + +void DexLayout::OutputDexFile(const std::string& dex_file_location) { + std::string error_msg; + std::unique_ptr<File> new_file; + if (!options_.output_to_memmap_) { std::string output_location(options_.output_dex_directory_); - size_t last_slash = dex_file->GetLocation().rfind('/'); - output_location.append(dex_file->GetLocation().substr(last_slash)); - DexWriter::OutputDexFile(*header, output_location.c_str()); + size_t last_slash = dex_file_location.rfind("/"); + std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1); + if (output_location == dex_file_directory) { + output_location = dex_file_location + ".new"; + } else if (last_slash != std::string::npos) { + output_location += dex_file_location.substr(last_slash); + } else { + output_location += "/" + dex_file_location + ".new"; + } + new_file.reset(OS::CreateEmptyFile(output_location.c_str())); + ftruncate(new_file->Fd(), header_->FileSize()); + mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED, + new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg)); + } else { + mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(), + PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg)); + } + if (mem_map_ == nullptr) { + LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg; + if (new_file.get() != nullptr) { + new_file->Erase(); + } + return; + } + DexWriter::Output(header_, mem_map_.get()); + if (new_file != nullptr) { + UNUSED(new_file->FlushCloseOrErase()); + } +} + +/* + * Dumps the requested sections of the file. + */ +void DexLayout::ProcessDexFile(const char* file_name, + const DexFile* dex_file, + size_t dex_file_index) { + std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file)); + SetHeader(header.get()); + + if (options_.verbose_) { + fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", + file_name, dex_file->GetHeader().magic_ + 4); + } + + if (options_.visualize_pattern_) { + VisualizeDexLayout(header_, dex_file, dex_file_index, info_); + return; + } + + // Dump dex file. + if (options_.dump_) { + DumpDexFile(); + } + + // Output dex file as file or memmap. + if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) { + if (info_ != nullptr) { + LayoutOutputFile(dex_file); + } + OutputDexFile(dex_file->GetLocation()); } } /* * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). */ -int ProcessFile(const char* file_name) { +int DexLayout::ProcessFile(const char* file_name) { if (options_.verbose_) { fprintf(out_file_, "Processing '%s'...\n", file_name); } diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index a5bd99284e..ac1a4a6efb 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -26,8 +26,13 @@ #include <stdint.h> #include <stdio.h> +#include "dex_ir.h" +#include "mem_map.h" + namespace art { +class DexFile; +class Instruction; class ProfileCompilationInfo; /* Supported output formats. */ @@ -37,28 +42,90 @@ enum OutputFormat { }; /* Command-line options. */ -struct Options { - bool build_dex_ir_; - bool checksum_only_; - bool disassemble_; - bool exports_only_; - bool ignore_bad_checksum_; - bool show_annotations_; - bool show_file_headers_; - bool show_section_headers_; - bool verbose_; - bool visualize_pattern_; - OutputFormat output_format_; - const char* output_dex_directory_; - const char* output_file_name_; - const char* profile_file_name_; +class Options { + public: + Options() = default; + + bool dump_ = false; + bool build_dex_ir_ = false; + bool checksum_only_ = false; + bool disassemble_ = false; + bool exports_only_ = false; + bool ignore_bad_checksum_ = false; + bool output_to_memmap_ = false; + bool show_annotations_ = false; + bool show_file_headers_ = false; + bool show_section_headers_ = false; + bool verbose_ = false; + bool visualize_pattern_ = false; + OutputFormat output_format_ = kOutputPlain; + const char* output_dex_directory_ = nullptr; + const char* output_file_name_ = nullptr; + const char* profile_file_name_ = nullptr; }; -/* Prototypes. */ -extern struct Options options_; -extern FILE* out_file_; -extern ProfileCompilationInfo* profile_info_; -int ProcessFile(const char* file_name); +class DexLayout { + public: + DexLayout(Options& options, + ProfileCompilationInfo* info, + FILE* out_file, + dex_ir::Header* + header = nullptr) + : options_(options), info_(info), out_file_(out_file), header_(header) { } + + int ProcessFile(const char* file_name); + void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index); + + dex_ir::Header* GetHeader() const { return header_; } + void SetHeader(dex_ir::Header* header) { header_ = header; } + + MemMap* GetAndReleaseMemMap() { return mem_map_.release(); } + + private: + void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item); + void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset); + void DumpCatches(const dex_ir::CodeItem* code); + void DumpClass(int idx, char** last_package); + void DumpClassAnnotations(int idx); + void DumpClassDef(int idx); + void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset); + void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation); + void DumpEncodedValue(const dex_ir::EncodedValue* data); + void DumpFileHeader(); + void DumpIField(uint32_t idx, uint32_t flags, int i); + void DumpInstruction(const dex_ir::CodeItem* code, + uint32_t code_offset, + uint32_t insn_idx, + uint32_t insn_width, + const Instruction* dec_insn); + void DumpInterface(const dex_ir::TypeId* type_item, int i); + void DumpLocalInfo(const dex_ir::CodeItem* code); + void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i); + void DumpPositionInfo(const dex_ir::CodeItem* code); + void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init); + void DumpDexFile(); + + std::vector<dex_ir::ClassDef*> LayoutClassDefsAndClassData(const DexFile* dex_file); + int32_t LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order); + template<class T> void FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, uint32_t diff); + void FixupSections(uint32_t offset, uint32_t diff); + + // Creates a new layout for the dex file based on profile info. + // Currently reorders ClassDefs, ClassDataItems, and CodeItems. + void LayoutOutputFile(const DexFile* dex_file); + void OutputDexFile(const std::string& dex_file_location); + + void DumpCFG(const DexFile* dex_file, int idx); + void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code); + + Options& options_; + ProfileCompilationInfo* info_; + FILE* out_file_; + dex_ir::Header* header_; + std::unique_ptr<MemMap> mem_map_; + + DISALLOW_COPY_AND_ASSIGN(DexLayout); +}; } // namespace art diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index 825dd50355..5f8a118bde 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -68,64 +68,67 @@ int DexlayoutDriver(int argc, char** argv) { InitLogging(argv, Runtime::Aborter); MemMap::Init(); - // Reset options. + Options options; + options.dump_ = true; + options.verbose_ = true; bool want_usage = false; - memset(&options_, 0, sizeof(options_)); - options_.verbose_ = true; // Parse all arguments. while (1) { - const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:"); + const int ic = getopt(argc, argv, "abcdefghil:mo:p:sw:"); if (ic < 0) { break; // done } switch (ic) { case 'a': // display annotations - options_.show_annotations_ = true; + options.show_annotations_ = true; break; case 'b': // build dex_ir - options_.build_dex_ir_ = true; + options.build_dex_ir_ = true; break; case 'c': // verify the checksum then exit - options_.checksum_only_ = true; + options.checksum_only_ = true; break; case 'd': // disassemble Dalvik instructions - options_.disassemble_ = true; + options.disassemble_ = true; break; case 'e': // exported items only - options_.exports_only_ = true; + options.exports_only_ = true; break; case 'f': // display outer file header - options_.show_file_headers_ = true; + options.show_file_headers_ = true; break; case 'h': // display section headers, i.e. all meta-data - options_.show_section_headers_ = true; + options.show_section_headers_ = true; break; case 'i': // continue even if checksum is bad - options_.ignore_bad_checksum_ = true; + options.ignore_bad_checksum_ = true; break; case 'l': // layout if (strcmp(optarg, "plain") == 0) { - options_.output_format_ = kOutputPlain; + options.output_format_ = kOutputPlain; } else if (strcmp(optarg, "xml") == 0) { - options_.output_format_ = kOutputXml; - options_.verbose_ = false; + options.output_format_ = kOutputXml; + options.verbose_ = false; } else { want_usage = true; } break; + case 'm': // output dex files to a memmap + options.output_to_memmap_ = true; + break; case 'o': // output file - options_.output_file_name_ = optarg; + options.output_file_name_ = optarg; break; case 'p': // profile file - options_.profile_file_name_ = optarg; + options.profile_file_name_ = optarg; break; case 's': // visualize access pattern - options_.visualize_pattern_ = true; - options_.verbose_ = false; + options.visualize_pattern_ = true; + options.verbose_ = false; break; case 'w': // output dex files directory - options_.output_dex_directory_ = optarg; + options.output_dex_directory_ = optarg; break; default: want_usage = true; @@ -138,7 +141,7 @@ int DexlayoutDriver(int argc, char** argv) { fprintf(stderr, "%s: no file specified\n", kProgramName); want_usage = true; } - if (options_.checksum_only_ && options_.ignore_bad_checksum_) { + if (options.checksum_only_ && options.ignore_bad_checksum_) { fprintf(stderr, "Can't specify both -c and -i\n"); want_usage = true; } @@ -148,32 +151,37 @@ int DexlayoutDriver(int argc, char** argv) { } // Open alternative output file. - if (options_.output_file_name_) { - out_file_ = fopen(options_.output_file_name_, "w"); - if (!out_file_) { - fprintf(stderr, "Can't open %s\n", options_.output_file_name_); + FILE* out_file = stdout; + if (options.output_file_name_) { + out_file = fopen(options.output_file_name_, "w"); + if (!out_file) { + fprintf(stderr, "Can't open %s\n", options.output_file_name_); return 1; } } // Open profile file. - if (options_.profile_file_name_) { - int profile_fd = open(options_.profile_file_name_, O_RDONLY); + ProfileCompilationInfo* profile_info = nullptr; + if (options.profile_file_name_) { + int profile_fd = open(options.profile_file_name_, O_RDONLY); if (profile_fd < 0) { - fprintf(stderr, "Can't open %s\n", options_.profile_file_name_); + fprintf(stderr, "Can't open %s\n", options.profile_file_name_); return 1; } - profile_info_ = new ProfileCompilationInfo(); - if (!profile_info_->Load(profile_fd)) { - fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_); + profile_info = new ProfileCompilationInfo(); + if (!profile_info->Load(profile_fd)) { + fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_); return 1; } } + // Create DexLayout instance. + DexLayout dex_layout(options, profile_info, out_file); + // Process all files supplied on command line. int result = 0; while (optind < argc) { - result |= ProcessFile(argv[optind++]); + result |= dex_layout.ProcessFile(argv[optind++]); } // while return result != 0; } diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index c7f36be905..665baa6c73 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -22,11 +22,57 @@ #include <unistd.h> #include "base/stringprintf.h" +#include "base/unix_file/fd_file.h" #include "common_runtime_test.h" #include "utils.h" namespace art { +static const char kDexFileLayoutInputDex[] = + "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH" + "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB" + "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA" + "AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAEAAAAAAAAAdQEAAAAAAAABAAAA" + "AAAAAAIAAAAAAAAAAgAAAAAAAAB/AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB" + "AAAAbwEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph" + "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQAAgIAEgAIAAAEAAYCABJgCAAAACwAA" + "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA" + "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC" + "AAAAdQEAAAAQAAABAAAAjAEAAA=="; + +static const char kDexFileLayoutInputProfile[] = + "cHJvADAwMgABAAsAAAABAPUpbf5jbGFzc2VzLmRleAEA"; + +static const char kDexFileLayoutExpectedOutputDex[] = + "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH" + "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB" + "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA" + "AAAAAAABAAAAAAAAAAIAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAIAAAAAAAAAdQEAAAAAAAAAAAAA" + "AAAAAAIAAAAAAAAAAQAAAAAAAAB/AQAAAAAAAAEAAQABAAAAbwEAAAQAAABwEAIAAAAOAAEAAQAB" + "AAAAaQEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph" + "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQABgIAEgAIAAAEAAICABJgCAAAACwAA" + "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA" + "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC" + "AAAAdQEAAAAQAAABAAAAjAEAAA=="; + +static void WriteFileBase64(const char* base64, const char* location) { + // Decode base64. + CHECK(base64 != nullptr); + size_t length; + std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length)); + CHECK(bytes.get() != nullptr); + + // Write to provided file. + std::unique_ptr<File> file(OS::CreateEmptyFile(location)); + CHECK(file.get() != nullptr); + if (!file->WriteFully(bytes.get(), length)) { + PLOG(FATAL) << "Failed to write base64 as file"; + } + if (file->FlushCloseOrErase() != 0) { + PLOG(FATAL) << "Could not flush and close test file."; + } +} + class DexLayoutTest : public CommonRuntimeTest { protected: virtual void SetUp() { @@ -51,7 +97,6 @@ class DexLayoutTest : public CommonRuntimeTest { { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file }; std::vector<std::string> dexlayout_exec_argv = { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file }; - if (!::art::Exec(dexdump_exec_argv, error_msg)) { return false; } @@ -78,13 +123,11 @@ class DexLayoutTest : public CommonRuntimeTest { for (const std::string &dex_file : GetLibCoreDexFileNames()) { std::vector<std::string> dexlayout_exec_argv = - { dexlayout, "-d", "-f", "-h", "-l", "plain", "-w", tmp_dir, "-o", tmp_name, dex_file }; - + { dexlayout, "-w", tmp_dir, "-o", tmp_name, dex_file }; if (!::art::Exec(dexlayout_exec_argv, error_msg)) { return false; } - - size_t dex_file_last_slash = dex_file.rfind('/'); + size_t dex_file_last_slash = dex_file.rfind("/"); std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1); std::vector<std::string> unzip_exec_argv = { "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir}; @@ -105,7 +148,44 @@ class DexLayoutTest : public CommonRuntimeTest { return false; } } + return true; + } + + // Runs DexFileOutput test. + bool DexFileLayoutExec(std::string* error_msg) { + ScratchFile tmp_file; + std::string tmp_name = tmp_file.GetFilename(); + size_t tmp_last_slash = tmp_name.rfind("/"); + std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1); + + // Write inputs and expected outputs. + std::string dex_file = tmp_dir + "classes.dex"; + WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str()); + std::string profile_file = tmp_dir + "primary.prof"; + WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str()); + std::string expected_output = tmp_dir + "expected.dex"; + WriteFileBase64(kDexFileLayoutExpectedOutputDex, expected_output.c_str()); + std::string output_dex = tmp_dir + "classes.dex.new"; + + std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout"; + EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; + + std::vector<std::string> dexlayout_exec_argv = + { dexlayout, "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file }; + if (!::art::Exec(dexlayout_exec_argv, error_msg)) { + return false; + } + std::vector<std::string> diff_exec_argv = + { "/usr/bin/diff", expected_output, output_dex }; + if (!::art::Exec(diff_exec_argv, error_msg)) { + return false; + } + std::vector<std::string> rm_exec_argv = + { "/bin/rm", dex_file, profile_file, expected_output, output_dex }; + if (!::art::Exec(rm_exec_argv, error_msg)) { + return false; + } return true; } }; @@ -125,4 +205,11 @@ TEST_F(DexLayoutTest, DexFileOutput) { ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg; } +TEST_F(DexLayoutTest, DexFileLayout) { + // Disable test on target. + TEST_DISABLED_FOR_TARGET(); + std::string error_msg; + ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg; +} + } // namespace art diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc index dc197c1066..6e3e1d87e5 100644 --- a/runtime/compiler_filter.cc +++ b/runtime/compiler_filter.cc @@ -33,6 +33,7 @@ bool CompilerFilter::IsBytecodeCompilationEnabled(Filter filter) { case CompilerFilter::kTime: case CompilerFilter::kSpeedProfile: case CompilerFilter::kSpeed: + case CompilerFilter::kLayoutProfile: case CompilerFilter::kEverythingProfile: case CompilerFilter::kEverything: return true; } @@ -52,6 +53,7 @@ bool CompilerFilter::IsJniCompilationEnabled(Filter filter) { case CompilerFilter::kTime: case CompilerFilter::kSpeedProfile: case CompilerFilter::kSpeed: + case CompilerFilter::kLayoutProfile: case CompilerFilter::kEverythingProfile: case CompilerFilter::kEverything: return true; } @@ -71,6 +73,7 @@ bool CompilerFilter::IsVerificationEnabled(Filter filter) { case CompilerFilter::kTime: case CompilerFilter::kSpeedProfile: case CompilerFilter::kSpeed: + case CompilerFilter::kLayoutProfile: case CompilerFilter::kEverythingProfile: case CompilerFilter::kEverything: return true; } @@ -97,6 +100,7 @@ bool CompilerFilter::DependsOnProfile(Filter filter) { case CompilerFilter::kVerifyProfile: case CompilerFilter::kSpaceProfile: case CompilerFilter::kSpeedProfile: + case CompilerFilter::kLayoutProfile: case CompilerFilter::kEverythingProfile: return true; } UNREACHABLE(); @@ -121,6 +125,7 @@ CompilerFilter::Filter CompilerFilter::GetNonProfileDependentFilterFrom(Filter f return CompilerFilter::kSpace; case CompilerFilter::kSpeedProfile: + case CompilerFilter::kLayoutProfile: return CompilerFilter::kSpeed; case CompilerFilter::kEverythingProfile: @@ -146,6 +151,7 @@ std::string CompilerFilter::NameOfFilter(Filter filter) { case CompilerFilter::kTime: return "time"; case CompilerFilter::kSpeedProfile: return "speed-profile"; case CompilerFilter::kSpeed: return "speed"; + case CompilerFilter::kLayoutProfile: return "layout-profile"; case CompilerFilter::kEverythingProfile: return "everything-profile"; case CompilerFilter::kEverything: return "everything"; } @@ -173,6 +179,8 @@ bool CompilerFilter::ParseCompilerFilter(const char* option, Filter* filter) { *filter = kSpeed; } else if (strcmp(option, "speed-profile") == 0) { *filter = kSpeedProfile; + } else if (strcmp(option, "layout-profile") == 0) { + *filter = kLayoutProfile; } else if (strcmp(option, "everything") == 0) { *filter = kEverything; } else if (strcmp(option, "everything-profile") == 0) { diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h index 37631cc6d2..781d43aa6e 100644 --- a/runtime/compiler_filter.h +++ b/runtime/compiler_filter.h @@ -39,6 +39,7 @@ class CompilerFilter FINAL { kSpace, // Maximize space savings. kBalanced, // Good performance return on compilation investment. kSpeedProfile, // Maximize runtime performance based on profile. + kLayoutProfile, // Temporary filter for dexlayout. Will be merged with kSpeedProfile. kSpeed, // Maximize runtime performance. kEverythingProfile, // Compile everything capable of being compiled based on profile. kEverything, // Compile everything capable of being compiled. diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index 4effed4a95..ed507110bd 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -590,7 +590,7 @@ bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, (reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + idx)-> class_idx_; if (class_type_index != my_class_index) { - ErrorStringPrintf("Method's class index unexpected, %" PRIu16 "vs %" PRIu16, + ErrorStringPrintf("Method's class index unexpected, %" PRIu16 " vs %" PRIu16, my_class_index.index_, class_type_index.index_); return false; |