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
This commit is contained in:
parent
d316336162
commit
e1041c9f9c
11
src/ast.h
11
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
|
// 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 {
|
|||||||
// 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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.
|
||||||
|
if (is_trivial_receiver) {
|
||||||
|
frame()->Push(prop->obj());
|
||||||
|
} else {
|
||||||
frame()->Dup();
|
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) {
|
|||||||
|
|
||||||
// Evaluate the right-hand side.
|
// Evaluate the right-hand side.
|
||||||
if (node->is_compound()) {
|
if (node->is_compound()) {
|
||||||
|
if (is_trivial_receiver) {
|
||||||
|
frame()->Push(prop->obj());
|
||||||
|
} else {
|
||||||
frame()->Dup();
|
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) {
|
|||||||
// 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());
|
||||||
|
} 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 result = frame()->Pop();
|
||||||
Result receiver = frame()->Pop();
|
Result receiver = frame()->Pop();
|
||||||
frame()->Push(&result);
|
frame()->Push(&result);
|
||||||
frame()->Push(&receiver);
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
|||||||
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).
|
||||||
|
Loading…
Reference in New Issue
Block a user