зеркало из https://github.com/mozilla/gecko-dev.git
[INFER] Bail out from IC code on any recompilation/expansion change in the compartment, bug 646006.
This commit is contained in:
Родитель
173fbcdb0c
Коммит
c4ce815d34
|
@ -2009,8 +2009,6 @@ TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
|
|||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
recompilations++;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -658,6 +658,14 @@ struct TypeCompartment
|
|||
/* Pending recompilations to perform before execution of JIT code can resume. */
|
||||
Vector<JSScript*> *pendingRecompiles;
|
||||
|
||||
/*
|
||||
* Number of recompilation events and inline frame expansions that have
|
||||
* occurred in this compartment. If these change, code should not count on
|
||||
* compiled code or the current stack being intact.
|
||||
*/
|
||||
unsigned recompilations;
|
||||
unsigned frameExpansions;
|
||||
|
||||
/* Tables for determining types of singleton/JSON objects. */
|
||||
|
||||
ArrayTypeTable *arrayTypeTable;
|
||||
|
@ -700,9 +708,6 @@ struct TypeCompartment
|
|||
unsigned typeCounts[TYPE_COUNT_LIMIT];
|
||||
unsigned typeCountOver;
|
||||
|
||||
/* Number of recompilations triggered. */
|
||||
unsigned recompilations;
|
||||
|
||||
void init(JSContext *cx);
|
||||
~TypeCompartment();
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#define jsjaeger_h__
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jscompartment.h"
|
||||
|
||||
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
||||
#include "assembler/assembler/CodeLocation.h"
|
||||
|
@ -145,6 +146,12 @@ struct VMFrame
|
|||
|
||||
JSRuntime *runtime() { return cx->runtime; }
|
||||
|
||||
/*
|
||||
* Get the current frame and JIT. Note that these are NOT stable in case
|
||||
* of recompilations; all code which expects these to be stable should
|
||||
* check that cx->recompilations() has not changed across a call that could
|
||||
* trigger recompilation (pretty much any time the VM is called into).
|
||||
*/
|
||||
JSStackFrame *&fp() { return regs.fp; }
|
||||
mjit::JITScript *jit() { return fp()->jit(); }
|
||||
|
||||
|
@ -160,6 +167,30 @@ extern "C" void JaegerStubVeneer(void);
|
|||
|
||||
namespace mjit {
|
||||
|
||||
/* Helper to watch for recompilation and frame expansion activity on a compartment. */
|
||||
struct RecompilationMonitor
|
||||
{
|
||||
JSContext *cx;
|
||||
|
||||
/*
|
||||
* If either a recompilation or expansion occurs, then ICs and stubs should
|
||||
* not depend on the frame or JITs being intact. The two are separated for logging.
|
||||
*/
|
||||
unsigned recompilations;
|
||||
unsigned frameExpansions;
|
||||
|
||||
RecompilationMonitor(JSContext *cx)
|
||||
: cx(cx),
|
||||
recompilations(cx->compartment->types.recompilations),
|
||||
frameExpansions(cx->compartment->types.frameExpansions)
|
||||
{}
|
||||
|
||||
bool recompiled() {
|
||||
return cx->compartment->types.recompilations != recompilations
|
||||
|| cx->compartment->types.frameExpansions != frameExpansions;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Trampolines to force returns from jit code.
|
||||
* See also TrampolineCompiler::generateForceReturn(Fast).
|
||||
|
@ -348,13 +379,6 @@ struct JITScript {
|
|||
uint32 nPICs;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Number of on-stack recompilations of this JIT script. Reset to zero if
|
||||
* the JIT script is destroyed if marked for recompilation with no active
|
||||
* frame on the stack.
|
||||
*/
|
||||
uint32 recompilations;
|
||||
|
||||
#ifdef JS_MONOIC
|
||||
/* Inline cache at function entry for checking this/argument types. */
|
||||
JSC::CodeLocationLabel argsCheckStub;
|
||||
|
|
|
@ -805,13 +805,13 @@ class CallCompiler : public BaseCompiler
|
|||
if (callingNew)
|
||||
vp[1].setMagicWithObjectOrNullPayload(NULL);
|
||||
|
||||
uint32 recompilations = jit->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
|
||||
if (!CallJSNative(cx, fun->u.n.native, ic.frameSize.getArgc(f), vp))
|
||||
THROWV(true);
|
||||
|
||||
/* Don't touch the IC if the call triggered a recompilation. */
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return true;
|
||||
|
||||
/* Right now, take slow-path for IC misses or multiple stubs. */
|
||||
|
@ -985,7 +985,7 @@ class CallCompiler : public BaseCompiler
|
|||
{
|
||||
JSStackFrame *fp = f.fp();
|
||||
JITScript *jit = fp->jit();
|
||||
uint32 recompilations = jit->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
|
||||
stubs::UncachedCallResult ucr;
|
||||
if (callingNew)
|
||||
|
@ -996,7 +996,7 @@ class CallCompiler : public BaseCompiler
|
|||
// Watch out in case the IC was invalidated by a recompilation on the calling
|
||||
// script. This can happen either if the callee is executed or if it compiles
|
||||
// and the compilation has a static overflow.
|
||||
if (fp->jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return ucr.codeAddr;
|
||||
|
||||
// If the function cannot be jitted (generally unjittable or empty script),
|
||||
|
|
|
@ -505,10 +505,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||
JSProperty *prop = NULL;
|
||||
|
||||
/* lookupProperty can trigger recompilations. */
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
if (!obj->lookupProperty(cx, id, &holder, &prop))
|
||||
return error();
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return Lookup_Uncacheable;
|
||||
|
||||
/* If the property exists but is on a prototype, treat as addprop. */
|
||||
|
@ -609,10 +609,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||
return disable("insufficient slot capacity");
|
||||
|
||||
if (pic.typeMonitored) {
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
||||
return error();
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return Lookup_Uncacheable;
|
||||
}
|
||||
|
||||
|
@ -629,10 +629,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||
if (!shape->hasSlot())
|
||||
return disable("invalid slot");
|
||||
if (pic.typeMonitored) {
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
||||
return error();
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return Lookup_Uncacheable;
|
||||
}
|
||||
} else {
|
||||
|
@ -643,7 +643,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
return disable("setter");
|
||||
}
|
||||
if (pic.typeMonitored) {
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
JSScript *script = obj->getCallObjCalleeFunction()->script();
|
||||
uint16 slot = uint16(shape->shortid);
|
||||
if (!script->ensureVarTypes(cx))
|
||||
|
@ -655,7 +655,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
if (!script->typeSetLocal(cx, slot, pic.rhsTypes))
|
||||
return error();
|
||||
}
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return Lookup_Uncacheable;
|
||||
}
|
||||
}
|
||||
|
@ -726,10 +726,10 @@ struct GetPropertyHelper {
|
|||
if (!aobj->isNative())
|
||||
return ic.disable(cx, "non-native");
|
||||
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
if (!aobj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
|
||||
return ic.error(cx);
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return Lookup_Uncacheable;
|
||||
|
||||
if (!prop)
|
||||
|
@ -1869,7 +1869,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
|||
JSFrameRegs ®s = f.regs;
|
||||
|
||||
JSScript *script = f.fp()->script();
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(cx);
|
||||
|
||||
Value lval;
|
||||
lval = regs.sp[-1];
|
||||
|
@ -1960,7 +1960,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
|||
if (regs.sp[-2].isUndefined() && !f.script()->typeMonitorUndefined(cx, f.pc()))
|
||||
THROW();
|
||||
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return;
|
||||
|
||||
GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, DisabledCallPropIC);
|
||||
|
|
|
@ -279,6 +279,12 @@ Recompiler::expandInlineFrames(JSContext *cx, JSStackFrame *fp, mjit::CallSite *
|
|||
{
|
||||
JS_ASSERT_IF(next, next->prev() == fp && next->prevInline() == inlined);
|
||||
|
||||
/*
|
||||
* Treat any frame expansion as a recompilation event, so that f.jit() is
|
||||
* stable if no recompilations have occurred.
|
||||
*/
|
||||
cx->compartment->types.frameExpansions++;
|
||||
|
||||
void **frameAddr = f->returnAddressLocation();
|
||||
bool patchFrameReturn = (f->scratch != NATIVE_CALL_SCRATCH_VALUE && fp->jit()->isValidCode(*frameAddr));
|
||||
|
||||
|
@ -490,25 +496,21 @@ Recompiler::recompile()
|
|||
|
||||
Vector<CallSite> normalSites(cx);
|
||||
Vector<CallSite> ctorSites(cx);
|
||||
uint32 normalRecompilations;
|
||||
uint32 ctorRecompilations;
|
||||
|
||||
if (script->jitNormal && !cleanup(script->jitNormal, &normalSites, &normalRecompilations))
|
||||
if (script->jitNormal && !cleanup(script->jitNormal, &normalSites))
|
||||
return false;
|
||||
if (script->jitCtor && !cleanup(script->jitCtor, &ctorSites, &ctorRecompilations))
|
||||
if (script->jitCtor && !cleanup(script->jitCtor, &ctorSites))
|
||||
return false;
|
||||
|
||||
ReleaseScriptCode(cx, script);
|
||||
|
||||
if (normalFrames.length() &&
|
||||
!recompile(normalFrames, normalPatches, normalSites, normalNatives,
|
||||
normalRecompilations)) {
|
||||
!recompile(normalFrames, normalPatches, normalSites, normalNatives)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctorFrames.length() &&
|
||||
!recompile(ctorFrames, ctorPatches, ctorSites, ctorNatives,
|
||||
ctorRecompilations)) {
|
||||
!recompile(ctorFrames, ctorPatches, ctorSites, ctorNatives)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -523,11 +525,13 @@ Recompiler::recompile()
|
|||
return false;
|
||||
}
|
||||
|
||||
cx->compartment->types.recompilations++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites, uint32 *recompilations)
|
||||
Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites)
|
||||
{
|
||||
while (!JS_CLIST_IS_EMPTY(&jit->callers)) {
|
||||
JaegerSpew(JSpew_Recompile, "Purging IC caller\n");
|
||||
|
@ -550,15 +554,12 @@ Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites, uint32 *recompilati
|
|||
return false;
|
||||
}
|
||||
|
||||
*recompilations = jit->recompilations;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
|
||||
Vector<PatchableNative> &natives,
|
||||
uint32 recompilations)
|
||||
Vector<PatchableNative> &natives)
|
||||
{
|
||||
JSStackFrame *fp = frames[0].fp;
|
||||
|
||||
|
@ -577,7 +578,6 @@ Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &
|
|||
return false;
|
||||
|
||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||
jit->recompilations = recompilations + 1;
|
||||
|
||||
/* Perform the earlier scanned patches */
|
||||
for (uint32 i = 0; i < patches.length(); i++)
|
||||
|
|
|
@ -118,14 +118,13 @@ private:
|
|||
void patchNative(JITScript *jit, PatchableNative &native);
|
||||
bool recompile(Vector<PatchableFrame> &frames,
|
||||
Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
|
||||
Vector<PatchableNative> &natives,
|
||||
uint32 recompilations);
|
||||
Vector<PatchableNative> &natives);
|
||||
|
||||
static JSStackFrame *
|
||||
expandInlineFrameChain(JSContext *cx, JSStackFrame *outer, InlineFrame *inner);
|
||||
|
||||
/* Detach jit from any IC callers and save any traps to sites. */
|
||||
bool cleanup(JITScript *jit, Vector<CallSite> *sites, uint32 *recompilations);
|
||||
bool cleanup(JITScript *jit, Vector<CallSite> *sites);
|
||||
};
|
||||
|
||||
} /* namespace mjit */
|
||||
|
|
|
@ -2814,8 +2814,7 @@ stubs::CheckArgumentTypes(VMFrame &f)
|
|||
JSStackFrame *fp = f.fp();
|
||||
JSFunction *fun = fp->fun();
|
||||
JSScript *script = fun->script();
|
||||
|
||||
uint32 recompilations = f.jit()->recompilations;
|
||||
RecompilationMonitor monitor(f.cx);
|
||||
|
||||
/* Postpone recompilations until all args have been updated. */
|
||||
types::AutoEnterTypeInference enter(f.cx);
|
||||
|
@ -2833,7 +2832,7 @@ stubs::CheckArgumentTypes(VMFrame &f)
|
|||
if (!f.cx->compartment->types.checkPendingRecompiles(f.cx))
|
||||
THROW();
|
||||
|
||||
if (f.jit()->recompilations != recompilations)
|
||||
if (monitor.recompiled())
|
||||
return;
|
||||
|
||||
#ifdef JS_MONOIC
|
||||
|
|
Загрузка…
Ссылка в новой задаче