Clean up OatQuickMethodHeader after Quick removal.

This reduces the size of the pre-header by 8 bytes, reducing
oat file size and mmapped .text section size. The memory
needed to store a CompiledMethod by dex2oat is also reduced,
for 32-bit dex2oat by 8B and for 64-bit dex2oat by 16B. The
aosp_flounder-userdebug 32-bit and 64-bit boot.oat are each
about 1.1MiB smaller.

Disable the broken StubTest.IMT, b/27991555 .

Change-Id: I05fe45c28c8ffb7a0fa8b1117b969786748b1039
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 3a67b1e..cf1c114 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -275,9 +275,7 @@
     size_code_alignment_(0),
     size_relative_call_thunks_(0),
     size_misc_thunks_(0),
-    size_mapping_table_(0),
     size_vmap_table_(0),
-    size_gc_map_(0),
     size_oat_dex_file_location_size_(0),
     size_oat_dex_file_location_data_(0),
     size_oat_dex_file_location_checksum_(0),
@@ -498,72 +496,6 @@
 OatWriter::~OatWriter() {
 }
 
-struct OatWriter::GcMapDataAccess {
-  static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
-    return compiled_method->GetGcMap();
-  }
-
-  static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    uint32_t offset = oat_class->method_headers_[method_offsets_index].gc_map_offset_;
-    return offset == 0u ? 0u :
-        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
-  }
-
-  static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
-      ALWAYS_INLINE {
-    oat_class->method_headers_[method_offsets_index].gc_map_offset_ =
-        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
-  }
-
-  static const char* Name() {
-    return "GC map";
-  }
-};
-
-struct OatWriter::MappingTableDataAccess {
-  static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
-    return compiled_method->GetMappingTable();
-  }
-
-  static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_;
-    return offset == 0u ? 0u :
-        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
-  }
-
-  static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
-      ALWAYS_INLINE {
-    oat_class->method_headers_[method_offsets_index].mapping_table_offset_ =
-        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
-  }
-
-  static const char* Name() {
-    return "mapping table";
-  }
-};
-
-struct OatWriter::VmapTableDataAccess {
-  static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
-    return compiled_method->GetVmapTable();
-  }
-
-  static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_;
-    return offset == 0u ? 0u :
-        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
-  }
-
-  static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
-      ALWAYS_INLINE {
-    oat_class->method_headers_[method_offsets_index].vmap_table_offset_ =
-        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
-  }
-
-  static const char* Name() {
-    return "vmap table";
-  }
-};
-
 class OatWriter::DexMethodVisitor {
  public:
   DexMethodVisitor(OatWriter* writer, size_t offset)
@@ -726,26 +658,24 @@
       uint32_t thumb_offset = compiled_method->CodeDelta();
 
       // Deduplicate code arrays if we are not producing debuggable code.
-      bool deduped = false;
+      bool deduped = true;
       MethodReference method_ref(dex_file_, it.GetMemberIndex());
       if (debuggable_) {
         quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
         if (quick_code_offset != 0u) {
           // Duplicate methods, we want the same code for both of them so that the oat writer puts
           // the same code in both ArtMethods so that we do not get different oat code at runtime.
-          deduped = true;
         } else {
           quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
+          deduped = false;
         }
       } else {
-        auto lb = dedupe_map_.lower_bound(compiled_method);
-        if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(compiled_method, lb->first)) {
-          quick_code_offset = lb->second;
-          deduped = true;
-        } else {
-          quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
-          dedupe_map_.PutBefore(lb, compiled_method, quick_code_offset);
-        }
+        quick_code_offset = dedupe_map_.GetOrCreate(
+            compiled_method,
+            [this, &deduped, compiled_method, &it, thumb_offset]() {
+              deduped = false;
+              return NewQuickCodeOffset(compiled_method, it, thumb_offset);
+            });
       }
 
       if (code_size != 0) {
@@ -763,33 +693,25 @@
       // Update quick method header.
       DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
       OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
-      uint32_t mapping_table_offset = method_header->mapping_table_offset_;
       uint32_t vmap_table_offset = method_header->vmap_table_offset_;
       // If we don't have quick code, then we must have a vmap, as that is how the dex2dex
       // compiler records its transformations.
       DCHECK(!quick_code.empty() || vmap_table_offset != 0);
-      uint32_t gc_map_offset = method_header->gc_map_offset_;
       // The code offset was 0 when the mapping/vmap table offset was set, so it's set
       // to 0-offset and we need to adjust it by code_offset.
       uint32_t code_offset = quick_code_offset - thumb_offset;
-      if (mapping_table_offset != 0u && code_offset != 0u) {
-        mapping_table_offset += code_offset;
-        DCHECK_LT(mapping_table_offset, code_offset) << "Overflow in oat offsets";
-      }
       if (vmap_table_offset != 0u && code_offset != 0u) {
         vmap_table_offset += code_offset;
         DCHECK_LT(vmap_table_offset, code_offset) << "Overflow in oat offsets";
       }
-      if (gc_map_offset != 0u && code_offset != 0u) {
-        gc_map_offset += code_offset;
-        DCHECK_LT(gc_map_offset, code_offset) << "Overflow in oat offsets";
-      }
       uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
       uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
       uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
-      *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
-                                            gc_map_offset, frame_size_in_bytes, core_spill_mask,
-                                            fp_spill_mask, code_size);
+      *method_header = OatQuickMethodHeader(vmap_table_offset,
+                                            frame_size_in_bytes,
+                                            core_spill_mask,
+                                            fp_spill_mask,
+                                            code_size);
 
       if (!deduped) {
         // Update offsets. (Checksum is updated when writing.)
@@ -844,15 +766,6 @@
         } else {
           status = mirror::Class::kStatusNotReady;
         }
