diff --git a/js/src/frontend/SourceNotes.h b/js/src/frontend/SourceNotes.h index d09db7998521..b9958ba5b6c5 100644 --- a/js/src/frontend/SourceNotes.h +++ b/js/src/frontend/SourceNotes.h @@ -34,6 +34,44 @@ namespace js { * NB: the js_SrcNoteSpec array in BytecodeEmitter.cpp is indexed by this * enum, so its initializers need to match the order here. */ + +class SrcNote { + public: + // SRC_TABLESWITCH: Source note for JSOP_TABLESWITCH. + class TableSwitch { + public: + enum Fields { + // The offset of the end of switch (the first non-JumpTarget op + // after switch) from JSOP_TABLESWITCH. + EndOffset, + Count + }; + }; + // SRC_CONDSWITCH: Source note for JSOP_CONDSWITCH. + class CondSwitch { + public: + enum Fields { + // The offset of the end of switch (the first non-JumpTarget op + // after switch) from JSOP_CONDSWITCH. + EndOffset, + + // The offset of JSOP_CASE for the first case from JSOP_CONDSWITCH. + FirstCaseOffset, + Count + }; + }; + // SRC_NEXTCASE: Source note for JSOP_CASE in a JSOP_CONDSWITCH. + class NextCase { + public: + enum Fields { + // Offset of the next JSOP_CASE from this JSOP_CASE. This field is + // 0 if this is the last JSOP_CASE. + NextCaseOffset, + Count + }; + }; +}; + #define FOR_EACH_SRC_NOTE_TYPE(M) \ M(SRC_NULL, "null", 0) /* Terminates a note vector. */ \ M(SRC_IF, "if", 0) /* JSOP_IFEQ bytecode is from an if-then. */ \ @@ -50,11 +88,9 @@ namespace js { M(SRC_BREAK, "break", 0) /* JSOP_GOTO is a break. */ \ M(SRC_BREAK2LABEL, "break2label", 0) /* JSOP_GOTO for 'break label'. */ \ M(SRC_SWITCHBREAK, "switchbreak", 0) /* JSOP_GOTO is a break in a switch. */ \ - M(SRC_TABLESWITCH, "tableswitch", 1) /* JSOP_TABLESWITCH; offset points to end of switch. */ \ - M(SRC_CONDSWITCH, "condswitch", 2) /* JSOP_CONDSWITCH; 1st offset points to end of switch, \ - 2nd points to first JSOP_CASE. */ \ - M(SRC_NEXTCASE, "nextcase", 1) /* Distance forward from one CASE in a CONDSWITCH to \ - the next. */ \ + M(SRC_TABLESWITCH, "tableswitch", SrcNote::TableSwitch::Count) \ + M(SRC_CONDSWITCH, "condswitch", SrcNote::CondSwitch::Count) \ + M(SRC_NEXTCASE, "nextcase", SrcNote::NextCase::Count) \ M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \ M(SRC_CLASS_SPAN, "class", 2) /* The starting and ending offsets for the class, used \ for toString correctness for default ctors. */ \ diff --git a/js/src/frontend/SwitchEmitter.cpp b/js/src/frontend/SwitchEmitter.cpp index 9f8723bb9310..18e6c214497d 100644 --- a/js/src/frontend/SwitchEmitter.cpp +++ b/js/src/frontend/SwitchEmitter.cpp @@ -233,8 +233,11 @@ SwitchEmitter::emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault) if (state_ == State::Case) { // Link the last JSOP_CASE's SRC_NEXTCASE to current JSOP_CASE for the // benefit of IonBuilder. - if (!bce_->setSrcNoteOffset(caseNoteIndex_, 0, bce_->offset() - lastCaseOffset_)) + if (!bce_->setSrcNoteOffset(caseNoteIndex_, SrcNote::NextCase::NextCaseOffset, + bce_->offset() - lastCaseOffset_)) + { return false; + } } if (!bce_->newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex_)) @@ -392,8 +395,14 @@ SwitchEmitter::emitEnd() } // Set the SRC_SWITCH note's offset operand to tell end of switch. - if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->lastNonJumpTargetOffset() - top_)) + // This code is shared between table switch and cond switch. + static_assert(unsigned(SrcNote::TableSwitch::EndOffset) == unsigned(SrcNote::CondSwitch::EndOffset), + "{TableSwitch,CondSwitch}::EndOffset should be same"); + if (!bce_->setSrcNoteOffset(noteIndex_, SrcNote::TableSwitch::EndOffset, + bce_->lastNonJumpTargetOffset() - top_)) + { return false; + } if (kind_ == Kind::Table) { // Skip over the already-initialized switch bounds. diff --git a/js/src/jit/IonControlFlow.cpp b/js/src/jit/IonControlFlow.cpp index 7b5d8c0eae2d..78f35b379575 100644 --- a/js/src/jit/IonControlFlow.cpp +++ b/js/src/jit/IonControlFlow.cpp @@ -1118,8 +1118,8 @@ ControlFlowGenerator::processCondSwitch() MOZ_ASSERT(SN_TYPE(sn) == SRC_CONDSWITCH); // Get the exit pc - jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, 0); - jsbytecode* firstCase = pc + GetSrcNoteOffset(sn, 1); + jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, SrcNote::CondSwitch::EndOffset); + jsbytecode* firstCase = pc + GetSrcNoteOffset(sn, SrcNote::CondSwitch::FirstCaseOffset); // Iterate all cases in the conditional switch. // - Stop at the default case. (always emitted after the last case) @@ -1134,7 +1134,7 @@ ControlFlowGenerator::processCondSwitch() // Fetch the next case. jssrcnote* caseSn = GetSrcNote(gsn, script, curCase); MOZ_ASSERT(caseSn && SN_TYPE(caseSn) == SRC_NEXTCASE); - ptrdiff_t off = GetSrcNoteOffset(caseSn, 0); + ptrdiff_t off = GetSrcNoteOffset(caseSn, SrcNote::NextCase::NextCaseOffset); MOZ_ASSERT_IF(off == 0, JSOp(*GetNextPc(curCase)) == JSOP_JUMPTARGET); curCase = off ? curCase + off : GetNextPc(GetNextPc(curCase)); MOZ_ASSERT(pc < curCase && curCase <= exitpc); @@ -1167,7 +1167,7 @@ ControlFlowGenerator::processCondSwitch() defaultIdx++; jssrcnote* caseSn = GetSrcNote(gsn, script, curCase); - ptrdiff_t off = GetSrcNoteOffset(caseSn, 0); + ptrdiff_t off = GetSrcNoteOffset(caseSn, SrcNote::NextCase::NextCaseOffset); curCase = off ? curCase + off : GetNextPc(GetNextPc(curCase)); lastTarget = curTarget; } @@ -1223,7 +1223,7 @@ ControlFlowGenerator::processCondSwitchCase(CFGState& state) // Fetch the following case in which we will continue. jssrcnote* sn = GetSrcNote(gsn, script, pc); - ptrdiff_t off = GetSrcNoteOffset(sn, 0); + ptrdiff_t off = GetSrcNoteOffset(sn, SrcNote::NextCase::NextCaseOffset); MOZ_ASSERT_IF(off == 0, JSOp(*GetNextPc(pc)) == JSOP_JUMPTARGET); jsbytecode* casePc = off ? pc + off : GetNextPc(GetNextPc(pc)); bool nextIsDefault = JSOp(*casePc) == JSOP_DEFAULT; @@ -1849,7 +1849,7 @@ ControlFlowGenerator::processTableSwitch(JSOp op, jssrcnote* sn) MOZ_ASSERT(SN_TYPE(sn) == SRC_TABLESWITCH); // Get the default and exit pc - jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, 0); + jsbytecode* exitpc = pc + GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset); jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc); MOZ_ASSERT(defaultpc > pc && defaultpc <= exitpc); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 4b2a10537440..0faacf76f62c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2757,16 +2757,26 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) break; case SRC_WHILE: - case SRC_NEXTCASE: if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0)))) return false; break; + case SRC_NEXTCASE: + if (!sp->jsprintf(" next case offset %u", + unsigned(GetSrcNoteOffset(sn, SrcNote::NextCase::NextCaseOffset)))) + { + return false; + } + break; + case SRC_TABLESWITCH: { mozilla::DebugOnly op = JSOp(script->code()[offset]); MOZ_ASSERT(op == JSOP_TABLESWITCH); - if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0)))) + if (!sp->jsprintf(" end offset %u", + unsigned(GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset)))) + { return false; + } UpdateSwitchTableBounds(cx, script, offset, &switchTableStart, &switchTableEnd); break; @@ -2774,9 +2784,14 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) case SRC_CONDSWITCH: { mozilla::DebugOnly op = JSOp(script->code()[offset]); MOZ_ASSERT(op == JSOP_CONDSWITCH); - if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0)))) + if (!sp->jsprintf(" end offset %u", + unsigned(GetSrcNoteOffset(sn, SrcNote::CondSwitch::EndOffset)))) + { return false; - if (unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1)) { + } + if (unsigned caseOff = + unsigned(GetSrcNoteOffset(sn, SrcNote::CondSwitch::FirstCaseOffset))) + { if (!sp->jsprintf(" first case offset %u", caseOff)) return false; } diff --git a/js/src/vm/CodeCoverage.cpp b/js/src/vm/CodeCoverage.cpp index df877acc2112..47063710aafb 100644 --- a/js/src/vm/CodeCoverage.cpp +++ b/js/src/vm/CodeCoverage.cpp @@ -200,7 +200,7 @@ LCovSource::writeScript(JSScript* script) else if (type == SRC_NEWLINE) lineno++; else if (type == SRC_TABLESWITCH) - tableswitchExitOffset = GetSrcNoteOffset(sn, 0); + tableswitchExitOffset = GetSrcNoteOffset(sn, SrcNote::TableSwitch::EndOffset); sn = SN_NEXT(sn); snpc += SN_DELTA(sn);