Move code item to the data pointer and remove code_item_offset.

This saves 4 bytes on 32bit and 8 bytes on 64bit on ArtMethod.

Also update nterp to directly fetch the code item from the data pointer.

Test: test.py
Bug: 112676029

Change-Id: Ic01f43c7ccf2cbce1ec517478e81362232d36371
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index 7d56da0..9212ea6 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -17,6 +17,7 @@
 #include <memory>
 #include <type_traits>
 
+#include "art_method-inl.h"
 #include "base/arena_allocator.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
@@ -128,7 +129,7 @@
 
 TEST_F(ExceptionTest, FindCatchHandler) {
   ScopedObjectAccess soa(Thread::Current());
-  CodeItemDataAccessor accessor(*dex_, dex_->GetCodeItem(method_f_->GetCodeItemOffset()));
+  CodeItemDataAccessor accessor(*dex_, method_f_->GetCodeItem());
 
   ASSERT_TRUE(accessor.HasCodeItem());
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 392aadd..3c168ba 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1238,7 +1238,7 @@
 
   const DexFile* dex_file = method->GetDexFile();
   const uint16_t class_def_idx = method->GetClassDefIndex();
-  const dex::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+  const dex::CodeItem* code_item = method->GetCodeItem();
   const uint32_t method_idx = method->GetDexMethodIndex();
   const uint32_t access_flags = method->GetAccessFlags();
 
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index fbdffa8..42c570f 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -3473,8 +3473,10 @@
         StubType stub_type = orig->IsCriticalNative() ? StubType::kJNIDlsymLookupCriticalTrampoline
                                                       : StubType::kJNIDlsymLookupTrampoline;
         copy->SetEntryPointFromJniPtrSize(GetOatAddress(stub_type), target_ptr_size_);
-      } else {
+      } else if (!orig->HasCodeItem()) {
         CHECK(copy->GetDataPtrSize(target_ptr_size_) == nullptr);
+      } else {
+        CHECK(copy->GetDataPtrSize(target_ptr_size_) != nullptr);
       }
     }
   }
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index e7f071f..f2646c6 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -190,7 +190,8 @@
     return ERR(NONE);
   }
 
-  DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
+  DCHECK(art_method->HasCodeItem());
+  DCHECK_NE(art_method->GetCodeItem(), nullptr);
   *size_ptr = art_method->DexInstructionData().InsSize();
 
   return ERR(NONE);
@@ -306,7 +307,8 @@
     return ERR(NONE);
   }
 
-  DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
+  DCHECK(art_method->HasCodeItem());
+  DCHECK_NE(art_method->GetCodeItem(), nullptr);
   *max_ptr = art_method->DexInstructionData().RegistersSize();
 
   return ERR(NONE);
@@ -420,7 +422,8 @@
     return ERR(NONE);
   }
 
-  DCHECK_NE(art_method->GetCodeItemOffset(), 0u);
+  DCHECK(art_method->HasCodeItem());
+  DCHECK_NE(art_method->GetCodeItem(), nullptr);
   *start_location_ptr = 0;
   *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1;
 
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index d442799..afaea62 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -2583,7 +2583,10 @@
     uint32_t dex_method_idx = dex_file_->GetIndexForMethodId(*method_id);
     method.SetDexMethodIndex(dex_method_idx);
     linker->SetEntryPointsToInterpreter(&method);
-    method.SetCodeItemOffset(dex_file_->FindCodeItemOffset(class_def, dex_method_idx));
+    if (method.HasCodeItem()) {
+      method.SetCodeItem(
+          dex_file_->GetCodeItem(dex_file_->FindCodeItemOffset(class_def, dex_method_idx)));
+    }
     // Clear all the intrinsics related flags.
     method.SetNotIntrinsic();
   }
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 03b4ce9..01fa33f 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -223,7 +223,14 @@
 }
 
 inline const dex::CodeItem* ArtMethod::GetCodeItem() {
-  return GetDexFile()->GetCodeItem(GetCodeItemOffset());
+  if (!HasCodeItem()) {
+    return nullptr;
+  }
+  Runtime* runtime = Runtime::Current();
+  PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
+  return runtime->IsAotCompiler()
+      ? GetDexFile()->GetCodeItem(reinterpret_cast32<uint32_t>(GetDataPtrSize(pointer_size)))
+      : reinterpret_cast<const dex::CodeItem*>(GetDataPtrSize(pointer_size));
 }
 
 inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx) {
@@ -384,8 +391,6 @@
     if (old_native_code != new_native_code) {
       SetEntryPointFromJniPtrSize(new_native_code, pointer_size);
     }
-  } else {
-    DCHECK(GetDataPtrSize(pointer_size) == nullptr);
   }
   const void* old_code = GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
   const void* new_code = visitor(old_code);
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 45a6938..0a824e3 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -771,7 +771,7 @@
   }
 
   // Clear the data pointer, it will be set if needed by the caller.
