mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Fold FrameState closed vars/args analysis into analyze::Script, bug 642569.
This commit is contained in:
parent
99c7da4cca
commit
c738c5d025
13
js/src/jit-test/tests/basic/bug642569.js
Normal file
13
js/src/jit-test/tests/basic/bug642569.js
Normal 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);
|
@ -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);
|
||||
if (!locals)
|
||||
return false;
|
||||
PodZero(locals, script->nfixed);
|
||||
} else {
|
||||
locals = NULL;
|
||||
}
|
||||
unsigned nfixed = analysis->localCount();
|
||||
locals = ArenaArray<LifetimeVariable>(pool, nfixed);
|
||||
if (!locals)
|
||||
return false;
|
||||
PodZero(locals, nfixed);
|
||||
|
||||
if (fun && fun->nargs) {
|
||||
args = ArenaArray<LifetimeVariable>(pool, fun->nargs);
|
||||
if (!args)
|
||||
return false;
|
||||
PodZero(args, fun->nargs);
|
||||
} else {
|
||||
args = NULL;
|
||||
}
|
||||
unsigned nargs = fun ? fun->nargs : 0;
|
||||
args = ArenaArray<LifetimeVariable>(pool, nargs);
|
||||
if (!args)
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user