Bug 937058 - Paper over debug-mode checks of stack depth for unreachable bytecode. r=jandem

This commit is contained in:
Andy Wingo 2013-11-11 16:21:20 +01:00
parent e3b27bcf78
commit 89a820f764
5 changed files with 88 additions and 63 deletions

View File

@ -0,0 +1,5 @@
// |jit-test| error: ReferenceError
for (var c in foo)
try {
throw new Error();
} catch (e) {}

View File

@ -795,8 +795,8 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
BaselineScript *baselineScript = script->baselineScript();
#ifdef DEBUG
uint32_t expectedDepth = js_ReconstructStackDepth(cx, script,
resumeAfter ? GetNextPc(pc) : pc);
uint32_t expectedDepth;
if (ReconstructStackDepth(cx, script, resumeAfter ? GetNextPc(pc) : pc, &expectedDepth)) {
if (op != JSOP_FUNAPPLY || !iter.moreFrames() || resumeAfter) {
if (op == JSOP_FUNCALL) {
// For fun.call(this, ...); the reconstructStackDepth will
@ -821,6 +821,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
JS_ASSERT(exprStackSlots == expectedDepth);
}
}
}
IonSpew(IonSpew_BaselineBailouts, " Resuming %s pc offset %d (op %s) (line %d) of %s:%d",
resumeAfter ? "after" : "at", (int) pcOff, js_CodeName[op],

View File

@ -279,7 +279,8 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
#ifdef DEBUG
if (GetIonContext()->cx) {
uint32_t stackDepth = js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC);
uint32_t stackDepth;
if (ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth)) {
if (JSOp(*bailPC) == JSOP_FUNCALL) {
// For fun.call(this, ...); the reconstructStackDepth will
// include the this. When inlining that is not included.
@ -293,13 +294,15 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
// funapply. In that case exprStackSlots, will have the real
// arguments in the slots and not be 4.
// With accessors, we have different stack depths depending on whether or not we
// inlined the accessor, as the inlined stack contains a callee function that should
// never have been there and we might just be capturing an uneventful property site,
// in which case there won't have been any violence.
// With accessors, we have different stack depths depending on
// whether or not we inlined the accessor, as the inlined stack
// contains a callee function that should never have been there
// and we might just be capturing an uneventful property site, in
// which case there won't have been any violence.
JS_ASSERT(exprStack == stackDepth);
}
}
}
#endif
#ifdef TRACK_SNAPSHOTS

View File

@ -402,12 +402,16 @@ class BytecodeParser
bool parse();
#ifdef DEBUG
bool isReachable(uint32_t offset) { return maybeCode(offset); }
bool isReachable(const jsbytecode *pc) { return maybeCode(pc); }
#endif
uint32_t stackDepthAtPC(uint32_t offset) {
// Sometimes the code generator in debug mode asks about the stack depth
// of unreachable code (bug 932180 comment 22). Assume that unreachable
// code has no operands on the stack.
Bytecode *code = maybeCode(offset);
return code ? code->stackDepth : 0;
return getCode(offset).stackDepth;
}
uint32_t stackDepthAtPC(const jsbytecode *pc) { return stackDepthAtPC(pc - script_->code); }
@ -697,6 +701,21 @@ BytecodeParser::parse()
#ifdef DEBUG
bool
js::ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc, uint32_t *depth)
{
BytecodeParser parser(cx, script);
if (!parser.parse())
return false;
if (!parser.isReachable(pc))
return false;
*depth = parser.stackDepthAtPC(pc);
return true;
}
/*
* If pc != nullptr, include a prefix indicating whether the PC is at the
* current line. If showAll is true, include the source note type and the
@ -707,10 +726,14 @@ js_DisassembleAtPC(JSContext *cx, JSScript *scriptArg, bool lines,
jsbytecode *pc, bool showAll, Sprinter *sp)
{
RootedScript script(cx, scriptArg);
BytecodeParser parser(cx, script);
jsbytecode *next, *end;
unsigned len;
if (showAll && !parser.parse())
return false;
if (showAll)
Sprint(sp, "%s:%u\n", script->filename(), script->lineno);
@ -757,10 +780,10 @@ js_DisassembleAtPC(JSContext *cx, JSScript *scriptArg, bool lines,
}
else
sp->put(" ");
if (script->hasAnalysis() && script->analysis()->maybeCode(next))
Sprint(sp, "%05u ", script->analysis()->getCode(next).stackDepth);
if (parser.isReachable(next))
Sprint(sp, "%05u ", parser.stackDepthAtPC(next));
else
sp->put(" ");
Sprint(sp, " ", parser.stackDepthAtPC(next));
}
len = js_Disassemble1(cx, script, next, next - script->code, lines, sp);
if (!len)
@ -1985,16 +2008,6 @@ js::DecompileArgument(JSContext *cx, int formalIndex, HandleValue v)
return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
}
unsigned
js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc)
{
BytecodeParser parser(cx, script);
if (!parser.parse())
return 0;
return parser.stackDepthAtPC(pc);
}
bool
js::CallResultEscapes(jsbytecode *pc)
{

View File

@ -351,14 +351,17 @@ StackUses(JSScript *script, jsbytecode *pc);
extern unsigned
StackDefs(JSScript *script, jsbytecode *pc);
} /* namespace js */
#ifdef DEBUG
/*
* Given bytecode address pc in script's main program code, return the operand
* stack depth just before (JSOp) *pc executes.
* Given bytecode address pc in script's main program code, compute the operand
* stack depth just before (JSOp) *pc executes. If *pc is not reachable, return
* false.
*/
extern unsigned
js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
extern bool
ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc, uint32_t *depth);
#endif
} /* namespace js */
#ifdef _MSC_VER
#pragma warning(pop)