[INFER] Fold FrameState closed vars/args analysis into analyze::Script, bug 642569.

This commit is contained in:
Brian Hackett 2011-03-20 08:23:27 -07:00
parent 99c7da4cca
commit c738c5d025
7 changed files with 72 additions and 124 deletions

View File

@ -0,0 +1,13 @@
function main() {
var v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42,
v43, v44, v45, v46, v47;
var v48 = 0, v49 = 0;
if (true) {
var v50 = v48 - 1;
var v51 = v49 + 1;
return v51;
}
}
assertEq(main(), 1);

View File

@ -248,12 +248,15 @@ Script::analyze(JSContext *cx, JSScript *script)
this->script = script;
unsigned length = script->length;
unsigned nargs = script->fun ? script->fun->nargs : 0;
unsigned nfixed = localCount();
codeArray = ArenaArray<Bytecode*>(pool, length);
locals = ArenaArray<uint32>(pool, nfixed);
closedArgs = ArenaArray<JSPackedBool>(pool, nargs);
closedVars = ArenaArray<JSPackedBool>(pool, nfixed);
if (!codeArray || !locals) {
if (!codeArray || !locals || !closedArgs || !closedVars) {
setOOM(cx);
return;
}
@ -263,6 +266,20 @@ Script::analyze(JSContext *cx, JSScript *script)
for (unsigned i = 0; i < nfixed; i++)
locals[i] = LOCAL_CONDITIONALLY_DEFINED;
PodZero(closedArgs, nargs);
for (uint32 i = 0; i < script->nClosedArgs; i++) {
unsigned arg = script->getClosedArg(i);
JS_ASSERT(arg < nargs);
closedArgs[arg] = true;
}
PodZero(closedVars, nfixed);
for (uint32 i = 0; i < script->nClosedVars; i++) {
unsigned local = script->getClosedVar(i);
if (local < nfixed)
closedVars[local] = true;
}
/*
* Treat locals as having a possible use-before-def if they could be accessed
* by debug code or by eval, or if they could be accessed by an inner script.
@ -640,8 +657,8 @@ Script::analyze(JSContext *cx, JSScript *script)
/////////////////////////////////////////////////////////////////////
LifetimeScript::LifetimeScript()
: analysis(NULL), script(NULL), fun(NULL), codeArray(NULL)
{
PodZero(this);
JS_InitArenaPool(&pool, "script_liverange", 256, 8, NULL);
}
@ -664,27 +681,21 @@ LifetimeScript::analyze(JSContext *cx, analyze::Script *analysis, JSScript *scri
return false;
PodZero(codeArray, script->length);
if (script->nfixed) {
locals = ArenaArray<LifetimeVariable>(pool, script->nfixed);
unsigned nfixed = analysis->localCount();
locals = ArenaArray<LifetimeVariable>(pool, nfixed);
if (!locals)
return false;
PodZero(locals, script->nfixed);
} else {
locals = NULL;
}
PodZero(locals, nfixed);
if (fun && fun->nargs) {
args = ArenaArray<LifetimeVariable>(pool, fun->nargs);
unsigned nargs = fun ? fun->nargs : 0;
args = ArenaArray<LifetimeVariable>(pool, nargs);
if (!args)
return false;
PodZero(args, fun->nargs);
} else {
args = NULL;
}
PodZero(args, nargs);
PodZero(&thisVar);
saved = ArenaArray<LifetimeVariable*>(pool, script->nfixed + (fun ? fun->nargs : 0));
saved = ArenaArray<LifetimeVariable*>(pool, nfixed + nargs + 1);
if (!saved)
return false;
savedCount = 0;
@ -707,11 +718,11 @@ LifetimeScript::analyze(JSContext *cx, analyze::Script *analysis, JSScript *scri
* and extend it to the end of the loop.
*/
unsigned backedge = codeArray[offset].loopBackedge;
for (unsigned i = 0; i < script->nfixed; i++) {
for (unsigned i = 0; i < nfixed; i++) {
if (locals[i].lifetime && !extendVariable(cx, locals[i], offset, backedge))
return false;
}
for (unsigned i = 0; fun && i < fun->nargs; i++) {
for (unsigned i = 0; i < nargs; i++) {
if (args[i].lifetime && !extendVariable(cx, args[i], offset, backedge))
return false;
}
@ -752,6 +763,7 @@ LifetimeScript::analyze(JSContext *cx, analyze::Script *analysis, JSScript *scri
case JSOP_GETLOCALPROP: {
unsigned local = GET_SLOTNO(pc);
if (!analysis->localEscapes(local)) {
JS_ASSERT(local < nfixed);
if (!addVariable(cx, locals[local], offset))
return false;
}
@ -762,8 +774,10 @@ LifetimeScript::analyze(JSContext *cx, analyze::Script *analysis, JSScript *scri
case JSOP_SETLOCALPOP:
case JSOP_DEFLOCALFUN: {
unsigned local = GET_SLOTNO(pc);
if (!analysis->localEscapes(local))
if (!analysis->localEscapes(local)) {
JS_ASSERT(local < nfixed);
killVariable(cx, locals[local], offset);
}
break;
}

View File

@ -140,6 +140,9 @@ class Script
bool usesRval;
bool usesScope;
JSPackedBool *closedVars;
JSPackedBool *closedArgs;
public:
/* Pool for allocating analysis structures which will not outlive this script. */
JSArenaPool pool;
@ -204,26 +207,15 @@ class Script
bool argEscapes(unsigned arg)
{
if (script->usesEval || script->usesArguments || script->compartment->debugMode)
return true;
for (unsigned i = 0; i < script->nClosedArgs; i++) {
if (arg == script->getClosedArg(i))
return true;
}
return false;
JS_ASSERT(script->fun && arg < script->fun->nargs);
return script->usesEval || script->usesArguments || script->compartment->debugMode ||
closedArgs[arg];
}
bool localEscapes(unsigned local)
{
if (script->usesEval || script->compartment->debugMode)
return true;
if (local >= localCount())
return true;
for (unsigned i = 0; i < script->nClosedVars; i++) {
if (local == script->getClosedVar(i))
return true;
}
return false;
return script->usesEval || script->compartment->debugMode || local >= localCount() ||
closedVars[local];
}
private:
@ -424,8 +416,14 @@ class LifetimeScript
void dumpArg(unsigned i) { dumpVariable(args[i]); }
#endif
Lifetime * argLive(uint32 arg, uint32 offset) { return args[arg].live(offset); }
Lifetime * localLive(uint32 local, uint32 offset) { return locals[local].live(offset); }
Lifetime * argLive(uint32 arg, uint32 offset) {
JS_ASSERT(fun && arg < fun->nargs);
return args[arg].live(offset);
}
Lifetime * localLive(uint32 local, uint32 offset) {
JS_ASSERT(local < analysis->localCount());
return locals[local].live(offset);
}
Lifetime * thisLive(uint32 offset) { return thisVar.live(offset); }
private:

View File

@ -242,11 +242,6 @@ mjit::Compiler::performCompilation(JITScript **jitp)
script->debugMode = debugMode();
#endif
for (uint32 i = 0; i < script->nClosedVars; i++)
frame.setClosedVar(script->getClosedVar(i));
for (uint32 i = 0; i < script->nClosedArgs; i++)
frame.setClosedArg(script->getClosedArg(i));
types::AutoEnterTypeInference enter(cx, true);
if (cx->typeInferenceEnabled()) {
@ -5411,23 +5406,12 @@ mjit::Compiler::enterBlock(JSObject *obj)
interruptCheckHelper();
}
uint32 oldFrameDepth = frame.localSlots();
/* For now, don't bother doing anything for this opcode. */
frame.syncAndForgetEverything();
masm.move(ImmPtr(obj), Registers::ArgReg1);
uint32 n = js_GetEnterBlockStackDefs(cx, script, PC);
INLINE_STUBCALL(stubs::EnterBlock);
frame.enterBlock(n);
uintN base = JSSLOT_FREE(&js_BlockClass);
uintN count = OBJ_BLOCK_COUNT(cx, obj);
uintN limit = base + count;
for (uintN slot = base, i = 0; slot < limit; slot++, i++) {
const Value &v = obj->getSlotRef(slot);
if (v.isBoolean() && v.toBoolean())
frame.setClosedVar(oldFrameDepth + i);
}
}
void

View File

@ -1088,7 +1088,7 @@ inline void
FrameState::pushLocal(uint32 n, JSValueType knownType)
{
FrameEntry *fe = getLocal(n);
if (!isClosedVar(n)) {
if (!analysis->localEscapes(n)) {
pushCopyOf(indexOfFe(fe));
} else {
#ifdef DEBUG
@ -1111,7 +1111,7 @@ inline void
FrameState::pushArg(uint32 n, JSValueType knownType)
{
FrameEntry *fe = getArg(n);
if (!isClosedArg(n)) {
if (!analysis->argEscapes(n)) {
pushCopyOf(indexOfFe(fe));
} else {
#ifdef DEBUG
@ -1159,8 +1159,6 @@ FrameState::enterBlock(uint32 n)
JS_ASSERT(!tracker.nentries);
JS_ASSERT(uint32(sp + n - locals) <= script->nslots);
if (!eval)
memset(&closedVars[uint32(sp - locals)], 0, n * sizeof(*closedVars));
sp += n;
}
@ -1174,20 +1172,6 @@ FrameState::eviscerate(FrameEntry *fe)
fe->setCopyOf(NULL);
}
inline void
FrameState::setClosedVar(uint32 slot)
{
if (!eval)
closedVars[slot] = true;
}
inline void
FrameState::setClosedArg(uint32 slot)
{
if (!eval && !usesArguments)
closedArgs[slot] = true;
}
inline StateRemat
FrameState::dataRematInfo(const FrameEntry *fe) const
{
@ -1262,18 +1246,6 @@ FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) cons
masm.loadDouble(addressOf(fe), fpReg);
}
inline bool
FrameState::isClosedVar(uint32 slot) const
{
return eval || closedVars[slot];
}
inline bool
FrameState::isClosedArg(uint32 slot) const
{
return eval || usesArguments || closedArgs[slot];
}
class PinRegAcrossSyncAndKill
{
typedef JSC::MacroAssembler::RegisterID RegisterID;

View File

@ -61,9 +61,6 @@ FrameState::FrameState(JSContext *cx, JSScript *script, JSFunction *fun,
#if defined JS_NUNBOX32
reifier(cx, *thisFromCtor()),
#endif
closedVars(NULL),
closedArgs(NULL),
usesArguments(script->usesArguments),
inTryBlock(false)
{
}
@ -83,17 +80,9 @@ FrameState::init()
return true;
}
eval = script->usesEval || cx->compartment->debugMode;
size_t totalBytes = sizeof(FrameEntry) * nentries + // entries[], w/ callee+this
sizeof(FrameEntry *) * nentries + // tracker.entries
sizeof(types::TypeSet *) * script->nslots + // typeSets
(eval
? 0
: sizeof(JSPackedBool) * script->nslots) + // closedVars[]
(eval || usesArguments
? 0
: sizeof(JSPackedBool) * nargs); // closedArgs[]
sizeof(types::TypeSet *) * script->nslots; // typeSets
uint8 *cursor = (uint8 *)cx->calloc(totalBytes);
if (!cursor)
@ -120,17 +109,6 @@ FrameState::init()
typeSets = (types::TypeSet **)cursor;
cursor += sizeof(types::TypeSet *) * script->nslots;
if (!eval) {
if (script->nslots) {
closedVars = (JSPackedBool *)cursor;
cursor += sizeof(JSPackedBool) * script->nslots;
}
if (!usesArguments && nargs) {
closedArgs = (JSPackedBool *)cursor;
cursor += sizeof(JSPackedBool) * nargs;
}
}
JS_ASSERT(reinterpret_cast<uint8 *>(entries) + totalBytes == cursor);
return true;
@ -196,11 +174,11 @@ FrameState::variableLive(FrameEntry *fe, jsbytecode *pc) const
if (fe == this_)
return liveness.thisLive(offset);
if (isArg(fe)) {
JS_ASSERT(!isClosedArg(fe - args));
JS_ASSERT(!analysis->argEscapes(fe - args));
return liveness.argLive(fe - args, offset);
}
if (isLocal(fe)) {
JS_ASSERT(!isClosedVar(fe - locals));
JS_ASSERT(!analysis->localEscapes(fe - locals));
return liveness.localLive(fe - locals, offset);
}
@ -1913,7 +1891,7 @@ FrameState::storeLocal(uint32 n, JSValueType type, bool popGuaranteed, bool fixe
{
FrameEntry *local = getLocal(n);
if (isClosedVar(n)) {
if (analysis->localEscapes(n)) {
JS_ASSERT(local->data.inMemory());
storeTo(peek(-1), addressOf(local), popGuaranteed);
return;
@ -1941,7 +1919,7 @@ FrameState::storeArg(uint32 n, JSValueType type, bool popGuaranteed)
// aliased (but not written to) via f.arguments.
FrameEntry *arg = getArg(n);
if (isClosedArg(n)) {
if (analysis->argEscapes(n)) {
JS_ASSERT(arg->data.inMemory());
storeTo(peek(-1), addressOf(arg), popGuaranteed);
return;

View File

@ -822,10 +822,6 @@ class FrameState
*/
void shift(int32 n);
// Notifies the frame that a local variable or argument slot is closed over.
inline void setClosedVar(uint32 slot);
inline void setClosedArg(uint32 slot);
inline void setInTryBlock(bool inTryBlock) {
this->inTryBlock = inTryBlock;
}
@ -924,9 +920,6 @@ class FrameState
}
uint32 feLimit() const { return script->nslots + nargs + 2; }
inline bool isClosedVar(uint32 slot) const;
inline bool isClosedArg(uint32 slot) const;
RegisterState & regstate(AnyRegisterID reg) {
JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
return regstate_[reg.reg_];
@ -1045,10 +1038,6 @@ class FrameState
mutable ImmutableSync reifier;
#endif
JSPackedBool *closedVars;
JSPackedBool *closedArgs;
bool eval;
bool usesArguments;
bool inTryBlock;
};