Refactor InstructionBuilder into NewRegisterInstructions experiment

Reduces the amount of boiler plate code.

Bug: 77721545
Test: test-art-host

Change-Id: Ib5baf7768ba5f8e6aa6c8644b5aabbd35e834df5
diff --git a/tools/dexanalyze/dexanalyze_bytecode.cc b/tools/dexanalyze/dexanalyze_bytecode.cc
index 7e9f177..d18b0df 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.cc
+++ b/tools/dexanalyze/dexanalyze_bytecode.cc
@@ -67,13 +67,12 @@
     std::map<size_t, TypeLinkage> types;
     std::set<const void*> visited;
     for (ClassAccessor accessor : dex_file->GetClasses()) {
-      InstructionBuilder inst_builder(types,
-                                      /*count_types*/ true,
-                                      /*dump*/ false,
-                                      experiments_,
-                                      instruction_freq_);
       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
-        inst_builder.Process(*dex_file, method.GetInstructionsAndData(), accessor.GetClassIdx());
+        ProcessCodeItem(*dex_file,
+                        method.GetInstructionsAndData(),
+                        accessor.GetClassIdx(),
+                        /*count_types*/ true,
+                        types);
       }
     }
     // Reorder to get an index for each map instead of a count.
@@ -85,11 +84,6 @@
     }
     // Visit classes and convert code items.
     for (ClassAccessor accessor : dex_file->GetClasses()) {
-      InstructionBuilder inst_builder(types,
-                                      /*count_types*/ false,
-                                      dump_,
-                                      experiments_,
-                                      instruction_freq_);
       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
         if (method.GetCodeItem() == nullptr || !visited.insert(method.GetCodeItem()).second) {
           continue;
@@ -99,8 +93,13 @@
                     << "Processing " << dex_file->PrettyMethod(method.GetIndex(), true);
         }
         CodeItemDataAccessor data = method.GetInstructionsAndData();
-        inst_builder.Process(*dex_file, data, accessor.GetClassIdx());
-        std::vector<uint8_t> buffer = std::move(inst_builder.buffer_);
+        ProcessCodeItem(*dex_file,
+                        data,
+                        accessor.GetClassIdx(),
+                        /*count_types*/ false,
+                        types);
+        std::vector<uint8_t> buffer = std::move(buffer_);
+        buffer_.clear();
         const size_t buffer_size = buffer.size();
         dex_code_bytes_ += data.InsnsSizeInBytes();
         output_size_ += buffer_size;
@@ -114,8 +113,6 @@
           deduped_size_ += buffer_size;
         }
       }
-      missing_field_idx_count_ += inst_builder.missing_field_idx_count_;
-      missing_method_idx_count_ += inst_builder.missing_method_idx_count_;
     }
   }
 }
@@ -153,25 +150,16 @@
      << Percent(top_instructions_savings, total_size) << "\n";
 }
 