-  if (!src->IsNative()) {
+  if (!src->HasCodeItem() && !src->IsNative()) {
     SetDataPtrSize(nullptr, image_pointer_size);
   }
   // Clear hotness to let the JIT properly decide when to compile this method.
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 6050f00..30357f7 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -78,7 +78,7 @@
   // constexpr, and ensure that the value is correct in art_method.cc.
   static constexpr uint32_t kRuntimeMethodDexMethodIndex = 0xFFFFFFFF;
 
-  ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0),
+  ArtMethod() : access_flags_(0), dex_method_index_(0),
       method_index_(0), hotness_count_(0) { }
 
   ArtMethod(ArtMethod* src, PointerSize image_pointer_size) {
@@ -419,15 +419,6 @@
     return MemberOffset(OFFSETOF_MEMBER(ArtMethod, imt_index_));
   }
 
-  uint32_t GetCodeItemOffset() const {
-    return dex_code_item_offset_;
-  }
-
-  void SetCodeItemOffset(uint32_t new_code_off) REQUIRES_SHARED(Locks::mutator_lock_) {
-    // Not called within a transaction.
-    dex_code_item_offset_ = new_code_off;
-  }
-
   // Number of 32bit registers that would be required to hold all the arguments
   static size_t NumArgRegisters(const char* shorty);
 
@@ -587,6 +578,15 @@
     return dex_method_index_ == kRuntimeMethodDexMethodIndex;
   }
 
+  bool HasCodeItem() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return !IsRuntimeMethod() && !IsNative() && !IsProxyMethod() && !IsAbstract();
+  }
+
+  void SetCodeItem(const dex::CodeItem* code_item) REQUIRES_SHARED(Locks::mutator_lock_) {
+    DCHECK(HasCodeItem());
+    SetDataPtrSize(code_item, kRuntimePointerSize);
+  }
+
   // Is this a hand crafted method used for something like describing callee saves?
   bool IsCalleeSaveMethod() REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -742,7 +742,6 @@
     DCHECK(IsImagePointerSize(kRuntimePointerSize));
     visitor(this, &declaring_class_, "declaring_class_");
     visitor(this, &access_flags_, "access_flags_");
-    visitor(this, &dex_code_item_offset_, "dex_code_item_offset_");
     visitor(this, &dex_method_index_, "dex_method_index_");
     visitor(this, &method_index_, "method_index_");
     visitor(this, &hotness_count_, "hotness_count_");
@@ -782,9 +781,6 @@
 
   /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
 
-  // Offset to the CodeItem.
-  uint32_t dex_code_item_offset_;
-
   // Index into method_ids of the dex file associated with this method.
   uint32_t dex_method_index_;
 
@@ -816,7 +812,8 @@
     //   - conflict method: ImtConflictTable,
     //   - abstract/interface method: the single-implementation if any,
     //   - proxy method: the original interface method or constructor,
-    //   - other methods: the profiling data.
+    //   - other methods: during AOT the code item offset, at runtime a pointer
+    //                    to the code item.
     void* data_;
 
     // Method dispatch from quick compiled code invokes this pointer which may cause bridging into
diff --git a/runtime/cha.cc b/runtime/cha.cc
index a142723..c345af8 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -543,7 +543,8 @@
       // Abstract method starts with single-implementation flag set and null
       // implementation method.
       method->SetHasSingleImplementation(true);
-      DCHECK(method->GetSingleImplementation(pointer_size) == nullptr);
+      DCHECK(!method->HasCodeItem()) << method->PrettyMethod();
+      DCHECK(method->GetSingleImplementation(pointer_size) == nullptr) << method->PrettyMethod();
     }
   // Default conflicting methods cannot be treated with single implementations,
   // as we need to call them (and not inline them) in case of ICCE.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 09fa99b..c181c22 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2199,10 +2199,21 @@
     }, space->Begin(), image_pointer_size_);
   }
 
