Don't build cross-eval upvars for heavyweight functions (bug 616762, r=brendan, a=CLOSED TREE).
authorDavid Anderson <danderson@mozilla.com>
Tue, 14 Dec 2010 11:50:20 -0800
changeset 59184 abe8842594814d9758eef43c67a4004378920556
parent 59183 a272338eb57a623106e8032905009813d91e8e28
child 59185 d78f9cb65e919a47fa23c597f724387f87561fc1
child 59188 f11f7ed625ba5f0ff8e20e4367c89d135d924428
push id17569
push userdanderson@mozilla.com
push dateTue, 14 Dec 2010 21:12:46 +0000
treeherdermozilla-central@abe884259481 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan, CLOSED
bugs616762
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Don't build cross-eval upvars for heavyweight functions (bug 616762, r=brendan, a=CLOSED TREE).
js/src/jsemit.cpp
js/src/trace-test/tests/basic/bug616762.js
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -2236,16 +2236,37 @@ BindNameToSlot(JSContext *cx, JSCodeGene
              * and the scope chain matches the function's variable object.
              * Optimize access to function's arguments and variable and the
              * arguments object.
              */
             if (op != JSOP_NAME)
                 return JS_TRUE;
 
             /*
+             * It is illegal to add upvars to heavyweight functions (and
+             * unnecessary, since the optimization avoids creating call
+             * objects). Take the following code as an eval string:
+             *
+             *   (function () {
+             *       $(init);
+             *       function init() {
+             *           $();
+             *       }
+             *    })();
+             *
+             * The first instance of "$" cannot be an upvar, because the
+             * outermost lambda is on "init"'s scope chain, which escapes.
+             *
+             * A similar restriction exists for upvars which do not cross
+             * eval (see the end of BindNameToSlot and bug 616762).
+             */
+            if (cg->flags & TCF_FUN_HEAVYWEIGHT)
+                return JS_TRUE;
+
+            /*
              * Generator functions may be resumed from any call stack, which
              * defeats the display optimization to static link searching used
              * by JSOP_{GET,CALL}UPVAR.
              */
             JSFunction *fun = cg->parser->callerFrame->fun();
             JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel);
             unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
             if (cg->skipSpansGenerator(skip))
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/basic/bug616762.js
@@ -0,0 +1,26 @@
+// vim: set ts=4 sw=4 tw=99 et:
+document = {
+    ready: function (x) {
+        this.exec = x;
+    }
+};
+
+var $ = function (x) {
+    return document;
+};
+
+(function ($) {
+    eval("(function(){\n" +
+         "  var Private={};\n" +
+         "  $(document).ready(function(){\n" +
+         "      init()\n" +
+         "  });\n" +
+         "  function init(){\n" +
+         "      $(Private)\n" +
+         "  };\n" +
+         "})();");
+})($);
+document.exec();
+
+// Don't crash or assert.
+