// 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/common/assert-scope.h" #include "src/base/lazy-instance.h" #include "src/base/platform/platform.h" #include "src/execution/isolate.h" #include "src/utils/utils.h" namespace v8 { namespace internal { namespace { DEFINE_LAZY_LEAKY_OBJECT_GETTER(base::Thread::LocalStorageKey, GetPerThreadAssertKey, base::Thread::CreateThreadLocalKey()) } // 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(*GetPerThreadAssertKey())); } static void SetCurrent(PerThreadAssertData* data) { base::Thread::SetThreadLocal(*GetPerThreadAssertKey(), 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() { PerThreadAssertData* current_data = PerThreadAssertData::GetCurrent(); if (current_data == nullptr) { current_data = new PerThreadAssertData(); PerThreadAssertData::SetCurrent(current_data); } data_and_old_state_.update(current_data, current_data->Get(kType)); current_data->IncrementLevel(); current_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() { auto* current_data = data(); DCHECK_NOT_NULL(current_data); current_data->Set(kType, old_state()); if (current_data->DecrementLevel()) { PerThreadAssertData::SetCurrent(nullptr); delete current_data; } set_data(nullptr); } // static template <PerThreadAssertType kType, bool kAllow> bool PerThreadAssertScope<kType, kAllow>::IsAllowed() { PerThreadAssertData* current_data = PerThreadAssertData::GetCurrent(); return current_data == nullptr || current_data->Get(kType); } namespace { template <PerIsolateAssertType kType> using DataBit = base::BitField<bool, kType, 1>; } // namespace 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<kType>::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<kType>::decode(isolate->per_isolate_assert_data()); } // ----------------------------------------------------------------------------- // Instantiations. template class PerThreadAssertScope<GARBAGE_COLLECTION_ASSERT, false>; template class PerThreadAssertScope<GARBAGE_COLLECTION_ASSERT, true>; 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<CODE_DEPENDENCY_CHANGE_ASSERT, false>; template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>; template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, false>; template class PerThreadAssertScope<CODE_ALLOCATION_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<JAVASCRIPT_EXECUTION_DUMP, false>; template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, 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