mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Bail out from IC code on any recompilation/expansion change in the compartment, bug 646006.
This commit is contained in:
parent
ed887865ed
commit
7b1f08d78a
@ -2009,8 +2009,6 @@ TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
|
|||||||
cx->compartment->types.setPendingNukeTypes(cx);
|
cx->compartment->types.setPendingNukeTypes(cx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
recompilations++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -658,6 +658,14 @@ struct TypeCompartment
|
|||||||
/* Pending recompilations to perform before execution of JIT code can resume. */
|
/* Pending recompilations to perform before execution of JIT code can resume. */
|
||||||
Vector<JSScript*> *pendingRecompiles;
|
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. */
|
/* Tables for determining types of singleton/JSON objects. */
|
||||||
|
|
||||||
ArrayTypeTable *arrayTypeTable;
|
ArrayTypeTable *arrayTypeTable;
|
||||||
@ -700,9 +708,6 @@ struct TypeCompartment
|
|||||||
unsigned typeCounts[TYPE_COUNT_LIMIT];
|
unsigned typeCounts[TYPE_COUNT_LIMIT];
|
||||||
unsigned typeCountOver;
|
unsigned typeCountOver;
|
||||||
|
|
||||||
/* Number of recompilations triggered. */
|
|
||||||
unsigned recompilations;
|
|
||||||
|
|
||||||
void init(JSContext *cx);
|
void init(JSContext *cx);
|
||||||
~TypeCompartment();
|
~TypeCompartment();
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#define jsjaeger_h__
|
#define jsjaeger_h__
|
||||||
|
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
#include "jscompartment.h"
|
||||||
|
|
||||||
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
#include "assembler/assembler/MacroAssemblerCodeRef.h"
|
||||||
#include "assembler/assembler/CodeLocation.h"
|
#include "assembler/assembler/CodeLocation.h"
|
||||||
@ -145,6 +146,12 @@ struct VMFrame
|
|||||||
|
|
||||||
JSRuntime *runtime() { return cx->runtime; }
|
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; }
|
JSStackFrame *&fp() { return regs.fp; }
|
||||||
mjit::JITScript *jit() { return fp()->jit(); }
|
mjit::JITScript *jit() { return fp()->jit(); }
|
||||||
|
|
||||||
@ -160,6 +167,30 @@ extern "C" void JaegerStubVeneer(void);
|
|||||||
|
|
||||||
namespace mjit {
|
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.
|
* Trampolines to force returns from jit code.
|
||||||
* See also TrampolineCompiler::generateForceReturn(Fast).
|
* See also TrampolineCompiler::generateForceReturn(Fast).
|
||||||
@ -348,13 +379,6 @@ struct JITScript {
|
|||||||
uint32 nPICs;
|
uint32 nPICs;
|
||||||
#endif
|
#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
|
#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;
|
||||||
|
@ -805,13 +805,13 @@ class CallCompiler : public BaseCompiler
|
|||||||
if (callingNew)
|
if (callingNew)
|
||||||
vp[1].setMagicWithObjectOrNullPayload(NULL);
|
vp[1].setMagicWithObjectOrNullPayload(NULL);
|
||||||
|
|
||||||
uint32 recompilations = jit->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
|
|
||||||
if (!CallJSNative(cx, fun->u.n.native, ic.frameSize.getArgc(f), vp))
|
if (!CallJSNative(cx, fun->u.n.native, ic.frameSize.getArgc(f), vp))
|
||||||
THROWV(true);
|
THROWV(true);
|
||||||
|
|
||||||
/* Don't touch the IC if the call triggered a recompilation. */
|
/* Don't touch the IC if the call triggered a recompilation. */
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Right now, take slow-path for IC misses or multiple stubs. */
|
/* Right now, take slow-path for IC misses or multiple stubs. */
|
||||||
@ -985,7 +985,7 @@ class CallCompiler : public BaseCompiler
|
|||||||
{
|
{
|
||||||
JSStackFrame *fp = f.fp();
|
JSStackFrame *fp = f.fp();
|
||||||
JITScript *jit = fp->jit();
|
JITScript *jit = fp->jit();
|
||||||
uint32 recompilations = jit->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
|
|
||||||
stubs::UncachedCallResult ucr;
|
stubs::UncachedCallResult ucr;
|
||||||
if (callingNew)
|
if (callingNew)
|
||||||
@ -996,7 +996,7 @@ class CallCompiler : public BaseCompiler
|
|||||||
// Watch out in case the IC was invalidated by a recompilation on the calling
|
// 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
|
// script. This can happen either if the callee is executed or if it compiles
|
||||||
// and the compilation has a static overflow.
|
// and the compilation has a static overflow.
|
||||||
if (fp->jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return ucr.codeAddr;
|
return ucr.codeAddr;
|
||||||
|
|
||||||
// If the function cannot be jitted (generally unjittable or empty script),
|
// If the function cannot be jitted (generally unjittable or empty script),
|
||||||
|
@ -505,10 +505,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||||||
JSProperty *prop = NULL;
|
JSProperty *prop = NULL;
|
||||||
|
|
||||||
/* lookupProperty can trigger recompilations. */
|
/* lookupProperty can trigger recompilations. */
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
if (!obj->lookupProperty(cx, id, &holder, &prop))
|
if (!obj->lookupProperty(cx, id, &holder, &prop))
|
||||||
return error();
|
return error();
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return Lookup_Uncacheable;
|
return Lookup_Uncacheable;
|
||||||
|
|
||||||
/* If the property exists but is on a prototype, treat as addprop. */
|
/* 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");
|
return disable("insufficient slot capacity");
|
||||||
|
|
||||||
if (pic.typeMonitored) {
|
if (pic.typeMonitored) {
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
||||||
return error();
|
return error();
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return Lookup_Uncacheable;
|
return Lookup_Uncacheable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,10 +629,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||||||
if (!shape->hasSlot())
|
if (!shape->hasSlot())
|
||||||
return disable("invalid slot");
|
return disable("invalid slot");
|
||||||
if (pic.typeMonitored) {
|
if (pic.typeMonitored) {
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
if (!cx->addTypePropertyId(obj->getType(), shape->id, pic.rhsTypes))
|
||||||
return error();
|
return error();
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return Lookup_Uncacheable;
|
return Lookup_Uncacheable;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -643,7 +643,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||||||
return disable("setter");
|
return disable("setter");
|
||||||
}
|
}
|
||||||
if (pic.typeMonitored) {
|
if (pic.typeMonitored) {
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
JSScript *script = obj->getCallObjCalleeFunction()->script();
|
JSScript *script = obj->getCallObjCalleeFunction()->script();
|
||||||
uint16 slot = uint16(shape->shortid);
|
uint16 slot = uint16(shape->shortid);
|
||||||
if (!script->ensureVarTypes(cx))
|
if (!script->ensureVarTypes(cx))
|
||||||
@ -655,7 +655,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||||||
if (!script->typeSetLocal(cx, slot, pic.rhsTypes))
|
if (!script->typeSetLocal(cx, slot, pic.rhsTypes))
|
||||||
return error();
|
return error();
|
||||||
}
|
}
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return Lookup_Uncacheable;
|
return Lookup_Uncacheable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -726,10 +726,10 @@ struct GetPropertyHelper {
|
|||||||
if (!aobj->isNative())
|
if (!aobj->isNative())
|
||||||
return ic.disable(cx, "non-native");
|
return ic.disable(cx, "non-native");
|
||||||
|
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
if (!aobj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
|
if (!aobj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
|
||||||
return ic.error(cx);
|
return ic.error(cx);
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return Lookup_Uncacheable;
|
return Lookup_Uncacheable;
|
||||||
|
|
||||||
if (!prop)
|
if (!prop)
|
||||||
@ -1869,7 +1869,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
|
|||||||
JSFrameRegs ®s = f.regs;
|
JSFrameRegs ®s = f.regs;
|
||||||
|
|
||||||
JSScript *script = f.fp()->script();
|
JSScript *script = f.fp()->script();
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
RecompilationMonitor monitor(cx);
|
||||||
|
|
||||||
Value lval;
|
Value lval;
|
||||||
lval = regs.sp[-1];
|
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()))
|
if (regs.sp[-2].isUndefined() && !f.script()->typeMonitorUndefined(cx, f.pc()))
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, DisabledCallPropIC);
|
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);
|
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();
|
void **frameAddr = f->returnAddressLocation();
|
||||||
bool patchFrameReturn = (f->scratch != NATIVE_CALL_SCRATCH_VALUE && fp->jit()->isValidCode(*frameAddr));
|
bool patchFrameReturn = (f->scratch != NATIVE_CALL_SCRATCH_VALUE && fp->jit()->isValidCode(*frameAddr));
|
||||||
|
|
||||||
@ -490,25 +496,21 @@ Recompiler::recompile()
|
|||||||
|
|
||||||
Vector<CallSite> normalSites(cx);
|
Vector<CallSite> normalSites(cx);
|
||||||
Vector<CallSite> ctorSites(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;
|
return false;
|
||||||
if (script->jitCtor && !cleanup(script->jitCtor, &ctorSites, &ctorRecompilations))
|
if (script->jitCtor && !cleanup(script->jitCtor, &ctorSites))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReleaseScriptCode(cx, script);
|
ReleaseScriptCode(cx, script);
|
||||||
|
|
||||||
if (normalFrames.length() &&
|
if (normalFrames.length() &&
|
||||||
!recompile(normalFrames, normalPatches, normalSites, normalNatives,
|
!recompile(normalFrames, normalPatches, normalSites, normalNatives)) {
|
||||||
normalRecompilations)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctorFrames.length() &&
|
if (ctorFrames.length() &&
|
||||||
!recompile(ctorFrames, ctorPatches, ctorSites, ctorNatives,
|
!recompile(ctorFrames, ctorPatches, ctorSites, ctorNatives)) {
|
||||||
ctorRecompilations)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,11 +525,13 @@ Recompiler::recompile()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx->compartment->types.recompilations++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites, uint32 *recompilations)
|
Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites)
|
||||||
{
|
{
|
||||||
while (!JS_CLIST_IS_EMPTY(&jit->callers)) {
|
while (!JS_CLIST_IS_EMPTY(&jit->callers)) {
|
||||||
JaegerSpew(JSpew_Recompile, "Purging IC caller\n");
|
JaegerSpew(JSpew_Recompile, "Purging IC caller\n");
|
||||||
@ -550,15 +554,12 @@ Recompiler::cleanup(JITScript *jit, Vector<CallSite> *sites, uint32 *recompilati
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*recompilations = jit->recompilations;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
|
Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
|
||||||
Vector<PatchableNative> &natives,
|
Vector<PatchableNative> &natives)
|
||||||
uint32 recompilations)
|
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = frames[0].fp;
|
JSStackFrame *fp = frames[0].fp;
|
||||||
|
|
||||||
@ -577,7 +578,6 @@ Recompiler::recompile(Vector<PatchableFrame> &frames, Vector<PatchableAddress> &
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
JITScript *jit = script->getJIT(fp->isConstructing());
|
JITScript *jit = script->getJIT(fp->isConstructing());
|
||||||
jit->recompilations = recompilations + 1;
|
|
||||||
|
|
||||||
/* Perform the earlier scanned patches */
|
/* Perform the earlier scanned patches */
|
||||||
for (uint32 i = 0; i < patches.length(); i++)
|
for (uint32 i = 0; i < patches.length(); i++)
|
||||||
|
@ -118,14 +118,13 @@ private:
|
|||||||
void patchNative(JITScript *jit, PatchableNative &native);
|
void patchNative(JITScript *jit, PatchableNative &native);
|
||||||
bool recompile(Vector<PatchableFrame> &frames,
|
bool recompile(Vector<PatchableFrame> &frames,
|
||||||
Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
|
Vector<PatchableAddress> &patches, Vector<CallSite> &sites,
|
||||||
Vector<PatchableNative> &natives,
|
Vector<PatchableNative> &natives);
|
||||||
uint32 recompilations);
|
|
||||||
|
|
||||||
static JSStackFrame *
|
static JSStackFrame *
|
||||||
expandInlineFrameChain(JSContext *cx, JSStackFrame *outer, InlineFrame *inner);
|
expandInlineFrameChain(JSContext *cx, JSStackFrame *outer, InlineFrame *inner);
|
||||||
|
|
||||||
/* Detach jit from any IC callers and save any traps to sites. */
|
/* 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 */
|
} /* namespace mjit */
|
||||||
|
@ -2814,8 +2814,7 @@ stubs::CheckArgumentTypes(VMFrame &f)
|
|||||||
JSStackFrame *fp = f.fp();
|
JSStackFrame *fp = f.fp();
|
||||||
JSFunction *fun = fp->fun();
|
JSFunction *fun = fp->fun();
|
||||||
JSScript *script = fun->script();
|
JSScript *script = fun->script();
|
||||||
|
RecompilationMonitor monitor(f.cx);
|
||||||
uint32 recompilations = f.jit()->recompilations;
|
|
||||||
|
|
||||||
/* Postpone recompilations until all args have been updated. */
|
/* Postpone recompilations until all args have been updated. */
|
||||||
types::AutoEnterTypeInference enter(f.cx);
|
types::AutoEnterTypeInference enter(f.cx);
|
||||||
@ -2833,7 +2832,7 @@ stubs::CheckArgumentTypes(VMFrame &f)
|
|||||||
if (!f.cx->compartment->types.checkPendingRecompiles(f.cx))
|
if (!f.cx->compartment->types.checkPendingRecompiles(f.cx))
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
if (f.jit()->recompilations != recompilations)
|
if (monitor.recompiled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef JS_MONOIC
|
#ifdef JS_MONOIC
|
||||||
|
Loading…
Reference in New Issue
Block a user