-InstructionBuilder::InstructionBuilder(std::map<size_t, TypeLinkage>& types,
-                                       bool count_types,
-                                       bool dump,
-                                       uint64_t experiments,
-                                       std::map<std::vector<uint8_t>, size_t>& instruction_freq)
-    : types_(types),
-      count_types_(count_types),
-      dump_(dump),
-      experiments_(experiments),
-      instruction_freq_(instruction_freq) {}
-
-void InstructionBuilder::Process(const DexFile& dex_file,
-                                 const CodeItemDataAccessor& code_item,
-                                 dex::TypeIndex current_class_type) {
-  TypeLinkage& current_type = types_[current_class_type.index_];
+void NewRegisterInstructions::ProcessCodeItem(const DexFile& dex_file,
+                                              const CodeItemDataAccessor& code_item,
+                                              dex::TypeIndex current_class_type,
+                                              bool count_types,
+                                              std::map<size_t, TypeLinkage>& types) {
+  TypeLinkage& current_type = types[current_class_type.index_];
   bool skip_next = false;
   size_t last_start = 0u;
   for (auto inst = code_item.begin(); ; ++inst) {
-    if (!count_types_ && last_start != buffer_.size()) {
+    if (!count_types && last_start != buffer_.size()) {
       // Register the instruction blob.
       ++instruction_freq_[std::vector<uint8_t>(buffer_.begin() + last_start, buffer_.end())];
       last_start = buffer_.size();
@@ -223,21 +211,21 @@
         if (Enabled(kExperimentInstanceFieldSelf) &&
             first_arg_reg == receiver &&
             holder_type == current_class_type) {
-          if (count_types_) {
+          if (count_types) {
             ++current_type.fields_.FindOrAdd(dex_field_idx)->second;
           } else {
-            uint32_t field_idx = types_[holder_type.index_].fields_.Get(dex_field_idx);
+            uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
             ExtendPrefix(&out_reg, &field_idx);
             CHECK(InstNibbles(new_opcode, {out_reg, field_idx}));
             continue;
           }
         } else if (Enabled(kExperimentInstanceField)) {
-          if (count_types_) {
+          if (count_types) {
             ++current_type.types_.FindOrAdd(holder_type.index_)->second;
-            ++types_[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
+            ++types[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
           } else {
             uint32_t type_idx = current_type.types_.Get(holder_type.index_);
-            uint32_t field_idx = types_[holder_type.index_].fields_.Get(dex_field_idx);
+            uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
             ExtendPrefix(&type_idx, &field_idx);
             CHECK(InstNibbles(new_opcode, {out_reg, receiver, type_idx, field_idx}));
             continue;
@@ -252,7 +240,7 @@
         uint32_t out_reg = is_jumbo ? inst->VRegA_31c() : inst->VRegA_21c();
         if (Enabled(kExperimentString)) {
           new_opcode = Instruction::CONST_STRING;
-          if (count_types_) {
+          if (count_types) {
             ++current_type.strings_.FindOrAdd(str_idx)->second;
           } else {
             uint32_t idx = current_type.strings_.Get(str_idx);
@@ -283,22 +271,22 @@
         dex::TypeIndex holder_type = dex_file.GetFieldId(dex_field_idx).class_idx_;
         if (Enabled(kExperimentStaticField)) {
           if (holder_type == current_class_type) {
-            if (count_types_) {
-              ++types_[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
+            if (count_types) {
+              ++types[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
             } else {
-              uint32_t field_idx = types_[holder_type.index_].fields_.Get(dex_field_idx);
+              uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
               ExtendPrefix(&out_reg, &field_idx);
               if (InstNibbles(new_opcode, {out_reg, field_idx})) {
                 continue;
               }
             }
           } else {
-            if (count_types_) {
-              ++types_[current_class_type.index_].types_.FindOrAdd(holder_type.index_)->second;
-              ++types_[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
+            if (count_types) {
+              ++types[current_class_type.index_].types_.FindOrAdd(holder_type.index_)->second;
+              ++types[holder_type.index_].fields_.FindOrAdd(dex_field_idx)->second;
             } else {
               uint32_t type_idx = current_type.types_.Get(holder_type.index_);
-              uint32_t field_idx = types_[holder_type.index_].fields_.Get(dex_field_idx);
+              uint32_t field_idx = types[holder_type.index_].fields_.Get(dex_field_idx);
               ExtendPrefix(&type_idx, &field_idx);
               if (InstNibbles(new_opcode, {out_reg >> 4, out_reg & 0xF, type_idx, field_idx})) {
                 continue;
@@ -318,9 +306,9 @@
         const DexFile::MethodId& method = dex_file.GetMethodId(method_idx);
         const dex::TypeIndex receiver_type = method.class_idx_;
         if (Enabled(kExperimentInvoke)) {
-          if (count_types_) {
+          if (count_types) {
             ++current_type.types_.FindOrAdd(receiver_type.index_)->second;
-            ++types_[receiver_type.index_].methods_.FindOrAdd(method_idx)->second;
+            ++types[receiver_type.index_].methods_.FindOrAdd(method_idx)->second;
           } else {
             uint32_t args[6] = {};
             uint32_t arg_count = inst->GetVarArgs(args);
@@ -340,7 +328,7 @@
 
             bool result = false;
             uint32_t type_idx = current_type.types_.Get(receiver_type.index_);
-            uint32_t local_idx = types_[receiver_type.index_].methods_.Get(method_idx);
+            uint32_t local_idx = types[receiver_type.index_].methods_.Get(method_idx);
             ExtendPrefix(&type_idx, &local_idx);
             ExtendPrefix(&dest_reg, &local_idx);
             if (arg_count == 0) {
@@ -373,7 +361,7 @@
       case Instruction::IF_NEZ: {
         uint32_t reg = inst->VRegA_21t();
         int16_t offset = inst->VRegB_21t();
-        if (!count_types_ &&
+        if (!count_types &&
             Enabled(kExperimentSmallIf) &&
             InstNibbles(opcode, {reg, static_cast<uint16_t>(offset)})) {
           continue;
@@ -384,7 +372,7 @@
         uint32_t type_idx = inst->VRegC_22c();
         uint32_t in_reg = inst->VRegB_22c();
         uint32_t out_reg = inst->VRegA_22c();
-        if (count_types_) {
+        if (count_types) {
           ++current_type.types_.FindOrAdd(type_idx)->second;
         } else {
           uint32_t local_type = current_type.types_.Get(type_idx);
@@ -398,7 +386,7 @@
         uint32_t len_reg = inst->VRegB_22c();
         uint32_t type_idx = inst->VRegC_22c();
         uint32_t out_reg = inst->VRegA_22c();
-        if (count_types_) {
+        if (count_types) {
           ++current_type.types_.FindOrAdd(type_idx)->second;
         } else {
           uint32_t local_type = current_type.types_.Get(type_idx);
@@ -414,7 +402,7 @@
         uint32_t type_idx = inst->VRegB_21c();
         uint32_t out_reg = inst->VRegA_21c();
         if (Enabled(kExperimentLocalType)) {
-          if (count_types_) {
+          if (count_types) {
             ++current_type.types_.FindOrAdd(type_idx)->second;
           } else {
             bool next_is_init = false;
@@ -445,7 +433,7 @@
       case Instruction::RETURN_OBJECT:
       case Instruction::RETURN_WIDE:
       case Instruction::RETURN_VOID: {
-        if (!count_types_ && Enabled(kExperimentReturn)) {
+        if (!count_types && Enabled(kExperimentReturn)) {
           if (opcode == Instruction::RETURN_VOID || inst->VRegA_11x() == 0) {
             if (InstNibbles(opcode, {})) {
               continue;
@@ -457,7 +445,7 @@
       default:
         break;
     }
-    if (!count_types_) {
+    if (!count_types) {
       Add(new_opcode, inst.Inst());
     }
   }
@@ -468,13 +456,13 @@
   }
 }
 
-void InstructionBuilder::Add(Instruction::Code opcode, const Instruction& inst) {
+void NewRegisterInstructions::Add(Instruction::Code opcode, const Instruction& inst) {
   const uint8_t* start = reinterpret_cast<const uint8_t*>(&inst);
   buffer_.push_back(opcode);
   buffer_.insert(buffer_.end(), start + 1, start + 2 * inst.SizeInCodeUnits());
 }
 
-void InstructionBuilder::ExtendPrefix(uint32_t* value1, uint32_t* value2) {
+void NewRegisterInstructions::ExtendPrefix(uint32_t* value1, uint32_t* value2) {
   if (*value1 < 16 && *value2 < 16) {
     return;
   }
@@ -504,7 +492,7 @@
   *value2 &= 0XF;
 }
 
-bool InstructionBuilder::InstNibblesAndIndex(uint8_t opcode,
+bool NewRegisterInstructions::InstNibblesAndIndex(uint8_t opcode,
                                              uint16_t idx,
                                              const std::vector<uint32_t>& args) {
   if (!InstNibbles(opcode, args)) {
@@ -515,7 +503,7 @@
   return true;
 }
 
-bool InstructionBuilder::InstNibbles(uint8_t opcode, const std::vector<uint32_t>& args) {
+bool NewRegisterInstructions::InstNibbles(uint8_t opcode, const std::vector<uint32_t>& args) {
   if (dump_) {
     std::cout << " ==> " << Instruction::Name(static_cast<Instruction::Code>(opcode)) << " ";
     for (int v : args) {
diff --git a/tools/dexanalyze/dexanalyze_bytecode.h b/tools/dexanalyze/dexanalyze_bytecode.h
index e7c5e7b..9ea819b 100644
--- a/tools/dexanalyze/dexanalyze_bytecode.h
+++ b/tools/dexanalyze/dexanalyze_bytecode.h
@@ -51,16 +51,17 @@
   SafeMap<size_t, size_t> strings_;
 };
 
-class InstructionBuilder {
+class NewRegisterInstructions : public Experiment {
  public:
-  InstructionBuilder(std::map<size_t, TypeLinkage>& types,
-                     bool count_types,
-                     bool dump,
-                     uint64_t experiments,
-                     std::map<std::vector<uint8_t>, size_t>& instruction_freq);
-  void Process(const DexFile& dex_file,
-               const CodeItemDataAccessor& code_item,
-               dex::TypeIndex current_class_type);
+  explicit NewRegisterInstructions(uint64_t experiments) : experiments_(experiments) {}
+  void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
+  void Dump(std::ostream& os, uint64_t total_size) const;
+
+  void ProcessCodeItem(const DexFile& dex_file,
+                       const CodeItemDataAccessor& code_item,
+                       dex::TypeIndex current_class_type,
+                       bool count_types,
+                       std::map<size_t, TypeLinkage>& types);
   void Add(Instruction::Code opcode, const Instruction& inst);
   bool InstNibblesAndIndex(uint8_t opcode, uint16_t idx, const std::vector<uint32_t>& args);
   bool InstNibbles(uint8_t opcode, const std::vector<uint32_t>& args);
@@ -69,25 +70,8 @@
     return experiments_ & (1u << static_cast<uint64_t>(experiment));
   }
 
-  size_t alignment_ = 1u;
-  std::vector<uint8_t> buffer_;
-  // Global index -> local index maps.
-  std::map<size_t, TypeLinkage>& types_;
-  uint64_t missing_field_idx_count_ = 0u;
-  uint64_t missing_method_idx_count_ = 0u;
-  const bool count_types_;
-  const bool dump_;
-  uint64_t experiments_ = std::numeric_limits<uint64_t>::max();
-  std::map<std::vector<uint8_t>, size_t>& instruction_freq_;
-};
-
-class NewRegisterInstructions : public Experiment {
- public:
-  explicit NewRegisterInstructions(uint64_t experiments) : experiments_(experiments) {}
-  void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
-  void Dump(std::ostream& os, uint64_t total_size) const;
-
  private:
+  size_t alignment_ = 1u;
   uint64_t output_size_ = 0u;
   uint64_t deduped_size_ = 0u;
   uint64_t dex_code_bytes_ = 0u;
@@ -95,6 +79,8 @@
   uint64_t missing_method_idx_count_ = 0u;
   uint64_t experiments_ = std::numeric_limits<uint64_t>::max();
   std::map<std::vector<uint8_t>, size_t> instruction_freq_;
+  // Output instruction buffer.
+  std::vector<uint8_t> buffer_;
 };
 
 }  // namespace dexanalyze