Fix issue with __proto__ when using ES6 object literals
authorarv <arv@chromium.org>
Tue, 20 Jan 2015 16:31:27 +0000 (08:31 -0800)
committerCommit bot <commit-bot@chromium.org>
Tue, 20 Jan 2015 16:31:43 +0000 (16:31 +0000)
It should be possible to create a concise method with the name
__proto__ without setting the [[Prototype]]. Similarly, property
name shorthands with the name __proto__ should define an own
property.

BUG=v8:3818
LOG=Y
R=adamk, dslomov@chromium.org

Review URL: https://codereview.chromium.org/858673002

Cr-Commit-Position: refs/heads/master@{#26172}

src/ast.cc
src/ast.h
src/compiler/ast-graph-builder.cc
src/ia32/full-codegen-ia32.cc
src/preparser.h
test/mjsunit/harmony/object-literals-method.js
test/mjsunit/harmony/object-literals-property-shorthand.js
test/mjsunit/object-literal-multiple-proto-fields.js [new file with mode: 0644]

index 1e1e224..7369e75 100644 (file)
@@ -183,8 +183,18 @@ void FunctionLiteral::InitializeSharedInfo(
 }
 
 
-ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
-                                             AstValueFactory* ast_value_factory,
+ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
+                                             Kind kind, bool is_static,
+                                             bool is_computed_name)
+    : key_(key),
+      value_(value),
+      kind_(kind),
+      emit_store_(true),
+      is_static_(is_static),
+      is_computed_name_(is_computed_name) {}
+
+
+ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
                                              Expression* key, Expression* value,
                                              bool is_static,
                                              bool is_computed_name)
@@ -207,19 +217,6 @@ 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 ObjectLiteral::Property::IsCompileTimeValue() {
   return kind_ == CONSTANT ||
       (kind_ == MATERIALIZED_LITERAL &&
@@ -242,6 +239,7 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
 
   ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity,
                     allocator);
+  bool seen_prototype = false;
   for (int i = properties()->length() - 1; i >= 0; i--) {
     ObjectLiteral::Property* property = properties()->at(i);
     if (property->is_computed_name()) continue;
@@ -254,6 +252,12 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
          property->kind() == ObjectLiteral::Property::COMPUTED) &&
         table.Lookup(literal, hash, false, allocator) != NULL) {
       property->set_emit_store(false);
+    } else if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
+      // Only emit a store for the last prototype property. Make sure we do not
+      // clobber the "__proto__" name for instance properties (using method or
+      // literal shorthand syntax).
+      property->set_emit_store(!seen_prototype);
+      seen_prototype = true;
     } else {
       // Add key to the table.
       table.Lookup(literal, hash, true, allocator);
index 716fded..74d6461 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1452,12 +1452,10 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
  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,
+  ObjectLiteralProperty(Expression* key, Expression* value, Kind kind,
+                        bool is_static, bool is_computed_name);
+  ObjectLiteralProperty(AstValueFactory* ast_value_factory, Expression* key,
+                        Expression* value, bool is_static,
                         bool is_computed_name);
 
  private:
@@ -3355,20 +3353,18 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
                                      boilerplate_properties, has_function, pos);
   }
 
+  ObjectLiteral::Property* NewObjectLiteralProperty(
+      Expression* key, Expression* value, ObjectLiteralProperty::Kind kind,
+      bool is_static, bool is_computed_name) {
+    return new (zone_)
+        ObjectLiteral::Property(key, value, kind, is_static, is_computed_name);
+  }
+
   ObjectLiteral::Property* NewObjectLiteralProperty(Expression* 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);
-  }
-
-  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,
+    return new (zone_) ObjectLiteral::Property(ast_value_factory_, key, value,
                                                is_static, is_computed_name);
   }
 
