blob: 8937197d2695b3787eeee80028dd457d5d009eff [file] [log] [blame]
// Copyright 2013 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.
#ifndef V8_COMMON_ASSERT_SCOPE_H_
#define V8_COMMON_ASSERT_SCOPE_H_
#include <stdint.h>
#include <memory>
#include "src/base/macros.h"
#include "src/base/optional.h"
#include "src/base/platform/mutex.h"
#include "src/common/globals.h"
#include "src/utils/pointer-with-payload.h"
namespace v8 {
namespace internal {
// Forward declarations.
class Isolate;
class PerThreadAssertData;
template <>
struct PointerWithPayloadTraits<PerThreadAssertData> {
static constexpr int value = 1;
};
enum PerThreadAssertType {
GARBAGE_COLLECTION_ASSERT,
HEAP_ALLOCATION_ASSERT,
HANDLE_ALLOCATION_ASSERT,
HANDLE_DEREFERENCE_ASSERT,
CODE_DEPENDENCY_CHANGE_ASSERT,
CODE_ALLOCATION_ASSERT,
LAST_PER_THREAD_ASSERT_TYPE
};
enum PerIsolateAssertType {
JAVASCRIPT_EXECUTION_ASSERT,
JAVASCRIPT_EXECUTION_THROWS,
JAVASCRIPT_EXECUTION_DUMP,
DEOPTIMIZATION_ASSERT,
COMPILATION_ASSERT,
NO_EXCEPTION_ASSERT
};
template <PerThreadAssertType kType, bool kAllow>
class PerThreadAssertScope {
public:
V8_EXPORT_PRIVATE PerThreadAssertScope();
V8_EXPORT_PRIVATE ~PerThreadAssertScope();
V8_EXPORT_PRIVATE static bool IsAllowed();
void Release();
private:
PointerWithPayload<PerThreadAssertData, bool, 1> data_and_old_state_;
V8_INLINE void set_data(PerThreadAssertData* data) {
data_and_old_state_.SetPointer(data);
}
V8_INLINE PerThreadAssertData* data() const {
return data_and_old_state_.GetPointer();
}
V8_INLINE void set_old_state(bool old_state) {
return data_and_old_state_.SetPayload(old_state);
}
V8_INLINE bool old_state() const { return data_and_old_state_.GetPayload(); }
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope);
};
template <PerIsolateAssertType type, bool allow>
class PerIsolateAssertScope {
public:
V8_EXPORT_PRIVATE explicit PerIsolateAssertScope(Isolate* isolate);
V8_EXPORT_PRIVATE ~PerIsolateAssertScope();
static bool IsAllowed(Isolate* isolate);
private:
Isolate* isolate_;
uint32_t old_data_;
DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope);
};
template <PerThreadAssertType type, bool allow>
#ifdef DEBUG
class PerThreadAssertScopeDebugOnly : public PerThreadAssertScope<type, allow> {
#else
class PerThreadAssertScopeDebugOnly {
public:
PerThreadAssertScopeDebugOnly() { // NOLINT (modernize-use-equals-default)
// Define a constructor to avoid unused variable warnings.
}
void Release() {}
#endif
};
template <PerIsolateAssertType type, bool allow>
#ifdef DEBUG
class PerIsolateAssertScopeDebugOnly
: public PerIsolateAssertScope<type, allow> {
public:
explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate)
: PerIsolateAssertScope<type, allow>(isolate) {}
#else
class PerIsolateAssertScopeDebugOnly {
public:
explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) {}
#endif
};
// Per-thread assert scopes.
// Scope to document where we do not expect handles to be created.
using DisallowHandleAllocation =
PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>;
// Scope to introduce an exception to DisallowHandleAllocation.
using AllowHandleAllocation =
PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>;
// Scope to document where we do not expect garbage collections. It differs from
// DisallowHeapAllocation by also forbidding safepoints.
using DisallowGarbageCollection =
PerThreadAssertScopeDebugOnly<GARBAGE_COLLECTION_ASSERT, false>;
// The DISALLOW_GARBAGE_COLLECTION macro can be used to define a
// DisallowGarbageCollection field in classes that isn't present in release
// builds.
#ifdef DEBUG
#define DISALLOW_GARBAGE_COLLECTION(name) DisallowGarbageCollection name;
#else
#define DISALLOW_GARBAGE_COLLECTION(name)
#endif
// Scope to introduce an exception to DisallowGarbageCollection.
using AllowGarbageCollection =
PerThreadAssertScopeDebugOnly<GARBAGE_COLLECTION_ASSERT, true>;
// Scope to document where we do not expect any allocation and GC. Deprecated
// and will eventually be removed, use DisallowGarbageCollection instead.
using DisallowHeapAllocation =
PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>;
// The DISALLOW_HEAP_ALLOCATION macro can be used to define a
// DisallowHeapAllocation field in classes that isn't present in release
// builds.
#ifdef DEBUG
#define DISALLOW_HEAP_ALLOCATION(name) DisallowHeapAllocation name;
#else
#define DISALLOW_HEAP_ALLOCATION(name)
#endif
// Scope to introduce an exception to DisallowHeapAllocation.
using AllowHeapAllocation =
PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>;
// Scope to document where we do not expect any handle dereferences.
using DisallowHandleDereference =
PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>;
// Scope to introduce an exception to DisallowHandleDereference.
using AllowHandleDereference =
PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>;
// Scope to document where we do not expect code dependencies to change.
using DisallowCodeDependencyChange =
PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>;
// Scope to introduce an exception to DisallowCodeDependencyChange.
using AllowCodeDependencyChange =
PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>;
// Scope to document where we do not expect code to be allocated.
using DisallowCodeAllocation =
PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, false>;
// Scope to introduce an exception to DisallowCodeAllocation.
using AllowCodeAllocation =
PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, true>;
class DisallowHeapAccess {
DisallowCodeDependencyChange no_dependency_change_;
DisallowHandleAllocation no_handle_allocation_;
DisallowHandleDereference no_handle_dereference_;
DisallowHeapAllocation no_heap_allocation_;
};
class DisallowHeapAccessIf {
public:
explicit DisallowHeapAccessIf(bool condition) {
if (condition) maybe_disallow_.emplace();
}
private:
base::Optional<DisallowHeapAccess> maybe_disallow_;
};
// Like MutexGuard but also asserts that no heap allocation happens while
// we're holding the mutex.
class NoHeapAllocationMutexGuard {
public:
explicit NoHeapAllocationMutexGuard(base::Mutex* mutex)
: guard_(mutex), mutex_(mutex), no_gc_(new DisallowHeapAllocation()) {}
void Unlock() {
mutex_->Unlock();
no_gc_.reset();
}
void Lock() {
mutex_->Lock();
no_gc_.reset(new DisallowHeapAllocation());
}
private:
base::MutexGuard guard_;
base::Mutex* mutex_;
std::unique_ptr<DisallowHeapAllocation> no_gc_;
};
// Per-isolate assert scopes.
// Scope to document where we do not expect javascript execution.
using DisallowJavascriptExecution =
PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>;
// Scope to introduce an exception to DisallowJavascriptExecution.
using AllowJavascriptExecution =
PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>;
// Scope to document where we do not expect javascript execution (debug only)
using DisallowJavascriptExecutionDebugOnly =
PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, false>;
// Scope to introduce an exception to DisallowJavascriptExecutionDebugOnly.
using AllowJavascriptExecutionDebugOnly =
PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, true>;
// Scope in which javascript execution leads to exception being thrown.
using ThrowOnJavascriptExecution =
PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>;
// Scope to introduce an exception to ThrowOnJavascriptExecution.
using NoThrowOnJavascriptExecution =
PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>;
// Scope in which javascript execution causes dumps.
using DumpOnJavascriptExecution =
PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>;
// Scope in which javascript execution causes dumps.
using NoDumpOnJavascriptExecution =
PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>;
// Scope to document where we do not expect deoptimization.
using DisallowDeoptimization =
PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>;
// Scope to introduce an exception to DisallowDeoptimization.
using AllowDeoptimization =
PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>;
// Scope to document where we do not expect deoptimization.
using DisallowCompilation =
PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>;
// Scope to introduce an exception to DisallowDeoptimization.
using AllowCompilation =
PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>;
// Scope to document where we do not expect exceptions.
using DisallowExceptions =
PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, false>;
// Scope to introduce an exception to DisallowExceptions.
using AllowExceptions =
PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, true>;
// Explicit instantiation declarations.
extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>;
extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>;
extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>;
extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>;
extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>;
extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>;
extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT,
false>;
extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>;
extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, false>;
extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, true>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>;
extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>;
extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>;
extern template class PerIsolateAssertScope<COMPILATION_ASSERT, false>;
extern template class PerIsolateAssertScope<COMPILATION_ASSERT, true>;
extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, false>;
extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, true>;
} // namespace internal
} // namespace v8
#endif // V8_COMMON_ASSERT_SCOPE_H_