From 268764da8022cafa5661c5b514eaa343c5257e57 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Tue, 13 Sep 2016 12:09:38 -0700 Subject: [PATCH] Make ScopedAssertNoThreadSuspension no overhead for non-debug Previously it required Thread::Current() which may not be free. The plan is to add a lot more ScopedAssertNoThreadSuspension in the codebase. Also cleaned up callers. Bug: 31458474 Change-Id: I5a1621a5435476504d22266cc01a9bf26aab7568 --- compiler/driver/compiler_driver.cc | 2 +- compiler/image_writer.cc | 2 +- compiler/oat_writer.cc | 4 ++-- runtime/art_method.cc | 2 +- runtime/class_linker.cc | 29 ++++++++++++++--------------- runtime/class_linker.h | 3 +-- runtime/debugger.cc | 6 +++--- runtime/entrypoints/entrypoint_utils-inl.h | 2 +- runtime/gc/heap.cc | 2 +- runtime/instrumentation.cc | 2 +- runtime/interpreter/interpreter_common.h | 5 ++--- runtime/jit/jit.cc | 7 +++---- runtime/jit/jit.h | 3 +-- runtime/mirror/class.cc | 2 +- runtime/native/java_lang_Class.cc | 3 +-- runtime/reflection.cc | 18 ++++++++++++------ runtime/reflection.h | 6 ++++-- runtime/thread.h | 24 +++++++++++++++--------- 18 files changed, 65 insertions(+), 57 deletions(-) diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index daac7fbb9..72c54feaa 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2473,7 +2473,7 @@ class InitializeClassVisitor : public CompilationVisitor { // mode which prevents the GC from visiting objects modified during the transaction. // Ensure GC is not run so don't access freed objects when aborting transaction. - ScopedAssertNoThreadSuspension ants(soa.Self(), "Transaction end"); + ScopedAssertNoThreadSuspension ants("Transaction end"); runtime->ExitTransactionMode(); if (!success) { diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 763451045..6d86f7d9d 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -868,7 +868,7 @@ void ImageWriter::PruneNonImageClasses() { // Clear references to removed classes from the DexCaches. ArtMethod* resolution_method = runtime->GetResolutionMethod(); - ScopedAssertNoThreadSuspension sa(self, __FUNCTION__); + ScopedAssertNoThreadSuspension sa(__FUNCTION__); ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // For ClassInClassTable ReaderMutexLock mu2(self, *class_linker->DexLock()); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 43e01d54a..5e0c64ba8 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -994,7 +994,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { out_(out), file_offset_(file_offset), soa_(Thread::Current()), - no_thread_suspension_(soa_.Self(), "OatWriter patching"), + no_thread_suspension_("OatWriter patching"), class_linker_(Runtime::Current()->GetClassLinker()), dex_cache_(nullptr) { patched_code_.reserve(16 * KB); @@ -1036,7 +1036,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); // No thread suspension since dex_cache_ that may get invalidated if that occurs. - ScopedAssertNoThreadSuspension tsc(Thread::Current(), __FUNCTION__); + ScopedAssertNoThreadSuspension tsc(__FUNCTION__); if (compiled_method != nullptr) { // ie. not an abstract method size_t file_offset = file_offset_; OutputStream* out = out_; diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 1392399bd..82f8edf69 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -107,7 +107,7 @@ size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) { } bool ArtMethod::HasSameNameAndSignature(ArtMethod* other) { - ScopedAssertNoThreadSuspension ants(Thread::Current(), "HasSameNameAndSignature"); + ScopedAssertNoThreadSuspension ants("HasSameNameAndSignature"); const DexFile* dex_file = GetDexFile(); const DexFile::MethodId& mid = dex_file->GetMethodId(GetDexMethodIndex()); if (GetDexCache() == other->GetDexCache()) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 8edb1b4d1..830648508 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1533,7 +1533,7 @@ static std::unique_ptr OpenOatDexFile(const OatFile* oat_file, bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space, std::vector>* out_dex_files, std::string* error_msg) { - ScopedAssertNoThreadSuspension nts(Thread::Current(), __FUNCTION__); + ScopedAssertNoThreadSuspension nts(__FUNCTION__); const ImageHeader& header = space->GetImageHeader(); mirror::Object* dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); DCHECK(dex_caches_object != nullptr); @@ -1923,7 +1923,7 @@ void ClassLinker::VisitClasses(ClassVisitor* visitor) { ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // Not safe to have thread suspension when we are holding a lock. if (self != nullptr) { - ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); + ScopedAssertNoThreadSuspension nts(__FUNCTION__); VisitClassesInternal(visitor); } else { VisitClassesInternal(visitor); @@ -1965,9 +1965,8 @@ class GetClassInToObjectArray : public ClassVisitor { void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { // TODO: it may be possible to avoid secondary storage if we iterate over dex caches. The problem // is avoiding duplicates. - Thread* const self = Thread::Current(); if (!kMovingClasses) { - ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); + ScopedAssertNoThreadSuspension nts(__FUNCTION__); GetClassesInToVector accumulator; VisitClasses(&accumulator); for (mirror::Class* klass : accumulator.classes_) { @@ -1976,6 +1975,7 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { } } } else { + Thread* const self = Thread::Current(); StackHandleScope<1> hs(self); auto classes = hs.NewHandle>(nullptr); // We size the array assuming classes won't be added to the class table during the visit. @@ -3047,7 +3047,7 @@ void ClassLinker::LoadClassMembers(Thread* self, { // Note: We cannot have thread suspension until the field and method arrays are setup or else // Class::VisitFieldRoots may miss some fields or methods. - ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); + ScopedAssertNoThreadSuspension nts(__FUNCTION__); // Load static fields. // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. @@ -3113,7 +3113,7 @@ void ClassLinker::LoadClassMembers(Thread* self, // TODO These should really use the iterators. for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_); - LoadMethod(self, dex_file, it, klass, method); + LoadMethod(dex_file, it, klass, method); LinkCode(method, oat_class, class_def_method_index); uint32_t it_method_index = it.GetMemberIndex(); if (last_dex_method_index == it_method_index) { @@ -3128,7 +3128,7 @@ void ClassLinker::LoadClassMembers(Thread* self, } for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); - LoadMethod(self, dex_file, it, klass, method); + LoadMethod(dex_file, it, klass, method); DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); LinkCode(method, oat_class, class_def_method_index); class_def_method_index++; @@ -3149,8 +3149,7 @@ void ClassLinker::LoadField(const ClassDataItemIterator& it, dst->SetAccessFlags(it.GetFieldAccessFlags()); } -void ClassLinker::LoadMethod(Thread* self, - const DexFile& dex_file, +void ClassLinker::LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& it, Handle klass, ArtMethod* dst) { @@ -3158,7 +3157,7 @@ void ClassLinker::LoadMethod(Thread* self, const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); - ScopedAssertNoThreadSuspension ants(self, "LoadMethod"); + ScopedAssertNoThreadSuspension ants("LoadMethod"); dst->SetDexMethodIndex(dex_method_idx); dst->SetDeclaringClass(klass.Get()); dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); @@ -3692,7 +3691,7 @@ void ClassLinker::AddImageClassesToClassTable(std::vector*> dex_caches_vector = GetImageDexCaches(Runtime::Current()->GetHeap()->GetBootImageSpaces()); for (mirror::ObjectArray* dex_caches : dex_caches_vector) { @@ -6503,7 +6502,7 @@ bool ClassLinker::SetupInterfaceLookupTable(Thread* self, Handle size_t new_ifcount; { - ScopedAssertNoThreadSuspension nts(self, "Copying mirror::Class*'s for FillIfTable"); + ScopedAssertNoThreadSuspension nts("Copying mirror::Class*'s for FillIfTable"); std::vector to_add; for (size_t i = 0; i < num_interfaces; i++) { mirror::Class* interface = have_interfaces ? interfaces->Get(i) : @@ -8266,7 +8265,7 @@ void ClassLinker::CleanupClassLoaders() { std::set ClassLinker::GetResolvedClasses(bool ignore_boot_classes) { ScopedTrace trace(__PRETTY_FUNCTION__); ScopedObjectAccess soa(Thread::Current()); - ScopedAssertNoThreadSuspension ants(soa.Self(), __FUNCTION__); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); std::set ret; VLOG(class_linker) << "Collecting resolved classes"; const uint64_t start_time = NanoTime(); @@ -8340,7 +8339,7 @@ std::unordered_set ClassLinker::GetClassDescriptorsForProfileKeys( Thread* const self = Thread::Current(); std::unordered_map location_to_dex_file; ScopedObjectAccess soa(self); - ScopedAssertNoThreadSuspension ants(soa.Self(), __FUNCTION__); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); ReaderMutexLock mu(self, *DexLock()); for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { if (!self->IsJWeakCleared(data.weak_root)) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 4bd1bd242..b0ed96941 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -768,8 +768,7 @@ class ClassLinker { void LoadField(const ClassDataItemIterator& it, Handle klass, ArtField* dst) REQUIRES_SHARED(Locks::mutator_lock_); - void LoadMethod(Thread* self, - const DexFile& dex_file, + void LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& it, Handle klass, ArtMethod* dst) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 9f3c2aa89..28210040c 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1986,7 +1986,7 @@ JDWP::JdwpError Dbg::GetThreadGroup(JDWP::ObjectId thread_id, JDWP::ExpandBuf* p if (error != JDWP::ERR_NONE) { return JDWP::ERR_INVALID_OBJECT; } - ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroup"); + ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroup"); // Okay, so it's an object, but is it actually a thread? DecodeThread(soa, thread_id, &error); if (error == JDWP::ERR_THREAD_NOT_ALIVE) { @@ -2036,7 +2036,7 @@ JDWP::JdwpError Dbg::GetThreadGroupName(JDWP::ObjectId thread_group_id, JDWP::Ex if (error != JDWP::ERR_NONE) { return error; } - ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroupName"); + ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroupName"); ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_name); CHECK(f != nullptr); mirror::String* s = reinterpret_cast(f->GetObject(thread_group)); @@ -2055,7 +2055,7 @@ JDWP::JdwpError Dbg::GetThreadGroupParent(JDWP::ObjectId thread_group_id, JDWP:: } mirror::Object* parent; { - ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroupParent"); + ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroupParent"); ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_parent); CHECK(f != nullptr); parent = f->GetObject(thread_group); diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index d03a9d80e..1bf5c5388 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -48,7 +48,7 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, // This method is being used by artQuickResolutionTrampoline, before it sets up // the passed parameters in a GC friendly way. Therefore we must never be // suspended while executing it. - ScopedAssertNoThreadSuspension sants(Thread::Current(), __FUNCTION__); + ScopedAssertNoThreadSuspension sants(__FUNCTION__); uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth); InvokeType invoke_type = static_cast( diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 600aff19d..cb5226b7b 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -1011,7 +1011,7 @@ void Heap::VisitObjects(ObjectCallback callback, void* arg) { DecrementDisableMovingGC(self); } else { // GCs can move objects, so don't allow this. - ScopedAssertNoThreadSuspension ants(self, "Visiting objects"); + ScopedAssertNoThreadSuspension ants("Visiting objects"); DCHECK(region_space_ == nullptr); VisitObjectsInternal(callback, arg); } diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 388561b01..ff433890a 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -966,7 +966,7 @@ void Instrumentation::InvokeVirtualOrInterfaceImpl(Thread* thread, ArtMethod* callee) const { // We cannot have thread suspension since that would cause the this_object parameter to // potentially become a dangling pointer. An alternative could be to put it in a handle instead. - ScopedAssertNoThreadSuspension ants(thread, __FUNCTION__); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); for (InstrumentationListener* listener : invoke_virtual_or_interface_listeners_) { if (listener != nullptr) { listener->InvokeVirtualOrInterface(thread, this_object, caller, dex_pc, callee); diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 9d76685fb..814adf713 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -147,8 +147,7 @@ static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instr jit::Jit* jit = Runtime::Current()->GetJit(); if (jit != nullptr) { if (type == kVirtual || type == kInterface) { - jit->InvokeVirtualOrInterface( - self, receiver, sf_method, shadow_frame.GetDexPC(), called_method); + jit->InvokeVirtualOrInterface(receiver, sf_method, shadow_frame.GetDexPC(), called_method); } jit->AddSamples(self, sf_method, 1, /*with_backedges*/false); } @@ -195,7 +194,7 @@ static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, jit::Jit* jit = Runtime::Current()->GetJit(); if (jit != nullptr) { jit->InvokeVirtualOrInterface( - self, receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method); + receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method); jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges*/false); } instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index cff23541b..d984f4525 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -431,7 +431,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, const uint8_t* native_pc = nullptr; { - ScopedAssertNoThreadSuspension sts(thread, "Holding OSR method"); + ScopedAssertNoThreadSuspension sts("Holding OSR method"); const OatQuickMethodHeader* osr_method = jit->GetCodeCache()->LookupOsrMethodHeader(method); if (osr_method == nullptr) { // No osr method yet, just return to the interpreter. @@ -683,12 +683,11 @@ void Jit::MethodEntered(Thread* thread, ArtMethod* method) { } } -void Jit::InvokeVirtualOrInterface(Thread* thread, - mirror::Object* this_object, +void Jit::InvokeVirtualOrInterface(mirror::Object* this_object, ArtMethod* caller, uint32_t dex_pc, ArtMethod* callee ATTRIBUTE_UNUSED) { - ScopedAssertNoThreadSuspension ants(thread, __FUNCTION__); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); DCHECK(this_object != nullptr); ProfilingInfo* info = caller->GetProfilingInfo(kRuntimePointerSize); if (info != nullptr) { diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index 417a18585..37edfd195 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -108,8 +108,7 @@ class Jit { void AddSamples(Thread* self, ArtMethod* method, uint16_t samples, bool with_backedges) REQUIRES_SHARED(Locks::mutator_lock_); - void InvokeVirtualOrInterface(Thread* thread, - mirror::Object* this_object, + void InvokeVirtualOrInterface(mirror::Object* this_object, ArtMethod* caller, uint32_t dex_pc, ArtMethod* callee) diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index c979c2813..b69f06b12 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -784,7 +784,7 @@ ArtField* Class::FindStaticField(Thread* self, } // Though GetDirectInterface() should not cause thread suspension when called // from here, it takes a Handle as an argument, so we need to wrap `k`. - ScopedAssertNoThreadSuspension ants(self, __FUNCTION__); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); StackHandleScope<1> hs(self); Handle h_k(hs.NewHandle(k)); // Is this field in any of this class' interfaces? diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index d89a334f3..2b17f4e46 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -668,8 +668,7 @@ static jobject Class_newInstance(JNIEnv* env, jobject javaThis) { caller.Assign(GetCallingClass(soa.Self(), 1)); } if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess( - soa.Self(), receiver.Get(), declaring_class, constructor->GetAccessFlags(), - caller.Get()))) { + receiver.Get(), declaring_class, constructor->GetAccessFlags(), caller.Get()))) { soa.Self()->ThrowNewExceptionF( "Ljava/lang/IllegalAccessException;", "%s is not accessible from %s", PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str()); diff --git a/runtime/reflection.cc b/runtime/reflection.cc index f2af3da6e..67e3fe886 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -625,8 +625,12 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM // If method is not set to be accessible, verify it can be accessed by the caller. mirror::Class* calling_class = nullptr; - if (!accessible && !VerifyAccess(soa.Self(), receiver, declaring_class, m->GetAccessFlags(), - &calling_class, num_frames)) { + if (!accessible && !VerifyAccess(soa.Self(), + receiver, + declaring_class, + m->GetAccessFlags(), + &calling_class, + num_frames)) { ThrowIllegalAccessException( StringPrintf("Class %s cannot access %s method %s of class %s", calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(), @@ -857,15 +861,17 @@ bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_cl return false; } *calling_class = klass; - return VerifyAccess(self, obj, declaring_class, access_flags, klass); + return VerifyAccess(obj, declaring_class, access_flags, klass); } -bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class, - uint32_t access_flags, mirror::Class* calling_class) { +bool VerifyAccess(mirror::Object* obj, + mirror::Class* declaring_class, + uint32_t access_flags, + mirror::Class* calling_class) { if (calling_class == declaring_class) { return true; } - ScopedAssertNoThreadSuspension sants(self, "verify-access"); + ScopedAssertNoThreadSuspension sants("verify-access"); if ((access_flags & kAccPrivate) != 0) { return false; } diff --git a/runtime/reflection.h b/runtime/reflection.h index 579c6b1c7..208b53391 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -74,8 +74,10 @@ bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_cl REQUIRES_SHARED(Locks::mutator_lock_); // This version takes a known calling class. -bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class, - uint32_t access_flags, mirror::Class* calling_class) +bool VerifyAccess(mirror::Object* obj, + mirror::Class* declaring_class, + uint32_t access_flags, + mirror::Class* calling_class) REQUIRES_SHARED(Locks::mutator_lock_); // Get the calling class by using a stack visitor, may return null for unattached native threads. diff --git a/runtime/thread.h b/runtime/thread.h index d248123db..1036d00f9 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -1546,19 +1546,25 @@ class Thread { class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension { public: - ScopedAssertNoThreadSuspension(Thread* self, const char* cause) ACQUIRE(Roles::uninterruptible_) - : self_(self), old_cause_(self->StartAssertNoThreadSuspension(cause)) { - } - ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) { - self_->EndAssertNoThreadSuspension(old_cause_); + ALWAYS_INLINE ScopedAssertNoThreadSuspension(const char* cause) ACQUIRE(Roles::uninterruptible_) { + if (kIsDebugBuild) { + self_ = Thread::Current(); + old_cause_ = self_->StartAssertNoThreadSuspension(cause); + } else { + Roles::uninterruptible_.Acquire(); // No-op. + } } - Thread* Self() { - return self_; + ALWAYS_INLINE ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) { + if (kIsDebugBuild) { + self_->EndAssertNoThreadSuspension(old_cause_); + } else { + Roles::uninterruptible_.Release(); // No-op. + } } private: - Thread* const self_; - const char* const old_cause_; + Thread* self_; + const char* old_cause_; }; class ScopedStackedShadowFramePusher { -- 2.11.0