summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/common_compiler_test.cc10
-rw-r--r--openjdkjvmti/events.cc2
-rw-r--r--openjdkjvmti/ti_redefine.cc4
-rw-r--r--runtime/class_linker.cc35
-rw-r--r--runtime/class_linker.h4
-rw-r--r--runtime/common_runtime_test.cc2
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc2
-rw-r--r--runtime/instrumentation.cc28
-rw-r--r--runtime/instrumentation.h8
-rw-r--r--runtime/jit/jit_code_cache.cc11
-rw-r--r--runtime/quick_exception_handler.cc5
-rw-r--r--runtime/runtime.cc6
-rw-r--r--runtime/runtime_callbacks_test.cc2
13 files changed, 81 insertions, 38 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index bbb2016566..1b69f2a1d4 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -149,18 +149,20 @@ const void* CommonCompilerTestImpl::MakeExecutable(ArrayRef<const uint8_t> code,
void CommonCompilerTestImpl::MakeExecutable(ArtMethod* method,
const CompiledMethod* compiled_method) {
CHECK(method != nullptr);
- const void* method_code = nullptr;
// If the code size is 0 it means the method was skipped due to profile guided compilation.
if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0u) {
const void* code_ptr = MakeExecutable(compiled_method->GetQuickCode(),
compiled_method->GetVmapTable(),
compiled_method->GetInstructionSet());
- method_code =
+ const void* method_code =
CompiledMethod::CodePointer(code_ptr, compiled_method->GetInstructionSet());
LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
+ method->SetEntryPointFromQuickCompiledCode(method_code);
+ } else {
+ // No code? You must mean to go into the interpreter.
+ // Or the generic JNI...
+ GetClassLinker()->SetEntryPointsToInterpreter(method);
}
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(
- method, /*aot_code=*/ method_code);
}
void CommonCompilerTestImpl::SetUp() {
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index a6425af621..c69ee7b480 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -1260,7 +1260,7 @@ void EventHandler::HandleLocalAccessCapabilityAdded() {
continue;
} else if (!runtime_->GetClassLinker()->IsQuickToInterpreterBridge(code) &&
!runtime_->IsAsyncDeoptimizeable(reinterpret_cast<uintptr_t>(code))) {
- runtime_->GetInstrumentation()->InitializeMethodsCode(&m, /*aot_code=*/ nullptr);
+ runtime_->GetInstrumentation()->UpdateMethodsCodeToInterpreterEntryPoint(&m);
}
}
return true;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index c234bd42fe..37a61d3c54 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -2116,7 +2116,7 @@ art::ObjPtr<art::mirror::Class> Redefiner::ClassRedefinition::AllocateNewClassOb
}
// Finish setting up methods.
linked_class->VisitMethods([&](art::ArtMethod* m) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- driver_->runtime_->GetInstrumentation()->InitializeMethodsCode(m, /* aot_code= */ nullptr);
+ linker->SetEntryPointsToInterpreter(m);
m->SetNotIntrinsic();
DCHECK(m->IsCopied() || m->GetDeclaringClass() == linked_class.Get())
<< m->PrettyMethod()
@@ -2543,7 +2543,7 @@ void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class>
CHECK(method_id != nullptr);
uint32_t dex_method_idx = dex_file_->GetIndexForMethodId(*method_id);
method.SetDexMethodIndex(dex_method_idx);
- driver_->runtime_->GetInstrumentation()->InitializeMethodsCode(&method, /*aot_code=*/ nullptr);
+ linker->SetEntryPointsToInterpreter(&method);
if (method.HasCodeItem()) {
method.SetCodeItem(
dex_file_->GetCodeItem(dex_file_->FindCodeItemOffset(class_def, dex_method_idx)),
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 62dd4d2110..d2ab81e7cf 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -201,6 +201,22 @@ static void HandleEarlierErroneousStateError(Thread* self,
self->AssertPendingException();
}
+static void ChangeInterpreterBridgeToNterp(ArtMethod* method, ClassLinker* class_linker)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ Runtime* runtime = Runtime::Current();
+ if (class_linker->IsQuickToInterpreterBridge(method->GetEntryPointFromQuickCompiledCode()) &&
+ CanMethodUseNterp(method)) {
+ if (method->GetDeclaringClass()->IsVisiblyInitialized() ||
+ !NeedsClinitCheckBeforeCall(method)) {
+ runtime->GetInstrumentation()->UpdateMethodsCode(method, interpreter::GetNterpEntryPoint());
+ } else {
+ // Put the resolution stub, which will initialize the class and then
+ // call the method with nterp.
+ runtime->GetInstrumentation()->UpdateMethodsCode(method, GetQuickResolutionStub());
+ }
+ }
+}
+
static void UpdateClassAfterVerification(Handle<mirror::Class> klass,
PointerSize pointer_size,
verifier::FailureKind failure_kind)
@@ -215,9 +231,7 @@ static void UpdateClassAfterVerification(Handle<mirror::Class> klass,
// to methods that currently use the switch interpreter.
if (interpreter::CanRuntimeUseNterp()) {
for (ArtMethod& m : klass->GetMethods(pointer_size)) {
- if (class_linker->IsQuickToInterpreterBridge(m.GetEntryPointFromQuickCompiledCode())) {
- runtime->GetInstrumentation()->InitializeMethodsCode(&m, /*aot_code=*/nullptr);
- }
+ ChangeInterpreterBridgeToNterp(&m, class_linker);
}
}
}
@@ -1959,11 +1973,10 @@ bool ClassLinker::AddImageSpace(
// reset it with the runtime value.
method.ResetCounter(hotness_threshold);
}
+ // Set image methods' entry point that point to the interpreter bridge to the
+ // nterp entry point.
if (method.GetEntryPointFromQuickCompiledCode() == nterp_trampoline_) {
if (can_use_nterp) {
- // 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(!NeedsClinitCheckBeforeCall(&method) ||
method.GetDeclaringClass()->IsVisiblyInitialized());
method.SetEntryPointFromQuickCompiledCode(interpreter::GetNterpEntryPoint());
@@ -3340,7 +3353,6 @@ void ClassLinker::FixupStaticTrampolines(Thread* self, ObjPtr<mirror::Class> kla
return;
}
- instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
// Link the code of methods skipped by LinkCode.
for (size_t method_index = 0; method_index < num_direct_methods; ++method_index) {
ArtMethod* method = klass->GetDirectMethod(method_index, pointer_size);
@@ -3348,6 +3360,7 @@ void ClassLinker::FixupStaticTrampolines(Thread* self, ObjPtr<mirror::Class> kla
// Only update static methods.
continue;
}
+ instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
instrumentation->UpdateMethodsCode(method, instrumentation->GetCodeForInvoke(method));
}
// Ignore virtual methods on the iterator.
@@ -9643,6 +9656,14 @@ const void* ClassLinker::GetRuntimeQuickGenericJniStub() const {
return GetQuickGenericJniStub();
}
+void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const {
+ if (!method->IsNative()) {
+ method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+ } else {
+ method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
+ }
+}
+
void ClassLinker::SetEntryPointsForObsoleteMethod(ArtMethod* method) const {
DCHECK(method->IsObsolete());
// We cannot mess with the entrypoints of native methods because they are used to determine how
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7ba62f4e89..b0c02e538e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -620,6 +620,10 @@ class ClassLinker {
return intern_table_;
}
+ // Set the entrypoints up for method to the enter the interpreter.
+ void SetEntryPointsToInterpreter(ArtMethod* method) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
// Set the entrypoints up for an obsolete method.
void SetEntryPointsForObsoleteMethod(ArtMethod* method) const
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 6ff4f1a3f8..f949759df2 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -400,7 +400,7 @@ void CommonRuntimeTestImpl::SetUpRuntimeOptionsForFillHeap(RuntimeOptions *optio
void CommonRuntimeTestImpl::MakeInterpreted(ObjPtr<mirror::Class> klass) {
PointerSize pointer_size = class_linker_->GetImagePointerSize();
for (ArtMethod& method : klass->GetMethods(pointer_size)) {
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(&method, /*aot_code=*/ nullptr);
+ class_linker_->SetEntryPointsToInterpreter(&method);
}
}
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 926d534496..027bda5299 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1052,7 +1052,7 @@ extern "C" const void* artInstrumentationMethodEntryFromCode(ArtMethod* method,
!jit->GetCodeCache()->ContainsPc(result))
<< method->PrettyMethod() << " code will jump to possibly cleaned up jit code!";
- bool interpreter_entry = Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(result);
+ bool interpreter_entry = (result == GetQuickToInterpreterBridge());
bool is_static = method->IsStatic();
uint32_t shorty_len;
const char* shorty =
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 65123ffe5a..71d48ee025 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -375,7 +375,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 (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
@@ -397,17 +397,10 @@ void Instrumentation::InitializeMethodsCode(ArtMethod* method, const void* aot_c
return;
}
- // We check if the class is verified as we need the slow interpreter for lock verification.
- // If the class is not verified, This will be updated in
- // ClassLinker::UpdateClassAfterVerification.
- if (interpreter::CanRuntimeUseNterp() &&
- CanMethodUseNterp(method) &&
- method->GetDeclaringClass()->IsVerified()) {
- UpdateEntryPoints(method, interpreter::GetNterpEntryPoint());
- 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());
}
@@ -1107,6 +1100,19 @@ void Instrumentation::UpdateMethodsCode(ArtMethod* method, const void* new_code)
UpdateMethodsCodeImpl(method, new_code);
}
+void Instrumentation::UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method) {
+ UpdateMethodsCodeImpl(method, GetQuickToInterpreterBridge());
+}
+
+void Instrumentation::UpdateMethodsCodeForJavaDebuggable(ArtMethod* method,
+ 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, new_code);
+}
+
bool Instrumentation::AddDeoptimizedMethod(ArtMethod* method) {
if (IsDeoptimizedMethod(method)) {
// Already in the map. Return.
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index d4cb85bbd7..276d1ca2fc 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -312,6 +312,14 @@ class Instrumentation {
void UpdateNativeMethodsCodeToJitCode(ArtMethod* method, const void* new_code)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!GetDeoptimizedMethodsLock());
+ // Update the code of a method to the interpreter respecting any installed stubs from debugger.
+ void UpdateMethodsCodeToInterpreterEntryPoint(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!GetDeoptimizedMethodsLock());
+
+ // Update the code of a method respecting any installed stubs from debugger.
+ void UpdateMethodsCodeForJavaDebuggable(ArtMethod* method, const void* new_code)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!GetDeoptimizedMethodsLock());
+
// Return the code that we can execute for an invoke including from the JIT.
const void* GetCodeForInvoke(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 34ddfc4233..8b91f9eee1 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -793,7 +793,8 @@ bool JitCodeCache::RemoveMethod(ArtMethod* method, bool release_memory) {
}
ClearMethodCounter(method, /* was_warm= */ false);
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr);
+ Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+ method, GetQuickToInterpreterBridge());
VLOG(jit)
<< "JIT removed (osr=" << std::boolalpha << osr << std::noboolalpha << ") "
<< ArtMethod::PrettyMethod(method) << "@" << method
@@ -1317,8 +1318,7 @@ void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
OatQuickMethodHeader::FromEntryPoint(entry_point);
if (CodeInfo::IsBaseline(method_header->GetOptimizedCodeInfoPtr())) {
info->GetMethod()->ResetCounter(warmup_threshold);
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(
- info->GetMethod(), /*aot_code=*/ nullptr);
+ info->GetMethod()->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
}
}
}
@@ -1744,7 +1744,7 @@ void JitCodeCache::InvalidateAllCompiledCode() {
if (meth->IsObsolete()) {
linker->SetEntryPointsForObsoleteMethod(meth);
} else {
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(meth, /*aot_code=*/ nullptr);
+ linker->SetEntryPointsToInterpreter(meth);
}
}
saved_compiled_methods_map_.clear();
@@ -1761,7 +1761,8 @@ void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method,
if (method_entrypoint == header->GetEntryPoint()) {
// The entrypoint is the one to invalidate, so we just update it to the interpreter entry point
// and clear the counter to get the method Jitted again.
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr);
+ Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+ method, GetQuickToInterpreterBridge());
ClearMethodCounter(method, /*was_warm=*/ true);
} else {
MutexLock mu(Thread::Current(), *Locks::jit_lock_);
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index c3722484ca..ac5065b2a6 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -606,8 +606,9 @@ void QuickExceptionHandler::DeoptimizeSingleFrame(DeoptimizationKind kind) {
Runtime::Current()->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor(
deopt_method, visitor.GetSingleFrameDeoptQuickMethodHeader());
} else {
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(
- deopt_method, /*aot_code=*/ nullptr);
+ // Transfer the code to interpreter.
+ Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+ deopt_method, GetQuickToInterpreterBridge());
}
PrepareForLongJumpToInvokeStubOrInterpreterBridge();
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index afa8504389..54e9d38b3c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -3095,21 +3095,21 @@ class UpdateEntryPointsClassVisitor : public ClassVisitor {
if (Runtime::Current()->GetHeap()->IsInBootImageOatFile(code) &&
!m.IsNative() &&
!m.IsProxyMethod()) {
- instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr);
+ instrumentation_->UpdateMethodsCodeForJavaDebuggable(&m, GetQuickToInterpreterBridge());
}
if (Runtime::Current()->GetJit() != nullptr &&
Runtime::Current()->GetJit()->GetCodeCache()->IsInZygoteExecSpace(code) &&
!m.IsNative()) {
DCHECK(!m.IsProxyMethod());
- instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr);
+ instrumentation_->UpdateMethodsCodeForJavaDebuggable(&m, GetQuickToInterpreterBridge());
}
if (m.IsPreCompiled()) {
// Precompilation is incompatible with debuggable, so clear the flag
// and update the entrypoint in case it has been compiled.
m.ClearPreCompiled();
- instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr);
+ instrumentation_->UpdateMethodsCodeForJavaDebuggable(&m, GetQuickToInterpreterBridge());
}
}
return true;
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index 7f64721a4f..7619750032 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -80,7 +80,7 @@ class RuntimeCallbacksTest : public CommonRuntimeTest {
PointerSize pointer_size = class_linker_->GetImagePointerSize();
for (auto& m : klass->GetMethods(pointer_size)) {
if (!m.IsAbstract()) {
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(&m, /*aot_code=*/ nullptr);
+ class_linker_->SetEntryPointsToInterpreter(&m);
}
}
}