Bug 781859 - Fix chunked compilation bug with unreachable code. r=dvander
☠☠ backed out by 65404c2b69c4 ☠ ☠
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 03 Oct 2012 13:11:48 +0200
changeset 115348 6f31bcbcdbf466f4fe2c1d9b903098ed057b2195
parent 115347 876ea6e98dd92d0cf2fe23c433d5eaee2e8c90ca
child 115349 ffcdd896a1fa7bb419077873da59d2d2ed9e3271
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs781859
milestone18.0a1
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
Bug 781859 - Fix chunked compilation bug with unreachable code. r=dvander
js/src/jit-test/tests/jaeger/bug781859-1.js
js/src/jit-test/tests/jaeger/bug781859-2.js
js/src/jit-test/tests/jaeger/bug781859-3.js
js/src/methodjit/Compiler.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug781859-1.js
@@ -0,0 +1,25 @@
+// |jit-test| error:ReferenceError
+function e() {
+    try {} catch (e) {
+    return (actual = "FAIL");
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+    }
+    while (t) continue;
+}
+e();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug781859-2.js
@@ -0,0 +1,9 @@
+mjitChunkLimit(42);
+Function("\
+    switch (/x/) {\
+        case 8:\
+        break;\
+        t(function(){})\
+    }\
+    while (false)(function(){})\
+")()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug781859-3.js
@@ -0,0 +1,10 @@
+mjitChunkLimit(10);
+function e() {
+    try {
+        var t = undefined;
+    } catch (e) { }
+    while (t)
+        continue;
+}
+for (var i = 0; i < 20; i++)
+  e();
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -861,16 +861,32 @@ MakeJITScript(JSContext *cx, JSScript *s
                     const CrossChunkEdge &edge = currentEdges[i];
                     if (edge.target >= nextOffset) {
                         analysis->getCode(edge.target).safePoint = true;
                         if (!edges.append(edge))
                             return NULL;
                     }
                 }
                 currentEdges.clear();
+
+                /*
+                 * A loop's LOOPHEAD instruction is usually marked as safepoint if
+                 * either:
+                 *   (1) The whole loop is contained in a single chunk and tracked
+                 *       in the compiler (see shouldStartLoop).
+                 *   (2) The loop's backedge and LOOPHEAD are in different chunks.
+                 *
+                 * If a while loop follows an unreachable op, we may insert a chunk
+                 * boundary between the loop's initial GOTO and LOOPHEAD. In this
+                 * case we have to explicitly mark the LOOPHEAD as safepoint since
+                 * both of these conditions don't apply.
+                 */
+                jsbytecode *nextpc = script->code + nextOffset;
+                if (JSOp(*nextpc) == JSOP_LOOPHEAD)
+                    analysis->getCode(chunkStart).safePoint = true;
             }
         }
 
         if (chunkStart != script->length) {
             ChunkDescriptor desc;
             desc.begin = chunkStart;
             desc.end = script->length;
             if (!chunks.append(desc))
@@ -2026,19 +2042,16 @@ mjit::Compiler::shouldStartLoop(jsbyteco
     return false;
 }
 
 CompileStatus
 mjit::Compiler::generateMethod()
 {
     SrcNoteLineScanner scanner(script_->notes(), script_->lineno);
 
-    /* For join points, whether there was fallthrough from the previous opcode. */
-    bool fallthrough = true;
-
     /* Last bytecode processed. */
     jsbytecode *lastPC = NULL;
 
     if (!outerJIT())
         return Compile_Retry;
 
     uint32_t chunkBegin = 0, chunkEnd = script_->length;
     if (!a->parent) {
@@ -2077,16 +2090,19 @@ mjit::Compiler::generateMethod()
 
         if (chunkIndex != 0) {
             uint32_t depth = analysis->getCode(PC).stackDepth;
             for (uint32_t i = 0; i < depth; i++)
                 frame.pushSynced(JSVAL_TYPE_UNKNOWN);
         }
     }
 
+    /* For join points, whether there was fallthrough from the previous opcode. */
+    bool fallthrough = (chunkIndex == 0 || analysis->maybeCode(PC)->fallthrough);
+
     for (;;) {
         JSOp op = JSOp(*PC);
         int trap = stubs::JSTRAP_NONE;
 
         if (script_->hasBreakpointsAt(PC))
             trap |= stubs::JSTRAP_TRAP;
 
         Bytecode *opinfo = analysis->maybeCode(PC);
@@ -7095,16 +7111,28 @@ mjit::Compiler::startLoop(jsbytecode *he
 
 bool
 mjit::Compiler::finishLoop(jsbytecode *head)
 {
     if (!cx->typeInferenceEnabled() || !bytecodeInChunk(head))
         return true;
 
     /*
+     * Edge case: for a while loop, the initial GOTO and LOOPHEAD following it
+     * may be in different chunks. In that case bytecodeInChunk(head) may be
+     * true, but we didn't track this loop, since the GOTO is in the previous
+     * chunk.
+     */
+    if (!loop) {
+        JS_ASSERT(chunkIndex > 0);
+        JS_ASSERT(head - outerScript->code == outerChunk.begin);
+        return true;
+    }
+
+    /*
      * We're done processing the current loop. Every loop has exactly one backedge
      * at the end ('continue' statements are forward jumps to the loop test),
      * and after jumpAndRun'ing on that edge we can pop it from the frame.
      */
     JS_ASSERT(loop && loop->headOffset() == uint32_t(head - script_->code));
 
     jsbytecode *entryTarget = script_->code + loop->entryOffset();