Add iterative primitive type analysis.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 23 Mar 2010 13:01:37 +0000 (13:01 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 23 Mar 2010 13:01:37 +0000 (13:01 +0000)
This change adds a data-flow pass to statically determine
if a variable contains a primitive type.

It requires building the flow graph and computing reaching
definitions as pre-requisites. The analysis annotates all
VariableProxy nodes with the result.

Review URL: http://codereview.chromium.org/1132005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4224 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ast.cc
src/ast.h
src/compiler.cc
src/data-flow.cc
src/data-flow.h
src/prettyprinter.cc
src/prettyprinter.h

index 04f2a3b453abc5299309c4be03b4b09988a1f683..94daa1c227d45edd8258d63fbe7c051b8e45d57e 100644 (file)
@@ -79,7 +79,8 @@ VariableProxy::VariableProxy(Handle<String> name,
     is_this_(is_this),
     inside_with_(inside_with),
     is_trivial_(false),
-    reaching_definitions_(NULL) {
+    reaching_definitions_(NULL),
+    is_primitive_(false) {
   // names must be canonicalized for fast equality checks
   ASSERT(name->IsSymbol());
 }
@@ -87,7 +88,8 @@ VariableProxy::VariableProxy(Handle<String> name,
 
 VariableProxy::VariableProxy(bool is_this)
   : is_this_(is_this),
-    reaching_definitions_(NULL) {
+    reaching_definitions_(NULL),
+    is_primitive_(false) {
 }
 
 
@@ -518,12 +520,18 @@ bool ThisFunction::IsPrimitive() { return false; }
 
 // The following expression types are not always primitive because we do not
 // have enough information to conclude that they are.
-bool VariableProxy::IsPrimitive() { return false; }
 bool Property::IsPrimitive() { return false; }
 bool Call::IsPrimitive() { return false; }
 bool CallRuntime::IsPrimitive() { return false; }
 
 
+// A variable use is not primitive unless the primitive-type analysis
+// determines otherwise.
+bool VariableProxy::IsPrimitive() {
+  ASSERT(!is_primitive_ || (var() != NULL && var()->IsStackAllocated()));
+  return is_primitive_;
+}
+
 // The value of a conditional is the value of one of the alternatives.  It's
 // always primitive if both alternatives are always primitive.
 bool Conditional::IsPrimitive() {
index 96e398d90c10481c3cb4f776b313a9f3eade6a74..7114c2df00dde0f14e0134a206240ecffddcb727 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1078,6 +1078,8 @@ class VariableProxy: public Expression {
 
   virtual bool IsPrimitive();
 
+  void SetIsPrimitive(bool value) { is_primitive_ = value; }
+
   bool IsVariable(Handle<String> n) {
     return !is_this() && name().is_identical_to(n);
   }
@@ -1107,6 +1109,7 @@ class VariableProxy: public Expression {
   bool inside_with_;
   bool is_trivial_;
   BitVector* reaching_definitions_;
+  bool is_primitive_;
 
   VariableProxy(Handle<String> name, bool is_this, bool inside_with);
   explicit VariableProxy(bool is_this);
index c92fe5650ba52cb1a84e5ff21f4456f608fb4234..a88f18afb825b43b662f8ae47775834677d0b944 100755 (executable)
@@ -100,6 +100,12 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
                                builder.body_definitions(),
                                variable_count);
         rd.Compute();
+
+        TypeAnalyzer ta(builder.postorder(),
+                        builder.body_definitions(),
+                        variable_count,
+                        function->num_parameters());
+        ta.Compute();
       }
     }
 
@@ -503,14 +509,20 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
       FlowGraphBuilder builder(variable_count);
       builder.Build(literal);
 
-    if (!builder.HasStackOverflow()) {
-      if (variable_count > 0) {
-        ReachingDefinitions rd(builder.postorder(),
-                               builder.body_definitions(),
-                               variable_count);
-        rd.Compute();
+      if (!builder.HasStackOverflow()) {
+        if (variable_count > 0) {
+          ReachingDefinitions rd(builder.postorder(),
+                                 builder.body_definitions(),
+                                 variable_count);
+          rd.Compute();
+
+          TypeAnalyzer ta(builder.postorder(),
+                          builder.body_definitions(),
+                          variable_count,
+                          literal->num_parameters());
+          ta.Compute();
+        }
       }
-    }
 
 #ifdef DEBUG
       if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
index efd14fcb184facc8e04937e3f5923a5b0f719568..e327c5755dc7cfb22ed30dc7c455b9962976eb2f 100644 (file)
@@ -1994,4 +1994,56 @@ void ReachingDefinitions::Compute() {
 }
 
 
+bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
+  if (def_num < param_count_) return false;
+  if (def_num < variable_count_) return true;
+  return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
+}
+
+
+void TypeAnalyzer::Compute() {
+  bool changed;
+  int count = 0;
+
+  do {
+    changed = false;
+
+    if (FLAG_print_graph_text) {
+      PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
+    }
+
+    for (int i = postorder_->length() - 1; i >= 0; --i) {
+      Node* node = postorder_->at(i);
+      if (node->IsBlockNode()) {
+        BlockNode* block = BlockNode::cast(node);
+        for (int j = 0; j < block->instructions()->length(); j++) {
+          Expression* expr = block->instructions()->at(j)->AsExpression();
+          if (expr != NULL) {
+            // For variable uses: Compute new type from reaching definitions.
+            VariableProxy* proxy = expr->AsVariableProxy();
+            if (proxy != NULL && proxy->reaching_definitions() != NULL) {
+              BitVector* rd = proxy->reaching_definitions();
+              bool prim_type = true;
+              // TODO(fsc): A sparse set representation of reaching
+              // definitions would speed up iterating here.
+              for (int k = 0; k < rd->length(); k++) {
+                if (rd->Contains(k) && !IsPrimitiveDef(k)) {
+                  prim_type = false;
+                  break;
+                }
+              }
+              // Reset changed flag if new type information was computed.
+              if (prim_type != proxy->IsPrimitive()) {
+                changed = true;
+                proxy->SetIsPrimitive(prim_type);
+              }
+            }
+          }
+        }
+      }
+    }
+  } while (changed);
+}
+
+
 } }  // namespace v8::internal
index 874b4189f719f91b3dd74ad657b9b8a9554e8a27..9e7e6a496247005b28f9d4b88489fe24d1b088b8 100644 (file)
@@ -305,6 +305,8 @@ class BlockNode: public Node {
 
   bool is_empty() { return instructions_.is_empty(); }
 
+  ZoneList<AstNode*>* instructions() { return &instructions_; }
+
   void AddPredecessor(Node* predecessor) {
     ASSERT(predecessor_ == NULL && predecessor != NULL);
     predecessor_ = predecessor;
@@ -620,6 +622,31 @@ class ReachingDefinitions BASE_EMBEDDED {
 };
 
 
+
+class TypeAnalyzer BASE_EMBEDDED {
+ public:
+  TypeAnalyzer(ZoneList<Node*>* postorder,
+              ZoneList<Expression*>* body_definitions,
+               int variable_count,
+               int param_count)
+      : postorder_(postorder),
+        body_definitions_(body_definitions),
+        variable_count_(variable_count),
+        param_count_(param_count) {}
+
+  void Compute();
+
+ private:
+  // Get the primitity of definition number i. Definitions are numbered
+  // by the flow graph builder.
+  bool IsPrimitiveDef(int def_num);
+
+  ZoneList<Node*>* postorder_;
+  ZoneList<Expression*>* body_definitions_;
+  int variable_count_;
+  int param_count_;
+};
+
 } }  // namespace v8::internal
 
 
index 3e8cc3003f587838fc3f2e8aebefdfd0a11e521b..75f6fc3cbd491394db8f7c0ffcbf88c3960e0870 100644 (file)
@@ -668,7 +668,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
                                               Variable* var,
                                               Handle<Object> value,
                                               StaticType* type,
-                                              int num) {
+                                              int num,
+                                              bool is_primitive) {
   if (var == NULL) {
     PrintLiteralIndented(info, value, true);
   } else {
@@ -682,6 +683,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
     if (num != AstNode::kNoNumber) {
       pos += OS::SNPrintF(buf + pos, ", num = %d", num);
     }
+    pos += OS::SNPrintF(buf + pos,
+                        is_primitive ? ", primitive" : ", non-primitive");
     OS::SNPrintF(buf + pos, ")");
     PrintLiteralIndented(buf.start(), value, true);
   }
@@ -740,7 +743,8 @@ void AstPrinter::PrintParameters(Scope* scope) {
       PrintLiteralWithModeIndented("VAR", scope->parameter(i),
                                    scope->parameter(i)->name(),
                                    scope->parameter(i)->type(),
-                                   AstNode::kNoNumber);
+                                   AstNode::kNoNumber,
+                                   false);
     }
   }
 }
