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}
This commit is contained in:
mvstanton 2015-03-30 02:19:58 -07:00 committed by Commit bot
parent f303b81bde
commit 7c347c545e
13 changed files with 119 additions and 149 deletions

View File

@ -1698,21 +1698,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
__ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(constant_properties)); __ mov(r1, Operand(constant_properties));
int flags = expr->fast_elements() int flags = expr->ComputeFlags();
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
flags |= expr->has_function()
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ mov(r0, Operand(Smi::FromInt(flags))); __ mov(r0, Operand(Smi::FromInt(flags)));
int properties_count = constant_properties->length() / 2; if (MustCreateObjectLiteralWithRuntime(expr)) {
if (expr->may_store_doubles() || expr->depth() > 1 ||
masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements ||
properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
__ Push(r3, r2, r1, r0); __ Push(r3, r2, r1, r0);
__ CallRuntime(Runtime::kCreateObjectLiteral, 4); __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else { } else {
FastCloneShallowObjectStub stub(isolate(), properties_count); FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
__ CallStub(&stub); __ CallStub(&stub);
} }
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
@ -1904,17 +1896,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate()); expr->BuildConstantElements(isolate());
int flags = expr->depth() == 1
? ArrayLiteral::kShallowElements
: ArrayLiteral::kNoFlags;
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements(); Handle<FixedArray> constant_elements = expr->constant_elements();
DCHECK_EQ(2, constant_elements->length()); bool has_fast_elements =
ElementsKind constant_elements_kind = IsFastObjectElementsKind(expr->constant_elements_kind());
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind);
Handle<FixedArrayBase> constant_elements_values( Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1))); FixedArrayBase::cast(constant_elements->get(1)));
@ -1929,8 +1914,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
__ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r1, Operand(constant_elements)); __ mov(r1, Operand(constant_elements));
if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { if (MustCreateArrayLiteralWithRuntime(expr)) {
__ mov(r0, Operand(Smi::FromInt(flags))); __ mov(r0, Operand(Smi::FromInt(expr->ComputeFlags())));
__ Push(r3, r2, r1, r0); __ Push(r3, r2, r1, r0);
__ CallRuntime(Runtime::kCreateArrayLiteral, 4); __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else { } else {
@ -1940,6 +1925,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
// Emit code to evaluate all the non-constant subexpressions and to store // Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array. // them into the newly cloned array.
@ -1956,7 +1943,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
VisitForAccumulatorValue(subexpr); VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) { if (has_fast_elements) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize); int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ ldr(r6, MemOperand(sp, kPointerSize)); // Copy of array literal. __ ldr(r6, MemOperand(sp, kPointerSize)); // Copy of array literal.
__ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset)); __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));

View File

