// 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(key_arg); *key = base::Thread::CreateThreadLocalKey(); } }; typedef base::LazyStaticInstance::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( 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 PerThreadAssertScope::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 PerThreadAssertScope::~PerThreadAssertScope() { if (data_ == nullptr) return; Release(); } template void PerThreadAssertScope::Release() { DCHECK_NOT_NULL(data_); data_->Set(kType, old_state_); if (data_->DecrementLevel()) { PerThreadAssertData::SetCurrent(nullptr); delete data_; } data_ = nullptr; } // static template bool PerThreadAssertScope::IsAllowed() { PerThreadAssertData* data = PerThreadAssertData::GetCurrent(); return data == nullptr || data->Get(kType); } template class PerIsolateAssertScope::DataBit : public BitField {}; template PerIsolateAssertScope::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 PerIsolateAssertScope::~PerIsolateAssertScope() { isolate_->set_per_isolate_assert_data(old_data_); } // static template bool PerIsolateAssertScope::IsAllowed(Isolate* isolate) { return DataBit::decode(isolate->per_isolate_assert_data()); } // ----------------------------------------------------------------------------- // Instantiations. template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerThreadAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; template class PerIsolateAssertScope; } // namespace internal } // namespace v8