Skip to content

Commit 0bc684a

Browse files
author
yangguo@chromium.org
committed
Introduce per-isolate assert scopes and API to guard JS execution.
R=jochen@chromium.org Review URL: https://codereview.chromium.org/198253004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20062 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
1 parent 0f1f071 commit 0bc684a

17 files changed

Lines changed: 236 additions & 92 deletions

include/v8.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4084,6 +4084,37 @@ class V8_EXPORT Isolate {
40844084
Scope& operator=(const Scope&);
40854085
};
40864086

4087+
4088+
/**
4089+
* Assert that no Javascript code is invoked.
4090+
*/
4091+
class DisallowJavascriptExecutionScope {
4092+
public:
4093+
explicit DisallowJavascriptExecutionScope(Isolate* isolate);
4094+
~DisallowJavascriptExecutionScope();
4095+
4096+
private:
4097+
void* internal_;
4098+
4099+
// Prevent copying of Scope objects.
4100+
DisallowJavascriptExecutionScope(const DisallowJavascriptExecutionScope&);
4101+
DisallowJavascriptExecutionScope& operator=(
4102+
const DisallowJavascriptExecutionScope&);
4103+
};
4104+
4105+
4106+
/**
4107+
* Introduce exception to DisallowJavascriptExecutionScope.
4108+
*/
4109+
class AllowJavascriptExecutionScope {
4110+
public:
4111+
explicit AllowJavascriptExecutionScope(Isolate* isolate);
4112+
~AllowJavascriptExecutionScope();
4113+
4114+
private:
4115+
void* internal_;
4116+
};
4117+
40874118
/**
40884119
* Types of garbage collections that can be requested via
40894120
* RequestGarbageCollectionForTesting.

src/api.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6514,6 +6514,32 @@ void Isolate::Exit() {
65146514
}
65156515

65166516

6517+
Isolate::DisallowJavascriptExecutionScope::DisallowJavascriptExecutionScope(
6518+
Isolate* isolate) {
6519+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6520+
internal_ = reinterpret_cast<void*>(
6521+
new i::DisallowJavascriptExecution(i_isolate));
6522+
}
6523+
6524+
6525+
Isolate::DisallowJavascriptExecutionScope::~DisallowJavascriptExecutionScope() {
6526+
delete reinterpret_cast<i::DisallowJavascriptExecution*>(internal_);
6527+
}
6528+
6529+
6530+
Isolate::AllowJavascriptExecutionScope::AllowJavascriptExecutionScope(
6531+
Isolate* isolate) {
6532+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
6533+
internal_ = reinterpret_cast<void*>(
6534+
new i::AllowJavascriptExecution(i_isolate));
6535+
}
6536+
6537+
6538+
Isolate::AllowJavascriptExecutionScope::~AllowJavascriptExecutionScope() {
6539+
delete reinterpret_cast<i::AllowJavascriptExecution*>(internal_);
6540+
}
6541+
6542+
65176543
void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) {
65186544
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
65196545
if (!isolate->IsInitialized()) {

src/assert-scope.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
6+
#include "assert-scope.h"
7+
#include "v8.h"
8+
9+
namespace v8 {
10+
namespace internal {
11+
12+
uint32_t PerIsolateAssertBase::GetData(Isolate* isolate) {
13+
return isolate->per_isolate_assert_data();
14+
}
15+
16+
17+
void PerIsolateAssertBase::SetData(Isolate* isolate, uint32_t data) {
18+
isolate->set_per_isolate_assert_data(data);
19+
}
20+
21+
} } // namespace v8::internal

src/assert-scope.h

Lines changed: 100 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include "allocation.h"
3232
#include "platform.h"
33+
#include "utils.h"
3334

3435
namespace v8 {
3536
namespace internal {
@@ -46,7 +47,12 @@ enum PerThreadAssertType {
4647
};
4748

4849

49-
#ifdef DEBUG
50+
enum PerIsolateAssertType {
51+
JAVASCRIPT_EXECUTION_ASSERT,
52+
ALLOCATION_FAILURE_ASSERT
53+
};
54+
55+
5056
class PerThreadAssertData {
5157
public:
5258
PerThreadAssertData() : nesting_level_(0) {
@@ -72,12 +78,9 @@ class PerThreadAssertData {
7278

7379
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData);
7480
};
75-
#endif // DEBUG
7681

7782

7883
class PerThreadAssertScopeBase {
79-
#ifdef DEBUG
80-
8184
protected:
8285
PerThreadAssertScopeBase() {
8386
data_ = GetAssertData();
@@ -110,18 +113,12 @@ class PerThreadAssertScopeBase {
110113
static void SetThreadLocalData(PerThreadAssertData* data) {
111114
Thread::SetThreadLocal(thread_local_key, data);
112115
}
113-
#endif // DEBUG
114116
};
115117

116118

117-
118119
template <PerThreadAssertType type, bool allow>
119120
class PerThreadAssertScope : public PerThreadAssertScopeBase {
120121
public:
121-
#ifndef DEBUG
122-
PerThreadAssertScope() { }
123-
static void SetIsAllowed(bool is_allowed) { }
124-
#else
125122
PerThreadAssertScope() {
126123
old_state_ = data_->get(type);
127124
data_->set(type, allow);
@@ -136,49 +133,132 @@ class PerThreadAssertScope : public PerThreadAssertScopeBase {
136133

137134
private:
138135
bool old_state_;
136+
137+
DISALLOW_COPY_AND_ASSIGN(PerThreadAssertScope);
138+
};
139+
140+
141+
class PerIsolateAssertBase {
142+
protected:
143+
static uint32_t GetData(Isolate* isolate);
144+
static void SetData(Isolate* isolate, uint32_t data);
145+
};
146+
147+
148+
template <PerIsolateAssertType type, bool allow>
149+
class PerIsolateAssertScope : public PerIsolateAssertBase {
150+
public:
151+
explicit PerIsolateAssertScope(Isolate* isolate) : isolate_(isolate) {
152+
STATIC_ASSERT(type < 32);
153+
old_data_ = GetData(isolate_);
154+
SetData(isolate_, DataBit::update(old_data_, allow));
155+
}
156+
157+
~PerIsolateAssertScope() {
158+
SetData(isolate_, old_data_);
159+
}
160+
161+
static bool IsAllowed(Isolate* isolate) {
162+
return DataBit::decode(GetData(isolate));
163+
}
164+
165+
private:
166+
typedef BitField<bool, type, 1> DataBit;
167+
168+
uint32_t old_data_;
169+
Isolate* isolate_;
170+
171+
DISALLOW_COPY_AND_ASSIGN(PerIsolateAssertScope);
172+
};
173+
174+
175+
template <PerThreadAssertType type, bool allow>
176+
#ifdef DEBUG
177+
class PerThreadAssertScopeDebugOnly : public
178+
PerThreadAssertScope<type, allow> {
179+
#else
180+
class PerThreadAssertScopeDebugOnly {
181+
public:
182+
PerThreadAssertScopeDebugOnly() { }
183+
#endif
184+
};
185+
186+
187+
template <PerIsolateAssertType type, bool allow>
188+
#ifdef DEBUG
189+
class PerIsolateAssertScopeDebugOnly : public
190+
PerIsolateAssertScope<type, allow> {
191+
public:
192+
explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate)
193+
: PerIsolateAssertScope<type, allow>(isolate) { }
194+
#else
195+
class PerIsolateAssertScopeDebugOnly {
196+
public:
197+
explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) { }
139198
#endif
140199
};
141200

201+
// Per-thread assert scopes.
202+
142203
// Scope to document where we do not expect handles to be created.
143-
typedef PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>
204+
typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>
144205
DisallowHandleAllocation;
145206

146207
// Scope to introduce an exception to DisallowHandleAllocation.
147-
typedef PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>
208+
typedef PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>
148209
AllowHandleAllocation;
149210

150211
// Scope to document where we do not expect any allocation and GC.
151-
typedef PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>
212+
typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>
152213
DisallowHeapAllocation;
153214

154215
// Scope to introduce an exception to DisallowHeapAllocation.
155-
typedef PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>
216+
typedef PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>
156217
AllowHeapAllocation;
157218

158219
// Scope to document where we do not expect any handle dereferences.
159-
typedef PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>
220+
typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>
160221
DisallowHandleDereference;
161222

162223
// Scope to introduce an exception to DisallowHandleDereference.
163-
typedef PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>
224+
typedef PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>
164225
AllowHandleDereference;
165226

166227
// Scope to document where we do not expect deferred handles to be dereferenced.
167-
typedef PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>
228+
typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, false>
168229
DisallowDeferredHandleDereference;
169230

170231
// Scope to introduce an exception to DisallowDeferredHandleDereference.
171-
typedef PerThreadAssertScope<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>
232+
typedef PerThreadAssertScopeDebugOnly<DEFERRED_HANDLE_DEREFERENCE_ASSERT, true>
172233
AllowDeferredHandleDereference;
173234

174235
// Scope to document where we do not expect deferred handles to be dereferenced.
175-
typedef PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, false>
236+
typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>
176237
DisallowCodeDependencyChange;
177238

178239
// Scope to introduce an exception to DisallowDeferredHandleDereference.
179-
typedef PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>
240+
typedef PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>
180241
AllowCodeDependencyChange;
181242

243+
244+
// Per-isolate assert scopes.
245+
246+
// Scope to document where we do not expect javascript execution.
247+
typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>
248+
DisallowJavascriptExecution;
249+
250+
// Scope to introduce an exception to DisallowJavascriptExecution.
251+
typedef PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>
252+
AllowJavascriptExecution;
253+
254+
// Scope to document where we do not expect an allocation failure.
255+
typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, false>
256+
DisallowAllocationFailure;
257+
258+
// Scope to introduce an exception to DisallowAllocationFailure.
259+
typedef PerIsolateAssertScopeDebugOnly<ALLOCATION_FAILURE_ASSERT, true>
260+
AllowAllocationFailure;
261+
182262
} } // namespace v8::internal
183263

184264
#endif // V8_ASSERT_SCOPE_H_

src/builtins.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1665,7 +1665,7 @@ void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
16651665
{
16661666
// During startup it's OK to always allocate and defer GC to later.
16671667
// This simplifies things because we don't need to retry.
1668-
AlwaysAllocateScope __scope__;
1668+
AlwaysAllocateScope __scope__(isolate);
16691669
{ MaybeObject* maybe_code =
16701670
heap->CreateCode(desc, flags, masm.CodeObject());
16711671
if (!maybe_code->ToObject(&code)) {

src/execution.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ static Handle<Object> Invoke(bool is_construct,
7777

7878
// Entering JavaScript.
7979
VMState<JS> state(isolate);
80+
CHECK(AllowJavascriptExecution::IsAllowed(isolate));
8081

8182
// Placeholder for return value.
8283
MaybeObject* value = reinterpret_cast<Object*>(kZapValue);

src/heap-inl.h

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ MaybeObject* Heap::AllocateRaw(int size_in_bytes,
223223
HeapProfiler* profiler = isolate_->heap_profiler();
224224
#ifdef DEBUG
225225
if (FLAG_gc_interval >= 0 &&
226-
!disallow_allocation_failure_ &&
226+
AllowAllocationFailure::IsAllowed(isolate_) &&
227227
Heap::allocation_timeout_-- <= 0) {
228228
return Failure::RetryAfterGC(space);
229229
}
@@ -663,7 +663,7 @@ Isolate* Heap::isolate() {
663663
(ISOLATE)->counters()->gc_last_resort_from_handles()->Increment(); \
664664
(ISOLATE)->heap()->CollectAllAvailableGarbage("last resort gc"); \
665665
{ \
666-
AlwaysAllocateScope __scope__; \
666+
AlwaysAllocateScope __scope__(ISOLATE); \
667667
__maybe_object__ = FUNCTION_CALL; \
668668
} \
669669
if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \
@@ -778,21 +778,20 @@ void Heap::CompletelyClearInstanceofCache() {
778778
}
779779

780780

781-
AlwaysAllocateScope::AlwaysAllocateScope() {
781+
AlwaysAllocateScope::AlwaysAllocateScope(Isolate* isolate)
782+
: heap_(isolate->heap()), daf_(isolate) {
782783
// We shouldn't hit any nested scopes, because that requires
783784
// non-handle code to call handle code. The code still works but
784785
// performance will degrade, so we want to catch this situation
785786
// in debug mode.
786-
Isolate* isolate = Isolate::Current();
787-
ASSERT(isolate->heap()->always_allocate_scope_depth_ == 0);
788-
isolate->heap()->always_allocate_scope_depth_++;
787+
ASSERT(heap_->always_allocate_scope_depth_ == 0);
788+
heap_->always_allocate_scope_depth_++;
789789
}
790790

791791

792792
AlwaysAllocateScope::~AlwaysAllocateScope() {
793-
Isolate* isolate = Isolate::Current();
794-
isolate->heap()->always_allocate_scope_depth_--;
795-
ASSERT(isolate->heap()->always_allocate_scope_depth_ == 0);
793+
heap_->always_allocate_scope_depth_--;
794+
ASSERT(heap_->always_allocate_scope_depth_ == 0);
796795
}
797796

798797

@@ -848,23 +847,6 @@ double GCTracer::SizeOfHeapObjects() {
848847
}
849848

850849

851-
DisallowAllocationFailure::DisallowAllocationFailure() {
852-
#ifdef DEBUG
853-
Isolate* isolate = Isolate::Current();
854-
old_state_ = isolate->heap()->disallow_allocation_failure_;
855-
isolate->heap()->disallow_allocation_failure_ = true;
856-
#endif
857-
}
858-
859-
860-
DisallowAllocationFailure::~DisallowAllocationFailure() {
861-
#ifdef DEBUG
862-
Isolate* isolate = Isolate::Current();
863-
isolate->heap()->disallow_allocation_failure_ = old_state_;
864-
#endif
865-
}
866-
867-
868850
} } // namespace v8::internal
869851

870852
#endif // V8_HEAP_INL_H_

src/heap.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ Heap::Heap()
105105
unflattened_strings_length_(0),
106106
#ifdef DEBUG
107107
allocation_timeout_(0),
108-
disallow_allocation_failure_(false),
109108
#endif // DEBUG
110109
new_space_high_promotion_mode_active_(false),
111110
old_generation_allocation_limit_(kMinimumOldGenerationAllocationLimit),
@@ -7618,7 +7617,7 @@ void DescriptorLookupCache::Clear() {
76187617
void Heap::GarbageCollectionGreedyCheck() {
76197618
ASSERT(FLAG_gc_greedy);
76207619
if (isolate_->bootstrapper()->IsActive()) return;
7621-
if (disallow_allocation_failure()) return;
7620+
if (!AllowAllocationFailure::IsAllowed(isolate_)) return;
76227621
CollectGarbage(NEW_SPACE);
76237622
}
76247623
#endif

0 commit comments

Comments
 (0)