@@ -786,7 +790,8 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
                                  node->proxy()->AsVariable(),
                                  node->proxy()->name(),
                                  node->proxy()->AsVariable()->type(),
-                                 AstNode::kNoNumber);
+                                 AstNode::kNoNumber,
+                                 node->proxy()->IsPrimitive());
   } else {
     // function declarations
     PrintIndented("FUNCTION ");
@@ -1022,7 +1027,7 @@ void AstPrinter::VisitSlot(Slot* node) {
 
 void AstPrinter::VisitVariableProxy(VariableProxy* node) {
   PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
-                               node->type(), node->num());
+                               node->type(), node->num(), node->IsPrimitive());
   Variable* var = node->var();
   if (var != NULL && var->rewrite() != NULL) {
     IndentedScope indent;
index 8e958c77e2d1b0d49d200f4b8d5737bfb519018a..93ba0d95a86142b67dcb001ee1d9a7214dcb258f 100644 (file)
@@ -103,7 +103,8 @@ class AstPrinter: public PrettyPrinter {
                                     Variable* var,
                                     Handle<Object> value,
                                     StaticType* type,
-                                    int num);
+                                    int num,
+                                    bool is_primitive);
   void PrintLabelsIndented(const char* info, ZoneStringList* labels);
 
   void inc_indent() { indent_++; }