Add an implementation of Nterp for x64.
And enable it on x64 when runtime and ArtMethod requirements are met
(see nterp.cc).
Test: test.py
Bug: 112676029
Change-Id: I772cd20a20fdc0ff99529df7495801d773091584
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index a0a2365..ffa772e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -143,6 +143,8 @@
#include "verifier/class_verifier.h"
#include "well_known_classes.h"
+#include "interpreter/interpreter_mterp_impl.h"
+
namespace art {
using android::base::StringPrintf;
@@ -224,16 +226,25 @@
// Ensures that methods have the kAccSkipAccessChecks bit set. We use the
// kAccVerificationAttempted bit on the class access flags to determine whether this has been done
// before.
-template <bool kNeedsVerified = false>
static void EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_) {
- if (kNeedsVerified) {
- // To not fail access-flags access checks, push a minimal state.
- mirror::Class::SetStatus(klass, ClassStatus::kVerified, Thread::Current());
- }
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
if (!klass->WasVerificationAttempted()) {
klass->SetSkipAccessChecksFlagOnAllMethods(pointer_size);
klass->SetVerificationAttempted();
+ // Now that the class has passed verification, try to set nterp entrypoints
+ // to methods that currently use the switch interpreter.
+ if (interpreter::CanRuntimeUseNterp()) {
+ for (ArtMethod& m : klass->GetMethods(pointer_size)) {
+ if (class_linker->IsQuickToInterpreterBridge(m.GetEntryPointFromQuickCompiledCode()) &&
+ interpreter::CanMethodUseNterp(&m)) {
+ if (klass->IsVisiblyInitialized() || !NeedsClinitCheckBeforeCall(&m)) {
+ runtime->GetInstrumentation()->UpdateMethodsCode(&m, interpreter::GetNterpEntryPoint());
+ }
+ }
+ }
+ }
}
}
@@ -3681,6 +3692,11 @@
// No code and native? Use generic trampoline.
return GetQuickGenericJniStub();
}
+
+ if (interpreter::CanRuntimeUseNterp() && interpreter::CanMethodUseNterp(method)) {
+ return interpreter::GetNterpEntryPoint();
+ }
+
return GetQuickToInterpreterBridge();
}
@@ -3778,27 +3794,41 @@
// Only update static methods.
continue;
}
- if (!IsQuickResolutionStub(method->GetEntryPointFromQuickCompiledCode())) {
- // Only update methods whose entrypoint is the resolution stub.
- continue;
- }
const void* quick_code = nullptr;
+
+ // In order:
+ // 1) Check if we have AOT Code.
+ // 2) Check if we have JIT Code.
+ // 3) Check if we can use Nterp.
if (has_oat_class) {
OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
quick_code = oat_method.GetQuickCode();
}
- // Check if we have JIT compiled code for it.
+
jit::Jit* jit = runtime->GetJit();
if (quick_code == nullptr && jit != nullptr) {
quick_code = jit->GetCodeCache()->GetSavedEntryPointOfPreCompiledMethod(method);
}
+
+ if (quick_code == nullptr &&
+ interpreter::CanRuntimeUseNterp() &&
+ interpreter::CanMethodUseNterp(method)) {
+ quick_code = interpreter::GetNterpEntryPoint();
+ }
+
// Check whether the method is native, in which case it's generic JNI.
if (quick_code == nullptr && method->IsNative()) {
quick_code = GetQuickGenericJniStub();
} else if (ShouldUseInterpreterEntrypoint(method, quick_code)) {
// Use interpreter entry point.
+ if (IsQuickToInterpreterBridge(method->GetEntryPointFromQuickCompiledCode())) {
+ // If we have the trampoline or the bridge already, no need to update.
+ // This saves in not dirtying boot image memory.
+ continue;
+ }
quick_code = GetQuickToInterpreterBridge();
}
+ CHECK(quick_code != nullptr);
runtime->GetInstrumentation()->UpdateMethodsCode(method, quick_code);
}
// Ignore virtual methods on the iterator.