From e1041c9f9cc8f7d84e4fef154d2a04c1fa4f1576 Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Fri, 19 Feb 2010 09:01:31 +0000 Subject: [PATCH] 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 --- src/ast.h | 11 ++++++++- src/ia32/codegen-ia32.cc | 44 ++++++++++++++++++++++++---------- src/ia32/virtual-frame-ia32.cc | 19 +++++++++++++++ src/ia32/virtual-frame-ia32.h | 4 ++++ 4 files changed, 65 insertions(+), 13 deletions(-) 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).