diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 24ccf09ce5..3dc54203b1 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1686,13 +1686,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->CalculateEmitStore(zone()); AccessorTable accessor_table(zone()); - int property_index = 0; - for (; property_index < expr->properties()->length(); property_index++) { - ObjectLiteral::Property* property = expr->properties()->at(property_index); - if (property->is_computed_name()) break; + for (int i = 0; i < expr->properties()->length(); i++) { + ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; - Literal* key = property->key()->AsLiteral(); + Literal* key = property->key(); Expression* value = property->value(); if (!result_saved) { __ push(r0); // Save result on stack @@ -1780,67 +1778,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ 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()) { DCHECK(result_saved); __ ldr(r0, MemOperand(sp)); @@ -2541,7 +2478,9 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { for (int i = 0; i < lit->properties()->length(); i++) { ObjectLiteral::Property* property = lit->properties()->at(i); + Literal* key = property->key()->AsLiteral(); Expression* value = property->value(); + DCHECK(key != NULL); if (property->is_static()) { __ ldr(scratch, MemOperand(sp, kPointerSize)); // constructor @@ -2549,7 +2488,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { __ ldr(scratch, MemOperand(sp, 0)); // prototype } __ push(scratch); - EmitPropertyKey(property); + VisitForStackValue(key); VisitForStackValue(value); EmitSetHomeObjectIfNeeded(value, 2); @@ -2562,11 +2501,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { break; case ObjectLiteral::Property::GETTER: - __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassGetter, 3); break; case ObjectLiteral::Property::SETTER: - __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassSetter, 3); break; default: diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 67267a6312..0d3d34b695 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -1667,13 +1667,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->CalculateEmitStore(zone()); AccessorTable accessor_table(zone()); - int property_index = 0; - for (; property_index < expr->properties()->length(); property_index++) { - ObjectLiteral::Property* property = expr->properties()->at(property_index); - if (property->is_computed_name()) break; + for (int i = 0; i < expr->properties()->length(); i++) { + ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; - Literal* key = property->key()->AsLiteral(); + Literal* key = property->key(); Expression* value = property->value(); if (!result_saved) { __ Push(x0); // Save result on stack @@ -1761,67 +1759,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ 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()) { DCHECK(result_saved); __ Peek(x0, 0); @@ -2238,7 +2175,9 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { for (int i = 0; i < lit->properties()->length(); i++) { ObjectLiteral::Property* property = lit->properties()->at(i); + Literal* key = property->key()->AsLiteral(); Expression* value = property->value(); + DCHECK(key != NULL); if (property->is_static()) { __ Peek(scratch, kPointerSize); // constructor @@ -2246,7 +2185,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { __ Peek(scratch, 0); // prototype } __ Push(scratch); - EmitPropertyKey(property); + VisitForStackValue(key); VisitForStackValue(value); EmitSetHomeObjectIfNeeded(value, 2); @@ -2259,11 +2198,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { break; case ObjectLiteral::Property::GETTER: - __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassGetter, 3); break; case ObjectLiteral::Property::SETTER: - __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassSetter, 3); break; default: diff --git a/src/ast-numbering.cc b/src/ast-numbering.cc index 8b1c2eccdd..c2dd70e1bb 100644 --- a/src/ast-numbering.cc +++ b/src/ast-numbering.cc @@ -476,7 +476,6 @@ void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) { void AstNumberingVisitor::VisitObjectLiteralProperty( ObjectLiteralProperty* node) { - if (node->is_computed_name()) DisableTurbofan(kComputedPropertyName); Visit(node->key()); Visit(node->value()); } diff --git a/src/ast.cc b/src/ast.cc index 298cd23c5b..6329371faa 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -185,17 +185,13 @@ void FunctionLiteral::InitializeSharedInfo( ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory, - Expression* key, Expression* value, - bool is_static, - bool is_computed_name) - : key_(key), - value_(value), - emit_store_(true), - is_static_(is_static), - is_computed_name_(is_computed_name) { - if (!is_computed_name && - key->AsLiteral()->raw_value()->EqualsString( - ast_value_factory->proto_string())) { + Literal* key, Expression* value, + bool is_static) { + emit_store_ = true; + key_ = key; + value_ = value; + is_static_ = is_static; + if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) { kind_ = PROTOTYPE; } else if (value_->AsMaterializedLiteral() != NULL) { kind_ = MATERIALIZED_LITERAL; @@ -208,16 +204,13 @@ ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter, - Expression* key, FunctionLiteral* value, - bool is_static, - bool is_computed_name) - : key_(key), - value_(value), - kind_(is_getter ? GETTER : SETTER), - emit_store_(true), - is_static_(is_static), - is_computed_name_(is_computed_name) {} + bool is_static) { + emit_store_ = true; + value_ = value; + kind_ = is_getter ? GETTER : SETTER; + is_static_ = is_static; +} bool ObjectLiteral::Property::IsCompileTimeValue() { @@ -244,11 +237,10 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { allocator); for (int i = properties()->length() - 1; i >= 0; i--) { ObjectLiteral::Property* property = properties()->at(i); - if (property->is_computed_name()) continue; - Literal* literal = property->key()->AsLiteral(); + Literal* literal = property->key(); if (literal->value()->IsNull()) continue; uint32_t hash = literal->Hash(); - // If the key of a computed property value is in the table, do not emit + // If the key of a computed property is in the table, do not emit // a store for the property later. if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL || property->kind() == ObjectLiteral::Property::COMPUTED) && @@ -287,13 +279,6 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { is_simple = false; continue; } - - if (position == boilerplate_properties_ * 2) { - DCHECK(property->is_computed_name()); - break; - } - DCHECK(!property->is_computed_name()); - MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); if (m_literal != NULL) { m_literal->BuildConstants(isolate); @@ -303,7 +288,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined // value for COMPUTED properties, the real value is filled in at // runtime. The enumeration order is maintained. - Handle key = property->key()->AsLiteral()->value(); + Handle key = property->key()->value(); Handle value = GetBoilerplateValue(property->value(), isolate); // Ensure objects that may, at any point in time, contain fields with double @@ -655,8 +640,7 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) { void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { - DCHECK(!is_computed_name()); - TypeFeedbackId id = key()->AsLiteral()->LiteralFeedbackId(); + TypeFeedbackId id = key()->LiteralFeedbackId(); SmallMapList maps; oracle->CollectReceiverTypes(id, &maps); receiver_type_ = maps.length() == 1 ? maps.at(0) diff --git a/src/ast.h b/src/ast.h index 8579ff4e33..43bde6ad25 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1467,7 +1467,10 @@ class ObjectLiteralProperty FINAL : public ZoneObject { PROTOTYPE // Property is __proto__. }; - Expression* key() { return key_; } + ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory, + Literal* key, Expression* value, bool is_static); + + Literal* key() { return key_; } Expression* value() { return value_; } Kind kind() { return kind_; } @@ -1482,26 +1485,20 @@ class ObjectLiteralProperty FINAL : public ZoneObject { bool emit_store(); bool is_static() const { return is_static_; } - bool is_computed_name() const { return is_computed_name_; } protected: friend class AstNodeFactory; - ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory, - Expression* key, Expression* value, bool is_static, - bool is_computed_name); - - ObjectLiteralProperty(Zone* zone, bool is_getter, Expression* key, - FunctionLiteral* value, bool is_static, - bool is_computed_name); + ObjectLiteralProperty(Zone* zone, bool is_getter, FunctionLiteral* value, + bool is_static); + void set_key(Literal* key) { key_ = key; } private: - Expression* key_; + Literal* key_; Expression* value_; Kind kind_; bool emit_store_; bool is_static_; - bool is_computed_name_; Handle receiver_type_; }; @@ -3380,21 +3377,20 @@ class AstNodeFactory FINAL BASE_EMBEDDED { boilerplate_properties, has_function, pos); } - ObjectLiteral::Property* NewObjectLiteralProperty(Expression* key, + ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key, Expression* value, - bool is_static, - bool is_computed_name) { - return new (zone_) ObjectLiteral::Property( - zone_, ast_value_factory_, key, value, is_static, is_computed_name); + bool is_static) { + return new (zone_) ObjectLiteral::Property(zone_, ast_value_factory_, key, + value, is_static); } ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter, - Expression* key, FunctionLiteral* value, - int pos, bool is_static, - bool is_computed_name) { - return new (zone_) ObjectLiteral::Property(zone_, is_getter, key, value, - is_static, is_computed_name); + int pos, bool is_static) { + ObjectLiteral::Property* prop = + new (zone_) ObjectLiteral::Property(zone_, is_getter, value, is_static); + prop->set_key(NewStringLiteral(value->raw_name(), pos)); + return prop; } RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, diff --git a/src/bailout-reason.h b/src/bailout-reason.h index 1c65fb9c04..7287d629d2 100644 --- a/src/bailout-reason.h +++ b/src/bailout-reason.h @@ -47,7 +47,6 @@ namespace internal { V(kCodeGenerationFailed, "Code generation failed") \ V(kCodeObjectNotProperlyPatched, "Code object not properly patched") \ V(kCompoundAssignmentToLookupSlot, "Compound assignment to lookup slot") \ - V(kComputedPropertyName, "Computed property name") \ V(kContextAllocatedArguments, "Context-allocated arguments") \ V(kCopyBuffersOverlap, "Copy buffers overlap") \ V(kCouldNotGenerateZero, "Could not generate +0.0") \ diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index d4fc6cd919..7105eb25e2 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1596,7 +1596,6 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_tostring) EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_templates) EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sloppy) EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode) -EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_computed_property_names) void Genesis::InstallNativeFunctions_harmony_proxies() { @@ -1627,7 +1626,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_templates) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_sloppy) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_unicode) -EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_computed_property_names) void Genesis::InitializeGlobal_harmony_regexps() { Handle builtins(native_context()->builtins()); @@ -2182,7 +2180,6 @@ bool Genesis::InstallExperimentalNatives() { "native harmony-templates.js", NULL}; static const char* harmony_sloppy_natives[] = {NULL}; static const char* harmony_unicode_natives[] = {NULL}; - static const char* harmony_computed_property_names_natives[] = {NULL}; for (int i = ExperimentalNatives::GetDebuggerCount(); i < ExperimentalNatives::GetBuiltinsCount(); i++) { diff --git a/src/builtins.h b/src/builtins.h index b776f733ae..13a4b8027f 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -165,36 +165,35 @@ enum BuiltinExtraArguments { DEBUG_BREAK) // Define list of builtins implemented in JavaScript. -#define BUILTINS_LIST_JS(V) \ - V(EQUALS, 1) \ - V(STRICT_EQUALS, 1) \ - V(COMPARE, 2) \ - V(ADD, 1) \ - V(SUB, 1) \ - V(MUL, 1) \ - V(DIV, 1) \ - V(MOD, 1) \ - V(BIT_OR, 1) \ - V(BIT_AND, 1) \ - V(BIT_XOR, 1) \ - V(SHL, 1) \ - V(SAR, 1) \ - V(SHR, 1) \ - V(DELETE, 2) \ - V(IN, 1) \ - V(INSTANCE_OF, 1) \ - V(FILTER_KEY, 1) \ - V(CALL_NON_FUNCTION, 0) \ - V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \ +#define BUILTINS_LIST_JS(V) \ + V(EQUALS, 1) \ + V(STRICT_EQUALS, 1) \ + V(COMPARE, 2) \ + V(ADD, 1) \ + V(SUB, 1) \ + V(MUL, 1) \ + V(DIV, 1) \ + V(MOD, 1) \ + V(BIT_OR, 1) \ + V(BIT_AND, 1) \ + V(BIT_XOR, 1) \ + V(SHL, 1) \ + V(SAR, 1) \ + V(SHR, 1) \ + V(DELETE, 2) \ + V(IN, 1) \ + V(INSTANCE_OF, 1) \ + V(FILTER_KEY, 1) \ + V(CALL_NON_FUNCTION, 0) \ + V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \ V(CALL_FUNCTION_PROXY, 1) \ V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR, 1) \ - V(TO_OBJECT, 0) \ - V(TO_NUMBER, 0) \ - V(TO_STRING, 0) \ - V(TO_NAME, 0) \ - V(STRING_ADD_LEFT, 1) \ - V(STRING_ADD_RIGHT, 1) \ - V(APPLY_PREPARE, 1) \ + V(TO_OBJECT, 0) \ + V(TO_NUMBER, 0) \ + V(TO_STRING, 0) \ + V(STRING_ADD_LEFT, 1) \ + V(STRING_ADD_RIGHT, 1) \ + V(APPLY_PREPARE, 1) \ V(STACK_OVERFLOW, 1) class BuiltinFunctionTable; diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 1c538738a2..cde5e7182d 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -910,7 +910,7 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; - Literal* key = property->key()->AsLiteral(); + Literal* key = property->key(); switch (property->kind()) { case ObjectLiteral::Property::CONSTANT: UNREACHABLE(); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 4a598bdde6..1bde01134c 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -172,16 +172,15 @@ DEFINE_IMPLICATION(harmony, es_staging) DEFINE_IMPLICATION(es_staging, harmony) // Features that are still work in progress (behind individual flags). -#define HARMONY_INPROGRESS(V) \ - V(harmony_modules, "harmony modules (implies block scoping)") \ - V(harmony_arrays, "harmony array methods") \ - V(harmony_array_includes, "harmony Array.prototype.includes") \ - V(harmony_regexps, "harmony regular expression extensions") \ - V(harmony_arrow_functions, "harmony arrow functions") \ - V(harmony_proxies, "harmony proxies") \ - V(harmony_sloppy, "harmony features in sloppy mode") \ - V(harmony_unicode, "harmony unicode escapes") \ - V(harmony_computed_property_names, "harmony computed property names") +#define HARMONY_INPROGRESS(V) \ + V(harmony_modules, "harmony modules (implies block scoping)") \ + V(harmony_arrays, "harmony array methods") \ + V(harmony_array_includes, "harmony Array.prototype.includes") \ + V(harmony_regexps, "harmony regular expression extensions") \ + V(harmony_arrow_functions, "harmony arrow functions") \ + V(harmony_proxies, "harmony proxies") \ + V(harmony_sloppy, "harmony features in sloppy mode") \ + V(harmony_unicode, "harmony unicode escapes") // Features that are complete (but still behind --harmony/es-staging flag). #define HARMONY_STAGED(V) \ diff --git a/src/full-codegen.cc b/src/full-codegen.cc index ec674ff3db..cb8f4aafcd 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -1211,13 +1211,6 @@ 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) { Comment cmnt(masm_, "[ ReturnStatement"); SetStatementPosition(stmt); diff --git a/src/full-codegen.h b/src/full-codegen.h index f870caefde..1439942db8 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -568,9 +568,6 @@ class FullCodeGenerator: public AstVisitor { // in the accumulator after installing all the properties. 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 // of the stack and the right one in the accumulator. void EmitBinaryOp(BinaryOperation* expr, diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 86fa8c55c2..987d60b334 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -5607,12 +5607,9 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { for (int i = 0; i < expr->properties()->length(); i++) { ObjectLiteral::Property* property = expr->properties()->at(i); - if (property->is_computed_name()) { - return Bailout(kComputedPropertyName); - } if (property->IsCompileTimeValue()) continue; - Literal* key = property->key()->AsLiteral(); + Literal* key = property->key(); Expression* value = property->value(); switch (property->kind()) { @@ -5638,7 +5635,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { } Handle map = property->GetReceiverType(); - Handle name = key->AsPropertyName(); + Handle name = property->key()->AsPropertyName(); HInstruction* store; if (map.is_null()) { // If we don't know the monomorphic type, do a generic store. diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 45627eae1f..1ba4095715 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1617,13 +1617,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->CalculateEmitStore(zone()); AccessorTable accessor_table(zone()); - int property_index = 0; - for (; property_index < expr->properties()->length(); property_index++) { - ObjectLiteral::Property* property = expr->properties()->at(property_index); - if (property->is_computed_name()) break; + for (int i = 0; i < expr->properties()->length(); i++) { + ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; - Literal* key = property->key()->AsLiteral(); + Literal* key = property->key(); Expression* value = property->value(); if (!result_saved) { __ push(eax); // Save result on the stack @@ -1703,65 +1701,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ 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()) { DCHECK(result_saved); __ push(Operand(esp, 0)); @@ -2455,14 +2394,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { for (int i = 0; i < lit->properties()->length(); i++) { ObjectLiteral::Property* property = lit->properties()->at(i); + Literal* key = property->key()->AsLiteral(); Expression* value = property->value(); + DCHECK(key != NULL); if (property->is_static()) { __ push(Operand(esp, kPointerSize)); // constructor } else { __ push(Operand(esp, 0)); // prototype } - EmitPropertyKey(property); + VisitForStackValue(key); VisitForStackValue(value); EmitSetHomeObjectIfNeeded(value, 2); @@ -2475,11 +2416,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { break; case ObjectLiteral::Property::GETTER: - __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassGetter, 3); break; case ObjectLiteral::Property::SETTER: - __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassSetter, 3); break; default: diff --git a/src/parser.cc b/src/parser.cc index e5b366bf0d..0713b26e8b 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -407,8 +407,9 @@ bool ParserTraits::IsConstructor(const AstRawString* identifier) const { bool ParserTraits::IsThisProperty(Expression* expression) { DCHECK(expression != NULL); Property* property = expression->AsProperty(); - return property != NULL && property->obj()->IsVariableProxy() && - property->obj()->AsVariableProxy()->is_this(); + return property != NULL && + property->obj()->AsVariableProxy() != NULL && + property->obj()->AsVariableProxy()->is_this(); } @@ -432,7 +433,8 @@ void ParserTraits::PushPropertyName(FuncNameInferrer* fni, void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left, Expression* right) { DCHECK(left != NULL); - if (left->IsProperty() && right->IsFunctionLiteral()) { + if (left->AsProperty() != NULL && + right->AsFunctionLiteral() != NULL) { right->AsFunctionLiteral()->set_pretenure(); } } @@ -804,8 +806,6 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) set_allow_harmony_templates(FLAG_harmony_templates); set_allow_harmony_sloppy(FLAG_harmony_sloppy); 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; ++feature) { use_counts_[feature] = 0; @@ -3976,8 +3976,6 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( reusable_preparser_->set_allow_harmony_templates(allow_harmony_templates()); reusable_preparser_->set_allow_harmony_sloppy(allow_harmony_sloppy()); 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 = reusable_preparser_->PreParseLazyFunction(strict_mode(), @@ -4037,11 +4035,8 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, if (fni_ != NULL) fni_->Enter(); const bool in_class = true; const bool is_static = false; - bool is_computed_name = false; // Classes do not care about computed - // property names here. - ObjectLiteral::Property* property = - ParsePropertyDefinition(NULL, in_class, is_static, &is_computed_name, - &has_seen_constructor, CHECK_OK); + ObjectLiteral::Property* property = ParsePropertyDefinition( + NULL, in_class, is_static, &has_seen_constructor, CHECK_OK); if (has_seen_constructor && constructor == NULL) { constructor = GetPropertyValue(property); diff --git a/src/parser.h b/src/parser.h index 0c58869dd6..02dfe15f8e 100644 --- a/src/parser.h +++ b/src/parser.h @@ -412,6 +412,11 @@ class ParserTraits { 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) { return property->value(); } @@ -421,9 +426,7 @@ class ParserTraits { static void PushLiteralName(FuncNameInferrer* fni, const AstRawString* id) { fni->PushLiteralName(id); } - void PushPropertyName(FuncNameInferrer* fni, Expression* expression); - static void InferFunctionName(FuncNameInferrer* fni, FunctionLiteral* func_to_infer) { fni->AddFunction(func_to_infer); diff --git a/src/preparser.cc b/src/preparser.cc index 51cac17cfa..1bd33409f0 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -990,10 +990,8 @@ PreParserExpression PreParser::ParseClassLiteral( if (Check(Token::SEMICOLON)) continue; const bool in_class = true; const bool is_static = false; - bool is_computed_name = false; // Classes do not care about computed - // property names here. - ParsePropertyDefinition(NULL, in_class, is_static, &is_computed_name, - &has_seen_constructor, CHECK_OK); + ParsePropertyDefinition(NULL, in_class, is_static, &has_seen_constructor, + CHECK_OK); } Expect(Token::RBRACE, CHECK_OK); diff --git a/src/preparser.h b/src/preparser.h index c79f6a6756..3b221ac092 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -87,7 +87,6 @@ class ParserBase : public Traits { allow_harmony_arrow_functions_(false), allow_harmony_object_literals_(false), allow_harmony_sloppy_(false), - allow_harmony_computed_property_names_(false), zone_(zone) {} // Getters that indicate whether certain syntactical constructs are @@ -109,9 +108,6 @@ class ParserBase : public Traits { bool allow_harmony_templates() const { return scanner()->HarmonyTemplates(); } bool allow_harmony_sloppy() const { return allow_harmony_sloppy_; } 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 // allowed to be parsed by this instance of the parser. @@ -144,9 +140,6 @@ class ParserBase : public Traits { void set_allow_harmony_unicode(bool allow) { scanner()->SetHarmonyUnicode(allow); } - void set_allow_harmony_computed_property_names(bool allow) { - allow_harmony_computed_property_names_ = allow; - } protected: enum AllowEvalOrArgumentsAsIdentifier { @@ -497,13 +490,11 @@ class ParserBase : public Traits { ExpressionT ParsePrimaryExpression(bool* ok); ExpressionT ParseExpression(bool accept_IN, bool* ok); ExpressionT ParseArrayLiteral(bool* ok); - ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set, - bool* is_static, bool* is_computed_name, + IdentifierT ParsePropertyName(bool* is_get, bool* is_set, bool* is_static, bool* ok); ExpressionT ParseObjectLiteral(bool* ok); ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker, bool in_class, bool is_static, - bool* is_computed_name, bool* has_seen_constructor, bool* ok); typename Traits::Type::ExpressionList ParseArguments(bool* ok); @@ -607,7 +598,6 @@ class ParserBase : public Traits { bool allow_harmony_arrow_functions_; bool allow_harmony_object_literals_; bool allow_harmony_sloppy_; - bool allow_harmony_computed_property_names_; typename Traits::Type::Zone* zone_; // Only used by Parser. }; @@ -1041,16 +1031,13 @@ class PreParserFactory { return PreParserExpression::Default(); } PreParserExpression NewObjectLiteralProperty(bool is_getter, - PreParserExpression key, PreParserExpression value, - int pos, bool is_static, - bool is_computed_name) { + int pos, bool is_static) { return PreParserExpression::Default(); } PreParserExpression NewObjectLiteralProperty(PreParserExpression key, PreParserExpression value, - bool is_static, - bool is_computed_name) { + bool is_static) { return PreParserExpression::Default(); } PreParserExpression NewObjectLiteral(PreParserExpressionList properties, @@ -1236,13 +1223,11 @@ class PreParserTraits { // PreParser should not use FuncNameInferrer. UNREACHABLE(); } - static void PushPropertyName(FuncNameInferrer* fni, PreParserExpression expression) { // PreParser should not use FuncNameInferrer. UNREACHABLE(); } - static void InferFunctionName(FuncNameInferrer* fni, PreParserExpression expression) { // PreParser should not use FuncNameInferrer. @@ -2002,55 +1987,24 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral( template -typename ParserBase::ExpressionT ParserBase::ParsePropertyName( - IdentifierT* name, bool* is_get, bool* is_set, bool* is_static, - bool* is_computed_name, bool* ok) { - 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) { +typename ParserBase::IdentifierT ParserBase::ParsePropertyName( + bool* is_get, bool* is_set, bool* is_static, bool* ok) { + Token::Value next = peek(); + switch (next) { case Token::STRING: Consume(Token::STRING); - *name = this->GetSymbol(scanner()); - break; - + return this->GetSymbol(scanner_); case Token::NUMBER: Consume(Token::NUMBER); - *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. + return this->GetNumberAsSymbol(scanner_); case Token::STATIC: *is_static = true; - - // Fall through. + // Fall through. default: - *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK); - break; + return ParseIdentifierNameOrGetOrSet(is_get, is_set, ok); } - - uint32_t index; - return this->IsArrayIndex(*name, &index) - ? factory()->NewNumberLiteral(index, pos) - : factory()->NewStringLiteral(*name, pos); + UNREACHABLE(); + return this->EmptyIdentifier(); } @@ -2058,11 +2012,9 @@ template typename ParserBase::ObjectLiteralPropertyT ParserBase< Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, bool in_class, bool is_static, - bool* is_computed_name, bool* has_seen_constructor, bool* ok) { DCHECK(!in_class || is_static || has_seen_constructor != NULL); ExpressionT value = this->EmptyExpression(); - IdentifierT name = this->EmptyIdentifier(); bool is_get = false; bool is_set = false; bool name_is_static = false; @@ -2070,17 +2022,15 @@ typename ParserBase::ObjectLiteralPropertyT ParserBase< Token::Value name_token = peek(); int next_pos = peek_position(); - ExpressionT name_expression = ParsePropertyName( - &name, &is_get, &is_set, &name_is_static, is_computed_name, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + IdentifierT name = + ParsePropertyName(&is_get, &is_set, &name_is_static, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - if (fni_ != NULL && !*is_computed_name) { - this->PushLiteralName(fni_, name); - } + if (fni_ != NULL) this->PushLiteralName(fni_, name); if (!in_class && !is_generator && peek() == Token::COLON) { // PropertyDefinition : PropertyName ':' AssignmentExpression - if (!*is_computed_name && checker != NULL) { + if (checker != NULL) { checker->CheckProperty(name_token, kValueProperty, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); } @@ -2118,7 +2068,7 @@ typename ParserBase::ObjectLiteralPropertyT ParserBase< kind = FunctionKind::kNormalFunction; } - if (!*is_computed_name && checker != NULL) { + if (checker != NULL) { checker->CheckProperty(name_token, kValueProperty, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); } @@ -2132,18 +2082,14 @@ typename ParserBase::ObjectLiteralPropertyT ParserBase< } else if (in_class && name_is_static && !is_static) { // static MethodDefinition - return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL, - ok); + return ParsePropertyDefinition(checker, true, true, NULL, ok); } else if (is_get || is_set) { // Accessor - name = this->EmptyIdentifier(); bool dont_care = false; name_token = peek(); - - name_expression = ParsePropertyName( - &name, &dont_care, &dont_care, &dont_care, is_computed_name, - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); + name = ParsePropertyName(&dont_care, &dont_care, &dont_care, + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); // Validate the property. if (is_static && this->IsPrototype(name)) { @@ -2155,7 +2101,7 @@ typename ParserBase::ObjectLiteralPropertyT ParserBase< *ok = false; return this->EmptyObjectLiteralProperty(); } - if (!*is_computed_name && checker != NULL) { + if (checker != NULL) { checker->CheckProperty(name_token, is_get ? kGetterProperty : kSetterProperty, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); @@ -2168,17 +2114,8 @@ typename ParserBase::ObjectLiteralPropertyT ParserBase< FunctionLiteral::ANONYMOUS_EXPRESSION, is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); - - // 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); + return factory()->NewObjectLiteralProperty(is_get, value, next_pos, + is_static); } else if (!in_class && allow_harmony_object_literals_ && Token::IsIdentifier(name_token, strict_mode(), @@ -2192,8 +2129,12 @@ typename ParserBase::ObjectLiteralPropertyT ParserBase< return this->EmptyObjectLiteralProperty(); } - return factory()->NewObjectLiteralProperty(name_expression, value, is_static, - *is_computed_name); + uint32_t index; + LiteralT key = this->IsArrayIndex(name, &index) + ? factory()->NewNumberLiteral(index, next_pos) + : factory()->NewStringLiteral(name, next_pos); + + return factory()->NewObjectLiteralProperty(key, value, is_static); } @@ -2208,7 +2149,6 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral( this->NewPropertyList(4, zone_); int number_of_boilerplate_properties = 0; bool has_function = false; - bool has_computed_names = false; ObjectLiteralChecker checker(this, strict_mode()); @@ -2219,13 +2159,8 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral( const bool in_class = false; const bool is_static = false; - bool is_computed_name = false; ObjectLiteralPropertyT property = this->ParsePropertyDefinition( - &checker, in_class, is_static, &is_computed_name, NULL, CHECK_OK); - - if (is_computed_name) { - has_computed_names = true; - } + &checker, in_class, is_static, NULL, CHECK_OK); // Mark top-level object literals that contain function literals and // pretenure the literal so it can be added as a constant function @@ -2234,7 +2169,7 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral( &has_function); // Count CONSTANT or COMPUTED properties to maintain the enumeration order. - if (!has_computed_names && this->IsBoilerplateProperty(property)) { + if (this->IsBoilerplateProperty(property)) { number_of_boilerplate_properties++; } properties->Add(property, zone()); diff --git a/src/runtime.js b/src/runtime.js index 145823b1f2..79824e4e02 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -468,12 +468,6 @@ 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 - - - ------------------------------------- diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc index 00567d4323..7c827f0bd9 100644 --- a/src/runtime/runtime-classes.cc +++ b/src/runtime/runtime-classes.cc @@ -153,10 +153,18 @@ RUNTIME_FUNCTION(Runtime_DefineClassMethod) { 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(Object, key, 1); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2); uint32_t index; + if (key->ToArrayIndex(&index)) { + RETURN_FAILURE_ON_EXCEPTION( + isolate, JSObject::SetOwnElement(object, index, function, STRICT)); + } + + Handle name; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, + Runtime::ToName(isolate, key)); if (name->AsArrayIndex(&index)) { RETURN_FAILURE_ON_EXCEPTION( isolate, JSObject::SetOwnElement(object, index, function, STRICT)); @@ -169,6 +177,42 @@ 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; + 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; + 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) { HandleScope shs(isolate); DCHECK(args.length() == 1); diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index 43620bb9b6..407f237794 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -1606,35 +1606,5 @@ RUNTIME_FUNCTION(RuntimeReference_ClassOf) { if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); 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 diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index a39e320f11..9e6c495162 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -187,6 +187,8 @@ namespace internal { F(HomeObjectSymbol, 0, 1) \ F(DefineClass, 6, 1) \ F(DefineClassMethod, 3, 1) \ + F(DefineClassGetter, 3, 1) \ + F(DefineClassSetter, 3, 1) \ F(ClassGetSourceCode, 1, 1) \ F(ThrowNonMethodError, 0, 1) \ F(ThrowUnsupportedSuperError, 0, 1) \ @@ -260,8 +262,6 @@ namespace internal { F(DefineDataPropertyUnchecked, 4, 1) \ F(DefineAccessorPropertyUnchecked, 5, 1) \ F(GetDataProperty, 2, 1) \ - F(DefineGetterPropertyUnchecked, 3, 1) \ - F(DefineSetterPropertyUnchecked, 3, 1) \ \ /* Arrays */ \ F(RemoveArrayHoles, 2, 1) \ diff --git a/src/typing.cc b/src/typing.cc index 3fb6030a10..88c530eeee 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -408,9 +408,7 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL && !CompileTimeValue::IsCompileTimeValue(prop->value())) || prop->kind() == ObjectLiteral::Property::COMPUTED) { - if (!prop->is_computed_name() && - prop->key()->AsLiteral()->value()->IsInternalizedString() && - prop->emit_store()) { + if (prop->key()->value()->IsInternalizedString() && prop->emit_store()) { prop->RecordTypeFeedback(oracle()); } } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 571cc337f6..24747ee9e8 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1651,13 +1651,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->CalculateEmitStore(zone()); AccessorTable accessor_table(zone()); - int property_index = 0; - for (; property_index < expr->properties()->length(); property_index++) { - ObjectLiteral::Property* property = expr->properties()->at(property_index); - if (property->is_computed_name()) break; + for (int i = 0; i < expr->properties()->length(); i++) { + ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; - Literal* key = property->key()->AsLiteral(); + Literal* key = property->key(); Expression* value = property->value(); if (!result_saved) { __ Push(rax); // Save result on the stack @@ -1737,65 +1735,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ 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()) { DCHECK(result_saved); __ Push(Operand(rsp, 0)); @@ -2454,14 +2393,16 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { for (int i = 0; i < lit->properties()->length(); i++) { ObjectLiteral::Property* property = lit->properties()->at(i); + Literal* key = property->key()->AsLiteral(); Expression* value = property->value(); + DCHECK(key != NULL); if (property->is_static()) { __ Push(Operand(rsp, kPointerSize)); // constructor } else { __ Push(Operand(rsp, 0)); // prototype } - EmitPropertyKey(property); + VisitForStackValue(key); VisitForStackValue(value); EmitSetHomeObjectIfNeeded(value, 2); @@ -2474,11 +2415,11 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { break; case ObjectLiteral::Property::GETTER: - __ CallRuntime(Runtime::kDefineGetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassGetter, 3); break; case ObjectLiteral::Property::SETTER: - __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3); + __ CallRuntime(Runtime::kDefineClassSetter, 3); break; default: diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index f08f9b31d9..ef6b5d30c4 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1358,8 +1358,7 @@ enum ParserFlag { kAllowHarmonyObjectLiterals, kAllowHarmonyTemplates, kAllowHarmonySloppy, - kAllowHarmonyUnicode, - kAllowHarmonyComputedPropertyNames + kAllowHarmonyUnicode }; @@ -1386,8 +1385,6 @@ void SetParserFlags(i::ParserBase* parser, parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates)); parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy)); parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode)); - parser->set_allow_harmony_computed_property_names( - flags.Contains(kAllowHarmonyComputedPropertyNames)); } @@ -4585,61 +4582,3 @@ TEST(LexicalScopingSloppyMode) { always_true_flags, arraysize(always_true_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)); -} diff --git a/test/mjsunit/harmony/computed-property-names-classes.js b/test/mjsunit/harmony/computed-property-names-classes.js deleted file mode 100644 index bcd031811e..0000000000 --- a/test/mjsunit/harmony/computed-property-names-classes.js +++ /dev/null @@ -1,367 +0,0 @@ -// 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()); -})(); diff --git a/test/mjsunit/harmony/computed-property-names-object-literals-methods.js b/test/mjsunit/harmony/computed-property-names-object-literals-methods.js deleted file mode 100644 index 135d09854e..0000000000 --- a/test/mjsunit/harmony/computed-property-names-object-literals-methods.js +++ /dev/null @@ -1,121 +0,0 @@ -// 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()); -})(); diff --git a/test/mjsunit/harmony/computed-property-names.js b/test/mjsunit/harmony/computed-property-names.js deleted file mode 100644 index 36ce6754d5..0000000000 --- a/test/mjsunit/harmony/computed-property-names.js +++ /dev/null @@ -1,270 +0,0 @@ -// 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__')); -})();