Revision: 3906
Author: [email protected]
Date: Fri Feb 19 01:01:31 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=3906
Modified:
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc
/branches/bleeding_edge/src/ia32/virtual-frame-ia32.h
=======================================
--- /branches/bleeding_edge/src/ast.h Fri Feb 12 02:16:30 2010
+++ /branches/bleeding_edge/src/ast.h Fri Feb 19 01:01:31 2010
@@ -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:
@@ -198,6 +198,10 @@
// Function literals are leaves because their subexpressions are not
// 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
@@ -738,6 +742,7 @@
}
virtual bool IsLeaf() { return true; }
+ virtual bool IsTrivial() { return true; }
// Identity testers.
bool IsNull() const { return
handle_.is_identical_to(Factory::null_value()); }
@@ -925,6 +930,10 @@
ASSERT(var_ != NULL); // Variable must be resolved.
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);
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Feb 18 05:02:17
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Feb 19 01:01:31
2010
@@ -4762,8 +4762,9 @@
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 @@
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 @@
// 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 @@
// 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);
}
=======================================
--- /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc Thu Feb 18
02:09:54 2010
+++ /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc Fri Feb 19
01:01:31 2010
@@ -1173,6 +1173,25 @@
stack_pointer_++;
__ push(immediate);
}
+
+
+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 __
=======================================
--- /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h Mon Feb 15
06:24:38 2010
+++ /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h Fri Feb 19
01:01:31 2010
@@ -414,6 +414,10 @@
}
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
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev