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,