1// Copyright 2014 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#include "src/assert-scope.h"
6
7#include "src/base/lazy-instance.h"
8#include "src/base/platform/platform.h"
9#include "src/isolate.h"
10#include "src/utils.h"
11
12namespace v8 {
13namespace internal {
14
15namespace {
16
17struct PerThreadAssertKeyConstructTrait final {
18  static void Construct(base::Thread::LocalStorageKey* key) {
19    *key = base::Thread::CreateThreadLocalKey();
20  }
21};
22
23
24typedef base::LazyStaticInstance<base::Thread::LocalStorageKey,
25                                 PerThreadAssertKeyConstructTrait>::type
26    PerThreadAssertKey;
27
28
29PerThreadAssertKey kPerThreadAssertKey;
30
31}  // namespace
32
33
34class PerThreadAssertData final {
35 public:
36  PerThreadAssertData() : nesting_level_(0) {
37    for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
38      assert_states_[i] = true;
39    }
40  }
41
42  ~PerThreadAssertData() {
43    for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; ++i) {
44      DCHECK(assert_states_[i]);
45    }
46  }
47
48  bool Get(PerThreadAssertType type) const { return assert_states_[type]; }
49  void Set(PerThreadAssertType type, bool x) { assert_states_[type] = x; }
50
51  void IncrementLevel() { ++nesting_level_; }
52  bool DecrementLevel() { return --nesting_level_ == 0; }
53
54  static PerThreadAssertData* GetCurrent() {
55    return reinterpret_cast<PerThreadAssertData*>(
56        base::Thread::GetThreadLocal(kPerThreadAssertKey.Get()));
57  }
58  static void SetCurrent(PerThreadAssertData* data) {
59    base::Thread::SetThreadLocal(kPerThreadAssertKey.Get(), data);
60  }
61
62 private:
63  bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE];
64  int nesting_level_;
65
66  DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
67};
68
69
70template <PerThreadAssertType kType, bool kAllow>
71PerThreadAssertScope<kType, kAllow>::PerThreadAssertScope()
72    : data_(PerThreadAssertData::GetCurrent()) {
73  if (data_ == NULL) {
74    data_ = new PerThreadAssertData();
75    PerThreadAssertData::SetCurrent(data_);
76  }
77  data_->IncrementLevel();
78  old_state_ = data_->Get(kType);
79  data_->Set(kType, kAllow);
80}
81
82
83template <PerThreadAssertType kType, bool kAllow>
84PerThreadAssertScope<kType, kAllow>::~PerThreadAssertScope() {
85  if (data_ == nullptr) return;
86  Release();
87}
88
89template <PerThreadAssertType kType, bool kAllow>
90void PerThreadAssertScope<kType, kAllow>::Release() {
91  DCHECK_NOT_NULL(data_);
92  data_->Set(kType, old_state_);
93  if (data_->DecrementLevel()) {
94    PerThreadAssertData::SetCurrent(NULL);
95    delete data_;
96  }
97  data_ = nullptr;
98}
99
100// static
101template <PerThreadAssertType kType, bool kAllow>
102bool PerThreadAssertScope<kType, kAllow>::IsAllowed() {
103  PerThreadAssertData* data = PerThreadAssertData::GetCurrent();
104  return data == NULL || data->Get(kType);
105}
106
107
108template <PerIsolateAssertType kType, bool kAllow>
109class PerIsolateAssertScope<kType, kAllow>::DataBit
110    : public BitField<bool, kType, 1> {};
111
112
113template <PerIsolateAssertType kType, bool kAllow>
114PerIsolateAssertScope<kType, kAllow>::PerIsolateAssertScope(Isolate* isolate)
115    : isolate_(isolate), old_data_(isolate->per_isolate_assert_data()) {
116  DCHECK_NOT_NULL(isolate);
117  STATIC_ASSERT(kType < 32);
118  isolate_->set_per_isolate_assert_data(DataBit::update(old_data_, kAllow));
119}
120
121
122template <PerIsolateAssertType kType, bool kAllow>
123PerIsolateAssertScope<kType, kAllow>::~PerIsolateAssertScope() {
124  isolate_->set_per_isolate_assert_data(old_data_);
125}
126
127
128// static
129template <PerIsolateAssertType kType, bool kAllow>
130bool PerIsolateAssertScope<kType, kAllow>::IsAllowed(Isolate* isolate) {
131  return DataBit::decode(isolate->per_isolate_assert_data());
132}
133
134
135// -----------------------------------------------------------------------------
136// Instantiations.
137
138template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>;
139template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>;
140template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>;
141template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>;
142template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>;
143template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>;
144template class PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>;
145template class PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>;
146template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, false>;
147template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>;
148
149template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>;
150template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>;
151template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>;
152template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>;
153template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>;
154template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>;
155template class PerIsolateAssertScope<COMPILATION_ASSERT, false>;
156template class PerIsolateAssertScope<COMPILATION_ASSERT, true>;
157template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, false>;
158template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, true>;
159
160}  // namespace internal
161}  // namespace v8
162