| Index: src/ast.cc
|
| diff --git a/src/ast.cc b/src/ast.cc
|
| index 7dd991fd4261cb2929a950a8e0ff24017e71cd3e..7d26cd92cec93923e5bfdb19cdf15e48d6ac2f85 100644
|
| --- a/src/ast.cc
|
| +++ b/src/ast.cc
|
| @@ -28,6 +28,7 @@
|
| #include "v8.h"
|
|
|
| #include "ast.h"
|
| +#include "data-flow.h"
|
| #include "parser.h"
|
| #include "scopes.h"
|
| #include "string-stream.h"
|
| @@ -600,6 +601,199 @@ bool BinaryOperation::IsPrimitive() {
|
| bool CompareOperation::IsPrimitive() { return true; }
|
|
|
|
|
| +// Overridden IsCritical member functions. IsCritical is true for AST nodes
|
| +// whose evaluation is absolutely required (they are never dead) because
|
| +// they are externally visible.
|
| +
|
| +// References to global variables or lookup slots are critical because they
|
| +// may have getters. All others, including parameters rewritten to explicit
|
| +// property references, are not critical.
|
| +bool VariableProxy::IsCritical() {
|
| + Variable* var = AsVariable();
|
| + return var != NULL &&
|
| + (var->slot() == NULL || var->slot()->type() == Slot::LOOKUP);
|
| +}
|
| +
|
| +
|
| +// Literals are never critical.
|
| +bool Literal::IsCritical() { return false; }
|
| +
|
| +
|
| +// Property assignments and throwing of reference errors are always
|
| +// critical. Assignments to escaping variables are also critical. In
|
| +// addition the operation of compound assignments is critical if either of
|
| +// its operands is non-primitive (the arithmetic operations all use one of
|
| +// ToPrimitive, ToNumber, ToInt32, or ToUint32 on each of their operands).
|
| +// In this case, we mark the entire AST node as critical because there is
|
| +// no binary operation node to mark.
|
| +bool Assignment::IsCritical() {
|
| + Variable* var = AssignedVariable();
|
| + return var == NULL ||
|
| + !var->IsStackAllocated() ||
|
| + (is_compound() && (!target()->IsPrimitive() || !value()->IsPrimitive()));
|
| +}
|
| +
|
| +
|
| +// Property references are always critical, because they may have getters.
|
| +bool Property::IsCritical() { return true; }
|
| +
|
| +
|
| +// Calls are always critical.
|
| +bool Call::IsCritical() { return true; }
|
| +
|
| +
|
| +// +,- use ToNumber on the value of their operand.
|
| +bool UnaryOperation::IsCritical() {
|
| + ASSERT(op() == Token::ADD || op() == Token::SUB);
|
| + return !expression()->IsPrimitive();
|
| +}
|
| +
|
| +
|
| +// Count operations targeting properties and reference errors are always
|
| +// critical. Count operations on escaping variables are critical. Count
|
| +// operations targeting non-primitives are also critical because they use
|
| +// ToNumber.
|
| +bool CountOperation::IsCritical() {
|
| + Variable* var = AssignedVariable();
|
| + return var == NULL ||
|
| + !var->IsStackAllocated() ||
|
| + !expression()->IsPrimitive();
|
| +}
|
| +
|
| +
|
| +// Arithmetic operations all use one of ToPrimitive, ToNumber, ToInt32, or
|
| +// ToUint32 on each of their operands.
|
| +bool BinaryOperation::IsCritical() {
|
| + ASSERT(op() != Token::COMMA);
|
| + ASSERT(op() != Token::OR);
|
| + ASSERT(op() != Token::AND);
|
| + return !left()->IsPrimitive() || !right()->IsPrimitive();
|
| +}
|
| +
|
| +
|
| +// <, >, <=, and >= all use ToPrimitive on both their operands.
|
| +bool CompareOperation::IsCritical() {
|
| + ASSERT(op() != Token::EQ);
|
| + ASSERT(op() != Token::NE);
|
| + ASSERT(op() != Token::EQ_STRICT);
|
| + ASSERT(op() != Token::NE_STRICT);
|
| + ASSERT(op() != Token::INSTANCEOF);
|
| + ASSERT(op() != Token::IN);
|
| + return !left()->IsPrimitive() || !right()->IsPrimitive();
|
| +}
|
| +
|
| +
|
| +static inline void MarkIfNotLive(Expression* expr, List<AstNode*>* stack) {
|
| + if (!expr->is_live()) {
|
| + expr->mark_as_live();
|
| + stack->Add(expr);
|
| + }
|
| +}
|
| +
|
| +
|
| +// Overloaded functions for marking children of live code as live.
|
| +void VariableProxy::ProcessNonLiveChildren(
|
| + List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + // A reference to a stack-allocated variable depends on all the
|
| + // definitions reaching it.
|
| + BitVector* defs = reaching_definitions();
|
| + if (defs != NULL) {
|
| + ASSERT(var()->IsStackAllocated());
|
| + // The first variable_count definitions are the initial parameter and
|
| + // local declarations.
|
| + for (int i = variable_count; i < defs->length(); i++) {
|
| + if (defs->Contains(i)) {
|
| + MarkIfNotLive(body_definitions->at(i - variable_count), stack);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void Literal::ProcessNonLiveChildren(List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + // Leaf node, no children.
|
| +}
|
| +
|
| +
|
| +void Assignment::ProcessNonLiveChildren(
|
| + List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + Property* prop = target()->AsProperty();
|
| + VariableProxy* proxy = target()->AsVariableProxy();
|
| +
|
| + if (prop != NULL) {
|
| + if (!prop->key()->IsPropertyName()) MarkIfNotLive(prop->key(), stack);
|
| + MarkIfNotLive(prop->obj(), stack);
|
| + } else if (proxy == NULL) {
|
| + // Must be a reference error.
|
| + ASSERT(!target()->IsValidLeftHandSide());
|
| + MarkIfNotLive(target(), stack);
|
| + } else if (is_compound()) {
|
| + // A variable assignment so lhs is an operand to the operation.
|
| + MarkIfNotLive(target(), stack);
|
| + }
|
| + MarkIfNotLive(value(), stack);
|
| +}
|
| +
|
| +
|
| +void Property::ProcessNonLiveChildren(List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + if (!key()->IsPropertyName()) MarkIfNotLive(key(), stack);
|
| + MarkIfNotLive(obj(), stack);
|
| +}
|
| +
|
| +
|
| +void Call::ProcessNonLiveChildren(List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + ZoneList<Expression*>* args = arguments();
|
| + for (int i = args->length() - 1; i >= 0; i--) {
|
| + MarkIfNotLive(args->at(i), stack);
|
| + }
|
| + MarkIfNotLive(expression(), stack);
|
| +}
|
| +
|
| +
|
| +void UnaryOperation::ProcessNonLiveChildren(
|
| + List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + MarkIfNotLive(expression(), stack);
|
| +}
|
| +
|
| +
|
| +void CountOperation::ProcessNonLiveChildren(
|
| + List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + MarkIfNotLive(expression(), stack);
|
| +}
|
| +
|
| +
|
| +void BinaryOperation::ProcessNonLiveChildren(
|
| + List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + MarkIfNotLive(right(), stack);
|
| + MarkIfNotLive(left(), stack);
|
| +}
|
| +
|
| +
|
| +void CompareOperation::ProcessNonLiveChildren(
|
| + List<AstNode*>* stack,
|
| + ZoneList<Expression*>* body_definitions,
|
| + int variable_count) {
|
| + MarkIfNotLive(right(), stack);
|
| + MarkIfNotLive(left(), stack);
|
| +}
|
| +
|
| +
|
| // Implementation of a copy visitor. The visitor create a deep copy
|
| // of ast nodes. Nodes that do not require a deep copy are copied
|
| // with the default copy constructor.
|
|
|