Move code size from OatQuickMethodHeader to CodeInfo.

This saves 0.5% of oat file size.
(0.8% saving from this CL minus 0.3% due to go/aog/1614482)

Bug: 123510633
Test: m dump-oat
Test: m test-art-host-gtest
Test: ./art/test.py -b -r --host
Change-Id: I035b54a47b300a5808aa8c2992f87eae009fd245
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 1aaeac0..9170a85 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -57,7 +57,7 @@
     CHECK_NE(code_size, 0u);
     const uint32_t vmap_table_offset = vmap_table.empty() ? 0u
         : sizeof(OatQuickMethodHeader) + vmap_table.size();
-    OatQuickMethodHeader method_header(vmap_table_offset, code_size);
+    OatQuickMethodHeader method_header(vmap_table_offset);
     const size_t code_alignment = GetInstructionSetAlignment(instruction_set);
     DCHECK_ALIGNED_PARAM(kPageSize, code_alignment);
     code_offset_ = RoundUp(vmap_table.size() + sizeof(method_header), code_alignment);
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index 6a01452..495398b 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -94,7 +94,7 @@
       AlignUp(&fake_header_code_and_maps_[stack_maps_size + header_size], code_alignment);
 
     memcpy(&fake_header_code_and_maps_[0], stack_map.data(), stack_maps_size);
-    OatQuickMethodHeader method_header(code_ptr - fake_header_code_and_maps_.data(), code_size);
+    OatQuickMethodHeader method_header(code_ptr - fake_header_code_and_maps_.data());
     static_assert(std::is_trivially_copyable<OatQuickMethodHeader>::value, "Cannot use memcpy");
     memcpy(code_ptr - header_size, &method_header, header_size);
     memcpy(code_ptr, fake_code_.data(), fake_code_.size());
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 99c607b..d6eff94 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -1375,18 +1375,16 @@
     // 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 vmap_table_offset = method_header->GetVmapTableOffset();
-    // 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_info_offset = method_header->GetCodeInfoOffset();
     uint32_t code_offset = quick_code_offset - thumb_offset;
     CHECK(!compiled_method->GetQuickCode().empty());
     // If the code is compiled, we write the offset of the stack map relative
-    // to the code.
-    if (vmap_table_offset != 0u) {
-      vmap_table_offset += code_offset;
-      DCHECK_LT(vmap_table_offset, code_offset);
+    // to the code. The offset was previously stored relative to start of file.
+    if (code_info_offset != 0u) {
+      DCHECK_LT(code_info_offset, code_offset);
+      code_info_offset = code_offset - code_info_offset;
     }
-    *method_header = OatQuickMethodHeader(vmap_table_offset, code_size);
+    *method_header = OatQuickMethodHeader(code_info_offset);
 
     if (!deduped) {
       // Update offsets. (Checksum is updated when writing.)
@@ -1511,7 +1509,7 @@
 
     if (HasCompiledCode(compiled_method)) {
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
-      DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
+      DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetCodeInfoOffset(), 0u);
 
       ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
       if (map.size() != 0u) {
@@ -1519,9 +1517,9 @@
           // Deduplicate the inner BitTable<>s within the CodeInfo.
           return offset_ + dedupe_bit_table_.Dedupe(map.data());
         });
-        // Code offset is not initialized yet, so set the map offset to 0u-offset.
+        // Code offset is not initialized yet, so set file offset for now.
         DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
-        oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
+        oat_class->method_headers_[method_offsets_index_].SetCodeInfoOffset(offset);
       }
       ++method_offsets_index_;
     }
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 614cfc4..92fc2e4 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -511,7 +511,7 @@
   // it is time to update OatHeader::kOatVersion
   EXPECT_EQ(64U, sizeof(OatHeader));
   EXPECT_EQ(4U, sizeof(OatMethodOffsets));
