summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2022-12-12 09:12:21 +0000
committer VladimĂ­r Marko <vmarko@google.com> 2022-12-12 15:57:57 +0000
commita20ec9bb10d7ded8ae7d95d4de1e190d22260c73 (patch)
tree50b5a757c4aa9f5aa7c663d47d96474f538476a2
parentb9df137d1dbdab1fdca13bb459705b6603e9328b (diff)
Fix clinit debug check in instrumentation.
Test: m test-art-host-gtest Test: testrunner.py --host --optimizing --jit --interpreter Change-Id: Idae620b0b8f9ed67574f5b785fdac3efcb534cfd
-rw-r--r--dex2oat/linker/image_writer.cc7
-rw-r--r--runtime/art_method-inl.h26
-rw-r--r--runtime/art_method.h26
-rw-r--r--runtime/class_linker.cc8
-rw-r--r--runtime/common_dex_operations.h8
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h7
-rw-r--r--runtime/entrypoints/entrypoint_utils.h4
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc28
-rw-r--r--runtime/instrumentation.cc10
-rw-r--r--runtime/jit/jit.cc3
-rw-r--r--runtime/jit/jit_code_cache.cc43
-rw-r--r--runtime/jni/java_vm_ext.cc2
-rw-r--r--runtime/runtime.cc2
14 files changed, 95 insertions, 81 deletions
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 54f0d1142e..2c3c2206bf 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -3342,8 +3342,7 @@ const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method, const ImageInfo& ima
quick_code = GetOatAddressForOffset(quick_oat_code_offset, image_info);
}
- bool needs_clinit_check = NeedsClinitCheckBeforeCall(method) &&
- !method->GetDeclaringClass<kWithoutReadBarrier>()->IsVisiblyInitialized();
+ bool still_needs_clinit_check = method->StillNeedsClinitCheck<kWithoutReadBarrier>();
if (quick_code == nullptr) {
// If we don't have code, use generic jni / interpreter.
@@ -3353,7 +3352,7 @@ const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method, const ImageInfo& ima
} else if (CanMethodUseNterp(method, compiler_options_.GetInstructionSet())) {
// The nterp trampoline doesn't do initialization checks, so install the
// resolution stub if needed.
- if (needs_clinit_check) {
+ if (still_needs_clinit_check) {
quick_code = GetOatAddress(StubType::kQuickResolutionTrampoline);
} else {
quick_code = GetOatAddress(StubType::kNterpTrampoline);
@@ -3362,7 +3361,7 @@ const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method, const ImageInfo& ima
// The interpreter brige performs class initialization check if needed.
quick_code = GetOatAddress(StubType::kQuickToInterpreterBridge);
}
- } else if (needs_clinit_check && !compiler_options_.ShouldCompileWithClinitCheck(method)) {
+ } else if (still_needs_clinit_check && !compiler_options_.ShouldCompileWithClinitCheck(method)) {
// If we do have code but the method needs a class initialization check before calling
// that code, install the resolution stub that will perform the check.
quick_code = GetOatAddress(StubType::kQuickResolutionTrampoline);
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 6e051424bd..b1d8a4ef54 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -669,6 +669,32 @@ inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize poi
}
}
+template <ReadBarrierOption kReadBarrierOption>
+inline bool ArtMethod::StillNeedsClinitCheck() {
+ if (!NeedsClinitCheckBeforeCall()) {
+ return false;
+ }
+ ObjPtr<mirror::Class> klass = GetDeclaringClass<kReadBarrierOption>();
+ return !klass->IsVisiblyInitialized();
+}
+
+inline bool ArtMethod::StillNeedsClinitCheckMayBeDead() {
+ if (!NeedsClinitCheckBeforeCall()) {
+ return false;
+ }
+ // To avoid resurrecting an unreachable object, or crashing the GC in some GC phases,
+ // we must not use a full read barrier. Therefore we read the declaring class without
+ // a read barrier and check if it's already marked. If yes, we check the status of the
+ // to-space class object as intended. Otherwise, there is no to-space object and the
+ // from-space class object contains the most recent value of the status field; even if
+ // this races with another thread doing a read barrier and updating the status, that's
+ // no different from a race with a thread that just updates the status.
+ ObjPtr<mirror::Class> klass = GetDeclaringClass<kWithoutReadBarrier>();
+ ObjPtr<mirror::Class> marked = ReadBarrier::IsMarked(klass.Ptr());
+ ObjPtr<mirror::Class> checked_klass = (marked != nullptr) ? marked : klass;
+ return !checked_klass->IsVisiblyInitialized();
+}
+
inline CodeItemInstructionAccessor ArtMethod::DexInstructions() {
return CodeItemInstructionAccessor(*GetDexFile(), GetCodeItem());
}
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 9e55f38779..e6dcb43ed0 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -711,6 +711,32 @@ class ArtMethod final {
typename detail::HandleShortyTraits<ArgType>::Type... args)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns true if the method needs a class initialization check according to access flags.
+ // Only static methods other than the class initializer need this check.
+ // The caller is responsible for performing the actual check.
+ bool NeedsClinitCheckBeforeCall() const {
+ return NeedsClinitCheckBeforeCall(GetAccessFlags());
+ }
+
+ static bool NeedsClinitCheckBeforeCall(uint32_t access_flags) {
+ // The class initializer is special as it is invoked during initialization
+ // and does not need the check.
+ return IsStatic(access_flags) && !IsConstructor(access_flags);
+ }
+
+ // Check if the method needs a class initialization check before call
+ // and its declaring class is not yet visibly initialized.
+ // (The class needs to be visibly initialized before we can use entrypoints
+ // to compiled code for static methods. See b/18161648 .)
+ template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+ bool StillNeedsClinitCheck() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Similar to `StillNeedsClinitCheck()` but the method's declaring class may
+ // be dead but not yet reclaimed by the GC, so we cannot do a full read barrier
+ // but we still want to check the class status in the to-space class if any.
+ // Note: JIT can hold and use such methods during managed heap GC.
+ bool StillNeedsClinitCheckMayBeDead() REQUIRES_SHARED(Locks::mutator_lock_);
+
const void* GetEntryPointFromQuickCompiledCode() const {
return GetEntryPointFromQuickCompiledCodePtrSize(kRuntimePointerSize);
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 08131c5d88..07300d2733 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2128,8 +2128,7 @@ bool ClassLinker::AddImageSpace(
// Set image methods' entry point that point to the nterp trampoline to the
// nterp entry point. This allows taking the fast path when doing a
// nterp->nterp call.
- DCHECK_IMPLIES(NeedsClinitCheckBeforeCall(&method),
- method.GetDeclaringClass()->IsVisiblyInitialized());
+ DCHECK(!method.StillNeedsClinitCheck());
method.SetEntryPointFromQuickCompiledCode(interpreter::GetNterpEntryPoint());
} else {
method.SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
@@ -3504,10 +3503,9 @@ void ClassLinker::FixupStaticTrampolines(Thread* self, ObjPtr<mirror::Class> kla
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
for (size_t method_index = 0; method_index < num_direct_methods; ++method_index) {
ArtMethod* method = klass->GetDirectMethod(method_index, pointer_size);
- if (!NeedsClinitCheckBeforeCall(method)) {
- continue;
+ if (method->NeedsClinitCheckBeforeCall()) {
+ instrumentation->UpdateMethodsCode(method, instrumentation->GetCodeForInvoke(method));
}
- instrumentation->UpdateMethodsCode(method, instrumentation->GetCodeForInvoke(method));
}
// Ignore virtual methods on the iterator.
}
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index b8d9cbe141..0b9d3fbb53 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -61,18 +61,14 @@ namespace interpreter {
inline bool EnsureInitialized(Thread* self, ShadowFrame* shadow_frame)
REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!NeedsClinitCheckBeforeCall(shadow_frame->GetMethod())) {
- return true;
- }
- ObjPtr<mirror::Class> declaring_class = shadow_frame->GetMethod()->GetDeclaringClass();
- if (LIKELY(declaring_class->IsVisiblyInitialized())) {
+ if (LIKELY(!shadow_frame->GetMethod()->StillNeedsClinitCheck())) {
return true;
}
// Save the shadow frame.
ScopedStackedShadowFramePusher pusher(self, shadow_frame);
StackHandleScope<1> hs(self);
- Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
+ Handle<mirror::Class> h_class = hs.NewHandle(shadow_frame->GetMethod()->GetDeclaringClass());
if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(
self, h_class, /*can_init_fields=*/ true, /*can_init_parents=*/ true))) {
DCHECK(self->IsExceptionPending());
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index e2aa81f837..91163f4139 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -715,13 +715,6 @@ inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
}
}
-inline bool NeedsClinitCheckBeforeCall(ArtMethod* method) {
- // The class needs to be visibly initialized before we can use entrypoints to
- // compiled code for static methods. See b/18161648 . The class initializer is
- // special as it is invoked during initialization and does not need the check.
- return method->IsStatic() && !method->IsConstructor();
-}
-
inline ObjPtr<mirror::Object> GetGenericJniSynchronizationObject(Thread* self, ArtMethod* called)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!called->IsCriticalNative());
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index ae5687506a..777fd9880d 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -204,10 +204,6 @@ CallerAndOuterMethod GetCalleeSaveMethodCallerAndOuterMethod(Thread* self, Calle
ArtMethod* GetCalleeSaveOuterMethod(Thread* self, CalleeSaveType type)
REQUIRES_SHARED(Locks::mutator_lock_);
-// Returns whether we need to do class initialization check before invoking the method.
-// The caller is responsible for performing that check.
-bool NeedsClinitCheckBeforeCall(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
-
// Returns the synchronization object for a native method for a GenericJni frame
// we have just created or are about to exit. The synchronization object is
// the class object for static methods and the `this` object otherwise.
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 80eb89f4e3..e606c2173a 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -75,7 +75,7 @@ extern "C" const void* artFindNativeMethodRunnable(Thread* self)
// These calls do not have an explicit class initialization check, so do the check now.
// (When going through the stub or GenericJNI, the check was already done.)
- DCHECK(NeedsClinitCheckBeforeCall(target_method));
+ DCHECK(target_method->NeedsClinitCheckBeforeCall());
ObjPtr<mirror::Class> declaring_class = target_method->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsVisiblyInitialized())) {
StackHandleScope<1> hs(self);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 87ef22a706..9475414f4e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1036,10 +1036,10 @@ extern "C" const void* artInstrumentationMethodEntryFromCode(ArtMethod* method,
StackHandleScope<2> hs(self);
Handle<mirror::Object> h_object(hs.NewHandle(is_static ? nullptr : this_object));
- Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
// Ensure that the called method's class is initialized.
- if (NeedsClinitCheckBeforeCall(method) && !h_class->IsVisiblyInitialized()) {
+ if (method->StillNeedsClinitCheck()) {
+ Handle<mirror::Class> h_class = hs.NewHandle(method->GetDeclaringClass());
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
visitor.FixupReferences();
DCHECK(self->IsExceptionPending());
@@ -1354,11 +1354,10 @@ extern "C" const void* artQuickResolutionTrampoline(
// Static invokes need class initialization check but instance invokes can proceed even if
// the class is erroneous, i.e. in the edge case of escaping instances of erroneous classes.
bool success = true;
- ObjPtr<mirror::Class> called_class = called->GetDeclaringClass();
- if (NeedsClinitCheckBeforeCall(called) && !called_class->IsVisiblyInitialized()) {
+ if (called->StillNeedsClinitCheck()) {
// Ensure that the called method's class is initialized.
StackHandleScope<1> hs(soa.Self());
- HandleWrapperObjPtr<mirror::Class> h_called_class(hs.NewHandleWrapper(&called_class));
+ Handle<mirror::Class> h_called_class = hs.NewHandle(called->GetDeclaringClass());
success = linker->EnsureInitialized(soa.Self(), h_called_class, true, true);
}
if (success) {
@@ -1373,7 +1372,7 @@ extern "C" const void* artQuickResolutionTrampoline(
// stub.
code = instrumentation->GetMaybeInstrumentedCodeForInvoke(called);
} else {
- DCHECK(called_class->IsErroneous());
+ DCHECK(called->GetDeclaringClass()->IsErroneous());
DCHECK(self->IsExceptionPending());
}
}
@@ -2092,16 +2091,13 @@ extern "C" const void* artQuickGenericJniTrampoline(Thread* self,
// We can set the entrypoint of a native method to generic JNI even when the
// class hasn't been initialized, so we need to do the initialization check
// before invoking the native code.
- if (NeedsClinitCheckBeforeCall(called)) {
- ObjPtr<mirror::Class> declaring_class = called->GetDeclaringClass();
- if (UNLIKELY(!declaring_class->IsVisiblyInitialized())) {
- // Ensure static method's class is initialized.
- StackHandleScope<1> hs(self);
- Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
- if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
- DCHECK(Thread::Current()->IsExceptionPending()) << called->PrettyMethod();
- return nullptr; // Report error.
- }
+ if (called->StillNeedsClinitCheck()) {
+ // Ensure static method's class is initialized.
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class = hs.NewHandle(called->GetDeclaringClass());
+ if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
+ DCHECK(Thread::Current()->IsExceptionPending()) << called->PrettyMethod();
+ return nullptr; // Report error.
}
}
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 6c68cdb701..1d0e22fd90 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -251,8 +251,7 @@ static bool CodeNeedsEntryExitStub(const void* entry_point, ArtMethod* method)
static void UpdateEntryPoints(ArtMethod* method, const void* quick_code)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (kIsDebugBuild) {
- if (NeedsClinitCheckBeforeCall(method) &&
- !method->GetDeclaringClass()->IsVisiblyInitialized()) {
+ if (method->StillNeedsClinitCheckMayBeDead()) {
CHECK(CanHandleInitializationCheck(quick_code));
}
jit::Jit* jit = Runtime::Current()->GetJit();
@@ -379,7 +378,7 @@ void Instrumentation::InitializeMethodsCode(ArtMethod* method, const void* aot_c
}
// Special case if we need an initialization check.
- if (NeedsClinitCheckBeforeCall(method) && !method->GetDeclaringClass()->IsVisiblyInitialized()) {
+ if (method->StillNeedsClinitCheck()) {
// If we have code but the method needs a class initialization check before calling
// that code, install the resolution stub that will perform the check.
// It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
@@ -449,7 +448,7 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
// We're being asked to restore the entrypoints after instrumentation.
CHECK_EQ(instrumentation_level_, InstrumentationLevel::kInstrumentNothing);
// We need to have the resolution stub still if the class is not initialized.
- if (NeedsClinitCheckBeforeCall(method) && !method->GetDeclaringClass()->IsVisiblyInitialized()) {
+ if (method->StillNeedsClinitCheck()) {
UpdateEntryPoints(method, GetQuickResolutionStub());
return;
}
@@ -1248,8 +1247,7 @@ void Instrumentation::Undeoptimize(ArtMethod* method) {
// We still retain interpreter bridge if we need it for other reasons.
if (InterpretOnly(method)) {
UpdateEntryPoints(method, GetQuickToInterpreterBridge());
- } else if (NeedsClinitCheckBeforeCall(method) &&
- !method->GetDeclaringClass()->IsVisiblyInitialized()) {
+ } else if (method->StillNeedsClinitCheck()) {
if (EntryExitStubsInstalled()) {
UpdateEntryPoints(method, GetQuickInstrumentationEntryPoint());
} else {
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 2cc4aef27a..abade3a7d3 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -1808,8 +1808,7 @@ void Jit::MaybeEnqueueCompilation(ArtMethod* method, Thread* self) {
// Check if we have precompiled this method.
if (UNLIKELY(method->IsPreCompiled())) {
- if (!NeedsClinitCheckBeforeCall(method) ||
- method->GetDeclaringClass()->IsVisiblyInitialized()) {
+ if (!method->StillNeedsClinitCheck()) {
const void* entry_point = code_cache_->GetSavedEntryPointOfPreCompiledMethod(method);
if (entry_point != nullptr) {
Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(method, entry_point);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index ee5d5c7ce3..86eedca285 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -127,31 +127,19 @@ class JitCodeCache::JniStubData {
DCHECK(entrypoint == OatQuickMethodHeader::FromCodePointer(GetCode())->GetEntryPoint());
instrumentation::Instrumentation* instrum = Runtime::Current()->GetInstrumentation();
for (ArtMethod* m : GetMethods()) {
- // Because `m` might be in the process of being deleted:
- // - Call the dedicated method instead of the more generic UpdateMethodsCode
- // - Check the class status without a full read barrier; use ReadBarrier::IsMarked().
- bool can_set_entrypoint = true;
- if (NeedsClinitCheckBeforeCall(m)) {
- // To avoid resurrecting an unreachable object, we must not use a full read
- // barrier but we do not want to miss updating an entrypoint under common
- // circumstances, i.e. during a GC the class becomes visibly initialized,
- // the method becomes hot, we compile the thunk and want to update the
- // entrypoint while the method's declaring class field still points to the
- // from-space class object with the old status. Therefore we read the
- // declaring class without a read barrier and check if it's already marked.
- // If yes, we check the status of the to-space class object as intended.
- // Otherwise, there is no to-space object and the from-space class object
- // contains the most recent value of the status field; even if this races
- // with another thread doing a read barrier and updating the status, that's
- // no different from a race with a thread that just updates the status.
- // Such race can happen only for the zygote method pre-compilation, as we
- // otherwise compile only thunks for methods of visibly initialized classes.
- ObjPtr<mirror::Class> klass = m->GetDeclaringClass<kWithoutReadBarrier>();
- ObjPtr<mirror::Class> marked = ReadBarrier::IsMarked(klass.Ptr());
- ObjPtr<mirror::Class> checked_klass = (marked != nullptr) ? marked : klass;
- can_set_entrypoint = checked_klass->IsVisiblyInitialized();
- }
- if (can_set_entrypoint) {
+ // Because `m` might be in the process of being deleted,
+ // - use the `ArtMethod::StillNeedsClinitCheckMayBeDead()` to check if
+ // we can update the entrypoint, and
+ // - call `Instrumentation::UpdateNativeMethodsCodeToJitCode` instead of the
+ // more generic function `Instrumentation::UpdateMethodsCode()`.
+ // The `ArtMethod::StillNeedsClinitCheckMayBeDead()` checks the class status
+ // in the to-space object if any even if the method's declaring class points to
+ // the from-space class object. This way we do not miss updating an entrypoint
+ // even under uncommon circumstances, when during a GC the class becomes visibly
+ // initialized, the method becomes hot, we compile the thunk and want to update
+ // the entrypoint while the method's declaring class field still points to the
+ // from-space class object with the old status.
+ if (!m->StillNeedsClinitCheckMayBeDead()) {
instrum->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
}
}
@@ -741,8 +729,7 @@ bool JitCodeCache::Commit(Thread* self,
}
if (compilation_kind == CompilationKind::kOsr) {
osr_code_map_.Put(method, code_ptr);
- } else if (NeedsClinitCheckBeforeCall(method) &&
- !method->GetDeclaringClass()->IsVisiblyInitialized()) {
+ } else if (method->StillNeedsClinitCheck()) {
// This situation currently only occurs in the jit-zygote mode.
DCHECK(!garbage_collect_code_);
DCHECK(method->IsPreCompiled());
@@ -1636,7 +1623,7 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method,
}
}
- if (NeedsClinitCheckBeforeCall(method) && !prejit) {
+ if (method->NeedsClinitCheckBeforeCall() && !prejit) {
// We do not need a synchronization barrier for checking the visibly initialized status
// or checking the initialized status just for requesting visible initialization.
ClassStatus status = method->GetDeclaringClass()
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index 9c695ca513..b4e7938e91 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -1157,7 +1157,7 @@ void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m, std::string* error_msg, b
CHECK(m->IsNative());
ObjPtr<mirror::Class> c = m->GetDeclaringClass();
// If this is a static method, it could be called before the class has been initialized.
- CHECK(c->IsInitializing() || !NeedsClinitCheckBeforeCall(m))
+ CHECK(c->IsInitializing() || !m->NeedsClinitCheckBeforeCall())
<< c->GetStatus() << " " << m->PrettyMethod();
Thread* const self = Thread::Current();
void* native_method = libraries_->FindNativeMethod(self, m, error_msg, can_suspend);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 521e7c6764..f60d016230 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -726,7 +726,7 @@ class UpdateMethodsPreFirstForkVisitor : public ClassVisitor {
bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
bool is_initialized = klass->IsVisiblyInitialized();
for (ArtMethod& method : klass->GetDeclaredMethods(kRuntimePointerSize)) {
- if (is_initialized || !NeedsClinitCheckBeforeCall(&method)) {
+ if (is_initialized || !method.NeedsClinitCheckBeforeCall()) {
if (method.IsNative()) {
const void* existing = method.GetEntryPointFromJni();
if (method.IsCriticalNative()