blob: 2d9666a1c64fd7556b8e4e57c3b889cfd7df72cf [file] [log] [blame]
// 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/enum-set.h"
#include "src/execution/isolate.h"
namespace v8 {
namespace internal {
namespace {
// All asserts are allowed by default except for one, and the cleared bit is not
// set.
constexpr PerThreadAsserts kInitialValue =
~PerThreadAsserts{HANDLE_DEREFERENCE_ALL_THREADS_ASSERT};
static_assert(kInitialValue.contains(ASSERT_TYPE_IS_VALID_MARKER));
// The cleared value is the only one where ASSERT_TYPE_IS_VALID_MARKER is not
// set.
constexpr PerThreadAsserts kClearedValue = PerThreadAsserts{};
static_assert(!kClearedValue.contains(ASSERT_TYPE_IS_VALID_MARKER));
// Thread-local storage for assert data.
thread_local PerThreadAsserts current_per_thread_assert_data(kInitialValue);
} // namespace
template <bool kAllow, PerThreadAssertType... kTypes>
PerThreadAssertScope<kAllow, kTypes...>::PerThreadAssertScope()
: old_data_(current_per_thread_assert_data) {
static_assert(((kTypes != ASSERT_TYPE_IS_VALID_MARKER) && ...),
"PerThreadAssertScope types should not include the "
"ASSERT_TYPE_IS_VALID_MARKER");
DCHECK(old_data_.contains(ASSERT_TYPE_IS_VALID_MARKER));
if (kAllow) {
current_per_thread_assert_data = old_data_ | PerThreadAsserts({kTypes...});
} else {
current_per_thread_assert_data = old_data_ - PerThreadAsserts({kTypes...});
}
}
template <bool kAllow, PerThreadAssertType... kTypes>
PerThreadAssertScope<kAllow, kTypes...>::~PerThreadAssertScope() {
Release();
}
template <bool kAllow, PerThreadAssertType... kTypes>
void PerThreadAssertScope<kAllow, kTypes...>::Release() {
if (old_data_ == kClearedValue) return;
current_per_thread_assert_data = old_data_;
old_data_ = kClearedValue;
}
// static
template <bool kAllow, PerThreadAssertType... kTypes>
bool PerThreadAssertScope<kAllow, kTypes...>::IsAllowed() {
return current_per_thread_assert_data.contains_all({kTypes...});
}
#define PER_ISOLATE_ASSERT_SCOPE_DEFINITION(ScopeType, field, enable) \
ScopeType::ScopeType(Isolate* isolate) \
: isolate_(isolate), old_data_(isolate->field()) { \
DCHECK_NOT_NULL(isolate); \
isolate_->set_##field(enable); \
} \
\
ScopeType::~ScopeType() { isolate_->set_##field(old_data_); } \
\
/* static */ \
bool ScopeType::IsAllowed(Isolate* isolate) { return isolate->field(); } \
\
/* static */ \
void ScopeType::Open(Isolate* isolate, bool* was_execution_allowed) { \
DCHECK_NOT_NULL(isolate); \
DCHECK_NOT_NULL(was_execution_allowed); \
*was_execution_allowed = isolate->field(); \
isolate->set_##field(enable); \
} \
/* static */ \
void ScopeType::Close(Isolate* isolate, bool was_execution_allowed) { \
DCHECK_NOT_NULL(isolate); \
isolate->set_##field(was_execution_allowed); \
}
#define PER_ISOLATE_ASSERT_ENABLE_SCOPE_DEFINITION(EnableType, _, field, \
enable) \
PER_ISOLATE_ASSERT_SCOPE_DEFINITION(EnableType, field, enable)
#define PER_ISOLATE_ASSERT_DISABLE_SCOPE_DEFINITION(_, DisableType, field, \
enable) \
PER_ISOLATE_ASSERT_SCOPE_DEFINITION(DisableType, field, enable)
PER_ISOLATE_DCHECK_TYPE(PER_ISOLATE_ASSERT_ENABLE_SCOPE_DEFINITION, true)
PER_ISOLATE_CHECK_TYPE(PER_ISOLATE_ASSERT_ENABLE_SCOPE_DEFINITION, true)
PER_ISOLATE_DCHECK_TYPE(PER_ISOLATE_ASSERT_DISABLE_SCOPE_DEFINITION, false)
PER_ISOLATE_CHECK_TYPE(PER_ISOLATE_ASSERT_DISABLE_SCOPE_DEFINITION, false)
// -----------------------------------------------------------------------------
// Instantiations.
template class PerThreadAssertScope<false, HEAP_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<true, HEAP_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<false, SAFEPOINTS_ASSERT>;
template class PerThreadAssertScope<true, SAFEPOINTS_ASSERT>;
template class PerThreadAssertScope<false, HANDLE_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<true, HANDLE_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<false, HANDLE_DEREFERENCE_ASSERT>;
template class PerThreadAssertScope<true, HANDLE_DEREFERENCE_ASSERT>;
template class PerThreadAssertScope<true,
HANDLE_DEREFERENCE_ALL_THREADS_ASSERT>;
template class PerThreadAssertScope<false, CODE_DEPENDENCY_CHANGE_ASSERT>;
template class PerThreadAssertScope<true, CODE_DEPENDENCY_CHANGE_ASSERT>;
template class PerThreadAssertScope<false, CODE_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<true, CODE_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<false, GC_MOLE>;
template class PerThreadAssertScope<false, POSITION_INFO_SLOW_ASSERT>;
template class PerThreadAssertScope<true, POSITION_INFO_SLOW_ASSERT>;
template class PerThreadAssertScope<false, SAFEPOINTS_ASSERT,
HEAP_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<true, SAFEPOINTS_ASSERT,
HEAP_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<
false, CODE_DEPENDENCY_CHANGE_ASSERT, HANDLE_DEREFERENCE_ASSERT,
HANDLE_ALLOCATION_ASSERT, HEAP_ALLOCATION_ASSERT>;
template class PerThreadAssertScope<
true, CODE_DEPENDENCY_CHANGE_ASSERT, HANDLE_DEREFERENCE_ASSERT,
HANDLE_ALLOCATION_ASSERT, HEAP_ALLOCATION_ASSERT>;
static_assert(Internals::kDisallowGarbageCollectionAlign ==
alignof(DisallowGarbageCollectionInRelease));
static_assert(Internals::kDisallowGarbageCollectionSize ==
sizeof(DisallowGarbageCollectionInRelease));
} // namespace internal
} // namespace v8