mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 988619 - Handle OOM when sweeping type information, r=jandem.
This commit is contained in:
parent
13d6e8211c
commit
43872e699a
@ -105,7 +105,7 @@ Zone::onTooMuchMalloc()
|
||||
}
|
||||
|
||||
void
|
||||
Zone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
Zone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
|
||||
{
|
||||
/*
|
||||
* Periodically release observed types for all scripts. This is safe to
|
||||
@ -116,7 +116,7 @@ Zone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
|
||||
types.sweep(fop, releaseTypes);
|
||||
types.sweep(fop, releaseTypes, oom);
|
||||
}
|
||||
|
||||
if (!fop->runtime()->debuggerList.isEmpty())
|
||||
|
@ -315,7 +315,7 @@ struct Zone : public JS::shadow::Zone,
|
||||
|
||||
js::types::TypeZone types;
|
||||
|
||||
void sweep(js::FreeOp *fop, bool releaseTypes);
|
||||
void sweep(js::FreeOp *fop, bool releaseTypes, bool *oom);
|
||||
|
||||
bool hasMarkedCompartments();
|
||||
|
||||
|
@ -2803,7 +2803,11 @@ static void
|
||||
FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript)
|
||||
{
|
||||
types::TypeZone &types = script->zone()->types;
|
||||
ionScript->recompileInfo().compilerOutput(types)->invalidate();
|
||||
|
||||
// Note: If the script is about to be swept, the compiler output may have
|
||||
// already been destroyed.
|
||||
if (types::CompilerOutput *output = ionScript->recompileInfo().compilerOutput(types))
|
||||
output->invalidate();
|
||||
|
||||
// If this script has Ion code on the stack, invalidated() will return
|
||||
// true. In this case we have to wait until destroying it.
|
||||
|
@ -3978,7 +3978,22 @@ BeginSweepingZoneGroup(JSRuntime *rt)
|
||||
|
||||
for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
|
||||
gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex);
|
||||
zone->sweep(&fop, releaseTypes && !zone->isPreservingCode());
|
||||
|
||||
// If there is an OOM while sweeping types, the type information
|
||||
// will be deoptimized so that it is still correct (i.e.
|
||||
// overapproximates the possible types in the zone), but the
|
||||
// constraints might not have been triggered on the deoptimization
|
||||
// or even copied over completely. In this case, destroy all JIT
|
||||
// code and new script addendums in the zone, the only things whose
|
||||
// correctness depends on the type constraints.
|
||||
bool oom = false;
|
||||
zone->sweep(&fop, releaseTypes && !zone->isPreservingCode(), &oom);
|
||||
|
||||
if (oom) {
|
||||
zone->setPreservingCode(false);
|
||||
zone->discardJitCode(&fop);
|
||||
zone->types.clearAllNewScriptAddendumsOnOOM();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jit/ExecutionModeInlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
using namespace js::types;
|
||||
@ -3120,6 +3122,29 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeObject::maybeClearNewScriptAddendumOnOOM()
|
||||
{
|
||||
if (!isMarked())
|
||||
return;
|
||||
|
||||
if (!addendum || addendum->kind != TypeObjectAddendum::NewScript)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < getPropertyCount(); i++) {
|
||||
Property *prop = getProperty(i);
|
||||
if (!prop)
|
||||
continue;
|
||||
if (prop->types.definiteProperty())
|
||||
prop->types.setNonDataPropertyIgnoringConstraints();
|
||||
}
|
||||
|
||||
// This method is called during GC sweeping, so there is no write barrier
|
||||
// that needs to be triggered.
|
||||
js_free(addendum);
|
||||
addendum.unsafeSet(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
TypeObject::clearTypedObjectAddendum(ExclusiveContext *cx)
|
||||
{
|
||||
@ -3943,7 +3968,7 @@ ExclusiveContext::getSingletonType(const Class *clasp, TaggedProto proto)
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
ConstraintTypeSet::sweep(Zone *zone)
|
||||
ConstraintTypeSet::sweep(Zone *zone, bool *oom)
|
||||
{
|
||||
/*
|
||||
* Purge references to type objects that are no longer live. Type sets hold
|
||||
@ -3964,9 +3989,14 @@ ConstraintTypeSet::sweep(Zone *zone)
|
||||
TypeObjectKey **pentry =
|
||||
HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(zone->types.typeLifoAlloc, objectSet, objectCount, object);
|
||||
if (!pentry)
|
||||
CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
|
||||
*pentry = object;
|
||||
if (pentry) {
|
||||
*pentry = object;
|
||||
} else {
|
||||
*oom = true;
|
||||
flags |= TYPE_FLAG_ANYOBJECT;
|
||||
clearObjects();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
setBaseObjectCount(objectCount);
|
||||
@ -3987,10 +4017,12 @@ ConstraintTypeSet::sweep(Zone *zone)
|
||||
while (constraint) {
|
||||
TypeConstraint *copy;
|
||||
if (constraint->sweep(zone->types, ©)) {
|
||||
if (!copy)
|
||||
CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
|
||||
copy->next = constraintList;
|
||||
constraintList = copy;
|
||||
if (copy) {
|
||||
copy->next = constraintList;
|
||||
constraintList = copy;
|
||||
} else {
|
||||
*oom = true;
|
||||
}
|
||||
}
|
||||
constraint = constraint->next;
|
||||
}
|
||||
@ -4011,7 +4043,7 @@ TypeObject::clearProperties()
|
||||
* so that type objects do not need later finalization.
|
||||
*/
|
||||
inline void
|
||||
TypeObject::sweep(FreeOp *fop)
|
||||
TypeObject::sweep(FreeOp *fop, bool *oom)
|
||||
{
|
||||
if (!isMarked()) {
|
||||
if (addendum)
|
||||
@ -4019,7 +4051,7 @@ TypeObject::sweep(FreeOp *fop)
|
||||
return;
|
||||
}
|
||||
|
||||
js::LifoAlloc &typeLifoAlloc = zone()->types.typeLifoAlloc;
|
||||
LifoAlloc &typeLifoAlloc = zone()->types.typeLifoAlloc;
|
||||
|
||||
/*
|
||||
* Properties were allocated from the old arena, and need to be copied over
|
||||
@ -4046,17 +4078,21 @@ TypeObject::sweep(FreeOp *fop)
|
||||
}
|
||||
|
||||
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
|
||||
if (!newProp)
|
||||
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
|
||||
if (newProp) {
|
||||
Property **pentry =
|
||||
HashSetInsert<jsid,Property,Property>
|
||||
(typeLifoAlloc, propertySet, propertyCount, prop->id);
|
||||
if (pentry) {
|
||||
*pentry = newProp;
|
||||
newProp->types.sweep(zone(), oom);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Property **pentry =
|
||||
HashSetInsert<jsid,Property,Property>
|
||||
(typeLifoAlloc, propertySet, propertyCount, prop->id);
|
||||
if (!pentry)
|
||||
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
|
||||
|
||||
*pentry = newProp;
|
||||
newProp->types.sweep(zone());
|
||||
*oom = true;
|
||||
addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
|
||||
clearProperties();
|
||||
return;
|
||||
}
|
||||
}
|
||||
setBasePropertyCount(propertyCount);
|
||||
@ -4067,18 +4103,17 @@ TypeObject::sweep(FreeOp *fop)
|
||||
clearProperties();
|
||||
} else {
|
||||
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
|
||||
if (!newProp)
|
||||
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
|
||||
|
||||
propertySet = (Property **) newProp;
|
||||
newProp->types.sweep(zone());
|
||||
if (newProp) {
|
||||
propertySet = (Property **) newProp;
|
||||
newProp->types.sweep(zone(), oom);
|
||||
} else {
|
||||
*oom = true;
|
||||
addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
|
||||
clearProperties();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (basePropertyCount() <= SET_ARRAY_SIZE) {
|
||||
for (unsigned i = 0; i < basePropertyCount(); i++)
|
||||
JS_ASSERT(propertySet[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -4196,7 +4231,7 @@ TypeCompartment::~TypeCompartment()
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
TypeScript::Sweep(FreeOp *fop, JSScript *script)
|
||||
TypeScript::Sweep(FreeOp *fop, JSScript *script, bool *oom)
|
||||
{
|
||||
JSCompartment *compartment = script->compartment();
|
||||
JS_ASSERT(compartment->zone()->isGCSweeping());
|
||||
@ -4206,7 +4241,7 @@ TypeScript::Sweep(FreeOp *fop, JSScript *script)
|
||||
|
||||
/* Remove constraints and references to dead objects from the persistent type sets. */
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
typeArray[i].sweep(compartment->zone());
|
||||
typeArray[i].sweep(compartment->zone(), oom);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4278,7 +4313,7 @@ TypeZone::~TypeZone()
|
||||
}
|
||||
|
||||
void
|
||||
TypeZone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
|
||||
{
|
||||
JS_ASSERT(zone()->isGCSweeping());
|
||||
|
||||
@ -4298,10 +4333,12 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
CompilerOutput &output = (*compilerOutputs)[i];
|
||||
if (output.isValid()) {
|
||||
JSScript *script = output.script();
|
||||
if (IsScriptAboutToBeFinalized(&script))
|
||||
if (IsScriptAboutToBeFinalized(&script)) {
|
||||
jit::GetIonScript(script, output.mode())->recompileInfoRef() = uint32_t(-1);
|
||||
output.invalidate();
|
||||
else
|
||||
} else {
|
||||
output.setSweepIndex(newCompilerOutputCount++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4312,7 +4349,7 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
for (CellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->types) {
|
||||
types::TypeScript::Sweep(fop, script);
|
||||
types::TypeScript::Sweep(fop, script, oom);
|
||||
|
||||
if (releaseTypes) {
|
||||
if (script->hasParallelIonScript()) {
|
||||
@ -4351,7 +4388,7 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
!iter.done(); iter.next())
|
||||
{
|
||||
TypeObject *object = iter.get<TypeObject>();
|
||||
object->sweep(fop);
|
||||
object->sweep(fop, oom);
|
||||
}
|
||||
|
||||
for (CompartmentsInZoneIter comp(zone()); !comp.done(); comp.next())
|
||||
@ -4386,6 +4423,17 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeZone::clearAllNewScriptAddendumsOnOOM()
|
||||
{
|
||||
for (gc::CellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT);
|
||||
!iter.done(); iter.next())
|
||||
{
|
||||
TypeObject *object = iter.get<TypeObject>();
|
||||
object->maybeClearNewScriptAddendumOnOOM();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
TypeScript::printTypes(JSContext *cx, HandleScript script) const
|
||||
|
@ -607,7 +607,7 @@ class ConstraintTypeSet : public TypeSet
|
||||
/* Add a new constraint to this set. */
|
||||
bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
|
||||
inline void sweep(JS::Zone *zone);
|
||||
inline void sweep(JS::Zone *zone, bool *oom);
|
||||
};
|
||||
|
||||
class StackTypeSet : public ConstraintTypeSet
|
||||
@ -622,6 +622,7 @@ class HeapTypeSet : public ConstraintTypeSet
|
||||
public:
|
||||
/* Mark this type set as representing a non-data property. */
|
||||
inline void setNonDataProperty(ExclusiveContext *cx);
|
||||
inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC.
|
||||
|
||||
/* Mark this type set as representing a non-writable property. */
|
||||
inline void setNonWritableProperty(ExclusiveContext *cx);
|
||||
@ -1122,13 +1123,14 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
||||
void clearAddendum(ExclusiveContext *cx);
|
||||
void clearNewScriptAddendum(ExclusiveContext *cx);
|
||||
void clearTypedObjectAddendum(ExclusiveContext *cx);
|
||||
void maybeClearNewScriptAddendumOnOOM();
|
||||
bool isPropertyNonData(jsid id);
|
||||
bool isPropertyNonWritable(jsid id);
|
||||
|
||||
void print();
|
||||
|
||||
inline void clearProperties();
|
||||
inline void sweep(FreeOp *fop);
|
||||
inline void sweep(FreeOp *fop, bool *oom);
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
@ -1284,7 +1286,7 @@ class TypeScript
|
||||
|
||||
static void Purge(JSContext *cx, HandleScript script);
|
||||
|
||||
static void Sweep(FreeOp *fop, JSScript *script);
|
||||
static void Sweep(FreeOp *fop, JSScript *script, bool *oom);
|
||||
void destroy();
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
@ -1576,7 +1578,8 @@ struct TypeZone
|
||||
|
||||
JS::Zone *zone() const { return zone_; }
|
||||
|
||||
void sweep(FreeOp *fop, bool releaseTypes);
|
||||
void sweep(FreeOp *fop, bool releaseTypes, bool *oom);
|
||||
void clearAllNewScriptAddendumsOnOOM();
|
||||
|
||||
/* Mark a script as needing recompilation once inference has finished. */
|
||||
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
|
||||
|
@ -1078,7 +1078,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc)
|
||||
|
||||
if (false) {
|
||||
unknownObject:
|
||||
type = Type::AnyObjectType();
|
||||
flags |= TYPE_FLAG_ANYOBJECT;
|
||||
clearObjects();
|
||||
}
|
||||
@ -1128,13 +1127,19 @@ HeapTypeSet::newPropertyState(ExclusiveContext *cxArg)
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
HeapTypeSet::setNonDataPropertyIgnoringConstraints()
|
||||
{
|
||||
flags |= TYPE_FLAG_NON_DATA_PROPERTY;
|
||||
}
|
||||
|
||||
inline void
|
||||
HeapTypeSet::setNonDataProperty(ExclusiveContext *cx)
|
||||
{
|
||||
if (flags & TYPE_FLAG_NON_DATA_PROPERTY)
|
||||
return;
|
||||
|
||||
flags |= TYPE_FLAG_NON_DATA_PROPERTY;
|
||||
setNonDataPropertyIgnoringConstraints();
|
||||
newPropertyState(cx);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user