From 7c347c545e33d279b5aa476e754a5358201be846 Mon Sep 17 00:00:00 2001 From: mvstanton Date: Mon, 30 Mar 2015 02:19:58 -0700 Subject: [PATCH] Ensure object literal element boilerplates aren't modified. A bug allows JSObject literals with elements to have the elements in the boilerplate modified. BUG=466993 LOG=N Review URL: https://codereview.chromium.org/1037273002 Cr-Commit-Position: refs/heads/master@{#27511} --- src/arm/full-codegen-arm.cc | 33 +++++++--------------- src/arm64/full-codegen-arm64.cc | 37 +++++++------------------ src/ast.cc | 1 + src/ast.h | 24 +++++++++++++--- src/compiler/ast-graph-builder.cc | 4 +-- src/full-codegen.cc | 21 ++++++++++++++ src/full-codegen.h | 5 +++- src/hydrogen.cc | 13 ++------- src/ia32/full-codegen-ia32.cc | 38 ++++++++------------------ src/mips/full-codegen-mips.cc | 36 ++++++------------------ src/runtime/runtime-literals.cc | 3 +- src/x64/full-codegen-x64.cc | 35 ++++++------------------ test/mjsunit/regress/regress-466993.js | 18 ++++++++++++ 13 files changed, 119 insertions(+), 149 deletions(-) create mode 100644 test/mjsunit/regress/regress-466993.js diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 0bcb6a79cc..6ee8eb1cd6 100644 --- a/src/arm/full-codegen-arm.cc +++ b/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/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 015ec188cd..9feac938b5 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/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/src/ast.cc b/src/ast.cc index f8289311c4..8caf9c2a29 100644 --- a/src/ast.cc +++ b/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/src/ast.h b/src/ast.h index 676ec26231..27e8f09a90 100644 --- a/src/ast.h +++ b/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/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 373c6ea4ff..e550f51128 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/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/src/full-codegen.cc b/src/full-codegen.cc index c264704cbf..327230e75d 100644 --- a/src/full-codegen.cc +++ b/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/src/full-codegen.h b/src/full-codegen.h index 3420ca9b9b..d558ae6f22 100644 --- a/src/full-codegen.h +++ b/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/src/hydrogen.cc b/src/hydrogen.cc index 4389bfe78a..cde901cad5 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -5552,19 +5552,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), @@ -5723,10 +5717,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/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 357c2df1ce..1e578b4141 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/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/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 9a7de136ef..9f3655232b 100644 --- a/src/mips/full-codegen-mips.cc +++ b/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/src/runtime/runtime-literals.cc b/src/runtime/runtime-literals.cc index 83a2fcf45f..76226d68f5 100644 --- a/src/runtime/runtime-literals.cc +++ b/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/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index d8bf19fc11..5861327bb5 100644 --- a/src/x64/full-codegen-x64.cc +++ b/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/test/mjsunit/regress/regress-466993.js b/test/mjsunit/regress/regress-466993.js new file mode 100644 index 0000000000..6bf02bbbae --- /dev/null +++ b/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();