Support running clinit in instrumentation trampolines.
This helps in being consistent when setting up the instrumentaton.
Test: test.py
Change-Id: I260083fe944890cefdb0d74f320d61be37e6c4c3
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 3488cef..03e0be4 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1065,8 +1065,21 @@
RememberForGcArgumentVisitor visitor(sp, is_static, shorty, shorty_len, &soa);
visitor.VisitArguments();
+ 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 (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
+ visitor.FixupReferences();
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+ }
+
instrumentation->PushInstrumentationStackFrame(self,
- is_static ? nullptr : this_object,
+ is_static ? nullptr : h_object.Get(),
method,
reinterpret_cast<uintptr_t>(
QuickArgumentVisitor::GetCallingPcAddr(sp)),
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 8ef5ef4..7449408 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -255,6 +255,14 @@
return true;
}
+static bool CanHandleInitializationCheck(const void* code) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->IsQuickResolutionStub(code) ||
+ class_linker->IsQuickToInterpreterBridge(code) ||
+ class_linker->IsQuickGenericJniStub(code) ||
+ (code == GetQuickInstrumentationEntryPoint());
+}
+
void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
if (!method->IsInvokable() || method->IsProxyMethod()) {
// Do not change stubs for these methods.
@@ -277,45 +285,42 @@
bool uninstall = (instrumentation_level_ == InstrumentationLevel::kInstrumentNothing);
Runtime* const runtime = Runtime::Current();
ClassLinker* const class_linker = runtime->GetClassLinker();
- bool is_class_initialized = method->GetDeclaringClass()->IsInitialized();
+ bool needs_clinit =
+ NeedsClinitCheckBeforeCall(method) && !method->GetDeclaringClass()->IsVisiblyInitialized();
if (uninstall) {
if ((forced_interpret_only_ || IsDeoptimized(method)) && !method->IsNative()) {
new_quick_code = GetQuickToInterpreterBridge();
- } else if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
- new_quick_code = GetCodeForInvoke(method);
- } else {
+ } else if (needs_clinit) {
new_quick_code = GetQuickResolutionStub();
+ } else {
+ new_quick_code = GetCodeForInvoke(method);
}
} else { // !uninstall
if ((InterpretOnly() || IsDeoptimized(method)) && !method->IsNative()) {
new_quick_code = GetQuickToInterpreterBridge();
} else {
- // Do not overwrite resolution trampoline. When the trampoline initializes the method's
- // class, all its static methods code will be set to the instrumentation entry point.
- // For more details, see ClassLinker::FixupStaticTrampolines.
- if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
- if (EntryExitStubsInstalled()) {
- // This needs to be checked first since the instrumentation entrypoint will be able to
- // find the actual JIT compiled code that corresponds to this method.
- const void* code = method->GetEntryPointFromQuickCompiledCodePtrSize(kRuntimePointerSize);
- if (CodeNeedsEntryExitStub(code, method)) {
- new_quick_code = GetQuickInstrumentationEntryPoint();
- } else {
- new_quick_code = code;
- }
- } else if (NeedDebugVersionFor(method)) {
- // It would be great to search the JIT for its implementation here but we cannot due to
- // the locks we hold. Instead just set to the interpreter bridge and that code will search
- // the JIT when it gets called and replace the entrypoint then.
- new_quick_code = GetQuickToInterpreterBridge();
+ if (EntryExitStubsInstalled()) {
+ // This needs to be checked first since the instrumentation entrypoint will be able to
+ // find the actual JIT compiled code that corresponds to this method.
+ const void* code = method->GetEntryPointFromQuickCompiledCodePtrSize(kRuntimePointerSize);
+ if (CodeNeedsEntryExitStub(code, method)) {
+ new_quick_code = GetQuickInstrumentationEntryPoint();
} else {
- new_quick_code = class_linker->GetQuickOatCodeFor(method);
+ new_quick_code = code;
}
+ } else if (NeedDebugVersionFor(method)) {
+ // It would be great to search the JIT for its implementation here but we cannot due to
+ // the locks we hold. Instead just set to the interpreter bridge and that code will search
+ // the JIT when it gets called and replace the entrypoint then.
+ new_quick_code = GetQuickToInterpreterBridge();
} else {
- new_quick_code = GetQuickResolutionStub();
+ new_quick_code = class_linker->GetQuickOatCodeFor(method);
}
}
}
+ if (kIsDebugBuild && needs_clinit) {
+ CHECK(CanHandleInitializationCheck(method->GetEntryPointFromQuickCompiledCode()));
+ }
UpdateEntrypoints(method, new_quick_code);
}