зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1261826 part 8 - Add JSOP_JUMPTARGET opcode. r=jandem,jorendorff,shu
This commit is contained in:
Родитель
d02bd6369a
Коммит
e037534d4b
|
@ -331,6 +331,8 @@ bool
|
|||
BytecodeEmitter::emitJumpTarget(JumpTarget* target)
|
||||
{
|
||||
target->offset = offset();
|
||||
if (!emit1(JSOP_JUMPTARGET))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -402,6 +404,8 @@ BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target)
|
|||
{
|
||||
MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset());
|
||||
MOZ_ASSERT(0 <= target.offset && target.offset <= offset());
|
||||
MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),
|
||||
BytecodeIsJumpTarget(JSOp(*code(target.offset))));
|
||||
jump.patchAll(code(0), target);
|
||||
}
|
||||
|
||||
|
|
|
@ -1260,12 +1260,16 @@ BaselineCompiler::emit_JSOP_POS()
|
|||
bool
|
||||
BaselineCompiler::emit_JSOP_LOOPHEAD()
|
||||
{
|
||||
if (!emit_JSOP_JUMPTARGET())
|
||||
return false;
|
||||
return emitInterruptCheck();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_LOOPENTRY()
|
||||
{
|
||||
if (!emit_JSOP_JUMPTARGET())
|
||||
return false;
|
||||
frame.syncStack(0);
|
||||
return emitWarmUpCounterIncrement(LoopEntryCanIonOsr(pc));
|
||||
}
|
||||
|
@ -3345,6 +3349,9 @@ BaselineCompiler::emit_JSOP_THROWING()
|
|||
bool
|
||||
BaselineCompiler::emit_JSOP_TRY()
|
||||
{
|
||||
if (!emit_JSOP_JUMPTARGET())
|
||||
return false;
|
||||
|
||||
// Ionmonkey can't inline function with JSOP_TRY.
|
||||
script->setUninlineable();
|
||||
return true;
|
||||
|
@ -3776,6 +3783,8 @@ BaselineCompiler::emit_JSOP_ISNOITER()
|
|||
bool
|
||||
BaselineCompiler::emit_JSOP_ENDITER()
|
||||
{
|
||||
if (!emit_JSOP_JUMPTARGET())
|
||||
return false;
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
ICIteratorClose_Fallback::Compiler compiler(cx);
|
||||
|
@ -4326,3 +4335,9 @@ BaselineCompiler::emit_JSOP_DEBUGCHECKSELFHOSTED()
|
|||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_JUMPTARGET()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -223,7 +223,8 @@ namespace jit {
|
|||
_(JSOP_INITHIDDENELEM_GETTER) \
|
||||
_(JSOP_INITHIDDENELEM_SETTER) \
|
||||
_(JSOP_CHECKOBJCOERCIBLE) \
|
||||
_(JSOP_DEBUGCHECKSELFHOSTED)
|
||||
_(JSOP_DEBUGCHECKSELFHOSTED) \
|
||||
_(JSOP_JUMPTARGET)
|
||||
|
||||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
|
|
|
@ -1645,6 +1645,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_NOP_DESTRUCTURING:
|
||||
case JSOP_LINENO:
|
||||
case JSOP_LOOPENTRY:
|
||||
case JSOP_JUMPTARGET:
|
||||
return true;
|
||||
|
||||
case JSOP_LABEL:
|
||||
|
@ -3006,7 +3007,8 @@ IonBuilder::processContinue(JSOp op)
|
|||
CFGState* found = nullptr;
|
||||
jsbytecode* target = pc + GetJumpOffset(pc);
|
||||
for (size_t i = loops_.length() - 1; i < loops_.length(); i--) {
|
||||
if (loops_[i].continuepc == target ||
|
||||
// +1 to skip JSOP_JUMPTARGET.
|
||||
if (loops_[i].continuepc == target + 1 ||
|
||||
EffectiveContinue(loops_[i].continuepc) == target)
|
||||
{
|
||||
found = &cfgStack_[loops_[i].cfgEntry];
|
||||
|
@ -4071,7 +4073,8 @@ IonBuilder::jsop_condswitch()
|
|||
jssrcnote* caseSn = info().getNote(gsn, curCase);
|
||||
MOZ_ASSERT(caseSn && SN_TYPE(caseSn) == SRC_NEXTCASE);
|
||||
ptrdiff_t off = GetSrcNoteOffset(caseSn, 0);
|
||||
curCase = off ? curCase + off : GetNextPc(curCase);
|
||||
MOZ_ASSERT_IF(off == 0, JSOp(*GetNextPc(curCase)) == JSOP_JUMPTARGET);
|
||||
curCase = off ? curCase + off : GetNextPc(GetNextPc(curCase));
|
||||
MOZ_ASSERT(pc < curCase && curCase <= exitpc);
|
||||
|
||||
// Count non-aliased cases.
|
||||
|
@ -4151,7 +4154,8 @@ IonBuilder::processCondSwitchCase(CFGState& state)
|
|||
// Fetch the following case in which we will continue.
|
||||
jssrcnote* sn = info().getNote(gsn, pc);
|
||||
ptrdiff_t off = GetSrcNoteOffset(sn, 0);
|
||||
jsbytecode* casePc = off ? pc + off : GetNextPc(pc);
|
||||
MOZ_ASSERT_IF(off == 0, JSOp(*GetNextPc(pc)) == JSOP_JUMPTARGET);
|
||||
jsbytecode* casePc = off ? pc + off : GetNextPc(GetNextPc(pc));
|
||||
bool caseIsDefault = JSOp(*casePc) == JSOP_DEFAULT;
|
||||
MOZ_ASSERT(JSOp(*casePc) == JSOP_CASE || caseIsDefault);
|
||||
|
||||
|
|
|
@ -529,6 +529,14 @@ BytecodeParser::parse()
|
|||
continue;
|
||||
}
|
||||
|
||||
// On a jump target, we reload the offsetStack saved for the current
|
||||
// bytecode, as it contains either the original offset stack, or the
|
||||
// merged offset stack.
|
||||
if (BytecodeIsJumpTarget(op)) {
|
||||
for (uint32_t n = 0; n < code->stackDepth; ++n)
|
||||
offsetStack[n] = code->offsetStack[n];
|
||||
}
|
||||
|
||||
if (code->parsed) {
|
||||
// No need to reparse.
|
||||
continue;
|
||||
|
|
|
@ -431,6 +431,21 @@ BytecodeFallsThrough(JSOp op)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
BytecodeIsJumpTarget(JSOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case JSOP_JUMPTARGET:
|
||||
case JSOP_LOOPHEAD:
|
||||
case JSOP_LOOPENTRY:
|
||||
case JSOP_ENDITER:
|
||||
case JSOP_TRY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class SrcNoteLineScanner
|
||||
{
|
||||
/* offset of the current JSOp in the bytecode */
|
||||
|
|
|
@ -3072,11 +3072,13 @@ JSScript::assertValidJumpTargets() const
|
|||
if (IsJumpOpcode(JSOp(*pc))) {
|
||||
jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
|
||||
MOZ_ASSERT(mainEntry <= target && target < end);
|
||||
MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*target)));
|
||||
|
||||
// Check fallthrough of conditional jump instructions.
|
||||
if (BytecodeFallsThrough(JSOp(*pc))) {
|
||||
jsbytecode* fallthrough = GetNextPc(pc);
|
||||
MOZ_ASSERT(mainEntry <= fallthrough && fallthrough < end);
|
||||
MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*fallthrough)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3087,6 +3089,7 @@ JSScript::assertValidJumpTargets() const
|
|||
|
||||
// Default target.
|
||||
MOZ_ASSERT(mainEntry <= pc + len && pc + len < end);
|
||||
MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*(pc + len))));
|
||||
|
||||
pc2 += JUMP_OFFSET_LEN;
|
||||
int32_t low = GET_JUMP_OFFSET(pc2);
|
||||
|
@ -3098,6 +3101,7 @@ JSScript::assertValidJumpTargets() const
|
|||
int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
|
||||
// Case (i + low)
|
||||
MOZ_ASSERT_IF(off, mainEntry <= pc + off && pc + off < end);
|
||||
MOZ_ASSERT_IF(off, BytecodeIsJumpTarget(JSOp(*(pc + off))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3114,6 +3118,7 @@ JSScript::assertValidJumpTargets() const
|
|||
|
||||
jsbytecode* tryTarget = tryStart + tn->length;
|
||||
MOZ_ASSERT(mainEntry <= tryTarget && tryTarget < end);
|
||||
MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*tryTarget)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,19 +252,20 @@ LCovSource::writeScript(JSScript* script)
|
|||
// Get the low and high from the tableswitch
|
||||
int32_t low = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN * 1);
|
||||
int32_t high = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN * 2);
|
||||
int32_t numCases = high - low + 1;
|
||||
MOZ_ASSERT(high > low);
|
||||
size_t numCases = high - low + 1;
|
||||
jsbytecode* jumpTable = pc + JUMP_OFFSET_LEN * 3;
|
||||
|
||||
jsbytecode* firstcasepc = exitpc;
|
||||
for (int j = 0; j < numCases; j++) {
|
||||
for (size_t j = 0; j < numCases; j++) {
|
||||
jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
|
||||
if (testpc < firstcasepc)
|
||||
firstcasepc = testpc;
|
||||
}
|
||||
|
||||
jsbytecode* lastcasepc = firstcasepc;
|
||||
uint64_t allCaseHits = 0;
|
||||
for (int i = 0; i < numCases; i++) {
|
||||
uint64_t fallsThroughHits = 0;
|
||||
for (size_t i = 0; i < numCases; i++) {
|
||||
jsbytecode* casepc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * i);
|
||||
// The case is not present, and jumps to the default pc if used.
|
||||
if (casepc == pc)
|
||||
|
@ -272,7 +273,7 @@ LCovSource::writeScript(JSScript* script)
|
|||
|
||||
// PCs might not be in increasing order of case indexes.
|
||||
lastcasepc = firstcasepc - 1;
|
||||
for (int j = 0; j < numCases; j++) {
|
||||
for (size_t j = 0; j < numCases; j++) {
|
||||
jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
|
||||
if (lastcasepc < testpc && testpc < casepc)
|
||||
lastcasepc = testpc;
|
||||
|
@ -287,16 +288,17 @@ LCovSource::writeScript(JSScript* script)
|
|||
caseHits = counts->numExec();
|
||||
|
||||
// Remove fallthrough.
|
||||
fallsThroughHits = 0;
|
||||
if (casepc != firstcasepc) {
|
||||
jsbytecode* endpc = lastcasepc;
|
||||
while (GetNextPc(endpc) < casepc)
|
||||
endpc = GetNextPc(endpc);
|
||||
|
||||
if (BytecodeFallsThrough(JSOp(*endpc)))
|
||||
caseHits -= script->getHitCount(endpc);
|
||||
fallsThroughHits = script->getHitCount(endpc);
|
||||
}
|
||||
|
||||
allCaseHits += caseHits;
|
||||
caseHits -= fallsThroughHits;
|
||||
}
|
||||
|
||||
outBRDA_.printf("BRDA:%d,%d,%d,", lineno, branchId, i);
|
||||
|
@ -315,14 +317,30 @@ LCovSource::writeScript(JSScript* script)
|
|||
uint64_t defaultHits = 0;
|
||||
|
||||
if (sc) {
|
||||
// Look for the last case entry before the default pc.
|
||||
lastcasepc = firstcasepc - 1;
|
||||
for (size_t j = 0; j < numCases; j++) {
|
||||
jsbytecode* testpc = pc + GET_JUMP_OFFSET(jumpTable + JUMP_OFFSET_LEN * j);
|
||||
if (lastcasepc < testpc && testpc < defaultpc)
|
||||
lastcasepc = testpc;
|
||||
}
|
||||
|
||||
// Look if the last case entry fallthrough to the default case,
|
||||
// in which case we have to remove the number of fallthrough
|
||||
// hits out of the default case hits.
|
||||
if (lastcasepc != pc) {
|
||||
jsbytecode* endpc = lastcasepc;
|
||||
while (GetNextPc(endpc) < defaultpc)
|
||||
endpc = GetNextPc(endpc);
|
||||
|
||||
if (BytecodeFallsThrough(JSOp(*endpc)))
|
||||
fallsThroughHits = script->getHitCount(endpc);
|
||||
}
|
||||
|
||||
const PCCounts* counts = sc->maybeGetPCCounts(script->pcToOffset(defaultpc));
|
||||
if (counts)
|
||||
defaultHits = counts->numExec();
|
||||
|
||||
// Note: currently we do not track edges, so we might have
|
||||
// false-positive if we have any throw / return inside some
|
||||
// of the case statements.
|
||||
defaultHits -= allCaseHits;
|
||||
defaultHits -= fallsThroughHits;
|
||||
}
|
||||
|
||||
outBRDA_.printf("BRDA:%d,%d,%d,", lineno, branchId, numCases);
|
||||
|
|
|
@ -5398,14 +5398,19 @@ class BytecodeRangeWithPosition : private BytecodeRange
|
|||
|
||||
BytecodeRangeWithPosition(JSContext* cx, JSScript* script)
|
||||
: BytecodeRange(cx, script), lineno(script->lineno()), column(0),
|
||||
sn(script->notes()), snpc(script->code()), isEntryPoint(false)
|
||||
sn(script->notes()), snpc(script->code()), isEntryPoint(false),
|
||||
wasArtifactEntryPoint(false)
|
||||
{
|
||||
if (!SN_IS_TERMINATOR(sn))
|
||||
snpc += SN_DELTA(sn);
|
||||
updatePosition();
|
||||
while (frontPC() != script->main())
|
||||
popFront();
|
||||
isEntryPoint = true;
|
||||
|
||||
if (frontOpcode() != JSOP_JUMPTARGET)
|
||||
isEntryPoint = true;
|
||||
else
|
||||
wasArtifactEntryPoint = true;
|
||||
}
|
||||
|
||||
void popFront() {
|
||||
|
@ -5414,6 +5419,19 @@ class BytecodeRangeWithPosition : private BytecodeRange
|
|||
isEntryPoint = false;
|
||||
else
|
||||
updatePosition();
|
||||
|
||||
// The following conditions are handling artifacts introduced by the
|
||||
// bytecode emitter, such that we do not add breakpoints on empty
|
||||
// statements of the source code of the user.
|
||||
if (wasArtifactEntryPoint) {
|
||||
wasArtifactEntryPoint = false;
|
||||
isEntryPoint = true;
|
||||
}
|
||||
|
||||
if (isEntryPoint && frontOpcode() == JSOP_JUMPTARGET) {
|
||||
wasArtifactEntryPoint = isEntryPoint;
|
||||
isEntryPoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t frontLineNumber() const { return lineno; }
|
||||
|
@ -5463,6 +5481,7 @@ class BytecodeRangeWithPosition : private BytecodeRange
|
|||
jssrcnote* sn;
|
||||
jsbytecode* snpc;
|
||||
bool isEntryPoint;
|
||||
bool wasArtifactEntryPoint;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -5579,13 +5598,23 @@ class FlowGraphSummary {
|
|||
size_t prevColumn = 0;
|
||||
JSOp prevOp = JSOP_NOP;
|
||||
for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
|
||||
size_t lineno = r.frontLineNumber();
|
||||
size_t column = r.frontColumnNumber();
|
||||
size_t lineno = prevLineno;
|
||||
size_t column = prevColumn;
|
||||
JSOp op = r.frontOpcode();
|
||||
|
||||
if (FlowsIntoNext(prevOp))
|
||||
addEdge(prevLineno, prevColumn, r.frontOffset());
|
||||
|
||||
if (BytecodeIsJumpTarget(op)) {
|
||||
lineno = entries_[r.frontOffset()].lineno();
|
||||
column = entries_[r.frontOffset()].column();
|
||||
}
|
||||
|
||||
if (r.frontIsEntryPoint()) {
|
||||
lineno = r.frontLineNumber();
|
||||
column = r.frontColumnNumber();
|
||||
}
|
||||
|
||||
if (CodeSpec[op].type() == JOF_JUMP) {
|
||||
addEdge(lineno, column, r.frontOffset() + GET_JUMP_OFFSET(r.frontPC()));
|
||||
} else if (op == JSOP_TABLESWITCH) {
|
||||
|
@ -5606,6 +5635,22 @@ class FlowGraphSummary {
|
|||
addEdge(lineno, column, target);
|
||||
pc += step;
|
||||
}
|
||||
} else if (op == JSOP_TRY) {
|
||||
// As there is no literal incoming edge into the catch block, we
|
||||
// make a fake one by copying the JSOP_TRY location, as-if this
|
||||
// was an incoming edge of the catch block. This is needed
|
||||
// because we only report offsets of entry points which have
|
||||
// valid incoming edges.
|
||||
JSTryNote* tn = script->trynotes()->vector;
|
||||
JSTryNote* tnlimit = tn + script->trynotes()->length;
|
||||
for (; tn < tnlimit; tn++) {
|
||||
uint32_t startOffset = script->mainOffset() + tn->start;
|
||||
if (startOffset == r.frontOffset() + 1) {
|
||||
uint32_t catchOffset = startOffset + tn->length;
|
||||
if (tn->kind == JSTRY_CATCH || tn->kind == JSTRY_FINALLY)
|
||||
addEdge(lineno, column, catchOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prevLineno = lineno;
|
||||
|
|
|
@ -1811,6 +1811,7 @@ CASE(JSOP_UNUSED222)
|
|||
CASE(JSOP_UNUSED223)
|
||||
CASE(JSOP_CONDSWITCH)
|
||||
CASE(JSOP_TRY)
|
||||
CASE(JSOP_JUMPTARGET)
|
||||
{
|
||||
MOZ_ASSERT(CodeSpec[*REGS.pc].length == 1);
|
||||
ADVANCE_AND_DISPATCH(1);
|
||||
|
|
|
@ -2180,14 +2180,23 @@
|
|||
* Operands:
|
||||
* Stack: =>
|
||||
*/ \
|
||||
macro(JSOP_NOP_DESTRUCTURING, 229, "nop-destructuring", NULL, 1, 0, 0, JOF_BYTE)
|
||||
macro(JSOP_NOP_DESTRUCTURING, 229, "nop-destructuring", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* This opcode is a no-op and it indicates the location of a jump
|
||||
* instruction target. Some other opcodes act as jump targets, such as
|
||||
* LOOPENTRY, as well as all which are matched by BytecodeIsJumpTarget
|
||||
* function.
|
||||
* Category: Other
|
||||
* Operands:
|
||||
* Stack: =>
|
||||
*/ \
|
||||
macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)
|
||||
|
||||
/*
|
||||
* In certain circumstances it may be useful to "pad out" the opcode space to
|
||||
* a power of two. Use this macro to do so.
|
||||
*/
|
||||
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
|
||||
macro(230) \
|
||||
macro(231) \
|
||||
macro(232) \
|
||||
macro(233) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче