diff options
| -rw-r--r-- | runtime/interpreter/mterp/mterp.cc | 10 | ||||
| -rw-r--r-- | runtime/runtime.cc | 1 | ||||
| -rw-r--r-- | runtime/runtime.h | 12 | ||||
| -rw-r--r-- | runtime/thread.cc | 1 |
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_); |