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..a272c5b2d1ca8f 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 --- @@ -1090,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/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/test-api.cc b/deps/v8/test/cctest/test-api.cc index 8432cbfba12598..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()); @@ -21876,35 +21908,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',