-        ArrayRef<const uint8_t> gc_map = compiled_method->GetGcMap();
-        if (!gc_map.empty()) {
-          size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
-          bool is_native = it.MemberIsNative();
-          CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
-              << gc_map_size << " " << (is_native ? "true" : "false") << " "
-              << (status < mirror::Class::kStatusVerified) << " " << status << " "
-              << PrettyMethod(it.GetMemberIndex(), *dex_file_);
-        }
       }
 
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
@@ -872,15 +785,9 @@
         return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
       }
       // If the code is the same, all other fields are likely to be the same as well.
-      if (UNLIKELY(lhs->GetMappingTable().data() != rhs->GetMappingTable().data())) {
-        return lhs->GetMappingTable().data() < rhs->GetMappingTable().data();
-      }
       if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
         return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
       }
-      if (UNLIKELY(lhs->GetGcMap().data() != rhs->GetGcMap().data())) {
-        return lhs->GetGcMap().data() < rhs->GetGcMap().data();
-      }
       if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
         return lhs->GetPatches().data() < rhs->GetPatches().data();
       }
@@ -907,7 +814,6 @@
   const bool debuggable_;
 };
 
-template <typename DataAccess>
 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
  public:
   InitMapMethodVisitor(OatWriter* writer, size_t offset)
@@ -921,19 +827,21 @@
 
     if (compiled_method != nullptr) {
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
-      DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u);
+      DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].vmap_table_offset_, 0u);
 
-      ArrayRef<const uint8_t> map = DataAccess::GetData(compiled_method);
+      ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
       uint32_t map_size = map.size() * sizeof(map[0]);
       if (map_size != 0u) {
-        auto lb = dedupe_map_.lower_bound(map.data());
-        if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map.data(), lb->first)) {
-          DataAccess::SetOffset(oat_class, method_offsets_index_, lb->second);
-        } else {
-          DataAccess::SetOffset(oat_class, method_offsets_index_, offset_);
-          dedupe_map_.PutBefore(lb, map.data(), offset_);
-          offset_ += map_size;
-        }
+        size_t offset = dedupe_map_.GetOrCreate(
+            map.data(),
+            [this, map_size]() {
+              uint32_t new_offset = offset_;
+              offset_ += map_size;
+              return new_offset;
+            });
+        // Code offset is not initialized yet, so set the map offset to 0u-offset.
+        DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
+        oat_class->method_headers_[method_offsets_index_].vmap_table_offset_ = 0u - offset;
       }
       ++method_offsets_index_;
     }
@@ -1342,10 +1250,11 @@
   }
 };
 
-template <typename DataAccess>
 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
  public:
-  WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
+  WriteMapMethodVisitor(OatWriter* writer,
+                        OutputStream* out,
+                        const size_t file_offset,
                         size_t relative_offset)
     : OatDexMethodVisitor(writer, relative_offset),
       out_(out),
@@ -1360,22 +1269,31 @@
       size_t file_offset = file_offset_;
       OutputStream* out = out_;
 
