Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Unified Diff: src/ast.cc

Issue 1159005: Initial support for marking live code. (Closed)
Patch Set: Addressed review comments. Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/ast.h ('k') | src/compiler.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « src/ast.h ('k') | src/compiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698