Bug 773655 - Don't destroy JM code before Ion compilation. r=bhackett

This commit is contained in:
Jan de Mooij 2012-07-17 13:20:28 +02:00
parent b63445b8d8
commit a1826885c6
4 changed files with 67 additions and 18 deletions

View File

@ -1008,6 +1008,19 @@ mjit::CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc,
unsigned chunkIndex = jit->chunkIndex(pc);
ChunkDescriptor &desc = jit->chunkDescriptor(chunkIndex);
if (jit->mustDestroyEntryChunk) {
// We kept this chunk around so that Ion can get info from its caches.
// If we end up here, we decided not to use Ion so we can destroy the
// chunk now.
JS_ASSERT(jit->nchunks == 1);
jit->mustDestroyEntryChunk = false;
if (desc.chunk) {
jit->destroyChunk(cx->runtime->defaultFreeOp(), chunkIndex, /* resetUses = */ false);
return Compile_Skipped;
}
}
if (desc.chunk)
return Compile_Okay;

View File

@ -1306,23 +1306,7 @@ JITScript::destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses)
argsCheckPool = NULL;
}
invokeEntry = NULL;
fastEntry = NULL;
argsCheckEntry = NULL;
arityCheckEntry = NULL;
// Fixup any ICs still referring to this chunk.
while (!JS_CLIST_IS_EMPTY(&callers)) {
JS_STATIC_ASSERT(offsetof(ic::CallICInfo, links) == 0);
ic::CallICInfo *ic = (ic::CallICInfo *) callers.next;
uint8_t *start = (uint8_t *)ic->funGuard.executableAddress();
JSC::RepatchBuffer repatch(JSC::JITCode(start - 32, 64));
repatch.repatch(ic->funGuard, NULL);
repatch.relink(ic->funJump, ic->slowPathStart);
ic->purgeGuardedObject();
}
disableScriptEntry();
}
}
@ -1346,6 +1330,28 @@ JITScript::purgeCaches()
}
}
void
JITScript::disableScriptEntry()
{
invokeEntry = NULL;
fastEntry = NULL;
argsCheckEntry = NULL;
arityCheckEntry = NULL;
// Fixup any ICs still referring to this script.
while (!JS_CLIST_IS_EMPTY(&callers)) {
JS_STATIC_ASSERT(offsetof(ic::CallICInfo, links) == 0);
ic::CallICInfo *ic = (ic::CallICInfo *) callers.next;
uint8_t *start = (uint8_t *)ic->funGuard.executableAddress();
JSC::RepatchBuffer repatch(JSC::JITCode(start - 32, 64));
repatch.repatch(ic->funGuard, NULL);
repatch.relink(ic->funJump, ic->slowPathStart);
ic->purgeGuardedObject();
}
}
const js::mjit::JITScript *JSScript::JITScriptHandle::UNJITTABLE =
reinterpret_cast<js::mjit::JITScript *>(1);

View File

@ -779,6 +779,13 @@ struct JITScript
*/
JSC::ExecutablePool *shimPool;
/*
* If set, we decided to keep the JITChunk so that Ion can access its caches.
* The chunk has to be destroyed the next time the script runs in JM.
* Note that this flag implies nchunks == 1.
*/
bool mustDestroyEntryChunk;
#ifdef JS_MONOIC
/* Inline cache at function entry for checking this/argument types. */
JSC::CodeLocationLabel argsCheckStub;
@ -829,6 +836,8 @@ struct JITScript
void trace(JSTracer *trc);
void purgeCaches();
void disableScriptEntry();
};
/*

View File

@ -40,6 +40,10 @@
#include "vm/RegExpObject-inl.h"
#include "vm/String-inl.h"
#ifdef JS_ION
#include "ion/Ion.h"
#endif
#ifdef XP_WIN
# include "jswin.h"
#endif
@ -780,8 +784,25 @@ stubs::Interrupt(VMFrame &f, jsbytecode *pc)
void JS_FASTCALL
stubs::RecompileForInline(VMFrame &f)
{
JSScript *script = f.script();
ExpandInlineFrames(f.cx->compartment);
Recompiler::clearStackReferences(f.cx->runtime->defaultFreeOp(), f.script());
Recompiler::clearStackReferences(f.cx->runtime->defaultFreeOp(), script);
#ifdef JS_ION
if (ion::IsEnabled(f.cx) && f.jit()->nchunks == 1 &&
script->canIonCompile() && !script->hasIonScript())
{
// After returning to the interpreter, IonMonkey will try to compile
// this script. Don't destroy the JITChunk immediately so that Ion
// still has access to its ICs.
JS_ASSERT(!f.jit()->mustDestroyEntryChunk);
f.jit()->mustDestroyEntryChunk = true;
f.jit()->disableScriptEntry();
return;
}
#endif
f.jit()->destroyChunk(f.cx->runtime->defaultFreeOp(), f.chunkIndex(), /* resetUses = */ false);
}