From c803763b7f4ee725717839b679cadeb1637b6be5 Mon Sep 17 00:00:00 2001 From: huangs Date: Thu, 19 May 2016 11:16:40 -0700 Subject: [PATCH] [Courgette] Using LabelManager to reduce Courgette-apply peak RAM by 25%. AssemblyProgram previously allocates new Label instances as it parses an executable and emits instructions. This CL replaces the flow by using LabelManager to precompute Labels in one array. This allows us to reduce Courgette-apply peak RAM by 25%, measured by "choke RAM until failure" method. Details: - We precompute Labels in AssemblyProgram::PrecomputeLabels(), which relies on RvaVisitor inherited classes for architecture-specific extraction of abs32 and rel32 targets. - TrimLabel()'s complex post-processing flow is simplified using PrecomputeLabels(), which runs before main file parse. - This requires RemoveUnusedRel32Locations() to update rel32. - Deprecating C_TRIM_FAILED error message. - Moving more common functionality to Disassembler, but duplicating some code for win32-x86 and win32-x64 to follow existing pattern. BUG=613216 Review-Url: https://codereview.chromium.org/1935203002 Cr-Commit-Position: refs/heads/master@{#394815} --- courgette/adjustment_method_unittest.cc | 20 +++- courgette/assembly_program.cc | 122 +++++++----------------- courgette/assembly_program.h | 30 +++--- courgette/courgette.h | 1 - courgette/disassembler.cc | 31 ++++++ courgette/disassembler.h | 48 ++++++++++ courgette/disassembler_elf_32.cc | 98 ++++++++++++++----- courgette/disassembler_elf_32.h | 38 ++++++-- courgette/disassembler_elf_32_arm.cc | 7 +- courgette/disassembler_elf_32_arm.h | 2 +- courgette/disassembler_elf_32_x86.cc | 4 +- courgette/disassembler_elf_32_x86.h | 2 +- courgette/disassembler_win32_x64.cc | 35 ++++++- courgette/disassembler_win32_x64.h | 5 + courgette/disassembler_win32_x86.cc | 32 ++++++- courgette/disassembler_win32_x86.h | 5 + courgette/encoded_program.cc | 76 +++++++++------ courgette/encoded_program.h | 15 ++- courgette/encoded_program_unittest.cc | 69 +++++--------- courgette/image_utils.h | 8 +- courgette/label_manager.cc | 11 --- courgette/label_manager.h | 4 - courgette/program_detector.cc | 3 - courgette/rel32_finder_win32_x86.cc | 3 +- 24 files changed, 416 insertions(+), 253 deletions(-) diff --git a/courgette/adjustment_method_unittest.cc b/courgette/adjustment_method_unittest.cc index 3200f10c60994..d8b987c2d89e1 100644 --- a/courgette/adjustment_method_unittest.cc +++ b/courgette/adjustment_method_unittest.cc @@ -5,11 +5,13 @@ #include #include #include +#include #include "base/strings/string_util.h" #include "courgette/assembly_program.h" #include "courgette/courgette.h" #include "courgette/encoded_program.h" +#include "courgette/image_utils.h" #include "courgette/streams.h" #include "testing/gtest/include/gtest/gtest.h" @@ -32,8 +34,20 @@ class AdjustmentMethodTest : public testing::Test { new courgette::AssemblyProgram(courgette::EXE_WIN_32_X86)); prog->set_image_base(0x00400000); - courgette::Label* labelA = prog->FindOrMakeAbs32Label(0x00410000); - courgette::Label* labelB = prog->FindOrMakeAbs32Label(0x00410004); + courgette::RVA kRvaA = 0x00410000; + courgette::RVA kRvaB = 0x00410004; + + std::vector abs32_rvas; + abs32_rvas.push_back(kRvaA); + abs32_rvas.push_back(kRvaB); + std::vector rel32_rvas; // Stub. + + courgette::TrivialRvaVisitor abs32_visitor(abs32_rvas); + courgette::TrivialRvaVisitor rel32_visitor(rel32_rvas); + prog->PrecomputeLabels(&abs32_visitor, &rel32_visitor); + + courgette::Label* labelA = prog->FindAbs32Label(kRvaA); + courgette::Label* labelB = prog->FindAbs32Label(kRvaB); EXPECT_TRUE(prog->EmitAbs32(labelA)); EXPECT_TRUE(prog->EmitAbs32(labelA)); @@ -88,7 +102,6 @@ class AdjustmentMethodTest : public testing::Test { } }; - void AdjustmentMethodTest::Test1() const { std::unique_ptr prog1 = MakeProgramA(); std::unique_ptr prog2 = MakeProgramB(); @@ -109,7 +122,6 @@ void AdjustmentMethodTest::Test1() const { EXPECT_TRUE(s5 == s6); // Adjustment did change B into A } - TEST_F(AdjustmentMethodTest, All) { Test1(); } diff --git a/courgette/assembly_program.cc b/courgette/assembly_program.cc index 5344cff95f848..f20ed67ea3fa3 100644 --- a/courgette/assembly_program.cc +++ b/courgette/assembly_program.cc @@ -111,11 +111,6 @@ AssemblyProgram::AssemblyProgram(ExecutableType kind) : kind_(kind), image_base_(0) { } -static void DeleteContainedLabels(const RVAToLabel& labels) { - for (RVAToLabel::const_iterator p = labels.begin(); p != labels.end(); ++p) - UncheckedDelete(p->second); -} - AssemblyProgram::~AssemblyProgram() { for (size_t i = 0; i < instructions_.size(); ++i) { Instruction* instruction = instructions_[i]; @@ -126,8 +121,6 @@ AssemblyProgram::~AssemblyProgram() { for (size_t i = 0; i < 256; ++i) UncheckedDelete(byte_instruction_cache_[i]); } - DeleteContainedLabels(rel32_labels_); - DeleteContainedLabels(abs32_labels_); } CheckBool AssemblyProgram::EmitPeRelocsInstruction() { @@ -178,27 +171,50 @@ CheckBool AssemblyProgram::EmitAbs64(Label* label) { ScopedInstruction(UncheckedNew(ABS64, label))); } -Label* AssemblyProgram::FindOrMakeAbs32Label(RVA rva) { - return FindLabel(rva, &abs32_labels_); +void AssemblyProgram::PrecomputeLabels(RvaVisitor* abs32_visitor, + RvaVisitor* rel32_visitor) { + abs32_label_manager_.Read(abs32_visitor); + rel32_label_manager_.Read(rel32_visitor); + TrimLabels(); } -Label* AssemblyProgram::FindOrMakeRel32Label(RVA rva) { - return FindLabel(rva, &rel32_labels_); -} +// Chosen empirically to give the best reduction in payload size for +// an update from daisy_3701.98.0 to daisy_4206.0.0. +const int AssemblyProgram::kLabelLowerLimit = 5; -void AssemblyProgram::DefaultAssignIndexes() { - DefaultAssignIndexes(&abs32_labels_); - DefaultAssignIndexes(&rel32_labels_); +void AssemblyProgram::TrimLabels() { + // For now only trim for ARM binaries. + if (kind() != EXE_ELF_32_ARM) + return; + + int lower_limit = kLabelLowerLimit; + + VLOG(1) << "TrimLabels: threshold " << lower_limit; + + rel32_label_manager_.RemoveUnderusedLabels(lower_limit); } void AssemblyProgram::UnassignIndexes() { - UnassignIndexes(&abs32_labels_); - UnassignIndexes(&rel32_labels_); + abs32_label_manager_.UnassignIndexes(); + rel32_label_manager_.UnassignIndexes(); +} + +void AssemblyProgram::DefaultAssignIndexes() { + abs32_label_manager_.DefaultAssignIndexes(); + rel32_label_manager_.DefaultAssignIndexes(); } void AssemblyProgram::AssignRemainingIndexes() { - AssignRemainingIndexes(&abs32_labels_); - AssignRemainingIndexes(&rel32_labels_); + abs32_label_manager_.AssignRemainingIndexes(); + rel32_label_manager_.AssignRemainingIndexes(); +} + +Label* AssemblyProgram::FindAbs32Label(RVA rva) { + return abs32_label_manager_.Find(rva); +} + +Label* AssemblyProgram::FindRel32Label(RVA rva) { + return rel32_label_manager_.Find(rva); } Label* AssemblyProgram::InstructionAbs32Label( @@ -238,17 +254,6 @@ CheckBool AssemblyProgram::EmitShared(Instruction* instruction) { return instruction && instructions_.push_back(instruction); } -Label* AssemblyProgram::FindLabel(RVA rva, RVAToLabel* labels) { - Label*& slot = (*labels)[rva]; - if (slot == NULL) { - slot = UncheckedNew