summaryrefslogtreecommitdiff
path: root/runtime/instrumentation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/instrumentation.cc')
-rw-r--r--runtime/instrumentation.cc150
1 files changed, 119 insertions, 31 deletions
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index f1b52e0a40..d3e631cd64 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -211,7 +211,7 @@ static bool CanHandleInitializationCheck(const void* code) {
(code == GetQuickInstrumentationEntryPoint());
}
-static void UpdateEntrypoints(ArtMethod* method, const void* quick_code)
+static void UpdateEntryPoints(ArtMethod* method, const void* quick_code)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (kIsDebugBuild) {
if (NeedsClinitCheckBeforeCall(method) &&
@@ -226,7 +226,11 @@ static void UpdateEntrypoints(ArtMethod* method, const void* quick_code)
}
}
}
- method->SetEntryPointFromQuickCompiledCode(quick_code);
+ // If the method is from a boot image, don't dirty it if the entrypoint
+ // doesn't change.
+ if (method->GetEntryPointFromQuickCompiledCode() != quick_code) {
+ method->SetEntryPointFromQuickCompiledCode(quick_code);
+ }
}
bool Instrumentation::CodeNeedsEntryExitStub(const void* code, ArtMethod* method) {
@@ -289,6 +293,35 @@ bool Instrumentation::InterpretOnly(ArtMethod* method) REQUIRES_SHARED(Locks::mu
Runtime::Current()->GetRuntimeCallbacks()->MethodNeedsDebugVersion(method);
}
+static bool CanUseAotCode(ArtMethod* method, const void* quick_code)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (quick_code == nullptr) {
+ return false;
+ }
+ if (method->IsNative()) {
+ // AOT code for native methods can always be used.
+ return true;
+ }
+
+ Runtime* runtime = Runtime::Current();
+ // For simplicity, we never use AOT code for debuggable.
+ if (runtime->IsJavaDebuggable()) {
+ return false;
+ }
+
+ if (runtime->IsNativeDebuggable()) {
+ DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse());
+ // If we are doing native debugging, ignore application's AOT code,
+ // since we want to JIT it (at first use) with extra stackmaps for native
+ // debugging. We keep however all AOT code from the boot image,
+ // since the JIT-at-first-use is blocking and would result in non-negligible
+ // startup performance impact.
+ return runtime->GetHeap()->IsInBootImageOatFile(quick_code);
+ }
+
+ return true;
+}
+
static const void* GetOptimizedCodeFor(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!Runtime::Current()->GetInstrumentation()->InterpretOnly(method));
CHECK(method->IsInvokable()) << method->PrettyMethod();
@@ -297,12 +330,10 @@ static const void* GetOptimizedCodeFor(ArtMethod* method) REQUIRES_SHARED(Locks:
}
// In debuggable mode, we can only use AOT code for native methods.
- if (!Runtime::Current()->IsJavaDebuggable() || method->IsNative()) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const void* code = method->GetOatMethodQuickCode(class_linker->GetImagePointerSize());
- if (code != nullptr) {
- return code;
- }
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const void* aot_code = method->GetOatMethodQuickCode(class_linker->GetImagePointerSize());
+ if (CanUseAotCode(method, aot_code)) {
+ return aot_code;
}
// If the method has been precompiled, there can be a JIT version.
@@ -314,13 +345,67 @@ static const void* GetOptimizedCodeFor(ArtMethod* method) REQUIRES_SHARED(Locks:
}
}
- if (interpreter::CanRuntimeUseNterp() && CanMethodUseNterp(method)) {
+ // We need to check if the class has been verified for setting up nterp, as
+ // the verifier could punt the method to the switch interpreter in case we
+ // need to do lock counting.
+ if (interpreter::CanRuntimeUseNterp() &&
+ CanMethodUseNterp(method) &&
+ method->GetDeclaringClass()->IsVerified()) {
return interpreter::GetNterpEntryPoint();
}
return method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge();
}
+void Instrumentation::InitializeMethodsCode(ArtMethod* method, const void* aot_code)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Use instrumentation entrypoints if instrumentation is installed.
+ if (UNLIKELY(EntryExitStubsInstalled())) {
+ if (!method->IsNative() && InterpretOnly()) {
+ UpdateEntryPoints(method, GetQuickToInterpreterBridge());
+ } else {
+ UpdateEntryPoints(method, GetQuickInstrumentationEntryPoint());
+ }
+ return;
+ }
+
+ if (UNLIKELY(IsForcedInterpretOnly())) {
+ UpdateEntryPoints(
+ method, method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge());
+ return;
+ }
+
+ // Special case if we need an initialization check.
+ if (NeedsClinitCheckBeforeCall(method)) {
+ // 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
+ // after initializing class (see ClassLinker::InitializeClass method).
+ // Note: this mimics the logic in image_writer.cc that installs the resolution
+ // stub only if we have compiled code and the method needs a class initialization
+ // check.
+ if (aot_code != nullptr || method->IsNative()) {
+ UpdateEntryPoints(method, GetQuickResolutionStub());
+ } else {
+ UpdateEntryPoints(method, GetQuickToInterpreterBridge());
+ }
+ return;
+ }
+
+ // Use the provided AOT code if possible.
+ if (CanUseAotCode(method, aot_code)) {
+ UpdateEntryPoints(method, aot_code);
+ return;
+ }
+
+ // Use default entrypoints.
+ // Note we cannot use the nterp entrypoint because we do not know if the
+ // method will need the slow interpreter for lock verification. This will
+ // be updated in ClassLinker::UpdateClassAfterVerification.
+ UpdateEntryPoints(
+ method, method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge());
+}
+
void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
if (!method->IsInvokable() || method->IsProxyMethod()) {
// Do not change stubs for these methods.
@@ -336,14 +421,14 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
// If the instrumentation needs to go through the interpreter, just update the
// entrypoint to interpreter.
if (InterpretOnly(method)) {
- UpdateEntrypoints(method, GetQuickToInterpreterBridge());
+ UpdateEntryPoints(method, GetQuickToInterpreterBridge());
return;
}
if (EntryExitStubsInstalled()) {
// Install the instrumentation entry point if needed.
if (CodeNeedsEntryExitStub(method->GetEntryPointFromQuickCompiledCode(), method)) {
- UpdateEntrypoints(method, GetQuickInstrumentationEntryPoint());
+ UpdateEntryPoints(method, GetQuickInstrumentationEntryPoint());
}
return;
}
@@ -352,10 +437,10 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
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()) {
- UpdateEntrypoints(method, GetQuickResolutionStub());
+ UpdateEntryPoints(method, GetQuickResolutionStub());
return;
}
- UpdateEntrypoints(method, GetOptimizedCodeFor(method));
+ UpdateEntryPoints(method, GetOptimizedCodeFor(method));
}
// Places the instrumentation exit pc as the return PC for every quick frame. This also allows
@@ -943,7 +1028,7 @@ void Instrumentation::ResetQuickAllocEntryPoints() {
}
}
-static std::string EntrypointString(const void* code) {
+std::string Instrumentation::EntryPointString(const void* code) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
jit::Jit* jit = Runtime::Current()->GetJit();
if (class_linker->IsQuickToInterpreterBridge(code)) {
@@ -966,38 +1051,41 @@ static std::string EntrypointString(const void* code) {
return "unknown";
}
-void Instrumentation::UpdateMethodsCodeImpl(ArtMethod* method, const void* quick_code) {
+void Instrumentation::UpdateMethodsCodeImpl(ArtMethod* method, const void* new_code) {
if (!EntryExitStubsInstalled()) {
// Fast path: no instrumentation.
DCHECK(!IsDeoptimized(method));
- UpdateEntrypoints(method, quick_code);
+ UpdateEntryPoints(method, new_code);
return;
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (class_linker->IsQuickToInterpreterBridge(quick_code)) {
+ if (class_linker->IsQuickToInterpreterBridge(new_code)) {
// It's always OK to update to the interpreter.
- UpdateEntrypoints(method, quick_code);
+ UpdateEntryPoints(method, new_code);
return;
}
if (IsDeoptimized(method)) {
DCHECK(class_linker->IsQuickToInterpreterBridge(method->GetEntryPointFromQuickCompiledCode()))
- << EntrypointString(method->GetEntryPointFromQuickCompiledCode());
+ << EntryPointString(method->GetEntryPointFromQuickCompiledCode());
// Don't update, stay deoptimized.
return;
}
- if (CodeNeedsEntryExitStub(quick_code, method)) {
+ if (CodeNeedsEntryExitStub(new_code, method)) {
+ DCHECK(method->GetEntryPointFromQuickCompiledCode() == GetQuickInstrumentationEntryPoint() ||
+ class_linker->IsQuickToInterpreterBridge(method->GetEntryPointFromQuickCompiledCode()))
+ << EntryPointString(method->GetEntryPointFromQuickCompiledCode());
// If the code we want to update the method with still needs entry/exit stub, just skip.
return;
}
// At this point, we can update as asked.
- UpdateEntrypoints(method, quick_code);
+ UpdateEntryPoints(method, new_code);
}
-void Instrumentation::UpdateNativeMethodsCodeToJitCode(ArtMethod* method, const void* quick_code) {
+void Instrumentation::UpdateNativeMethodsCodeToJitCode(ArtMethod* method, const void* new_code) {
// We don't do any read barrier on `method`'s declaring class in this code, as the JIT might
// enter here on a soon-to-be deleted ArtMethod. Updating the entrypoint is OK though, as
// the ArtMethod is still in memory.
@@ -1005,12 +1093,12 @@ void Instrumentation::UpdateNativeMethodsCodeToJitCode(ArtMethod* method, const
// If stubs are installed don't update.
return;
}
- UpdateEntrypoints(method, quick_code);
+ UpdateEntryPoints(method, new_code);
}
-void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* quick_code) {
+void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* new_code) {
DCHECK(method->GetDeclaringClass()->IsResolved());
- UpdateMethodsCodeImpl(method, quick_code);
+ UpdateMethodsCodeImpl(method, new_code);
}
void Instrumentation::UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method) {
@@ -1018,12 +1106,12 @@ void Instrumentation::UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method
}
void Instrumentation::UpdateMethodsCodeForJavaDebuggable(ArtMethod* method,
- const void* quick_code) {
+ const void* new_code) {
// When the runtime is set to Java debuggable, we may update the entry points of
// all methods of a class to the interpreter bridge. A method's declaring class
// might not be in resolved state yet in that case, so we bypass the DCHECK in
// UpdateMethodsCode.
- UpdateMethodsCodeImpl(method, quick_code);
+ UpdateMethodsCodeImpl(method, new_code);
}
bool Instrumentation::AddDeoptimizedMethod(ArtMethod* method) {
@@ -1074,7 +1162,7 @@ void Instrumentation::Deoptimize(ArtMethod* method) {
<< " is already deoptimized";
}
if (!InterpreterStubsInstalled()) {
- UpdateEntrypoints(method, GetQuickToInterpreterBridge());
+ UpdateEntryPoints(method, GetQuickToInterpreterBridge());
// Install instrumentation exit stub and instrumentation frames. We may already have installed
// these previously so it will only cover the newly created frames.
@@ -1108,12 +1196,12 @@ void Instrumentation::Undeoptimize(ArtMethod* method) {
if (!InterpreterStubsInstalled()) {
// Restore its code or resolution trampoline.
if (InterpretOnly(method)) {
- UpdateEntrypoints(method, GetQuickToInterpreterBridge());
+ UpdateEntryPoints(method, GetQuickToInterpreterBridge());
} else if (NeedsClinitCheckBeforeCall(method) &&
!method->GetDeclaringClass()->IsVisiblyInitialized()) {
- UpdateEntrypoints(method, GetQuickResolutionStub());
+ UpdateEntryPoints(method, GetQuickResolutionStub());
} else {
- UpdateEntrypoints(method, GetOptimizedCodeFor(method));
+ UpdateEntryPoints(method, GetOptimizedCodeFor(method));
}
// If there is no deoptimized method left, we can restore the stack of each thread.