@ -1677,23 +1677,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset)); __ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset));
__ Mov(x2, Smi::FromInt(expr->literal_index())); __ Mov(x2, Smi::FromInt(expr->literal_index()));
__ Mov(x1, Operand(constant_properties)); __ Mov(x1, Operand(constant_properties));
int flags = expr->fast_elements() int flags = expr->ComputeFlags();
? ObjectLiteral::kFastElements
: ObjectLiteral::kNoFlags;
flags |= expr->has_function()
? ObjectLiteral::kHasFunction
: ObjectLiteral::kNoFlags;
__ Mov(x0, Smi::FromInt(flags)); __ Mov(x0, Smi::FromInt(flags));
int properties_count = constant_properties->length() / 2; if (MustCreateObjectLiteralWithRuntime(expr)) {
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) {
__ Push(x3, x2, x1, x0); __ Push(x3, x2, x1, x0);
__ CallRuntime(Runtime::kCreateObjectLiteral, 4); __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else { } else {
FastCloneShallowObjectStub stub(isolate(), properties_count); FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
__ CallStub(&stub); __ CallStub(&stub);
} }
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
@ -1885,18 +1875,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate()); expr->BuildConstantElements(isolate());
int flags = (expr->depth() == 1) ? ArrayLiteral::kShallowElements
: ArrayLiteral::kNoFlags;
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements(); Handle<FixedArray> constant_elements = expr->constant_elements();
DCHECK_EQ(2, constant_elements->length()); bool has_fast_elements =
ElementsKind constant_elements_kind = IsFastObjectElementsKind(expr->constant_elements_kind());
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind);
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
if (has_fast_elements && !FLAG_allocation_site_pretenuring) { if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
@ -1909,8 +1890,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset)); __ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset));
__ Mov(x2, Smi::FromInt(expr->literal_index())); __ Mov(x2, Smi::FromInt(expr->literal_index()));
__ Mov(x1, Operand(constant_elements)); __ Mov(x1, Operand(constant_elements));
if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { if (MustCreateArrayLiteralWithRuntime(expr)) {
__ Mov(x0, Smi::FromInt(flags)); __ Mov(x0, Smi::FromInt(expr->ComputeFlags()));
__ Push(x3, x2, x1, x0); __ Push(x3, x2, x1, x0);
__ CallRuntime(Runtime::kCreateArrayLiteral, 4); __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else { } else {
@ -1920,6 +1901,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
// Emit code to evaluate all the non-constant subexpressions and to store // Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array. // them into the newly cloned array.
@ -1936,7 +1919,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
VisitForAccumulatorValue(subexpr); VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) { if (has_fast_elements) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize); int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ Peek(x6, kPointerSize); // Copy of array literal. __ Peek(x6, kPointerSize); // Copy of array literal.
__ Ldr(x1, FieldMemOperand(x6, JSObject::kElementsOffset)); __ Ldr(x1, FieldMemOperand(x6, JSObject::kElementsOffset));

View File

@ -368,6 +368,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
constant_properties_ = constant_properties; constant_properties_ = constant_properties;
fast_elements_ = fast_elements_ =
(max_element_index <= 32) || ((2 * elements) >= max_element_index); (max_element_index <= 32) || ((2 * elements) >= max_element_index);
has_elements_ = elements > 0;
set_is_simple(is_simple); set_is_simple(is_simple);
set_depth(depth_acc); set_depth(depth_acc);
} }

View File

