Allow multiple function literals to be assigned to the same var / property.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 16 Apr 2009 16:34:24 +0000 (16:34 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 16 Apr 2009 16:34:24 +0000 (16:34 +0000)
In such a case all functions get the same name. I think it's a good performance / usability tradeoff. In case a developer wants more clarity, it's up to him to give names to functions.

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

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

src/func-name-inferrer.cc
src/func-name-inferrer.h
src/rewriter.cc
test/cctest/test-func-name-inference.cc

index ef0c7db..75f7a99 100644 (file)
@@ -63,11 +63,12 @@ Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
 }
 
 
-void FuncNameInferrer::MaybeInferFunctionName() {
-  if (func_to_infer_ != NULL) {
-    func_to_infer_->set_inferred_name(MakeNameFromStack());
-    func_to_infer_ = NULL;
+void FuncNameInferrer::InferFunctionsNames() {
+  Handle<String> func_name = MakeNameFromStack();
+  for (int i = 0; i < funcs_to_infer_.length(); ++i) {
+    funcs_to_infer_[i]->set_inferred_name(func_name);
   }
+  funcs_to_infer_.Rewind(0);
 }
 
 
index 9dcf7c5..d8270c3 100644 (file)
@@ -45,7 +45,7 @@ class FuncNameInferrer BASE_EMBEDDED {
   FuncNameInferrer() :
       entries_stack_(10),
       names_stack_(5),
-      func_to_infer_(NULL),
+      funcs_to_infer_(4),
       dot_(Factory::NewStringFromAscii(CStrVector("."))) {
   }
 
@@ -57,39 +57,34 @@ class FuncNameInferrer BASE_EMBEDDED {
     entries_stack_.Add(names_stack_.length());
   }
 
-  void Leave() {
-    ASSERT(IsOpen());
-    names_stack_.Rewind(entries_stack_.RemoveLast());
-  }
-
   void PushName(Handle<String> name) {
     if (IsOpen()) {
       names_stack_.Add(name);
     }
   }
 
-  void SetFuncToInfer(FunctionLiteral* func_to_infer) {
+  void AddFunction(FunctionLiteral* func_to_infer) {
     if (IsOpen()) {
-      // If we encounter another function literal after already having
-      // encountered one, the second one replaces the first.
-      func_to_infer_ = func_to_infer;
+      funcs_to_infer_.Add(func_to_infer);
     }
   }
 
   void InferAndLeave() {
     ASSERT(IsOpen());
-    MaybeInferFunctionName();
-    Leave();
+    if (!funcs_to_infer_.is_empty()) {
+      InferFunctionsNames();
+    }
+    names_stack_.Rewind(entries_stack_.RemoveLast());
   }
 
  private:
   Handle<String> MakeNameFromStack();
   Handle<String> MakeNameFromStackHelper(int pos, Handle<String> prev);
-  void MaybeInferFunctionName();
+  void InferFunctionsNames();
 
   List<int> entries_stack_;
   List<Handle<String> > names_stack_;
-  FunctionLiteral* func_to_infer_;
+  List<FunctionLiteral*> funcs_to_infer_;
   Handle<String> dot_;
 
   DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
index 6641f26..4e3676b 100644 (file)
@@ -194,7 +194,7 @@ void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
 
   if (node->name()->length() == 0) {
     // Anonymous function.
-    func_name_inferrer_.SetFuncToInfer(node);
+    func_name_inferrer_.AddFunction(node);
   }
 }
 
@@ -282,10 +282,7 @@ void AstOptimizer::VisitAssignment(Assignment* node) {
     case Token::ASSIGN:
       // No type can be infered from the general assignment.
 
-      if (node->value()->AsFunctionLiteral() != NULL ||
-          node->value()->AsObjectLiteral() != NULL) {
-        scoped_fni.Enter();
-      }
+      scoped_fni.Enter();
       break;
     case Token::ASSIGN_BIT_OR:
     case Token::ASSIGN_BIT_XOR:
index 5058629..d91f75f 100644 (file)
@@ -221,3 +221,30 @@ TEST(AsParameter) {
   CheckFunctionName(script, "return 2", "");
   CheckFunctionName(script, "return 3", "");
 }
+
+
+TEST(MultipleFuncsConditional) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::Handle<v8::Script> script = Compile(
+      "fun1 = 0 ?\n"
+      "    function() { return 1; } :\n"
+      "    function() { return 2; }");
+  CheckFunctionName(script, "return 1", "fun1");
+  CheckFunctionName(script, "return 2", "fun1");
+}
+
+
+TEST(MultipleFuncsInLiteral) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::Handle<v8::Script> script = Compile(
+      "function MyClass() {}\n"
+      "MyClass.prototype = {\n"
+      "  method1: 0 ? function() { return 1; } :\n"
+      "               function() { return 2; } }");
+  CheckFunctionName(script, "return 1", "MyClass.method1");
+  CheckFunctionName(script, "return 2", "MyClass.method1");
+}