From: yangguo@chromium.org Date: Mon, 3 Jun 2013 15:32:22 +0000 (+0000) Subject: Make assertion scopes thread safe. X-Git-Tag: upstream/4.7.83~14032 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7f8a3d803cf1136f3e502e533c5a3e1dc8cb3163;p=platform%2Fupstream%2Fv8.git Make assertion scopes thread safe. R=svenpanne@chromium.org BUG= Review URL: https://chromiumcodereview.appspot.com/15691017 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14919 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/include/v8.h b/include/v8.h index 54b513a02..a41445d82 100644 --- a/include/v8.h +++ b/include/v8.h @@ -4142,13 +4142,13 @@ class V8EXPORT PersistentHandleVisitor { // NOLINT */ class V8EXPORT AssertNoGCScope { #ifndef DEBUG - V8_INLINE(AssertNoGCScope(Isolate* isolate)) {} + // TODO(yangguo): remove isolate argument. + V8_INLINE(AssertNoGCScope(Isolate* isolate)) { } #else AssertNoGCScope(Isolate* isolate); ~AssertNoGCScope(); private: - Isolate* isolate_; - bool last_state_; + void* disallow_heap_allocation_; #endif }; diff --git a/src/accessors.cc b/src/accessors.cc index 64047a284..202a5170d 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -687,7 +687,7 @@ const AccessorDescriptor Accessors::FunctionArguments = { class FrameFunctionIterator { public: - FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise) + FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise) : frame_iterator_(isolate), functions_(2), index_(0) { @@ -734,13 +734,13 @@ class FrameFunctionIterator { MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) { Isolate* isolate = Isolate::Current(); HandleScope scope(isolate); - AssertNoAllocation no_alloc; + DisallowHeapAllocation no_allocation; JSFunction* holder = FindInstanceOf(isolate, object); if (holder == NULL) return isolate->heap()->undefined_value(); if (holder->shared()->native()) return isolate->heap()->null_value(); Handle function(holder, isolate); - FrameFunctionIterator it(isolate, no_alloc); + FrameFunctionIterator it(isolate, no_allocation); // Find the function from the frames. if (!it.Find(*function)) { diff --git a/src/api.cc b/src/api.cc index 0755ae192..7645a3f7a 100644 --- a/src/api.cc +++ b/src/api.cc @@ -32,6 +32,7 @@ #include "../include/v8-debug.h" #include "../include/v8-profiler.h" #include "../include/v8-testing.h" +#include "assert-scope.h" #include "bootstrapper.h" #include "code-stubs.h" #include "compiler.h" @@ -5101,7 +5102,7 @@ void v8::V8::VisitHandlesWithClassIds(PersistentHandleVisitor* visitor) { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::V8::VisitHandlesWithClassId"); - i::AssertNoAllocation no_allocation; + i::DisallowHeapAllocation no_allocation; VisitorAdapter visitor_adapter(visitor); isolate->global_handles()->IterateAllRootsWithClassIds(&visitor_adapter); @@ -5114,7 +5115,7 @@ void v8::V8::VisitHandlesForPartialDependence( ASSERT(isolate == i::Isolate::Current()); IsDeadCheck(isolate, "v8::V8::VisitHandlesForPartialDependence"); - i::AssertNoAllocation no_allocation; + i::DisallowHeapAllocation no_allocation; VisitorAdapter visitor_adapter(visitor); isolate->global_handles()->IterateAllRootsInNewSpaceWithClassIds( @@ -6265,14 +6266,12 @@ Local v8::Integer::NewFromUnsigned(uint32_t value, Isolate* isolate) { #ifdef DEBUG -v8::AssertNoGCScope::AssertNoGCScope(v8::Isolate* isolate) - : isolate_(isolate), - last_state_(i::EnterAllocationScope( - reinterpret_cast(isolate), false)) { +v8::AssertNoGCScope::AssertNoGCScope(v8::Isolate* isolate) { + disallow_heap_allocation_ = new i::DisallowHeapAllocation(); } v8::AssertNoGCScope::~AssertNoGCScope() { - i::ExitAllocationScope(reinterpret_cast(isolate_), last_state_); + delete static_cast(disallow_heap_allocation_); } #endif @@ -7804,8 +7803,7 @@ DeferredHandles* HandleScopeImplementer::Detach(Object** prev_limit) { while (!blocks_.is_empty()) { Object** block_start = blocks_.last(); Object** block_limit = &block_start[kHandleBlockSize]; - // We should not need to check for NoHandleAllocation here. Assert - // this. + // We should not need to check for SealHandleScope here. Assert this. ASSERT(prev_limit == block_limit || !(block_start <= prev_limit && prev_limit <= block_limit)); if (prev_limit == block_limit) break; diff --git a/src/api.h b/src/api.h index 62380ce65..3d7e3778e 100644 --- a/src/api.h +++ b/src/api.h @@ -636,7 +636,7 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { internal::Object** block_start = blocks_.last(); internal::Object** block_limit = block_start + kHandleBlockSize; #ifdef DEBUG - // NoHandleAllocation may make the prev_limit to point inside the block. + // SealHandleScope may make the prev_limit to point inside the block. if (block_start <= prev_limit && prev_limit <= block_limit) { #ifdef ENABLE_EXTRA_CHECKS internal::HandleScope::ZapRange(prev_limit, block_limit); diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 0102f337b..66c3dbf03 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -308,7 +308,7 @@ Operand::Operand(Handle handle) { #ifdef DEBUG Isolate* isolate = Isolate::Current(); #endif - ALLOW_HANDLE_DEREF(isolate, "using and embedding raw address"); + AllowDeferredHandleDereference using_raw_address; rm_ = no_reg; // Verify all Objects referred by code are NOT in new space. Object* obj = *handle; diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc index d973889bb..ea3287aa3 100644 --- a/src/arm/deoptimizer-arm.cc +++ b/src/arm/deoptimizer-arm.cc @@ -48,7 +48,7 @@ void Deoptimizer::DeoptimizeFunctionWithPreparedFunctionList( JSFunction* function) { Isolate* isolate = function->GetIsolate(); HandleScope scope(isolate); - AssertNoAllocation no_allocation; + DisallowHeapAllocation no_allocation; ASSERT(function->IsOptimized()); ASSERT(function->FunctionsInFunctionListShareSameCode()); diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 06a6506b2..2ef695160 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -947,8 +947,7 @@ void LCodeGen::PopulateDeoptimizationData(Handle code) { Handle literals = factory()->NewFixedArray(deoptimization_literals_.length(), TENURED); - { ALLOW_HANDLE_DEREF(isolate(), - "copying a ZoneList of handles into a FixedArray"); + { AllowDeferredHandleDereference copy_handles; for (int i = 0; i < deoptimization_literals_.length(); i++) { literals->set(i, *deoptimization_literals_[i]); } @@ -1920,7 +1919,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) { void LCodeGen::DoConstantT(LConstantT* instr) { Handle value = instr->value(); - ALLOW_HANDLE_DEREF(isolate(), "smi check"); + AllowDeferredHandleDereference smi_check; if (value->IsSmi()) { __ mov(ToRegister(instr->result()), Operand(value)); } else { @@ -5291,7 +5290,7 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { void LCodeGen::DoCheckFunction(LCheckFunction* instr) { Register reg = ToRegister(instr->value()); Handle target = instr->hydrogen()->target(); - ALLOW_HANDLE_DEREF(isolate(), "smi check"); + AllowDeferredHandleDereference smi_check; if (isolate()->heap()->InNewSpace(*target)) { Register reg = ToRegister(instr->value()); Handle cell = diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 9d87c6090..f3cfdc76a 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -74,7 +74,7 @@ void MacroAssembler::Jump(Handle code, RelocInfo::Mode rmode, Condition cond) { ASSERT(RelocInfo::IsCodeTarget(rmode)); // 'code' is always generated ARM code, never THUMB code - ALLOW_HANDLE_DEREF(isolate(), "embedding raw address"); + AllowDeferredHandleDereference embedding_raw_address; Jump(reinterpret_cast(code.location()), rmode, cond); } @@ -163,7 +163,7 @@ int MacroAssembler::CallSize(Handle code, RelocInfo::Mode rmode, TypeFeedbackId ast_id, Condition cond) { - ALLOW_HANDLE_DEREF(isolate(), "using raw address"); + AllowDeferredHandleDereference using_raw_address; return CallSize(reinterpret_cast
(code.location()), rmode, cond); } @@ -181,7 +181,7 @@ void MacroAssembler::Call(Handle code, rmode = RelocInfo::CODE_TARGET_WITH_ID; } // 'code' is always generated ARM code, never THUMB code - ALLOW_HANDLE_DEREF(isolate(), "embedding raw address"); + AllowDeferredHandleDereference embedding_raw_address; Call(reinterpret_cast
(code.location()), rmode, cond, mode); } @@ -398,7 +398,7 @@ void MacroAssembler::StoreRoot(Register source, void MacroAssembler::LoadHeapObject(Register result, Handle object) { - ALLOW_HANDLE_DEREF(isolate(), "using raw address"); + AllowDeferredHandleDereference using_raw_address; if (isolate()->heap()->InNewSpace(*object)) { Handle cell = isolate()->factory()->NewJSGlobalPropertyCell(object); diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 25e4a04fe..11d3066b9 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -162,7 +162,7 @@ class MacroAssembler: public Assembler { void LoadHeapObject(Register dst, Handle object); void LoadObject(Register result, Handle object) { - ALLOW_HANDLE_DEREF(isolate(), "heap object check"); + AllowDeferredHandleDereference heap_object_check; if (object->IsHeapObject()) { LoadHeapObject(result, Handle::cast(object)); } else { diff --git a/src/assert-scope.h b/src/assert-scope.h new file mode 100644 index 000000000..d32d680d1 --- /dev/null +++ b/src/assert-scope.h @@ -0,0 +1,149 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_ASSERT_SCOPE_H_ +#define V8_ASSERT_SCOPE_H_ + +#include "allocation.h" +#include "platform.h" + +namespace v8 { +namespace internal { + +class Isolate; + +enum PerThreadAssertType { + HEAP_ALLOCATION_ASSERT, + HANDLE_ALLOCATION_ASSERT, + HANDLE_DEREFERENCE_ASSERT, + DEFERRED_HANDLE_DEREFERENCE_ASSERT, + LAST_PER_THREAD_ASSERT_TYPE +}; + + +#ifdef DEBUG +class PerThreadAssertData { + public: + PerThreadAssertData() { + 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]; + } + + private: + bool assert_states_[LAST_PER_THREAD_ASSERT_TYPE]; + + DISALLOW_COPY_AND_ASSIGN(PerThreadAssertData); +}; +#endif // DEBUG + + +class PerThreadAssertScopeBase { +#ifdef DEBUG + protected: + static PerThreadAssertData* AssertData() { + PerThreadAssertData* data = reinterpret_cast( + Thread::GetThreadLocal(thread_local_key)); + if (data == NULL) { + data = new PerThreadAssertData(); + Thread::SetThreadLocal(thread_local_key, data); + } + return data; + } + + static Thread::LocalStorageKey thread_local_key; + friend class Isolate; +#endif // DEBUG +}; + + + +template +class PerThreadAssertScope : public PerThreadAssertScopeBase { + public: +#ifndef DEBUG + PerThreadAssertScope() { } + static void SetIsAllowed(bool is_allowed) { } +#else + PerThreadAssertScope() { + PerThreadAssertData* data = AssertData(); + old_state_ = data->get(type); + data->set(type, allow); + } + + ~PerThreadAssertScope() { AssertData()->set(type, old_state_); } + + static bool IsAllowed() { return AssertData()->get(type); } + + private: + bool old_state_; +#endif +}; + +// Scope to document where we do not expect handles to be created. +typedef PerThreadAssertScope + DisallowHandleAllocation; + +// Scope to introduce an exception to DisallowHandleAllocation. +typedef PerThreadAssertScope + AllowHandleAllocation; + +// Scope to document where we do not expect any allocation and GC. +typedef PerThreadAssertScope + DisallowHeapAllocation; + +// Scope to introduce an exception to DisallowHeapAllocation. +typedef PerThreadAssertScope + AllowHeapAllocation; + +// Scope to document where we do not expect any handle dereferences. +typedef PerThreadAssertScope + DisallowHandleDereference; + +// Scope to introduce an exception to DisallowHandleDereference. +typedef PerThreadAssertScope + AllowHandleDereference; + +// Scope to document where we do not expect deferred handles to be dereferenced. +typedef PerThreadAssertScope + DisallowDeferredHandleDereference; + +// Scope to introduce an exception to DisallowDeferredHandleDereference. +typedef PerThreadAssertScope + AllowDeferredHandleDereference; + +} } // namespace v8::internal + +#endif // V8_ASSERT_SCOPE_H_ diff --git a/src/builtins.cc b/src/builtins.cc index 81b600574..37ba1e530 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -563,7 +563,7 @@ BUILTIN(ArrayPush) { } // Add the provided values. - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); for (int index = 0; index < to_add; index++) { elms->set(index + len, args[index + 1], mode); @@ -612,7 +612,7 @@ BUILTIN(ArrayPush) { } // Add the provided values. - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; int index; for (index = 0; index < to_add; index++) { Object* arg = args[index + 1]; @@ -695,7 +695,7 @@ BUILTIN(ArrayShift) { // Shift the elements. if (elms_obj->IsFixedArray()) { FixedArray* elms = FixedArray::cast(elms_obj); - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; heap->MoveElements(elms, 0, 1, len - 1); elms->set(len - 1, heap->the_hole_value()); } else { @@ -762,12 +762,12 @@ BUILTIN(ArrayUnshift) { elms = new_elms; array->set_elements(elms); } else { - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; heap->MoveElements(elms, to_add, 0, len); } // Add the provided values. - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); for (int i = 0; i < to_add; i++) { elms->set(i, args[i + 1], mode); @@ -898,7 +898,7 @@ BUILTIN(ArraySlice) { result_len, result_len); - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; if (result_len == 0) return maybe_array; if (!maybe_array->To(&result_array)) return maybe_array; @@ -1000,7 +1000,7 @@ BUILTIN(ArraySplice) { if (!maybe_array->To(&result_array)) return maybe_array; if (actual_delete_count > 0) { - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; ElementsAccessor* accessor = array->GetElementsAccessor(); MaybeObject* maybe_failure = accessor->CopyElements( NULL, actual_start, elements_kind, result_array->elements(), @@ -1025,7 +1025,7 @@ BUILTIN(ArraySplice) { MoveDoubleElements(elms, delta, elms, 0, actual_start); } else { FixedArray* elms = FixedArray::cast(elms_obj); - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; heap->MoveElements(elms, delta, 0, actual_start); } @@ -1041,7 +1041,7 @@ BUILTIN(ArraySplice) { FillWithHoles(elms, new_length, len); } else { FixedArray* elms = FixedArray::cast(elms_obj); - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; heap->MoveElements(elms, actual_start + item_count, actual_start + actual_delete_count, (len - actual_delete_count - actual_start)); @@ -1062,7 +1062,7 @@ BUILTIN(ArraySplice) { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); if (!maybe_obj->To(&new_elms)) return maybe_obj; - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; ElementsKind kind = array->GetElementsKind(); ElementsAccessor* accessor = array->GetElementsAccessor(); @@ -1083,7 +1083,7 @@ BUILTIN(ArraySplice) { elms_obj = new_elms; elms_changed = true; } else { - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; heap->MoveElements(elms, actual_start + item_count, actual_start + actual_delete_count, (len - actual_delete_count - actual_start)); @@ -1102,7 +1102,7 @@ BUILTIN(ArraySplice) { } } else { FixedArray* elms = FixedArray::cast(elms_obj); - AssertNoAllocation no_gc; + DisallowHeapAllocation no_gc; WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); for (int k = actual_start; k < actual_start + item_count; k++) { elms->set(k, args[3 + k - actual_start], mode); diff --git a/src/checks.cc b/src/checks.cc index 8bcde1c61..82086824d 100644 --- a/src/checks.cc +++ b/src/checks.cc @@ -36,6 +36,8 @@ static int fatal_error_handler_nesting_depth = 0; // Contains protection against recursive calls (faults while handling faults). extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) { + i::AllowHandleDereference allow_deref; + i::AllowDeferredHandleDereference allow_deferred_deref; fflush(stdout); fflush(stderr); fatal_error_handler_nesting_depth++; diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 9a9f0d5f1..4ec8654eb 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -36,10 +36,9 @@ namespace internal { static LChunk* OptimizeGraph(HGraph* graph) { - Isolate* isolate = graph->isolate(); - AssertNoAllocation no_gc; - NoHandleAllocation no_handles(isolate); - HandleDereferenceGuard no_deref(isolate, HandleDereferenceGuard::DISALLOW); + DisallowHeapAllocation no_allocation; + DisallowHandleAllocation no_handles; + DisallowHandleDereference no_deref; ASSERT(graph != NULL); SmartArrayPointer bailout_reason; diff --git a/src/compiler.cc b/src/compiler.cc index b799a5a6e..1334f5aaf 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -393,9 +393,9 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() { } OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() { - AssertNoAllocation no_gc; - NoHandleAllocation no_handles(isolate()); - HandleDereferenceGuard no_deref(isolate(), HandleDereferenceGuard::DISALLOW); + DisallowHeapAllocation no_allocation; + DisallowHandleAllocation no_handles; + DisallowHandleDereference no_deref; ASSERT(last_status() == SUCCEEDED); Timer t(this, &time_taken_to_optimize_); @@ -424,8 +424,7 @@ OptimizingCompiler::Status OptimizingCompiler::GenerateAndInstallCode() { // graph creation. To make sure that we don't encounter inconsistencies // between graph creation and code generation, we disallow accessing // objects through deferred handles during the latter, with exceptions. - HandleDereferenceGuard no_deref_deferred( - isolate(), HandleDereferenceGuard::DISALLOW_DEFERRED); + DisallowDeferredHandleDereference no_deferred_handle_deref(); Handle optimized_code = chunk_->Codegen(); if (optimized_code.is_null()) { info()->set_bailout_reason("code generation failed"); diff --git a/src/debug.cc b/src/debug.cc index a61a39413..7d0225220 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -121,7 +121,7 @@ BreakLocationIterator::~BreakLocationIterator() { void BreakLocationIterator::Next() { - AssertNoAllocation nogc; + DisallowHeapAllocation no_gc; ASSERT(!RinfoDone()); // Iterate through reloc info for code and original code stopping at each @@ -2022,7 +2022,7 @@ void Debug::PrepareForBreakPoints() { // Ensure no GC in this scope as we are going to use gc_metadata // field in the Code object to mark active functions. - AssertNoAllocation no_allocation; + DisallowHeapAllocation no_allocation; Object* active_code_marker = heap->the_hole_value(); @@ -2137,7 +2137,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle