blob: 5086eaa426932e5b0ea67cab17d1b2e9f191b054 [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_ASSERT_SCOPE_H_
#define V8_ASSERT_SCOPE_H_
#include "allocation.h"
#include "platform.h"
#include "utils.h"
namespace v8 {
namespace internal {
class Isolate;
enum PerThreadAssertType {
HEAP_ALLOCATION_ASSERT,
HANDLE_ALLOCATION_ASSERT,
HANDLE_DEREFERENCE_ASSERT,
DEFERRED_HANDLE_DEREFERENCE_ASSERT,
CODE_DEPENDENCY_CHANGE_ASSERT,
LAST_PER_THREAD_ASSERT_TYPE
};
enum PerIsolateAssertType {
JAVASCRIPT_EXECUTION_ASSERT,
JAVASCRIPT_EXECUTION_THROWS,
ALLOCATION_FAILURE_ASSERT,
DEOPTIMIZATION_ASSERT
};
class PerThreadAssertData {
public:
PerThreadAssertData() : nesting_level_(0) {
for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
assert_states_[i] = true;
}
}
void set(PerThreadAssertType type, bool allow) {
assert_states_[type] = allow;
}
bool get(PerThreadAssertType type) const {
return assert_states_[type];
}
void increment_level() { ++nesting_level_; }
bool decrement_level() { return --nesting_level_ == 0; }
private:
bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE];
int nesting_level_;
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
};
class PerThreadAssertScopeBase {
protected:
PerThreadAssertScopeBase() {
data_ = GetAssertData();
if (data_ == NULL) {
data_ = new PerThreadAssertData();
SetThreadLocalData(data_);
}
data_->increment_level();
}
~PerThreadAssertScopeBase() {
if (!data_->decrement_level()) return;
for (int i = 0; i < LAST_PER_THREAD_ASSERT_TYPE; i++) {
ASSERT(data_->get(static_cast<PerThreadAssertType>(i)));
}
delete data_;
SetThreadLocalData(NULL);
}
static PerThreadAssertData* GetAssertData() {
return reinterpret_cast<PerThreadAssertData*>(
Thread::GetThreadLocal(thread_local_key));
}
static Thread::LocalStorageKey thread_local_key;
PerThreadAssertData* data_;
friend class Isolate;
private:
static void SetThreadLocalData(PerThreadAssertData* data) {
Thread::SetThreadLocal(thread_local_key, data);
}
};
template <PerThreadAssertType type, bool allow>
class PerThreadAssertScope : public PerThreadAssertScopeBase {
public:
PerThreadAssertScope() {
old_state_ = data_->get(type);
data_->set(type, allow);
}
~PerThreadAssertScope() { data_->set(type, old_state_); }
static bool IsAllowed() {
PerThreadAssertData* data = GetAssertData();
return data == NULL || data->get(type);
}
private:
bool old_state_;
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope);
};
class PerIsolateAssertBase {
protected:
static uint32_t GetData(Isolate* isolate);
static void SetData(Isolate* isolate, uint32_t data);
};
template <PerIsolateAssertType type, bool allow>
class PerIsolateAssertScope : public PerIsolateAssertBase {
public:
explicit PerIsolateAssertScope(Isolate* isolate) : isolate_(isolate) {
STATIC_ASSERT(type < 32);
old_data_ = GetData(isolate_);
SetData(isolate_, DataBit::update(old_data_, allow));
}
~PerIsolateAssertScope() {
SetData(isolate_, old_data_);
}
static bool IsAllowed(Isolate* isolate) {
return DataBit::decode(GetData(isolate));
}
private:
typedef BitField<bool, type, 1> DataBit;
uint32_t old_data_;
Isolate* isolate_;
DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope);
};
template <PerThreadAssertType type, bool allow>
#ifdef DEBUG
class PerThreadAssertScopeDebugOnly : public
PerThreadAssertScope<type, allow> {
#else
class PerThreadAssertScopeDebugOnly {
public:
PerThreadAssertScopeDebugOnly() { }
#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.
typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>
DisallowHandleAllocation;
// Scope to introduce an exception to DisallowHandleAllocation.
typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>
AllowHandleAllocation;
// Scope to document where we do not expect any allocation and GC.
typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>
DisallowHeapAllocation;
// Scope to introduce an exception to DisallowHeapAllocation.
typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>
AllowHeapAllocation;
// Scope to document where we do not expect any handle dereferences.
typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>
DisallowHandleDereference;
// Scope to introduce an exception to DisallowHandleDereference.
typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>
AllowHandleDereference;
// Scope to document where we do not expect deferred handles to be dereferenced.
typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>
DisallowDeferredHandleDereference;
// Scope to introduce an exception to DisallowDeferredHandleDereference.
typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>
AllowDeferredHandleDereference;
// Scope to document where we do not expect deferred handles to be dereferenced.
typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>
DisallowCodeDependencyChange;
// Scope to introduce an exception to DisallowDeferredHandleDereference.
typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>
AllowCodeDependencyChange;
// Per-isolate assert scopes.
// Scope to document where we do not expect javascript execution.
typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>
DisallowJavascriptExecution;
// Scope to introduce an exception to DisallowJavascriptExecution.
typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>
AllowJavascriptExecution;
// Scope in which javascript execution leads to exception being thrown.
typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>
ThrowOnJavascriptExecution;
// Scope to introduce an exception to ThrowOnJavascriptExecution.
typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>
NoThrowOnJavascriptExecution;
// Scope to document where we do not expect an allocation failure.
typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, false>
DisallowAllocationFailure;
// Scope to introduce an exception to DisallowAllocationFailure.
typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, true>
AllowAllocationFailure;
// Scope to document where we do not expect deoptimization.
typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>
DisallowDeoptimization;
// Scope to introduce an exception to DisallowDeoptimization.
typedef PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>
AllowDeoptimization;
} } // namespace v8::internal
#endif // V8_ASSERT_SCOPE_H_