@ -1482,10 +1482,12 @@ class ObjectLiteral FINAL : public MaterializedLiteral {
Handle<FixedArray> constant_properties() const { Handle<FixedArray> constant_properties() const {
return constant_properties_; return constant_properties_;
} }
int properties_count() const { return constant_properties_->length() / 2; }
ZoneList<Property*>* properties() const { return properties_; } ZoneList<Property*>* properties() const { return properties_; }
bool fast_elements() const { return fast_elements_; } bool fast_elements() const { return fast_elements_; }
bool may_store_doubles() const { return may_store_doubles_; } bool may_store_doubles() const { return may_store_doubles_; }
bool has_function() const { return has_function_; } bool has_function() const { return has_function_; }
bool has_elements() const { return has_elements_; }
// Decide if a property should be in the object boilerplate. // Decide if a property should be in the object boilerplate.
static bool IsBoilerplateProperty(Property* property); static bool IsBoilerplateProperty(Property* property);
@ -1499,16 +1501,20 @@ class ObjectLiteral FINAL : public MaterializedLiteral {
void CalculateEmitStore(Zone* zone); void CalculateEmitStore(Zone* zone);
// Assemble bitfield of flags for the CreateObjectLiteral helper. // Assemble bitfield of flags for the CreateObjectLiteral helper.
int ComputeFlags() const { int ComputeFlags(bool disable_mementos = false) const {
int flags = fast_elements() ? kFastElements : kNoFlags; int flags = fast_elements() ? kFastElements : kNoFlags;
flags |= has_function() ? kHasFunction : kNoFlags; flags |= has_function() ? kHasFunction : kNoFlags;
if (disable_mementos) {
flags |= kDisableMementos;
}
return flags; return flags;
} }
enum Flags { enum Flags {
kNoFlags = 0, kNoFlags = 0,
kFastElements = 1, kFastElements = 1,
kHasFunction = 1 << 1 kHasFunction = 1 << 1,
kDisableMementos = 1 << 2
}; };
struct Accessors: public ZoneObject { struct Accessors: public ZoneObject {
@ -1533,6 +1539,7 @@ class ObjectLiteral FINAL : public MaterializedLiteral {
properties_(properties), properties_(properties),
boilerplate_properties_(boilerplate_properties), boilerplate_properties_(boilerplate_properties),
fast_elements_(false), fast_elements_(false),
has_elements_(false),
may_store_doubles_(false), may_store_doubles_(false),
has_function_(has_function) {} has_function_(has_function) {}
static int parent_num_ids() { return MaterializedLiteral::num_ids(); } static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
@ -1543,6 +1550,7 @@ class ObjectLiteral FINAL : public MaterializedLiteral {
ZoneList<Property*>* properties_; ZoneList<Property*>* properties_;
int boilerplate_properties_; int boilerplate_properties_;
bool fast_elements_; bool fast_elements_;
bool has_elements_;
bool may_store_doubles_; bool may_store_doubles_;
bool has_function_; bool has_function_;
}; };
@ -1578,6 +1586,12 @@ class ArrayLiteral FINAL : public MaterializedLiteral {
DECLARE_NODE_TYPE(ArrayLiteral) DECLARE_NODE_TYPE(ArrayLiteral)
Handle<FixedArray> constant_elements() const { return constant_elements_; } Handle<FixedArray> constant_elements() const { return constant_elements_; }
ElementsKind constant_elements_kind() const {
DCHECK_EQ(2, constant_elements_->length());
return static_cast<ElementsKind>(
Smi::cast(constant_elements_->get(0))->value());
}
ZoneList<Expression*>* values() const { return values_; } ZoneList<Expression*>* values() const { return values_; }
BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); } BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
@ -1593,9 +1607,11 @@ class ArrayLiteral FINAL : public MaterializedLiteral {
void BuildConstantElements(Isolate* isolate); void BuildConstantElements(Isolate* isolate);
// Assemble bitfield of flags for the CreateArrayLiteral helper. // Assemble bitfield of flags for the CreateArrayLiteral helper.
int ComputeFlags() const { int ComputeFlags(bool disable_mementos = false) const {
int flags = depth() == 1 ? kShallowElements : kNoFlags; int flags = depth() == 1 ? kShallowElements : kNoFlags;
flags |= ArrayLiteral::kDisableMementos; if (disable_mementos) {
flags |= kDisableMementos;
}
return flags; return flags;
} }

View File

@ -1627,7 +1627,7 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset); BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_properties()); Node* constants = jsgraph()->Constant(expr->constant_properties());
Node* flags = jsgraph()->Constant(expr->ComputeFlags()); Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
const Operator* op = const Operator* op =
javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4); javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags); Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
@ -1819,7 +1819,7 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset); BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_elements()); Node* constants = jsgraph()->Constant(expr->constant_elements());
Node* flags = jsgraph()->Constant(expr->ComputeFlags()); Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
const Operator* op = const Operator* op =
javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4); javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, constants, flags); Node* literal = NewNode(op, literals_array, literal_index, constants, flags);

View File

