Revision: 8383
Author:   [email protected]
Date:     Wed Jun 22 13:23:48 2011
Log:      Fix issue 1354: Bad function name inference.

[email protected], [email protected]
BUG=1354
TEST=test-func-name-inference

Review URL: http://codereview.chromium.org/7206015
http://code.google.com/p/v8/source/detail?r=8383

Modified:
 /branches/bleeding_edge/src/func-name-inferrer.cc
 /branches/bleeding_edge/src/func-name-inferrer.h
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/test/cctest/cctest.status
 /branches/bleeding_edge/test/cctest/test-func-name-inference.cc

=======================================
--- /branches/bleeding_edge/src/func-name-inferrer.cc Tue May 3 01:23:58 2011 +++ /branches/bleeding_edge/src/func-name-inferrer.cc Wed Jun 22 13:23:48 2011
@@ -34,48 +34,62 @@
 namespace v8 {
 namespace internal {

+FuncNameInferrer::FuncNameInferrer(Isolate* isolate)
+    : isolate_(isolate),
+      entries_stack_(10),
+      names_stack_(5),
+      funcs_to_infer_(4) {
+}
+

 void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
   // Enclosing name is a name of a constructor function. To check
   // that it is really a constructor, we check that it is not empty
   // and starts with a capital letter.
   if (name->length() > 0 && Runtime::IsUpperCaseChar(
-      Isolate::Current()->runtime_state(), name->Get(0))) {
-    names_stack_.Add(name);
+          isolate()->runtime_state(), name->Get(0))) {
+    names_stack_.Add(Name(name, kEnclosingConstructorName));
   }
 }


 void FuncNameInferrer::PushLiteralName(Handle<String> name) {
-  if (IsOpen() && !HEAP->prototype_symbol()->Equals(*name)) {
-    names_stack_.Add(name);
+  if (IsOpen() && !isolate()->heap()->prototype_symbol()->Equals(*name)) {
+    names_stack_.Add(Name(name, kLiteralName));
   }
 }


 void FuncNameInferrer::PushVariableName(Handle<String> name) {
-  if (IsOpen() && !HEAP->result_symbol()->Equals(*name)) {
-    names_stack_.Add(name);
+  if (IsOpen() && !isolate()->heap()->result_symbol()->Equals(*name)) {
+    names_stack_.Add(Name(name, kVariableName));
   }
 }


 Handle<String> FuncNameInferrer::MakeNameFromStack() {
-  if (names_stack_.is_empty()) {
-    return FACTORY->empty_string();
-  } else {
-    return MakeNameFromStackHelper(1, names_stack_.at(0));
-  }
+  return MakeNameFromStackHelper(0, isolate()->factory()->empty_string());
 }


 Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
Handle<String> prev) {
-  if (pos >= names_stack_.length()) {
-    return prev;
+  if (pos >= names_stack_.length()) return prev;
+  if (pos < names_stack_.length() - 1 &&
+      names_stack_.at(pos).type == kVariableName &&
+      names_stack_.at(pos + 1).type == kVariableName) {
+    // Skip consecutive variable declarations.
+    return MakeNameFromStackHelper(pos + 1, prev);
   } else {
- Handle<String> curr = FACTORY->NewConsString(dot_, names_stack_.at(pos)); - return MakeNameFromStackHelper(pos + 1, FACTORY->NewConsString(prev, curr));
+    if (prev->length() > 0) {
+      Factory* factory = isolate()->factory();
+      Handle<String> curr = factory->NewConsString(
+          factory->dot_symbol(), names_stack_.at(pos).name);
+      return MakeNameFromStackHelper(pos + 1,
+                                     factory->NewConsString(prev, curr));
+    } else {
+      return MakeNameFromStackHelper(pos + 1, names_stack_.at(pos).name);
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/src/func-name-inferrer.h Fri Mar 18 13:35:07 2011 +++ /branches/bleeding_edge/src/func-name-inferrer.h Wed Jun 22 13:23:48 2011
@@ -31,6 +31,8 @@
 namespace v8 {
 namespace internal {

+class Isolate;
+
 // FuncNameInferrer is a stateful class that is used to perform name
 // inference for anonymous functions during static analysis of source code.
 // Inference is performed in cases when an anonymous function is assigned
@@ -43,12 +45,7 @@
 // a name.
 class FuncNameInferrer : public ZoneObject {
  public:
-  FuncNameInferrer()
-      : entries_stack_(10),
-        names_stack_(5),
-        funcs_to_infer_(4),
-        dot_(FACTORY->NewStringFromAscii(CStrVector("."))) {
-  }
+  explicit FuncNameInferrer(Isolate* isolate);

   // Returns whether we have entered name collection state.
   bool IsOpen() const { return !entries_stack_.is_empty(); }
@@ -81,13 +78,26 @@
     }
   }

-  // Infers a function name and leaves names collection state.
+  // Leaves names collection state.
   void Leave() {
     ASSERT(IsOpen());
     names_stack_.Rewind(entries_stack_.RemoveLast());
   }

  private:
+  enum NameType {
+    kEnclosingConstructorName,
+    kLiteralName,
+    kVariableName
+  };
+  struct Name {
+    Name(Handle<String> name, NameType type) : name(name), type(type) { }
+    Handle<String> name;
+    NameType type;
+  };
+
+  Isolate* isolate() { return isolate_; }
+
   // Constructs a full name in dotted notation from gathered names.
   Handle<String> MakeNameFromStack();

@@ -97,10 +107,10 @@
   // Performs name inferring for added functions.
   void InferFunctionsNames();

+  Isolate* isolate_;
   ZoneList<int> entries_stack_;
-  ZoneList<Handle<String> > names_stack_;
+  ZoneList<Name> names_stack_;
   ZoneList<FunctionLiteral*> funcs_to_infer_;
-  Handle<String> dot_;

   DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer);
 };
=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Jun 20 03:20:57 2011
+++ /branches/bleeding_edge/src/heap.h  Wed Jun 22 13:23:48 2011
@@ -218,7 +218,9 @@
   V(global_eval_symbol, "GlobalEval")                                    \
   V(identity_hash_symbol, "v8::IdentityHash")                            \
   V(closure_symbol, "(closure)")                                         \
-  V(use_strict, "use strict")
+  V(use_strict, "use strict")                                            \
+  V(dot_symbol, ".")                                                     \
+  V(anonymous_function_symbol, "(anonymous function)")

 // Forward declarations.
 class GCTracer;
=======================================
--- /branches/bleeding_edge/src/parser.cc       Wed Jun 22 02:06:03 2011
+++ /branches/bleeding_edge/src/parser.cc       Wed Jun 22 13:23:48 2011
@@ -595,7 +595,7 @@

   HistogramTimerScope timer(isolate()->counters()->parse());
   isolate()->counters()->total_parse_size()->Increment(source->length());
-  fni_ = new(zone()) FuncNameInferrer();
+  fni_ = new(zone()) FuncNameInferrer(isolate());

   // Initialize parser state.
   source->TryFlatten();
@@ -707,7 +707,7 @@
   ASSERT(target_stack_ == NULL);

   Handle<String> name(String::cast(shared_info->name()));
-  fni_ = new(zone()) FuncNameInferrer();
+  fni_ = new(zone()) FuncNameInferrer(isolate());
   fni_->PushEnclosingName(name);

   mode_ = PARSE_EAGERLY;
@@ -1613,7 +1613,11 @@
       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();
+      if (fni_ != NULL &&
+          value->AsCall() == NULL &&
+          value->AsCallNew() == NULL) {
+        fni_->Infer();
+      }
     }

     // Make sure that 'const c' actually initializes 'c' to undefined
@@ -2380,7 +2384,7 @@
     if ((op == Token::INIT_VAR
          || op == Token::INIT_CONST
          || op == Token::ASSIGN)
-        && (right->AsCall() == NULL)) {
+        && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
       fni_->Infer();
     }
     fni_->Leave();
@@ -2787,6 +2791,14 @@
         int pos = scanner().location().beg_pos;
         Expression* index = ParseExpression(true, CHECK_OK);
         result = new(zone()) Property(result, index, pos);
+        if (fni_ != NULL) {
+          if (index->IsPropertyName()) {
+            fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
+          } else {
+            fni_->PushLiteralName(
+                isolate()->factory()->anonymous_function_symbol());
+          }
+        }
         Expect(Token::RBRACK, CHECK_OK);
         break;
       }
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.status Fri Jun 17 01:40:30 2011 +++ /branches/bleeding_edge/test/cctest/cctest.status Wed Jun 22 13:23:48 2011
@@ -38,14 +38,6 @@
 test-serialize/TestThatAlwaysFails: FAIL
 test-serialize/DependentTestThatAlwaysFails: FAIL

-##############################################################################
-# BUG(1354): Bad function name inference
-test-func-name-inference/FactoryHashmapConditional: FAIL
-test-func-name-inference/FactoryHashmapVariable: FAIL
-test-func-name-inference/FactoryHashmap: FAIL
-test-func-name-inference/MultipleAssignments: FAIL
-test-func-name-inference/PassedAsConstructorParameter: FAIL
-
##############################################################################
 [ $arch == arm ]

=======================================
--- /branches/bleeding_edge/test/cctest/test-func-name-inference.cc Mon May 2 04:08:44 2011 +++ /branches/bleeding_edge/test/cctest/test-func-name-inference.cc Wed Jun 22 13:23:48 2011
@@ -288,19 +288,28 @@
   v8::HandleScope scope;

   v8::Handle<v8::Script> script = Compile(
-      "var fun1 = fun2 = function () { return 1; }");
+      "var fun1 = fun2 = function () { return 1; }\n"
+      "var bar1 = bar2 = bar3 = function () { return 2; }\n"
+      "foo1 = foo2 = function () { return 3; }\n"
+      "baz1 = baz2 = baz3 = function () { return 4; }");
   CheckFunctionName(script, "return 1", "fun2");
+  CheckFunctionName(script, "return 2", "bar3");
+  CheckFunctionName(script, "return 3", "foo2");
+  CheckFunctionName(script, "return 4", "baz3");
 }


-TEST(PassedAsConstructorParameter) {
+TEST(AsConstructorParameter) {
   InitializeVM();
   v8::HandleScope scope;

   v8::Handle<v8::Script> script = Compile(
       "function Foo() {}\n"
-      "var foo = new Foo(function() { return 1; })");
+      "var foo = new Foo(function() { return 1; })\n"
+ "var bar = new Foo(function() { return 2; }, function() { return 3; })");
   CheckFunctionName(script, "return 1", "");
+  CheckFunctionName(script, "return 2", "");
+  CheckFunctionName(script, "return 3", "");
 }


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to