Home | History | Annotate | Download | only in src
      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:
     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 
     63 class 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 
     99 template <PerThreadAssertType type, bool allow>
    100 class 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 
    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:
    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 
    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:
    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