[INFER] Don't discard JIT code for the topmost frame while recompiling, bug 647424.

This commit is contained in:
Brian Hackett 2011-04-03 14:37:50 -07:00
parent 54470b0628
commit 55790989cb
4 changed files with 49 additions and 59 deletions

View File

@ -89,14 +89,12 @@ static const char *OpcodeNames[] = {
*/
static const size_t CALLS_BACKEDGES_BEFORE_INLINING = 10000;
mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript,
bool isConstructing, bool isEval, JSObject *globalObj,
mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing,
const Vector<PatchableFrame> *patchFrames, bool recompiling)
: BaseCompiler(cx),
outerScript(outerScript),
isConstructing(isConstructing),
isEval(isEval),
globalObj(globalObj),
globalObj(outerScript->global),
patchFrames(patchFrames),
savedTraps(NULL),
frame(cx, *this, masm, stubcc),
@ -345,7 +343,7 @@ mjit::Compiler::performCompilation(JITScript **jitp)
if (!script->jitNormal) {
CompileStatus status = Compile_Retry;
while (status == Compile_Retry) {
mjit::Compiler cc(cx, script, isConstructing, false, globalObj, NULL, true);
mjit::Compiler cc(cx, script, isConstructing, NULL, true);
status = cc.compile();
}
if (status != Compile_Okay) {
@ -450,8 +448,7 @@ mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
// before giving up.
CompileStatus status = Compile_Retry;
for (unsigned i = 0; status == Compile_Retry && i < 5; i++) {
Compiler cc(cx, fp->script(), fp->isConstructing(), fp->isEvalFrame(),
fp->scopeChain().getGlobal(), NULL, fp->script()->inlineParents);
Compiler cc(cx, fp->script(), fp->isConstructing(), NULL, fp->script()->inlineParents);
status = cc.compile();
}
@ -2961,30 +2958,22 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
* even on the entry frame. To avoid double-putting, EnterMethodJIT clears
* out the entry frame's activation objects.
*/
if (script->fun) {
if (script->fun->isHeavyweight()) {
/* There will always be a call object. */
prepareStubCall(Uses(fe ? 1 : 0));
INLINE_STUBCALL(stubs::PutActivationObjects);
} else {
/* if (hasCallObj() || hasArgsObj()) */
Jump putObjs = masm.branchTest32(Assembler::NonZero,
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
stubcc.linkExit(putObjs, Uses(frame.frameSlots()));
stubcc.leave();
OOL_STUBCALL(stubs::PutActivationObjects);
emitReturnValue(&stubcc.masm, fe);
emitFinalReturn(stubcc.masm);
}
if (script->fun && script->fun->isHeavyweight()) {
/* There will always be a call object. */
prepareStubCall(Uses(fe ? 1 : 0));
INLINE_STUBCALL(stubs::PutActivationObjects);
} else {
if (isEval && script->strictModeCode) {
/* There will always be a call object. */
prepareStubCall(Uses(fe ? 1 : 0));
INLINE_STUBCALL(stubs::PutActivationObjects);
}
/* if (hasCallObj() || hasArgsObj()) */
Jump putObjs = masm.branchTest32(Assembler::NonZero,
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
stubcc.linkExit(putObjs, Uses(frame.frameSlots()));
stubcc.leave();
OOL_STUBCALL(stubs::PutActivationObjects);
emitReturnValue(&stubcc.masm, fe);
emitFinalReturn(stubcc.masm);
}
emitReturnValue(&masm, fe);

View File

@ -354,7 +354,6 @@ class Compiler : public BaseCompiler
JSScript *outerScript;
bool isConstructing;
bool isEval;
JSObject *globalObj;
@ -453,8 +452,7 @@ class Compiler : public BaseCompiler
// follows interpreter usage in JSOP_LENGTH.
enum { LengthAtomIndex = uint32(-2) };
Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing, bool isEval,
JSObject *globalObj,
Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing,
const Vector<PatchableFrame> *patchFrames, bool recompiling);
~Compiler();

View File

@ -511,26 +511,29 @@ Recompiler::recompile()
ReleaseScriptCode(cx, script, true);
ReleaseScriptCode(cx, script, false);
if (normalFrames.length() &&
!recompile(normalFrames, normalPatches, normalSites, normalNatives)) {
/*
* Regenerate the code if there are JIT frames on the stack, if this script
* has inline parents and thus always needs JIT code, or if it is a newly
* pushed frame by e.g. the interpreter. :XXX: it would be nice if we could
* ensure that compiling a script does not then trigger its recompilation.
*/
JSStackFrame *top = (cx->fp() && cx->fp()->isScriptFrame()) ? cx->fp() : NULL;
bool keepNormal = !normalFrames.empty() || script->inlineParents ||
(top && top->script() == script && !top->isConstructing());
bool keepCtor = !ctorFrames.empty() ||
(top && top->script() == script && top->isConstructing());
if (keepNormal && !recompile(script, false,
normalFrames, normalPatches, normalSites, normalNatives)) {
return false;
}
if (keepCtor && !recompile(script, true,
ctorFrames, ctorPatches, ctorSites, ctorNatives)) {
return false;
}
if (ctorFrames.length() &&
!recompile(ctorFrames, ctorPatches, ctorSites, ctorNatives)) {
return false;
}
/* Make sure that scripts with inline parents still have JIT code. */
if (script->inlineParents && !script->jitNormal) {
CompileStatus status = Compile_Retry;
while (status == Compile_Retry) {
mjit::Compiler cc(cx, script, false, false, script->global, NULL, true);
status = cc.compile();
}
if (status != Compile_Okay)
return false;
}
JS_ASSERT_IF(keepNormal, script->jitNormal);
JS_ASSERT_IF(keepCtor, script->jitCtor);
cx->compartment->types.recompilations++;
@ -568,18 +571,17 @@ Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites)
}
bool
Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
Recompiler::recompile(JSScript *script, bool isConstructing,
Vector<PatchableFrame> &frames,
Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
Vector<PatchableNative> &natives)
{
JSStackFrame *fp = frames[0].fp;
JaegerSpew(JSpew_Recompile, "On stack recompilation, %u patches, %u natives\n",
patches.length(), natives.length());
JaegerSpew(JSpew_Recompile, "On stack recompilation, %u frames, %u patches, %u natives\n",
frames.length(), patches.length(), natives.length());
CompileStatus status = Compile_Retry;
while (status == Compile_Retry) {
Compiler cc(cx, fp->script(), fp->isConstructing(), fp->isEvalFrame(),
fp->scopeChain().getGlobal(), &frames, true);
Compiler cc(cx, script, isConstructing, &frames, true);
if (!cc.loadOldTraps(sites))
return false;
status = cc.compile();
@ -587,7 +589,7 @@ Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &
if (status != Compile_Okay)
return false;
JITScript *jit = script->getJIT(fp->isConstructing());
JITScript *jit = script->getJIT(isConstructing);
/* Perform the earlier scanned patches */
for (uint32 i = 0; i < patches.length(); i++)

View File

@ -116,7 +116,8 @@ private:
static void applyPatch(JITScript *jit, PatchableAddress& toPatch);
PatchableNative stealNative(JITScript *jit, jsbytecode *pc);
void patchNative(JITScript *jit, PatchableNative &native);
bool recompile(Vector<PatchableFrame> &frames,
bool recompile(JSScript *script, bool isConstructing,
Vector<PatchableFrame> &frames,
Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
Vector<PatchableNative> &natives);