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_ASSERT_SCOPE_H_
6 #define V8_ASSERT_SCOPE_H_
7 
8 #include "src/allocation.h"
9 #include "src/base/platform/platform.h"
10 #include "src/utils.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 class Isolate;
16 
17 enum PerThreadAssertType {
18   HEAP_ALLOCATION_ASSERT,
19   HANDLE_ALLOCATION_ASSERT,
20   HANDLE_DEREFERENCE_ASSERT,
21   DEFERRED_HANDLE_DEREFERENCE_ASSERT,
22   CODE_DEPENDENCY_CHANGE_ASSERT,
23   LAST_PER_THREAD_ASSERT_TYPE
24 };
25 
26 
27 enum PerIsolateAssertType {
28   JAVASCRIPT_EXECUTION_ASSERT,
29   JAVASCRIPT_EXECUTION_THROWS,
30   ALLOCATION_FAILURE_ASSERT,
31   DEOPTIMIZATION_ASSERT,
32   COMPILATION_ASSERT
33 };
34 
35 
36 class PerThreadAssertData {
37  public:
PerThreadAssertData()38   PerThreadAssertData() : nesting_level_(0) {
39     for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
40       assert_states_[i] = true;
41     }
42   }
43 
set(PerThreadAssertType type,bool allow)44   void set(PerThreadAssertType type, bool allow) {
45     assert_states_[type] = allow;
46   }
47 
get(PerThreadAssertType type)48   bool get(PerThreadAssertType type) const {
49     return assert_states_[type];
50   }
51 
increment_level()52   void increment_level() { ++nesting_level_; }
decrement_level()53   bool decrement_level() { return --nesting_level_ == 0; }
54 
55  private:
56   bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE];
57   int nesting_level_;
58 
59   DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
60 };
61 
62 
63 class PerThreadAssertScopeBase {
64  protected:
PerThreadAssertScopeBase()65   PerThreadAssertScopeBase() {
66     data_ = GetAssertData();
67     if (data_ == NULL) {
68       data_ = new PerThreadAssertData();
69       SetThreadLocalData(data_);
70     }
71     data_->increment_level();
72   }
73 
~PerThreadAssertScopeBase()74   ~PerThreadAssertScopeBase() {
75     if (!data_->decrement_level()) return;
76     for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
77       DCHECK(data_->get(static_cast<PerThreadAssertType>(i)));
78     }
79     delete data_;
80     SetThreadLocalData(NULL);
81   }
82 
GetAssertData()83   static PerThreadAssertData* GetAssertData() {
84     return reinterpret_cast<PerThreadAssertData*>(
85         base::Thread::GetThreadLocal(thread_local_key));
86   }
87 
88   static base::Thread::LocalStorageKey thread_local_key;
89   PerThreadAssertData* data_;
90   friend class Isolate;
91 
92  private:
SetThreadLocalData(PerThreadAssertData * data)93   static void SetThreadLocalData(PerThreadAssertData* data) {
94     base::Thread::SetThreadLocal(thread_local_key, data);
95   }
96 };
97 
98 
99 template <PerThreadAssertType type, bool allow>
100 class PerThreadAssertScope : public PerThreadAssertScopeBase {
101  public:
PerThreadAssertScope()102   PerThreadAssertScope() {
103     old_state_ = data_->get(type);
104     data_->set(type, allow);
105   }
106 
~PerThreadAssertScope()107   ~PerThreadAssertScope() { data_->set(type, old_state_); }
108 
IsAllowed()109   static bool IsAllowed() {
110     PerThreadAssertData* data = GetAssertData();
111     return data == NULL || data->get(type);
112   }
113 
114  private:
115   bool old_state_;
116 
117   DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope);
118 };
119 
120 
121 class PerIsolateAssertBase {
122  protected:
123   static uint32_t GetData(Isolate* isolate);
124   static void SetData(Isolate* isolate, uint32_t data);
125 };
126 
127 
128 template <PerIsolateAssertType type, bool allow>
129 class PerIsolateAssertScope : public PerIsolateAssertBase {
130  public:
PerIsolateAssertScope(Isolate * isolate)131   explicit PerIsolateAssertScope(Isolate* isolate) : isolate_(isolate) {
132     STATIC_ASSERT(type < 32);
133     old_data_ = GetData(isolate_);
134     SetData(isolate_, DataBit::update(old_data_, allow));
135   }
136 
~PerIsolateAssertScope()137   ~PerIsolateAssertScope() {
138     SetData(isolate_, old_data_);
139   }
140 
IsAllowed(Isolate * isolate)141   static bool IsAllowed(Isolate* isolate) {
142     return DataBit::decode(GetData(isolate));
143   }
144 
145  private:
146   typedef BitField<bool, type, 1> DataBit;
147 
148   uint32_t old_data_;
149   Isolate* isolate_;
150 
151   DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope);
152 };
153 
154 
155 template <PerThreadAssertType type, bool allow>
156 #ifdef DEBUG
157 class PerThreadAssertScopeDebugOnly : public
158     PerThreadAssertScope<type, allow> {
159 #else
160 class PerThreadAssertScopeDebugOnly {
161  public:
162   PerThreadAssertScopeDebugOnly() { }
163 #endif
164 };
165 
166 
167 template <PerIsolateAssertType type, bool allow>
168 #ifdef DEBUG
169 class PerIsolateAssertScopeDebugOnly : public
170     PerIsolateAssertScope<type, allow> {
171  public:
PerIsolateAssertScopeDebugOnly(Isolate * isolate)172   explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate)
173       : PerIsolateAssertScope<type, allow>(isolate) { }
174 #else
175 class PerIsolateAssertScopeDebugOnly {
176  public:
177   explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) { }
178 #endif
179 };
180 
181 // Per-thread assert scopes.
182 
183 // Scope to document where we do not expect handles to be created.
184 typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>
185     DisallowHandleAllocation;
186 
187 // Scope to introduce an exception to DisallowHandleAllocation.
188 typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>
189     AllowHandleAllocation;
190 
191 // Scope to document where we do not expect any allocation and GC.
192 typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>
193     DisallowHeapAllocation;
194 
195 // Scope to introduce an exception to DisallowHeapAllocation.
196 typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>
197     AllowHeapAllocation;
198 
199 // Scope to document where we do not expect any handle dereferences.
200 typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>
201     DisallowHandleDereference;
202 
203 // Scope to introduce an exception to DisallowHandleDereference.
204 typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>
205     AllowHandleDereference;
206 
207 // Scope to document where we do not expect deferred handles to be dereferenced.
208 typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>
209     DisallowDeferredHandleDereference;
210 
211 // Scope to introduce an exception to DisallowDeferredHandleDereference.
212 typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>
213     AllowDeferredHandleDereference;
214 
215 // Scope to document where we do not expect deferred handles to be dereferenced.
216 typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>
217     DisallowCodeDependencyChange;
218 
219 // Scope to introduce an exception to DisallowDeferredHandleDereference.
220 typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>
221     AllowCodeDependencyChange;
222 
223 
224 // Per-isolate assert scopes.
225 
226 // Scope to document where we do not expect javascript execution.
227 typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>
228     DisallowJavascriptExecution;
229 
230 // Scope to introduce an exception to DisallowJavascriptExecution.
231 typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>
232     AllowJavascriptExecution;
233 
234 // Scope in which javascript execution leads to exception being thrown.
235 typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>
236     ThrowOnJavascriptExecution;
237 
238 // Scope to introduce an exception to ThrowOnJavascriptExecution.
239 typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>
240     NoThrowOnJavascriptExecution;
241 
242 // Scope to document where we do not expect an allocation failure.
243 typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, false>
244     DisallowAllocationFailure;
245 
246 // Scope to introduce an exception to DisallowAllocationFailure.
247 typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, true>
248     AllowAllocationFailure;
249 
250 // Scope to document where we do not expect deoptimization.
251 typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>
252     DisallowDeoptimization;
253 
254 // Scope to introduce an exception to DisallowDeoptimization.
255 typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>
256     AllowDeoptimization;
257 
258 // Scope to document where we do not expect deoptimization.
259 typedef PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>
260     DisallowCompilation;
261 
262 // Scope to introduce an exception to DisallowDeoptimization.
263 typedef PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>
264     AllowCompilation;
265 } }  // namespace v8::internal
266 
267 #endif  // V8_ASSERT_SCOPE_H_
268