Computed property names for object literals in TurboFan.

R=dslomov@chromium.org
TEST=mjsunit/harmony/computed-property-names

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

Cr-Commit-Position: refs/heads/master@{#26174}
This commit is contained in:
mstarzinger 2015-01-20 08:52:52 -08:00 committed by Commit bot
parent 65c01bdc64
commit bd7f546f11
3 changed files with 70 additions and 8 deletions

View File

@ -1027,9 +1027,11 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
expr->CalculateEmitStore(zone()); expr->CalculateEmitStore(zone());
// Create nodes to store computed values into the literal. // Create nodes to store computed values into the literal.
int property_index = 0;
AccessorTable accessor_table(zone()); AccessorTable accessor_table(zone());
for (int i = 0; i < expr->properties()->length(); i++) { for (; property_index < expr->properties()->length(); property_index++) {
ObjectLiteral::Property* property = expr->properties()->at(i); ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (property->is_computed_name()) break;
if (property->IsCompileTimeValue()) continue; if (property->IsCompileTimeValue()) continue;
Literal* key = property->key()->AsLiteral(); Literal* key = property->key()->AsLiteral();
@ -1111,6 +1113,64 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
PrepareFrameState(call, BailoutId::None()); PrepareFrameState(call, BailoutId::None());
} }
// 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_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);
environment()->Push(literal); // Duplicate receiver.
VisitForValue(property->key());
environment()->Push(BuildToName(environment()->Pop()));
// TODO(mstarzinger): For ObjectLiteral::Property::PROTOTYPE the key should
// not be on the operand stack while the value is being evaluated. Come up
// with a repro for this and fix it. Also find a nice way to do so. :)
VisitForValue(property->value());
Node* value = environment()->Pop();
Node* key = environment()->Pop();
Node* receiver = environment()->Pop();
switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT:
case ObjectLiteral::Property::COMPUTED:
case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
Node* attr = jsgraph()->Constant(NONE);
const Operator* op =
javascript()->CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
Node* call = NewNode(op, receiver, key, value, attr);
PrepareFrameState(call, BailoutId::None());
break;
}
case ObjectLiteral::Property::PROTOTYPE: {
const Operator* op =
javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
Node* call = NewNode(op, receiver, value);
PrepareFrameState(call, BailoutId::None());
break;
}
case ObjectLiteral::Property::GETTER: {
const Operator* op = javascript()->CallRuntime(
Runtime::kDefineGetterPropertyUnchecked, 3);
Node* call = NewNode(op, receiver, key, value);
PrepareFrameState(call, BailoutId::None());
break;
}
case ObjectLiteral::Property::SETTER: {
const Operator* op = javascript()->CallRuntime(
Runtime::kDefineSetterPropertyUnchecked, 3);
Node* call = NewNode(op, receiver, key, value);
PrepareFrameState(call, BailoutId::None());
break;
}
}
}
// Transform literals that contain functions to fast properties. // Transform literals that contain functions to fast properties.
if (expr->has_function()) { if (expr->has_function()) {
const Operator* op = const Operator* op =

View File

@ -263,10 +263,17 @@ function ID(x) {
}; };
assertEquals(proto, Object.getPrototypeOf(object)); assertEquals(proto, Object.getPrototypeOf(object));
var object = { object = {
['__proto__']: proto ['__proto__']: proto
}; };
assertEquals(Object.prototype, Object.getPrototypeOf(object)); assertEquals(Object.prototype, Object.getPrototypeOf(object));
assertEquals(proto, object.__proto__); assertEquals(proto, object.__proto__);
assertTrue(object.hasOwnProperty('__proto__')); assertTrue(object.hasOwnProperty('__proto__'));
object = {
[ID('x')]: 'X',
__proto__: proto
};
assertEquals('X', object.x);
assertEquals(proto, Object.getPrototypeOf(object));
})(); })();

View File

@ -84,11 +84,6 @@
# not work, but we expect it to not crash. # not work, but we expect it to not crash.
'debug-step-turbofan': [PASS, FAIL], 'debug-step-turbofan': [PASS, FAIL],
# TODO(mstarzinger): Investigate failures with computed property names.
# Note that this happens in GC-stress mode only.
'harmony/computed-property-names': [PASS, NO_VARIANTS],
'harmony/computed-property-names-object-literals-methods': [PASS, NO_VARIANTS],
# TODO(jarin/mstarzinger): Investigate debugger issues with TurboFan. # TODO(jarin/mstarzinger): Investigate debugger issues with TurboFan.
'debug-evaluate-const': [PASS, NO_VARIANTS], 'debug-evaluate-const': [PASS, NO_VARIANTS],
'debug-evaluate-locals': [PASS, NO_VARIANTS], 'debug-evaluate-locals': [PASS, NO_VARIANTS],