1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMMON_ASSERT_SCOPE_H_ 6 #define V8_COMMON_ASSERT_SCOPE_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 12 #include "src/base/macros.h" 13 #include "src/base/optional.h" 14 #include "src/base/platform/mutex.h" 15 #include "src/common/globals.h" 16 #include "src/utils/pointer-with-payload.h" 17 18 namespace v8 { 19 namespace internal { 20 21 // Forward declarations. 22 class Isolate; 23 class PerThreadAssertData; 24 25 template <> 26 struct PointerWithPayloadTraits<PerThreadAssertData> { 27 static constexpr int value = 1; 28 }; 29 30 enum PerThreadAssertType { 31 GARBAGE_COLLECTION_ASSERT, 32 HEAP_ALLOCATION_ASSERT, 33 HANDLE_ALLOCATION_ASSERT, 34 HANDLE_DEREFERENCE_ASSERT, 35 CODE_DEPENDENCY_CHANGE_ASSERT, 36 CODE_ALLOCATION_ASSERT, 37 LAST_PER_THREAD_ASSERT_TYPE 38 }; 39 40 enum PerIsolateAssertType { 41 JAVASCRIPT_EXECUTION_ASSERT, 42 JAVASCRIPT_EXECUTION_THROWS, 43 JAVASCRIPT_EXECUTION_DUMP, 44 DEOPTIMIZATION_ASSERT, 45 COMPILATION_ASSERT, 46 NO_EXCEPTION_ASSERT 47 }; 48 49 template <PerThreadAssertType kType, bool kAllow> 50 class PerThreadAssertScope { 51 public: 52 V8_EXPORT_PRIVATE PerThreadAssertScope(); 53 V8_EXPORT_PRIVATE ~PerThreadAssertScope(); 54 55 V8_EXPORT_PRIVATE static bool IsAllowed(); 56 57 void Release(); 58 59 private: 60 PointerWithPayload<PerThreadAssertData, bool, 1> data_and_old_state_; 61 62 V8_INLINE void set_data(PerThreadAssertData* data) { 63 data_and_old_state_.SetPointer(data); 64 } 65 66 V8_INLINE PerThreadAssertData* data() const { 67 return data_and_old_state_.GetPointer(); 68 } 69 70 V8_INLINE void set_old_state(bool old_state) { 71 return data_and_old_state_.SetPayload(old_state); 72 } 73 74 V8_INLINE bool old_state() const { return data_and_old_state_.GetPayload(); } 75 76 DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope); 77 }; 78 79 template <PerIsolateAssertType type, bool allow> 80 class PerIsolateAssertScope { 81 public: 82 V8_EXPORT_PRIVATE explicit PerIsolateAssertScope(Isolate* isolate); 83 V8_EXPORT_PRIVATE ~PerIsolateAssertScope(); 84 85 static bool IsAllowed(Isolate* isolate); 86 87 private: 88 Isolate* isolate_; 89 uint32_t old_data_; 90 91 DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope); 92 }; 93 94 template <PerThreadAssertType type, bool allow> 95 #ifdef DEBUG 96 class PerThreadAssertScopeDebugOnly : public PerThreadAssertScope<type, allow> { 97 #else 98 class PerThreadAssertScopeDebugOnly { 99 public: 100 PerThreadAssertScopeDebugOnly() { // NOLINT (modernize-use-equals-default) 101 // Define a constructor to avoid unused variable warnings. 102 } 103 void Release() {} 104 #endif 105 }; 106 107 template <PerIsolateAssertType type, bool allow> 108 #ifdef DEBUG 109 class PerIsolateAssertScopeDebugOnly 110 : public PerIsolateAssertScope<type, allow> { 111 public: 112 explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) 113 : PerIsolateAssertScope<type, allow>(isolate) {} 114 #else 115 class PerIsolateAssertScopeDebugOnly { 116 public: 117 explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) {} 118 #endif 119 }; 120 121 // Per-thread assert scopes. 122 123 // Scope to document where we do not expect handles to be created. 124 using DisallowHandleAllocation = 125 PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>; 126 127 // Scope to introduce an exception to DisallowHandleAllocation. 128 using AllowHandleAllocation = 129 PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>; 130 131 // Scope to document where we do not expect garbage collections. It differs from 132 // DisallowHeapAllocation by also forbidding safepoints. 133 using DisallowGarbageCollection = 134 PerThreadAssertScopeDebugOnly<GARBAGE_COLLECTION_ASSERT, false>; 135 // The DISALLOW_GARBAGE_COLLECTION macro can be used to define a 136 // DisallowGarbageCollection field in classes that isn't present in release 137 // builds. 138 #ifdef DEBUG 139 #define DISALLOW_GARBAGE_COLLECTION(name) DisallowGarbageCollection name; 140 #else 141 #define DISALLOW_GARBAGE_COLLECTION(name) 142 #endif 143 144 // Scope to introduce an exception to DisallowGarbageCollection. 145 using AllowGarbageCollection = 146 PerThreadAssertScopeDebugOnly<GARBAGE_COLLECTION_ASSERT, true>; 147 148 // Scope to document where we do not expect any allocation and GC. Deprecated 149 // and will eventually be removed, use DisallowGarbageCollection instead. 150 using DisallowHeapAllocation = 151 PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>; 152 // The DISALLOW_HEAP_ALLOCATION macro can be used to define a 153 // DisallowHeapAllocation field in classes that isn't present in release 154 // builds. 155 #ifdef DEBUG 156 #define DISALLOW_HEAP_ALLOCATION(name) DisallowHeapAllocation name; 157 #else 158 #define DISALLOW_HEAP_ALLOCATION(name) 159 #endif 160 161 // Scope to introduce an exception to DisallowHeapAllocation. 162 using AllowHeapAllocation = 163 PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>; 164 165 // Scope to document where we do not expect any handle dereferences. 166 using DisallowHandleDereference = 167 PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>; 168 169 // Scope to introduce an exception to DisallowHandleDereference. 170 using AllowHandleDereference = 171 PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>; 172 173 // Scope to document where we do not expect code dependencies to change. 174 using DisallowCodeDependencyChange = 175 PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>; 176 177 // Scope to introduce an exception to DisallowCodeDependencyChange. 178 using AllowCodeDependencyChange = 179 PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>; 180 181 // Scope to document where we do not expect code to be allocated. 182 using DisallowCodeAllocation = 183 PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, false>; 184 185 // Scope to introduce an exception to DisallowCodeAllocation. 186 using AllowCodeAllocation = 187 PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, true>; 188 189 class DisallowHeapAccess { 190 DisallowCodeDependencyChange no_dependency_change_; 191 DisallowHandleAllocation no_handle_allocation_; 192 DisallowHandleDereference no_handle_dereference_; 193 DisallowHeapAllocation no_heap_allocation_; 194 }; 195 196 class DisallowHeapAccessIf { 197 public: 198 explicit DisallowHeapAccessIf(bool condition) { 199 if (condition) maybe_disallow_.emplace(); 200 } 201 202 private: 203 base::Optional<DisallowHeapAccess> maybe_disallow_; 204 }; 205 206 // Like MutexGuard but also asserts that no heap allocation happens while 207 // we're holding the mutex. 208 class NoHeapAllocationMutexGuard { 209 public: 210 explicit NoHeapAllocationMutexGuard(base::Mutex* mutex) 211 : guard_(mutex), mutex_(mutex), no_gc_(new DisallowHeapAllocation()) {} 212 213 void Unlock() { 214 mutex_->Unlock(); 215 no_gc_.reset(); 216 } 217 void Lock() { 218 mutex_->Lock(); 219 no_gc_.reset(new DisallowHeapAllocation()); 220 } 221 222 private: 223 base::MutexGuard guard_; 224 base::Mutex* mutex_; 225 std::unique_ptr<DisallowHeapAllocation> no_gc_; 226 }; 227 228 // Per-isolate assert scopes. 229 230 // Scope to document where we do not expect javascript execution. 231 using DisallowJavascriptExecution = 232 PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>; 233 234 // Scope to introduce an exception to DisallowJavascriptExecution. 235 using AllowJavascriptExecution = 236 PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>; 237 238 // Scope to document where we do not expect javascript execution (debug only) 239 using DisallowJavascriptExecutionDebugOnly = 240 PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, false>; 241 242 // Scope to introduce an exception to DisallowJavascriptExecutionDebugOnly. 243 using AllowJavascriptExecutionDebugOnly = 244 PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, true>; 245 246 // Scope in which javascript execution leads to exception being thrown. 247 using ThrowOnJavascriptExecution = 248 PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>; 249 250 // Scope to introduce an exception to ThrowOnJavascriptExecution. 251 using NoThrowOnJavascriptExecution = 252 PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>; 253 254 // Scope in which javascript execution causes dumps. 255 using DumpOnJavascriptExecution = 256 PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>; 257 258 // Scope in which javascript execution causes dumps. 259 using NoDumpOnJavascriptExecution = 260 PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>; 261 262 // Scope to document where we do not expect deoptimization. 263 using DisallowDeoptimization = 264 PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>; 265 266 // Scope to introduce an exception to DisallowDeoptimization. 267 using AllowDeoptimization = 268 PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>; 269 270 // Scope to document where we do not expect deoptimization. 271 using DisallowCompilation = 272 PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>; 273 274 // Scope to introduce an exception to DisallowDeoptimization. 275 using AllowCompilation = 276 PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>; 277 278 // Scope to document where we do not expect exceptions. 279 using DisallowExceptions = 280 PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, false>; 281 282 // Scope to introduce an exception to DisallowExceptions. 283 using AllowExceptions = 284 PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, true>; 285 286 // Explicit instantiation declarations. 287 extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>; 288 extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>; 289 extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>; 290 extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>; 291 extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>; 292 extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>; 293 extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, 294 false>; 295 extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>; 296 extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, false>; 297 extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, true>; 298 299 extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>; 300 extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>; 301 extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>; 302 extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>; 303 extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>; 304 extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>; 305 extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>; 306 extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>; 307 extern template class PerIsolateAssertScope<COMPILATION_ASSERT, false>; 308 extern template class PerIsolateAssertScope<COMPILATION_ASSERT, true>; 309 extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, false>; 310 extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, true>; 311 312 } // namespace internal 313 } // namespace v8 314 315 #endif // V8_COMMON_ASSERT_SCOPE_H_ 316