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