-// 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:
// 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.
}
virtual bool IsLeaf() { return true; }
+ virtual bool IsTrivial() { return true; }
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
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);
}
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();
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();
// 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());
// 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);
}