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