ES6 computed property names
This adds support for computed property names, under the flag
--harmony-computed-property-names, for both object literals and
classes.
This is a revert of the revert, 7d48fd9dc2
.
BUG=v8:3754
LOG=Y
R=dslomov@chromium.org
Review URL: https://codereview.chromium.org/798243004
Cr-Commit-Position: refs/heads/master@{#26084}
This commit is contained in:
parent
d3cd92a2f8
commit
74e38e34b3
@ -1686,11 +1686,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
expr->CalculateEmitStore(zone());
|
expr->CalculateEmitStore(zone());
|
||||||
|
|
||||||
AccessorTable accessor_table(zone());
|
AccessorTable accessor_table(zone());
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
int property_index = 0;
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
if (property->is_computed_name()) break;
|
||||||
if (property->IsCompileTimeValue()) continue;
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key()->AsLiteral();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ push(r0); // Save result on stack
|
__ push(r0); // Save result on stack
|
||||||
@ -1778,6 +1780,67 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Object literals have two parts. The "static" part on the left contains no
|
||||||
|
// computed property names, and so we can compute its map ahead of time; see
|
||||||
|
// runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
|
||||||
|
// starts with the first computed property name, and continues with all
|
||||||
|
// properties to its right. All the code from above initializes the static
|
||||||
|
// component of the object literal, and arranges for the map of the result to
|
||||||
|
// reflect the static order in which the keys appear. For the dynamic
|
||||||
|
// properties, we compile them into a series of "SetOwnProperty" runtime
|
||||||
|
// calls. This will preserve insertion order.
|
||||||
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
|
||||||
|
Expression* value = property->value();
|
||||||
|
if (!result_saved) {
|
||||||
|
__ push(r0); // Save result on the stack
|
||||||
|
result_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__ ldr(r0, MemOperand(sp)); // Duplicate receiver.
|
||||||
|
__ push(r0);
|
||||||
|
|
||||||
|
if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
|
||||||
|
DCHECK(!property->is_computed_name());
|
||||||
|
VisitForStackValue(value);
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ CallRuntime(Runtime::kInternalSetPrototype, 2);
|
||||||
|
} else {
|
||||||
|
__ Drop(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EmitPropertyKey(property);
|
||||||
|
VisitForStackValue(value);
|
||||||
|
|
||||||
|
switch (property->kind()) {
|
||||||
|
case ObjectLiteral::Property::CONSTANT:
|
||||||
|
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
|
||||||
|
case ObjectLiteral::Property::COMPUTED:
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ mov(r0, Operand(Smi::FromInt(NONE)));
|
||||||
|
__ push(r0);
|
||||||
|
__ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
|
||||||
|
} else {
|
||||||
|
__ Drop(3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::PROTOTYPE:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::GETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::SETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (expr->has_function()) {
|
if (expr->has_function()) {
|
||||||
DCHECK(result_saved);
|
DCHECK(result_saved);
|
||||||
__ ldr(r0, MemOperand(sp));
|
__ ldr(r0, MemOperand(sp));
|
||||||
@ -2478,9 +2541,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
|
|
||||||
for (int i = 0; i < lit->properties()->length(); i++) {
|
for (int i = 0; i < lit->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = lit->properties()->at(i);
|
ObjectLiteral::Property* property = lit->properties()->at(i);
|
||||||
Literal* key = property->key()->AsLiteral();
|
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
DCHECK(key != NULL);
|
|
||||||
|
|
||||||
if (property->is_static()) {
|
if (property->is_static()) {
|
||||||
__ ldr(scratch, MemOperand(sp, kPointerSize)); // constructor
|
__ ldr(scratch, MemOperand(sp, kPointerSize)); // constructor
|
||||||
@ -2488,7 +2549,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
__ ldr(scratch, MemOperand(sp, 0)); // prototype
|
__ ldr(scratch, MemOperand(sp, 0)); // prototype
|
||||||
}
|
}
|
||||||
__ push(scratch);
|
__ push(scratch);
|
||||||
VisitForStackValue(key);
|
EmitPropertyKey(property);
|
||||||
VisitForStackValue(value);
|
VisitForStackValue(value);
|
||||||
EmitSetHomeObjectIfNeeded(value, 2);
|
EmitSetHomeObjectIfNeeded(value, 2);
|
||||||
|
|
||||||
@ -2501,11 +2562,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::GETTER:
|
case ObjectLiteral::Property::GETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassGetter, 3);
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::SETTER:
|
case ObjectLiteral::Property::SETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassSetter, 3);
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1667,11 +1667,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
expr->CalculateEmitStore(zone());
|
expr->CalculateEmitStore(zone());
|
||||||
|
|
||||||
AccessorTable accessor_table(zone());
|
AccessorTable accessor_table(zone());
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
int property_index = 0;
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
if (property->is_computed_name()) break;
|
||||||
if (property->IsCompileTimeValue()) continue;
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key()->AsLiteral();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ Push(x0); // Save result on stack
|
__ Push(x0); // Save result on stack
|
||||||
@ -1759,6 +1761,67 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Object literals have two parts. The "static" part on the left contains no
|
||||||
|
// computed property names, and so we can compute its map ahead of time; see
|
||||||
|
// runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
|
||||||
|
// starts with the first computed property name, and continues with all
|
||||||
|
// properties to its right. All the code from above initializes the static
|
||||||
|
// component of the object literal, and arranges for the map of the result to
|
||||||
|
// reflect the static order in which the keys appear. For the dynamic
|
||||||
|
// properties, we compile them into a series of "SetOwnProperty" runtime
|
||||||
|
// calls. This will preserve insertion order.
|
||||||
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
|
||||||
|
Expression* value = property->value();
|
||||||
|
if (!result_saved) {
|
||||||
|
__ Push(x0); // Save result on stack
|
||||||
|
result_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__ Peek(x10, 0); // Duplicate receiver.
|
||||||
|
__ Push(x10);
|
||||||
|
|
||||||
|
if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
|
||||||
|
DCHECK(!property->is_computed_name());
|
||||||
|
VisitForStackValue(value);
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ CallRuntime(Runtime::kInternalSetPrototype, 2);
|
||||||
|
} else {
|
||||||
|
__ Drop(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EmitPropertyKey(property);
|
||||||
|
VisitForStackValue(value);
|
||||||
|
|
||||||
|
switch (property->kind()) {
|
||||||
|
case ObjectLiteral::Property::CONSTANT:
|
||||||
|
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
|
||||||
|
case ObjectLiteral::Property::COMPUTED:
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ Mov(x0, Smi::FromInt(NONE));
|
||||||
|
__ Push(x0);
|
||||||
|
__ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
|
||||||
|
} else {
|
||||||
|
__ Drop(3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::PROTOTYPE:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::GETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::SETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (expr->has_function()) {
|
if (expr->has_function()) {
|
||||||
DCHECK(result_saved);
|
DCHECK(result_saved);
|
||||||
__ Peek(x0, 0);
|
__ Peek(x0, 0);
|
||||||
@ -2175,9 +2238,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
|
|
||||||
for (int i = 0; i < lit->properties()->length(); i++) {
|
for (int i = 0; i < lit->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = lit->properties()->at(i);
|
ObjectLiteral::Property* property = lit->properties()->at(i);
|
||||||
Literal* key = property->key()->AsLiteral();
|
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
DCHECK(key != NULL);
|
|
||||||
|
|
||||||
if (property->is_static()) {
|
if (property->is_static()) {
|
||||||
__ Peek(scratch, kPointerSize); // constructor
|
__ Peek(scratch, kPointerSize); // constructor
|
||||||
@ -2185,7 +2246,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
__ Peek(scratch, 0); // prototype
|
__ Peek(scratch, 0); // prototype
|
||||||
}
|
}
|
||||||
__ Push(scratch);
|
__ Push(scratch);
|
||||||
VisitForStackValue(key);
|
EmitPropertyKey(property);
|
||||||
VisitForStackValue(value);
|
VisitForStackValue(value);
|
||||||
EmitSetHomeObjectIfNeeded(value, 2);
|
EmitSetHomeObjectIfNeeded(value, 2);
|
||||||
|
|
||||||
@ -2198,11 +2259,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::GETTER:
|
case ObjectLiteral::Property::GETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassGetter, 3);
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::SETTER:
|
case ObjectLiteral::Property::SETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassSetter, 3);
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -476,6 +476,7 @@ void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) {
|
|||||||
|
|
||||||
void AstNumberingVisitor::VisitObjectLiteralProperty(
|
void AstNumberingVisitor::VisitObjectLiteralProperty(
|
||||||
ObjectLiteralProperty* node) {
|
ObjectLiteralProperty* node) {
|
||||||
|
if (node->is_computed_name()) DisableTurbofan(kComputedPropertyName);
|
||||||
Visit(node->key());
|
Visit(node->key());
|
||||||
Visit(node->value());
|
Visit(node->value());
|
||||||
}
|
}
|
||||||
|
50
src/ast.cc
50
src/ast.cc
@ -185,13 +185,17 @@ void FunctionLiteral::InitializeSharedInfo(
|
|||||||
|
|
||||||
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
|
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
|
||||||
AstValueFactory* ast_value_factory,
|
AstValueFactory* ast_value_factory,
|
||||||
Literal* key, Expression* value,
|
Expression* key, Expression* value,
|
||||||
bool is_static) {
|
bool is_static,
|
||||||
emit_store_ = true;
|
bool is_computed_name)
|
||||||
key_ = key;
|
: key_(key),
|
||||||
value_ = value;
|
value_(value),
|
||||||
is_static_ = is_static;
|
emit_store_(true),
|
||||||
if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) {
|
is_static_(is_static),
|
||||||
|
is_computed_name_(is_computed_name) {
|
||||||
|
if (!is_computed_name &&
|
||||||
|
key->AsLiteral()->raw_value()->EqualsString(
|
||||||
|
ast_value_factory->proto_string())) {
|
||||||
kind_ = PROTOTYPE;
|
kind_ = PROTOTYPE;
|
||||||
} else if (value_->AsMaterializedLiteral() != NULL) {
|
} else if (value_->AsMaterializedLiteral() != NULL) {
|
||||||
kind_ = MATERIALIZED_LITERAL;
|
kind_ = MATERIALIZED_LITERAL;
|
||||||
@ -204,13 +208,16 @@ ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
|
|||||||
|
|
||||||
|
|
||||||
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter,
|
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter,
|
||||||
|
Expression* key,
|
||||||
FunctionLiteral* value,
|
FunctionLiteral* value,
|
||||||
bool is_static) {
|
bool is_static,
|
||||||
emit_store_ = true;
|
bool is_computed_name)
|
||||||
value_ = value;
|
: key_(key),
|
||||||
kind_ = is_getter ? GETTER : SETTER;
|
value_(value),
|
||||||
is_static_ = is_static;
|
kind_(is_getter ? GETTER : SETTER),
|
||||||
}
|
emit_store_(true),
|
||||||
|
is_static_(is_static),
|
||||||
|
is_computed_name_(is_computed_name) {}
|
||||||
|
|
||||||
|
|
||||||
bool ObjectLiteral::Property::IsCompileTimeValue() {
|
bool ObjectLiteral::Property::IsCompileTimeValue() {
|
||||||
@ -237,10 +244,11 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
|
|||||||
allocator);
|
allocator);
|
||||||
for (int i = properties()->length() - 1; i >= 0; i--) {
|
for (int i = properties()->length() - 1; i >= 0; i--) {
|
||||||
ObjectLiteral::Property* property = properties()->at(i);
|
ObjectLiteral::Property* property = properties()->at(i);
|
||||||
Literal* literal = property->key();
|
if (property->is_computed_name()) continue;
|
||||||
|
Literal* literal = property->key()->AsLiteral();
|
||||||
if (literal->value()->IsNull()) continue;
|
if (literal->value()->IsNull()) continue;
|
||||||
uint32_t hash = literal->Hash();
|
uint32_t hash = literal->Hash();
|
||||||
// If the key of a computed property is in the table, do not emit
|
// If the key of a computed property value is in the table, do not emit
|
||||||
// a store for the property later.
|
// a store for the property later.
|
||||||
if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL ||
|
if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL ||
|
||||||
property->kind() == ObjectLiteral::Property::COMPUTED) &&
|
property->kind() == ObjectLiteral::Property::COMPUTED) &&
|
||||||
@ -279,6 +287,13 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
|
|||||||
is_simple = false;
|
is_simple = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (position == boilerplate_properties_ * 2) {
|
||||||
|
DCHECK(property->is_computed_name());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DCHECK(!property->is_computed_name());
|
||||||
|
|
||||||
MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
|
MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
|
||||||
if (m_literal != NULL) {
|
if (m_literal != NULL) {
|
||||||
m_literal->BuildConstants(isolate);
|
m_literal->BuildConstants(isolate);
|
||||||
@ -288,7 +303,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
|
|||||||
// Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
|
// Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
|
||||||
// value for COMPUTED properties, the real value is filled in at
|
// value for COMPUTED properties, the real value is filled in at
|
||||||
// runtime. The enumeration order is maintained.
|
// runtime. The enumeration order is maintained.
|
||||||
Handle<Object> key = property->key()->value();
|
Handle<Object> key = property->key()->AsLiteral()->value();
|
||||||
Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
|
Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
|
||||||
|
|
||||||
// Ensure objects that may, at any point in time, contain fields with double
|
// Ensure objects that may, at any point in time, contain fields with double
|
||||||
@ -630,7 +645,8 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
|
|||||||
|
|
||||||
|
|
||||||
void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
|
void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
|
||||||
TypeFeedbackId id = key()->LiteralFeedbackId();
|
DCHECK(!is_computed_name());
|
||||||
|
TypeFeedbackId id = key()->AsLiteral()->LiteralFeedbackId();
|
||||||
SmallMapList maps;
|
SmallMapList maps;
|
||||||
oracle->CollectReceiverTypes(id, &maps);
|
oracle->CollectReceiverTypes(id, &maps);
|
||||||
receiver_type_ = maps.length() == 1 ? maps.at(0)
|
receiver_type_ = maps.length() == 1 ? maps.at(0)
|
||||||
|
38
src/ast.h
38
src/ast.h
@ -1432,10 +1432,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
|
|||||||
PROTOTYPE // Property is __proto__.
|
PROTOTYPE // Property is __proto__.
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory,
|
Expression* key() { return key_; }
|
||||||
Literal* key, Expression* value, bool is_static);
|
|
||||||
|
|
||||||
Literal* key() { return key_; }
|
|
||||||
Expression* value() { return value_; }
|
Expression* value() { return value_; }
|
||||||
Kind kind() { return kind_; }
|
Kind kind() { return kind_; }
|
||||||
|
|
||||||
@ -1450,20 +1447,26 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
|
|||||||
bool emit_store();
|
bool emit_store();
|
||||||
|
|
||||||
bool is_static() const { return is_static_; }
|
bool is_static() const { return is_static_; }
|
||||||
|
bool is_computed_name() const { return is_computed_name_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class AstNodeFactory;
|
friend class AstNodeFactory;
|
||||||
|
|
||||||
ObjectLiteralProperty(Zone* zone, bool is_getter, FunctionLiteral* value,
|
ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory,
|
||||||
bool is_static);
|
Expression* key, Expression* value, bool is_static,
|
||||||
void set_key(Literal* key) { key_ = key; }
|
bool is_computed_name);
|
||||||
|
|
||||||
|
ObjectLiteralProperty(Zone* zone, bool is_getter, Expression* key,
|
||||||
|
FunctionLiteral* value, bool is_static,
|
||||||
|
bool is_computed_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Literal* key_;
|
Expression* key_;
|
||||||
Expression* value_;
|
Expression* value_;
|
||||||
Kind kind_;
|
Kind kind_;
|
||||||
bool emit_store_;
|
bool emit_store_;
|
||||||
bool is_static_;
|
bool is_static_;
|
||||||
|
bool is_computed_name_;
|
||||||
Handle<Map> receiver_type_;
|
Handle<Map> receiver_type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3344,20 +3347,21 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
|
|||||||
boilerplate_properties, has_function, pos);
|
boilerplate_properties, has_function, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key,
|
ObjectLiteral::Property* NewObjectLiteralProperty(Expression* key,
|
||||||
Expression* value,
|
Expression* value,
|
||||||
bool is_static) {
|
bool is_static,
|
||||||
return new (zone_) ObjectLiteral::Property(zone_, ast_value_factory_, key,
|
bool is_computed_name) {
|
||||||
value, is_static);
|
return new (zone_) ObjectLiteral::Property(
|
||||||
|
zone_, ast_value_factory_, key, value, is_static, is_computed_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter,
|
ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter,
|
||||||
|
Expression* key,
|
||||||
FunctionLiteral* value,
|
FunctionLiteral* value,
|
||||||
int pos, bool is_static) {
|
int pos, bool is_static,
|
||||||
ObjectLiteral::Property* prop =
|
bool is_computed_name) {
|
||||||
new (zone_) ObjectLiteral::Property(zone_, is_getter, value, is_static);
|
return new (zone_) ObjectLiteral::Property(zone_, is_getter, key, value,
|
||||||
prop->set_key(NewStringLiteral(value->raw_name(), pos));
|
is_static, is_computed_name);
|
||||||
return prop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern,
|
RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern,
|
||||||
|
@ -47,6 +47,7 @@ namespace internal {
|
|||||||
V(kCodeGenerationFailed, "Code generation failed") \
|
V(kCodeGenerationFailed, "Code generation failed") \
|
||||||
V(kCodeObjectNotProperlyPatched, "Code object not properly patched") \
|
V(kCodeObjectNotProperlyPatched, "Code object not properly patched") \
|
||||||
V(kCompoundAssignmentToLookupSlot, "Compound assignment to lookup slot") \
|
V(kCompoundAssignmentToLookupSlot, "Compound assignment to lookup slot") \
|
||||||
|
V(kComputedPropertyName, "Computed property name") \
|
||||||
V(kContextAllocatedArguments, "Context-allocated arguments") \
|
V(kContextAllocatedArguments, "Context-allocated arguments") \
|
||||||
V(kCopyBuffersOverlap, "Copy buffers overlap") \
|
V(kCopyBuffersOverlap, "Copy buffers overlap") \
|
||||||
V(kCouldNotGenerateZero, "Could not generate +0.0") \
|
V(kCouldNotGenerateZero, "Could not generate +0.0") \
|
||||||
|
@ -1597,6 +1597,7 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_tostring)
|
|||||||
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_templates)
|
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_templates)
|
||||||
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sloppy)
|
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sloppy)
|
||||||
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode)
|
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode)
|
||||||
|
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_computed_property_names)
|
||||||
|
|
||||||
|
|
||||||
void Genesis::InstallNativeFunctions_harmony_proxies() {
|
void Genesis::InstallNativeFunctions_harmony_proxies() {
|
||||||
@ -1626,6 +1627,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tostring)
|
|||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_templates)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_templates)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_sloppy)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_sloppy)
|
||||||
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_computed_property_names)
|
||||||
|
|
||||||
void Genesis::InitializeGlobal_harmony_regexps() {
|
void Genesis::InitializeGlobal_harmony_regexps() {
|
||||||
Handle<JSObject> builtins(native_context()->builtins());
|
Handle<JSObject> builtins(native_context()->builtins());
|
||||||
@ -2192,6 +2194,7 @@ bool Genesis::InstallExperimentalNatives() {
|
|||||||
"native harmony-templates.js", NULL};
|
"native harmony-templates.js", NULL};
|
||||||
static const char* harmony_sloppy_natives[] = {NULL};
|
static const char* harmony_sloppy_natives[] = {NULL};
|
||||||
static const char* harmony_unicode_natives[] = {NULL};
|
static const char* harmony_unicode_natives[] = {NULL};
|
||||||
|
static const char* harmony_computed_property_names_natives[] = {NULL};
|
||||||
|
|
||||||
for (int i = ExperimentalNatives::GetDebuggerCount();
|
for (int i = ExperimentalNatives::GetDebuggerCount();
|
||||||
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
||||||
|
@ -165,35 +165,36 @@ enum BuiltinExtraArguments {
|
|||||||
DEBUG_BREAK)
|
DEBUG_BREAK)
|
||||||
|
|
||||||
// Define list of builtins implemented in JavaScript.
|
// Define list of builtins implemented in JavaScript.
|
||||||
#define BUILTINS_LIST_JS(V) \
|
#define BUILTINS_LIST_JS(V) \
|
||||||
V(EQUALS, 1) \
|
V(EQUALS, 1) \
|
||||||
V(STRICT_EQUALS, 1) \
|
V(STRICT_EQUALS, 1) \
|
||||||
V(COMPARE, 2) \
|
V(COMPARE, 2) \
|
||||||
V(ADD, 1) \
|
V(ADD, 1) \
|
||||||
V(SUB, 1) \
|
V(SUB, 1) \
|
||||||
V(MUL, 1) \
|
V(MUL, 1) \
|
||||||
V(DIV, 1) \
|
V(DIV, 1) \
|
||||||
V(MOD, 1) \
|
V(MOD, 1) \
|
||||||
V(BIT_OR, 1) \
|
V(BIT_OR, 1) \
|
||||||
V(BIT_AND, 1) \
|
V(BIT_AND, 1) \
|
||||||
V(BIT_XOR, 1) \
|
V(BIT_XOR, 1) \
|
||||||
V(SHL, 1) \
|
V(SHL, 1) \
|
||||||
V(SAR, 1) \
|
V(SAR, 1) \
|
||||||
V(SHR, 1) \
|
V(SHR, 1) \
|
||||||
V(DELETE, 2) \
|
V(DELETE, 2) \
|
||||||
V(IN, 1) \
|
V(IN, 1) \
|
||||||
V(INSTANCE_OF, 1) \
|
V(INSTANCE_OF, 1) \
|
||||||
V(FILTER_KEY, 1) \
|
V(FILTER_KEY, 1) \
|
||||||
V(CALL_NON_FUNCTION, 0) \
|
V(CALL_NON_FUNCTION, 0) \
|
||||||
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
|
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
|
||||||
V(CALL_FUNCTION_PROXY, 1) \
|
V(CALL_FUNCTION_PROXY, 1) \
|
||||||
V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR, 1) \
|
V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR, 1) \
|
||||||
V(TO_OBJECT, 0) \
|
V(TO_OBJECT, 0) \
|
||||||
V(TO_NUMBER, 0) \
|
V(TO_NUMBER, 0) \
|
||||||
V(TO_STRING, 0) \
|
V(TO_STRING, 0) \
|
||||||
V(STRING_ADD_LEFT, 1) \
|
V(TO_NAME, 0) \
|
||||||
V(STRING_ADD_RIGHT, 1) \
|
V(STRING_ADD_LEFT, 1) \
|
||||||
V(APPLY_PREPARE, 1) \
|
V(STRING_ADD_RIGHT, 1) \
|
||||||
|
V(APPLY_PREPARE, 1) \
|
||||||
V(STACK_OVERFLOW, 1)
|
V(STACK_OVERFLOW, 1)
|
||||||
|
|
||||||
class BuiltinFunctionTable;
|
class BuiltinFunctionTable;
|
||||||
|
@ -926,7 +926,7 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||||
if (property->IsCompileTimeValue()) continue;
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key()->AsLiteral();
|
||||||
switch (property->kind()) {
|
switch (property->kind()) {
|
||||||
case ObjectLiteral::Property::CONSTANT:
|
case ObjectLiteral::Property::CONSTANT:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -177,15 +177,16 @@ DEFINE_IMPLICATION(harmony, es_staging)
|
|||||||
DEFINE_IMPLICATION(es_staging, harmony)
|
DEFINE_IMPLICATION(es_staging, harmony)
|
||||||
|
|
||||||
// Features that are still work in progress (behind individual flags).
|
// Features that are still work in progress (behind individual flags).
|
||||||
#define HARMONY_INPROGRESS(V) \
|
#define HARMONY_INPROGRESS(V) \
|
||||||
V(harmony_modules, "harmony modules (implies block scoping)") \
|
V(harmony_modules, "harmony modules (implies block scoping)") \
|
||||||
V(harmony_arrays, "harmony array methods") \
|
V(harmony_arrays, "harmony array methods") \
|
||||||
V(harmony_array_includes, "harmony Array.prototype.includes") \
|
V(harmony_array_includes, "harmony Array.prototype.includes") \
|
||||||
V(harmony_regexps, "harmony regular expression extensions") \
|
V(harmony_regexps, "harmony regular expression extensions") \
|
||||||
V(harmony_arrow_functions, "harmony arrow functions") \
|
V(harmony_arrow_functions, "harmony arrow functions") \
|
||||||
V(harmony_proxies, "harmony proxies") \
|
V(harmony_proxies, "harmony proxies") \
|
||||||
V(harmony_sloppy, "harmony features in sloppy mode") \
|
V(harmony_sloppy, "harmony features in sloppy mode") \
|
||||||
V(harmony_unicode, "harmony unicode escapes")
|
V(harmony_unicode, "harmony unicode escapes") \
|
||||||
|
V(harmony_computed_property_names, "harmony computed property names")
|
||||||
|
|
||||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||||
#define HARMONY_STAGED(V) \
|
#define HARMONY_STAGED(V) \
|
||||||
|
@ -1211,6 +1211,13 @@ void FullCodeGenerator::EmitUnwindBeforeReturn() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property) {
|
||||||
|
VisitForStackValue(property->key());
|
||||||
|
__ InvokeBuiltin(Builtins::TO_NAME, CALL_FUNCTION);
|
||||||
|
__ Push(result_register());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
|
void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
|
||||||
Comment cmnt(masm_, "[ ReturnStatement");
|
Comment cmnt(masm_, "[ ReturnStatement");
|
||||||
SetStatementPosition(stmt);
|
SetStatementPosition(stmt);
|
||||||
|
@ -568,6 +568,9 @@ class FullCodeGenerator: public AstVisitor {
|
|||||||
// in the accumulator after installing all the properties.
|
// in the accumulator after installing all the properties.
|
||||||
void EmitClassDefineProperties(ClassLiteral* lit);
|
void EmitClassDefineProperties(ClassLiteral* lit);
|
||||||
|
|
||||||
|
// Pushes the property key as a Name on the stack.
|
||||||
|
void EmitPropertyKey(ObjectLiteralProperty* property);
|
||||||
|
|
||||||
// Apply the compound assignment operator. Expects the left operand on top
|
// Apply the compound assignment operator. Expects the left operand on top
|
||||||
// of the stack and the right one in the accumulator.
|
// of the stack and the right one in the accumulator.
|
||||||
void EmitBinaryOp(BinaryOperation* expr,
|
void EmitBinaryOp(BinaryOperation* expr,
|
||||||
|
@ -5565,6 +5565,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
DCHECK(!HasStackOverflow());
|
DCHECK(!HasStackOverflow());
|
||||||
DCHECK(current_block() != NULL);
|
DCHECK(current_block() != NULL);
|
||||||
DCHECK(current_block()->HasPredecessor());
|
DCHECK(current_block()->HasPredecessor());
|
||||||
|
|
||||||
expr->BuildConstantProperties(isolate());
|
expr->BuildConstantProperties(isolate());
|
||||||
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
|
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
|
||||||
HInstruction* literal;
|
HInstruction* literal;
|
||||||
@ -5620,9 +5621,10 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
|
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||||
|
if (property->is_computed_name()) return Bailout(kComputedPropertyName);
|
||||||
if (property->IsCompileTimeValue()) continue;
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key()->AsLiteral();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
|
|
||||||
switch (property->kind()) {
|
switch (property->kind()) {
|
||||||
@ -5648,7 +5650,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<Map> map = property->GetReceiverType();
|
Handle<Map> map = property->GetReceiverType();
|
||||||
Handle<String> name = property->key()->AsPropertyName();
|
Handle<String> name = key->AsPropertyName();
|
||||||
HInstruction* store;
|
HInstruction* store;
|
||||||
if (map.is_null()) {
|
if (map.is_null()) {
|
||||||
// If we don't know the monomorphic type, do a generic store.
|
// If we don't know the monomorphic type, do a generic store.
|
||||||
|
@ -1617,11 +1617,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
expr->CalculateEmitStore(zone());
|
expr->CalculateEmitStore(zone());
|
||||||
|
|
||||||
AccessorTable accessor_table(zone());
|
AccessorTable accessor_table(zone());
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
int property_index = 0;
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
if (property->is_computed_name()) break;
|
||||||
if (property->IsCompileTimeValue()) continue;
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key()->AsLiteral();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ push(eax); // Save result on the stack
|
__ push(eax); // Save result on the stack
|
||||||
@ -1701,6 +1703,65 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Object literals have two parts. The "static" part on the left contains no
|
||||||
|
// computed property names, and so we can compute its map ahead of time; see
|
||||||
|
// runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
|
||||||
|
// starts with the first computed property name, and continues with all
|
||||||
|
// properties to its right. All the code from above initializes the static
|
||||||
|
// component of the object literal, and arranges for the map of the result to
|
||||||
|
// reflect the static order in which the keys appear. For the dynamic
|
||||||
|
// properties, we compile them into a series of "SetOwnProperty" runtime
|
||||||
|
// calls. This will preserve insertion order.
|
||||||
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
|
||||||
|
Expression* value = property->value();
|
||||||
|
if (!result_saved) {
|
||||||
|
__ push(eax); // Save result on the stack
|
||||||
|
result_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__ push(Operand(esp, 0)); // Duplicate receiver.
|
||||||
|
|
||||||
|
if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
|
||||||
|
DCHECK(!property->is_computed_name());
|
||||||
|
VisitForStackValue(value);
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ CallRuntime(Runtime::kInternalSetPrototype, 2);
|
||||||
|
} else {
|
||||||
|
__ Drop(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EmitPropertyKey(property);
|
||||||
|
VisitForStackValue(value);
|
||||||
|
|
||||||
|
switch (property->kind()) {
|
||||||
|
case ObjectLiteral::Property::CONSTANT:
|
||||||
|
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
|
||||||
|
case ObjectLiteral::Property::COMPUTED:
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ push(Immediate(Smi::FromInt(NONE)));
|
||||||
|
__ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
|
||||||
|
} else {
|
||||||
|
__ Drop(3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::PROTOTYPE:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::GETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::SETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (expr->has_function()) {
|
if (expr->has_function()) {
|
||||||
DCHECK(result_saved);
|
DCHECK(result_saved);
|
||||||
__ push(Operand(esp, 0));
|
__ push(Operand(esp, 0));
|
||||||
@ -2394,16 +2455,14 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
|
|
||||||
for (int i = 0; i < lit->properties()->length(); i++) {
|
for (int i = 0; i < lit->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = lit->properties()->at(i);
|
ObjectLiteral::Property* property = lit->properties()->at(i);
|
||||||
Literal* key = property->key()->AsLiteral();
|
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
DCHECK(key != NULL);
|
|
||||||
|
|
||||||
if (property->is_static()) {
|
if (property->is_static()) {
|
||||||
__ push(Operand(esp, kPointerSize)); // constructor
|
__ push(Operand(esp, kPointerSize)); // constructor
|
||||||
} else {
|
} else {
|
||||||
__ push(Operand(esp, 0)); // prototype
|
__ push(Operand(esp, 0)); // prototype
|
||||||
}
|
}
|
||||||
VisitForStackValue(key);
|
EmitPropertyKey(property);
|
||||||
VisitForStackValue(value);
|
VisitForStackValue(value);
|
||||||
EmitSetHomeObjectIfNeeded(value, 2);
|
EmitSetHomeObjectIfNeeded(value, 2);
|
||||||
|
|
||||||
@ -2416,11 +2475,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::GETTER:
|
case ObjectLiteral::Property::GETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassGetter, 3);
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::SETTER:
|
case ObjectLiteral::Property::SETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassSetter, 3);
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -407,9 +407,8 @@ bool ParserTraits::IsConstructor(const AstRawString* identifier) const {
|
|||||||
bool ParserTraits::IsThisProperty(Expression* expression) {
|
bool ParserTraits::IsThisProperty(Expression* expression) {
|
||||||
DCHECK(expression != NULL);
|
DCHECK(expression != NULL);
|
||||||
Property* property = expression->AsProperty();
|
Property* property = expression->AsProperty();
|
||||||
return property != NULL &&
|
return property != NULL && property->obj()->IsVariableProxy() &&
|
||||||
property->obj()->AsVariableProxy() != NULL &&
|
property->obj()->AsVariableProxy()->is_this();
|
||||||
property->obj()->AsVariableProxy()->is_this();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -433,8 +432,7 @@ void ParserTraits::PushPropertyName(FuncNameInferrer* fni,
|
|||||||
void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
|
void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
|
||||||
Expression* right) {
|
Expression* right) {
|
||||||
DCHECK(left != NULL);
|
DCHECK(left != NULL);
|
||||||
if (left->AsProperty() != NULL &&
|
if (left->IsProperty() && right->IsFunctionLiteral()) {
|
||||||
right->AsFunctionLiteral() != NULL) {
|
|
||||||
right->AsFunctionLiteral()->set_pretenure();
|
right->AsFunctionLiteral()->set_pretenure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,6 +804,8 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
|
|||||||
set_allow_harmony_templates(FLAG_harmony_templates);
|
set_allow_harmony_templates(FLAG_harmony_templates);
|
||||||
set_allow_harmony_sloppy(FLAG_harmony_sloppy);
|
set_allow_harmony_sloppy(FLAG_harmony_sloppy);
|
||||||
set_allow_harmony_unicode(FLAG_harmony_unicode);
|
set_allow_harmony_unicode(FLAG_harmony_unicode);
|
||||||
|
set_allow_harmony_computed_property_names(
|
||||||
|
FLAG_harmony_computed_property_names);
|
||||||
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
||||||
++feature) {
|
++feature) {
|
||||||
use_counts_[feature] = 0;
|
use_counts_[feature] = 0;
|
||||||
@ -3956,6 +3956,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
|||||||
reusable_preparser_->set_allow_harmony_templates(allow_harmony_templates());
|
reusable_preparser_->set_allow_harmony_templates(allow_harmony_templates());
|
||||||
reusable_preparser_->set_allow_harmony_sloppy(allow_harmony_sloppy());
|
reusable_preparser_->set_allow_harmony_sloppy(allow_harmony_sloppy());
|
||||||
reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode());
|
reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode());
|
||||||
|
reusable_preparser_->set_allow_harmony_computed_property_names(
|
||||||
|
allow_harmony_computed_property_names());
|
||||||
}
|
}
|
||||||
PreParser::PreParseResult result =
|
PreParser::PreParseResult result =
|
||||||
reusable_preparser_->PreParseLazyFunction(strict_mode(),
|
reusable_preparser_->PreParseLazyFunction(strict_mode(),
|
||||||
@ -4015,8 +4017,11 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
|
|||||||
if (fni_ != NULL) fni_->Enter();
|
if (fni_ != NULL) fni_->Enter();
|
||||||
const bool in_class = true;
|
const bool in_class = true;
|
||||||
const bool is_static = false;
|
const bool is_static = false;
|
||||||
ObjectLiteral::Property* property = ParsePropertyDefinition(
|
bool is_computed_name = false; // Classes do not care about computed
|
||||||
NULL, in_class, is_static, &has_seen_constructor, CHECK_OK);
|
// property names here.
|
||||||
|
ObjectLiteral::Property* property =
|
||||||
|
ParsePropertyDefinition(NULL, in_class, is_static, &is_computed_name,
|
||||||
|
&has_seen_constructor, CHECK_OK);
|
||||||
|
|
||||||
if (has_seen_constructor && constructor == NULL) {
|
if (has_seen_constructor && constructor == NULL) {
|
||||||
constructor = GetPropertyValue(property);
|
constructor = GetPropertyValue(property);
|
||||||
|
@ -413,11 +413,6 @@ class ParserTraits {
|
|||||||
return string->AsArrayIndex(index);
|
return string->AsArrayIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsConstructorProperty(ObjectLiteral::Property* property) {
|
|
||||||
return property->key()->raw_value()->EqualsString(
|
|
||||||
ast_value_factory()->constructor_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
static Expression* GetPropertyValue(ObjectLiteral::Property* property) {
|
static Expression* GetPropertyValue(ObjectLiteral::Property* property) {
|
||||||
return property->value();
|
return property->value();
|
||||||
}
|
}
|
||||||
@ -427,7 +422,9 @@ class ParserTraits {
|
|||||||
static void PushLiteralName(FuncNameInferrer* fni, const AstRawString* id) {
|
static void PushLiteralName(FuncNameInferrer* fni, const AstRawString* id) {
|
||||||
fni->PushLiteralName(id);
|
fni->PushLiteralName(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushPropertyName(FuncNameInferrer* fni, Expression* expression);
|
void PushPropertyName(FuncNameInferrer* fni, Expression* expression);
|
||||||
|
|
||||||
static void InferFunctionName(FuncNameInferrer* fni,
|
static void InferFunctionName(FuncNameInferrer* fni,
|
||||||
FunctionLiteral* func_to_infer) {
|
FunctionLiteral* func_to_infer) {
|
||||||
fni->AddFunction(func_to_infer);
|
fni->AddFunction(func_to_infer);
|
||||||
|
@ -990,8 +990,10 @@ PreParserExpression PreParser::ParseClassLiteral(
|
|||||||
if (Check(Token::SEMICOLON)) continue;
|
if (Check(Token::SEMICOLON)) continue;
|
||||||
const bool in_class = true;
|
const bool in_class = true;
|
||||||
const bool is_static = false;
|
const bool is_static = false;
|
||||||
ParsePropertyDefinition(NULL, in_class, is_static, &has_seen_constructor,
|
bool is_computed_name = false; // Classes do not care about computed
|
||||||
CHECK_OK);
|
// property names here.
|
||||||
|
ParsePropertyDefinition(NULL, in_class, is_static, &is_computed_name,
|
||||||
|
&has_seen_constructor, CHECK_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expect(Token::RBRACE, CHECK_OK);
|
Expect(Token::RBRACE, CHECK_OK);
|
||||||
|
140
src/preparser.h
140
src/preparser.h
@ -87,6 +87,7 @@ class ParserBase : public Traits {
|
|||||||
allow_harmony_arrow_functions_(false),
|
allow_harmony_arrow_functions_(false),
|
||||||
allow_harmony_object_literals_(false),
|
allow_harmony_object_literals_(false),
|
||||||
allow_harmony_sloppy_(false),
|
allow_harmony_sloppy_(false),
|
||||||
|
allow_harmony_computed_property_names_(false),
|
||||||
zone_(zone) {}
|
zone_(zone) {}
|
||||||
|
|
||||||
// Getters that indicate whether certain syntactical constructs are
|
// Getters that indicate whether certain syntactical constructs are
|
||||||
@ -108,6 +109,9 @@ class ParserBase : public Traits {
|
|||||||
bool allow_harmony_templates() const { return scanner()->HarmonyTemplates(); }
|
bool allow_harmony_templates() const { return scanner()->HarmonyTemplates(); }
|
||||||
bool allow_harmony_sloppy() const { return allow_harmony_sloppy_; }
|
bool allow_harmony_sloppy() const { return allow_harmony_sloppy_; }
|
||||||
bool allow_harmony_unicode() const { return scanner()->HarmonyUnicode(); }
|
bool allow_harmony_unicode() const { return scanner()->HarmonyUnicode(); }
|
||||||
|
bool allow_harmony_computed_property_names() const {
|
||||||
|
return allow_harmony_computed_property_names_;
|
||||||
|
}
|
||||||
|
|
||||||
// Setters that determine whether certain syntactical constructs are
|
// Setters that determine whether certain syntactical constructs are
|
||||||
// allowed to be parsed by this instance of the parser.
|
// allowed to be parsed by this instance of the parser.
|
||||||
@ -140,6 +144,9 @@ class ParserBase : public Traits {
|
|||||||
void set_allow_harmony_unicode(bool allow) {
|
void set_allow_harmony_unicode(bool allow) {
|
||||||
scanner()->SetHarmonyUnicode(allow);
|
scanner()->SetHarmonyUnicode(allow);
|
||||||
}
|
}
|
||||||
|
void set_allow_harmony_computed_property_names(bool allow) {
|
||||||
|
allow_harmony_computed_property_names_ = allow;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum AllowEvalOrArgumentsAsIdentifier {
|
enum AllowEvalOrArgumentsAsIdentifier {
|
||||||
@ -499,11 +506,13 @@ class ParserBase : public Traits {
|
|||||||
ExpressionT ParsePrimaryExpression(bool* ok);
|
ExpressionT ParsePrimaryExpression(bool* ok);
|
||||||
ExpressionT ParseExpression(bool accept_IN, bool* ok);
|
ExpressionT ParseExpression(bool accept_IN, bool* ok);
|
||||||
ExpressionT ParseArrayLiteral(bool* ok);
|
ExpressionT ParseArrayLiteral(bool* ok);
|
||||||
IdentifierT ParsePropertyName(bool* is_get, bool* is_set, bool* is_static,
|
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
|
||||||
|
bool* is_static, bool* is_computed_name,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
ExpressionT ParseObjectLiteral(bool* ok);
|
ExpressionT ParseObjectLiteral(bool* ok);
|
||||||
ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker,
|
ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker,
|
||||||
bool in_class, bool is_static,
|
bool in_class, bool is_static,
|
||||||
|
bool* is_computed_name,
|
||||||
bool* has_seen_constructor,
|
bool* has_seen_constructor,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
typename Traits::Type::ExpressionList ParseArguments(bool* ok);
|
typename Traits::Type::ExpressionList ParseArguments(bool* ok);
|
||||||
@ -607,6 +616,7 @@ class ParserBase : public Traits {
|
|||||||
bool allow_harmony_arrow_functions_;
|
bool allow_harmony_arrow_functions_;
|
||||||
bool allow_harmony_object_literals_;
|
bool allow_harmony_object_literals_;
|
||||||
bool allow_harmony_sloppy_;
|
bool allow_harmony_sloppy_;
|
||||||
|
bool allow_harmony_computed_property_names_;
|
||||||
|
|
||||||
typename Traits::Type::Zone* zone_; // Only used by Parser.
|
typename Traits::Type::Zone* zone_; // Only used by Parser.
|
||||||
};
|
};
|
||||||
@ -1040,13 +1050,16 @@ class PreParserFactory {
|
|||||||
return PreParserExpression::Default();
|
return PreParserExpression::Default();
|
||||||
}
|
}
|
||||||
PreParserExpression NewObjectLiteralProperty(bool is_getter,
|
PreParserExpression NewObjectLiteralProperty(bool is_getter,
|
||||||
|
PreParserExpression key,
|
||||||
PreParserExpression value,
|
PreParserExpression value,
|
||||||
int pos, bool is_static) {
|
int pos, bool is_static,
|
||||||
|
bool is_computed_name) {
|
||||||
return PreParserExpression::Default();
|
return PreParserExpression::Default();
|
||||||
}
|
}
|
||||||
PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
|
PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
|
||||||
PreParserExpression value,
|
PreParserExpression value,
|
||||||
bool is_static) {
|
bool is_static,
|
||||||
|
bool is_computed_name) {
|
||||||
return PreParserExpression::Default();
|
return PreParserExpression::Default();
|
||||||
}
|
}
|
||||||
PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
|
PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
|
||||||
@ -1232,11 +1245,13 @@ class PreParserTraits {
|
|||||||
// PreParser should not use FuncNameInferrer.
|
// PreParser should not use FuncNameInferrer.
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PushPropertyName(FuncNameInferrer* fni,
|
static void PushPropertyName(FuncNameInferrer* fni,
|
||||||
PreParserExpression expression) {
|
PreParserExpression expression) {
|
||||||
// PreParser should not use FuncNameInferrer.
|
// PreParser should not use FuncNameInferrer.
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InferFunctionName(FuncNameInferrer* fni,
|
static void InferFunctionName(FuncNameInferrer* fni,
|
||||||
PreParserExpression expression) {
|
PreParserExpression expression) {
|
||||||
// PreParser should not use FuncNameInferrer.
|
// PreParser should not use FuncNameInferrer.
|
||||||
@ -1997,34 +2012,68 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
|||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName(
|
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
||||||
bool* is_get, bool* is_set, bool* is_static, bool* ok) {
|
IdentifierT* name, bool* is_get, bool* is_set, bool* is_static,
|
||||||
Token::Value next = peek();
|
bool* is_computed_name, bool* ok) {
|
||||||
switch (next) {
|
Token::Value token = peek();
|
||||||
|
int pos = peek_position();
|
||||||
|
|
||||||
|
// For non computed property names we normalize the name a bit:
|
||||||
|
//
|
||||||
|
// "12" -> 12
|
||||||
|
// 12.3 -> "12.3"
|
||||||
|
// 12.30 -> "12.3"
|
||||||
|
// identifier -> "identifier"
|
||||||
|
//
|
||||||
|
// This is important because we use the property name as a key in a hash
|
||||||
|
// table when we compute constant properties.
|
||||||
|
switch (token) {
|
||||||
case Token::STRING:
|
case Token::STRING:
|
||||||
Consume(Token::STRING);
|
Consume(Token::STRING);
|
||||||
return this->GetSymbol(scanner_);
|
*name = this->GetSymbol(scanner());
|
||||||
|
break;
|
||||||
|
|
||||||
case Token::NUMBER:
|
case Token::NUMBER:
|
||||||
Consume(Token::NUMBER);
|
Consume(Token::NUMBER);
|
||||||
return this->GetNumberAsSymbol(scanner_);
|
*name = this->GetNumberAsSymbol(scanner());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Token::LBRACK:
|
||||||
|
if (allow_harmony_computed_property_names_) {
|
||||||
|
*is_computed_name = true;
|
||||||
|
Consume(Token::LBRACK);
|
||||||
|
ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK);
|
||||||
|
Expect(Token::RBRACK, CHECK_OK);
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall through.
|
||||||
case Token::STATIC:
|
case Token::STATIC:
|
||||||
*is_static = true;
|
*is_static = true;
|
||||||
// Fall through.
|
|
||||||
|
// Fall through.
|
||||||
default:
|
default:
|
||||||
return ParseIdentifierNameOrGetOrSet(is_get, is_set, ok);
|
*name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
|
||||||
return this->EmptyIdentifier();
|
uint32_t index;
|
||||||
|
return this->IsArrayIndex(*name, &index)
|
||||||
|
? factory()->NewNumberLiteral(index, pos)
|
||||||
|
: factory()->NewStringLiteral(*name, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
typename ParserBase<Traits>::ObjectLiteralPropertyT
|
||||||
Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
|
ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
|
||||||
bool in_class, bool is_static,
|
bool in_class, bool is_static,
|
||||||
bool* has_seen_constructor, bool* ok) {
|
bool* is_computed_name,
|
||||||
|
bool* has_seen_constructor,
|
||||||
|
bool* ok) {
|
||||||
DCHECK(!in_class || is_static || has_seen_constructor != NULL);
|
DCHECK(!in_class || is_static || has_seen_constructor != NULL);
|
||||||
ExpressionT value = this->EmptyExpression();
|
ExpressionT value = this->EmptyExpression();
|
||||||
|
IdentifierT name = this->EmptyIdentifier();
|
||||||
bool is_get = false;
|
bool is_get = false;
|
||||||
bool is_set = false;
|
bool is_set = false;
|
||||||
bool name_is_static = false;
|
bool name_is_static = false;
|
||||||
@ -2032,15 +2081,17 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
|||||||
|
|
||||||
Token::Value name_token = peek();
|
Token::Value name_token = peek();
|
||||||
int next_pos = peek_position();
|
int next_pos = peek_position();
|
||||||
IdentifierT name =
|
ExpressionT name_expression = ParsePropertyName(
|
||||||
ParsePropertyName(&is_get, &is_set, &name_is_static,
|
&name, &is_get, &is_set, &name_is_static, is_computed_name,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
|
|
||||||
if (fni_ != NULL) this->PushLiteralName(fni_, name);
|
if (fni_ != NULL && !*is_computed_name) {
|
||||||
|
this->PushLiteralName(fni_, name);
|
||||||
|
}
|
||||||
|
|
||||||
if (!in_class && !is_generator && peek() == Token::COLON) {
|
if (!in_class && !is_generator && peek() == Token::COLON) {
|
||||||
// PropertyDefinition : PropertyName ':' AssignmentExpression
|
// PropertyDefinition : PropertyName ':' AssignmentExpression
|
||||||
if (checker != NULL) {
|
if (!*is_computed_name && checker != NULL) {
|
||||||
checker->CheckProperty(name_token, kValueProperty,
|
checker->CheckProperty(name_token, kValueProperty,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
}
|
}
|
||||||
@ -2078,7 +2129,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
|||||||
kind = FunctionKind::kNormalFunction;
|
kind = FunctionKind::kNormalFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checker != NULL) {
|
if (!*is_computed_name && checker != NULL) {
|
||||||
checker->CheckProperty(name_token, kValueProperty,
|
checker->CheckProperty(name_token, kValueProperty,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
}
|
}
|
||||||
@ -2092,14 +2143,18 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
|||||||
|
|
||||||
} else if (in_class && name_is_static && !is_static) {
|
} else if (in_class && name_is_static && !is_static) {
|
||||||
// static MethodDefinition
|
// static MethodDefinition
|
||||||
return ParsePropertyDefinition(checker, true, true, NULL, ok);
|
return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL,
|
||||||
|
ok);
|
||||||
|
|
||||||
} else if (is_get || is_set) {
|
} else if (is_get || is_set) {
|
||||||
// Accessor
|
// Accessor
|
||||||
|
name = this->EmptyIdentifier();
|
||||||
bool dont_care = false;
|
bool dont_care = false;
|
||||||
name_token = peek();
|
name_token = peek();
|
||||||
name = ParsePropertyName(&dont_care, &dont_care, &dont_care,
|
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
name_expression = ParsePropertyName(
|
||||||
|
&name, &dont_care, &dont_care, &dont_care, is_computed_name,
|
||||||
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
|
|
||||||
// Validate the property.
|
// Validate the property.
|
||||||
if (is_static && this->IsPrototype(name)) {
|
if (is_static && this->IsPrototype(name)) {
|
||||||
@ -2111,7 +2166,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
|||||||
*ok = false;
|
*ok = false;
|
||||||
return this->EmptyObjectLiteralProperty();
|
return this->EmptyObjectLiteralProperty();
|
||||||
}
|
}
|
||||||
if (checker != NULL) {
|
if (!*is_computed_name && checker != NULL) {
|
||||||
checker->CheckProperty(name_token,
|
checker->CheckProperty(name_token,
|
||||||
is_get ? kGetterProperty : kSetterProperty,
|
is_get ? kGetterProperty : kSetterProperty,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
@ -2124,8 +2179,17 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
|||||||
FunctionLiteral::ANONYMOUS_EXPRESSION,
|
FunctionLiteral::ANONYMOUS_EXPRESSION,
|
||||||
is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY,
|
is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY,
|
||||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||||
return factory()->NewObjectLiteralProperty(is_get, value, next_pos,
|
|
||||||
is_static);
|
// Make sure the name expression is a string since we need a Name for
|
||||||
|
// Runtime_DefineAccessorPropertyUnchecked and since we can determine this
|
||||||
|
// statically we can skip the extra runtime check.
|
||||||
|
if (!*is_computed_name) {
|
||||||
|
name_expression =
|
||||||
|
factory()->NewStringLiteral(name, name_expression->position());
|
||||||
|
}
|
||||||
|
|
||||||
|
return factory()->NewObjectLiteralProperty(
|
||||||
|
is_get, name_expression, value, next_pos, is_static, *is_computed_name);
|
||||||
|
|
||||||
} else if (!in_class && allow_harmony_object_literals_ &&
|
} else if (!in_class && allow_harmony_object_literals_ &&
|
||||||
Token::IsIdentifier(name_token, strict_mode(),
|
Token::IsIdentifier(name_token, strict_mode(),
|
||||||
@ -2139,12 +2203,8 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
|||||||
return this->EmptyObjectLiteralProperty();
|
return this->EmptyObjectLiteralProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t index;
|
return factory()->NewObjectLiteralProperty(name_expression, value, is_static,
|
||||||
LiteralT key = this->IsArrayIndex(name, &index)
|
*is_computed_name);
|
||||||
? factory()->NewNumberLiteral(index, next_pos)
|
|
||||||
: factory()->NewStringLiteral(name, next_pos);
|
|
||||||
|
|
||||||
return factory()->NewObjectLiteralProperty(key, value, is_static);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2159,6 +2219,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
|||||||
this->NewPropertyList(4, zone_);
|
this->NewPropertyList(4, zone_);
|
||||||
int number_of_boilerplate_properties = 0;
|
int number_of_boilerplate_properties = 0;
|
||||||
bool has_function = false;
|
bool has_function = false;
|
||||||
|
bool has_computed_names = false;
|
||||||
|
|
||||||
ObjectLiteralChecker checker(this, strict_mode());
|
ObjectLiteralChecker checker(this, strict_mode());
|
||||||
|
|
||||||
@ -2169,8 +2230,13 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
|||||||
|
|
||||||
const bool in_class = false;
|
const bool in_class = false;
|
||||||
const bool is_static = false;
|
const bool is_static = false;
|
||||||
|
bool is_computed_name = false;
|
||||||
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
|
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
|
||||||
&checker, in_class, is_static, NULL, CHECK_OK);
|
&checker, in_class, is_static, &is_computed_name, NULL, CHECK_OK);
|
||||||
|
|
||||||
|
if (is_computed_name) {
|
||||||
|
has_computed_names = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Mark top-level object literals that contain function literals and
|
// Mark top-level object literals that contain function literals and
|
||||||
// pretenure the literal so it can be added as a constant function
|
// pretenure the literal so it can be added as a constant function
|
||||||
@ -2179,7 +2245,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
|||||||
&has_function);
|
&has_function);
|
||||||
|
|
||||||
// Count CONSTANT or COMPUTED properties to maintain the enumeration order.
|
// Count CONSTANT or COMPUTED properties to maintain the enumeration order.
|
||||||
if (this->IsBoilerplateProperty(property)) {
|
if (!has_computed_names && this->IsBoilerplateProperty(property)) {
|
||||||
number_of_boilerplate_properties++;
|
number_of_boilerplate_properties++;
|
||||||
}
|
}
|
||||||
properties->Add(property, zone());
|
properties->Add(property, zone());
|
||||||
|
@ -468,6 +468,12 @@ function TO_STRING() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert the receiver to a string or symbol - forward to ToName.
|
||||||
|
function TO_NAME() {
|
||||||
|
return %ToName(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------
|
/* -------------------------------------
|
||||||
- - - C o n v e r s i o n s - - -
|
- - - C o n v e r s i o n s - - -
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
@ -153,18 +153,10 @@ RUNTIME_FUNCTION(Runtime_DefineClassMethod) {
|
|||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
DCHECK(args.length() == 3);
|
DCHECK(args.length() == 3);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
|
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
|
||||||
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
if (key->ToArrayIndex(&index)) {
|
|
||||||
RETURN_FAILURE_ON_EXCEPTION(
|
|
||||||
isolate, JSObject::SetOwnElement(object, index, function, STRICT));
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<Name> name;
|
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
|
||||||
Runtime::ToName(isolate, key));
|
|
||||||
if (name->AsArrayIndex(&index)) {
|
if (name->AsArrayIndex(&index)) {
|
||||||
RETURN_FAILURE_ON_EXCEPTION(
|
RETURN_FAILURE_ON_EXCEPTION(
|
||||||
isolate, JSObject::SetOwnElement(object, index, function, STRICT));
|
isolate, JSObject::SetOwnElement(object, index, function, STRICT));
|
||||||
@ -177,42 +169,6 @@ RUNTIME_FUNCTION(Runtime_DefineClassMethod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_DefineClassGetter) {
|
|
||||||
HandleScope scope(isolate);
|
|
||||||
DCHECK(args.length() == 3);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2);
|
|
||||||
|
|
||||||
Handle<Name> name;
|
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
|
||||||
Runtime::ToName(isolate, key));
|
|
||||||
RETURN_FAILURE_ON_EXCEPTION(
|
|
||||||
isolate,
|
|
||||||
JSObject::DefineAccessor(object, name, getter,
|
|
||||||
isolate->factory()->null_value(), NONE));
|
|
||||||
return isolate->heap()->undefined_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_DefineClassSetter) {
|
|
||||||
HandleScope scope(isolate);
|
|
||||||
DCHECK(args.length() == 3);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
|
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2);
|
|
||||||
|
|
||||||
Handle<Name> name;
|
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
|
|
||||||
Runtime::ToName(isolate, key));
|
|
||||||
RETURN_FAILURE_ON_EXCEPTION(
|
|
||||||
isolate,
|
|
||||||
JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
|
|
||||||
setter, NONE));
|
|
||||||
return isolate->heap()->undefined_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
|
RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) {
|
||||||
HandleScope shs(isolate);
|
HandleScope shs(isolate);
|
||||||
DCHECK(args.length() == 1);
|
DCHECK(args.length() == 1);
|
||||||
|
@ -1606,5 +1606,35 @@ RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
|
|||||||
if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
|
if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
|
||||||
return JSReceiver::cast(obj)->class_name();
|
return JSReceiver::cast(obj)->class_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
DCHECK(args.length() == 3);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2);
|
||||||
|
|
||||||
|
RETURN_FAILURE_ON_EXCEPTION(
|
||||||
|
isolate,
|
||||||
|
JSObject::DefineAccessor(object, name, getter,
|
||||||
|
isolate->factory()->null_value(), NONE));
|
||||||
|
return isolate->heap()->undefined_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
DCHECK(args.length() == 3);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2);
|
||||||
|
|
||||||
|
RETURN_FAILURE_ON_EXCEPTION(
|
||||||
|
isolate,
|
||||||
|
JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
|
||||||
|
setter, NONE));
|
||||||
|
return isolate->heap()->undefined_value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace v8::internal
|
} // namespace v8::internal
|
||||||
|
@ -187,8 +187,6 @@ namespace internal {
|
|||||||
F(HomeObjectSymbol, 0, 1) \
|
F(HomeObjectSymbol, 0, 1) \
|
||||||
F(DefineClass, 6, 1) \
|
F(DefineClass, 6, 1) \
|
||||||
F(DefineClassMethod, 3, 1) \
|
F(DefineClassMethod, 3, 1) \
|
||||||
F(DefineClassGetter, 3, 1) \
|
|
||||||
F(DefineClassSetter, 3, 1) \
|
|
||||||
F(ClassGetSourceCode, 1, 1) \
|
F(ClassGetSourceCode, 1, 1) \
|
||||||
F(ThrowNonMethodError, 0, 1) \
|
F(ThrowNonMethodError, 0, 1) \
|
||||||
F(ThrowUnsupportedSuperError, 0, 1) \
|
F(ThrowUnsupportedSuperError, 0, 1) \
|
||||||
@ -262,6 +260,8 @@ namespace internal {
|
|||||||
F(DefineDataPropertyUnchecked, 4, 1) \
|
F(DefineDataPropertyUnchecked, 4, 1) \
|
||||||
F(DefineAccessorPropertyUnchecked, 5, 1) \
|
F(DefineAccessorPropertyUnchecked, 5, 1) \
|
||||||
F(GetDataProperty, 2, 1) \
|
F(GetDataProperty, 2, 1) \
|
||||||
|
F(DefineGetterPropertyUnchecked, 3, 1) \
|
||||||
|
F(DefineSetterPropertyUnchecked, 3, 1) \
|
||||||
\
|
\
|
||||||
/* Arrays */ \
|
/* Arrays */ \
|
||||||
F(RemoveArrayHoles, 2, 1) \
|
F(RemoveArrayHoles, 2, 1) \
|
||||||
|
@ -408,7 +408,9 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
||||||
!CompileTimeValue::IsCompileTimeValue(prop->value())) ||
|
!CompileTimeValue::IsCompileTimeValue(prop->value())) ||
|
||||||
prop->kind() == ObjectLiteral::Property::COMPUTED) {
|
prop->kind() == ObjectLiteral::Property::COMPUTED) {
|
||||||
if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) {
|
if (!prop->is_computed_name() &&
|
||||||
|
prop->key()->AsLiteral()->value()->IsInternalizedString() &&
|
||||||
|
prop->emit_store()) {
|
||||||
prop->RecordTypeFeedback(oracle());
|
prop->RecordTypeFeedback(oracle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1651,11 +1651,13 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
expr->CalculateEmitStore(zone());
|
expr->CalculateEmitStore(zone());
|
||||||
|
|
||||||
AccessorTable accessor_table(zone());
|
AccessorTable accessor_table(zone());
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
int property_index = 0;
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
if (property->is_computed_name()) break;
|
||||||
if (property->IsCompileTimeValue()) continue;
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key()->AsLiteral();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ Push(rax); // Save result on the stack
|
__ Push(rax); // Save result on the stack
|
||||||
@ -1735,6 +1737,65 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
__ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Object literals have two parts. The "static" part on the left contains no
|
||||||
|
// computed property names, and so we can compute its map ahead of time; see
|
||||||
|
// runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
|
||||||
|
// starts with the first computed property name, and continues with all
|
||||||
|
// properties to its right. All the code from above initializes the static
|
||||||
|
// component of the object literal, and arranges for the map of the result to
|
||||||
|
// reflect the static order in which the keys appear. For the dynamic
|
||||||
|
// properties, we compile them into a series of "SetOwnProperty" runtime
|
||||||
|
// calls. This will preserve insertion order.
|
||||||
|
for (; property_index < expr->properties()->length(); property_index++) {
|
||||||
|
ObjectLiteral::Property* property = expr->properties()->at(property_index);
|
||||||
|
|
||||||
|
Expression* value = property->value();
|
||||||
|
if (!result_saved) {
|
||||||
|
__ Push(rax); // Save result on the stack
|
||||||
|
result_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__ Push(Operand(rsp, 0)); // Duplicate receiver.
|
||||||
|
|
||||||
|
if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
|
||||||
|
DCHECK(!property->is_computed_name());
|
||||||
|
VisitForStackValue(value);
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ CallRuntime(Runtime::kInternalSetPrototype, 2);
|
||||||
|
} else {
|
||||||
|
__ Drop(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EmitPropertyKey(property);
|
||||||
|
VisitForStackValue(value);
|
||||||
|
|
||||||
|
switch (property->kind()) {
|
||||||
|
case ObjectLiteral::Property::CONSTANT:
|
||||||
|
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
|
||||||
|
case ObjectLiteral::Property::COMPUTED:
|
||||||
|
if (property->emit_store()) {
|
||||||
|
__ Push(Smi::FromInt(NONE));
|
||||||
|
__ CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
|
||||||
|
} else {
|
||||||
|
__ Drop(3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::PROTOTYPE:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::GETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectLiteral::Property::SETTER:
|
||||||
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (expr->has_function()) {
|
if (expr->has_function()) {
|
||||||
DCHECK(result_saved);
|
DCHECK(result_saved);
|
||||||
__ Push(Operand(rsp, 0));
|
__ Push(Operand(rsp, 0));
|
||||||
@ -2393,16 +2454,14 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
|
|
||||||
for (int i = 0; i < lit->properties()->length(); i++) {
|
for (int i = 0; i < lit->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = lit->properties()->at(i);
|
ObjectLiteral::Property* property = lit->properties()->at(i);
|
||||||
Literal* key = property->key()->AsLiteral();
|
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
DCHECK(key != NULL);
|
|
||||||
|
|
||||||
if (property->is_static()) {
|
if (property->is_static()) {
|
||||||
__ Push(Operand(rsp, kPointerSize)); // constructor
|
__ Push(Operand(rsp, kPointerSize)); // constructor
|
||||||
} else {
|
} else {
|
||||||
__ Push(Operand(rsp, 0)); // prototype
|
__ Push(Operand(rsp, 0)); // prototype
|
||||||
}
|
}
|
||||||
VisitForStackValue(key);
|
EmitPropertyKey(property);
|
||||||
VisitForStackValue(value);
|
VisitForStackValue(value);
|
||||||
EmitSetHomeObjectIfNeeded(value, 2);
|
EmitSetHomeObjectIfNeeded(value, 2);
|
||||||
|
|
||||||
@ -2415,11 +2474,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::GETTER:
|
case ObjectLiteral::Property::GETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassGetter, 3);
|
__ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectLiteral::Property::SETTER:
|
case ObjectLiteral::Property::SETTER:
|
||||||
__ CallRuntime(Runtime::kDefineClassSetter, 3);
|
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1358,7 +1358,8 @@ enum ParserFlag {
|
|||||||
kAllowHarmonyObjectLiterals,
|
kAllowHarmonyObjectLiterals,
|
||||||
kAllowHarmonyTemplates,
|
kAllowHarmonyTemplates,
|
||||||
kAllowHarmonySloppy,
|
kAllowHarmonySloppy,
|
||||||
kAllowHarmonyUnicode
|
kAllowHarmonyUnicode,
|
||||||
|
kAllowHarmonyComputedPropertyNames
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1385,6 +1386,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
|
|||||||
parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
|
parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
|
||||||
parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
|
parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
|
||||||
parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
|
parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
|
||||||
|
parser->set_allow_harmony_computed_property_names(
|
||||||
|
flags.Contains(kAllowHarmonyComputedPropertyNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4582,3 +4585,61 @@ TEST(LexicalScopingSloppyMode) {
|
|||||||
always_true_flags, arraysize(always_true_flags),
|
always_true_flags, arraysize(always_true_flags),
|
||||||
always_false_flags, arraysize(always_false_flags));
|
always_false_flags, arraysize(always_false_flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ComputedPropertyName) {
|
||||||
|
const char* context_data[][2] = {{"({[", "]: 1});"},
|
||||||
|
{"({get [", "]() {}});"},
|
||||||
|
{"({set [", "](_) {}});"},
|
||||||
|
{"({[", "]() {}});"},
|
||||||
|
{"({*[", "]() {}});"},
|
||||||
|
{"(class {get [", "]() {}});"},
|
||||||
|
{"(class {set [", "](_) {}});"},
|
||||||
|
{"(class {[", "]() {}});"},
|
||||||
|
{"(class {*[", "]() {}});"},
|
||||||
|
{NULL, NULL}};
|
||||||
|
const char* error_data[] = {
|
||||||
|
"1, 2",
|
||||||
|
"var name",
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyComputedPropertyNames,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy,
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, error_data, kError, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
|
||||||
|
const char* name_data[] = {
|
||||||
|
"1",
|
||||||
|
"1 + 2",
|
||||||
|
"'name'",
|
||||||
|
"\"name\"",
|
||||||
|
"[]",
|
||||||
|
"{}",
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ComputedPropertyNameShorthandError) {
|
||||||
|
const char* context_data[][2] = {{"({", "});"},
|
||||||
|
{NULL, NULL}};
|
||||||
|
const char* error_data[] = {
|
||||||
|
"a: 1, [2]",
|
||||||
|
"[1], a: 1",
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
static const ParserFlag always_flags[] = {
|
||||||
|
kAllowHarmonyClasses,
|
||||||
|
kAllowHarmonyComputedPropertyNames,
|
||||||
|
kAllowHarmonyObjectLiterals,
|
||||||
|
kAllowHarmonySloppy,
|
||||||
|
};
|
||||||
|
RunParserSyncTest(context_data, error_data, kError, NULL, 0,
|
||||||
|
always_flags, arraysize(always_flags));
|
||||||
|
}
|
||||||
|
367
test/mjsunit/harmony/computed-property-names-classes.js
Normal file
367
test/mjsunit/harmony/computed-property-names-classes.js
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Flags: --harmony-computed-property-names --harmony-classes
|
||||||
|
|
||||||
|
|
||||||
|
function ID(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
(function TestClassMethodString() {
|
||||||
|
class C {
|
||||||
|
a() { return 'A'}
|
||||||
|
['b']() { return 'B'; }
|
||||||
|
c() { return 'C'; }
|
||||||
|
[ID('d')]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals('A', new C().a());
|
||||||
|
assertEquals('B', new C().b());
|
||||||
|
assertEquals('C', new C().c());
|
||||||
|
assertEquals('D', new C().d());
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(C.prototype));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestClassMethodNumber() {
|
||||||
|
class C {
|
||||||
|
a() { return 'A'; }
|
||||||
|
[1]() { return 'B'; }
|
||||||
|
c() { return 'C'; }
|
||||||
|
[ID(2)]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals('A', new C().a());
|
||||||
|
assertEquals('B', new C()[1]());
|
||||||
|
assertEquals('C', new C().c());
|
||||||
|
assertEquals('D', new C()[2]());
|
||||||
|
// Array indexes first.
|
||||||
|
assertArrayEquals(['1', '2', 'a', 'c'], Object.keys(C.prototype));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestClassMethodSymbol() {
|
||||||
|
var sym1 = Symbol();
|
||||||
|
var sym2 = Symbol();
|
||||||
|
class C {
|
||||||
|
a() { return 'A'; }
|
||||||
|
[sym1]() { return 'B'; }
|
||||||
|
c() { return 'C'; }
|
||||||
|
[ID(sym2)]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals('A', new C().a());
|
||||||
|
assertEquals('B', new C()[sym1]());
|
||||||
|
assertEquals('C', new C().c());
|
||||||
|
assertEquals('D', new C()[sym2]());
|
||||||
|
assertArrayEquals(['a', 'c'], Object.keys(C.prototype));
|
||||||
|
assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C.prototype));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function TestStaticClassMethodString() {
|
||||||
|
class C {
|
||||||
|
static a() { return 'A'}
|
||||||
|
static ['b']() { return 'B'; }
|
||||||
|
static c() { return 'C'; }
|
||||||
|
static ['d']() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals('A', C.a());
|
||||||
|
assertEquals('B', C.b());
|
||||||
|
assertEquals('C', C.c());
|
||||||
|
assertEquals('D', C.d());
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(C));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestStaticClassMethodNumber() {
|
||||||
|
class C {
|
||||||
|
static a() { return 'A'; }
|
||||||
|
static [1]() { return 'B'; }
|
||||||
|
static c() { return 'C'; }
|
||||||
|
static [2]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals('A', C.a());
|
||||||
|
assertEquals('B', C[1]());
|
||||||
|
assertEquals('C', C.c());
|
||||||
|
assertEquals('D', C[2]());
|
||||||
|
// Array indexes first.
|
||||||
|
assertArrayEquals(['1', '2', 'a', 'c'], Object.keys(C));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestStaticClassMethodSymbol() {
|
||||||
|
var sym1 = Symbol();
|
||||||
|
var sym2 = Symbol();
|
||||||
|
class C {
|
||||||
|
static a() { return 'A'; }
|
||||||
|
static [sym1]() { return 'B'; }
|
||||||
|
static c() { return 'C'; }
|
||||||
|
static [sym2]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals('A', C.a());
|
||||||
|
assertEquals('B', C[sym1]());
|
||||||
|
assertEquals('C', C.c());
|
||||||
|
assertEquals('D', C[sym2]());
|
||||||
|
assertArrayEquals(['a', 'c'], Object.keys(C));
|
||||||
|
assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(C));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function assertIteratorResult(value, done, result) {
|
||||||
|
assertEquals({ value: value, done: done}, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
(function TestGeneratorComputedName() {
|
||||||
|
class C {
|
||||||
|
*['a']() {
|
||||||
|
yield 1;
|
||||||
|
yield 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var iter = new C().a();
|
||||||
|
assertIteratorResult(1, false, iter.next());
|
||||||
|
assertIteratorResult(2, false, iter.next());
|
||||||
|
assertIteratorResult(undefined, true, iter.next());
|
||||||
|
assertArrayEquals(['a'], Object.keys(C.prototype));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestToNameSideEffects() {
|
||||||
|
var counter = 0;
|
||||||
|
var key1 = {
|
||||||
|
toString: function() {
|
||||||
|
assertEquals(0, counter++);
|
||||||
|
return 'b';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var key2 = {
|
||||||
|
toString: function() {
|
||||||
|
assertEquals(1, counter++);
|
||||||
|
return 'd';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class C {
|
||||||
|
a() { return 'A'; }
|
||||||
|
[key1]() { return 'B'; }
|
||||||
|
c() { return 'C'; }
|
||||||
|
[key2]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals(2, counter);
|
||||||
|
assertEquals('A', new C().a());
|
||||||
|
assertEquals('B', new C().b());
|
||||||
|
assertEquals('C', new C().c());
|
||||||
|
assertEquals('D', new C().d());
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(C.prototype));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestToNameSideEffectsNumbers() {
|
||||||
|
var counter = 0;
|
||||||
|
var key1 = {
|
||||||
|
valueOf: function() {
|
||||||
|
assertEquals(0, counter++);
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
toString: null
|
||||||
|
};
|
||||||
|
var key2 = {
|
||||||
|
valueOf: function() {
|
||||||
|
assertEquals(1, counter++);
|
||||||
|
return 2;
|
||||||
|
},
|
||||||
|
toString: null
|
||||||
|
};
|
||||||
|
|
||||||
|
class C {
|
||||||
|
a() { return 'A'; }
|
||||||
|
[key1]() { return 'B'; }
|
||||||
|
c() { return 'C'; }
|
||||||
|
[key2]() { return 'D'; }
|
||||||
|
}
|
||||||
|
assertEquals(2, counter);
|
||||||
|
assertEquals('A', new C().a());
|
||||||
|
assertEquals('B', new C()[1]());
|
||||||
|
assertEquals('C', new C().c());
|
||||||
|
assertEquals('D', new C()[2]());
|
||||||
|
// Array indexes first.
|
||||||
|
assertArrayEquals(['1', '2', 'a', 'c'], Object.keys(C.prototype));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestGetter() {
|
||||||
|
class C {
|
||||||
|
get ['a']() {
|
||||||
|
return 'A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals('A', new C().a);
|
||||||
|
|
||||||
|
class C2 {
|
||||||
|
get b() {
|
||||||
|
assertUnreachable();
|
||||||
|
}
|
||||||
|
get ['b']() {
|
||||||
|
return 'B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals('B', new C2().b);
|
||||||
|
|
||||||
|
class C3 {
|
||||||
|
get c() {
|
||||||
|
assertUnreachable();
|
||||||
|
}
|
||||||
|
get ['c']() {
|
||||||
|
assertUnreachable();
|
||||||
|
}
|
||||||
|
get ['c']() {
|
||||||
|
return 'C';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals('C', new C3().c);
|
||||||
|
|
||||||
|
class C4 {
|
||||||
|
get ['d']() {
|
||||||
|
assertUnreachable();
|
||||||
|
}
|
||||||
|
get d() {
|
||||||
|
return 'D';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals('D', new C4().d);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestSetter() {
|
||||||
|
var calls = 0;
|
||||||
|
class C {
|
||||||
|
set ['a'](_) {
|
||||||
|
calls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new C().a = 'A';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
calls = 0;
|
||||||
|
class C2 {
|
||||||
|
set b(_) {
|
||||||
|
assertUnreachable();
|
||||||
|
}
|
||||||
|
set ['b'](_) {
|
||||||
|
calls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new C2().b = 'B';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
calls = 0;
|
||||||
|
class C3 {
|
||||||
|
set c(_) {
|
||||||
|
assertUnreachable()
|
||||||
|
}
|
||||||
|
set ['c'](_) {
|
||||||
|
assertUnreachable()
|
||||||
|
}
|
||||||
|
set ['c'](_) {
|
||||||
|
calls++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new C3().c = 'C';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
calls = 0;
|
||||||
|
class C4 {
|
||||||
|
set ['d'](_) {
|
||||||
|
assertUnreachable()
|
||||||
|
}
|
||||||
|
set d(_) {
|
||||||
|
calls++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new C4().d = 'D';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestPrototype() {
|
||||||
|
// Normally a static prototype property is not allowed.
|
||||||
|
class C {
|
||||||
|
static ['prototype']() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(1, C.prototype());
|
||||||
|
|
||||||
|
class C2 {
|
||||||
|
static get ['prototype']() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(2, C2.prototype);
|
||||||
|
|
||||||
|
var calls = 0;
|
||||||
|
class C3 {
|
||||||
|
static set ['prototype'](x) {
|
||||||
|
assertEquals(3, x);
|
||||||
|
calls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
C3.prototype = 3;
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
class C4 {
|
||||||
|
static *['prototype']() {
|
||||||
|
yield 1;
|
||||||
|
yield 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var iter = C4.prototype();
|
||||||
|
assertIteratorResult(1, false, iter.next());
|
||||||
|
assertIteratorResult(2, false, iter.next());
|
||||||
|
assertIteratorResult(undefined, true, iter.next());
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestConstructor() {
|
||||||
|
// Normally a constructor property is not allowed.
|
||||||
|
class C {
|
||||||
|
['constructor']() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(C !== C.prototype.constructor);
|
||||||
|
assertEquals(1, new C().constructor());
|
||||||
|
|
||||||
|
class C2 {
|
||||||
|
get ['constructor']() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(2, new C2().constructor);
|
||||||
|
|
||||||
|
var calls = 0;
|
||||||
|
class C3 {
|
||||||
|
set ['constructor'](x) {
|
||||||
|
assertEquals(3, x);
|
||||||
|
calls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new C3().constructor = 3;
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
class C4 {
|
||||||
|
*['constructor']() {
|
||||||
|
yield 1;
|
||||||
|
yield 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var iter = new C4().constructor();
|
||||||
|
assertIteratorResult(1, false, iter.next());
|
||||||
|
assertIteratorResult(2, false, iter.next());
|
||||||
|
assertIteratorResult(undefined, true, iter.next());
|
||||||
|
})();
|
@ -0,0 +1,121 @@
|
|||||||
|
// Copyright 2014 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: --harmony-computed-property-names --harmony-object-literals
|
||||||
|
|
||||||
|
|
||||||
|
function ID(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
(function TestMethodComputedNameString() {
|
||||||
|
var object = {
|
||||||
|
a() { return 'A'},
|
||||||
|
['b']() { return 'B'; },
|
||||||
|
c() { return 'C'; },
|
||||||
|
[ID('d')]() { return 'D'; },
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a());
|
||||||
|
assertEquals('B', object.b());
|
||||||
|
assertEquals('C', object.c());
|
||||||
|
assertEquals('D', object.d());
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestMethodComputedNameNumber() {
|
||||||
|
var object = {
|
||||||
|
a() { return 'A'; },
|
||||||
|
[1]() { return 'B'; },
|
||||||
|
c() { return 'C'; },
|
||||||
|
[ID(2)]() { return 'D'; },
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a());
|
||||||
|
assertEquals('B', object[1]());
|
||||||
|
assertEquals('C', object.c());
|
||||||
|
assertEquals('D', object[2]());
|
||||||
|
// Array indexes first.
|
||||||
|
assertArrayEquals(['1', '2', 'a', 'c'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestMethodComputedNameSymbol() {
|
||||||
|
var sym1 = Symbol();
|
||||||
|
var sym2 = Symbol();
|
||||||
|
var object = {
|
||||||
|
a() { return 'A'; },
|
||||||
|
[sym1]() { return 'B'; },
|
||||||
|
c() { return 'C'; },
|
||||||
|
[ID(sym2)]() { return 'D'; },
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a());
|
||||||
|
assertEquals('B', object[sym1]());
|
||||||
|
assertEquals('C', object.c());
|
||||||
|
assertEquals('D', object[sym2]());
|
||||||
|
assertArrayEquals(['a', 'c'], Object.keys(object));
|
||||||
|
assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
function assertIteratorResult(value, done, result) {
|
||||||
|
assertEquals({ value: value, done: done}, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
(function TestGeneratorComputedName() {
|
||||||
|
var object = {
|
||||||
|
*['a']() {
|
||||||
|
yield 1;
|
||||||
|
yield 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var iter = object.a();
|
||||||
|
assertIteratorResult(1, false, iter.next());
|
||||||
|
assertIteratorResult(2, false, iter.next());
|
||||||
|
assertIteratorResult(undefined, true, iter.next());
|
||||||
|
assertArrayEquals(['a'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestToNameSideEffects() {
|
||||||
|
var counter = 0;
|
||||||
|
var key1 = {
|
||||||
|
toString: function() {
|
||||||
|
assertEquals(0, counter++);
|
||||||
|
return 'b';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var key2 = {
|
||||||
|
toString: function() {
|
||||||
|
assertEquals(1, counter++);
|
||||||
|
return 'd';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var object = {
|
||||||
|
a() { return 'A'; },
|
||||||
|
[key1]() { return 'B'; },
|
||||||
|
c() { return 'C'; },
|
||||||
|
[key2]() { return 'D'; },
|
||||||
|
};
|
||||||
|
assertEquals(2, counter);
|
||||||
|
assertEquals('A', object.a());
|
||||||
|
assertEquals('B', object.b());
|
||||||
|
assertEquals('C', object.c());
|
||||||
|
assertEquals('D', object.d());
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestDuplicateKeys() {
|
||||||
|
'use strict';
|
||||||
|
// ES5 does not allow duplicate keys.
|
||||||
|
// ES6 does but we haven't changed our code yet.
|
||||||
|
|
||||||
|
var object = {
|
||||||
|
a() { return 1; },
|
||||||
|
['a']() { return 2; },
|
||||||
|
};
|
||||||
|
assertEquals(2, object.a());
|
||||||
|
})();
|
270
test/mjsunit/harmony/computed-property-names.js
Normal file
270
test/mjsunit/harmony/computed-property-names.js
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
// Copyright 2014 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: --harmony-computed-property-names
|
||||||
|
|
||||||
|
|
||||||
|
function ID(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function TestBasicsString() {
|
||||||
|
var object = {
|
||||||
|
a: 'A',
|
||||||
|
['b']: 'B',
|
||||||
|
c: 'C',
|
||||||
|
[ID('d')]: 'D',
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a);
|
||||||
|
assertEquals('B', object.b);
|
||||||
|
assertEquals('C', object.c);
|
||||||
|
assertEquals('D', object.d);
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestBasicsNumber() {
|
||||||
|
var object = {
|
||||||
|
a: 'A',
|
||||||
|
[1]: 'B',
|
||||||
|
c: 'C',
|
||||||
|
[ID(2)]: 'D',
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a);
|
||||||
|
assertEquals('B', object[1]);
|
||||||
|
assertEquals('C', object.c);
|
||||||
|
assertEquals('D', object[2]);
|
||||||
|
// Array indexes first.
|
||||||
|
assertArrayEquals(['1', '2', 'a', 'c'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestBasicsSymbol() {
|
||||||
|
var sym1 = Symbol();
|
||||||
|
var sym2 = Symbol();
|
||||||
|
var object = {
|
||||||
|
a: 'A',
|
||||||
|
[sym1]: 'B',
|
||||||
|
c: 'C',
|
||||||
|
[ID(sym2)]: 'D',
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a);
|
||||||
|
assertEquals('B', object[sym1]);
|
||||||
|
assertEquals('C', object.c);
|
||||||
|
assertEquals('D', object[sym2]);
|
||||||
|
assertArrayEquals(['a', 'c'], Object.keys(object));
|
||||||
|
assertArrayEquals([sym1, sym2], Object.getOwnPropertySymbols(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestToNameSideEffects() {
|
||||||
|
var counter = 0;
|
||||||
|
var key1 = {
|
||||||
|
toString: function() {
|
||||||
|
assertEquals(0, counter++);
|
||||||
|
return 'b';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var key2 = {
|
||||||
|
toString: function() {
|
||||||
|
assertEquals(1, counter++);
|
||||||
|
return 'd';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var object = {
|
||||||
|
a: 'A',
|
||||||
|
[key1]: 'B',
|
||||||
|
c: 'C',
|
||||||
|
[key2]: 'D',
|
||||||
|
};
|
||||||
|
assertEquals(2, counter);
|
||||||
|
assertEquals('A', object.a);
|
||||||
|
assertEquals('B', object.b);
|
||||||
|
assertEquals('C', object.c);
|
||||||
|
assertEquals('D', object.d);
|
||||||
|
assertArrayEquals(['a', 'b', 'c', 'd'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestToNameSideEffectsNumbers() {
|
||||||
|
var counter = 0;
|
||||||
|
var key1 = {
|
||||||
|
valueOf: function() {
|
||||||
|
assertEquals(0, counter++);
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
toString: null
|
||||||
|
};
|
||||||
|
var key2 = {
|
||||||
|
valueOf: function() {
|
||||||
|
assertEquals(1, counter++);
|
||||||
|
return 2;
|
||||||
|
},
|
||||||
|
toString: null
|
||||||
|
};
|
||||||
|
|
||||||
|
var object = {
|
||||||
|
a: 'A',
|
||||||
|
[key1]: 'B',
|
||||||
|
c: 'C',
|
||||||
|
[key2]: 'D',
|
||||||
|
};
|
||||||
|
assertEquals(2, counter);
|
||||||
|
assertEquals('A', object.a);
|
||||||
|
assertEquals('B', object[1]);
|
||||||
|
assertEquals('C', object.c);
|
||||||
|
assertEquals('D', object[2]);
|
||||||
|
// Array indexes first.
|
||||||
|
assertArrayEquals(['1', '2', 'a', 'c'], Object.keys(object));
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestDoubleName() {
|
||||||
|
var object = {
|
||||||
|
[1.2]: 'A',
|
||||||
|
[1e55]: 'B',
|
||||||
|
[0.000001]: 'C',
|
||||||
|
[-0]: 'D',
|
||||||
|
[Infinity]: 'E',
|
||||||
|
[-Infinity]: 'F',
|
||||||
|
[NaN]: 'G',
|
||||||
|
};
|
||||||
|
assertEquals('A', object['1.2']);
|
||||||
|
assertEquals('B', object['1e+55']);
|
||||||
|
assertEquals('C', object['0.000001']);
|
||||||
|
assertEquals('D', object[0]);
|
||||||
|
assertEquals('E', object[Infinity]);
|
||||||
|
assertEquals('F', object[-Infinity]);
|
||||||
|
assertEquals('G', object[NaN]);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestGetter() {
|
||||||
|
var object = {
|
||||||
|
get ['a']() {
|
||||||
|
return 'A';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assertEquals('A', object.a);
|
||||||
|
|
||||||
|
object = {
|
||||||
|
get b() {
|
||||||
|
assertUnreachable();
|
||||||
|
},
|
||||||
|
get ['b']() {
|
||||||
|
return 'B';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assertEquals('B', object.b);
|
||||||
|
|
||||||
|
object = {
|
||||||
|
get c() {
|
||||||
|
assertUnreachable();
|
||||||
|
},
|
||||||
|
get ['c']() {
|
||||||
|
assertUnreachable();
|
||||||
|
},
|
||||||
|
get ['c']() {
|
||||||
|
return 'C';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assertEquals('C', object.c);
|
||||||
|
|
||||||
|
object = {
|
||||||
|
get ['d']() {
|
||||||
|
assertUnreachable();
|
||||||
|
},
|
||||||
|
get d() {
|
||||||
|
return 'D';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assertEquals('D', object.d);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestSetter() {
|
||||||
|
var calls = 0;
|
||||||
|
var object = {
|
||||||
|
set ['a'](_) {
|
||||||
|
calls++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.a = 'A';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
calls = 0;
|
||||||
|
object = {
|
||||||
|
set b(_) {
|
||||||
|
assertUnreachable();
|
||||||
|
},
|
||||||
|
set ['b'](_) {
|
||||||
|
calls++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.b = 'B';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
calls = 0;
|
||||||
|
object = {
|
||||||
|
set c(_) {
|
||||||
|
assertUnreachable()
|
||||||
|
},
|
||||||
|
set ['c'](_) {
|
||||||
|
assertUnreachable()
|
||||||
|
},
|
||||||
|
set ['c'](_) {
|
||||||
|
calls++
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.c = 'C';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
|
||||||
|
calls = 0;
|
||||||
|
object = {
|
||||||
|
set ['d'](_) {
|
||||||
|
assertUnreachable()
|
||||||
|
},
|
||||||
|
set d(_) {
|
||||||
|
calls++
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object.d = 'D';
|
||||||
|
assertEquals(1, calls);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestDuplicateKeys() {
|
||||||
|
'use strict';
|
||||||
|
// ES5 does not allow duplicate keys.
|
||||||
|
// ES6 does but we haven't changed our code yet.
|
||||||
|
|
||||||
|
var object = {
|
||||||
|
a: 1,
|
||||||
|
['a']: 2,
|
||||||
|
};
|
||||||
|
assertEquals(2, object.a);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function TestProto() {
|
||||||
|
var proto = {};
|
||||||
|
var object = {
|
||||||
|
__proto__: proto
|
||||||
|
};
|
||||||
|
assertEquals(proto, Object.getPrototypeOf(object));
|
||||||
|
|
||||||
|
object = {
|
||||||
|
'__proto__': proto
|
||||||
|
};
|
||||||
|
assertEquals(proto, Object.getPrototypeOf(object));
|
||||||
|
|
||||||
|
var object = {
|
||||||
|
['__proto__']: proto
|
||||||
|
};
|
||||||
|
assertEquals(Object.prototype, Object.getPrototypeOf(object));
|
||||||
|
assertEquals(proto, object.__proto__);
|
||||||
|
assertTrue(object.hasOwnProperty('__proto__'));
|
||||||
|
})();
|
@ -512,6 +512,9 @@
|
|||||||
|
|
||||||
# BUG(v8:3435)
|
# BUG(v8:3435)
|
||||||
'debug-script-breakpoints': [PASS, FAIL],
|
'debug-script-breakpoints': [PASS, FAIL],
|
||||||
|
|
||||||
|
# BUG(v8:3815). TODO(arv): Investigate.
|
||||||
|
'harmony/computed-property-names': [PASS, FAIL]
|
||||||
}], # 'system == windows'
|
}], # 'system == windows'
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
Loading…
Reference in New Issue
Block a user