| // Copyright 2013 the V8 project authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef V8_COMMON_ASSERT_SCOPE_H_ | 
 | #define V8_COMMON_ASSERT_SCOPE_H_ | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "src/base/macros.h" | 
 | #include "src/base/optional.h" | 
 | #include "src/base/platform/mutex.h" | 
 | #include "src/common/globals.h" | 
 | #include "src/utils/pointer-with-payload.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 |  | 
 | // Forward declarations. | 
 | class Isolate; | 
 | class PerThreadAssertData; | 
 |  | 
 | template <> | 
 | struct PointerWithPayloadTraits<PerThreadAssertData> { | 
 |   static constexpr int value = 1; | 
 | }; | 
 |  | 
 | enum PerThreadAssertType { | 
 |   GARBAGE_COLLECTION_ASSERT, | 
 |   HEAP_ALLOCATION_ASSERT, | 
 |   HANDLE_ALLOCATION_ASSERT, | 
 |   HANDLE_DEREFERENCE_ASSERT, | 
 |   CODE_DEPENDENCY_CHANGE_ASSERT, | 
 |   CODE_ALLOCATION_ASSERT, | 
 |   LAST_PER_THREAD_ASSERT_TYPE | 
 | }; | 
 |  | 
 | enum PerIsolateAssertType { | 
 |   JAVASCRIPT_EXECUTION_ASSERT, | 
 |   JAVASCRIPT_EXECUTION_THROWS, | 
 |   JAVASCRIPT_EXECUTION_DUMP, | 
 |   DEOPTIMIZATION_ASSERT, | 
 |   COMPILATION_ASSERT, | 
 |   NO_EXCEPTION_ASSERT | 
 | }; | 
 |  | 
 | template <PerThreadAssertType kType, bool kAllow> | 
 | class PerThreadAssertScope { | 
 |  public: | 
 |   V8_EXPORT_PRIVATE PerThreadAssertScope(); | 
 |   V8_EXPORT_PRIVATE ~PerThreadAssertScope(); | 
 |  | 
 |   V8_EXPORT_PRIVATE static bool IsAllowed(); | 
 |  | 
 |   void Release(); | 
 |  | 
 |  private: | 
 |   PointerWithPayload<PerThreadAssertData, bool, 1> data_and_old_state_; | 
 |  | 
 |   V8_INLINE void set_data(PerThreadAssertData* data) { | 
 |     data_and_old_state_.SetPointer(data); | 
 |   } | 
 |  | 
 |   V8_INLINE PerThreadAssertData* data() const { | 
 |     return data_and_old_state_.GetPointer(); | 
 |   } | 
 |  | 
 |   V8_INLINE void set_old_state(bool old_state) { | 
 |     return data_and_old_state_.SetPayload(old_state); | 
 |   } | 
 |  | 
 |   V8_INLINE bool old_state() const { return data_and_old_state_.GetPayload(); } | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope); | 
 | }; | 
 |  | 
 | template <PerIsolateAssertType type, bool allow> | 
 | class PerIsolateAssertScope { | 
 |  public: | 
 |   V8_EXPORT_PRIVATE explicit PerIsolateAssertScope(Isolate* isolate); | 
 |   V8_EXPORT_PRIVATE ~PerIsolateAssertScope(); | 
 |  | 
 |   static bool IsAllowed(Isolate* isolate); | 
 |  | 
 |  private: | 
 |   Isolate* isolate_; | 
 |   uint32_t old_data_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope); | 
 | }; | 
 |  | 
 | template <PerThreadAssertType type, bool allow> | 
 | #ifdef DEBUG | 
 | class PerThreadAssertScopeDebugOnly : public PerThreadAssertScope<type, allow> { | 
 | #else | 
 | class PerThreadAssertScopeDebugOnly { | 
 |  public: | 
 |   PerThreadAssertScopeDebugOnly() {  // NOLINT (modernize-use-equals-default) | 
 |     // Define a constructor to avoid unused variable warnings. | 
 |   } | 
 |   void Release() {} | 
 | #endif | 
 | }; | 
 |  | 
 | template <PerIsolateAssertType type, bool allow> | 
 | #ifdef DEBUG | 
 | class PerIsolateAssertScopeDebugOnly | 
 |     : public PerIsolateAssertScope<type, allow> { | 
 |  public: | 
 |   explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) | 
 |       : PerIsolateAssertScope<type, allow>(isolate) {} | 
 | #else | 
 | class PerIsolateAssertScopeDebugOnly { | 
 |  public: | 
 |   explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) {} | 
 | #endif | 
 | }; | 
 |  | 
 | // Per-thread assert scopes. | 
 |  | 
 | // Scope to document where we do not expect handles to be created. | 
 | using DisallowHandleAllocation = | 
 |     PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowHandleAllocation. | 
 | using AllowHandleAllocation = | 
 |     PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect garbage collections. It differs from | 
 | // DisallowHeapAllocation by also forbidding safepoints. | 
 | using DisallowGarbageCollection = | 
 |     PerThreadAssertScopeDebugOnly<GARBAGE_COLLECTION_ASSERT, false>; | 
 | // The DISALLOW_GARBAGE_COLLECTION macro can be used to define a | 
 | // DisallowGarbageCollection field in classes that isn't present in release | 
 | // builds. | 
 | #ifdef DEBUG | 
 | #define DISALLOW_GARBAGE_COLLECTION(name) DisallowGarbageCollection name; | 
 | #else | 
 | #define DISALLOW_GARBAGE_COLLECTION(name) | 
 | #endif | 
 |  | 
 | // Scope to introduce an exception to DisallowGarbageCollection. | 
 | using AllowGarbageCollection = | 
 |     PerThreadAssertScopeDebugOnly<GARBAGE_COLLECTION_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect any allocation and GC. Deprecated | 
 | // and will eventually be removed, use DisallowGarbageCollection instead. | 
 | using DisallowHeapAllocation = | 
 |     PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>; | 
 | // The DISALLOW_HEAP_ALLOCATION macro can be used to define a | 
 | // DisallowHeapAllocation field in classes that isn't present in release | 
 | // builds. | 
 | #ifdef DEBUG | 
 | #define DISALLOW_HEAP_ALLOCATION(name) DisallowHeapAllocation name; | 
 | #else | 
 | #define DISALLOW_HEAP_ALLOCATION(name) | 
 | #endif | 
 |  | 
 | // Scope to introduce an exception to DisallowHeapAllocation. | 
 | using AllowHeapAllocation = | 
 |     PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect any handle dereferences. | 
 | using DisallowHandleDereference = | 
 |     PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowHandleDereference. | 
 | using AllowHandleDereference = | 
 |     PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect code dependencies to change. | 
 | using DisallowCodeDependencyChange = | 
 |     PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowCodeDependencyChange. | 
 | using AllowCodeDependencyChange = | 
 |     PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect code to be allocated. | 
 | using DisallowCodeAllocation = | 
 |     PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowCodeAllocation. | 
 | using AllowCodeAllocation = | 
 |     PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, true>; | 
 |  | 
 | class DisallowHeapAccess { | 
 |   DisallowCodeDependencyChange no_dependency_change_; | 
 |   DisallowHandleAllocation no_handle_allocation_; | 
 |   DisallowHandleDereference no_handle_dereference_; | 
 |   DisallowHeapAllocation no_heap_allocation_; | 
 | }; | 
 |  | 
 | class DisallowHeapAccessIf { | 
 |  public: | 
 |   explicit DisallowHeapAccessIf(bool condition) { | 
 |     if (condition) maybe_disallow_.emplace(); | 
 |   } | 
 |  | 
 |  private: | 
 |   base::Optional<DisallowHeapAccess> maybe_disallow_; | 
 | }; | 
 |  | 
 | // Like MutexGuard but also asserts that no heap allocation happens while | 
 | // we're holding the mutex. | 
 | class NoHeapAllocationMutexGuard { | 
 |  public: | 
 |   explicit NoHeapAllocationMutexGuard(base::Mutex* mutex) | 
 |       : guard_(mutex), mutex_(mutex), no_gc_(new DisallowHeapAllocation()) {} | 
 |  | 
 |   void Unlock() { | 
 |     mutex_->Unlock(); | 
 |     no_gc_.reset(); | 
 |   } | 
 |   void Lock() { | 
 |     mutex_->Lock(); | 
 |     no_gc_.reset(new DisallowHeapAllocation()); | 
 |   } | 
 |  | 
 |  private: | 
 |   base::MutexGuard guard_; | 
 |   base::Mutex* mutex_; | 
 |   std::unique_ptr<DisallowHeapAllocation> no_gc_; | 
 | }; | 
 |  | 
 | // Per-isolate assert scopes. | 
 |  | 
 | // Scope to document where we do not expect javascript execution. | 
 | using DisallowJavascriptExecution = | 
 |     PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowJavascriptExecution. | 
 | using AllowJavascriptExecution = | 
 |     PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect javascript execution (debug only) | 
 | using DisallowJavascriptExecutionDebugOnly = | 
 |     PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowJavascriptExecutionDebugOnly. | 
 | using AllowJavascriptExecutionDebugOnly = | 
 |     PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, true>; | 
 |  | 
 | // Scope in which javascript execution leads to exception being thrown. | 
 | using ThrowOnJavascriptExecution = | 
 |     PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>; | 
 |  | 
 | // Scope to introduce an exception to ThrowOnJavascriptExecution. | 
 | using NoThrowOnJavascriptExecution = | 
 |     PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>; | 
 |  | 
 | // Scope in which javascript execution causes dumps. | 
 | using DumpOnJavascriptExecution = | 
 |     PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>; | 
 |  | 
 | // Scope in which javascript execution causes dumps. | 
 | using NoDumpOnJavascriptExecution = | 
 |     PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>; | 
 |  | 
 | // Scope to document where we do not expect deoptimization. | 
 | using DisallowDeoptimization = | 
 |     PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowDeoptimization. | 
 | using AllowDeoptimization = | 
 |     PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect deoptimization. | 
 | using DisallowCompilation = | 
 |     PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowDeoptimization. | 
 | using AllowCompilation = | 
 |     PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>; | 
 |  | 
 | // Scope to document where we do not expect exceptions. | 
 | using DisallowExceptions = | 
 |     PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, false>; | 
 |  | 
 | // Scope to introduce an exception to DisallowExceptions. | 
 | using AllowExceptions = | 
 |     PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, true>; | 
 |  | 
 | // Explicit instantiation declarations. | 
 | extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>; | 
 | extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>; | 
 | extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>; | 
 | extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>; | 
 | extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>; | 
 | extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>; | 
 | extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, | 
 |                                            false>; | 
 | extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>; | 
 | extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, false>; | 
 | extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, true>; | 
 |  | 
 | extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>; | 
 | extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>; | 
 | extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>; | 
 | extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>; | 
 | extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>; | 
 | extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>; | 
 | extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>; | 
 | extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>; | 
 | extern template class PerIsolateAssertScope<COMPILATION_ASSERT, false>; | 
 | extern template class PerIsolateAssertScope<COMPILATION_ASSERT, true>; | 
 | extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, false>; | 
 | extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, true>; | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace v8 | 
 |  | 
 | #endif  // V8_COMMON_ASSERT_SCOPE_H_ |