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
// modification, are permitted provided that the following conditions are
// met:
......@@ -199,6 +199,10 @@ class Expression: public AstNode {
// evaluated.
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
// statement. This is used to transform postfix increments to
// (faster) prefix increments.
......@@ -738,6 +742,7 @@ class Literal: public Expression {
}
virtual bool IsLeaf() { return true; }
virtual bool IsTrivial() { return true; }
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
......@@ -926,6 +931,10 @@ class VariableProxy: public Expression {
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) {
return !is_this() && name().is_identical_to(n);
}
......
......@@ -4762,8 +4762,9 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
Property* prop = node->target()->AsProperty();
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;
bool is_trivial_receiver = false;
if (var != NULL) {
name = var->name();
LoadGlobal();
......@@ -4771,17 +4772,23 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
Literal* lit = prop->key()->AsLiteral();
ASSERT(lit != NULL);
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()) {
// Change to slow case in the beginning of an initialization block to
// 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);
}
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
// converted back to fast case after the assignment.
frame()->Dup();
......@@ -4789,7 +4796,11 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Evaluate the right-hand side.
if (node->is_compound()) {
frame()->Dup();
if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
frame()->Dup();
}
Result value = EmitNamedLoad(name, var != NULL);
frame()->Push(&value);
Load(node->value());
......@@ -4807,18 +4818,27 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Perform the assignment. It is safe to ignore constants here.
ASSERT(var == NULL || var->mode() != Variable::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());
Result answer = EmitNamedStore(name);
frame()->Push(&answer);
if (node->ends_initialization_block()) {
// The argument to the runtime call is the extra copy of the receiver,
// which is below the value of the assignment. Swap the receiver and
// the value of the assignment expression.
Result result = frame()->Pop();
Result receiver = frame()->Pop();
frame()->Push(&result);
frame()->Push(&receiver);
// The argument to the runtime call is the receiver.
if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
// A copy of the receiver is below the value of the assignment. Swap
// the receiver and the value of the assignment expression.
Result result = frame()->Pop();
Result receiver = frame()->Pop();
frame()->Push(&result);
frame()->Push(&receiver);
}
Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
}
......
......@@ -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 __
} } // namespace v8::internal
......@@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject {
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
// 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).
......
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