-  EXPECT_EQ(8U, sizeof(OatQuickMethodHeader));
+  EXPECT_EQ(4U, sizeof(OatQuickMethodHeader));
   EXPECT_EQ(169 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
             sizeof(QuickEntryPoints));
 }
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 6660bb8..12c4d15 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1188,9 +1188,10 @@
         vios->Stream() << StringPrintf("%p ", method_header);
       }
       vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
-      if (method_header_offset > oat_file_.Size()) {
+      if (method_header_offset > oat_file_.Size() ||
+          sizeof(OatQuickMethodHeader) > oat_file_.Size() - method_header_offset) {
         vios->Stream() << StringPrintf(
-            "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
+            "WARNING: oat quick method header at offset 0x%08x is past end of file 0x%08zx.\n",
             method_header_offset, oat_file_.Size());
         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
         vios->Stream() << std::flush;
@@ -1202,8 +1203,8 @@
       if (options_.absolute_addresses_) {
         vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
       }
-      uint32_t vmap_table_offset = method_header ==
-          nullptr ? 0 : method_header->GetVmapTableOffset();
+      uint32_t vmap_table_offset =
+          (method_header == nullptr) ? 0 : method_header->GetCodeInfoOffset();
       vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
 
       size_t vmap_table_offset_limit =
@@ -1212,11 +1213,9 @@
               : method_header->GetCode() - oat_file_.Begin();
       if (vmap_table_offset >= vmap_table_offset_limit) {
         vios->Stream() << StringPrintf("WARNING: "
-                                       "vmap table offset 0x%08x is past end of file 0x%08zx. "
-                                       "vmap table offset was loaded from offset 0x%08x.\n",
+                                       "vmap table offset 0x%08x is past end of file 0x%08zx. ",
                                        vmap_table_offset,
-                                       vmap_table_offset_limit,
-                                       oat_method.GetVmapTableOffsetOffset());
+                                       vmap_table_offset_limit);
         success = false;
       } else if (options_.dump_vmap_) {
         DumpVmapData(vios, oat_method, code_item_accessor);
@@ -1244,14 +1243,7 @@
     }
     {
       vios->Stream() << "CODE: ";
-      uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
-      if (code_size_offset > oat_file_.Size()) {
-        ScopedIndentation indent2(vios);
-        vios->Stream() << StringPrintf("WARNING: "
-                                       "code size offset 0x%08x is past end of file 0x%08zx.",
-                                       code_size_offset, oat_file_.Size());
-        success = false;
-      } else {
+      {
         const void* code = oat_method.GetQuickCode();
         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
         uint64_t aligned_code_end = aligned_code_begin + code_size;
@@ -1262,9 +1254,8 @@
         if (options_.absolute_addresses_) {
           vios->Stream() << StringPrintf("%p ", code);
         }
-        vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
+        vios->Stream() << StringPrintf("(code_offset=0x%08x size=%u)%s\n",
                                        code_offset,
-                                       code_size_offset,
                                        code_size,
                                        code != nullptr ? "..." : "");
 
@@ -1278,12 +1269,13 @@
           vios->Stream() << StringPrintf(
               "WARNING: "
               "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
-              "code size is 0x%08x loaded from offset 0x%08x.\n",
-              aligned_code_end, oat_file_.Size(),
-              code_size, code_size_offset);
+              "code size is 0x%08x.\n",
+              aligned_code_end,
+              oat_file_.Size(),
+              code_size);
           success = false;
           if (options_.disassemble_code_) {
-            if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
+            if (aligned_code_begin + kPrologueBytes <= oat_file_.Size()) {
               DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
             }
           }
@@ -1291,12 +1283,13 @@
           vios->Stream() << StringPrintf(
               "WARNING: "
               "code size %d is bigger than max expected threshold of %d. "
-              "code size is 0x%08x loaded from offset 0x%08x.\n",
-              code_size, kMaxCodeSize,
-              code_size, code_size_offset);
+              "code size is 0x%08x.\n",
+              code_size,
+              kMaxCodeSize,
+              code_size);
           success = false;
           if (options_.disassemble_code_) {
-            if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
+            if (aligned_code_begin + kPrologueBytes <= oat_file_.Size()) {
               DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
             }
           }
diff --git a/runtime/interpreter/mterp/arm64ng/main.S b/runtime/interpreter/mterp/arm64ng/main.S
index a977a90..f9c41c7 100644
--- a/runtime/interpreter/mterp/arm64ng/main.S
+++ b/runtime/interpreter/mterp/arm64ng/main.S
@@ -249,11 +249,11 @@
     .hidden \name
     .global \name
     .balign 16
-    // Padding of 8 bytes to get 16 bytes alignment of code entry.
+    // Padding of 3 * 8 bytes to get 16 bytes alignment of code entry.
     .long 0
     .long 0
-    // OatQuickMethodHeader.
     .long 0
+    // OatQuickMethodHeader. Note that the top two bits must be clear.
     .long (\end - \name)
 \name:
 .endm
diff --git a/runtime/interpreter/mterp/armng/main.S b/runtime/interpreter/mterp/armng/main.S
index d2ca06f..2f8fbd1 100644
--- a/runtime/interpreter/mterp/armng/main.S
+++ b/runtime/interpreter/mterp/armng/main.S
@@ -248,11 +248,11 @@
     .hidden \name
     .global \name
     .balign 16
-    // Padding of 8 bytes to get 16 bytes alignment of code entry.
+    // Padding of 3 * 8 bytes to get 16 bytes alignment of code entry.
     .long 0
     .long 0
-    // OatQuickMethodHeader.
     .long 0
+    // OatQuickMethodHeader. Note that the top two bits must be clear.
     .long (\end - \name)
 \name:
 .endm
diff --git a/runtime/interpreter/mterp/x86_64ng/main.S b/runtime/interpreter/mterp/x86_64ng/main.S
index 02f0c5a..b7a95fa 100644
--- a/runtime/interpreter/mterp/x86_64ng/main.S
+++ b/runtime/interpreter/mterp/x86_64ng/main.S
@@ -208,7 +208,11 @@
     ASM_HIDDEN SYMBOL(\name)
     .global SYMBOL(\name)
     .balign 16
+    // Padding of 3 * 8 bytes to get 16 bytes alignment of code entry.
     .long 0
+    .long 0
+    .long 0
+    // OatQuickMethodHeader. Note that the top two bits must be clear.
     .long (SYMBOL(\end) - SYMBOL(\name))
 SYMBOL(\name):
 .endm
diff --git a/runtime/jit/jit_memory_region.cc b/runtime/jit/jit_memory_region.cc
index 022548d..58a4041 100644
--- a/runtime/jit/jit_memory_region.cc
+++ b/runtime/jit/jit_memory_region.cc
@@ -377,9 +377,7 @@
   // Write the header.
   OatQuickMethodHeader* method_header =
       OatQuickMethodHeader::FromCodePointer(w_memory + header_size);
-  new (method_header) OatQuickMethodHeader(
-      (stack_map != nullptr) ? result - stack_map : 0u,
-      code.size());
+  new (method_header) OatQuickMethodHeader((stack_map != nullptr) ? result - stack_map : 0u);
   if (has_should_deoptimize_flag) {
     method_header->SetHasShouldDeoptimizeFlag();
   }
diff --git a/runtime/oat.h b/runtime/oat.h
index 2c07145..301e7cf 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
-  // Last oat version changed reason: Add code size to CodeInfo.
-  static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '1', '\0' } };
+  // Last oat version changed reason: Move code size from OatQuickMethodHeader to CodeInfo.
+  static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '2', '\0' } };
 
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
   static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index b71c4e8..29b361b 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -41,14 +41,6 @@
   return reinterpret_cast<const uint8_t*>(method_header) - begin_;
 }
 
