Cleanup the code to determine instrumentation level
We used to maintain three different variables to maintain the
current instrumentation level. This CL unifies them into a
single variable which helps improve readability of the code.
Test: art/testrunner.py
Change-Id: Ibb2dfa14c90a209c3afbf28dab71533ad2fd8c7b
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 87db899..659b56e 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -168,9 +168,7 @@
Instrumentation::Instrumentation()
: current_force_deopt_id_(0),
instrumentation_stubs_installed_(false),
- entry_exit_stubs_installed_(false),
- interpreter_stubs_installed_(false),
- interpret_only_(false),
+ instrumentation_level_(InstrumentationLevel::kInstrumentNothing),
forced_interpret_only_(false),
have_method_entry_listeners_(false),
have_method_exit_listeners_(false),
@@ -276,7 +274,7 @@
return;
}
const void* new_quick_code;
- bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
+ bool uninstall = (instrumentation_level_ == InstrumentationLevel::kInstrumentNothing);
Runtime* const runtime = Runtime::Current();
ClassLinker* const class_linker = runtime->GetClassLinker();
bool is_class_initialized = method->GetDeclaringClass()->IsInitialized();
@@ -289,15 +287,14 @@
new_quick_code = GetQuickResolutionStub();
}
} else { // !uninstall
- if ((interpreter_stubs_installed_ || forced_interpret_only_ || IsDeoptimized(method)) &&
- !method->IsNative()) {
+ 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 (entry_exit_stubs_installed_) {
+ 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);
@@ -750,13 +747,7 @@
}
Instrumentation::InstrumentationLevel Instrumentation::GetCurrentInstrumentationLevel() const {
- if (interpreter_stubs_installed_) {
- return InstrumentationLevel::kInstrumentWithInterpreter;
- } else if (entry_exit_stubs_installed_) {
- return InstrumentationLevel::kInstrumentWithInstrumentationStubs;
- } else {
- return InstrumentationLevel::kInstrumentNothing;
- }
+ return instrumentation_level_;
}
bool Instrumentation::RequiresInstrumentationInstallation(InstrumentationLevel new_level) const {
@@ -798,6 +789,10 @@
UpdateStubs();
}
+void Instrumentation::UpdateInstrumentationLevel(InstrumentationLevel requested_level) {
+ instrumentation_level_ = requested_level;
+}
+
void Instrumentation::UpdateStubs() {
// Look for the highest required instrumentation level.
InstrumentationLevel requested_level = InstrumentationLevel::kInstrumentNothing;
@@ -810,9 +805,6 @@
<< "Use trampolines: " << can_use_instrumentation_trampolines_ << " level "
<< requested_level;
- interpret_only_ = (requested_level == InstrumentationLevel::kInstrumentWithInterpreter) ||
- forced_interpret_only_;
-
if (!RequiresInstrumentationInstallation(requested_level)) {
// We're already set.
return;
@@ -821,15 +813,8 @@
Runtime* runtime = Runtime::Current();
Locks::mutator_lock_->AssertExclusiveHeld(self);
Locks::thread_list_lock_->AssertNotHeld(self);
+ UpdateInstrumentationLevel(requested_level);
if (requested_level > InstrumentationLevel::kInstrumentNothing) {
- if (requested_level == InstrumentationLevel::kInstrumentWithInterpreter) {
- interpreter_stubs_installed_ = true;
- entry_exit_stubs_installed_ = true;
- } else {
- CHECK_EQ(requested_level, InstrumentationLevel::kInstrumentWithInstrumentationStubs);
- entry_exit_stubs_installed_ = true;
- interpreter_stubs_installed_ = false;
- }
InstallStubsClassVisitor visitor(this);
runtime->GetClassLinker()->VisitClasses(&visitor);
instrumentation_stubs_installed_ = true;
@@ -838,8 +823,6 @@
InstrumentThreadStack(thread, /* deopt_all_frames= */ false);
}
} else {
- interpreter_stubs_installed_ = false;
- entry_exit_stubs_installed_ = false;
InstallStubsClassVisitor visitor(this);
runtime->GetClassLinker()->VisitClasses(&visitor);
// Restore stack only if there is no method currently deoptimized.
@@ -947,14 +930,14 @@
if (LIKELY(!instrumentation_stubs_installed_)) {
new_quick_code = quick_code;
} else {
- if ((interpreter_stubs_installed_ || IsDeoptimized(method)) && !method->IsNative()) {
+ if ((InterpreterStubsInstalled() || IsDeoptimized(method)) && !method->IsNative()) {
new_quick_code = GetQuickToInterpreterBridge();
} else {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (class_linker->IsQuickResolutionStub(quick_code) ||
class_linker->IsQuickToInterpreterBridge(quick_code)) {
new_quick_code = quick_code;
- } else if (entry_exit_stubs_installed_ &&
+ } else if (EntryExitStubsInstalled() &&
// We need to make sure not to replace anything that InstallStubsForMethod
// wouldn't. Specifically we cannot stub out Proxy.<init> since subtypes copy the
// implementation directly and this will confuse the instrumentation trampolines.
@@ -976,7 +959,7 @@
// enter here on a soon-to-be deleted ArtMethod. Updating the entrypoint is OK though, as
// the ArtMethod is still in memory.
const void* new_quick_code = quick_code;
- if (UNLIKELY(instrumentation_stubs_installed_) && entry_exit_stubs_installed_) {
+ if (UNLIKELY(instrumentation_stubs_installed_) && EntryExitStubsInstalled()) {
new_quick_code = GetQuickInstrumentationEntryPoint();
}
UpdateEntrypoints(method, new_quick_code);
@@ -1047,7 +1030,7 @@
CHECK(has_not_been_deoptimized) << "Method " << ArtMethod::PrettyMethod(method)
<< " is already deoptimized";
}
- if (!interpreter_stubs_installed_) {
+ if (!InterpreterStubsInstalled()) {
UpdateEntrypoints(method, GetQuickInstrumentationEntryPoint());
// Install instrumentation exit stub and instrumentation frames. We may already have installed
@@ -1079,7 +1062,7 @@
}
// Restore code and possibly stack only if we did not deoptimize everything.
- if (!interpreter_stubs_installed_) {
+ if (!InterpreterStubsInstalled()) {
// Restore its code or resolution trampoline.
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (method->IsStatic() && !method->IsConstructor() &&
@@ -1093,7 +1076,7 @@
}
// If there is no deoptimized method left, we can restore the stack of each thread.
- if (empty && !entry_exit_stubs_installed_) {
+ if (empty && !EntryExitStubsInstalled()) {
MutexLock mu(self, *Locks::thread_list_lock_);
Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this);
instrumentation_stubs_installed_ = false;
@@ -1142,7 +1125,7 @@
if (!HasMethodEntryListeners() && !HasMethodExitListeners()) {
return false;
}
- return !deoptimization_enabled_ && !interpreter_stubs_installed_;
+ return !deoptimization_enabled_ && !InterpreterStubsInstalled();
}
void Instrumentation::DeoptimizeEverything(const char* key) {
@@ -1151,7 +1134,7 @@
}
void Instrumentation::UndeoptimizeEverything(const char* key) {
- CHECK(interpreter_stubs_installed_);
+ CHECK(InterpreterStubsInstalled());
CHECK(deoptimization_enabled_);
ConfigureStubs(key, InstrumentationLevel::kInstrumentNothing);
}
@@ -1174,7 +1157,7 @@
// This is called by instrumentation entry only and that should never be getting proxy methods.
DCHECK(!method->IsProxyMethod()) << method->PrettyMethod();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (LIKELY(!instrumentation_stubs_installed_ && !interpreter_stubs_installed_)) {
+ if (LIKELY(!InterpreterStubsInstalled())) {
// In general we just return whatever the method thinks its entrypoint is here. The only
// exception is if it still has the instrumentation entrypoint. That means we are racing another
// thread getting rid of instrumentation which is unexpected but possible. In that case we want
@@ -1183,24 +1166,18 @@
DCHECK(code != nullptr);
if (code != GetQuickInstrumentationEntryPoint()) {
return code;
- } else if (method->IsNative()) {
- return class_linker->GetQuickOatCodeFor(method);
}
// We don't know what it is. Fallthough to try to find the code from the JIT or Oat file.
- } else if (method->IsNative()) {
+ }
+
+ if (method->IsNative()) {
// TODO We could have JIT compiled native entrypoints. It might be worth it to find these.
return class_linker->GetQuickOatCodeFor(method);
- } else if (UNLIKELY(interpreter_stubs_installed_)) {
+ } else if (!NeedDebugVersionFor(method) || !InterpreterStubsInstalled()) {
+ return class_linker->GetQuickOatCodeFor(method);
+ } else {
return GetQuickToInterpreterBridge();
}
- // Since the method cannot be native due to ifs above we can always fall back to interpreter
- // bridge.
- const void* result = GetQuickToInterpreterBridge();
- if (!NeedDebugVersionFor(method)) {
- // If we don't need a debug version we should see what the oat file/class linker has to say.
- result = class_linker->GetQuickOatCodeFor(method);
- }
- return result;
}
const void* Instrumentation::GetQuickCodeFor(ArtMethod* method, PointerSize pointer_size) const {
@@ -1543,7 +1520,7 @@
}
}
return (visitor.caller != nullptr) &&
- (interpreter_stubs_installed_ || IsDeoptimized(visitor.caller) ||
+ (InterpreterStubsInstalled() || IsDeoptimized(visitor.caller) ||
self->IsForceInterpreter() ||
// NB Since structurally obsolete compiled methods might have the offsets of
// methods/fields compiled in we need to go back to interpreter whenever we hit
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 4f4bb42..5cf9eef 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -231,7 +231,7 @@
REQUIRES(!GetDeoptimizedMethodsLock());
bool AreAllMethodsDeoptimized() const {
- return interpreter_stubs_installed_;
+ return InterpreterStubsInstalled();
}
bool ShouldNotifyMethodEnterExitEvents() const REQUIRES_SHARED(Locks::mutator_lock_);
@@ -327,13 +327,21 @@
REQUIRES_SHARED(Locks::mutator_lock_);
void ForceInterpretOnly() {
- interpret_only_ = true;
forced_interpret_only_ = true;
}
+ bool EntryExitStubsInstalled() const {
+ return instrumentation_level_ == InstrumentationLevel::kInstrumentWithInstrumentationStubs ||
+ instrumentation_level_ == InstrumentationLevel::kInstrumentWithInterpreter;
+ }
+
+ bool InterpreterStubsInstalled() const {
+ return instrumentation_level_ == InstrumentationLevel::kInstrumentWithInterpreter;
+ }
+
// Called by ArtMethod::Invoke to determine dispatch mechanism.
bool InterpretOnly() const {
- return interpret_only_;
+ return forced_interpret_only_ || InterpreterStubsInstalled();
}
bool IsForcedInterpretOnly() const {
@@ -573,6 +581,9 @@
// directly call entry / exit hooks and don't need the stub.
bool CodeNeedsEntryExitStub(const void* code, ArtMethod* method);
+ // Update the current instrumentation_level_.
+ void UpdateInstrumentationLevel(InstrumentationLevel level);
+
// Does the job of installing or removing instrumentation code within methods.
// In order to support multiple clients using instrumentation at the same time,
// the caller must pass a unique key (a string) identifying it so we remind which
@@ -665,14 +676,11 @@
// Have we hijacked ArtMethod::code_ so that it calls instrumentation/interpreter code?
bool instrumentation_stubs_installed_;
- // Have we hijacked ArtMethod::code_ to reference the enter/exit stubs?
- bool entry_exit_stubs_installed_;
-
- // Have we hijacked ArtMethod::code_ to reference the enter interpreter stub?
- bool interpreter_stubs_installed_;
-
- // Do we need the fidelity of events that we only get from running within the interpreter?
- bool interpret_only_;
+ // The required level of instrumentation. This could be one of the following values:
+ // kInstrumentNothing: no instrumentation support is needed
+ // kInstrumentWithInstrumentationStubs: needs support to call method entry/exit stubs.
+ // kInstrumentWithInterpreter: only execute with interpreter
+ Instrumentation::InstrumentationLevel instrumentation_level_;
// Did the runtime request we only run in the interpreter? ie -Xint mode.
bool forced_interpret_only_;