index 8443cfa..bc9bfd6 100644 (file)
@@ -905,9 +905,9 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
     switch (property->kind()) {
       case ObjectLiteral::Property::CONSTANT:
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+      case ObjectLiteral::Property::PROTOTYPE:
         UNREACHABLE();
-      case ObjectLiteral::Property::COMPUTED:
-      case ObjectLiteral::Property::PROTOTYPE: {
+      case ObjectLiteral::Property::COMPUTED: {
         const Operator* op =
             javascript()->CallRuntime(Runtime::kDefineClassMethod, 3);
         NewNode(op, receiver, key, value);
index 487384c..69fcb4d 100644 (file)
@@ -2469,8 +2469,9 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
     switch (property->kind()) {
       case ObjectLiteral::Property::CONSTANT:
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
-      case ObjectLiteral::Property::COMPUTED:
       case ObjectLiteral::Property::PROTOTYPE:
+        UNREACHABLE();
+      case ObjectLiteral::Property::COMPUTED:
         __ CallRuntime(Runtime::kDefineClassMethod, 3);
         break;
 
@@ -2481,9 +2482,6 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
       case ObjectLiteral::Property::SETTER:
         __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
         break;
-
-      default:
-        UNREACHABLE();
     }
   }
 
index 09f6b1d..5e37d63 100644 (file)
@@ -1049,10 +1049,10 @@ class PreParserFactory {
                                       int pos) {
     return PreParserExpression::Default();
   }
-  PreParserExpression NewObjectLiteralProperty(bool is_getter,
-                                               PreParserExpression key,
+  PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
                                                PreParserExpression value,
-                                               int pos, bool is_static,
+                                               ObjectLiteralProperty::Kind kind,
+                                               bool is_static,
                                                bool is_computed_name) {
     return PreParserExpression::Default();
   }
@@ -2141,6 +2141,10 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
         FunctionLiteral::NORMAL_ARITY,
         CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
 
+    return factory()->NewObjectLiteralProperty(name_expression, value,
+                                               ObjectLiteralProperty::COMPUTED,
+                                               is_static, *is_computed_name);
+
   } else if (in_class && name_is_static && !is_static) {
     // static MethodDefinition
     return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL,
@@ -2189,12 +2193,18 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
     }
 
     return factory()->NewObjectLiteralProperty(
-        is_get, name_expression, value, next_pos, is_static, *is_computed_name);
+        name_expression, value,
+        is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER,
+        is_static, *is_computed_name);
 
   } else if (!in_class && allow_harmony_object_literals_ &&
              Token::IsIdentifier(name_token, strict_mode(),
                                  this->is_generator())) {
+    DCHECK(!*is_computed_name);
+    DCHECK(!is_static);
     value = this->ExpressionFromIdentifier(name, next_pos, scope_, factory());
+    return factory()->NewObjectLiteralProperty(
+        name_expression, value, ObjectLiteralProperty::COMPUTED, false, false);
 
   } else {
     Token::Value next = Next();
index 71f44d1..605e269 100644 (file)
@@ -246,3 +246,27 @@ function assertIteratorResult(value, done, result) {
   };
   assertEquals('*method() { yield 1; }', object.method.toString());
 })();
+
+
+(function TestProtoName() {
+  var object = {
+    __proto__() {
+      return 1;
+    }
+  };
+  assertEquals(Object.prototype, Object.getPrototypeOf(object));
+  assertEquals(1, object.__proto__());
+})();
+
+
+(function TestProtoName2() {
+  var p = {};
+  var object = {
+    __proto__() {
+      return 1;
+    },
+    __proto__: p
+  };
+  assertEquals(p, Object.getPrototypeOf(object));
+  assertEquals(1, object.__proto__());
+})();
index 2921495..9756da4 100644 (file)
   function f(x) { return {x}; }
   assertEquals('function f(x) { return {x}; }', f.toString());
 })();
+
+
+(function TestProtoName() {
+  var __proto__ = 1;
+  var object = {
+    __proto__
+  };
+  assertEquals(Object.prototype, Object.getPrototypeOf(object));
+  assertEquals(1, object.__proto__);
+})();
+
+
+(function TestProtoName2() {
+  var __proto__ = 1;
+  var p = {};
+  var object = {
+    __proto__: p,
+    __proto__,
+  };
+  assertEquals(p, Object.getPrototypeOf(object));
+  assertEquals(1, object.__proto__);
+})();
diff --git a/test/mjsunit/object-literal-multiple-proto-fields.js b/test/mjsunit/object-literal-multiple-proto-fields.js
new file mode 100644 (file)
index 0000000..d8822c9
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var p1 = {};
+var p2 = {};
+var p3 = {};
+var x = 0;
+var y = 0;
+var z = 0;
+var o = {
+  __proto__: (x++, p1),
+  __proto__: (y++, p2),
+  __proto__: (z++, p3)
+};
+assertEquals(1, x);
+assertEquals(1, y);
+assertEquals(1, z);
+assertEquals(Object.getPrototypeOf(o), p3);