mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 777537 - Ensure validity of CompilerOutput without a dangling pointer. r=bhackett
This commit is contained in:
parent
98d1923ea5
commit
e9cdb7efac
@ -2019,7 +2019,7 @@ void
|
||||
TypeCompartment::processPendingRecompiles(FreeOp *fop)
|
||||
{
|
||||
/* Steal the list of scripts to recompile, else we will try to recursively recompile them. */
|
||||
Vector<CompilerOutput> *pending = pendingRecompiles;
|
||||
Vector<RecompileInfo> *pending = pendingRecompiles;
|
||||
pendingRecompiles = NULL;
|
||||
|
||||
JS_ASSERT(!pending->empty());
|
||||
@ -2029,11 +2029,12 @@ TypeCompartment::processPendingRecompiles(FreeOp *fop)
|
||||
mjit::ExpandInlineFrames(compartment());
|
||||
|
||||
for (unsigned i = 0; i < pending->length(); i++) {
|
||||
const CompilerOutput &info = (*pending)[i];
|
||||
mjit::JITScript *jit = info.script->getJIT(info.constructing, info.barriers);
|
||||
if (jit && jit->chunkDescriptor(info.chunkIndex).chunk) {
|
||||
mjit::Recompiler::clearStackReferences(fop, info.script);
|
||||
jit->destroyChunk(fop, info.chunkIndex);
|
||||
CompilerOutput &co = *(*pending)[i].compilerOutput(*this);
|
||||
if (co.isJM()) {
|
||||
JS_ASSERT(co.isValid());
|
||||
mjit::Recompiler::clearStackReferences(fop, co.script);
|
||||
co.mjit()->destroyChunk(fop, co.chunkIndex);
|
||||
JS_ASSERT(co.script == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2103,56 +2104,69 @@ TypeCompartment::nukeTypes(FreeOp *fop)
|
||||
}
|
||||
|
||||
void
|
||||
TypeCompartment::addPendingRecompile(JSContext *cx, CompilerOutput &co)
|
||||
TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
|
||||
{
|
||||
if (!co.isValid())
|
||||
CompilerOutput *co = info.compilerOutput(cx);
|
||||
|
||||
if (co->pendingRecompilation)
|
||||
return;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::JITScript *jit = co.script->getJIT(co.constructing, co.barriers);
|
||||
if (!jit || !jit->chunkDescriptor(co.chunkIndex).chunk) {
|
||||
/* Scripts which haven't been compiled yet don't need to be recompiled. */
|
||||
if (!co->isValid()) {
|
||||
JS_ASSERT(co->script == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::JITScript *jit = co->script->getJIT(co->constructing, co->barriers);
|
||||
if (!jit || !jit->chunkDescriptor(co->chunkIndex).chunk) {
|
||||
/* Scripts which haven't been compiled yet don't need to be recompiled. */
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!pendingRecompiles) {
|
||||
pendingRecompiles = cx->new_< Vector<CompilerOutput> >(cx);
|
||||
pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
|
||||
if (!pendingRecompiles) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
co.invalidate();
|
||||
if (!pendingRecompiles->append(co)) {
|
||||
#if DEBUG
|
||||
for (size_t i = 0; i < pendingRecompiles->length(); i++) {
|
||||
RecompileInfo pr = (*pendingRecompiles)[i];
|
||||
JS_ASSERT(info.outputIndex != pr.outputIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!pendingRecompiles->append(info)) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
|
||||
{
|
||||
addPendingRecompile(cx, (*constrainedOutputs)[info.outputIndex]);
|
||||
co->setPendingRecompilation();
|
||||
}
|
||||
|
||||
void
|
||||
TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
CompilerOutput info;
|
||||
info.script = script;
|
||||
JS_ASSERT(script);
|
||||
if (!constrainedOutputs)
|
||||
return;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
for (int constructing = 0; constructing <= 1; constructing++) {
|
||||
for (int barriers = 0; barriers <= 1; barriers++) {
|
||||
if (mjit::JITScript *jit = script->getJIT((bool) constructing, (bool) barriers)) {
|
||||
info.constructing = constructing;
|
||||
info.barriers = barriers;
|
||||
info.chunkIndex = jit->chunkIndex(pc);
|
||||
info.mjit = jit;
|
||||
addPendingRecompile(cx, info);
|
||||
}
|
||||
mjit::JITScript *jit = script->getJIT((bool) constructing, (bool) barriers);
|
||||
if (!jit)
|
||||
continue;
|
||||
|
||||
unsigned int chunkIndex = jit->chunkIndex(pc);
|
||||
mjit::JITChunk *chunk = jit->chunkDescriptor(chunkIndex).chunk;
|
||||
if (!chunk)
|
||||
continue;
|
||||
|
||||
addPendingRecompile(cx, chunk->recompileInfo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1013,18 +1013,22 @@ struct CompilerOutput
|
||||
JSScript *script;
|
||||
bool constructing : 1;
|
||||
bool barriers : 1;
|
||||
uint32_t chunkIndex:30;
|
||||
bool pendingRecompilation : 1;
|
||||
uint32_t chunkIndex:29;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
js::mjit::JITScript *mjit; /* Information attached by JM */
|
||||
#endif
|
||||
CompilerOutput();
|
||||
|
||||
bool isJM() const { return true; }
|
||||
|
||||
mjit::JITScript * mjit() const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
void setPendingRecompilation() {
|
||||
pendingRecompilation = true;
|
||||
}
|
||||
void invalidate() {
|
||||
#ifdef JS_METHODJIT
|
||||
mjit = NULL;
|
||||
#endif
|
||||
script = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1033,9 +1037,15 @@ struct RecompileInfo
|
||||
static const uint32_t NoCompilerRunning = uint32_t(-1);
|
||||
uint32_t outputIndex;
|
||||
|
||||
RecompileInfo()
|
||||
: outputIndex(NoCompilerRunning)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator == (const RecompileInfo &o) const {
|
||||
return outputIndex == o.outputIndex;
|
||||
}
|
||||
CompilerOutput *compilerOutput(TypeCompartment &types) const;
|
||||
CompilerOutput *compilerOutput(JSContext *cx) const;
|
||||
};
|
||||
|
||||
@ -1077,7 +1087,7 @@ struct TypeCompartment
|
||||
Vector<CompilerOutput> *constrainedOutputs;
|
||||
|
||||
/* Pending recompilations to perform before execution of JIT code can resume. */
|
||||
Vector<CompilerOutput> *pendingRecompiles;
|
||||
Vector<RecompileInfo> *pendingRecompiles;
|
||||
|
||||
/*
|
||||
* Number of recompilation events and inline frame expansions that have
|
||||
@ -1148,7 +1158,6 @@ struct TypeCompartment
|
||||
void setPendingNukeTypesNoReport();
|
||||
|
||||
/* Mark a script as needing recompilation once inference has finished. */
|
||||
void addPendingRecompile(JSContext *cx, CompilerOutput &co);
|
||||
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
|
||||
void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
|
@ -27,16 +27,57 @@ namespace types {
|
||||
// CompilerOutput & RecompileInfo
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline
|
||||
CompilerOutput::CompilerOutput()
|
||||
: script(NULL),
|
||||
constructing(false),
|
||||
barriers(false),
|
||||
chunkIndex(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline mjit::JITScript *
|
||||
CompilerOutput::mjit() const
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
JS_ASSERT(isJM() && isValid());
|
||||
return script->getJIT(constructing, barriers);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool
|
||||
CompilerOutput::isValid() const
|
||||
{
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
TypeCompartment &types = script->compartment()->types;
|
||||
#endif
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
if (mjit != NULL && script->getJIT(constructing, barriers) == mjit)
|
||||
if (isJM()) {
|
||||
mjit::JITScript *jit = script->getJIT(constructing, barriers);
|
||||
if (!jit)
|
||||
return false;
|
||||
mjit::JITChunk *chunk = jit->chunkDescriptor(chunkIndex).chunk;
|
||||
if (!chunk)
|
||||
return false;
|
||||
JS_ASSERT(this == chunk->recompileInfo.compilerOutput(types));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
inline CompilerOutput*
|
||||
RecompileInfo::compilerOutput(TypeCompartment &types) const
|
||||
{
|
||||
return &(*types.constrainedOutputs)[outputIndex];
|
||||
}
|
||||
|
||||
inline CompilerOutput*
|
||||
RecompileInfo::compilerOutput(JSContext *cx) const
|
||||
{
|
||||
@ -261,6 +302,14 @@ struct AutoEnterCompilation
|
||||
co.barriers = cx->compartment->needsBarrier();
|
||||
co.chunkIndex = chunkIndex;
|
||||
|
||||
// This flag is used to prevent adding the current compiled script in
|
||||
// the list of compiler output which should be invalided. This is
|
||||
// necessary because we can run some analysis might discard the script
|
||||
// it-self, which can happen when the monitored value does not reflect
|
||||
// the types propagated by the type inference.
|
||||
co.pendingRecompilation = true;
|
||||
|
||||
JS_ASSERT(!co.isValid());
|
||||
TypeCompartment &types = cx->compartment->types;
|
||||
if (!types.constrainedOutputs) {
|
||||
types.constrainedOutputs = cx->new_< Vector<CompilerOutput> >(cx);
|
||||
@ -282,10 +331,10 @@ struct AutoEnterCompilation
|
||||
~AutoEnterCompilation()
|
||||
{
|
||||
CompilerOutput *co = info.compilerOutput(cx);
|
||||
#ifdef JS_METHODJIT
|
||||
if (co->script->hasMJITInfo())
|
||||
co->mjit = co->script->getJIT(co->constructing, co->barriers);
|
||||
#endif
|
||||
co->pendingRecompilation = false;
|
||||
if (!co->isValid())
|
||||
co->invalidate();
|
||||
|
||||
info.outputIndex = RecompileInfo::NoCompilerRunning;
|
||||
}
|
||||
};
|
||||
|
@ -1857,6 +1857,7 @@ mjit::Compiler::finishThisUp()
|
||||
}
|
||||
}
|
||||
|
||||
chunk->recompileInfo = cx->compartment->types.compiledInfo;
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
|
@ -1267,6 +1267,10 @@ JITScript::destroyChunk(FreeOp *fop, unsigned chunkIndex, bool resetUses)
|
||||
ChunkDescriptor &desc = chunkDescriptor(chunkIndex);
|
||||
|
||||
if (desc.chunk) {
|
||||
// Invalidates the CompilerOutput of the chunk.
|
||||
types::TypeCompartment &types = script->compartment()->types;
|
||||
desc.chunk->recompileInfo.compilerOutput(types)->invalidate();
|
||||
|
||||
/*
|
||||
* Write barrier: Before we destroy the chunk, trace through the objects
|
||||
* it holds.
|
||||
|
@ -667,6 +667,8 @@ struct JITChunk
|
||||
ExecPoolVector execPools;
|
||||
#endif
|
||||
|
||||
types::RecompileInfo recompileInfo;
|
||||
|
||||
// Additional ExecutablePools for native call and getter stubs.
|
||||
Vector<NativeCallStub, 0, SystemAllocPolicy> nativeCallStubs;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user