зеркало из https://github.com/mozilla/gecko-dev.git
Bug 927782 - Part 7: Refactor entering and leaving block scopes in BytecodeEmitter. r=luke
This commit is contained in:
Родитель
46f0c84994
Коммит
3b8c9f30e6
|
@ -142,11 +142,12 @@ EmitCheck(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t delta)
|
|||
}
|
||||
|
||||
static StaticBlockObject &
|
||||
CurrentBlock(StmtInfoBCE *topStmt)
|
||||
LastBlockAdded(BytecodeEmitter *bce, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(topStmt->type == STMT_BLOCK || topStmt->type == STMT_SWITCH);
|
||||
JS_ASSERT(topStmt->blockObj->is<StaticBlockObject>());
|
||||
return *topStmt->blockObj;
|
||||
DebugOnly<uint32_t> index = GET_UINT32_INDEX(pc);
|
||||
JS_ASSERT(index < bce->objectList.length);
|
||||
JS_ASSERT(index == bce->objectList.length - 1);
|
||||
return bce->objectList.lastbox->object->as<StaticBlockObject>();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -176,13 +177,13 @@ UpdateDepth(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t target)
|
|||
int nuses, ndefs;
|
||||
if (op == JSOP_ENTERBLOCK) {
|
||||
nuses = 0;
|
||||
ndefs = CurrentBlock(bce->topStmt).slotCount();
|
||||
ndefs = LastBlockAdded(bce, pc).slotCount();
|
||||
} else if (op == JSOP_ENTERLET0) {
|
||||
nuses = ndefs = CurrentBlock(bce->topStmt).slotCount();
|
||||
nuses = ndefs = LastBlockAdded(bce, pc).slotCount();
|
||||
} else if (op == JSOP_ENTERLET1) {
|
||||
nuses = ndefs = CurrentBlock(bce->topStmt).slotCount() + 1;
|
||||
nuses = ndefs = LastBlockAdded(bce, pc).slotCount() + 1;
|
||||
} else if (op == JSOP_ENTERLET2) {
|
||||
nuses = ndefs = CurrentBlock(bce->topStmt).slotCount() + 2;
|
||||
nuses = ndefs = LastBlockAdded(bce, pc).slotCount() + 2;
|
||||
} else {
|
||||
nuses = StackUses(nullptr, pc);
|
||||
ndefs = StackDefs(nullptr, pc);
|
||||
|
@ -653,10 +654,80 @@ EnclosingStaticScope(BytecodeEmitter *bce)
|
|||
return bce->sc->asFunctionBox()->function();
|
||||
}
|
||||
|
||||
// Push a block scope statement and link blockObj into bce->blockChain.
|
||||
// In a stack frame, block-scoped locals follow hoisted var-bound locals. If
|
||||
// the current compilation unit is a function, add the number of "fixed slots"
|
||||
// (var-bound locals) to the given block-scoped index, to arrive at its final
|
||||
// position in the call frame.
|
||||
//
|
||||
static bool
|
||||
PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
||||
ptrdiff_t top)
|
||||
AdjustBlockSlot(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t *slot)
|
||||
{
|
||||
JS_ASSERT(*slot < bce->maxStackDepth);
|
||||
if (bce->sc->isFunctionBox()) {
|
||||
*slot += bce->script->bindings.numVars();
|
||||
if ((unsigned) *slot >= SLOTNO_LIMIT) {
|
||||
bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
AllLocalsAliased(StaticBlockObject &obj)
|
||||
{
|
||||
for (unsigned i = 0; i < obj.slotCount(); i++)
|
||||
if (!obj.isAliased(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, StaticBlockObject &blockObj)
|
||||
{
|
||||
uint32_t depthPlusFixed = blockObj.stackDepth();
|
||||
if (!AdjustBlockSlot(cx, bce, &depthPlusFixed))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < blockObj.slotCount(); i++) {
|
||||
Definition *dn = blockObj.maybeDefinitionParseNode(i);
|
||||
|
||||
/* Beware the empty destructuring dummy. */
|
||||
if (!dn) {
|
||||
blockObj.setAliased(i, bce->sc->allLocalsAliased());
|
||||
continue;
|
||||
}
|
||||
|
||||
JS_ASSERT(dn->isDefn());
|
||||
JS_ASSERT(dn->frameSlot() + depthPlusFixed < JS_BIT(16));
|
||||
if (!dn->pn_cookie.set(bce->parser->tokenStream, dn->pn_cookie.level(),
|
||||
uint16_t(dn->frameSlot() + depthPlusFixed)))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
|
||||
JS_ASSERT(pnu->pn_lexdef == dn);
|
||||
JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
|
||||
JS_ASSERT(pnu->pn_cookie.isFree());
|
||||
}
|
||||
#endif
|
||||
|
||||
blockObj.setAliased(i, bce->isAliasedName(dn));
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(blockObj));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmitter *bce);
|
||||
|
||||
static bool
|
||||
EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
||||
unsigned extraSlots)
|
||||
{
|
||||
uint32_t parent = UINT32_MAX;
|
||||
if (bce->blockChain) {
|
||||
|
@ -667,16 +738,35 @@ PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, ObjectBox *objbox,
|
|||
|
||||
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
|
||||
|
||||
PushStatementBCE(bce, stmt, STMT_BLOCK, top);
|
||||
|
||||
unsigned scopeObjectIndex = bce->objectList.add(objbox);
|
||||
uint32_t scopeObjectIndex = bce->objectList.add(objbox);
|
||||
stmt->blockScopeIndex = bce->blockScopeList.length();
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
|
||||
return false;
|
||||
|
||||
int depth = bce->stackDepth - (blockObj.slotCount() + extraSlots);
|
||||
JS_ASSERT(depth >= 0);
|
||||
blockObj.setStackDepth(depth);
|
||||
|
||||
JSOp op;
|
||||
switch (extraSlots) {
|
||||
case 0: op = JSOP_ENTERLET0; break;
|
||||
case 1: op = JSOP_ENTERLET1; break;
|
||||
case 2: op = JSOP_ENTERLET2; break;
|
||||
default: MOZ_ASSUME_UNREACHABLE("unexpected extraSlots");
|
||||
}
|
||||
|
||||
if (!ComputeAliasedSlots(cx, bce, blockObj))
|
||||
return false;
|
||||
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, op, bce))
|
||||
return false;
|
||||
|
||||
PushStatementBCE(bce, stmt, STMT_BLOCK, bce->offset());
|
||||
blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
|
||||
FinishPushBlockScope(bce, stmt, blockObj);
|
||||
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -700,6 +790,35 @@ PopStatementBCE(ExclusiveContext *cx, BytecodeEmitter *bce)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
LeaveBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
StmtInfoBCE *stmt = bce->topStmt;
|
||||
uint32_t blockScopeIndex = stmt->blockScopeIndex;
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
JS_ASSERT(bce->blockScopeList.list[blockScopeIndex].length == 0);
|
||||
uint32_t blockObjIndex = bce->blockScopeList.list[blockScopeIndex].index;
|
||||
ObjectBox *blockObjBox = bce->objectList.find(blockObjIndex);
|
||||
StaticBlockObject *blockObj = &blockObjBox->object->as<StaticBlockObject>();
|
||||
JS_ASSERT(stmt->blockObj == blockObj);
|
||||
JS_ASSERT(blockObj == bce->blockChain);
|
||||
#endif
|
||||
|
||||
uint32_t slotCount = bce->blockChain->slotCount();
|
||||
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR);
|
||||
EMIT_UINT16_IMM_OP(op, slotCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitIndex32(ExclusiveContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
|
||||
{
|
||||
|
@ -1032,101 +1151,6 @@ BytecodeEmitter::isAliasedName(ParseNode *pn)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the slot for a block local to account for the number of variables
|
||||
* that share the same index space with locals. Due to the incremental code
|
||||
* generation for top-level script, we do the adjustment via code patching in
|
||||
* js::frontend::CompileScript; see comments there.
|
||||
*
|
||||
* The function returns -1 on failures.
|
||||
*/
|
||||
static int
|
||||
AdjustBlockSlot(ExclusiveContext *cx, BytecodeEmitter *bce, int slot)
|
||||
{
|
||||
JS_ASSERT((unsigned) slot < bce->maxStackDepth);
|
||||
if (bce->sc->isFunctionBox()) {
|
||||
slot += bce->script->bindings.numVars();
|
||||
if ((unsigned) slot >= SLOTNO_LIMIT) {
|
||||
bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
|
||||
slot = -1;
|
||||
}
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
AllLocalsAliased(StaticBlockObject &obj)
|
||||
{
|
||||
for (unsigned i = 0; i < obj.slotCount(); i++)
|
||||
if (!obj.isAliased(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
EmitEnterBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
|
||||
StmtInfoBCE *stmt = bce->topStmt;
|
||||
JS_ASSERT(stmt->type == STMT_BLOCK || stmt->type == STMT_SWITCH);
|
||||
JS_ASSERT(stmt->isBlockScope);
|
||||
JS_ASSERT(stmt->blockScopeIndex == bce->blockScopeList.length() - 1);
|
||||
JS_ASSERT(bce->blockScopeList.list[stmt->blockScopeIndex].length == 0);
|
||||
uint32_t scopeObjectIndex = bce->blockScopeList.list[stmt->blockScopeIndex].index;
|
||||
JS_ASSERT(scopeObjectIndex == bce->objectList.length - 1);
|
||||
JS_ASSERT(pn->pn_objbox == bce->objectList.lastbox);
|
||||
if (!EmitInternedObjectOp(cx, scopeObjectIndex, op, bce))
|
||||
return false;
|
||||
|
||||
Rooted<StaticBlockObject*> blockObj(cx, &pn->pn_objbox->object->as<StaticBlockObject>());
|
||||
|
||||
int extraSlots = (op == JSOP_ENTERLET1)
|
||||
? 1
|
||||
: (op == JSOP_ENTERLET2)
|
||||
? 2
|
||||
: 0;
|
||||
int depth = bce->stackDepth - (blockObj->slotCount() + extraSlots);
|
||||
JS_ASSERT(depth >= 0);
|
||||
|
||||
blockObj->setStackDepth(depth);
|
||||
|
||||
int depthPlusFixed = AdjustBlockSlot(cx, bce, depth);
|
||||
if (depthPlusFixed < 0)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < blockObj->slotCount(); i++) {
|
||||
Definition *dn = blockObj->maybeDefinitionParseNode(i);
|
||||
|
||||
/* Beware the empty destructuring dummy. */
|
||||
if (!dn) {
|
||||
blockObj->setAliased(i, bce->sc->allLocalsAliased());
|
||||
continue;
|
||||
}
|
||||
|
||||
JS_ASSERT(dn->isDefn());
|
||||
JS_ASSERT(unsigned(dn->frameSlot() + depthPlusFixed) < JS_BIT(16));
|
||||
if (!dn->pn_cookie.set(bce->parser->tokenStream, dn->pn_cookie.level(),
|
||||
uint16_t(dn->frameSlot() + depthPlusFixed)))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
|
||||
JS_ASSERT(pnu->pn_lexdef == dn);
|
||||
JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
|
||||
JS_ASSERT(pnu->pn_cookie.isFree());
|
||||
}
|
||||
#endif
|
||||
|
||||
blockObj->setAliased(i, bce->isAliasedName(dn));
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(*blockObj));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to convert a *NAME op with a free name to a more specialized GNAME,
|
||||
* INTRINSIC or ALIASEDVAR op, which optimize accesses on that name.
|
||||
|
@ -2299,7 +2323,6 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
int noteIndex;
|
||||
size_t switchSize;
|
||||
jsbytecode *pc;
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
|
||||
/* Try for most optimal, fall back if not dense ints. */
|
||||
switchOp = JSOP_TABLESWITCH;
|
||||
|
@ -2307,14 +2330,16 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
defaultOffset = -1;
|
||||
|
||||
pn2 = pn->pn_right;
|
||||
JS_ASSERT(pn2->isKind(PNK_LEXICALSCOPE) || pn2->isKind(PNK_STATEMENTLIST));
|
||||
|
||||
/*
|
||||
* If there are hoisted let declarations, their stack slots go under the
|
||||
* discriminant's value so push their slots now and enter the block later.
|
||||
*/
|
||||
uint32_t blockObjCount = 0;
|
||||
StaticBlockObject *blockObj = nullptr;
|
||||
if (pn2->isKind(PNK_LEXICALSCOPE)) {
|
||||
blockObjCount = pn2->pn_objbox->object->as<StaticBlockObject>().slotCount();
|
||||
for (uint32_t i = 0; i < blockObjCount; ++i) {
|
||||
blockObj = &pn2->pn_objbox->object->as<StaticBlockObject>();
|
||||
for (uint32_t i = 0; i < blockObj->slotCount(); ++i) {
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
|
||||
return false;
|
||||
}
|
||||
|
@ -2324,29 +2349,21 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
if (!EmitTree(cx, bce, pn->pn_left))
|
||||
return false;
|
||||
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
if (pn2->isKind(PNK_LEXICALSCOPE)) {
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, pn2->pn_objbox, -1))
|
||||
if (!EnterBlockScope(cx, bce, &stmtInfo, pn2->pn_objbox, 1))
|
||||
return false;
|
||||
stmtInfo.type = STMT_SWITCH;
|
||||
if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
|
||||
return false;
|
||||
stmtInfo.update = top = bce->offset();
|
||||
/* Advance pn2 to refer to the switch case list. */
|
||||
pn2 = pn2->expr();
|
||||
} else {
|
||||
JS_ASSERT(pn2->isKind(PNK_STATEMENTLIST));
|
||||
top = bce->offset();
|
||||
PushStatementBCE(bce, &stmtInfo, STMT_SWITCH, top);
|
||||
}
|
||||
|
||||
/* Switch bytecodes run from here till end of final case. */
|
||||
top = bce->offset();
|
||||
if (pn2->isKind(PNK_STATEMENTLIST)) {
|
||||
PushStatementBCE(bce, &stmtInfo, STMT_SWITCH, top);
|
||||
} else {
|
||||
/*
|
||||
* Set the statement info record's idea of top. Reset top too, since
|
||||
* repushBlock emits code.
|
||||
*/
|
||||
stmtInfo.update = top = bce->offset();
|
||||
|
||||
/* Advance pn2 to refer to the switch case list. */
|
||||
pn2 = pn2->expr();
|
||||
}
|
||||
|
||||
uint32_t caseCount = pn2->pn_count;
|
||||
uint32_t tableLength = 0;
|
||||
ScopedJSFreePtr<ParseNode*> table(nullptr);
|
||||
|
@ -2618,13 +2635,13 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
}
|
||||
}
|
||||
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
if (!LeaveBlockScope(cx, bce, JSOP_LEAVEBLOCK))
|
||||
return false;
|
||||
} else {
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -3139,8 +3156,8 @@ EmitGroupAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp,
|
|||
for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
|
||||
/* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
|
||||
JS_ASSERT(i < limit);
|
||||
int slot = AdjustBlockSlot(cx, bce, i);
|
||||
if (slot < 0)
|
||||
uint32_t slot = i;
|
||||
if (!AdjustBlockSlot(cx, bce, &slot))
|
||||
return false;
|
||||
|
||||
if (!EmitUnaliasedVarOp(cx, JSOP_GETLOCAL, slot, bce))
|
||||
|
@ -4173,26 +4190,16 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
|
|||
}
|
||||
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, letBody->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
|
||||
DebugOnly<ptrdiff_t> bodyBegin = bce->offset();
|
||||
if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
|
||||
if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, 0))
|
||||
return false;
|
||||
|
||||
if (!EmitTree(cx, bce, letBody->pn_expr))
|
||||
return false;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
if (!LeaveBlockScope(cx, bce, letBody->getOp()))
|
||||
return false;
|
||||
JSOp leaveOp = letBody->getOp();
|
||||
JS_ASSERT(leaveOp == JSOP_LEAVEBLOCK || leaveOp == JSOP_LEAVEBLOCKEXPR);
|
||||
EMIT_UINT16_IMM_OP(leaveOp, blockObj->slotCount());
|
||||
|
||||
DebugOnly<ptrdiff_t> bodyEnd = bce->offset();
|
||||
JS_ASSERT(bodyEnd > bodyBegin);
|
||||
|
||||
return PopStatementBCE(cx, bce);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4209,20 +4216,22 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
ObjectBox *objbox = pn->pn_objbox;
|
||||
StaticBlockObject &blockObj = objbox->object->as<StaticBlockObject>();
|
||||
size_t slots = blockObj.slotCount();
|
||||
if (!PushBlockScopeBCE(bce, &stmtInfo, objbox, bce->offset()))
|
||||
return false;
|
||||
|
||||
if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
|
||||
for (size_t n = 0; n < slots; ++n) {
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EnterBlockScope(cx, bce, &stmtInfo, objbox, 0))
|
||||
return false;
|
||||
|
||||
if (!EmitTree(cx, bce, pn->pn_expr))
|
||||
return false;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
if (!LeaveBlockScope(cx, bce, JSOP_LEAVEBLOCK))
|
||||
return false;
|
||||
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, slots);
|
||||
|
||||
return PopStatementBCE(cx, bce);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -4299,9 +4308,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
|||
// Enter the block before the loop body, after evaluating the obj.
|
||||
StmtInfoBCE letStmt(cx);
|
||||
if (letDecl) {
|
||||
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET2))
|
||||
if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4393,18 +4400,14 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
|||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
// Pop result and iter.
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, 2);
|
||||
|
||||
if (letDecl) {
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
|
||||
if (!LeaveBlockScope(cx, bce, JSOP_LEAVEBLOCK))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pop result, iter, and slots from the lexical block (if any).
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount + 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4477,9 +4480,7 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
|||
/* Enter the block before the loop body, after evaluating the obj. */
|
||||
StmtInfoBCE letStmt(cx);
|
||||
if (letDecl) {
|
||||
if (!PushBlockScopeBCE(bce, &letStmt, pn1->pn_objbox, bce->offset()))
|
||||
return false;
|
||||
if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
|
||||
if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4549,26 +4550,19 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
|||
if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, beq - jmp))
|
||||
return false;
|
||||
|
||||
/* Fixup breaks and continues before JSOP_ITER (and JSOP_LEAVEFORINLET). */
|
||||
// Fix up breaks and continues.
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
if (letDecl) {
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce->tryNoteList.append(JSTRY_ITER, bce->stackDepth, top, bce->offset()))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_ENDITER) < 0)
|
||||
return false;
|
||||
|
||||
if (letDecl)
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
|
||||
if (letDecl) {
|
||||
if (!LeaveBlockScope(cx, bce, JSOP_LEAVEBLOCK))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6432,8 +6426,6 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
return false;
|
||||
|
||||
case PNK_ARRAYPUSH: {
|
||||
int slot;
|
||||
|
||||
/*
|
||||
* The array object's stack index is in bce->arrayCompDepth. See below
|
||||
* under the array initialiser code generator for array comprehension
|
||||
|
@ -6442,8 +6434,8 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
*/
|
||||
if (!EmitTree(cx, bce, pn->pn_kid))
|
||||
return false;
|
||||
slot = AdjustBlockSlot(cx, bce, bce->arrayCompDepth);
|
||||
if (slot < 0)
|
||||
uint32_t slot = bce->arrayCompDepth;
|
||||
if (!AdjustBlockSlot(cx, bce, &slot))
|
||||
return false;
|
||||
if (!EmitUnaliasedVarOp(cx, pn->getOp(), slot, bce))
|
||||
return false;
|
||||
|
|
|
@ -666,7 +666,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
bool resumeAfter = excInfo ? false : iter.resumeAfter();
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
JS_ASSERT_IF(excInfo, op == JSOP_ENTERBLOCK);
|
||||
|
||||
// Fixup inlined JSOP_FUNCALL, JSOP_FUNAPPLY, and accessors on the caller side.
|
||||
// On the caller side this must represent like the function wasn't inlined.
|
||||
|
|
|
@ -3377,10 +3377,8 @@ DEFAULT()
|
|||
|
||||
switch (tn->kind) {
|
||||
case JSTRY_CATCH:
|
||||
JS_ASSERT(*REGS.pc == JSOP_ENTERBLOCK || *REGS.pc == JSOP_EXCEPTION);
|
||||
|
||||
/* Catch cannot intercept the closing of a generator. */
|
||||
if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
|
||||
if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
|
||||
break;
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче