From 2b67ca57385e1151127e8d9b9354bff8efe1af72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 6 Jun 2015 08:59:22 +0200 Subject: [PATCH 1/2] deps: upgrade v8 to 4.3.61.27 --- deps/v8/include/v8-version.h | 2 +- deps/v8/include/v8.h | 18 -- deps/v8/src/api.cc | 21 -- deps/v8/src/api.h | 5 +- deps/v8/src/arm/full-codegen-arm.cc | 33 +-- deps/v8/src/arm64/full-codegen-arm64.cc | 37 +-- deps/v8/src/ast.cc | 1 + deps/v8/src/ast.h | 24 +- deps/v8/src/compiler/ast-graph-builder.cc | 4 +- deps/v8/src/compiler/graph-visualizer.h | 1 - deps/v8/src/flag-definitions.h | 2 + deps/v8/src/full-codegen.cc | 21 ++ deps/v8/src/full-codegen.h | 5 +- deps/v8/src/heap/heap.cc | 21 +- deps/v8/src/heap/heap.h | 1 + deps/v8/src/hydrogen.cc | 13 +- deps/v8/src/ia32/full-codegen-ia32.cc | 38 +--- deps/v8/src/json-parser.h | 213 +++++++++++------- deps/v8/src/mips/full-codegen-mips.cc | 36 +-- deps/v8/src/mips64/full-codegen-mips64.cc | 36 +-- deps/v8/src/objects.cc | 10 +- deps/v8/src/ppc/full-codegen-ppc.cc | 31 +-- deps/v8/src/runtime/runtime-literals.cc | 3 +- deps/v8/src/scanner.cc | 2 +- deps/v8/src/scanner.h | 6 +- deps/v8/src/x64/full-codegen-x64.cc | 35 +-- deps/v8/test/cctest/cctest.status | 1 - deps/v8/test/cctest/test-api.cc | 32 --- deps/v8/test/mjsunit/regress/regress-3976.js | 2 +- .../v8/test/mjsunit/regress/regress-466993.js | 18 ++ .../v8/test/mjsunit/regress/regress-472504.js | 9 + .../mjsunit/regress/regress-crbug-485548-1.js | 33 +++ .../mjsunit/regress/regress-crbug-485548-2.js | 33 +++ .../mjsunit/regress/regress-smi-scanning.js | 7 + deps/v8/tools/run-tests.py | 4 - deps/v8/tools/testrunner/local/progress.py | 10 +- 36 files changed, 397 insertions(+), 371 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-466993.js create mode 100644 deps/v8/test/mjsunit/regress/regress-472504.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-485548-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-485548-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-smi-scanning.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 9cdb1259216c19..30cc2fc56194a9 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 4 #define V8_MINOR_VERSION 3 #define V8_BUILD_NUMBER 61 -#define V8_PATCH_LEVEL 21 +#define V8_PATCH_LEVEL 27 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index d3543f282fd19e..19de92fa8c45b0 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1018,24 +1018,6 @@ class V8_EXPORT EscapableHandleScope : public HandleScope { internal::Object** escape_slot_; }; -class V8_EXPORT SealHandleScope { - public: - SealHandleScope(Isolate* isolate); - ~SealHandleScope(); - - private: - // Make it hard to create heap-allocated or illegal handle scopes by - // disallowing certain operations. - SealHandleScope(const SealHandleScope&); - void operator=(const SealHandleScope&); - void* operator new(size_t size); - void operator delete(void*, size_t); - - internal::Isolate* isolate_; - int prev_level_; - internal::Object** prev_limit_; -}; - // --- Special objects --- diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index c9c0f3ad85284e..97ecc7efa2df04 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -682,27 +682,6 @@ i::Object** EscapableHandleScope::Escape(i::Object** escape_value) { } -SealHandleScope::SealHandleScope(Isolate* isolate) { - i::Isolate* internal_isolate = reinterpret_cast(isolate); - - isolate_ = internal_isolate; - i::HandleScopeData* current = internal_isolate->handle_scope_data(); - prev_limit_ = current->limit; - current->limit = current->next; - prev_level_ = current->level; - current->level = 0; -} - - -SealHandleScope::~SealHandleScope() { - i::HandleScopeData* current = isolate_->handle_scope_data(); - DCHECK_EQ(0, current->level); - current->level = prev_level_; - DCHECK_EQ(current->next, current->limit); - current->limit = prev_limit_; -} - - void Context::Enter() { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index 7fce3e3b0a27e2..fa8682bf572079 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -661,7 +661,7 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { while (!blocks_.is_empty()) { internal::Object** block_start = blocks_.last(); internal::Object** block_limit = block_start + kHandleBlockSize; - +#ifdef DEBUG // SealHandleScope may make the prev_limit to point inside the block. if (block_start <= prev_limit && prev_limit <= block_limit) { #ifdef ENABLE_HANDLE_ZAPPING @@ -669,6 +669,9 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { #endif break; } +#else + if (prev_limit == block_limit) break; +#endif blocks_.RemoveLast(); #ifdef ENABLE_HANDLE_ZAPPING diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 0bcb6a79ccd301..6ee8eb1cd68540 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -1698,21 +1698,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); __ mov(r1, Operand(constant_properties)); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; + int flags = expr->ComputeFlags(); __ mov(r0, Operand(Smi::FromInt(flags))); - int properties_count = constant_properties->length() / 2; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || - properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { + if (MustCreateObjectLiteralWithRuntime(expr)) { __ Push(r3, r2, r1, r0); __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1904,17 +1896,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = expr->depth() == 1 - ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); - bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind); + bool has_fast_elements = + IsFastObjectElementsKind(expr->constant_elements_kind()); Handle constant_elements_values( FixedArrayBase::cast(constant_elements->get(1))); @@ -1929,8 +1914,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); __ mov(r1, Operand(constant_elements)); - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { - __ mov(r0, Operand(Smi::FromInt(flags))); + if (MustCreateArrayLiteralWithRuntime(expr)) { + __ mov(r0, Operand(Smi::FromInt(expr->ComputeFlags()))); __ Push(r3, r2, r1, r0); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { @@ -1940,6 +1925,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1956,7 +1943,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_fast_elements) { int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ ldr(r6, MemOperand(sp, kPointerSize)); // Copy of array literal. __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset)); diff --git a/deps/v8/src/arm64/full-codegen-arm64.cc b/deps/v8/src/arm64/full-codegen-arm64.cc index 015ec188cd8164..9feac938b5320c 100644 --- a/deps/v8/src/arm64/full-codegen-arm64.cc +++ b/deps/v8/src/arm64/full-codegen-arm64.cc @@ -1677,23 +1677,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset)); __ Mov(x2, Smi::FromInt(expr->literal_index())); __ Mov(x1, Operand(constant_properties)); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; + int flags = expr->ComputeFlags(); __ Mov(x0, Smi::FromInt(flags)); - int properties_count = constant_properties->length() / 2; - const int max_cloned_properties = - FastCloneShallowObjectStub::kMaximumClonedProperties; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || - properties_count > max_cloned_properties) { + if (MustCreateObjectLiteralWithRuntime(expr)) { __ Push(x3, x2, x1, x0); __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1885,18 +1875,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = (expr->depth() == 1) ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); - bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind); - Handle constant_elements_values( - FixedArrayBase::cast(constant_elements->get(1))); + bool has_fast_elements = + IsFastObjectElementsKind(expr->constant_elements_kind()); AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; if (has_fast_elements && !FLAG_allocation_site_pretenuring) { @@ -1909,8 +1890,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset)); __ Mov(x2, Smi::FromInt(expr->literal_index())); __ Mov(x1, Operand(constant_elements)); - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { - __ Mov(x0, Smi::FromInt(flags)); + if (MustCreateArrayLiteralWithRuntime(expr)) { + __ Mov(x0, Smi::FromInt(expr->ComputeFlags())); __ Push(x3, x2, x1, x0); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { @@ -1920,6 +1901,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1936,7 +1919,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_fast_elements) { int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ Peek(x6, kPointerSize); // Copy of array literal. __ Ldr(x1, FieldMemOperand(x6, JSObject::kElementsOffset)); diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index f8289311c47812..8caf9c2a29ec4c 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -368,6 +368,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { constant_properties_ = constant_properties; fast_elements_ = (max_element_index <= 32) || ((2 * elements) >= max_element_index); + has_elements_ = elements > 0; set_is_simple(is_simple); set_depth(depth_acc); } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 676ec262310307..27e8f09a90dae8 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -1482,10 +1482,12 @@ class ObjectLiteral FINAL : public MaterializedLiteral { Handle constant_properties() const { return constant_properties_; } + int properties_count() const { return constant_properties_->length() / 2; } ZoneList* properties() const { return properties_; } bool fast_elements() const { return fast_elements_; } bool may_store_doubles() const { return may_store_doubles_; } bool has_function() const { return has_function_; } + bool has_elements() const { return has_elements_; } // Decide if a property should be in the object boilerplate. static bool IsBoilerplateProperty(Property* property); @@ -1499,16 +1501,20 @@ class ObjectLiteral FINAL : public MaterializedLiteral { void CalculateEmitStore(Zone* zone); // Assemble bitfield of flags for the CreateObjectLiteral helper. - int ComputeFlags() const { + int ComputeFlags(bool disable_mementos = false) const { int flags = fast_elements() ? kFastElements : kNoFlags; flags |= has_function() ? kHasFunction : kNoFlags; + if (disable_mementos) { + flags |= kDisableMementos; + } return flags; } enum Flags { kNoFlags = 0, kFastElements = 1, - kHasFunction = 1 << 1 + kHasFunction = 1 << 1, + kDisableMementos = 1 << 2 }; struct Accessors: public ZoneObject { @@ -1533,6 +1539,7 @@ class ObjectLiteral FINAL : public MaterializedLiteral { properties_(properties), boilerplate_properties_(boilerplate_properties), fast_elements_(false), + has_elements_(false), may_store_doubles_(false), has_function_(has_function) {} static int parent_num_ids() { return MaterializedLiteral::num_ids(); } @@ -1543,6 +1550,7 @@ class ObjectLiteral FINAL : public MaterializedLiteral { ZoneList* properties_; int boilerplate_properties_; bool fast_elements_; + bool has_elements_; bool may_store_doubles_; bool has_function_; }; @@ -1578,6 +1586,12 @@ class ArrayLiteral FINAL : public MaterializedLiteral { DECLARE_NODE_TYPE(ArrayLiteral) Handle constant_elements() const { return constant_elements_; } + ElementsKind constant_elements_kind() const { + DCHECK_EQ(2, constant_elements_->length()); + return static_cast( + Smi::cast(constant_elements_->get(0))->value()); + } + ZoneList* values() const { return values_; } BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); } @@ -1593,9 +1607,11 @@ class ArrayLiteral FINAL : public MaterializedLiteral { void BuildConstantElements(Isolate* isolate); // Assemble bitfield of flags for the CreateArrayLiteral helper. - int ComputeFlags() const { + int ComputeFlags(bool disable_mementos = false) const { int flags = depth() == 1 ? kShallowElements : kNoFlags; - flags |= ArrayLiteral::kDisableMementos; + if (disable_mementos) { + flags |= kDisableMementos; + } return flags; } diff --git a/deps/v8/src/compiler/ast-graph-builder.cc b/deps/v8/src/compiler/ast-graph-builder.cc index 373c6ea4ff41ad..e550f511288f0e 100644 --- a/deps/v8/src/compiler/ast-graph-builder.cc +++ b/deps/v8/src/compiler/ast-graph-builder.cc @@ -1627,7 +1627,7 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { BuildLoadObjectField(closure, JSFunction::kLiteralsOffset); Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* constants = jsgraph()->Constant(expr->constant_properties()); - Node* flags = jsgraph()->Constant(expr->ComputeFlags()); + Node* flags = jsgraph()->Constant(expr->ComputeFlags(true)); const Operator* op = javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4); Node* literal = NewNode(op, literals_array, literal_index, constants, flags); @@ -1819,7 +1819,7 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { BuildLoadObjectField(closure, JSFunction::kLiteralsOffset); Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* constants = jsgraph()->Constant(expr->constant_elements()); - Node* flags = jsgraph()->Constant(expr->ComputeFlags()); + Node* flags = jsgraph()->Constant(expr->ComputeFlags(true)); const Operator* op = javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4); Node* literal = NewNode(op, literals_array, literal_index, constants, flags); diff --git a/deps/v8/src/compiler/graph-visualizer.h b/deps/v8/src/compiler/graph-visualizer.h index 0e6a6471b84a63..17094c23c57c37 100644 --- a/deps/v8/src/compiler/graph-visualizer.h +++ b/deps/v8/src/compiler/graph-visualizer.h @@ -5,7 +5,6 @@ #ifndef V8_COMPILER_GRAPH_VISUALIZER_H_ #define V8_COMPILER_GRAPH_VISUALIZER_H_ -#include #include namespace v8 { diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index f1bdc0c2904cb4..42d8ce3cb23e27 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -844,6 +844,8 @@ DEFINE_BOOL(gc_verbose, false, "print stuff during garbage collection") DEFINE_BOOL(heap_stats, false, "report heap statistics before and after GC") DEFINE_BOOL(code_stats, false, "report code statistics after GC") DEFINE_BOOL(print_handles, false, "report handles after GC") +DEFINE_BOOL(check_handle_count, false, + "Check that there are not too many handles at GC") DEFINE_BOOL(print_global_handles, false, "report global handles after GC") // TurboFan debug-only flags. diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index c264704cbfb7fd..327230e75d457e 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -415,6 +415,27 @@ void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle code) { } +bool FullCodeGenerator::MustCreateObjectLiteralWithRuntime( + ObjectLiteral* expr) const { + // FastCloneShallowObjectStub doesn't copy elements, and object literals don't + // support copy-on-write (COW) elements for now. + // TODO(mvstanton): make object literals support COW elements. + return expr->may_store_doubles() || expr->depth() > 1 || + masm()->serializer_enabled() || + expr->ComputeFlags() != ObjectLiteral::kFastElements || + expr->has_elements() || + expr->properties_count() > + FastCloneShallowObjectStub::kMaximumClonedProperties; +} + + +bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime( + ArrayLiteral* expr) const { + return expr->depth() > 1 || + expr->values()->length() > JSObject::kInitialMaxFastElementArray; +} + + void FullCodeGenerator::Initialize() { InitializeAstVisitor(info_->isolate(), info_->zone()); // The generation of debug code must match between the snapshot code and the diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index 3420ca9b9b4cf4..d558ae6f224a9c 100644 --- a/deps/v8/src/full-codegen.h +++ b/deps/v8/src/full-codegen.h @@ -715,7 +715,7 @@ class FullCodeGenerator: public AstVisitor { loop_depth_--; } - MacroAssembler* masm() { return masm_; } + MacroAssembler* masm() const { return masm_; } class ExpressionContext; const ExpressionContext* context() { return context_; } @@ -759,6 +759,9 @@ class FullCodeGenerator: public AstVisitor { void PopulateDeoptimizationData(Handle code); void PopulateTypeFeedbackInfo(Handle code); + bool MustCreateObjectLiteralWithRuntime(ObjectLiteral* expr) const; + bool MustCreateArrayLiteralWithRuntime(ArrayLiteral* expr) const; + Handle handler_table() { return handler_table_; } struct BailoutEntry { diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 157024939d529c..7364dbabcab0ab 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -620,6 +620,7 @@ void Heap::GarbageCollectionEpilogue() { if (FLAG_gc_verbose) Print(); if (FLAG_code_stats) ReportCodeStatistics("After GC"); #endif + if (FLAG_check_handle_count) CheckHandleCount(); if (FLAG_deopt_every_n_garbage_collections > 0) { // TODO(jkummerow/ulan/jarin): This is not safe! We can't assume that // the topmost optimized frame can be deoptimized safely, because it @@ -1023,7 +1024,7 @@ bool Heap::ReserveSpace(Reservation* reservations) { } else { if (counter > 1) { CollectAllGarbage( - kReduceMemoryFootprintMask, + kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, "failed to reserve space in paged or large " "object space, trying to reduce memory footprint"); } else { @@ -5698,6 +5699,24 @@ void Heap::PrintHandles() { #endif +class CheckHandleCountVisitor : public ObjectVisitor { + public: + CheckHandleCountVisitor() : handle_count_(0) {} + ~CheckHandleCountVisitor() { CHECK(handle_count_ < 2000); } + void VisitPointers(Object** start, Object** end) { + handle_count_ += end - start; + } + + private: + ptrdiff_t handle_count_; +}; + + +void Heap::CheckHandleCount() { + CheckHandleCountVisitor v; + isolate_->handle_scope_implementer()->Iterate(&v); +} + Space* AllSpaces::next() { switch (counter_++) { diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index ee701b2d5a4ebe..444527cc947bda 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -987,6 +987,7 @@ class Heap { } static bool RootIsImmortalImmovable(int root_index); + void CheckHandleCount(); #ifdef VERIFY_HEAP // Verify the heap is in its normal state before or after a GC. diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 21a6979b3bc8ae..ae717e4ad9a014 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -5554,19 +5554,13 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { Handle closure_literals(closure->literals(), isolate()); Handle constant_properties = expr->constant_properties(); int literal_index = expr->literal_index(); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; + int flags = expr->ComputeFlags(true); Add(Add(closure_literals), Add(literal_index), Add(constant_properties), Add(flags)); - // TODO(mvstanton): Add a flag to turn off creation of any - // AllocationMementos for this call: we are in crankshaft and should have - // learned enough about transition behavior to stop emitting mementos. Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral; literal = Add(isolate()->factory()->empty_string(), Runtime::FunctionForId(function_id), @@ -5725,10 +5719,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { // pass an empty fixed array to the runtime function instead. Handle constants = isolate()->factory()->empty_fixed_array(); int literal_index = expr->literal_index(); - int flags = expr->depth() == 1 - ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - flags |= ArrayLiteral::kDisableMementos; + int flags = expr->ComputeFlags(true); Add(Add(literals), Add(literal_index), diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 357c2df1ced91c..1e578b41412e00 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -1622,17 +1622,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->BuildConstantProperties(isolate()); Handle constant_properties = expr->constant_properties(); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; - int properties_count = constant_properties->length() / 2; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || - flags != ObjectLiteral::kFastElements || - properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { + int flags = expr->ComputeFlags(); + // If any of the keys would store to the elements array, then we shouldn't + // allow it. + if (MustCreateObjectLiteralWithRuntime(expr)) { __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(expr->literal_index()))); @@ -1645,7 +1638,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index()))); __ mov(ecx, Immediate(constant_properties)); __ mov(edx, Immediate(Smi::FromInt(flags))); - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1824,20 +1817,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = expr->depth() == 1 - ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); bool has_constant_fast_elements = - IsFastObjectElementsKind(constant_elements_kind); - Handle constant_elements_values( - FixedArrayBase::cast(constant_elements->get(1))); + IsFastObjectElementsKind(expr->constant_elements_kind()); AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { @@ -1846,12 +1828,12 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; } - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { + if (MustCreateArrayLiteralWithRuntime(expr)) { __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(constant_elements)); - __ push(Immediate(Smi::FromInt(flags))); + __ push(Immediate(Smi::FromInt(expr->ComputeFlags()))); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); @@ -1864,6 +1846,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1880,7 +1864,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_constant_fast_elements) { // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they // cannot transition and don't need to call the runtime stub. int offset = FixedArray::kHeaderSize + (i * kPointerSize); diff --git a/deps/v8/src/json-parser.h b/deps/v8/src/json-parser.h index 12eea78fca16ae..54c78414804c20 100644 --- a/deps/v8/src/json-parser.h +++ b/deps/v8/src/json-parser.h @@ -16,6 +16,9 @@ namespace v8 { namespace internal { +enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle }; + + // A simple json parser. template class JsonParser BASE_EMBEDDED { @@ -155,6 +158,10 @@ class JsonParser BASE_EMBEDDED { // JavaScript array. Handle ParseJsonObject(); + // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded + // as an element, not a property. + ParseElementResult ParseElement(Handle json_object); + // Parses a JSON array literal (grammar production JSONArray). An array // literal is a square-bracketed and comma separated sequence (possibly empty) // of JSON values. @@ -299,6 +306,41 @@ Handle JsonParser::ParseJsonValue() { } +template +ParseElementResult JsonParser::ParseElement( + Handle json_object) { + uint32_t index = 0; + // Maybe an array index, try to parse it. + if (c0_ == '0') { + // With a leading zero, the string has to be "0" only to be an index. + Advance(); + } else { + do { + int d = c0_ - '0'; + if (index > 429496729U - ((d > 5) ? 1 : 0)) break; + index = (index * 10) + d; + Advance(); + } while (IsDecimalDigit(c0_)); + } + + if (c0_ == '"') { + // Successfully parsed index, parse and store element. + AdvanceSkipWhitespace(); + + if (c0_ == ':') { + AdvanceSkipWhitespace(); + Handle value = ParseJsonValue(); + if (!value.is_null()) { + JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert(); + return kElementFound; + } else { + return kNullHandle; + } + } + } + return kElementNotFound; +} + // Parse a JSON object. Position must be right at '{'. template Handle JsonParser::ParseJsonObject() { @@ -320,35 +362,12 @@ Handle JsonParser::ParseJsonObject() { int start_position = position_; Advance(); - uint32_t index = 0; if (IsDecimalDigit(c0_)) { - // Maybe an array index, try to parse it. - if (c0_ == '0') { - // With a leading zero, the string has to be "0" only to be an index. - Advance(); - } else { - do { - int d = c0_ - '0'; - if (index > 429496729U - ((d > 5) ? 1 : 0)) break; - index = (index * 10) + d; - Advance(); - } while (IsDecimalDigit(c0_)); - } - - if (c0_ == '"') { - // Successfully parsed index, parse and store element. - AdvanceSkipWhitespace(); - - if (c0_ != ':') return ReportUnexpectedCharacter(); - AdvanceSkipWhitespace(); - Handle value = ParseJsonValue(); - if (value.is_null()) return ReportUnexpectedCharacter(); - - JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert(); - continue; - } - // Not an index, fallback to the slow path. + ParseElementResult element_result = ParseElement(json_object); + if (element_result == kNullHandle) return Handle::null(); + if (element_result == kElementFound) continue; } + // Not an index, fallback to the slow path. position_ = start_position; #ifdef DEBUG @@ -360,81 +379,109 @@ Handle JsonParser::ParseJsonObject() { // Try to follow existing transitions as long as possible. Once we stop // transitioning, no transition can be found anymore. + DCHECK(transitioning); + // First check whether there is a single expected transition. If so, try + // to parse it first. + bool follow_expected = false; + Handle target; + if (seq_one_byte) { + key = TransitionArray::ExpectedTransitionKey(map); + follow_expected = !key.is_null() && ParseJsonString(key); + } + // If the expected transition hits, follow it. + if (follow_expected) { + target = TransitionArray::ExpectedTransitionTarget(map); + } else { + // If the expected transition failed, parse an internalized string and + // try to find a matching transition. + key = ParseJsonInternalizedString(); + if (key.is_null()) return ReportUnexpectedCharacter(); + + target = TransitionArray::FindTransitionToField(map, key); + // If a transition was found, follow it and continue. + transitioning = !target.is_null(); + } + if (c0_ != ':') return ReportUnexpectedCharacter(); + + AdvanceSkipWhitespace(); + value = ParseJsonValue(); + if (value.is_null()) return ReportUnexpectedCharacter(); + if (transitioning) { - // First check whether there is a single expected transition. If so, try - // to parse it first. - bool follow_expected = false; - Handle target; - if (seq_one_byte) { - key = TransitionArray::ExpectedTransitionKey(map); - follow_expected = !key.is_null() && ParseJsonString(key); - } - // If the expected transition hits, follow it. - if (follow_expected) { - target = TransitionArray::ExpectedTransitionTarget(map); + PropertyDetails details = + target->instance_descriptors()->GetDetails(descriptor); + Representation expected_representation = details.representation(); + + if (value->FitsRepresentation(expected_representation)) { + if (expected_representation.IsHeapObject() && + !target->instance_descriptors() + ->GetFieldType(descriptor) + ->NowContains(value)) { + Handle value_type( + value->OptimalType(isolate(), expected_representation)); + Map::GeneralizeFieldType(target, descriptor, + expected_representation, value_type); + } + DCHECK(target->instance_descriptors() + ->GetFieldType(descriptor) + ->NowContains(value)); + properties.Add(value, zone()); + map = target; + descriptor++; + continue; } else { - // If the expected transition failed, parse an internalized string and - // try to find a matching transition. - key = ParseJsonInternalizedString(); - if (key.is_null()) return ReportUnexpectedCharacter(); - - target = TransitionArray::FindTransitionToField(map, key); - // If a transition was found, follow it and continue. - transitioning = !target.is_null(); + transitioning = false; } - if (c0_ != ':') return ReportUnexpectedCharacter(); + } - AdvanceSkipWhitespace(); - value = ParseJsonValue(); - if (value.is_null()) return ReportUnexpectedCharacter(); + DCHECK(!transitioning); - if (transitioning) { - PropertyDetails details = - target->instance_descriptors()->GetDetails(descriptor); - Representation expected_representation = details.representation(); + // Commit the intermediate state to the object and stop transitioning. + CommitStateToJsonObject(json_object, map, &properties); - if (value->FitsRepresentation(expected_representation)) { - if (expected_representation.IsHeapObject() && - !target->instance_descriptors() - ->GetFieldType(descriptor) - ->NowContains(value)) { - Handle value_type(value->OptimalType( - isolate(), expected_representation)); - Map::GeneralizeFieldType(target, descriptor, - expected_representation, value_type); - } - DCHECK(target->instance_descriptors()->GetFieldType( - descriptor)->NowContains(value)); - properties.Add(value, zone()); - map = target; - descriptor++; - continue; - } else { - transitioning = false; - } + Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); + } while (transitioning && MatchSkipWhiteSpace(',')); + + // If we transitioned until the very end, transition the map now. + if (transitioning) { + CommitStateToJsonObject(json_object, map, &properties); + } else { + while (MatchSkipWhiteSpace(',')) { + HandleScope local_scope(isolate()); + if (c0_ != '"') return ReportUnexpectedCharacter(); + + int start_position = position_; + Advance(); + + if (IsDecimalDigit(c0_)) { + ParseElementResult element_result = ParseElement(json_object); + if (element_result == kNullHandle) return Handle::null(); + if (element_result == kElementFound) continue; } + // Not an index, fallback to the slow path. + + position_ = start_position; +#ifdef DEBUG + c0_ = '"'; +#endif + + Handle key; + Handle value; - // Commit the intermediate state to the object and stop transitioning. - CommitStateToJsonObject(json_object, map, &properties); - } else { key = ParseJsonInternalizedString(); if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); AdvanceSkipWhitespace(); value = ParseJsonValue(); if (value.is_null()) return ReportUnexpectedCharacter(); + + Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); } + } - Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); - } while (MatchSkipWhiteSpace(',')); if (c0_ != '}') { return ReportUnexpectedCharacter(); } - - // If we transitioned until the very end, transition the map now. - if (transitioning) { - CommitStateToJsonObject(json_object, map, &properties); - } } AdvanceSkipWhitespace(); return scope.CloseAndEscape(json_object); diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index 9a7de136ef1635..9f3655232bbb5b 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -1684,21 +1684,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); __ li(a2, Operand(Smi::FromInt(expr->literal_index()))); __ li(a1, Operand(constant_properties)); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; - __ li(a0, Operand(Smi::FromInt(flags))); - int properties_count = constant_properties->length() / 2; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || - properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { + __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags()))); + if (MustCreateObjectLiteralWithRuntime(expr)) { __ Push(a3, a2, a1, a0); __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1890,21 +1881,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = expr->depth() == 1 - ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); bool has_fast_elements = - IsFastObjectElementsKind(constant_elements_kind); - Handle constant_elements_values( - FixedArrayBase::cast(constant_elements->get(1))); + IsFastObjectElementsKind(expr->constant_elements_kind()); AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; if (has_fast_elements && !FLAG_allocation_site_pretenuring) { @@ -1918,8 +1898,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); __ li(a2, Operand(Smi::FromInt(expr->literal_index()))); __ li(a1, Operand(constant_elements)); - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { - __ li(a0, Operand(Smi::FromInt(flags))); + if (MustCreateArrayLiteralWithRuntime(expr)) { + __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags()))); __ Push(a3, a2, a1, a0); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { @@ -1929,6 +1909,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1946,7 +1928,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_fast_elements) { int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ lw(t2, MemOperand(sp, kPointerSize)); // Copy of array literal. __ lw(a1, FieldMemOperand(t2, JSObject::kElementsOffset)); diff --git a/deps/v8/src/mips64/full-codegen-mips64.cc b/deps/v8/src/mips64/full-codegen-mips64.cc index 525b04a23e9e6a..91d374a2c0263c 100644 --- a/deps/v8/src/mips64/full-codegen-mips64.cc +++ b/deps/v8/src/mips64/full-codegen-mips64.cc @@ -1682,21 +1682,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ ld(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); __ li(a2, Operand(Smi::FromInt(expr->literal_index()))); __ li(a1, Operand(constant_properties)); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; - __ li(a0, Operand(Smi::FromInt(flags))); - int properties_count = constant_properties->length() / 2; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || - properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { + __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags()))); + if (MustCreateObjectLiteralWithRuntime(expr)) { __ Push(a3, a2, a1, a0); __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1888,21 +1879,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = expr->depth() == 1 - ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); bool has_fast_elements = - IsFastObjectElementsKind(constant_elements_kind); - Handle constant_elements_values( - FixedArrayBase::cast(constant_elements->get(1))); + IsFastObjectElementsKind(expr->constant_elements_kind()); AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; if (has_fast_elements && !FLAG_allocation_site_pretenuring) { @@ -1916,8 +1896,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ ld(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); __ li(a2, Operand(Smi::FromInt(expr->literal_index()))); __ li(a1, Operand(constant_elements)); - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { - __ li(a0, Operand(Smi::FromInt(flags))); + if (MustCreateArrayLiteralWithRuntime(expr)) { + __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags()))); __ Push(a3, a2, a1, a0); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { @@ -1927,6 +1907,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1944,7 +1926,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_fast_elements) { int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ ld(a6, MemOperand(sp, kPointerSize)); // Copy of array literal. __ ld(a1, FieldMemOperand(a6, JSObject::kElementsOffset)); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 77a82e6d94a8ca..ce09632cf8daf9 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -1387,7 +1387,8 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT } switch (map()->instance_type()) { case MAP_TYPE: - os << "elements_kind() << ")>"; + os << "elements_kind()) + << ")>"; break; case FIXED_ARRAY_TYPE: os << "length() << "]>"; @@ -2891,6 +2892,13 @@ Handle Map::ReconfigureProperty(Handle old_map, int modify_index, split_kind, old_descriptors->GetKey(split_nof), split_attributes, *new_descriptors, *new_layout_descriptor); + if (from_kind != to_kind) { + // There was an elements kind change in the middle of transition tree and + // we reconstructed the tree so that all elements kind transitions are + // done at the beginning, therefore the |old_map| is no longer stable. + old_map->NotifyLeafMapLayoutChange(); + } + // If |transition_target_deprecated| is true then the transition array // already contains entry for given descriptor. This means that the transition // could be inserted regardless of whether transitions array is full or not. diff --git a/deps/v8/src/ppc/full-codegen-ppc.cc b/deps/v8/src/ppc/full-codegen-ppc.cc index 3082504cf8cd72..a12f17eba39740 100644 --- a/deps/v8/src/ppc/full-codegen-ppc.cc +++ b/deps/v8/src/ppc/full-codegen-ppc.cc @@ -1651,19 +1651,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ LoadP(r6, FieldMemOperand(r6, JSFunction::kLiteralsOffset)); __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); __ mov(r4, Operand(constant_properties)); - int flags = expr->fast_elements() ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; + int flags = expr->ComputeFlags(); __ LoadSmiLiteral(r3, Smi::FromInt(flags)); - int properties_count = constant_properties->length() / 2; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || - properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { + if (MustCreateObjectLiteralWithRuntime(expr)) { __ Push(r6, r5, r4, r3); __ CallRuntime(Runtime::kCreateObjectLiteral, 4); } else { - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1853,16 +1847,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = expr->depth() == 1 ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); - bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind); + bool has_fast_elements = + IsFastObjectElementsKind(expr->constant_elements_kind()); Handle constant_elements_values( FixedArrayBase::cast(constant_elements->get(1))); @@ -1877,8 +1864,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ LoadP(r6, FieldMemOperand(r6, JSFunction::kLiteralsOffset)); __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); __ mov(r4, Operand(constant_elements)); - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { - __ LoadSmiLiteral(r3, Smi::FromInt(flags)); + if (MustCreateArrayLiteralWithRuntime(expr)) { + __ LoadSmiLiteral(r3, Smi::FromInt(expr->ComputeFlags())); __ Push(r6, r5, r4, r3); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { @@ -1888,6 +1875,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1904,7 +1893,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_fast_elements) { int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ LoadP(r8, MemOperand(sp, kPointerSize)); // Copy of array literal. __ LoadP(r4, FieldMemOperand(r8, JSObject::kElementsOffset)); diff --git a/deps/v8/src/runtime/runtime-literals.cc b/deps/v8/src/runtime/runtime-literals.cc index 83a2fcf45f7e30..76226d68f596fa 100644 --- a/deps/v8/src/runtime/runtime-literals.cc +++ b/deps/v8/src/runtime/runtime-literals.cc @@ -237,6 +237,7 @@ RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) { CONVERT_SMI_ARG_CHECKED(flags, 3); bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; + bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0; RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length()); @@ -267,7 +268,7 @@ RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) { Handle(JSObject::cast(site->transition_info()), isolate); } - AllocationSiteUsageContext usage_context(isolate, site, true); + AllocationSiteUsageContext usage_context(isolate, site, enable_mementos); usage_context.EnterNewScope(); MaybeHandle maybe_copy = JSObject::DeepCopy(boilerplate, &usage_context); diff --git a/deps/v8/src/scanner.cc b/deps/v8/src/scanner.cc index a40688f52b8a54..e90ebc6518e95f 100644 --- a/deps/v8/src/scanner.cc +++ b/deps/v8/src/scanner.cc @@ -1007,7 +1007,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) { if (next_.literal_chars->one_byte_literal().length() <= 10 && value <= Smi::kMaxValue && c0_ != '.' && c0_ != 'e' && c0_ != 'E') { - smi_value_ = static_cast(value); + next_.smi_value_ = static_cast(value); literal.Complete(); HandleLeadSurrogate(); diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h index 804082562e1560..61deb743a29722 100644 --- a/deps/v8/src/scanner.h +++ b/deps/v8/src/scanner.h @@ -436,7 +436,7 @@ class Scanner { void clear_octal_position() { octal_pos_ = Location::invalid(); } // Returns the value of the last smi that was scanned. - int smi_value() const { return smi_value_; } + int smi_value() const { return current_.smi_value_; } // Seek forward to the given position. This operation does not // work in general, for instance when there are pushed back @@ -497,6 +497,7 @@ class Scanner { Location location; LiteralBuffer* literal_chars; LiteralBuffer* raw_literal_chars; + int smi_value_; }; static const int kCharacterLookaheadBufferSize = 1; @@ -724,9 +725,6 @@ class Scanner { // Start position of the octal literal last scanned. Location octal_pos_; - // Value of the last smi that was scanned. - int smi_value_; - // One Unicode character look-ahead; c0_ < 0 at the end of the input. uc32 c0_; diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index d8bf19fc111b3c..5861327bb59ba1 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -1657,16 +1657,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->BuildConstantProperties(isolate()); Handle constant_properties = expr->constant_properties(); - int flags = expr->fast_elements() - ? ObjectLiteral::kFastElements - : ObjectLiteral::kNoFlags; - flags |= expr->has_function() - ? ObjectLiteral::kHasFunction - : ObjectLiteral::kNoFlags; - int properties_count = constant_properties->length() / 2; - if (expr->may_store_doubles() || expr->depth() > 1 || - masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements || - properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { + int flags = expr->ComputeFlags(); + if (MustCreateObjectLiteralWithRuntime(expr)) { __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ Push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); __ Push(Smi::FromInt(expr->literal_index())); @@ -1679,7 +1671,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ Move(rbx, Smi::FromInt(expr->literal_index())); __ Move(rcx, constant_properties); __ Move(rdx, Smi::FromInt(flags)); - FastCloneShallowObjectStub stub(isolate(), properties_count); + FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); __ CallStub(&stub); } PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); @@ -1858,20 +1850,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); expr->BuildConstantElements(isolate()); - int flags = expr->depth() == 1 - ? ArrayLiteral::kShallowElements - : ArrayLiteral::kNoFlags; - - ZoneList* subexprs = expr->values(); - int length = subexprs->length(); Handle constant_elements = expr->constant_elements(); - DCHECK_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast(Smi::cast(constant_elements->get(0))->value()); bool has_constant_fast_elements = - IsFastObjectElementsKind(constant_elements_kind); - Handle constant_elements_values( - FixedArrayBase::cast(constant_elements->get(1))); + IsFastObjectElementsKind(expr->constant_elements_kind()); AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { @@ -1880,12 +1861,12 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; } - if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { + if (MustCreateArrayLiteralWithRuntime(expr)) { __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ Push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); __ Push(Smi::FromInt(expr->literal_index())); __ Push(constant_elements); - __ Push(Smi::FromInt(flags)); + __ Push(Smi::FromInt(expr->ComputeFlags())); __ CallRuntime(Runtime::kCreateArrayLiteral, 4); } else { __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); @@ -1898,6 +1879,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); bool result_saved = false; // Is the result saved to the stack? + ZoneList* subexprs = expr->values(); + int length = subexprs->length(); // Emit code to evaluate all the non-constant subexpressions and to store // them into the newly cloned array. @@ -1914,7 +1897,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (IsFastObjectElementsKind(constant_elements_kind)) { + if (has_constant_fast_elements) { // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they // cannot transition and don't need to call the runtime stub. int offset = FixedArray::kHeaderSize + (i * kPointerSize); diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index d7f72495ae6c7d..99f699071245e3 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -40,7 +40,6 @@ # they don't fail then test.py has failed. 'test-serialize/TestThatAlwaysFails': [FAIL], 'test-serialize/DependentTestThatAlwaysFails': [FAIL], - 'test-api/SealHandleScope': [FAIL], # This test always fails. It tests that LiveEdit causes abort when turned off. 'test-debug/LiveEditDisabled': [FAIL], diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 8432cbfba12598..0c169a4a3d06fd 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -21876,35 +21876,3 @@ TEST(NewStringRangeError) { } free(buffer); } - - -TEST(SealHandleScope) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handle_scope(isolate); - LocalContext env; - - v8::SealHandleScope seal(isolate); - - // Should fail - v8::Local obj = v8::Object::New(isolate); - - USE(obj); -} - - -TEST(SealHandleScopeNested) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handle_scope(isolate); - LocalContext env; - - v8::SealHandleScope seal(isolate); - - { - v8::HandleScope handle_scope(isolate); - - // Should work - v8::Local obj = v8::Object::New(isolate); - - USE(obj); - } -} diff --git a/deps/v8/test/mjsunit/regress/regress-3976.js b/deps/v8/test/mjsunit/regress/regress-3976.js index c151f689f46e57..efa3ac03bc05a5 100644 --- a/deps/v8/test/mjsunit/regress/regress-3976.js +++ b/deps/v8/test/mjsunit/regress/regress-3976.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --max-old-space-size=60 +// Flags: --max-old-space-size=60 --check-handle-count table = []; diff --git a/deps/v8/test/mjsunit/regress/regress-466993.js b/deps/v8/test/mjsunit/regress/regress-466993.js new file mode 100644 index 00000000000000..6bf02bbbae0485 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-466993.js @@ -0,0 +1,18 @@ +// Copyright 2015 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. + +// Flags: --allow-natives-syntax + +var test = function() { + var a = {"1": false, "2": false, "3": false, "4": false}; + assertEquals(false, a[1]); + a[1] = true; +}; +test(); +test(); +test(); +%OptimizeFunctionOnNextCall(test); +test(); +test(); +test(); diff --git a/deps/v8/test/mjsunit/regress/regress-472504.js b/deps/v8/test/mjsunit/regress/regress-472504.js new file mode 100644 index 00000000000000..0e956f6e94d738 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-472504.js @@ -0,0 +1,9 @@ +// Copyright 2015 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. + +// Should not crash in ASAN. +function shouldThrow() { + shouldThrow(JSON.parse('{"0":1}')); +} +assertThrows("shouldThrow()", RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-485548-1.js b/deps/v8/test/mjsunit/regress/regress-crbug-485548-1.js new file mode 100644 index 00000000000000..bbd0f7dd45e263 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-485548-1.js @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +// Flags: --allow-natives-syntax --expose-gc + +var inner = new Array(); +inner.a = {x:1}; +inner[0] = 1.5; +inner.b = {x:2}; +assertTrue(%HasFastDoubleElements(inner)); + +function foo(o) { + return o.field.a.x; +} + +var outer = {}; +outer.field = inner; +foo(outer); +foo(outer); +foo(outer); +%OptimizeFunctionOnNextCall(foo); +foo(outer); + +// Generalize representation of field "a" of inner object. +var v = { get x() { return 0x7fffffff; } }; +inner.a = v; + +gc(); + +var boom = foo(outer); +print(boom); +assertEquals(0x7fffffff, boom); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-485548-2.js b/deps/v8/test/mjsunit/regress/regress-crbug-485548-2.js new file mode 100644 index 00000000000000..7e449a6fd45035 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-485548-2.js @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +// Flags: --allow-natives-syntax --expose-gc + +var inner = new Array(); +inner.a = {x:1}; +inner[0] = 1.5; +inner.b = {x:2}; +assertTrue(%HasFastDoubleElements(inner)); + +function foo(o) { + return o.field.b.x; +} + +var outer = {}; +outer.field = inner; +foo(outer); +foo(outer); +foo(outer); +%OptimizeFunctionOnNextCall(foo); +foo(outer); + +// Generalize representation of field "b" of inner object. +var v = { get x() { return 0x7fffffff; } }; +inner.b = v; + +gc(); + +var boom = foo(outer); +print(boom); +assertEquals(0x7fffffff, boom); diff --git a/deps/v8/test/mjsunit/regress/regress-smi-scanning.js b/deps/v8/test/mjsunit/regress/regress-smi-scanning.js new file mode 100644 index 00000000000000..56cf9f9a2e60dd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-smi-scanning.js @@ -0,0 +1,7 @@ +// Copyright 2015 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. + +x = 2 +3; +assertEquals(2, x); diff --git a/deps/v8/tools/run-tests.py b/deps/v8/tools/run-tests.py index f7e77ca1543a1a..a20b55ae86775f 100755 --- a/deps/v8/tools/run-tests.py +++ b/deps/v8/tools/run-tests.py @@ -584,10 +584,6 @@ def Execute(arch, mode, args, options, suites, workspace): if options.report: verbose.PrintReport(all_tests) - if num_tests == 0: - print "No tests to run." - return 0 - # Run the tests, either locally or distributed on the network. start_time = time.time() progress_indicator = progress.PROGRESS_INDICATORS[options.progress]() diff --git a/deps/v8/tools/testrunner/local/progress.py b/deps/v8/tools/testrunner/local/progress.py index ed9d315b4ed36e..f303ab9736290c 100644 --- a/deps/v8/tools/testrunner/local/progress.py +++ b/deps/v8/tools/testrunner/local/progress.py @@ -192,10 +192,12 @@ def Truncate(self, string, length): def PrintProgress(self, name): self.ClearLine(self.last_status_length) elapsed = time.time() - self.start_time + progress = 0 if not self.runner.total else ( + ((self.runner.total - self.runner.remaining) * 100) // + self.runner.total) status = self.templates['status_line'] % { 'passed': self.runner.succeeded, - 'remaining': (((self.runner.total - self.runner.remaining) * 100) // - self.runner.total), + 'progress': progress, 'failed': len(self.runner.failed), 'test': name, 'mins': int(elapsed) / 60, @@ -212,7 +214,7 @@ class ColorProgressIndicator(CompactProgressIndicator): def __init__(self): templates = { 'status_line': ("[%(mins)02i:%(secs)02i|" - "\033[34m%%%(remaining) 4d\033[0m|" + "\033[34m%%%(progress) 4d\033[0m|" "\033[32m+%(passed) 4d\033[0m|" "\033[31m-%(failed) 4d\033[0m]: %(test)s"), 'stdout': "\033[1m%s\033[0m", @@ -228,7 +230,7 @@ class MonochromeProgressIndicator(CompactProgressIndicator): def __init__(self): templates = { - 'status_line': ("[%(mins)02i:%(secs)02i|%%%(remaining) 4d|" + 'status_line': ("[%(mins)02i:%(secs)02i|%%%(progress) 4d|" "+%(passed) 4d|-%(failed) 4d]: %(test)s"), 'stdout': '%s', 'stderr': '%s', From 9745ecab49dd397f03266fbeb049e04c7dafa427 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 11 Apr 2015 16:02:22 +0200 Subject: [PATCH 2/2] deps: backport 1f8555 from v8's upstream Original commit message: api: introduce SealHandleScope When debugging Handle leaks in io.js we found it very convenient to be able to Seal some specific (root in our case) scope to prevent Handle allocations in it, and easily find leakage. R=yangguo BUG= Review URL: https://codereview.chromium.org/1079713002 Cr-Commit-Position: refs/heads/master@{#27766} Should help us identify and fix Handle leaks in core and user-space code. NOTE: Works only in Debug build now, but is still better than nothing. PR-URL: https://github.com/iojs/io.js/pull/1395 Reviewed-By: Ben Noordhuis --- deps/v8/include/v8.h | 18 +++++++++++++++++ deps/v8/src/api.cc | 21 ++++++++++++++++++++ deps/v8/src/api.h | 5 +---- deps/v8/test/cctest/cctest.status | 1 + deps/v8/test/cctest/test-api.cc | 32 +++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 4 deletions(-) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 19de92fa8c45b0..a272c5b2d1ca8f 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1072,6 +1072,24 @@ class ScriptOrigin { Handle source_map_url_; }; +class V8_EXPORT SealHandleScope { + public: + SealHandleScope(Isolate* isolate); + ~SealHandleScope(); + + private: + // Make it hard to create heap-allocated or illegal handle scopes by + // disallowing certain operations. + SealHandleScope(const SealHandleScope&); + void operator=(const SealHandleScope&); + void* operator new(size_t size); + void operator delete(void*, size_t); + + internal::Isolate* isolate_; + int prev_level_; + internal::Object** prev_limit_; +}; + /** * A compiled JavaScript script, not yet tied to a Context. diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 97ecc7efa2df04..c9c0f3ad85284e 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -682,6 +682,27 @@ i::Object** EscapableHandleScope::Escape(i::Object** escape_value) { } +SealHandleScope::SealHandleScope(Isolate* isolate) { + i::Isolate* internal_isolate = reinterpret_cast(isolate); + + isolate_ = internal_isolate; + i::HandleScopeData* current = internal_isolate->handle_scope_data(); + prev_limit_ = current->limit; + current->limit = current->next; + prev_level_ = current->level; + current->level = 0; +} + + +SealHandleScope::~SealHandleScope() { + i::HandleScopeData* current = isolate_->handle_scope_data(); + DCHECK_EQ(0, current->level); + current->level = prev_level_; + DCHECK_EQ(current->next, current->limit); + current->limit = prev_limit_; +} + + void Context::Enter() { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index fa8682bf572079..7fce3e3b0a27e2 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -661,7 +661,7 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { while (!blocks_.is_empty()) { internal::Object** block_start = blocks_.last(); internal::Object** block_limit = block_start + kHandleBlockSize; -#ifdef DEBUG + // SealHandleScope may make the prev_limit to point inside the block. if (block_start <= prev_limit && prev_limit <= block_limit) { #ifdef ENABLE_HANDLE_ZAPPING @@ -669,9 +669,6 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { #endif break; } -#else - if (prev_limit == block_limit) break; -#endif blocks_.RemoveLast(); #ifdef ENABLE_HANDLE_ZAPPING diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 99f699071245e3..d7f72495ae6c7d 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -40,6 +40,7 @@ # they don't fail then test.py has failed. 'test-serialize/TestThatAlwaysFails': [FAIL], 'test-serialize/DependentTestThatAlwaysFails': [FAIL], + 'test-api/SealHandleScope': [FAIL], # This test always fails. It tests that LiveEdit causes abort when turned off. 'test-debug/LiveEditDisabled': [FAIL], diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 0c169a4a3d06fd..d60df1fb7e6326 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -18829,6 +18829,38 @@ void CallCompletedCallbackException() { } +TEST(SealHandleScope) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + v8::SealHandleScope seal(isolate); + + // Should fail + v8::Local obj = v8::Object::New(isolate); + + USE(obj); +} + + +TEST(SealHandleScopeNested) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + v8::SealHandleScope seal(isolate); + + { + v8::HandleScope handle_scope(isolate); + + // Should work + v8::Local obj = v8::Object::New(isolate); + + USE(obj); + } +} + + TEST(CallCompletedCallbackOneException) { LocalContext env; v8::HandleScope scope(env->GetIsolate());