Bug 785089 - Fix an assertion failure when naming functions on labels. r=jimb
authorAlex Crichton <acrichton@mozilla.com>
Thu, 23 Aug 2012 09:57:47 -0700
changeset 105226 fcbf82dee1db51014afea64aa31a4921ed5aa374
parent 105225 c129811b87ef38c26d4fa80b1df7fbcee033a72e
child 105227 00646164061dfcf3d35f796e9c54ef09a2195bc8
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersjimb
bugs785089
milestone17.0a1
Bug 785089 - Fix an assertion failure when naming functions on labels. r=jimb
js/src/frontend/NameFunctions.cpp
js/src/jit-test/tests/basic/functionnames.js
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -96,51 +96,61 @@ class NameResolver
         for (int pos = nparents - 1; pos >= 0; pos--) {
             ParseNode *cur = parents[pos];
             if (cur->isAssignment())
                 return cur;
 
             switch (cur->getKind()) {
                 case PNK_NAME:     return cur;  /* found the initialized declaration */
                 case PNK_FUNCTION: return NULL; /* won't find an assignment or declaration */
-                default:           break;       /* move on, nothing relevant */
 
-                /* These nodes are relevant to the naming process, so append */
+                case PNK_RETURN:
+                    /*
+                     * Normally the relevant parent of a node is its direct parent, but
+                     * sometimes with code like:
+                     *
+                     *    var foo = (function() { return function() {}; })();
+                     *
+                     * the outer function is just a helper to create a scope for the
+                     * returned function. Hence the name of the returned function should
+                     * actually be 'foo'.  This loop sees if the current node is a
+                     * PNK_RETURN, and if there is a direct function call we skip to
+                     * that.
+                     */
+                    for (int tmp = pos - 1; tmp > 0; tmp--) {
+                        if (isDirectCall(tmp, cur)) {
+                            pos = tmp;
+                            break;
+                        } else if (call(cur)) {
+                            /* Don't skip too high in the tree */
+                            break;
+                        }
+                        cur = parents[tmp];
+                    }
+                    break;
+
                 case PNK_COLON:
-                case PNK_LP:
-                case PNK_NEW:
+                    /*
+                     * If this is a PNK_COLON, but our parent is not a PNK_RC,
+                     * then this is a label and we're done naming. Otherwise we
+                     * record the PNK_COLON but skip the PNK_RC so we're not
+                     * flagged as a contributor.
+                     */
+                    if (pos == 0 || !parents[pos - 1]->isKind(PNK_RC))
+                        return NULL;
+                    pos--;
+                    /* fallthrough */
+
+                /* Save any other nodes we encounter on the way up. */
+                default:
                     JS_ASSERT(*size < MaxParents);
                     nameable[(*size)++] = cur;
                     break;
             }
 
-            /*
-             * Normally the relevant parent of a node is its direct parent, but
-             * sometimes with code like:
-             *
-             *    var foo = (function() { return function() {}; })();
-             *
-             * the outer function is just a helper to create a scope for the
-             * returned function. Hence the name of the returned function should
-             * actually be 'foo'.  This loop sees if the current node is a
-             * PNK_RETURN, and if there is a direct function call we skip to
-             * that.
-             */
-            if (cur->isKind(PNK_RETURN)) {
-                for (int tmp = pos - 1; tmp > 0; tmp--) {
-                    if (isDirectCall(tmp, cur)) {
-                        pos = tmp;
-                        break;
-                    } else if (call(cur)) {
-                        /* Don't skip too high in the tree */
-                        break;
-                    }
-                    cur = parents[tmp];
-                }
-            }
         }
 
         return NULL;
     }
 
     /*
      * Resolve the name of a function. If the function already has a name
      * listed, then it is skipped. Otherwise an intelligent name is guessed to
--- a/js/src/jit-test/tests/basic/functionnames.js
+++ b/js/src/jit-test/tests/basic/functionnames.js
@@ -112,8 +112,19 @@ function f(g) {
     assertName(g, 'x<');
     return g();
 }
 var x = f(function () { return function() {}; });
 assertName(x, 'x</<');
 
 var a = {'b': function(){}};
 assertName(a.b, 'a.b');
+
+function g(f) {
+  assertName(f, '');
+}
+label: g(function () {});
+
+var z = [function() {}];
+assertName(z[0], 'z<');
+
+/* fuzz bug from 785089 */
+odeURIL:(function(){})