mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
Bug 1143704 part 7 - Move more functions into BytecodeEmitter. r=bhackett
This commit is contained in:
parent
71389afa0d
commit
cf9bd1071f
@ -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))
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user