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
12namespace v8 {
13namespace internal {
14
15class Isolate;
16
17enum 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
27enum PerIsolateAssertType {
28  JAVASCRIPT_EXECUTION_ASSERT,
29  JAVASCRIPT_EXECUTION_THROWS,
30  ALLOCATION_FAILURE_ASSERT,
31  DEOPTIMIZATION_ASSERT,
32  COMPILATION_ASSERT
33};
34
35
36class PerThreadAssertData {
37 public:
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
44  void set(PerThreadAssertType type, bool allow) {
45    assert_states_[type] = allow;
46  }
47
48  bool get(PerThreadAssertType type) const {
49    return assert_states_[type];
50  }
51
52  void increment_level() { ++nesting_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
63class PerThreadAssertScopeBase {
64 protected:
65  PerThreadAssertScopeBase() {
66    data_ = GetAssertData();
67    if (data_ == NULL) {
68      data_ = new PerThreadAssertData();
69      SetThreadLocalData(data_);
70    }
71    data_->increment_level();
72  }
73
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
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:
93  static void SetThreadLocalData(PerThreadAssertData* data) {
94    base::Thread::SetThreadLocal(thread_local_key, data);
95  }
96};
97
98
99template <PerThreadAssertType type, bool allow>
100class PerThreadAssertScope : public PerThreadAssertScopeBase {
101 public:
102  PerThreadAssertScope() {
103    old_state_ = data_->get(type);
104    data_->set(type, allow);
105  }
106
107  ~PerThreadAssertScope() { data_->set(type, old_state_); }
108
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
121class PerIsolateAssertBase {
122 protected:
123  static uint32_t GetData(Isolate* isolate);
124  static void SetData(Isolate* isolate, uint32_t data);
125};
126
127
128template <PerIsolateAssertType type, bool allow>
129class PerIsolateAssertScope : public PerIsolateAssertBase {
130 public:
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
137  ~PerIsolateAssertScope() {
138    SetData(isolate_, old_data_);
139  }
140
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
155template <PerThreadAssertType type, bool allow>
156#ifdef DEBUG
157class PerThreadAssertScopeDebugOnly : public
158    PerThreadAssertScope<type, allow> {
159#else
160class PerThreadAssertScopeDebugOnly {
161 public:
162  PerThreadAssertScopeDebugOnly() { }
163#endif
164};
165
166
167template <PerIsolateAssertType type, bool allow>
168#ifdef DEBUG
169class PerIsolateAssertScopeDebugOnly : public
170    PerIsolateAssertScope<type, allow> {
171 public:
172  explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate)
173      : PerIsolateAssertScope<type, allow>(isolate) { }
174#else
175class 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.
184typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>
185    DisallowHandleAllocation;
186
187// Scope to introduce an exception to DisallowHandleAllocation.
188typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>
189    AllowHandleAllocation;
190
191// Scope to document where we do not expect any allocation and GC.
192typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>
193    DisallowHeapAllocation;
194
195// Scope to introduce an exception to DisallowHeapAllocation.
196typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>
197    AllowHeapAllocation;
198
199// Scope to document where we do not expect any handle dereferences.
200typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>
201    DisallowHandleDereference;
202
203// Scope to introduce an exception to DisallowHandleDereference.
204typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>
205    AllowHandleDereference;
206
207// Scope to document where we do not expect deferred handles to be dereferenced.
208typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>
209    DisallowDeferredHandleDereference;
210
211// Scope to introduce an exception to DisallowDeferredHandleDereference.
212typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>
213    AllowDeferredHandleDereference;
214
215// Scope to document where we do not expect deferred handles to be dereferenced.
216typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>
217    DisallowCodeDependencyChange;
218
219// Scope to introduce an exception to DisallowDeferredHandleDereference.
220typedef 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.
227typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>
228    DisallowJavascriptExecution;
229
230// Scope to introduce an exception to DisallowJavascriptExecution.
231typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>
232    AllowJavascriptExecution;
233
234// Scope in which javascript execution leads to exception being thrown.
235typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>
236    ThrowOnJavascriptExecution;
237
238// Scope to introduce an exception to ThrowOnJavascriptExecution.
239typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>
240    NoThrowOnJavascriptExecution;
241
242// Scope to document where we do not expect an allocation failure.
243typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, false>
244    DisallowAllocationFailure;
245
246// Scope to introduce an exception to DisallowAllocationFailure.
247typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, true>
248    AllowAllocationFailure;
249
250// Scope to document where we do not expect deoptimization.
251typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>
252    DisallowDeoptimization;
253
254// Scope to introduce an exception to DisallowDeoptimization.
255typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>
256    AllowDeoptimization;
257
258// Scope to document where we do not expect deoptimization.
259typedef PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>
260    DisallowCompilation;
261
262// Scope to introduce an exception to DisallowDeoptimization.
263typedef PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>
264    AllowCompilation;
265} }  // namespace v8::internal
266
267#endif  // V8_ASSERT_SCOPE_H_
268