author | Jan de Mooij <jdemooij@mozilla.com> |
Tue, 17 Jul 2012 13:20:28 +0200 | |
changeset 106554 | 2a4e60c030c594bc766c008c1232513f30f67aba |
parent 106553 | c967c6b03afa3cc95ff7b101478f8d139d79d0e2 |
child 106555 | 699ab277c0b82794a6e19090431623c8f2376354 |
push id | 23447 |
push user | danderson@mozilla.com |
push date | Tue, 11 Sep 2012 17:34:27 +0000 |
treeherder | mozilla-central@fdfaef738a00 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bhackett |
bugs | 773655 |
milestone | 16.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -1003,16 +1003,29 @@ mjit::CanMethodJIT(JSContext *cx, JSScri jith->setValid(jit); } else { jit = jith->getValid(); } 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; if (!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && ++desc.counter <= INFER_USES_BEFORE_COMPILE) { return Compile_Skipped; }
--- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1301,33 +1301,17 @@ JITScript::destroyChunk(FreeOp *fop, uns desc.counter = 0; if (chunkIndex == 0) { if (argsCheckPool) { argsCheckPool->release(); 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(); } } void JITScript::trace(JSTracer *trc) { for (unsigned i = 0; i < nchunks; i++) { ChunkDescriptor &desc = chunkDescriptor(i); @@ -1341,16 +1325,38 @@ JITScript::purgeCaches() { for (unsigned i = 0; i < nchunks; i++) { ChunkDescriptor &desc = chunkDescriptor(i); if (desc.chunk) desc.chunk->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); void JSScript::JITScriptHandle::staticAsserts() { // JITScriptHandle's memory layout must match that of JITScript *. JS_STATIC_ASSERT(sizeof(JSScript::JITScriptHandle) == sizeof(js::mjit::JITScript *));
--- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -774,16 +774,23 @@ struct JITScript uint32_t nedges; /* * Pool for shims which transfer control to the interpreter on cross chunk * edges to chunks which do not have compiled code. */ 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; JSC::CodeLocationLabel argsCheckFallthrough; JSC::CodeLocationJump argsCheckJump; JSC::ExecutablePool *argsCheckPool; void resetArgsCheck(); #endif @@ -824,16 +831,18 @@ struct JITScript size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf); void destroy(FreeOp *fop); void destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses = true); void trace(JSTracer *trc); void purgeCaches(); + + void disableScriptEntry(); }; /* * Execute the given mjit code. This is a low-level call and callers must * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT. */ JaegerStatus EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit, bool partial);
--- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -35,16 +35,20 @@ #include "jsatominlines.h" #include "StubCalls-inl.h" #include "jsfuninlines.h" #include "jstypedarray.h" #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 #include "jsautooplen.h" using namespace js; using namespace js::mjit; @@ -775,18 +779,35 @@ stubs::Interrupt(VMFrame &f, jsbytecode if (!js_HandleExecutionInterrupt(f.cx)) THROW(); } 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); } void JS_FASTCALL stubs::Trap(VMFrame &f, uint32_t trapTypes) { Value rval;