Small cleanups in artInvokeInterfaceTrampoline
- No need to do a conflict table lookup when the passed method is
already the interface method.
- Remove obsolete test that the IMT entry is indeed a conflict entry.
- Only call QuickArgumentVisitor::GetCallingMethod when needed.
Test: test.py
Bug: 112676029
Change-Id: I2d5da474ba3e8e4ad559fc7c13a19b04f4c2a515
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0bed8eb..8982368 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -6854,15 +6854,13 @@
ArtMethod* ClassLinker::AddMethodToConflictTable(ObjPtr<mirror::Class> klass,
ArtMethod* conflict_method,
ArtMethod* interface_method,
- ArtMethod* method,
- bool force_new_conflict_method) {
+ ArtMethod* method) {
ImtConflictTable* current_table = conflict_method->GetImtConflictTable(kRuntimePointerSize);
Runtime* const runtime = Runtime::Current();
LinearAlloc* linear_alloc = GetAllocatorForClassLoader(klass->GetClassLoader());
- bool new_entry = conflict_method == runtime->GetImtConflictMethod() || force_new_conflict_method;
// Create a new entry if the existing one is the shared conflict method.
- ArtMethod* new_conflict_method = new_entry
+ ArtMethod* new_conflict_method = (conflict_method == runtime->GetImtConflictMethod())
? runtime->CreateImtConflictMethod(linear_alloc)
: conflict_method;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 263fb1a..94d1999 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -717,8 +717,7 @@
ArtMethod* AddMethodToConflictTable(ObjPtr<mirror::Class> klass,
ArtMethod* conflict_method,
ArtMethod* interface_method,
- ArtMethod* method,
- bool force_new_conflict_method)
+ ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_);
// Create a conflict table with a specified capacity.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 3f89fe1..197e8ef 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2394,17 +2394,15 @@
ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
- StackHandleScope<2> hs(self);
- Handle<mirror::Object> this_object = hs.NewHandle(raw_this_object);
- Handle<mirror::Class> cls = hs.NewHandle(this_object->GetClass());
- ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
- ArtMethod* method = nullptr;
- ImTable* imt = cls->GetImt(kRuntimePointerSize);
-
- if (UNLIKELY(interface_method == nullptr) || interface_method->IsRuntimeMethod()) {
+ Runtime* runtime = Runtime::Current();
+ bool resolve_method = ((interface_method == nullptr) || interface_method->IsRuntimeMethod());
+ if (UNLIKELY(resolve_method)) {
// The interface method is unresolved, so resolve it in the dex file of the caller.
// Fetch the dex_method_idx of the target interface method from the caller.
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Object> this_object = hs.NewHandle(raw_this_object);
+ ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
uint32_t dex_method_idx;
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
const Instruction& instr = caller_method->DexInstructions().InstructionAt(dex_pc);
@@ -2428,7 +2426,7 @@
ScopedObjectAccessUnchecked soa(self->GetJniEnv());
RememberForGcArgumentVisitor visitor(sp, false, shorty, shorty_len, &soa);
visitor.VisitArguments();
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ClassLinker* class_linker = runtime->GetClassLinker();
interface_method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
self, dex_method_idx, caller_method, kInterface);
visitor.FixupReferences();
@@ -2439,58 +2437,57 @@
return GetTwoWordFailureValue(); // Failure.
}
MaybeUpdateBssMethodEntry(interface_method, MethodReference(&dex_file, dex_method_idx));
+
+ // Refresh `raw_this_object` which may have changed after resolution.
+ raw_this_object = this_object.Get();
}
// The compiler and interpreter make sure the conflict trampoline is never
// called on a method that resolves to j.l.Object.
- CHECK(!interface_method->GetDeclaringClass()->IsObjectClass());
- CHECK(interface_method->GetDeclaringClass()->IsInterface());
-
+ DCHECK(!interface_method->GetDeclaringClass()->IsObjectClass());
+ DCHECK(interface_method->GetDeclaringClass()->IsInterface());
DCHECK(!interface_method->IsRuntimeMethod());
- // Look whether we have a match in the ImtConflictTable.
+
+ ObjPtr<mirror::Object> obj_this = raw_this_object;
+ ObjPtr<mirror::Class> cls = obj_this->GetClass();
uint32_t imt_index = interface_method->GetImtIndex();
+ ImTable* imt = cls->GetImt(kRuntimePointerSize);
ArtMethod* conflict_method = imt->Get(imt_index, kRuntimePointerSize);
- if (LIKELY(conflict_method->IsRuntimeMethod())) {
+ DCHECK(conflict_method->IsRuntimeMethod());
+
+ if (UNLIKELY(resolve_method)) {
+ // Now that we know the interface method, look it up in the conflict table.
ImtConflictTable* current_table = conflict_method->GetImtConflictTable(kRuntimePointerSize);
DCHECK(current_table != nullptr);
- method = current_table->Lookup(interface_method, kRuntimePointerSize);
- } else {
- // It seems we aren't really a conflict method!
- if (kIsDebugBuild) {
- ArtMethod* m = cls->FindVirtualMethodForInterface(interface_method, kRuntimePointerSize);
- CHECK_EQ(conflict_method, m)
- << interface_method->PrettyMethod() << " / " << conflict_method->PrettyMethod() << " / "
- << " / " << ArtMethod::PrettyMethod(m) << " / " << cls->PrettyClass();
+ ArtMethod* method = current_table->Lookup(interface_method, kRuntimePointerSize);
+ if (method != nullptr) {
+ return GetTwoWordSuccessValue(
+ reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()),
+ reinterpret_cast<uintptr_t>(method));
}
- method = conflict_method;
- }
- if (method != nullptr) {
- return GetTwoWordSuccessValue(
- reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()),
- reinterpret_cast<uintptr_t>(method));
+ // Interface method is not in the conflict table. Continue looking up in the
+ // iftable.
}
- // No match, use the IfTable.
- method = cls->FindVirtualMethodForInterface(interface_method, kRuntimePointerSize);
+ ArtMethod* method = cls->FindVirtualMethodForInterface(interface_method, kRuntimePointerSize);
if (UNLIKELY(method == nullptr)) {
+ ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(
- interface_method, this_object.Get(), caller_method);
- return GetTwoWordFailureValue(); // Failure.
+ interface_method, obj_this.Ptr(), caller_method);
+ return GetTwoWordFailureValue();
}
// We arrive here if we have found an implementation, and it is not in the ImtConflictTable.
// We create a new table with the new pair { interface_method, method }.
- DCHECK(conflict_method->IsRuntimeMethod());
// Classes in the boot image should never need to update conflict methods in
// their IMT.
- CHECK(!Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(cls.Get())) << cls->PrettyClass();
- ArtMethod* new_conflict_method = Runtime::Current()->GetClassLinker()->AddMethodToConflictTable(
- cls.Get(),
+ CHECK(!runtime->GetHeap()->ObjectIsInBootImageSpace(cls.Ptr())) << cls->PrettyClass();
+ ArtMethod* new_conflict_method = runtime->GetClassLinker()->AddMethodToConflictTable(
+ cls.Ptr(),
conflict_method,
interface_method,
- method,
- /*force_new_conflict_method=*/false);
+ method);
if (new_conflict_method != conflict_method) {
// Update the IMT if we create a new conflict method. No fence needed here, as the
// data is consistent.