summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/interpreter/mterp/mterp.cc10
-rw-r--r--runtime/runtime.cc1
-rw-r--r--runtime/runtime.h12
-rw-r--r--runtime/thread.cc1
4 files changed, 22 insertions, 2 deletions
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 92dd19ed2f..987298bd8a 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -151,8 +151,14 @@ extern "C" size_t MterpShouldSwitchInterpreters()
Dbg::IsDebuggerActive() ||
// An async exception has been thrown. We need to go to the switch interpreter. MTerp doesn't
// know how to deal with these so we could end up never dealing with it if we are in an
- // infinite loop.
- UNLIKELY(Thread::Current()->IsAsyncExceptionPending());
+ // infinite loop. Since this can be called in a tight loop and getting the current thread
+ // requires a TLS read we instead first check a short-circuit runtime flag that will only be
+ // set if something tries to set an async exception. This will make this function faster in
+ // the common case where no async exception has ever been sent. We don't need to worry about
+ // synchronization on the runtime flag since it is only set in a checkpoint which will either
+ // take place on the current thread or act as a synchronization point.
+ (UNLIKELY(runtime->AreAsyncExceptionsThrown()) &&
+ Thread::Current()->IsAsyncExceptionPending());
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f09b6c9825..d15de38b0a 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -256,6 +256,7 @@ Runtime::Runtime()
force_native_bridge_(false),
is_native_bridge_loaded_(false),
is_native_debuggable_(false),
+ async_exceptions_thrown_(false),
is_java_debuggable_(false),
zygote_max_failed_boots_(0),
experimental_flags_(ExperimentalFlags::kNone),
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 6b01cc220f..476b71f169 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -586,6 +586,14 @@ class Runtime {
is_native_debuggable_ = value;
}
+ bool AreAsyncExceptionsThrown() const {
+ return async_exceptions_thrown_;
+ }
+
+ void SetAsyncExceptionsThrown() {
+ async_exceptions_thrown_ = true;
+ }
+
// Returns the build fingerprint, if set. Otherwise an empty string is returned.
std::string GetFingerprint() {
return fingerprint_;
@@ -899,6 +907,10 @@ class Runtime {
// Whether we are running under native debugger.
bool is_native_debuggable_;
+ // whether or not any async exceptions have ever been thrown. This is used to speed up the
+ // MterpShouldSwitchInterpreters function.
+ bool async_exceptions_thrown_;
+
// Whether Java code needs to be debuggable.
bool is_java_debuggable_;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index bec1c908ad..cb350edb5f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3700,6 +3700,7 @@ void Thread::DeoptimizeWithDeoptimizationException(JValue* result) {
void Thread::SetAsyncException(ObjPtr<mirror::Throwable> new_exception) {
CHECK(new_exception != nullptr);
+ Runtime::Current()->SetAsyncExceptionsThrown();
if (kIsDebugBuild) {
// Make sure we are in a checkpoint.
MutexLock mu(Thread::Current(), *Locks::thread_suspend_count_lock_);