-  if (interpreter::CanRuntimeUseNterp()) {
-    // Set image methods' entry point that point to the interpreter bridge to the nterp entry point.
+  if (!runtime->IsAotCompiler()) {
+    bool can_use_nterp = interpreter::CanRuntimeUseNterp();
     header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) {
-      ChangeInterpreterBridgeToNterp(&method, this);
+      // In the image, the `data` pointer field of the ArtMethod contains the code
+      // item offset. Change this to the actual pointer to the code item.
+      if (method.HasCodeItem()) {
+        const dex::CodeItem* code_item = method.GetDexFile()->GetCodeItem(
+            reinterpret_cast32<uint32_t>(method.GetDataPtrSize(image_pointer_size_)));
+        method.SetDataPtrSize(code_item, image_pointer_size_);
+      }
+      // Set image methods' entry point that point to the interpreter bridge to the
+      // nterp entry point.
+      if (can_use_nterp) {
+        ChangeInterpreterBridgeToNterp(&method, this);
+      }
     }, space->Begin(), image_pointer_size_);
   }
 
@@ -3977,7 +3988,6 @@
   ScopedAssertNoThreadSuspension ants("LoadMethod");
   dst->SetDexMethodIndex(dex_method_idx);
   dst->SetDeclaringClass(klass.Get());
-  dst->SetCodeItemOffset(method.GetCodeItemOffset());
 
   // Get access flags from the DexFile and set hiddenapi runtime access flags.
   uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method);
@@ -4026,6 +4036,18 @@
   if (klass->IsInterface() && dst->IsAbstract()) {
     dst->CalculateAndSetImtIndex();
   }
