Commit bc3b2960 authored by arv's avatar arv Committed by Commit bot

Fix issue with __proto__ when using ES6 object literals

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}
parent fc100702
...@@ -183,8 +183,18 @@ void FunctionLiteral::InitializeSharedInfo( ...@@ -183,8 +183,18 @@ void FunctionLiteral::InitializeSharedInfo(
} }
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
AstValueFactory* ast_value_factory, 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, Expression* key, Expression* value,
bool is_static, bool is_static,
bool is_computed_name) bool is_computed_name)
...@@ -207,19 +217,6 @@ ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, ...@@ -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() { bool ObjectLiteral::Property::IsCompileTimeValue() {
return kind_ == CONSTANT || return kind_ == CONSTANT ||
(kind_ == MATERIALIZED_LITERAL && (kind_ == MATERIALIZED_LITERAL &&
...@@ -242,6 +239,7 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { ...@@ -242,6 +239,7 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity,
allocator); allocator);
bool seen_prototype = false;
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);
if (property->is_computed_name()) continue; if (property->is_computed_name()) continue;
...@@ -254,6 +252,12 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { ...@@ -254,6 +252,12 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
property->kind() == ObjectLiteral::Property::COMPUTED) && property->kind() == ObjectLiteral::Property::COMPUTED) &&
table.Lookup(literal, hash, false, allocator) != NULL) { table.Lookup(literal, hash, false, allocator) != NULL) {
property->set_emit_store(false); 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 { } else {
// Add key to the table. // Add key to the table.
table.Lookup(literal, hash, true, allocator); table.Lookup(literal, hash, true, allocator);
......
...@@ -1452,12 +1452,10 @@ class ObjectLiteralProperty FINAL : public ZoneObject { ...@@ -1452,12 +1452,10 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
protected: protected:
friend class AstNodeFactory; friend class AstNodeFactory;
ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory, ObjectLiteralProperty(Expression* key, Expression* value, Kind kind,
Expression* key, Expression* value, bool is_static, bool is_static, bool is_computed_name);
bool is_computed_name); ObjectLiteralProperty(AstValueFactory* ast_value_factory, Expression* key,
Expression* value, bool is_static,
ObjectLiteralProperty(Zone* zone, bool is_getter, Expression* key,
FunctionLiteral* value, bool is_static,
bool is_computed_name); bool is_computed_name);
private: private:
...@@ -3355,20 +3353,18 @@ class AstNodeFactory FINAL BASE_EMBEDDED { ...@@ -3355,20 +3353,18 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
boilerplate_properties, has_function, pos); 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, ObjectLiteral::Property* NewObjectLiteralProperty(Expression* key,
Expression* value, Expression* value,
bool is_static, bool is_static,
bool is_computed_name) { bool is_computed_name) {
return new (zone_) ObjectLiteral::Property( return new (zone_) ObjectLiteral::Property(ast_value_factory_, key, value,
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,
is_static, is_computed_name); is_static, is_computed_name);
} }
......
...@@ -905,9 +905,9 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) { ...@@ -905,9 +905,9 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
switch (property->kind()) { switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT: case ObjectLiteral::Property::CONSTANT:
case ObjectLiteral::Property::MATERIALIZED_LITERAL: case ObjectLiteral::Property::MATERIALIZED_LITERAL:
case ObjectLiteral::Property::PROTOTYPE:
UNREACHABLE(); UNREACHABLE();
case ObjectLiteral::Property::COMPUTED: case ObjectLiteral::Property::COMPUTED: {
case ObjectLiteral::Property::PROTOTYPE: {
const Operator* op = const Operator* op =
javascript()->CallRuntime(Runtime::kDefineClassMethod, 3); javascript()->CallRuntime(Runtime::kDefineClassMethod, 3);
NewNode(op, receiver, key, value); NewNode(op, receiver, key, value);
......
...@@ -2469,8 +2469,9 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { ...@@ -2469,8 +2469,9 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
switch (property->kind()) { switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT: case ObjectLiteral::Property::CONSTANT:
case ObjectLiteral::Property::MATERIALIZED_LITERAL: case ObjectLiteral::Property::MATERIALIZED_LITERAL:
case ObjectLiteral::Property::COMPUTED:
case ObjectLiteral::Property::PROTOTYPE: case ObjectLiteral::Property::PROTOTYPE:
UNREACHABLE();
case ObjectLiteral::Property::COMPUTED:
__ CallRuntime(Runtime::kDefineClassMethod, 3); __ CallRuntime(Runtime::kDefineClassMethod, 3);
break; break;
...@@ -2481,9 +2482,6 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { ...@@ -2481,9 +2482,6 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
case ObjectLiteral::Property::SETTER: case ObjectLiteral::Property::SETTER:
__ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3); __ CallRuntime(Runtime::kDefineSetterPropertyUnchecked, 3);
break; break;
default:
UNREACHABLE();
} }
} }
......
...@@ -1049,10 +1049,10 @@ class PreParserFactory { ...@@ -1049,10 +1049,10 @@ class PreParserFactory {
int pos) { int pos) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewObjectLiteralProperty(bool is_getter, PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
PreParserExpression key,
PreParserExpression value, PreParserExpression value,
int pos, bool is_static, ObjectLiteralProperty::Kind kind,
bool is_static,
bool is_computed_name) { bool is_computed_name) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
...@@ -2141,6 +2141,10 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, ...@@ -2141,6 +2141,10 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
FunctionLiteral::NORMAL_ARITY, FunctionLiteral::NORMAL_ARITY,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); 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) { } else if (in_class && name_is_static && !is_static) {
// static MethodDefinition // static MethodDefinition
return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL, return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL,
...@@ -2189,12 +2193,18 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, ...@@ -2189,12 +2193,18 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
} }
return factory()->NewObjectLiteralProperty( 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_ && } else if (!in_class && allow_harmony_object_literals_ &&
Token::IsIdentifier(name_token, strict_mode(), Token::IsIdentifier(name_token, strict_mode(),
this->is_generator())) { this->is_generator())) {
DCHECK(!*is_computed_name);
DCHECK(!is_static);
value = this->ExpressionFromIdentifier(name, next_pos, scope_, factory()); value = this->ExpressionFromIdentifier(name, next_pos, scope_, factory());
return factory()->NewObjectLiteralProperty(
name_expression, value, ObjectLiteralProperty::COMPUTED, false, false);
} else { } else {
Token::Value next = Next(); Token::Value next = Next();
......
...@@ -246,3 +246,27 @@ function assertIteratorResult(value, done, result) { ...@@ -246,3 +246,27 @@ function assertIteratorResult(value, done, result) {
}; };
assertEquals('*method() { yield 1; }', object.method.toString()); 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__());
})();
...@@ -49,3 +49,25 @@ ...@@ -49,3 +49,25 @@
function f(x) { return {x}; } function f(x) { return {x}; }
assertEquals('function f(x) { return {x}; }', f.toString()); 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__);
})();
// 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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment