[INFER] Fix liveness analysis for try block, bug 673341. r=bhackett

This commit is contained in:
Shu-yu Guo 2011-07-22 11:53:18 -07:00
parent c46be499d6
commit 4ed56d317b
2 changed files with 65 additions and 2 deletions

View File

@ -863,6 +863,29 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
if (loop && code->jumpTarget && offset != loop->entry && offset > loop->lastBlock) if (loop && code->jumpTarget && offset != loop->entry && offset > loop->lastBlock)
loop->lastBlock = offset; loop->lastBlock = offset;
if (code->exceptionEntry) {
unsigned tryOffset;
JSTryNote *tn = script->trynotes()->vector;
JSTryNote *tnlimit = tn + script->trynotes()->length;
for (; tn < tnlimit; tn++) {
unsigned startOffset = script->main - script->code + tn->start;
if (startOffset + tn->length == offset) {
tryOffset = startOffset - 1;
break;
}
JS_NOT_REACHED("Start of try block not found");
}
/*
* Extend all live variables at exception entry to the start of
* the try block.
*/
for (unsigned i = 0; i < numSlots; i++) {
if (lifetimes[i].lifetime)
ensureVariable(lifetimes[i], tryOffset);
}
}
switch (op) { switch (op) {
case JSOP_GETARG: case JSOP_GETARG:
case JSOP_CALLARG: case JSOP_CALLARG:
@ -906,7 +929,6 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
case JSOP_LOOKUPSWITCHX: case JSOP_LOOKUPSWITCHX:
case JSOP_TABLESWITCH: case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX: case JSOP_TABLESWITCHX:
case JSOP_TRY:
/* Restore all saved variables. :FIXME: maybe do this precisely. */ /* Restore all saved variables. :FIXME: maybe do this precisely. */
for (unsigned i = 0; i < savedCount; i++) { for (unsigned i = 0; i < savedCount; i++) {
LifetimeVariable &var = *saved[i]; LifetimeVariable &var = *saved[i];
@ -922,6 +944,17 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
savedCount = 0; savedCount = 0;
break; break;
case JSOP_TRY:
for (unsigned i = 0; i < numSlots; i++) {
LifetimeVariable &var = lifetimes[i];
if (var.ensured) {
JS_ASSERT(var.lifetime);
if (var.lifetime->start == offset)
var.ensured = false;
}
}
break;
case JSOP_NEW: case JSOP_NEW:
case JSOP_CALL: case JSOP_CALL:
case JSOP_EVAL: case JSOP_EVAL:
@ -1063,6 +1096,9 @@ ScriptAnalysis::addVariable(JSContext *cx, LifetimeVariable &var, unsigned offse
LifetimeVariable **&saved, unsigned &savedCount) LifetimeVariable **&saved, unsigned &savedCount)
{ {
if (var.lifetime) { if (var.lifetime) {
if (var.ensured)
return;
JS_ASSERT(offset < var.lifetime->start); JS_ASSERT(offset < var.lifetime->start);
var.lifetime->start = offset; var.lifetime->start = offset;
} else { } else {
@ -1102,6 +1138,10 @@ ScriptAnalysis::killVariable(JSContext *cx, LifetimeVariable &var, unsigned offs
var.savedEnd = 0; var.savedEnd = 0;
return; return;
} }
if (var.ensured)
return;
JS_ASSERT(offset < var.lifetime->start); JS_ASSERT(offset < var.lifetime->start);
/* /*
@ -1124,6 +1164,16 @@ ScriptAnalysis::extendVariable(JSContext *cx, LifetimeVariable &var,
unsigned start, unsigned end) unsigned start, unsigned end)
{ {
JS_ASSERT(var.lifetime); JS_ASSERT(var.lifetime);
if (var.ensured) {
/*
* If we are still ensured to be live, the try block must scope over
* the loop, in which case the variable is already guaranteed to be
* live for the entire loop.
*/
JS_ASSERT(var.lifetime->start < start);
return;
}
var.lifetime->start = start; var.lifetime->start = start;
/* /*
@ -1193,6 +1243,15 @@ ScriptAnalysis::extendVariable(JSContext *cx, LifetimeVariable &var,
} }
} }
inline void
ScriptAnalysis::ensureVariable(LifetimeVariable &var, unsigned until)
{
JS_ASSERT(var.lifetime);
JS_ASSERT(until < var.lifetime->start);
var.lifetime->start = until;
var.ensured = true;
}
void void
ScriptAnalysis::clearAllocations() ScriptAnalysis::clearAllocations()
{ {

View File

@ -559,7 +559,10 @@ struct LifetimeVariable
Lifetime *saved; Lifetime *saved;
/* Jump preceding the basic block which killed this variable. */ /* Jump preceding the basic block which killed this variable. */
uint32 savedEnd; uint32 savedEnd : 31;
/* If the variable needs to be kept alive until lifetime->start. */
bool ensured : 1;
/* Whether this variable is live at offset. */ /* Whether this variable is live at offset. */
Lifetime * live(uint32 offset) const { Lifetime * live(uint32 offset) const {
@ -1168,6 +1171,7 @@ class ScriptAnalysis
inline void killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset, inline void killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
LifetimeVariable **&saved, unsigned &savedCount); LifetimeVariable **&saved, unsigned &savedCount);
inline void extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end); inline void extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
inline void ensureVariable(LifetimeVariable &var, unsigned until);
/* SSA helpers */ /* SSA helpers */
bool makePhi(JSContext *cx, uint32 slot, uint32 offset, SSAValue *pv); bool makePhi(JSContext *cx, uint32 slot, uint32 offset, SSAValue *pv);