Introduce 'trivial' expressions, use them for this property assignments.

Add a (currently) syntactic predicate to AST expression nodes telling
whether they are 'trivial'.  Trivial expressions have no side effects,
do not require storage to be allocated for them, and can be evaluated
out of order (because their value does not change between when they
are visited by the code generator as expressions in the AST and when
it is consumed).

Mark 'this' and literals as trivial.  Allow them to be pushed on the
virtual frame.  Make use of them to push 'this' more lazily in this
property assignments.

Review URL: http://codereview.chromium.org/647018

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3906 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d3163361
// Copyright 2006-2008 the V8 project authors. All rights reserved. // Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -199,6 +199,10 @@ class Expression: public AstNode { ...@@ -199,6 +199,10 @@ class Expression: public AstNode {
// evaluated. // evaluated.
virtual bool IsLeaf() { return false; } virtual bool IsLeaf() { return false; }
// True if the expression has no side effects and is safe to
// evaluate out of order.
virtual bool IsTrivial() { return false; }
// Mark the expression as being compiled as an expression // Mark the expression as being compiled as an expression
// statement. This is used to transform postfix increments to // statement. This is used to transform postfix increments to
// (faster) prefix increments. // (faster) prefix increments.
...@@ -738,6 +742,7 @@ class Literal: public Expression { ...@@ -738,6 +742,7 @@ class Literal: public Expression {
} }
virtual bool IsLeaf() { return true; } virtual bool IsLeaf() { return true; }
virtual bool IsTrivial() { return true; }
// Identity testers. // Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); } bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
...@@ -926,6 +931,10 @@ class VariableProxy: public Expression { ...@@ -926,6 +931,10 @@ class VariableProxy: public Expression {
return var()->is_global() || var()->rewrite()->IsLeaf(); return var()->is_global() || var()->rewrite()->IsLeaf();
} }
// Reading from a mutable variable is a side effect, but 'this' is
// immutable.
virtual bool IsTrivial() { return is_this(); }
bool IsVariable(Handle<String> n) { bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n); return !is_this() && name().is_identical_to(n);
} }
......
...@@ -4762,8 +4762,9 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { ...@@ -4762,8 +4762,9 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
Property* prop = node->target()->AsProperty(); Property* prop = node->target()->AsProperty();
ASSERT(var == NULL || (prop == NULL && var->is_global())); ASSERT(var == NULL || (prop == NULL && var->is_global()));
// Initialize name and evaluate the receiver subexpression. // Initialize name and evaluate the receiver subexpression if necessary.
Handle<String> name; Handle<String> name;
bool is_trivial_receiver = false;
if (var != NULL) { if (var != NULL) {
name = var->name(); name = var->name();
LoadGlobal(); LoadGlobal();
...@@ -4771,17 +4772,23 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { ...@@ -4771,17 +4772,23 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
Literal* lit = prop->key()->AsLiteral(); Literal* lit = prop->key()->AsLiteral();
ASSERT(lit != NULL); ASSERT(lit != NULL);
name = Handle<String>::cast(lit->handle()); name = Handle<String>::cast(lit->handle());
Load(prop->obj()); // Do not materialize the receiver on the frame if it is trivial.
is_trivial_receiver = prop->obj()->IsTrivial();
if (!is_trivial_receiver) Load(prop->obj());
} }
if (node->starts_initialization_block()) { if (node->starts_initialization_block()) {
// Change to slow case in the beginning of an initialization block to // Change to slow case in the beginning of an initialization block to
// avoid the quadratic behavior of repeatedly adding fast properties. // avoid the quadratic behavior of repeatedly adding fast properties.
frame()->Dup(); if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
frame()->Dup();
}
Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1); Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1);
} }
if (node->ends_initialization_block()) { if (node->ends_initialization_block() && !is_trivial_receiver) {
// Add an extra copy of the receiver to the frame, so that it can be // Add an extra copy of the receiver to the frame, so that it can be
// converted back to fast case after the assignment. // converted back to fast case after the assignment.
frame()->Dup(); frame()->Dup();
...@@ -4789,7 +4796,11 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { ...@@ -4789,7 +4796,11 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Evaluate the right-hand side. // Evaluate the right-hand side.
if (node->is_compound()) { if (node->is_compound()) {
frame()->Dup(); if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
frame()->Dup();
}
Result value = EmitNamedLoad(name, var != NULL); Result value = EmitNamedLoad(name, var != NULL);
frame()->Push(&value); frame()->Push(&value);
Load(node->value()); Load(node->value());
...@@ -4807,18 +4818,27 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) { ...@@ -4807,18 +4818,27 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Perform the assignment. It is safe to ignore constants here. // Perform the assignment. It is safe to ignore constants here.
ASSERT(var == NULL || var->mode() != Variable::CONST); ASSERT(var == NULL || var->mode() != Variable::CONST);
ASSERT(node->op() != Token::INIT_CONST); ASSERT(node->op() != Token::INIT_CONST);
if (is_trivial_receiver) {
Result value = frame()->Pop();
frame()->Push(prop->obj());
frame()->Push(&value);
}
CodeForSourcePosition(node->position()); CodeForSourcePosition(node->position());
Result answer = EmitNamedStore(name); Result answer = EmitNamedStore(name);
frame()->Push(&answer); frame()->Push(&answer);
if (node->ends_initialization_block()) { if (node->ends_initialization_block()) {
// The argument to the runtime call is the extra copy of the receiver, // The argument to the runtime call is the receiver.
// which is below the value of the assignment. Swap the receiver and if (is_trivial_receiver) {
// the value of the assignment expression. frame()->Push(prop->obj());
Result result = frame()->Pop(); } else {
Result receiver = frame()->Pop(); // A copy of the receiver is below the value of the assignment. Swap
frame()->Push(&result); // the receiver and the value of the assignment expression.
frame()->Push(&receiver); Result result = frame()->Pop();
Result receiver = frame()->Pop();
frame()->Push(&result);
frame()->Push(&receiver);
}
Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
} }
......
...@@ -1175,6 +1175,25 @@ void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) { ...@@ -1175,6 +1175,25 @@ void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
} }
void VirtualFrame::Push(Expression* expr) {
ASSERT(expr->IsTrivial());
Literal* lit = expr->AsLiteral();
if (lit != NULL) {
Push(lit->handle());
return;
}
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && proxy->is_this()) {
PushParameterAt(-1);
return;
}
UNREACHABLE();
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal
...@@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject { ...@@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject {
result->Unuse(); result->Unuse();
} }
// Pushing an expression expects that the expression is trivial (according
// to Expression::IsTrivial).
void Push(Expression* expr);
// Nip removes zero or more elements from immediately below the top // Nip removes zero or more elements from immediately below the top
// of the frame, leaving the previous top-of-frame value on top of // of the frame, leaving the previous top-of-frame value on top of
// the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x). // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
......
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