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); unsigned chunkIndex = jit->chunkIndex(pc);
ChunkDescriptor &desc = jit->chunkDescriptor(chunkIndex); 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) if (desc.chunk)
return Compile_Okay; return Compile_Okay;

View File

@ -1306,23 +1306,7 @@ JITScript::destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses)
argsCheckPool = NULL; argsCheckPool = NULL;
} }
invokeEntry = NULL; disableScriptEntry();
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();
}
} }
} }
@ -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 = const js::mjit::JITScript *JSScript::JITScriptHandle::UNJITTABLE =
reinterpret_cast<js::mjit::JITScript *>(1); reinterpret_cast<js::mjit::JITScript *>(1);

View File

@ -779,6 +779,13 @@ struct JITScript
*/ */
JSC::ExecutablePool *shimPool; 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 #ifdef JS_MONOIC
/* Inline cache at function entry for checking this/argument types. */ /* Inline cache at function entry for checking this/argument types. */
JSC::CodeLocationLabel argsCheckStub; JSC::CodeLocationLabel argsCheckStub;
@ -829,6 +836,8 @@ struct JITScript
void trace(JSTracer *trc); void trace(JSTracer *trc);
void purgeCaches(); void purgeCaches();
void disableScriptEntry();
}; };
/* /*

View File

@ -40,6 +40,10 @@
#include "vm/RegExpObject-inl.h" #include "vm/RegExpObject-inl.h"
#include "vm/String-inl.h" #include "vm/String-inl.h"
#ifdef JS_ION
#include "ion/Ion.h"
#endif
#ifdef XP_WIN #ifdef XP_WIN
# include "jswin.h" # include "jswin.h"
#endif #endif
@ -780,8 +784,25 @@ stubs::Interrupt(VMFrame &f, jsbytecode *pc)
void JS_FASTCALL void JS_FASTCALL
stubs::RecompileForInline(VMFrame &f) stubs::RecompileForInline(VMFrame &f)
{ {
JSScript *script = f.script();
ExpandInlineFrames(f.cx->compartment); 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); f.jit()->destroyChunk(f.cx->runtime->defaultFreeOp(), f.chunkIndex(), /* resetUses = */ false);
} }