| // Copyright 2014 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/assert-scope.h" | |
| #include "src/base/lazy-instance.h" | |
| #include "src/base/platform/platform.h" | |
| #include "src/isolate.h" | |
| #include "src/utils.h" | |
| namespace v8 { | |
| namespace internal { | |
| namespace { | |
| struct PerThreadAssertKeyConstructTrait final { | |
| static void Construct(void* key_arg) { | |
| auto key = reinterpret_cast<base::Thread::LocalStorageKey*>(key_arg); | |
| *key = base::Thread::CreateThreadLocalKey(); | |
| } | |
| }; | |
| typedef base::LazyStaticInstance<base::Thread::LocalStorageKey, | |
| PerThreadAssertKeyConstructTrait>::type | |
| PerThreadAssertKey; | |
| PerThreadAssertKey kPerThreadAssertKey; | |
| } // namespace | |
| class PerThreadAssertData final { | |
| public: | |
| PerThreadAssertData() : nesting_level_(0) { | |
| for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) { | |
| assert_states_[i] = true; | |
| } | |
| } | |
| ~PerThreadAssertData() { | |
| for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; ++i) { | |
| DCHECK(assert_states_[i]); | |
| } | |
| } | |
| bool Get(PerThreadAssertType type) const { return assert_states_[type]; } | |
| void Set(PerThreadAssertType type, bool x) { assert_states_[type] = x; } | |
| void IncrementLevel() { ++nesting_level_; } | |
| bool DecrementLevel() { return --nesting_level_ == 0; } | |
| static PerThreadAssertData* GetCurrent() { | |
| return reinterpret_cast<PerThreadAssertData*>( | |
| base::Thread::GetThreadLocal(kPerThreadAssertKey.Get())); | |
| } | |
| static void SetCurrent(PerThreadAssertData* data) { | |
| base::Thread::SetThreadLocal(kPerThreadAssertKey.Get(), data); | |
| } | |
| private: | |
| bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE]; | |
| int nesting_level_; | |
| DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData); | |
| }; | |
| template <PerThreadAssertType kType, bool kAllow> | |
| PerThreadAssertScope<kType, kAllow>::PerThreadAssertScope() | |
| : data_(PerThreadAssertData::GetCurrent()) { | |
| if (data_ == nullptr) { | |
| data_ = new PerThreadAssertData(); | |
| PerThreadAssertData::SetCurrent(data_); | |
| } | |
| data_->IncrementLevel(); | |
| old_state_ = data_->Get(kType); | |
| data_->Set(kType, kAllow); | |
| } | |
| template <PerThreadAssertType kType, bool kAllow> | |
| PerThreadAssertScope<kType, kAllow>::~PerThreadAssertScope() { | |
| if (data_ == nullptr) return; | |
| Release(); | |
| } | |
| template <PerThreadAssertType kType, bool kAllow> | |
| void PerThreadAssertScope<kType, kAllow>::Release() { | |
| DCHECK_NOT_NULL(data_); | |
| data_->Set(kType, old_state_); | |
| if (data_->DecrementLevel()) { | |
| PerThreadAssertData::SetCurrent(nullptr); | |
| delete data_; | |
| } | |
| data_ = nullptr; | |
| } | |
| // static | |
| template <PerThreadAssertType kType, bool kAllow> | |
| bool PerThreadAssertScope<kType, kAllow>::IsAllowed() { | |
| PerThreadAssertData* data = PerThreadAssertData::GetCurrent(); | |
| return data == nullptr || data->Get(kType); | |
| } | |
| template <PerIsolateAssertType kType, bool kAllow> | |
| class PerIsolateAssertScope<kType, kAllow>::DataBit | |
| : public BitField<bool, kType, 1> {}; | |
| template <PerIsolateAssertType kType, bool kAllow> | |
| PerIsolateAssertScope<kType, kAllow>::PerIsolateAssertScope(Isolate* isolate) | |
| : isolate_(isolate), old_data_(isolate->per_isolate_assert_data()) { | |
| DCHECK_NOT_NULL(isolate); | |
| STATIC_ASSERT(kType < 32); | |
| isolate_->set_per_isolate_assert_data(DataBit::update(old_data_, kAllow)); | |
| } | |
| template <PerIsolateAssertType kType, bool kAllow> | |
| PerIsolateAssertScope<kType, kAllow>::~PerIsolateAssertScope() { | |
| isolate_->set_per_isolate_assert_data(old_data_); | |
| } | |
| // static | |
| template <PerIsolateAssertType kType, bool kAllow> | |
| bool PerIsolateAssertScope<kType, kAllow>::IsAllowed(Isolate* isolate) { | |
| return DataBit::decode(isolate->per_isolate_assert_data()); | |
| } | |
| // ----------------------------------------------------------------------------- | |
| // Instantiations. | |
| template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>; | |
| template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>; | |
| template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>; | |
| template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>; | |
| template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>; | |
| template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>; | |
| template class PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>; | |
| template class PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>; | |
| template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, false>; | |
| template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>; | |
| template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>; | |
| template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>; | |
| template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>; | |
| template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>; | |
| template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>; | |
| template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>; | |
| template class PerIsolateAssertScope<COMPILATION_ASSERT, false>; | |
| template class PerIsolateAssertScope<COMPILATION_ASSERT, true>; | |
| template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, false>; | |
| template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, true>; | |
| } // namespace internal | |
| } // namespace v8 |