Bug 927782 - Part 3: Add DEBUGLEAVEBLOCK opcode to invalidate live DebugScopes. r=luke

This commit is contained in:
Andy Wingo 2013-11-25 12:19:58 +01:00
parent ab257efdd2
commit 7d7f78b80c
9 changed files with 61 additions and 12 deletions

View File

@ -588,6 +588,8 @@ EmitNonLocalJumpFixup(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *t
stmt = stmt->down;
if (stmt == toStmt)
break;
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
return false;
if (stmt->type == STMT_FOR_OF_LOOP) {
@ -600,6 +602,8 @@ EmitNonLocalJumpFixup(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *t
EMIT_UINT16_IMM_OP(JSOP_POPN, popCount);
} else {
/* There is a Block object with locals on the stack to pop. */
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
}
}
@ -2622,8 +2626,11 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!PopStatementBCE(cx, bce))
return false;
if (pn->pn_right->isKind(PNK_LEXICALSCOPE))
if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
}
return true;
}
@ -3941,6 +3948,8 @@ EmitTry(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
*/
if (Emit1(cx, bce, JSOP_THROWING) < 0)
return false;
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, count);
JS_ASSERT(bce->stackDepth == depth);
}
@ -4200,6 +4209,8 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
if (!EmitTree(cx, bce, letBody->pn_expr))
return false;
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
JSOp leaveOp = letBody->getOp();
JS_ASSERT(leaveOp == JSOP_LEAVEBLOCK || leaveOp == JSOP_LEAVEBLOCKEXPR);
EMIT_UINT16_IMM_OP(leaveOp, blockObj->slotCount());
@ -4233,6 +4244,8 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!EmitTree(cx, bce, pn->pn_expr))
return false;
if (Emit1(cx, bce, JSOP_DEBUGLEAVEBLOCK) < 0)
return false;
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, slots);
return PopStatementBCE(cx, bce);
@ -4410,6 +4423,8 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
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;
}
@ -4569,6 +4584,8 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
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;
}

View File

@ -2625,6 +2625,21 @@ BaselineCompiler::emit_JSOP_ENTERLET2()
return emitEnterBlock();
}
typedef bool (*DebugLeaveBlockFn)(JSContext *, BaselineFrame *);
static const VMFunction DebugLeaveBlockInfo = FunctionInfo<DebugLeaveBlockFn>(jit::DebugLeaveBlock);
bool
BaselineCompiler::emit_JSOP_DEBUGLEAVEBLOCK()
{
// Call a stub to pop the block from the block chain.
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
return callVM(DebugLeaveBlockInfo);
}
typedef bool (*LeaveBlockFn)(JSContext *, BaselineFrame *);
static const VMFunction LeaveBlockInfo = FunctionInfo<LeaveBlockFn>(jit::LeaveBlock);

View File

@ -152,6 +152,7 @@ namespace jit {
_(JSOP_LEAVEBLOCK) \
_(JSOP_LEAVEBLOCKEXPR) \
_(JSOP_LEAVEFORLETIN) \
_(JSOP_DEBUGLEAVEBLOCK) \
_(JSOP_EXCEPTION) \
_(JSOP_DEBUGGER) \
_(JSOP_ARGUMENTS) \

View File

@ -55,9 +55,6 @@ BaselineFrame::popBlock(JSContext *cx)
{
JS_ASSERT(hasBlockChain());
if (cx->compartment()->debugMode())
DebugScopes::onPopBlock(cx, this);
if (blockChain_->needsClone()) {
JS_ASSERT(scopeChain_->as<ClonedBlockObject>().staticBlock() == *blockChain_);
popOffScopeChain();

View File

@ -894,6 +894,17 @@ LeaveBlock(JSContext *cx, BaselineFrame *frame)
return true;
}
bool
DebugLeaveBlock(JSContext *cx, BaselineFrame *frame)
{
JS_ASSERT(frame->hasBlockChain());
if (JS_UNLIKELY(cx->compartment()->debugMode()))
DebugScopes::onPopBlock(cx, frame);
return true;
}
bool
InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t numStackValues)
{

View File

@ -654,6 +654,7 @@ bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bo
bool EnterBlock(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
bool LeaveBlock(JSContext *cx, BaselineFrame *frame);
bool DebugLeaveBlock(JSContext *cx, BaselineFrame *frame);
bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
uint32_t numStackValues);

View File

@ -438,9 +438,8 @@ OPDEF(JSOP_TYPEOFEXPR, 197,"typeofexpr", NULL, 1, 1, 1, JOF_BYTE|JOF_DE
*/
OPDEF(JSOP_ENTERBLOCK, 198,"enterblock", NULL, 5, 0, -1, JOF_OBJECT)
OPDEF(JSOP_LEAVEBLOCK, 199,"leaveblock", NULL, 3, -1, 0, JOF_UINT16)
OPDEF(JSOP_DEBUGLEAVEBLOCK, 200,"debugleaveblock", NULL, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED200, 200,"unused200", NULL, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_UNUSED201, 201,"unused201", NULL, 1, 0, 0, JOF_BYTE)
/*

View File

@ -855,6 +855,8 @@ js::UnwindScope(JSContext *cx, AbstractFramePtr frame, uint32_t stackDepth)
case ScopeIter::Block:
if (si.staticBlock().stackDepth() < stackDepth)
return;
if (cx->compartment()->debugMode())
DebugScopes::onPopBlock(cx, frame);
frame.popBlock(cx);
break;
case ScopeIter::With:
@ -1533,7 +1535,6 @@ CASE(JSOP_UNUSED191)
CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED194)
CASE(JSOP_UNUSED196)
CASE(JSOP_UNUSED200)
CASE(JSOP_UNUSED201)
CASE(JSOP_GETFUNNS)
CASE(JSOP_UNUSED208)
@ -3268,6 +3269,18 @@ CASE(JSOP_LEAVEBLOCKEXPR)
}
END_CASE(JSOP_LEAVEBLOCK)
CASE(JSOP_DEBUGLEAVEBLOCK)
{
JS_ASSERT(REGS.fp()->hasBlockChain());
// FIXME: This opcode should not be necessary. The debugger shouldn't need
// help from bytecode to do its job. See bug 927782.
if (JS_UNLIKELY(cx->compartment()->debugMode()))
DebugScopes::onPopBlock(cx, REGS.fp());
}
END_CASE(JSOP_DEBUGLEAVEBLOCK)
CASE(JSOP_GENERATOR)
{
JS_ASSERT(!cx->isExceptionPending());

View File

@ -372,11 +372,6 @@ StackFrame::pushBlock(JSContext *cx, StaticBlockObject &block)
void
StackFrame::popBlock(JSContext *cx)
{
JS_ASSERT(hasBlockChain());
if (JS_UNLIKELY(cx->compartment()->debugMode()))
DebugScopes::onPopBlock(cx, this);
if (blockChain_->needsClone()) {
JS_ASSERT(scopeChain_->as<ClonedBlockObject>().staticBlock() == *blockChain_);
popOffScopeChain();