@ -415,6 +415,27 @@ void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> 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() { void FullCodeGenerator::Initialize() {
InitializeAstVisitor(info_->isolate(), info_->zone()); InitializeAstVisitor(info_->isolate(), info_->zone());
// The generation of debug code must match between the snapshot code and the // The generation of debug code must match between the snapshot code and the

View File

@ -715,7 +715,7 @@ class FullCodeGenerator: public AstVisitor {
loop_depth_--; loop_depth_--;
} }
MacroAssembler* masm() { return masm_; } MacroAssembler* masm() const { return masm_; }
class ExpressionContext; class ExpressionContext;
const ExpressionContext* context() { return context_; } const ExpressionContext* context() { return context_; }
@ -759,6 +759,9 @@ class FullCodeGenerator: public AstVisitor {
void PopulateDeoptimizationData(Handle<Code> code); void PopulateDeoptimizationData(Handle<Code> code);
void PopulateTypeFeedbackInfo(Handle<Code> code); void PopulateTypeFeedbackInfo(Handle<Code> code);
bool MustCreateObjectLiteralWithRuntime(ObjectLiteral* expr) const;
bool MustCreateArrayLiteralWithRuntime(ArrayLiteral* expr) const;
Handle<HandlerTable> handler_table() { return handler_table_; } Handle<HandlerTable> handler_table() { return handler_table_; }
struct BailoutEntry { struct BailoutEntry {

View File

@ -5552,19 +5552,13 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<FixedArray> closure_literals(closure->literals(), isolate()); Handle<FixedArray> closure_literals(closure->literals(), isolate());
Handle<FixedArray> constant_properties = expr->constant_properties(); Handle<FixedArray> constant_properties = expr->constant_properties();
int literal_index = expr->literal_index(); int literal_index = expr->literal_index();
int flags = expr->fast_elements() int flags = expr->ComputeFlags(true);
? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags;
flags |= expr->has_function()
? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags;
Add<HPushArguments>(Add<HConstant>(closure_literals), Add<HPushArguments>(Add<HConstant>(closure_literals),
Add<HConstant>(literal_index), Add<HConstant>(literal_index),
Add<HConstant>(constant_properties), Add<HConstant>(constant_properties),
Add<HConstant>(flags)); Add<HConstant>(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; Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id), Runtime::FunctionForId(function_id),
@ -5723,10 +5717,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
// pass an empty fixed array to the runtime function instead. // pass an empty fixed array to the runtime function instead.
Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array(); Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array();
int literal_index = expr->literal_index(); int literal_index = expr->literal_index();
int flags = expr->depth() == 1 int flags = expr->ComputeFlags(true);
? ArrayLiteral::kShallowElements
: ArrayLiteral::kNoFlags;
flags |= ArrayLiteral::kDisableMementos;
Add<HPushArguments>(Add<HConstant>(literals), Add<HPushArguments>(Add<HConstant>(literals),
Add<HConstant>(literal_index), Add<HConstant>(literal_index),

View File

@ -1622,17 +1622,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
expr->BuildConstantProperties(isolate()); expr->BuildConstantProperties(isolate());
Handle<FixedArray> constant_properties = expr->constant_properties(); Handle<FixedArray> constant_properties = expr->constant_properties();
int flags = expr->fast_elements() int flags = expr->ComputeFlags();
? ObjectLiteral::kFastElements // If any of the keys would store to the elements array, then we shouldn't
: ObjectLiteral::kNoFlags; // allow it.
flags |= expr->has_function() if (MustCreateObjectLiteralWithRuntime(expr)) {
? 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) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index()))); __ 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(ebx, Immediate(Smi::FromInt(expr->literal_index())));
__ mov(ecx, Immediate(constant_properties)); __ mov(ecx, Immediate(constant_properties));
__ mov(edx, Immediate(Smi::FromInt(flags))); __ mov(edx, Immediate(Smi::FromInt(flags)));
FastCloneShallowObjectStub stub(isolate(), properties_count); FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
__ CallStub(&stub); __ CallStub(&stub);
} }
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
@ -1824,20 +1817,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate()); expr->BuildConstantElements(isolate());
int flags = expr->depth() == 1
? ArrayLiteral::kShallowElements
: ArrayLiteral::kNoFlags;
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements(); Handle<FixedArray> constant_elements = expr->constant_elements();
DCHECK_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
bool has_constant_fast_elements = bool has_constant_fast_elements =
IsFastObjectElementsKind(constant_elements_kind); IsFastObjectElementsKind(expr->constant_elements_kind());
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { 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; allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
} }
if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { if (MustCreateArrayLiteralWithRuntime(expr)) {
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
__ push(Immediate(Smi::FromInt(expr->literal_index()))); __ push(Immediate(Smi::FromInt(expr->literal_index())));
__ push(Immediate(constant_elements)); __ push(Immediate(constant_elements));
__ push(Immediate(Smi::FromInt(flags))); __ push(Immediate(Smi::FromInt(expr->ComputeFlags())));
__ CallRuntime(Runtime::kCreateArrayLiteral, 4); __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else { } else {
__ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
@ -1864,6 +1846,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
// Emit code to evaluate all the non-constant subexpressions and to store // Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array. // them into the newly cloned array.
@ -1880,7 +1864,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
VisitForAccumulatorValue(subexpr); VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) { if (has_constant_fast_elements) {
// Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
// cannot transition and don't need to call the runtime stub. // cannot transition and don't need to call the runtime stub.
int offset = FixedArray::kHeaderSize + (i * kPointerSize); int offset = FixedArray::kHeaderSize + (i * kPointerSize);

View File

@ -1684,21 +1684,12 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
__ li(a2, Operand(Smi::FromInt(expr->literal_index()))); __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
__ li(a1, Operand(constant_properties)); __ li(a1, Operand(constant_properties));
int flags = expr->fast_elements() __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags())));
? ObjectLiteral::kFastElements if (MustCreateObjectLiteralWithRuntime(expr)) {
: 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) {
__ Push(a3, a2, a1, a0); __ Push(a3, a2, a1, a0);
__ CallRuntime(Runtime::kCreateObjectLiteral, 4); __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else { } else {
FastCloneShallowObjectStub stub(isolate(), properties_count); FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
__ CallStub(&stub); __ CallStub(&stub);
} }
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
@ -1890,21 +1881,10 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate()); expr->BuildConstantElements(isolate());
int flags = expr->depth() == 1
? ArrayLiteral::kShallowElements
: ArrayLiteral::kNoFlags;
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements(); Handle<FixedArray> constant_elements = expr->constant_elements();
DCHECK_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
bool has_fast_elements = bool has_fast_elements =
IsFastObjectElementsKind(constant_elements_kind); IsFastObjectElementsKind(expr->constant_elements_kind());
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
if (has_fast_elements && !FLAG_allocation_site_pretenuring) { if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
@ -1918,8 +1898,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset)); __ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
__ li(a2, Operand(Smi::FromInt(expr->literal_index()))); __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
__ li(a1, Operand(constant_elements)); __ li(a1, Operand(constant_elements));
if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { if (MustCreateArrayLiteralWithRuntime(expr)) {
__ li(a0, Operand(Smi::FromInt(flags))); __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags())));
__ Push(a3, a2, a1, a0); __ Push(a3, a2, a1, a0);
__ CallRuntime(Runtime::kCreateArrayLiteral, 4); __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else { } else {
@ -1929,6 +1909,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
// Emit code to evaluate all the non-constant subexpressions and to store // Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array. // them into the newly cloned array.
@ -1946,7 +1928,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
VisitForAccumulatorValue(subexpr); VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) { if (has_fast_elements) {
int offset = FixedArray::kHeaderSize + (i * kPointerSize); int offset = FixedArray::kHeaderSize + (i * kPointerSize);
__ lw(t2, MemOperand(sp, kPointerSize)); // Copy of array literal. __ lw(t2, MemOperand(sp, kPointerSize)); // Copy of array literal.
__ lw(a1, FieldMemOperand(t2, JSObject::kElementsOffset)); __ lw(a1, FieldMemOperand(t2, JSObject::kElementsOffset));

View File

@ -237,6 +237,7 @@ RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
CONVERT_SMI_ARG_CHECKED(flags, 3); CONVERT_SMI_ARG_CHECKED(flags, 3);
bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 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()); RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length());
@ -267,7 +268,7 @@ RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
Handle<JSObject>(JSObject::cast(site->transition_info()), isolate); Handle<JSObject>(JSObject::cast(site->transition_info()), isolate);
} }
AllocationSiteUsageContext usage_context(isolate, site, true); AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
usage_context.EnterNewScope(); usage_context.EnterNewScope();
MaybeHandle<Object> maybe_copy = MaybeHandle<Object> maybe_copy =
JSObject::DeepCopy(boilerplate, &usage_context); JSObject::DeepCopy(boilerplate, &usage_context);

