Move the function name inferrer code from the AstOptimizer to
authorkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 23 Aug 2010 13:26:03 +0000 (13:26 +0000)
committerkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 23 Aug 2010 13:26:03 +0000 (13:26 +0000)
the parser in preparation for not using the optimizer when
using the full codegen. Code covered by existing tests.
Review URL: http://codereview.chromium.org/3141034

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

src/func-name-inferrer.cc
src/func-name-inferrer.h
src/parser.cc
src/rewriter.cc

index 2d6a86a6f7e3cacd30411012b71ab6f3b4282082..f12d026bdbe2253795e2ce11ea170d2fceb51ebc 100644 (file)
@@ -44,6 +44,20 @@ void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
 }
 
 
+void FuncNameInferrer::PushLiteralName(Handle<String> name) {
+  if (IsOpen() && !Heap::prototype_symbol()->Equals(*name)) {
+    names_stack_.Add(name);
+  }
+}
+
+
+void FuncNameInferrer::PushVariableName(Handle<String> name) {
+  if (IsOpen() && !Heap::result_symbol()->Equals(*name)) {
+    names_stack_.Add(name);
+  }
+}
+
+
 Handle<String> FuncNameInferrer::MakeNameFromStack() {
   if (names_stack_.is_empty()) {
     return Factory::empty_string();
index e88586a445ef70ecc106c27ef6f2f7081de702ee..a35034ecb52181017851321eb87aaed826089de5 100644 (file)
@@ -36,11 +36,12 @@ namespace internal {
 // Inference is performed in cases when an anonymous function is assigned
 // to a variable or a property (see test-func-name-inference.cc for examples.)
 //
-// The basic idea is that during AST traversal LHSs of expressions are
-// always visited before RHSs. Thus, during visiting the LHS, a name can be
-// collected, and during visiting the RHS, a function literal can be collected.
-// Inference is performed while leaving the assignment node.
-class FuncNameInferrer BASE_EMBEDDED {
+// The basic idea is that during parsing of LHSs of certain expressions
+// (assignments, declarations, object literals) we collect name strings,
+// and during parsing of the RHS, a function literal can be collected. After
+// parsing the RHS we can infer a name for function literals that do not have
+// a name.
+class FuncNameInferrer : public ZoneObject {
  public:
   FuncNameInferrer()
       : entries_stack_(10),
@@ -61,11 +62,9 @@ class FuncNameInferrer BASE_EMBEDDED {
   }
 
   // Pushes an encountered name onto names stack when in collection state.
-  void PushName(Handle<String> name) {
-    if (IsOpen()) {
-      names_stack_.Add(name);
-    }
-  }
+  void PushLiteralName(Handle<String> name);
+
+  void PushVariableName(Handle<String> name);
 
   // Adds a function to infer name for.
   void AddFunction(FunctionLiteral* func_to_infer) {
@@ -75,11 +74,16 @@ class FuncNameInferrer BASE_EMBEDDED {
   }
 
   // Infers a function name and leaves names collection state.
-  void InferAndLeave() {
+  void Infer() {
     ASSERT(IsOpen());
     if (!funcs_to_infer_.is_empty()) {
       InferFunctionsNames();
     }
+  }
+
+  // Infers a function name and leaves names collection state.
+  void Leave() {
+    ASSERT(IsOpen());
     names_stack_.Rewind(entries_stack_.RemoveLast());
   }
 
@@ -102,34 +106,6 @@ class FuncNameInferrer BASE_EMBEDDED {
 };
 
 
-// A wrapper class that automatically calls InferAndLeave when
-// leaving scope.
-class ScopedFuncNameInferrer BASE_EMBEDDED {
- public:
-  explicit ScopedFuncNameInferrer(FuncNameInferrer* inferrer)
-      : inferrer_(inferrer),
-        is_entered_(false) {}
-
-  ~ScopedFuncNameInferrer() {
-    if (is_entered_) {
-      inferrer_->InferAndLeave();
-    }
-  }
-
-  // Triggers the wrapped inferrer into name collection state.
-  void Enter() {
-    inferrer_->Enter();
-    is_entered_ = true;
-  }
-
- private:
-  FuncNameInferrer* inferrer_;
-  bool is_entered_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedFuncNameInferrer);
-};
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_FUNC_NAME_INFERRER_H_
index 0fef2e2b0e9915c6cf0804ef5c133b494ab8fc6b..016869a7327c978c315ec18d617a6347d7a9a932 100644 (file)
@@ -32,6 +32,7 @@
 #include "bootstrapper.h"
 #include "codegen.h"
 #include "compiler.h"
+#include "func-name-inferrer.h"
 #include "messages.h"
 #include "parser.h"
 #include "platform.h"
@@ -154,6 +155,7 @@ class Parser {
   bool is_pre_parsing_;
   ScriptDataImpl* pre_data_;
   bool seen_loop_stmt_;  // Used for inner loop detection.
+  FuncNameInferrer* fni_;
 
   bool inside_with() const  { return with_nesting_level_ > 0; }
   ParserFactory* factory() const  { return factory_; }
@@ -1214,7 +1216,8 @@ Parser::Parser(Handle<Script> script,
       log_(log),
       is_pre_parsing_(is_pre_parsing == PREPARSE),
       pre_data_(pre_data),
-      seen_loop_stmt_(false) {
+      seen_loop_stmt_(false),
+      fni_(NULL) {
 }
 
 
@@ -1243,6 +1246,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
 
   HistogramTimerScope timer(&Counters::parse);
   Counters::total_parse_size.Increment(source->length());
+  fni_ = new FuncNameInferrer();
 
   // Initialize parser state.
   source->TryFlatten();
@@ -1303,6 +1307,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source,
   HistogramTimerScope timer(&Counters::parse_lazy);
   Counters::total_parse_size.Increment(source->length());
 
+  fni_ = new FuncNameInferrer();
+  fni_->PushEnclosingName(name);
+
   // Initialize parser state.
   source->TryFlatten();
   scanner_.Initialize(source, start_position, end_position, JAVASCRIPT);
@@ -2080,9 +2087,12 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
   VariableProxy* last_var = NULL;  // the last variable declared
   int nvars = 0;  // the number of variables declared
   do {
+    if (fni_ != NULL) fni_->Enter();
+
     // Parse variable name.
     if (nvars > 0) Consume(Token::COMMA);
     Handle<String> name = ParseIdentifier(CHECK_OK);
+    if (fni_ != NULL) fni_->PushVariableName(name);
 
     // Declare variable.
     // Note that we *always* must treat the initial value via a separate init
@@ -2134,6 +2144,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
       Expect(Token::ASSIGN, CHECK_OK);
       position = scanner().location().beg_pos;
       value = ParseAssignmentExpression(accept_IN, CHECK_OK);
+      // Don't infer if it is "a = function(){...}();"-like expression.
+      if (fni_ != NULL && value->AsCall() == NULL) fni_->Infer();
     }
 
     // Make sure that 'const c' actually initializes 'c' to undefined
@@ -2210,6 +2222,8 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
       Assignment* assignment = NEW(Assignment(op, last_var, value, position));
       if (block) block->AddStatement(NEW(ExpressionStatement(assignment)));
     }
+
+    if (fni_ != NULL) fni_->Leave();
   } while (peek() == Token::COMMA);
 
   if (!is_const && nvars == 1) {
@@ -2822,9 +2836,11 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
   //   ConditionalExpression
   //   LeftHandSideExpression AssignmentOperator AssignmentExpression
 
+  if (fni_ != NULL) fni_->Enter();
   Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
 
   if (!Token::IsAssignmentOp(peek())) {
+    if (fni_ != NULL) fni_->Leave();
     // Parsed conditional expression only (no assignment).
     return expression;
   }
@@ -2855,6 +2871,19 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
     temp_scope_->AddProperty();
   }
 
+  if (fni_ != NULL) {
+    // Check if the right hand side is a call to avoid inferring a
+    // name if we're dealing with "a = function(){...}();"-like
+    // expression.
+    if ((op == Token::INIT_VAR
+         || op == Token::INIT_CONST
+         || op == Token::ASSIGN)
+        && (right->AsCall() == NULL)) {
+      fni_->Infer();
+    }
+    fni_->Leave();
+  }
+
   return NEW(Assignment(op, expression, right, pos));
 }
 
@@ -3125,6 +3154,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
         int pos = scanner().location().beg_pos;
         Handle<String> name = ParseIdentifierName(CHECK_OK);
         result = factory()->NewProperty(result, NEW(Literal(name)), pos);
+        if (fni_ != NULL) fni_->PushLiteralName(name);
         break;
       }
 
@@ -3211,6 +3241,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
         int pos = scanner().location().beg_pos;
         Handle<String> name = ParseIdentifierName(CHECK_OK);
         result = factory()->NewProperty(result, NEW(Literal(name)), pos);
+        if (fni_ != NULL) fni_->PushLiteralName(name);
         break;
       }
       case Token::LPAREN: {
@@ -3321,6 +3352,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
 
     case Token::IDENTIFIER: {
       Handle<String> name = ParseIdentifier(CHECK_OK);
+      if (fni_ != NULL) fni_->PushVariableName(name);
       if (is_pre_parsing_) {
         result = VariableProxySentinel::identifier_proxy();
       } else {
@@ -3343,6 +3375,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
           factory()->LookupSymbol(scanner_.literal_string(),
                                   scanner_.literal_length());
       result = NEW(Literal(symbol));
+      if (fni_ != NULL) fni_->PushLiteralName(symbol);
       break;
     }
 
@@ -3640,6 +3673,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
 
   Expect(Token::LBRACE, CHECK_OK);
   while (peek() != Token::RBRACE) {
+    if (fni_ != NULL) fni_->Enter();
+
     Literal* key = NULL;
     Token::Value next = peek();
     switch (next) {
@@ -3648,6 +3683,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
         bool is_setter = false;
         Handle<String> id =
             ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+        if (fni_ != NULL) fni_->PushLiteralName(id);
+
         if ((is_getter || is_setter) && peek() != Token::COLON) {
             ObjectLiteral::Property* property =
                 ParseObjectLiteralGetSet(is_getter, CHECK_OK);
@@ -3656,6 +3693,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
             }
             properties.Add(property);
             if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
+
+            if (fni_ != NULL) {
+              fni_->Infer();
+              fni_->Leave();
+            }
             continue;  // restart the while
         }
         // Failed to parse as get/set property, so it's just a property
@@ -3668,6 +3710,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
         Handle<String> string =
             factory()->LookupSymbol(scanner_.literal_string(),
                                     scanner_.literal_length());
+        if (fni_ != NULL) fni_->PushLiteralName(string);
         uint32_t index;
         if (!string.is_null() && string->AsArrayIndex(&index)) {
           key = NewNumberLiteral(index);
@@ -3711,6 +3754,11 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
 
     // TODO(1240767): Consider allowing trailing comma.
     if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
+
+    if (fni_ != NULL) {
+      fni_->Infer();
+      fni_->Leave();
+    }
   }
   Expect(Token::RBRACE, CHECK_OK);
   // Computation of literal_index must happen before pre parse bailout.
@@ -3922,6 +3970,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
     // when peeling or unrolling such a loop.
     seen_loop_stmt_ = true;
 
+    if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
     return function_literal;
   }
 }
index 73301b91864e797040c525d6c25b0840e243fd79..90bafeec943bb0176ab22fcd4e9942c2a24099a0 100644 (file)
@@ -28,7 +28,6 @@
 #include "v8.h"
 
 #include "ast.h"
-#include "func-name-inferrer.h"
 #include "scopes.h"
 #include "rewriter.h"
 
@@ -39,10 +38,6 @@ namespace internal {
 class AstOptimizer: public AstVisitor {
  public:
   explicit AstOptimizer() : has_function_literal_(false) {}
-  explicit AstOptimizer(Handle<String> enclosing_name)
-      : has_function_literal_(false) {
-    func_name_inferrer_.PushEnclosingName(enclosing_name);
-  }
 
   void Optimize(ZoneList<Statement*>* statements);
 
@@ -50,8 +45,6 @@ class AstOptimizer: public AstVisitor {
   // Used for loop condition analysis.  Cleared before visiting a loop
   // condition, set when a function literal is visited.
   bool has_function_literal_;
-  // Helper object for function name inferring.
-  FuncNameInferrer func_name_inferrer_;
 
   // Helpers
   void OptimizeArguments(ZoneList<Expression*>* arguments);
@@ -211,11 +204,6 @@ void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) {
 
 void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
   has_function_literal_ = true;
-
-  if (node->name()->length() == 0) {
-    // Anonymous function.
-    func_name_inferrer_.AddFunction(node);
-  }
 }
 
 
@@ -247,11 +235,6 @@ void AstOptimizer::VisitVariableProxy(VariableProxy* node) {
       var->type()->SetAsLikelySmi();
     }
 
-    if (!var->is_this() &&
-        !Heap::result_symbol()->Equals(*var->name())) {
-      func_name_inferrer_.PushName(var->name());
-    }
-
     if (FLAG_safe_int32_compiler) {
       if (var->IsStackAllocated() &&
           !var->is_arguments() &&
@@ -268,11 +251,6 @@ void AstOptimizer::VisitLiteral(Literal* node) {
   if (literal->IsSmi()) {
     node->type()->SetAsLikelySmi();
     node->set_side_effect_free(true);
-  } else if (literal->IsString()) {
-    Handle<String> lit_str(Handle<String>::cast(literal));
-    if (!Heap::prototype_symbol()->Equals(*lit_str)) {
-      func_name_inferrer_.PushName(lit_str);
-    }
   } else if (literal->IsHeapNumber()) {
     if (node->to_int32()) {
       // Any HeapNumber has an int32 value if it is the input to a bit op.
@@ -299,8 +277,6 @@ void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) {
 
 void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
   for (int i = 0; i < node->properties()->length(); i++) {
-    ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
-    scoped_fni.Enter();
     Visit(node->properties()->at(i)->key());
     Visit(node->properties()->at(i)->value());
   }
@@ -314,17 +290,11 @@ void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) {
 
 
 void AstOptimizer::VisitAssignment(Assignment* node) {
-  ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
   switch (node->op()) {
     case Token::INIT_VAR:
     case Token::INIT_CONST:
     case Token::ASSIGN:
       // No type can be infered from the general assignment.
-
-      // Don't infer if it is "a = function(){...}();"-like expression.
-      if (node->value()->AsCall() == NULL) {
-        scoped_fni.Enter();
-      }
       break;
     case Token::ASSIGN_BIT_OR:
     case Token::ASSIGN_BIT_XOR:
@@ -430,12 +400,6 @@ void AstOptimizer::VisitCallNew(CallNew* node) {
 
 
 void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
-  ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
-  if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) &&
-      node->arguments()->length() >= 2 &&
-      node->arguments()->at(1)->AsFunctionLiteral() != NULL) {
-      scoped_fni.Enter();
-  }
   OptimizeArguments(node->arguments());
 }
 
@@ -1025,7 +989,7 @@ bool Rewriter::Optimize(FunctionLiteral* function) {
 
   if (FLAG_optimize_ast && !body->is_empty()) {
     HistogramTimerScope timer(&Counters::ast_optimization);
-    AstOptimizer optimizer(function->name());
+    AstOptimizer optimizer;
     optimizer.Optimize(body);
     if (optimizer.HasStackOverflow()) {
       return false;