From a1826885c6a2e0f020c2dc2bbcf388bd80d9e3f7 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Tue, 17 Jul 2012 13:20:28 +0200 Subject: [PATCH] Bug 773655 - Don't destroy JM code before Ion compilation. r=bhackett --- js/src/methodjit/Compiler.cpp | 13 +++++++++++ js/src/methodjit/MethodJIT.cpp | 40 +++++++++++++++++++--------------- js/src/methodjit/MethodJIT.h | 9 ++++++++ js/src/methodjit/StubCalls.cpp | 23 ++++++++++++++++++- 4 files changed, 67 insertions(+), 18 deletions(-) diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 7ea9e487f17..82a479046f8 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -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; diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index ce87c5e1d46..9128bc619b1 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -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(1); diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index 8f3be3c2926..b54fa748e62 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -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(); }; /* diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 03e4092d539..1da5e6032c5 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -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); }