Bug 1274588 part 1.0 - Alias consecutive jump targets. r=jorendorff
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 02 Jun 2016 13:41:04 +0000
changeset 339173 0792b0daef2adbd8af9454fae418aa771726a95e
parent 339172 cd714f1275bedda2307f5ffbcbff99b2550bf180
child 339174 32eb8332d6185ecaaddd2a016d782d1c12227766
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1274588
milestone49.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 1274588 part 1.0 - Alias consecutive jump targets. r=jorendorff
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/jit/IonBuilder.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -325,17 +325,26 @@ BytecodeEmitter::emitN(JSOp op, size_t e
     if (offset)
         *offset = off;
     return true;
 }
 
 bool
 BytecodeEmitter::emitJumpTarget(JumpTarget* target)
 {
-    target->offset = offset();
+    ptrdiff_t off = offset();
+
+    // Alias consecutive jump targets.
+    if (off == current->lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
+        target->offset = current->lastTarget.offset;
+        return true;
+    }
+
+    target->offset = off;
+    current->lastTarget.offset = off;
     if (!emit1(JSOP_JUMPTARGET))
         return false;
     return true;
 }
 
 void
 JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
 {
@@ -3496,17 +3505,17 @@ BytecodeEmitter::emitSwitch(ParseNode* p
     } else {
         MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
         pc = code(top.offset);
         SET_JUMP_OFFSET(pc, defaultOffset.offset - top.offset);
         pc += JUMP_OFFSET_LEN;
     }
 
     // Set the SRC_SWITCH note's offset operand to tell end of switch.
-    if (!setSrcNoteOffset(noteIndex, 0, offset() - top.offset))
+    if (!setSrcNoteOffset(noteIndex, 0, lastNonJumpTargetOffset() - top.offset))
         return false;
 
     if (switchOp == JSOP_TABLESWITCH) {
         // Skip over the already-initialized switch bounds.
         pc += 2 * JUMP_OFFSET_LEN;
 
         // Fill in the jump table, if there is one.
         for (uint32_t i = 0; i < tableLength; i++) {
@@ -7975,17 +7984,17 @@ BytecodeEmitter::emitLabeledStatement(co
     JumpTarget stmtStart{ offset() };
     pushStatement(&stmtInfo, StmtType::LABEL, stmtStart);
     stmtInfo.label = pn->label();
 
     if (!emitTree(pn->statement()))
         return false;
 
     /* Patch the JSOP_LABEL offset. */
-    JumpTarget brk{ offset() };
+    JumpTarget brk{ lastNonJumpTargetOffset() };
     patchJumpsToTarget(top, brk);
 
     if (!popStatement())
         return false;
     return true;
 }
 
 bool
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -203,19 +203,21 @@ struct BytecodeEmitter
 
     struct EmitSection {
         BytecodeVector code;        /* bytecode */
         SrcNotesVector notes;       /* source notes, see below */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
         uint32_t    currentLine;    /* line number for tree-based srcnote gen */
         uint32_t    lastColumn;     /* zero-based column index on currentLine of
                                        last SRC_COLSPAN-annotated opcode */
+        JumpTarget lastTarget;      // Last jump target emitted.
 
         EmitSection(ExclusiveContext* cx, uint32_t lineNum)
-          : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0)
+          : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0),
+            lastTarget{ -1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH) }
         {}
     };
     EmitSection prologue, main, *current;
 
     /* the parser */
     Parser<FullParseHandler>* const parser;
 
     HandleScript    evalCaller;     /* scripted caller info for eval and dbgapi */
@@ -369,16 +371,29 @@ struct BytecodeEmitter
     void switchToPrologue() { current = &prologue; }
     bool inPrologue() const { return current == &prologue; }
 
     SrcNotesVector& notes() const { return current->notes; }
     ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
     unsigned currentLine() const { return current->currentLine; }
     unsigned lastColumn() const { return current->lastColumn; }
 
+    // Check if the last emitted opcode is a jump target.
+    bool lastOpcodeIsJumpTarget() const {
+        return offset() - current->lastTarget.offset == ptrdiff_t(JSOP_JUMPTARGET_LENGTH);
+    }
+
+    // JumpTarget should not be part of the emitted statement, as they can be
+    // aliased by multiple statements. If we included the jump target as part of
+    // the statement we might have issues where the enclosing statement might
+    // not contain all the opcodes of the enclosed statements.
+    ptrdiff_t lastNonJumpTargetOffset() const {
+        return lastOpcodeIsJumpTarget() ? current->lastTarget.offset : offset();
+    }
+
     void setFunctionBodyEndPos(TokenPos pos) {
         functionBodyEndPos = pos.end;
         functionBodyEndPosSet = true;
     }
 
     bool reportError(ParseNode* pn, unsigned errorNumber, ...);
     bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
     bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1456,16 +1456,17 @@ IonBuilder::traverseBytecode()
 
         for (;;) {
             if (!alloc().ensureBallast())
                 return false;
 
             // Check if we've hit an expected join point or edge in the bytecode.
             // Leaving one control structure could place us at the edge of another,
             // thus |while| instead of |if| so we don't skip any opcodes.
+            MOZ_ASSERT_IF(!cfgStack_.empty(), cfgStack_.back().stopAt >= pc);
             if (!cfgStack_.empty() && cfgStack_.back().stopAt == pc) {
                 ControlStatus status = processCfgStack();
                 if (status == ControlStatus_Error)
                     return false;
                 if (status == ControlStatus_Abort)
                     return abort("Aborted while processing control flow");
                 if (!current)
                     return true;