Bug 1143704 part 7 - Move more functions into BytecodeEmitter. r=bhackett

This commit is contained in:
Jan de Mooij 2015-03-21 12:54:18 +01:00
parent 71389afa0d
commit cf9bd1071f
2 changed files with 118 additions and 116 deletions

View File

@ -425,14 +425,13 @@ ReportStatementTooLarge(TokenStream &ts, StmtInfoBCE *topStmt)
* Emit a backpatch op with offset pointing to the previous jump of this type, * Emit a backpatch op with offset pointing to the previous jump of this type,
* so that we can walk back up the chain fixing up the op and jump offset. * so that we can walk back up the chain fixing up the op and jump offset.
*/ */
static bool bool
EmitBackPatchOp(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t *lastp) BytecodeEmitter::emitBackPatchOp(ptrdiff_t *lastp)
{ {
ptrdiff_t offset = bce->offset(); ptrdiff_t delta = offset() - *lastp;
ptrdiff_t delta = offset - *lastp; *lastp = offset();
*lastp = offset;
MOZ_ASSERT(delta > 0); MOZ_ASSERT(delta > 0);
return bce->emitJump(JSOP_BACKPATCH, delta) >= 0; return emitJump(JSOP_BACKPATCH, delta) >= 0;
} }
static inline unsigned static inline unsigned
@ -500,8 +499,8 @@ UpdateSourceCoordNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t offs
return true; return true;
} }
static bool bool
EmitLoopHead(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *nextpn) BytecodeEmitter::emitLoopHead(ParseNode *nextpn)
{ {
if (nextpn) { if (nextpn) {
/* /*
@ -512,64 +511,58 @@ EmitLoopHead(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST)); MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head) if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
nextpn = nextpn->pn_head; nextpn = nextpn->pn_head;
if (!UpdateSourceCoordNotes(cx, bce, nextpn->pn_pos.begin)) if (!UpdateSourceCoordNotes(cx, this, nextpn->pn_pos.begin))
return false; return false;
} }
return bce->emit1(JSOP_LOOPHEAD); return emit1(JSOP_LOOPHEAD);
} }
static bool bool
EmitLoopEntry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *nextpn) BytecodeEmitter::emitLoopEntry(ParseNode *nextpn)
{ {
if (nextpn) { if (nextpn) {
/* Update the line number, as for LOOPHEAD. */ /* Update the line number, as for LOOPHEAD. */
MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST)); MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head) if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
nextpn = nextpn->pn_head; nextpn = nextpn->pn_head;
if (!UpdateSourceCoordNotes(cx, bce, nextpn->pn_pos.begin)) if (!UpdateSourceCoordNotes(cx, this, nextpn->pn_pos.begin))
return false; return false;
} }
LoopStmtInfo *loop = LoopStmtInfo::fromStmtInfo(bce->topStmt); LoopStmtInfo *loop = LoopStmtInfo::fromStmtInfo(topStmt);
MOZ_ASSERT(loop->loopDepth > 0); MOZ_ASSERT(loop->loopDepth > 0);
uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loop->loopDepth, loop->canIonOsr); uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loop->loopDepth, loop->canIonOsr);
return bce->emit2(JSOP_LOOPENTRY, loopDepthAndFlags); return emit2(JSOP_LOOPENTRY, loopDepthAndFlags);
} }
/* void
* If op is JOF_TYPESET (see the type barriers comment in TypeInference.h), BytecodeEmitter::checkTypeSet(JSOp op)
* reserve a type set to store its result.
*/
static inline void
CheckTypeSet(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
{ {
if (js_CodeSpec[op].format & JOF_TYPESET) { if (js_CodeSpec[op].format & JOF_TYPESET) {
if (bce->typesetCount < UINT16_MAX) if (typesetCount < UINT16_MAX)
bce->typesetCount++; typesetCount++;
} }
} }
/* bool
* Macro to emit a bytecode followed by a uint16_t immediate operand stored in BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t i)
* big-endian order. {
* MOZ_ASSERT(i <= UINT16_MAX);
* NB: We use cx and bce from our caller's lexical environment, and return if (!emit3(op, UINT16_HI(i), UINT16_LO(i)))
* false on error. return false;
*/ checkTypeSet(op);
#define EMIT_UINT16_IMM_OP(op, i) \ return true;
JS_BEGIN_MACRO \ }
if (!bce->emit3(op, UINT16_HI(i), UINT16_LO(i))) \
return false; \
CheckTypeSet(cx, bce, op); \
JS_END_MACRO
static bool bool
FlushPops(ExclusiveContext *cx, BytecodeEmitter *bce, int *npops) BytecodeEmitter::flushPops(int *npops)
{ {
MOZ_ASSERT(*npops != 0); MOZ_ASSERT(*npops != 0);
EMIT_UINT16_IMM_OP(JSOP_POPN, *npops); if (!emitUint16Operand(JSOP_POPN, *npops))
return false;
*npops = 0; *npops = 0;
return true; return true;
} }
@ -638,13 +631,13 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
{ {
int npops = 0; int npops = 0;
#define FLUSH_POPS() if (npops && !FlushPops(cx, bce, &npops)) return false #define FLUSH_POPS() if (npops && !bce->flushPops(&npops)) return false
for (StmtInfoBCE *stmt = bce->topStmt; stmt != toStmt; stmt = stmt->down) { for (StmtInfoBCE *stmt = bce->topStmt; stmt != toStmt; stmt = stmt->down) {
switch (stmt->type) { switch (stmt->type) {
case STMT_FINALLY: case STMT_FINALLY:
FLUSH_POPS(); FLUSH_POPS();
if (!EmitBackPatchOp(cx, bce, &stmt->gosubs())) if (!bce->emitBackPatchOp(&stmt->gosubs()))
return false; return false;
break; break;
@ -705,41 +698,36 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
} // anonymous namespace } // anonymous namespace
static ptrdiff_t ptrdiff_t
EmitGoto(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *toStmt, ptrdiff_t *lastp, BytecodeEmitter::emitGoto(StmtInfoBCE *toStmt, ptrdiff_t *lastp, SrcNoteType noteType)
SrcNoteType noteType = SRC_NULL)
{ {
NonLocalExitScope nle(cx, bce); NonLocalExitScope nle(cx, this);
if (!nle.prepareForNonLocalJump(toStmt)) if (!nle.prepareForNonLocalJump(toStmt))
return -1; return -1;
if (noteType != SRC_NULL) { if (noteType != SRC_NULL) {
if (NewSrcNote(cx, bce, noteType) < 0) if (NewSrcNote(cx, this, noteType) < 0)
return -1; return -1;
} }
if (!EmitBackPatchOp(cx, bce, lastp)) if (!emitBackPatchOp(lastp))
return -1; return -1;
return *lastp; return *lastp;
} }
static bool void
BackPatch(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t last, jsbytecode *target, jsbytecode op) BytecodeEmitter::backPatch(ptrdiff_t last, jsbytecode *target, jsbytecode op)
{ {
jsbytecode *pc, *stop; jsbytecode *pc = code(last);
ptrdiff_t delta, span; jsbytecode *stop = code(-1);
pc = bce->code(last);
stop = bce->code(-1);
while (pc != stop) { while (pc != stop) {
delta = GET_JUMP_OFFSET(pc); ptrdiff_t delta = GET_JUMP_OFFSET(pc);
span = target - pc; ptrdiff_t span = target - pc;
SET_JUMP_OFFSET(pc, span); SET_JUMP_OFFSET(pc, span);
*pc = op; *pc = op;
pc -= delta; pc -= delta;
} }
return true;
} }
#define SET_STATEMENT_TOP(stmt, top) \ #define SET_STATEMENT_TOP(stmt, top) \
@ -994,11 +982,9 @@ static bool
PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce) PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
{ {
StmtInfoBCE *stmt = bce->topStmt; StmtInfoBCE *stmt = bce->topStmt;
if (!stmt->isTrying() && if (!stmt->isTrying()) {
(!BackPatch(cx, bce, stmt->breaks, bce->code().end(), JSOP_GOTO) || bce->backPatch(stmt->breaks, bce->code().end(), JSOP_GOTO);
!BackPatch(cx, bce, stmt->continues, bce->code(stmt->update), JSOP_GOTO))) bce->backPatch(stmt->continues, bce->code(stmt->update), JSOP_GOTO);
{
return false;
} }
FinishPopStatement(bce); FinishPopStatement(bce);
@ -1053,7 +1039,7 @@ EmitIndex32(ExclusiveContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
code[0] = jsbytecode(op); code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index); SET_UINT32_INDEX(code, index);
UpdateDepth(cx, bce, offset); UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, op); bce->checkTypeSet(op);
return true; return true;
} }
@ -1071,7 +1057,7 @@ EmitIndexOp(ExclusiveContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
code[0] = jsbytecode(op); code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index); SET_UINT32_INDEX(code, index);
UpdateDepth(cx, bce, offset); UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, op); bce->checkTypeSet(op);
return true; return true;
} }
@ -1133,11 +1119,11 @@ EmitRegExp(ExclusiveContext *cx, uint32_t index, BytecodeEmitter *bce)
} }
/* /*
* To catch accidental misuse, EMIT_UINT16_IMM_OP/emit3 assert that they are * To catch accidental misuse, emitUint16Operand/emit3 assert that they are
* not used to unconditionally emit JSOP_GETLOCAL. Variable access should * not used to unconditionally emit JSOP_GETLOCAL. Variable access should
* instead be emitted using EmitVarOp. In special cases, when the caller * instead be emitted using EmitVarOp. In special cases, when the caller
* definitely knows that a given local slot is unaliased, this function may be * definitely knows that a given local slot is unaliased, this function may be
* used as a non-asserting version of EMIT_UINT16_IMM_OP. * used as a non-asserting version of emitUint16Operand.
*/ */
static bool static bool
EmitLocalOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, uint32_t slot) EmitLocalOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, uint32_t slot)
@ -1201,7 +1187,7 @@ EmitScopeCoordOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, ScopeCoord
pc += SCOPECOORD_HOPS_LEN; pc += SCOPECOORD_HOPS_LEN;
SET_SCOPECOORD_SLOT(pc, sc.slot()); SET_SCOPECOORD_SLOT(pc, sc.slot());
pc += SCOPECOORD_SLOT_LEN; pc += SCOPECOORD_SLOT_LEN;
CheckTypeSet(cx, bce, op); bce->checkTypeSet(op);
return true; return true;
} }
@ -2240,7 +2226,7 @@ EmitNewInit(ExclusiveContext *cx, BytecodeEmitter *bce, JSProtoKey key)
code[3] = 0; code[3] = 0;
code[4] = 0; code[4] = 0;
UpdateDepth(cx, bce, offset); UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, JSOP_NEWINIT); bce->checkTypeSet(JSOP_NEWINIT);
return true; return true;
} }
@ -2519,7 +2505,7 @@ EmitElemOpBase(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
{ {
if (!bce->emit1(op)) if (!bce->emit1(op))
return false; return false;
CheckTypeSet(cx, bce, op); bce->checkTypeSet(op);
return true; return true;
} }
@ -2596,7 +2582,7 @@ EmitNumberOp(ExclusiveContext *cx, double dval, BytecodeEmitter *bce)
u = (uint32_t)ival; u = (uint32_t)ival;
if (u < JS_BIT(16)) { if (u < JS_BIT(16)) {
EMIT_UINT16_IMM_OP(JSOP_UINT16, u); bce->emitUint16Operand(JSOP_UINT16, u);
} else if (u < JS_BIT(24)) { } else if (u < JS_BIT(24)) {
off = bce->emitN(JSOP_UINT24, 3); off = bce->emitN(JSOP_UINT24, 3);
if (off < 0) if (off < 0)
@ -3496,7 +3482,7 @@ EmitIteratorNext(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn=nullp
return false; return false;
if (!bce->emitCall(JSOP_CALL, 0, pn)) // ... RESULT if (!bce->emitCall(JSOP_CALL, 0, pn)) // ... RESULT
return false; return false;
CheckTypeSet(cx, bce, JSOP_CALL); bce->checkTypeSet(JSOP_CALL);
return true; return true;
} }
@ -3565,7 +3551,7 @@ EmitDestructuringOpsArrayHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Pars
ptrdiff_t off = bce->emitN(JSOP_NEWARRAY, 3); // ... OBJ? ITER ARRAY ptrdiff_t off = bce->emitN(JSOP_NEWARRAY, 3); // ... OBJ? ITER ARRAY
if (off < 0) if (off < 0)
return false; return false;
CheckTypeSet(cx, bce, JSOP_NEWARRAY); bce->checkTypeSet(JSOP_NEWARRAY);
jsbytecode *pc = bce->code(off); jsbytecode *pc = bce->code(off);
SET_UINT24(pc, 0); SET_UINT24(pc, 0);
@ -4517,7 +4503,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
// When a finally block is active (STMT_FINALLY in our parse context), // When a finally block is active (STMT_FINALLY in our parse context),
// non-local jumps (including jumps-over-catches) result in a GOSUB // non-local jumps (including jumps-over-catches) result in a GOSUB
// being written into the bytecode stream and fixed-up later (c.f. // being written into the bytecode stream and fixed-up later (c.f.
// EmitBackPatchOp and BackPatch). // emitBackPatchOp and backPatch).
// //
PushStatementBCE(bce, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, bce->offset()); PushStatementBCE(bce, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, bce->offset());
@ -4542,7 +4528,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
// GOSUB to finally, if present. // GOSUB to finally, if present.
if (pn->pn_kid3) { if (pn->pn_kid3) {
if (!EmitBackPatchOp(cx, bce, &stmtInfo.gosubs())) if (!bce->emitBackPatchOp(&stmtInfo.gosubs()))
return false; return false;
} }
@ -4552,7 +4538,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
// Emit jump over catch and/or finally. // Emit jump over catch and/or finally.
ptrdiff_t catchJump = -1; ptrdiff_t catchJump = -1;
if (!EmitBackPatchOp(cx, bce, &catchJump)) if (!bce->emitBackPatchOp(&catchJump))
return false; return false;
ptrdiff_t tryEnd = bce->offset(); ptrdiff_t tryEnd = bce->offset();
@ -4597,14 +4583,14 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
// gosub <finally>, if required. // gosub <finally>, if required.
if (pn->pn_kid3) { if (pn->pn_kid3) {
if (!EmitBackPatchOp(cx, bce, &stmtInfo.gosubs())) if (!bce->emitBackPatchOp(&stmtInfo.gosubs()))
return false; return false;
MOZ_ASSERT(bce->stackDepth == depth); MOZ_ASSERT(bce->stackDepth == depth);
} }
// Jump over the remaining catch blocks. This will get fixed // Jump over the remaining catch blocks. This will get fixed
// up to jump to after catch/finally. // up to jump to after catch/finally.
if (!EmitBackPatchOp(cx, bce, &catchJump)) if (!bce->emitBackPatchOp(&catchJump))
return false; return false;
// If this catch block had a guard clause, patch the guard jump to // If this catch block had a guard clause, patch the guard jump to
@ -4632,8 +4618,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (pn->pn_kid3) { if (pn->pn_kid3) {
// Fix up the gosubs that might have been emitted before non-local // Fix up the gosubs that might have been emitted before non-local
// jumps to the finally code. // jumps to the finally code.
if (!BackPatch(cx, bce, stmtInfo.gosubs(), bce->code().end(), JSOP_GOSUB)) bce->backPatch(stmtInfo.gosubs(), bce->code().end(), JSOP_GOSUB);
return false;
finallyStart = bce->offset(); finallyStart = bce->offset();
@ -4658,8 +4643,7 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false; return false;
// Fix up the end-of-try/catch jumps to come here. // Fix up the end-of-try/catch jumps to come here.
if (!BackPatch(cx, bce, catchJump, bce->code().end(), JSOP_GOTO)) bce->backPatch(catchJump, bce->code().end(), JSOP_GOTO);
return false;
// Add the try note last, to let post-order give us the right ordering // Add the try note last, to let post-order give us the right ordering
// (first to last for a given nesting level, inner to outer by level). // (first to last for a given nesting level, inner to outer by level).
@ -4728,7 +4712,7 @@ EmitIf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* this function will fix up the backpatch chain linked from * this function will fix up the backpatch chain linked from
* stmtInfo.breaks. * stmtInfo.breaks.
*/ */
jmp = EmitGoto(cx, bce, &stmtInfo, &stmtInfo.breaks); jmp = bce->emitGoto(&stmtInfo, &stmtInfo.breaks);
if (jmp < 0) if (jmp < 0)
return false; return false;
@ -4876,7 +4860,7 @@ EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
return false; return false;
if (!bce->emitCall(JSOP_CALL, 0)) // ITER if (!bce->emitCall(JSOP_CALL, 0)) // ITER
return false; return false;
CheckTypeSet(cx, bce, JSOP_CALL); bce->checkTypeSet(JSOP_CALL);
return true; return true;
} }
@ -4977,7 +4961,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode *
top = bce->offset(); top = bce->offset();
SET_STATEMENT_TOP(&stmtInfo, top); SET_STATEMENT_TOP(&stmtInfo, top);
if (!EmitLoopHead(cx, bce, nullptr)) if (!bce->emitLoopHead(nullptr))
return false; return false;
if (type == STMT_SPREAD) if (type == STMT_SPREAD)
@ -5023,7 +5007,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode *
// COME FROM the beginning of the loop to here. // COME FROM the beginning of the loop to here.
SetJumpOffsetAt(bce, jmp); SetJumpOffsetAt(bce, jmp);
if (!EmitLoopEntry(cx, bce, forHeadExpr)) if (!bce->emitLoopEntry(forHeadExpr))
return false; return false;
if (type == STMT_FOR_OF_LOOP) { if (type == STMT_FOR_OF_LOOP) {
@ -5068,9 +5052,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode *
} }
// Pop the result and the iter. // Pop the result and the iter.
EMIT_UINT16_IMM_OP(JSOP_POPN, 2); return bce->emitUint16Operand(JSOP_POPN, 2);
return true;
} }
static bool static bool
@ -5129,7 +5111,7 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
top = bce->offset(); top = bce->offset();
SET_STATEMENT_TOP(&stmtInfo, top); SET_STATEMENT_TOP(&stmtInfo, top);
if (!EmitLoopHead(cx, bce, nullptr)) if (!bce->emitLoopHead(nullptr))
return false; return false;
#ifdef DEBUG #ifdef DEBUG
@ -5158,7 +5140,7 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
* Fixup the goto that starts the loop to jump down to JSOP_MOREITER. * Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
*/ */
SetJumpOffsetAt(bce, jmp); SetJumpOffsetAt(bce, jmp);
if (!EmitLoopEntry(cx, bce, nullptr)) if (!bce->emitLoopEntry(nullptr))
return false; return false;
if (!bce->emit1(JSOP_POP)) if (!bce->emit1(JSOP_POP))
return false; return false;
@ -5246,9 +5228,9 @@ EmitNormalFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff
SET_STATEMENT_TOP(&stmtInfo, top); SET_STATEMENT_TOP(&stmtInfo, top);
/* Emit code for the loop body. */ /* Emit code for the loop body. */
if (!EmitLoopHead(cx, bce, forBody)) if (!bce->emitLoopHead(forBody))
return false; return false;
if (jmp == -1 && !EmitLoopEntry(cx, bce, forBody)) if (jmp == -1 && !bce->emitLoopEntry(forBody))
return false; return false;
if (!EmitTree(cx, bce, forBody)) if (!EmitTree(cx, bce, forBody))
return false; return false;
@ -5292,7 +5274,7 @@ EmitNormalFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff
/* Fix up the goto from top to target the loop condition. */ /* Fix up the goto from top to target the loop condition. */
MOZ_ASSERT(jmp >= 0); MOZ_ASSERT(jmp >= 0);
SetJumpOffsetAt(bce, jmp); SetJumpOffsetAt(bce, jmp);
if (!EmitLoopEntry(cx, bce, forHead->pn_kid2)) if (!bce->emitLoopEntry(forHead->pn_kid2))
return false; return false;
if (!EmitTree(cx, bce, forHead->pn_kid2)) if (!EmitTree(cx, bce, forHead->pn_kid2))
@ -5499,13 +5481,13 @@ EmitDo(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
/* Compile the loop body. */ /* Compile the loop body. */
ptrdiff_t top = bce->offset(); ptrdiff_t top = bce->offset();
if (!EmitLoopHead(cx, bce, pn->pn_left)) if (!bce->emitLoopHead(pn->pn_left))
return false; return false;
LoopStmtInfo stmtInfo(cx); LoopStmtInfo stmtInfo(cx);
PushLoopStatement(bce, &stmtInfo, STMT_DO_LOOP, top); PushLoopStatement(bce, &stmtInfo, STMT_DO_LOOP, top);
if (!EmitLoopEntry(cx, bce, nullptr)) if (!bce->emitLoopEntry(nullptr))
return false; return false;
if (!EmitTree(cx, bce, pn->pn_left)) if (!EmitTree(cx, bce, pn->pn_left))
@ -5572,14 +5554,14 @@ EmitWhile(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
return false; return false;
top = bce->offset(); top = bce->offset();
if (!EmitLoopHead(cx, bce, pn->pn_right)) if (!bce->emitLoopHead(pn->pn_right))
return false; return false;
if (!EmitTree(cx, bce, pn->pn_right)) if (!EmitTree(cx, bce, pn->pn_right))
return false; return false;
SetJumpOffsetAt(bce, jmp); SetJumpOffsetAt(bce, jmp);
if (!EmitLoopEntry(cx, bce, pn->pn_left)) if (!bce->emitLoopEntry(pn->pn_left))
return false; return false;
if (!EmitTree(cx, bce, pn->pn_left)) if (!EmitTree(cx, bce, pn->pn_left))
return false; return false;
@ -5612,7 +5594,7 @@ EmitBreak(ExclusiveContext *cx, BytecodeEmitter *bce, PropertyName *label)
noteType = (stmt->type == STMT_SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK; noteType = (stmt->type == STMT_SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK;
} }
return EmitGoto(cx, bce, stmt, &stmt->breaks, noteType) >= 0; return bce->emitGoto(stmt, &stmt->breaks, noteType) >= 0;
} }
static bool static bool
@ -5633,7 +5615,7 @@ EmitContinue(ExclusiveContext *cx, BytecodeEmitter *bce, PropertyName *label)
stmt = stmt->down; stmt = stmt->down;
} }
return EmitGoto(cx, bce, stmt, &stmt->continues, SRC_CONTINUE) >= 0; return bce->emitGoto(stmt, &stmt->continues, SRC_CONTINUE) >= 0;
} }
static bool static bool
@ -5794,7 +5776,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
MOZ_ASSERT(depth >= 2); MOZ_ASSERT(depth >= 2);
ptrdiff_t initialSend = -1; ptrdiff_t initialSend = -1;
if (!EmitBackPatchOp(cx, bce, &initialSend)) // goto initialSend if (!bce->emitBackPatchOp(&initialSend)) // goto initialSend
return false; return false;
// Try prologue. // ITER RESULT // Try prologue. // ITER RESULT
@ -5818,7 +5800,7 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, bce->offset() - tryStart)) if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, bce->offset() - tryStart))
return false; return false;
ptrdiff_t subsequentSend = -1; ptrdiff_t subsequentSend = -1;
if (!EmitBackPatchOp(cx, bce, &subsequentSend)) // goto subsequentSend if (!bce->emitBackPatchOp(&subsequentSend)) // goto subsequentSend
return false; return false;
ptrdiff_t tryEnd = bce->offset(); // tryEnd: ptrdiff_t tryEnd = bce->offset(); // tryEnd:
@ -5863,10 +5845,10 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
return false; return false;
if (!bce->emitCall(JSOP_CALL, 1, iter)) // ITER RESULT if (!bce->emitCall(JSOP_CALL, 1, iter)) // ITER RESULT
return false; return false;
CheckTypeSet(cx, bce, JSOP_CALL); bce->checkTypeSet(JSOP_CALL);
MOZ_ASSERT(bce->stackDepth == depth); MOZ_ASSERT(bce->stackDepth == depth);
ptrdiff_t checkResult = -1; ptrdiff_t checkResult = -1;
if (!EmitBackPatchOp(cx, bce, &checkResult)) // goto checkResult if (!bce->emitBackPatchOp(&checkResult)) // goto checkResult
return false; return false;
// Catch epilogue. // Catch epilogue.
@ -5879,10 +5861,8 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
return false; return false;
// After the try/catch block: send the received value to the iterator. // After the try/catch block: send the received value to the iterator.
if (!BackPatch(cx, bce, initialSend, bce->code().end(), JSOP_GOTO)) // initialSend: bce->backPatch(initialSend, bce->code().end(), JSOP_GOTO); // initialSend:
return false; bce->backPatch(subsequentSend, bce->code().end(), JSOP_GOTO); // subsequentSend:
if (!BackPatch(cx, bce, subsequentSend, bce->code().end(), JSOP_GOTO)) // subsequentSend:
return false;
// Send location. // Send location.
// result = iter.next(received) // ITER RECEIVED // result = iter.next(received) // ITER RECEIVED
@ -5900,11 +5880,11 @@ EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, Parse
return false; return false;
if (!bce->emitCall(JSOP_CALL, 1, iter)) // ITER RESULT if (!bce->emitCall(JSOP_CALL, 1, iter)) // ITER RESULT
return false; return false;
CheckTypeSet(cx, bce, JSOP_CALL); bce->checkTypeSet(JSOP_CALL);
MOZ_ASSERT(bce->stackDepth == depth); MOZ_ASSERT(bce->stackDepth == depth);
if (!BackPatch(cx, bce, checkResult, bce->code().end(), JSOP_GOTO)) // checkResult: bce->backPatch(checkResult, bce->code().end(), JSOP_GOTO); // checkResult:
return false;
// if (!result.done) goto tryStart; // ITER RESULT // if (!result.done) goto tryStart; // ITER RESULT
if (!bce->emit1(JSOP_DUP)) // ITER RESULT RESULT if (!bce->emit1(JSOP_DUP)) // ITER RESULT RESULT
return false; return false;
@ -6138,7 +6118,7 @@ EmitSelfHostedCallFunction(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode
if (!bce->emitCall(pn->getOp(), argc)) if (!bce->emitCall(pn->getOp(), argc))
return false; return false;
CheckTypeSet(cx, bce, pn->getOp()); bce->checkTypeSet(pn->getOp());
return true; return true;
} }
@ -6303,14 +6283,15 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!bce->emit1(pn->getOp())) if (!bce->emit1(pn->getOp()))
return false; return false;
} }
CheckTypeSet(cx, bce, pn->getOp()); bce->checkTypeSet(pn->getOp());
if (pn->isOp(JSOP_EVAL) || if (pn->isOp(JSOP_EVAL) ||
pn->isOp(JSOP_STRICTEVAL) || pn->isOp(JSOP_STRICTEVAL) ||
pn->isOp(JSOP_SPREADEVAL) || pn->isOp(JSOP_SPREADEVAL) ||
pn->isOp(JSOP_STRICTSPREADEVAL)) pn->isOp(JSOP_STRICTSPREADEVAL))
{ {
uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin); uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
EMIT_UINT16_IMM_OP(JSOP_LINENO, lineNum); if (!bce->emitUint16Operand(JSOP_LINENO, lineNum))
return false;
} }
if (pn->pn_xflags & PNX_SETCALL) { if (pn->pn_xflags & PNX_SETCALL) {
if (!bce->emit1(JSOP_SETCALL)) if (!bce->emit1(JSOP_SETCALL))
@ -6765,7 +6746,7 @@ EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t co
ptrdiff_t off = bce->emitN(JSOP_NEWARRAY, 3); // ARRAY ptrdiff_t off = bce->emitN(JSOP_NEWARRAY, 3); // ARRAY
if (off < 0) if (off < 0)
return false; return false;
CheckTypeSet(cx, bce, JSOP_NEWARRAY); bce->checkTypeSet(JSOP_NEWARRAY);
jsbytecode *pc = bce->code(off); jsbytecode *pc = bce->code(off);
// For arrays with spread, this is a very pessimistic allocation, the // For arrays with spread, this is a very pessimistic allocation, the
@ -7066,7 +7047,7 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
restIsDefn = rest->isDefn(); restIsDefn = rest->isDefn();
if (!bce->emit1(JSOP_REST)) if (!bce->emit1(JSOP_REST))
return false; return false;
CheckTypeSet(cx, bce, JSOP_REST); bce->checkTypeSet(JSOP_REST);
// Only set the rest parameter if it's not aliased by a nested // Only set the rest parameter if it's not aliased by a nested
// function in the body. // function in the body.
@ -7103,7 +7084,7 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
bce->switchToProlog(); bce->switchToProlog();
if (!bce->emit1(JSOP_REST)) if (!bce->emit1(JSOP_REST))
return false; return false;
CheckTypeSet(cx, bce, JSOP_REST); bce->checkTypeSet(JSOP_REST);
if (!EmitVarOp(cx, pn2, JSOP_SETARG, bce)) if (!EmitVarOp(cx, pn2, JSOP_SETARG, bce))
return false; return false;
if (!bce->emit1(JSOP_POP)) if (!bce->emit1(JSOP_POP))

View File

@ -255,6 +255,12 @@ struct BytecodeEmitter
bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...); bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...);
bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...); bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...);
// If op is JOF_TYPESET (see the type barriers comment in TypeInference.h),
// reserve a type set to store its result.
void checkTypeSet(JSOp op);
bool flushPops(int *npops);
ptrdiff_t emitCheck(ptrdiff_t delta); ptrdiff_t emitCheck(ptrdiff_t delta);
// Emit one bytecode. // Emit one bytecode.
@ -267,11 +273,26 @@ struct BytecodeEmitter
// Emit three bytecodes, an opcode with two bytes of immediate operands. // Emit three bytecodes, an opcode with two bytes of immediate operands.
bool emit3(JSOp op, jsbytecode op1, jsbytecode op2); bool emit3(JSOp op, jsbytecode op1, jsbytecode op2);
// Emit a bytecode followed by an uint16 immediate operand stored in
// big-endian order.
bool emitUint16Operand(JSOp op, uint32_t i);
// Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
ptrdiff_t emitN(JSOp op, size_t extra); ptrdiff_t emitN(JSOp op, size_t extra);
ptrdiff_t emitJump(JSOp op, ptrdiff_t off); ptrdiff_t emitJump(JSOp op, ptrdiff_t off);
bool emitCall(JSOp op, uint16_t argc, ParseNode *pn = nullptr); bool emitCall(JSOp op, uint16_t argc, ParseNode *pn = nullptr);
bool emitLoopHead(ParseNode *nextpn);
bool emitLoopEntry(ParseNode *nextpn);
// Emit a backpatch op with offset pointing to the previous jump of this
// type, so that we can walk back up the chain fixing up the op and jump
// offset.
bool emitBackPatchOp(ptrdiff_t *lastp);
void backPatch(ptrdiff_t last, jsbytecode *target, jsbytecode op);
ptrdiff_t emitGoto(StmtInfoBCE *toStmt, ptrdiff_t *lastp, SrcNoteType noteType = SRC_NULL);
}; };
/* /*