-      uint32_t map_offset = DataAccess::GetOffset(oat_class, method_offsets_index_);
+      uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].vmap_table_offset_;
+      uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
       ++method_offsets_index_;
 
-      // Write deduplicated map.
-      ArrayRef<const uint8_t> map = DataAccess::GetData(compiled_method);
-      size_t map_size = map.size() * sizeof(map[0]);
-      DCHECK((map_size == 0u && map_offset == 0u) ||
-            (map_size != 0u && map_offset != 0u && map_offset <= offset_))
-          << map_size << " " << map_offset << " " << offset_ << " "
-          << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name();
-      if (map_size != 0u && map_offset == offset_) {
-        if (UNLIKELY(!writer_->WriteData(out, map.data(), map_size))) {
-          ReportWriteFailure(it);
-          return false;
+      DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
+             (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
+          << compiled_method->GetVmapTable().size() << " " << map_offset << " "
+          << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+
+      if (map_offset != 0u) {
+        // Transform map_offset to actual oat data offset.
+        map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
+        DCHECK_NE(map_offset, 0u);
+        DCHECK_LE(map_offset, offset_) << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+
+        ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
+        size_t map_size = map.size() * sizeof(map[0]);
+        if (map_offset == offset_) {
+          // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
+          if (UNLIKELY(!writer_->WriteData(out, map.data(), map_size))) {
+            ReportWriteFailure(it);
+            return false;
+          }
+          offset_ += map_size;
         }
-        offset_ += map_size;
       }
       DCHECK_OFFSET_();
     }
@@ -1388,7 +1306,7 @@
   size_t const file_offset_;
 
   void ReportWriteFailure(const ClassDataItemIterator& it) {
-    PLOG(ERROR) << "Failed to write " << DataAccess::Name() << " for "
+    PLOG(ERROR) << "Failed to write map for "
         << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation();
   }
 };
@@ -1481,19 +1399,10 @@
 }
 
 size_t OatWriter::InitOatMaps(size_t offset) {
-  #define VISIT(VisitorType)                          \
-    do {                                              \
-      VisitorType visitor(this, offset);              \
-      bool success = VisitDexMethods(&visitor);       \
-      DCHECK(success);                                \
-      offset = visitor.GetOffset();                   \
-    } while (false)
-
-  VISIT(InitMapMethodVisitor<GcMapDataAccess>);
-  VISIT(InitMapMethodVisitor<MappingTableDataAccess>);
-  VISIT(InitMapMethodVisitor<VmapTableDataAccess>);
-
-  #undef VISIT
+  InitMapMethodVisitor visitor(this, offset);
+  bool success = VisitDexMethods(&visitor);
+  DCHECK(success);
+  offset = visitor.GetOffset();
 
   return offset;
 }
@@ -1647,9 +1556,7 @@
     DO_STAT(size_code_alignment_);
     DO_STAT(size_relative_call_thunks_);
     DO_STAT(size_misc_thunks_);
-    DO_STAT(size_mapping_table_);
     DO_STAT(size_vmap_table_);
-    DO_STAT(size_gc_map_);
     DO_STAT(size_oat_dex_file_location_size_);
     DO_STAT(size_oat_dex_file_location_data_);
     DO_STAT(size_oat_dex_file_location_checksum_);
@@ -1764,29 +1671,14 @@
 }
 
 size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) {
-  #define VISIT(VisitorType)                                              \
-    do {                                                                  \
-      VisitorType visitor(this, out, file_offset, relative_offset);       \
-      if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \
-        return 0;                                                         \
-      }                                                                   \
-      relative_offset = visitor.GetOffset();                              \
-    } while (false)
-
-  size_t gc_maps_offset = relative_offset;
-  VISIT(WriteMapMethodVisitor<GcMapDataAccess>);
-  size_gc_map_ = relative_offset - gc_maps_offset;
-
-  size_t mapping_tables_offset = relative_offset;
-  VISIT(WriteMapMethodVisitor<MappingTableDataAccess>);
-  size_mapping_table_ = relative_offset - mapping_tables_offset;
-
   size_t vmap_tables_offset = relative_offset;
-  VISIT(WriteMapMethodVisitor<VmapTableDataAccess>);
+  WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
+  if (UNLIKELY(!VisitDexMethods(&visitor))) {
+    return 0;
+  }
+  relative_offset = visitor.GetOffset();
   size_vmap_table_ = relative_offset - vmap_tables_offset;
 
-  #undef VISIT
-
   return relative_offset;
 }