+  if (dst->HasCodeItem()) {
+    DCHECK_NE(method.GetCodeItemOffset(), 0u);
+    if (Runtime::Current()->IsAotCompiler()) {
+      dst->SetDataPtrSize(reinterpret_cast32<void*>(method.GetCodeItemOffset()), image_pointer_size_);
+    } else {
+      dst->SetDataPtrSize(dst->GetDexFile()->GetCodeItem(method.GetCodeItemOffset()),
+                          image_pointer_size_);
+    }
+  } else {
+    dst->SetDataPtrSize(nullptr, image_pointer_size_);
+    DCHECK_EQ(method.GetCodeItemOffset(), 0u);
+  }
 }
 
 void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile* dex_file) {
@@ -5304,10 +5326,6 @@
   const uint32_t kAddFlags = kAccFinal | kAccCompileDontBother;
   out->SetAccessFlags((out->GetAccessFlags() & ~kRemoveFlags) | kAddFlags);
 
-  // Clear the dex_code_item_offset_. It needs to be 0 since proxy methods have no CodeItems but the
-  // method they copy might (if it's a default method).
-  out->SetCodeItemOffset(0);
-
   // Set the original interface method.
   out->SetDataPtrSize(prototype, image_pointer_size_);
 
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 6261a93..c149aea 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -1745,7 +1745,7 @@
 int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t rel_pc) {
   // For native method, lineno should be -2 to indicate it is native. Note that
   // "line number == -2" is how libcore tells from StackTraceElement.
-  if (method->GetCodeItemOffset() == 0) {
+  if (!method->HasCodeItem()) {
     return -2;
   }
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index e357b75..af63f68 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -2872,8 +2872,10 @@
       image_header.VisitPackedArtMethods([&](ArtMethod& method)
           REQUIRES_SHARED(Locks::mutator_lock_) {
         main_patch_object_visitor.PatchGcRoot(&method.DeclaringClassRoot());
-        void** data_address = PointerAddress(&method, ArtMethod::DataOffset(kPointerSize));
-        main_patch_object_visitor.PatchNativePointer(data_address);
+        if (!method.HasCodeItem()) {
+          void** data_address = PointerAddress(&method, ArtMethod::DataOffset(kPointerSize));
+          main_patch_object_visitor.PatchNativePointer(data_address);
+        }
         void** entrypoint_address =
             PointerAddress(&method, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kPointerSize));
         main_patch_object_visitor.PatchNativePointer(entrypoint_address);
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index b5e5238..67644d6 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -445,7 +445,7 @@
     method->ThrowInvocationTimeError();
     return;
   } else {
-    DCHECK(method->IsNative());
+    DCHECK(method->IsNative()) << method->PrettyMethod();
     num_regs = num_ins = ArtMethod::NumArgRegisters(method->GetShorty());
     if (!method->IsStatic()) {
       num_regs++;
diff --git a/runtime/interpreter/mterp/arm64ng/main.S b/runtime/interpreter/mterp/arm64ng/main.S
index b4b3283..51ebea1 100644
--- a/runtime/interpreter/mterp/arm64ng/main.S
+++ b/runtime/interpreter/mterp/arm64ng/main.S
@@ -645,13 +645,10 @@
    ldp x0, x1, [sp], #16
 .endm
 
+// Input:  x0 contains the ArtMethod
 // Output: x8 contains the code item
 .macro GET_CODE_ITEM
-   // TODO: Get code item in a better way.
-   stp x0, x1, [sp, #-16]!
-   bl NterpGetCodeItem
-   mov x8, x0
-   ldp x0, x1, [sp], #16
+   ldr x8, [x0, #ART_METHOD_DATA_OFFSET_64]
 .endm
 
 .macro DO_ENTRY_POINT_CHECK call_compiled_code
@@ -1498,11 +1495,9 @@
     bl NterpGetShorty
     // Save shorty in callee-save xIBASE.
     mov xIBASE, x0
-    mov x0, xINST
-    bl NterpGetCodeItem
-    mov xPC, x0
 
     RESTORE_ALL_ARGUMENTS
+    ldr xPC, [xINST, #ART_METHOD_DATA_OFFSET_64]
 
     // Setup the stack for executing the method.
     SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS
diff --git a/runtime/interpreter/mterp/x86_64ng/main.S b/runtime/interpreter/mterp/x86_64ng/main.S
index 8966490..cce7282 100644
--- a/runtime/interpreter/mterp/x86_64ng/main.S
+++ b/runtime/interpreter/mterp/x86_64ng/main.S
@@ -784,6 +784,9 @@
 // - rPC: the new PC pointer to execute
 // - edi: number of arguments
 // - ecx: first dex register
+//
+// This helper expects:
+// - rax to contain the code item
 .macro SETUP_STACK_FOR_INVOKE
    // We do the same stack overflow check as the compiler. See CanMethodUseNterp
    // in how we limit the maximum nterp frame size.
@@ -969,13 +972,7 @@
    cmpq %rax, ART_METHOD_QUICK_CODE_OFFSET_64(%rdi)
    jne  VAR(call_compiled_code)
 
-   // TODO: Get code item in a better way and remove below
-   push %rdi
-   push %rsi
-   call SYMBOL(NterpGetCodeItem)
-   pop %rsi
-   pop %rdi
-   // TODO: Get code item in a better way and remove above
+   movq ART_METHOD_DATA_OFFSET_64(%rdi), %rax
 .endm
 
 // Uses r9 and r10 as temporary
@@ -1389,9 +1386,6 @@
     call SYMBOL(NterpGetShorty)
     // Save shorty in callee-save rbp.
     movq %rax, %rbp
-    movq %rbx, %rdi
-    call SYMBOL(NterpGetCodeItem)
-    movq %rax, rPC
 
     // Restore xmm registers + alignment.
     movq 0(%rsp), %xmm0
@@ -1413,6 +1407,8 @@
     POP rdi
     // TODO: Get shorty in a better way and remove above
 
+    movq ART_METHOD_DATA_OFFSET_64(%rdi), rPC
+
     // Setup the stack for executing the method.
     SETUP_STACK_FRAME rPC, rREFS, rFP, CFI_REFS
 
diff --git a/tools/cpp-define-generator/art_method.def b/tools/cpp-define-generator/art_method.def
index 75fbab0..097d466 100644
--- a/tools/cpp-define-generator/art_method.def
+++ b/tools/cpp-define-generator/art_method.def
@@ -28,6 +28,10 @@
            art::ArtMethod::EntryPointFromJniOffset(art::PointerSize::k32).Int32Value())
 ASM_DEFINE(ART_METHOD_JNI_OFFSET_64,
            art::ArtMethod::EntryPointFromJniOffset(art::PointerSize::k64).Int32Value())
+ASM_DEFINE(ART_METHOD_DATA_OFFSET_32,
+           art::ArtMethod::DataOffset(art::PointerSize::k32).Int32Value())
+ASM_DEFINE(ART_METHOD_DATA_OFFSET_64,
+           art::ArtMethod::DataOffset(art::PointerSize::k64).Int32Value())
 ASM_DEFINE(ART_METHOD_QUICK_CODE_OFFSET_32,
            art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(art::PointerSize::k32).Int32Value())
 ASM_DEFINE(ART_METHOD_QUICK_CODE_OFFSET_64,