[INFER] Restore known type of tracked vars at access points, not join points, bug 657304.

This commit is contained in:
Brian Hackett 2011-05-16 10:22:41 -07:00
parent 7c0d886caf
commit c3e5ec9390
5 changed files with 69 additions and 45 deletions

View File

@ -797,9 +797,6 @@ mjit::Compiler::generatePrologue()
recompileCheckHelper();
/* Update the initial types of arguments and locals with a use-before-def. */
restoreAnalysisTypes();
return Compile_Okay;
}
@ -1489,7 +1486,7 @@ mjit::Compiler::generateMethod()
if (!frame.discardForJoin(analysis->getAllocation(PC), opinfo->stackDepth))
return Compile_Error;
restoreAnalysisTypes();
updateJoinVarTypes();
fallthrough = true;
if (!cx->typeInferenceEnabled()) {
@ -2217,6 +2214,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_GETARG)
{
restoreVarType();
uint32 arg = GET_SLOTNO(PC);
frame.pushArg(arg);
}
@ -2224,6 +2222,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_CALLARG)
{
restoreVarType();
uint32 arg = GET_SLOTNO(PC);
if (JSObject *singleton = pushedSingleton(0))
frame.push(ObjectValue(*singleton));
@ -2239,7 +2238,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_SETARG)
{
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
jsbytecode *next = &PC[JSOP_SETARG_LENGTH];
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
frame.storeArg(GET_SLOTNO(PC), pop);
updateVarType();
@ -2254,6 +2253,13 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_GETLOCAL)
{
/*
* Update the var type unless we are about to pop the variable.
* Sync is not guaranteed for types of dead locals, and GETLOCAL
* followed by POP is not regarded as a use of the variable.
*/
if (PC[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
restoreVarType();
uint32 slot = GET_SLOTNO(PC);
frame.pushLocal(slot);
}
@ -2360,7 +2366,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_SETPROP)
{
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
jsbytecode *next = &PC[JSOP_SETPROP_LENGTH];
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true, pop))
return Compile_Error;
@ -2370,7 +2376,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_SETNAME)
BEGIN_CASE(JSOP_SETMETHOD)
{
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
jsbytecode *next = &PC[JSOP_SETNAME_LENGTH];
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true, pop))
return Compile_Error;
@ -2613,7 +2619,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_SETGNAME)
{
jsbytecode *next = &PC[JSOP_SETLOCAL_LENGTH];
jsbytecode *next = &PC[JSOP_SETGNAME_LENGTH];
bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
jsop_setgname(script->getAtom(fullAtomIndex(PC)), true, pop);
}
@ -2672,6 +2678,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_CALLLOCAL)
{
restoreVarType();
uint32 slot = GET_SLOTNO(PC);
if (JSObject *singleton = pushedSingleton(0))
frame.push(ObjectValue(*singleton));
@ -6804,42 +6811,6 @@ mjit::Compiler::fixDoubleTypes(jsbytecode *target)
}
}
void
mjit::Compiler::restoreAnalysisTypes()
{
if (!cx->typeInferenceEnabled())
return;
/* Update variable types for all new values at this bytecode. */
const SlotValue *newv = analysis->newValues(PC);
if (newv) {
while (newv->slot) {
if (newv->slot < TotalSlots(script)) {
VarType &vt = a->varTypes[newv->slot];
vt.types = analysis->getValueTypes(newv->value);
vt.type = vt.types->getKnownTypeTag(cx);
}
newv++;
}
}
/*
* Restore known types of locals/args. Skip this for dead entries: the type
* may not be synced, and the slot will not be used anyways.
*/
for (uint32 slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
JSValueType type = a->varTypes[slot].type;
if (type != JSVAL_TYPE_UNKNOWN &&
(type != JSVAL_TYPE_DOUBLE || analysis->trackSlot(slot)) &&
(!analysis->trackSlot(slot) || analysis->liveness(slot).live(PC - script->code))) {
FrameEntry *fe = frame.getSlotEntry(slot);
JS_ASSERT_IF(fe->isTypeKnown(), fe->isType(type));
if (!fe->isTypeKnown())
frame.learnType(fe, type, false);
}
}
}
void
mjit::Compiler::watchGlobalReallocation()
{
@ -6905,6 +6876,49 @@ mjit::Compiler::updateVarType()
}
}
void
mjit::Compiler::updateJoinVarTypes()
{
if (!cx->typeInferenceEnabled())
return;
/* Update variable types for all new values at this bytecode. */
const SlotValue *newv = analysis->newValues(PC);
if (newv) {
while (newv->slot) {
if (newv->slot < TotalSlots(script)) {
VarType &vt = a->varTypes[newv->slot];
vt.types = analysis->getValueTypes(newv->value);
vt.type = vt.types->getKnownTypeTag(cx);
}
newv++;
}
}
}
void
mjit::Compiler::restoreVarType()
{
uint32 slot = GetBytecodeSlot(script, PC);
if (slot >= analyze::TotalSlots(script))
return;
/*
* Restore the known type of a live local or argument. We ensure that types
* of tracked variables match their inferred type (as tracked in varTypes),
* but may have forgotten it due to a branch or syncAndForgetEverything.
*/
JSValueType type = a->varTypes[slot].type;
if (type != JSVAL_TYPE_UNKNOWN &&
(type != JSVAL_TYPE_DOUBLE || analysis->trackSlot(slot))) {
FrameEntry *fe = frame.getSlotEntry(slot);
JS_ASSERT_IF(fe->isTypeKnown(), fe->isType(type));
if (!fe->isTypeKnown())
frame.learnType(fe, type, false);
}
}
JSValueType
mjit::Compiler::knownPushedType(uint32 pushed)
{

View File

@ -535,9 +535,10 @@ class Compiler : public BaseCompiler
CompileStatus prepareInferenceTypes(JSScript *script, ActiveFrame *a);
void ensureDoubleArguments();
void fixDoubleTypes(jsbytecode *target);
void restoreAnalysisTypes();
void watchGlobalReallocation();
void updateVarType();
void updateJoinVarTypes();
void restoreVarType();
JSValueType knownPushedType(uint32 pushed);
bool mayPushUndefined(uint32 pushed);
types::TypeSet *pushedTypeSet(uint32 which);

View File

@ -912,6 +912,8 @@ mjit::Compiler::jsop_andor(JSOp op, jsbytecode *target)
bool
mjit::Compiler::jsop_localinc(JSOp op, uint32 slot)
{
restoreVarType();
types::TypeSet *types = pushedTypeSet(0);
JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
@ -973,6 +975,8 @@ mjit::Compiler::jsop_localinc(JSOp op, uint32 slot)
bool
mjit::Compiler::jsop_arginc(JSOp op, uint32 slot)
{
restoreVarType();
types::TypeSet *types = pushedTypeSet(0);
JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;

View File

@ -918,6 +918,9 @@ FrameState::learnType(FrameEntry *fe, JSValueType type, bool unsync)
JS_ASSERT(!fe->isType(JSVAL_TYPE_DOUBLE));
JS_ASSERT(type != JSVAL_TYPE_UNKNOWN);
if (fe->isCopy())
fe = fe->copyOf();
if (type == JSVAL_TYPE_DOUBLE)
JS_ASSERT(!fe->data.inRegister());
else

View File

@ -873,6 +873,8 @@ mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimi
JS_ASSERT(cx->fp() == fp);
FrameRegs &oldRegs = cx->regs();
fp->scopeChain();
JSBool ok;
{
AssertCompartmentUnchanged pcc(cx);