• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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