View File

@ -1657,16 +1657,8 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
expr->BuildConstantProperties(isolate()); expr->BuildConstantProperties(isolate());
Handle<FixedArray> constant_properties = expr->constant_properties(); Handle<FixedArray> constant_properties = expr->constant_properties();
int flags = expr->fast_elements() int flags = expr->ComputeFlags();
? ObjectLiteral::kFastElements if (MustCreateObjectLiteralWithRuntime(expr)) {
: 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) {
__ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ Push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); __ Push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index())); __ Push(Smi::FromInt(expr->literal_index()));
@ -1679,7 +1671,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Move(rbx, Smi::FromInt(expr->literal_index())); __ Move(rbx, Smi::FromInt(expr->literal_index()));
__ Move(rcx, constant_properties); __ Move(rcx, constant_properties);
__ Move(rdx, Smi::FromInt(flags)); __ Move(rdx, Smi::FromInt(flags));
FastCloneShallowObjectStub stub(isolate(), properties_count); FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
__ CallStub(&stub); __ CallStub(&stub);
} }
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
@ -1858,20 +1850,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Comment cmnt(masm_, "[ ArrayLiteral"); Comment cmnt(masm_, "[ ArrayLiteral");
expr->BuildConstantElements(isolate()); expr->BuildConstantElements(isolate());
int flags = expr->depth() == 1
? ArrayLiteral::kShallowElements
: ArrayLiteral::kNoFlags;
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
Handle<FixedArray> constant_elements = expr->constant_elements(); Handle<FixedArray> constant_elements = expr->constant_elements();
DCHECK_EQ(2, constant_elements->length());
ElementsKind constant_elements_kind =
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
bool has_constant_fast_elements = bool has_constant_fast_elements =
IsFastObjectElementsKind(constant_elements_kind); IsFastObjectElementsKind(expr->constant_elements_kind());
Handle<FixedArrayBase> constant_elements_values(
FixedArrayBase::cast(constant_elements->get(1)));
AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) { 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; allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
} }
if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) { if (MustCreateArrayLiteralWithRuntime(expr)) {
__ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ Push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); __ Push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index())); __ Push(Smi::FromInt(expr->literal_index()));
__ Push(constant_elements); __ Push(constant_elements);
__ Push(Smi::FromInt(flags)); __ Push(Smi::FromInt(expr->ComputeFlags()));
__ CallRuntime(Runtime::kCreateArrayLiteral, 4); __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
} else { } else {
__ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ movp(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
@ -1898,6 +1879,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG);
bool result_saved = false; // Is the result saved to the stack? bool result_saved = false; // Is the result saved to the stack?
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
// Emit code to evaluate all the non-constant subexpressions and to store // Emit code to evaluate all the non-constant subexpressions and to store
// them into the newly cloned array. // them into the newly cloned array.
@ -1914,7 +1897,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
} }
VisitForAccumulatorValue(subexpr); VisitForAccumulatorValue(subexpr);
if (IsFastObjectElementsKind(constant_elements_kind)) { if (has_constant_fast_elements) {
// Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
// cannot transition and don't need to call the runtime stub. // cannot transition and don't need to call the runtime stub.
int offset = FixedArray::kHeaderSize + (i * kPointerSize); int offset = FixedArray::kHeaderSize + (i * kPointerSize);

View File

@ -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();