diff --git a/src/ast.h b/src/ast.h index 8e717a6c8c..927a9f5035 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1,4 +1,4 @@ -// 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 n) { return !is_this() && name().is_identical_to(n); } diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 7ec3ff4c50..edf221bfb2 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -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 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::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); } diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index d2485392f5..5e44f94d0c 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -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 diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index b078ba0897..59142b40e2 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -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).