-inline uint32_t OatFile::OatMethod::GetQuickCodeSizeOffset() const {
-  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
-  if (method_header == nullptr) {
-    return 0u;
-  }
-  return reinterpret_cast<const uint8_t*>(method_header->GetCodeSizeAddr()) - begin_;
-}
-
 inline size_t OatFile::OatMethod::GetFrameSizeInBytes() const {
   const void* code = EntryPointToCodePointer(GetQuickCode());
   if (code == nullptr) {
@@ -78,20 +70,12 @@
   return static_cast<uint32_t>(vmap_table != nullptr ? vmap_table - begin_ : 0u);
 }
 
-inline uint32_t OatFile::OatMethod::GetVmapTableOffsetOffset() const {
-  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
-  if (method_header == nullptr) {
-    return 0u;
-  }
-  return reinterpret_cast<const uint8_t*>(method_header->GetVmapTableOffsetAddr()) - begin_;
-}
-
 inline const uint8_t* OatFile::OatMethod::GetVmapTable() const {
   const void* code = EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_));
   if (code == nullptr) {
     return nullptr;
   }
-  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].GetVmapTableOffset();
+  uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].GetCodeInfoOffset();
   if (UNLIKELY(offset == 0u)) {
     return nullptr;
   }
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index a22e043..7a0dce5 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -202,7 +202,6 @@
 
     // Returns size of quick code.
     uint32_t GetQuickCodeSize() const;
