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}
This commit is contained in:
arv 2015-01-20 08:31:27 -08:00 committed by Commit bot
parent fc1007027e
commit bc3b2960e3
8 changed files with 114 additions and 41 deletions

View 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);

View File

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

View 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);

View 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();
}
}

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

View 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__());
})();

View File

@ -49,3 +49,25 @@
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__);
})();

View File

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