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:
parent
fc1007027e
commit
bc3b2960e3
34
src/ast.cc
34
src/ast.cc
@ -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);
|
||||
|
28
src/ast.h
28
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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__());
|
||||
})();
|
||||
|
@ -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__);
|
||||
})();
|
||||
|
19
test/mjsunit/object-literal-multiple-proto-fields.js
Normal file
19
test/mjsunit/object-literal-multiple-proto-fields.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user