-    uint32_t GetQuickCodeSizeOffset() const;
 
     // Returns OatQuickMethodHeader for debugging. Most callers should
     // use more specific methods such as GetQuickCodeSize.
@@ -215,7 +214,6 @@
 
     const uint8_t* GetVmapTable() const;
     uint32_t GetVmapTableOffset() const;
-    uint32_t GetVmapTableOffsetOffset() const;
 
     // Create an OatMethod with offsets relative to the given base address
     OatMethod(const uint8_t* base, const uint32_t code_offset)
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
index 7e1fc9b..e0f942f 100644
--- a/runtime/oat_quick_method_header.h
+++ b/runtime/oat_quick_method_header.h
@@ -31,11 +31,8 @@
 // OatQuickMethodHeader precedes the raw code chunk generated by the compiler.
 class PACKED(4) OatQuickMethodHeader {
  public:
-  OatQuickMethodHeader() = default;
-  OatQuickMethodHeader(uint32_t vmap_table_offset,
-                       uint32_t code_size)
-      : vmap_table_offset_(vmap_table_offset),
-        code_size_(code_size) {
+  OatQuickMethodHeader(uint32_t code_info_offset = 0) {
+    SetCodeInfoOffset(code_info_offset);
   }
 
   static OatQuickMethodHeader* NterpMethodHeader;
@@ -67,17 +64,22 @@
   }
 
   bool IsOptimized() const {
-    return (code_size_ & kCodeSizeMask) != 0 && vmap_table_offset_ != 0;
+    uintptr_t code = reinterpret_cast<uintptr_t>(code_);
+    DCHECK_NE(data_, 0u) << std::hex << code;          // Probably a padding of native code.
+    DCHECK_NE(data_, 0xFFFFFFFF) << std::hex << code;  // Probably a stub or trampoline.
+    return (data_ & kIsCodeInfoMask) != 0;
   }
 
   const uint8_t* GetOptimizedCodeInfoPtr() const {
-    DCHECK(IsOptimized());
-    return code_ - vmap_table_offset_;
+    uint32_t offset = GetCodeInfoOffset();
+    DCHECK_NE(offset, 0u);
+    return code_ - offset;
   }
 
   uint8_t* GetOptimizedCodeInfoPtr() {
-    DCHECK(IsOptimized());
-    return code_ - vmap_table_offset_;
+    uint32_t offset = GetCodeInfoOffset();
+    DCHECK_NE(offset, 0u);
+    return code_ - offset;
   }
 
   const uint8_t* GetCode() const {
@@ -85,36 +87,17 @@
   }
 
   uint32_t GetCodeSize() const {
-    // ART compiled method are prefixed with header, but we can also easily
-    // accidentally use a function pointer to one of the stubs/trampolines.
-    // We prefix those with 0xFF in the aseembly so that we can do DCHECKs.
-    CHECK_NE(code_size_, 0xFFFFFFFF) << code_size_;
-    if (IsOptimized()) {
-      // Temporary code: Check that the code size in code info matches.
-      CHECK_EQ(code_size_ & kCodeSizeMask, CodeInfo::DecodeCodeSize(this));
-    }
-    return code_size_ & kCodeSizeMask;
+    return IsOptimized() ? CodeInfo::DecodeCodeSize(this) : (data_ & kCodeSizeMask);
   }
 
-  const uint32_t* GetCodeSizeAddr() const {
-    return &code_size_;
+  uint32_t GetCodeInfoOffset() const {
+    DCHECK(IsOptimized());
+    return data_ & kCodeInfoMask;
   }
 
-  uint32_t GetVmapTableOffset() const {
-    return vmap_table_offset_;
-  }
-
-  void SetVmapTableOffset(uint32_t offset) {
-    vmap_table_offset_ = offset;
-  }
-
-  const uint32_t* GetVmapTableOffsetAddr() const {
-    return &vmap_table_offset_;
-  }
-
-  const uint8_t* GetVmapTable() const {
-    CHECK(!IsOptimized()) << "Unimplemented vmap table for optimizing compiler";
-    return (vmap_table_offset_ == 0) ? nullptr : code_ - vmap_table_offset_;
+  void SetCodeInfoOffset(uint32_t offset) {
+    data_ = kIsCodeInfoMask | offset;
+    DCHECK_EQ(GetCodeInfoOffset(), offset);
   }
 
   bool Contains(uintptr_t pc) const {
@@ -164,25 +147,22 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetHasShouldDeoptimizeFlag() {
-    DCHECK_EQ(code_size_ & kShouldDeoptimizeMask, 0u);
-    code_size_ |= kShouldDeoptimizeMask;
+    DCHECK(!HasShouldDeoptimizeFlag());
+    data_ |= kShouldDeoptimizeMask;
   }
 
   bool HasShouldDeoptimizeFlag() const {
-    return (code_size_ & kShouldDeoptimizeMask) != 0;
+    return (data_ & kShouldDeoptimizeMask) != 0;
   }
 
  private:
   static constexpr uint32_t kShouldDeoptimizeMask = 0x80000000;
-  static constexpr uint32_t kCodeSizeMask = ~kShouldDeoptimizeMask;
+  static constexpr uint32_t kIsCodeInfoMask       = 0x40000000;
+  static constexpr uint32_t kCodeInfoMask         = 0x3FFFFFFF;  // If kIsCodeInfoMask is set.
+  static constexpr uint32_t kCodeSizeMask         = 0x3FFFFFFF;  // If kIsCodeInfoMask is clear.
 
-  // The offset in bytes from the start of the vmap table to the end of the header.
-  uint32_t vmap_table_offset_ = 0u;
-  // The code size in bytes. The highest bit is used to signify if the compiled
-  // code with the method header has should_deoptimize flag.
-  uint32_t code_size_ = 0u;
-  // The actual code.
-  uint8_t code_[0];
+  uint32_t data_ = 0u;  // Combination of fields using the above masks.
+  uint8_t code_[0];     // The actual method code.
 };
 
 }  // namespace art
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 276a67c..21f74c0 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -266,7 +266,7 @@
                     uint32_t code_offset,
                     bool verbose,
                     InstructionSet instruction_set) const {
-  vios->Stream() << "CodeInfo "
+  vios->Stream() << "CodeInfo"
     << " CodeSize:" << code_size_
     << " FrameSize:" << packed_frame_size_ * kStackAlignment
     << " CoreSpillMask:" << std::hex << core_spill_mask_