Backed out changeset b93e7a83b308 (bug 932982) for Linux mochitest-bc leaks.

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2013-12-11 17:07:48 -05:00
parent 8976499175
commit cb80ce98fe
22 changed files with 434 additions and 259 deletions

View File

@ -393,6 +393,7 @@ struct CompartmentStats
macro(Other, NotLiveGCThing, baselineStubsOptimized) \
macro(Other, NotLiveGCThing, ionData) \
macro(Other, NotLiveGCThing, typeInferenceTypeScripts) \
macro(Other, NotLiveGCThing, typeInferencePendingArrays) \
macro(Other, NotLiveGCThing, typeInferenceAllocationSiteTables) \
macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \
macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \

View File

@ -1122,11 +1122,14 @@ gc::MarkCycleCollectorChildren(JSTracer *trc, Shape *shape)
static void
ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
{
unsigned count = type->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
types::Property *prop = type->getProperty(i);
if (prop && JSID_IS_STRING(prop->id))
PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
/* Don't mark properties for singletons. They'll be purged by the GC. */
if (!type->singleton) {
unsigned count = type->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
types::Property *prop = type->getProperty(i);
if (prop && JSID_IS_STRING(prop->id))
PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
}
}
if (TaggedProto(type->proto).isObject())
@ -1347,7 +1350,7 @@ GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp)
}
void
GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
GCMarker::processMarkStackOther(SliceBudget &budget, uintptr_t tag, uintptr_t addr)
{
if (tag == TypeTag) {
ScanTypeObject(this, reinterpret_cast<types::TypeObject *>(addr));
@ -1361,6 +1364,35 @@ GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
pushObject(obj);
} else if (tag == IonCodeTag) {
MarkChildren(this, reinterpret_cast<jit::IonCode *>(addr));
} else if (tag == ArenaTag) {
ArenaHeader *aheader = reinterpret_cast<ArenaHeader *>(addr);
AllocKind thingKind = aheader->getAllocKind();
size_t thingSize = Arena::thingSize(thingKind);
for ( ; aheader; aheader = aheader->next) {
Arena *arena = aheader->getArena();
FreeSpan firstSpan(aheader->getFirstFreeSpan());
const FreeSpan *span = &firstSpan;
for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) {
JS_ASSERT(thing <= arena->thingsEnd());
if (thing == span->first) {
if (!span->hasNext())
break;
thing = span->last;
span = span->nextSpan();
} else {
JSObject *object = reinterpret_cast<JSObject *>(thing);
if (object->hasSingletonType() && object->markIfUnmarked(getMarkColor()))
pushObject(object);
budget.step();
}
}
if (budget.isOverBudget()) {
pushArenaList(aheader);
return;
}
}
}
}
@ -1398,7 +1430,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
goto scan_obj;
}
processMarkStackOther(tag, addr);
processMarkStackOther(budget, tag, addr);
return;
scan_value_array:

View File

@ -726,6 +726,11 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots)
if (IS_GC_MARKING_TRACER(trc) && !zone->isCollecting())
continue;
if (IS_GC_MARKING_TRACER(trc) && zone->isPreservingCode()) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_TYPES);
zone->markTypes(trc);
}
/* Do not discard scripts with counts while profiling. */
if (rt->profilingScripts && !rt->isHeapMinorCollecting()) {
for (CellIterUnderGC i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) {

View File

@ -276,6 +276,7 @@ static const PhaseInfo phases[] = {
{ PHASE_PURGE, "Purge", PHASE_NO_PARENT },
{ PHASE_MARK, "Mark", PHASE_NO_PARENT },
{ PHASE_MARK_ROOTS, "Mark Roots", PHASE_MARK },
{ PHASE_MARK_TYPES, "Mark Types", PHASE_MARK_ROOTS },
{ PHASE_MARK_DELAYED, "Mark Delayed", PHASE_MARK },
{ PHASE_SWEEP, "Sweep", PHASE_NO_PARENT },
{ PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP },

View File

@ -28,6 +28,7 @@ enum Phase {
PHASE_PURGE,
PHASE_MARK,
PHASE_MARK_ROOTS,
PHASE_MARK_TYPES,
PHASE_MARK_DELAYED,
PHASE_SWEEP,
PHASE_SWEEP_MARK,

View File

@ -80,6 +80,35 @@ Zone::setNeedsBarrier(bool needs, ShouldUpdateIon updateIon)
needsBarrier_ = needs;
}
void
Zone::markTypes(JSTracer *trc)
{
/*
* Mark all scripts, type objects and singleton JS objects in the
* compartment. These can be referred to directly by type sets, which we
* cannot modify while code which depends on these type sets is active.
*/
JS_ASSERT(isPreservingCode());
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
MarkScriptRoot(trc, &script, "mark_types_script");
JS_ASSERT(script == i.get<JSScript>());
}
for (size_t thingKind = FINALIZE_OBJECT0; thingKind < FINALIZE_OBJECT_LIMIT; thingKind++) {
ArenaHeader *aheader = allocator.arenas.getFirstArena(static_cast<AllocKind>(thingKind));
if (aheader)
trc->runtime->gcMarker.pushArenaList(aheader);
}
for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
types::TypeObject *type = i.get<types::TypeObject>();
MarkTypeObjectRoot(trc, &type, "mark_types_scan");
JS_ASSERT(type == i.get<types::TypeObject>());
}
}
void
Zone::resetGCMallocBytes()
{
@ -115,7 +144,7 @@ Zone::sweep(FreeOp *fop, bool releaseTypes)
if (active)
releaseTypes = false;
{
if (!isPreservingCode()) {
gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
types.sweep(fop, releaseTypes);
}

View File

@ -310,6 +310,8 @@ struct Zone : public JS::shadow::Zone,
js_ReportAllocationOverflow(nullptr);
}
void markTypes(JSTracer *trc);
js::types::TypeZone types;
void sweep(js::FreeOp *fop, bool releaseTypes);

View File

@ -5887,7 +5887,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
safepoints_.size(), callTargets.length(),
patchableBackedges_.length());
if (!ionScript) {
recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
recompileInfo.compilerOutput(cx->compartment()->types)->invalidate();
return false;
}
@ -5912,7 +5912,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
// Use js_free instead of IonScript::Destroy: the cache list and
// backedge list are still uninitialized.
js_free(ionScript);
recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
recompileInfo.compilerOutput(cx->compartment()->types)->invalidate();
return false;
}
@ -5933,7 +5933,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
/* resetUses */ false, /* cancelOffThread*/ false))
{
js_free(ionScript);
recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
recompileInfo.compilerOutput(cx->compartment()->types)->invalidate();
return false;
}
}

View File

@ -2481,7 +2481,7 @@ jit::InvalidateAll(FreeOp *fop, Zone *zone)
void
jit::Invalidate(types::TypeZone &types, FreeOp *fop,
jit::Invalidate(types::TypeCompartment &types, FreeOp *fop,
const Vector<types::RecompileInfo> &invalid, bool resetUses,
bool cancelOffThread)
{
@ -2564,7 +2564,7 @@ void
jit::Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses,
bool cancelOffThread)
{
jit::Invalidate(cx->zone()->types, cx->runtime()->defaultFreeOp(), invalid, resetUses,
jit::Invalidate(cx->compartment()->types, cx->runtime()->defaultFreeOp(), invalid, resetUses,
cancelOffThread);
}
@ -2611,13 +2611,14 @@ FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript, bool p
else
script->setIonScript(nullptr);
types::TypeZone &types = script->zone()->types;
ionScript->recompileInfo().compilerOutput(types)->invalidate();
// If this script has Ion code on the stack, invalidated() will return
// If this script has Ion code on the stack, invalidation() will return
// true. In this case we have to wait until destroying it.
if (!ionScript->invalidated())
if (!ionScript->invalidated()) {
types::TypeCompartment &types = script->compartment()->types;
ionScript->recompileInfo().compilerOutput(types)->invalidate();
jit::IonScript::Destroy(fop, ionScript);
}
}
void
@ -2636,6 +2637,8 @@ jit::FinishDiscardJitCode(FreeOp *fop, JSCompartment *comp)
// Free optimized baseline stubs.
if (comp->jitCompartment())
comp->jitCompartment()->optimizedStubSpace()->free();
comp->types.clearCompilerOutputs(fop);
}
void

View File

@ -364,7 +364,7 @@ IonExecStatus IonCannon(JSContext *cx, RunState &state);
IonExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args);
// Walk the stack and invalidate active Ion frames for the invalid scripts.
void Invalidate(types::TypeZone &types, FreeOp *fop,
void Invalidate(types::TypeCompartment &types, FreeOp *fop,
const Vector<types::RecompileInfo> &invalid, bool resetUses = true,
bool cancelOffThread = true);
void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true,

View File

@ -6286,7 +6286,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
types::HeapTypeSetKey property = staticType->property(id);
if (!property.maybeTypes() ||
!property.maybeTypes()->definiteProperty() ||
property.configured(constraints()))
property.configured(constraints(), staticType))
{
// The property has been reconfigured as non-configurable, non-enumerable
// or non-writable.
@ -6376,7 +6376,7 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name)
types::HeapTypeSetKey property = staticType->property(id);
if (!property.maybeTypes() ||
!property.maybeTypes()->definiteProperty() ||
property.configured(constraints()))
property.configured(constraints(), staticType))
{
// The property has been reconfigured as non-configurable, non-enumerable
// or non-writable.
@ -7826,7 +7826,7 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name,
*property = type->property(id);
return property->maybeTypes() &&
property->maybeTypes()->definiteProperty() &&
!property->configured(constraints());
!property->configured(constraints(), type);
}
bool

View File

@ -526,9 +526,6 @@ struct IonScript
const types::RecompileInfo& recompileInfo() const {
return recompileInfo_;
}
types::RecompileInfo& recompileInfoRef() {
return recompileInfo_;
}
uint32_t incrOsrPcMismatchCounter() {
return ++osrPcMismatchCounter_;
}

View File

@ -3025,7 +3025,7 @@ jit::PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
// Check if the property has been reconfigured or is a getter.
types::HeapTypeSetKey property = object->property(NameToId(name));
if (property.configured(constraints))
if (property.configured(constraints, object))
return false;
}
}

View File

@ -48,6 +48,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
#endif
global_(nullptr),
enterCompartmentDepth(0),
lastCodeRelease(0),
data(nullptr),
objectMetadataCallback(nullptr),
lastAnimationTime(0),
@ -544,6 +545,13 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
WeakMapBase::sweepCompartment(this);
}
if (zone()->isPreservingCode()) {
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
types.sweepShapes(fop);
} else {
JS_ASSERT(!types.constrainedOutputs);
}
NativeIterator *ni = enumerators->next();
while (ni != enumerators) {
JSObject *iterObj = ni->iterObj();
@ -856,6 +864,7 @@ JSCompartment::clearTraps(FreeOp *fop)
void
JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *tiPendingArrays,
size_t *tiAllocationSiteTables,
size_t *tiArrayTypeTables,
size_t *tiObjectTypeTables,
@ -867,7 +876,7 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *baselineStubsOptimized)
{
*compartmentObject += mallocSizeOf(this);
types.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
types.addSizeOfExcludingThis(mallocSizeOf, tiPendingArrays, tiAllocationSiteTables,
tiArrayTypeTables, tiObjectTypeTables);
*shapesCompartmentTables += baseShapes.sizeOfExcludingThis(mallocSizeOf)
+ initialShapes.sizeOfExcludingThis(mallocSizeOf)

View File

@ -188,6 +188,7 @@ struct JSCompartment
void adoptWorkerAllocator(js::Allocator *workerAllocator);
int64_t lastCodeRelease;
bool activeAnalysis;
/* Type information about the scripts and objects in this compartment. */
@ -220,6 +221,7 @@ struct JSCompartment
public:
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *tiPendingArrays,
size_t *tiAllocationSiteTables,
size_t *tiArrayTypeTables,
size_t *tiObjectTypeTables,

View File

@ -2849,14 +2849,18 @@ static bool
ShouldPreserveJITCode(JSCompartment *comp, int64_t currentTime)
{
JSRuntime *rt = comp->runtimeFromMainThread();
if (rt->gcShouldCleanUpEverything)
if (rt->gcShouldCleanUpEverything || !comp->zone()->types.inferenceEnabled)
return false;
if (rt->alwaysPreserveCode)
return true;
if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime)
if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime &&
comp->lastCodeRelease + (PRMJ_USEC_PER_SEC * 300) >= currentTime)
{
return true;
}
comp->lastCodeRelease = currentTime;
return false;
}
@ -3935,12 +3939,12 @@ BeginSweepingZoneGroup(JSRuntime *rt)
bool releaseTypes = ReleaseObservedTypes(rt);
for (GCCompartmentGroupIter c(rt); !c.done(); c.next()) {
gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex);
c->sweep(&fop, releaseTypes && !c->zone()->isPreservingCode());
c->sweep(&fop, releaseTypes);
}
for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex);
zone->sweep(&fop, releaseTypes && !zone->isPreservingCode());
zone->sweep(&fop, releaseTypes);
}
}
@ -5289,6 +5293,10 @@ js::ReleaseAllJITCode(FreeOp *fop)
jit::FinishDiscardBaselineScript(fop, script);
}
}
/* Sweep now invalidated compiler outputs from each compartment. */
for (CompartmentsIter comp(fop->runtime(), SkipAtoms); !comp.done(); comp.next())
comp->types.clearCompilerOutputs(fop);
#endif
}

View File

@ -1091,6 +1091,7 @@ struct GCMarker : public JSTracer {
ObjectTag,
TypeTag,
XmlTag,
ArenaTag,
SavedValueArrayTag,
IonCodeTag,
LastTag = IonCodeTag
@ -1118,6 +1119,10 @@ struct GCMarker : public JSTracer {
pushTaggedPtr(ObjectTag, obj);
}
void pushArenaList(gc::ArenaHeader *firstArena) {
pushTaggedPtr(ArenaTag, firstArena);
}
void pushType(types::TypeObject *type) {
pushTaggedPtr(TypeTag, type);
}
@ -1224,7 +1229,7 @@ struct GCMarker : public JSTracer {
bool restoreValueArray(JSObject *obj, void **vpp, void **endp);
void saveValueRanges();
inline void processMarkStackTop(SliceBudget &budget);
void processMarkStackOther(uintptr_t tag, uintptr_t addr);
void processMarkStackOther(SliceBudget &budget, uintptr_t tag, uintptr_t addr);
void appendGrayRoot(void *thing, JSGCTraceKind kind);

View File

@ -243,6 +243,14 @@ types::TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &val
if (id == id___proto__(cx) || id == id_constructor(cx) || id == id_caller(cx))
return true;
/*
* If we called in here while resolving a type constraint, we may be in the
* middle of resolving a standard class and the type sets will not be updated
* until the outer TypeSet::add finishes.
*/
if (cx->compartment()->types.pendingCount)
return true;
Type type = GetValueType(value);
AutoEnterAnalysis enter(cx);
@ -734,12 +742,12 @@ class TypeCompilerConstraint : public TypeConstraint
void newType(JSContext *cx, TypeSet *source, Type type) {
if (data.invalidateOnNewType(type))
cx->zone()->types.addPendingRecompile(cx, compilation);
cx->compartment()->types.addPendingRecompile(cx, compilation);
}
void newPropertyState(JSContext *cx, TypeSet *source) {
if (data.invalidateOnNewPropertyState(source))
cx->zone()->types.addPendingRecompile(cx, compilation);
cx->compartment()->types.addPendingRecompile(cx, compilation);
}
void newObjectState(JSContext *cx, TypeObject *object) {
@ -747,16 +755,7 @@ class TypeCompilerConstraint : public TypeConstraint
// will be sent on changes to its state, so always invalidate any
// associated compilations.
if (object->unknownProperties() || data.invalidateOnNewObjectState(object))
cx->zone()->types.addPendingRecompile(cx, compilation);
}
TypeConstraint *sweep(TypeZone &zone) {
if (data.shouldSweep() || compilation.shouldSweep(zone))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
if (!res)
zone.setPendingNukeTypes();
return res;
cx->compartment()->types.addPendingRecompile(cx, compilation);
}
};
@ -909,21 +908,13 @@ class TypeConstraintFreezeStack : public TypeConstraint
const char *kind() { return "freezeStack"; }
void newType(JSContext *cx, TypeSet *source, Type type) {
void newType(JSContext *cx, TypeSet *source, Type type)
{
/*
* Unlike TypeConstraintFreeze, triggering this constraint once does
* not disable it on future changes to the type set.
*/
cx->zone()->types.addPendingRecompile(cx, script_);
}
TypeConstraint *sweep(TypeZone &zone) {
if (IsScriptAboutToBeFinalized(&script_))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
if (!res)
zone.setPendingNukeTypes();
return res;
cx->compartment()->types.addPendingRecompile(cx, script_);
}
};
@ -938,22 +929,15 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
CompilerOutput co(script, executionMode);
TypeZone &types = cx->zone()->types;
if (!types.compilerOutputs) {
types.compilerOutputs = cx->new_< Vector<CompilerOutput> >(cx);
if (!types.compilerOutputs)
TypeCompartment &types = cx->compartment()->types;
if (!types.constrainedOutputs) {
types.constrainedOutputs = cx->new_< Vector<CompilerOutput> >(cx);
if (!types.constrainedOutputs)
return false;
}
#ifdef DEBUG
for (size_t i = 0; i < types.compilerOutputs->length(); i++) {
const CompilerOutput &co = (*types.compilerOutputs)[i];
JS_ASSERT_IF(co.isValid(), co.script() != script || co.mode() != executionMode);
}
#endif
uint32_t index = types.compilerOutputs->length();
if (!types.compilerOutputs->append(co))
uint32_t index = types.constrainedOutputs->length();
if (!types.constrainedOutputs->append(co))
return false;
*precompileInfo = RecompileInfo(index);
@ -995,8 +979,8 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
array[i].add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false);
}
if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
types.compilerOutputs->back().invalidate();
if (!succeeded || types.constrainedOutputs->back().pendingInvalidation()) {
types.constrainedOutputs->back().invalidate();
script->resetUseCount();
return false;
}
@ -1025,8 +1009,6 @@ class ConstraintDataFreeze
? property.maybeTypes()->isSubset(expected)
: property.maybeTypes()->empty();
}
bool shouldSweep() { return false; }
};
} /* anonymous namespace */
@ -1213,8 +1195,6 @@ class ConstraintDataFreezeObjectFlags
{
return !invalidateOnNewObjectState(property.object()->maybeType());
}
bool shouldSweep() { return false; }
};
} /* anonymous namespace */
@ -1309,8 +1289,6 @@ class ConstraintDataFreezeObjectForInlinedCall
{
return true;
}
bool shouldSweep() { return false; }
};
// Constraint which triggers recompilation when the template object for a
@ -1337,11 +1315,6 @@ class ConstraintDataFreezeObjectForNewScriptTemplate
{
return !invalidateOnNewObjectState(property.object()->maybeType());
}
bool shouldSweep() {
// Note: |templateObject| is only used for equality testing.
return false;
}
};
// Constraint which triggers recompilation when the underlying data pointer for
@ -1368,11 +1341,6 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer
{
return !invalidateOnNewObjectState(property.object()->maybeType());
}
bool shouldSweep() {
// Note: |viewData| is only used for equality testing.
return false;
}
};
} /* anonymous namespace */
@ -1445,7 +1413,10 @@ namespace {
class ConstraintDataFreezeConfiguredProperty
{
public:
ConstraintDataFreezeConfiguredProperty()
TypeObjectKey *object;
ConstraintDataFreezeConfiguredProperty(TypeObjectKey *object)
: object(object)
{}
const char *kind() { return "freezeConfiguredProperty"; }
@ -1459,16 +1430,31 @@ class ConstraintDataFreezeConfiguredProperty
bool constraintHolds(JSContext *cx,
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
{
// Everywhere compiled code depends on definite properties associated
// with a type object's newScript, we need to make sure there are
// constraints in place which will mark those properties as configured
// should the definite properties be invalidated.
TypeObject *type = object->isSingleObject()
? object->asSingleObject()->type()
: object->asTypeObject();
if (type->flags & OBJECT_FLAG_NEW_SCRIPT_REGENERATE) {
type->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
if (type->hasNewScript()) {
CheckNewScriptProperties(cx, type, type->newScript()->fun);
} else {
JS_ASSERT(type->flags & OBJECT_FLAG_ADDENDUM_CLEARED);
type->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
}
}
return !property.maybeTypes()->configuredProperty();
}
bool shouldSweep() { return false; }
};
} /* anonymous namespace */
bool
HeapTypeSetKey::configured(CompilerConstraintList *constraints)
HeapTypeSetKey::configured(CompilerConstraintList *constraints, TypeObjectKey *type)
{
if (maybeTypes() && maybeTypes()->configuredProperty())
return true;
@ -1477,7 +1463,7 @@ HeapTypeSetKey::configured(CompilerConstraintList *constraints)
typedef CompilerConstraintInstance<ConstraintDataFreezeConfiguredProperty> T;
constraints->add(alloc->new_<T>(alloc, *this,
ConstraintDataFreezeConfiguredProperty()));
ConstraintDataFreezeConfiguredProperty(type)));
return false;
}
@ -2000,7 +1986,7 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj)
if (type->unknownProperties())
return true;
HeapTypeSetKey index = type->property(JSID_VOID);
if (index.configured(constraints) || index.isOwnProperty(constraints))
if (index.configured(constraints, type) || index.isOwnProperty(constraints))
return true;
obj = obj->getProto();
} while (obj);
@ -2038,8 +2024,27 @@ types::TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints,
return PrototypeHasIndexedProperty(constraints, proto);
}
bool
TypeCompartment::growPendingArray(JSContext *cx)
{
unsigned newCapacity = js::Max(unsigned(100), pendingCapacity * 2);
PendingWork *newArray = js_pod_calloc<PendingWork>(newCapacity);
if (!newArray) {
cx->compartment()->types.setPendingNukeTypes(cx);
return false;
}
PodCopy(newArray, pendingArray, pendingCount);
js_free(pendingArray);
pendingArray = newArray;
pendingCapacity = newCapacity;
return true;
}
void
TypeZone::processPendingRecompiles(FreeOp *fop)
TypeCompartment::processPendingRecompiles(FreeOp *fop)
{
if (!pendingRecompiles)
return;
@ -2090,9 +2095,11 @@ TypeZone::nukeTypes(FreeOp *fop)
*/
JS_ASSERT(pendingNukeTypes);
if (pendingRecompiles) {
fop->free_(pendingRecompiles);
pendingRecompiles = nullptr;
for (CompartmentsInZoneIter comp(zone()); !comp.done(); comp.next()) {
if (comp->types.pendingRecompiles) {
fop->free_(comp->types.pendingRecompiles);
comp->types.pendingRecompiles = nullptr;
}
}
inferenceEnabled = false;
@ -2112,7 +2119,7 @@ TypeZone::nukeTypes(FreeOp *fop)
}
void
TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
{
CompilerOutput *co = info.compilerOutput(cx);
if (!co || !co->isValid() || co->pendingInvalidation())
@ -2138,7 +2145,7 @@ TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
}
void
TypeZone::addPendingRecompile(JSContext *cx, JSScript *script)
TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
{
JS_ASSERT(script);
@ -3139,15 +3146,6 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
}
void newType(JSContext *cx, TypeSet *source, Type type) {}
TypeConstraint *sweep(TypeZone &zone) {
if (IsTypeObjectAboutToBeFinalized(&object))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
if (!res)
zone.setPendingNukeTypes();
return res;
}
};
bool
@ -3194,15 +3192,6 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint
if (source->baseFlags() || source->getObjectCount() > 1)
object->clearAddendum(cx);
}
TypeConstraint *sweep(TypeZone &zone) {
if (IsTypeObjectAboutToBeFinalized(&object))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
if (!res)
zone.setPendingNukeTypes();
return res;
}
};
void
@ -3952,19 +3941,8 @@ ConstraintTypeSet::sweep(Zone *zone)
}
}
/*
* Type constraints only hold weak references. Copy constraints referring
* to data that is still live into the zone's new arena.
*/
TypeConstraint *constraint = constraintList;
/* All constraints are wiped out on each GC. */
constraintList = nullptr;
while (constraint) {
if (TypeConstraint *copy = constraint->sweep(zone->types)) {
copy->next = constraintList;
constraintList = copy;
}
constraint = constraint->next;
}
}
inline void
@ -3984,6 +3962,18 @@ TypeObject::clearProperties()
inline void
TypeObject::sweep(FreeOp *fop)
{
if (singleton) {
JS_ASSERT(!hasNewScript());
/*
* All properties can be discarded. We will regenerate them as needed
* as code gets reanalyzed.
*/
clearProperties();
return;
}
if (!isMarked()) {
if (addendum)
fop->free_(addendum);
@ -4006,14 +3996,6 @@ TypeObject::sweep(FreeOp *fop)
for (unsigned i = 0; i < oldCapacity; i++) {
Property *prop = oldArray[i];
if (prop) {
if (singleton && !prop->types.constraintList) {
/*
* Don't copy over properties of singleton objects which
* don't have associated constraints. The contents of these
* type sets will be regenerated as necessary.
*/
continue;
}
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
Property **pentry =
@ -4033,17 +4015,12 @@ TypeObject::sweep(FreeOp *fop)
setBasePropertyCount(propertyCount);
} else if (propertyCount == 1) {
Property *prop = (Property *) propertySet;
if (singleton && !prop->types.constraintList) {
// Skip, as above.
clearProperties();
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
propertySet = (Property **) newProp;
newProp->types.sweep(zone());
} else {
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
propertySet = (Property **) newProp;
newProp->types.sweep(zone());
} else {
zone()->types.setPendingNukeTypes();
}
zone()->types.setPendingNukeTypes();
}
}
@ -4051,6 +4028,14 @@ TypeObject::sweep(FreeOp *fop)
for (unsigned i = 0; i < basePropertyCount(); i++)
JS_ASSERT(propertySet[i]);
}
/*
* The GC will clear out the constraints ensuring the correctness of the
* newScript information, these constraints will need to be regenerated
* the next time we compile code which depends on this info.
*/
if (hasNewScript())
flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
}
void
@ -4134,6 +4119,52 @@ TypeCompartment::sweep(FreeOp *fop)
e.rekeyFront(key);
}
}
/*
* The pending array is reset on GC, it can grow large (75+ KB) and is easy
* to reallocate if the compartment becomes active again.
*/
if (pendingArray)
fop->free_(pendingArray);
pendingArray = nullptr;
pendingCapacity = 0;
}
void
TypeCompartment::sweepShapes(FreeOp *fop)
{
/*
* Sweep any weak shape references that may be finalized even if a GC is
* preserving type information.
*/
if (objectTypeTable) {
for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) {
const ObjectTableKey &key = e.front().key();
ObjectTableEntry &entry = e.front().value();
if (IsShapeAboutToBeFinalized(entry.shape.unsafeGet())) {
fop->free_(key.properties);
fop->free_(entry.types);
e.removeFront();
}
}
}
}
void
TypeCompartment::clearCompilerOutputs(FreeOp *fop)
{
if (constrainedOutputs) {
fop->delete_(constrainedOutputs);
constrainedOutputs = nullptr;
}
if (pendingRecompiles) {
JS_ASSERT(pendingRecompiles->length() == 0);
fop->delete_(pendingRecompiles);
pendingRecompiles = nullptr;
}
}
void
@ -4162,6 +4193,7 @@ JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
TypeCompartment::~TypeCompartment()
{
js_free(pendingArray);
js_delete(arrayTypeTable);
js_delete(objectTypeTable);
js_delete(allocationSiteTable);
@ -4180,6 +4212,12 @@ 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());
/*
* Freeze constraints on stack type sets need to be regenerated the next
* time the script is analyzed.
*/
script->clearHasFreezeConstraints();
}
void
@ -4196,10 +4234,20 @@ Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *typePoo
void
TypeCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *pendingArrays,
size_t *allocationSiteTables,
size_t *arrayTypeTables,
size_t *objectTypeTables)
{
/* Pending arrays are cleared on GC along with the analysis pool. */
*pendingArrays += mallocSizeOf(pendingArray);
/*
* TypeCompartment::pendingRecompiles is non-nullptr only while inference
* code is running.
*/
JS_ASSERT(!pendingRecompiles);
if (allocationSiteTable)
*allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
@ -4241,8 +4289,6 @@ TypeObject::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
TypeZone::TypeZone(Zone *zone)
: zone_(zone),
typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
compilerOutputs(nullptr),
pendingRecompiles(nullptr),
pendingNukeTypes(false),
inferenceEnabled(false)
{
@ -4250,8 +4296,6 @@ TypeZone::TypeZone(Zone *zone)
TypeZone::~TypeZone()
{
js_delete(compilerOutputs);
js_delete(pendingRecompiles);
}
void
@ -4268,21 +4312,11 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize());
oldAlloc.steal(&typeLifoAlloc);
/* Sweep and find compressed indexes for each compiler output. */
size_t newCompilerOutputCount = 0;
if (compilerOutputs) {
for (size_t i = 0; i < compilerOutputs->length(); i++) {
CompilerOutput &output = (*compilerOutputs)[i];
if (output.isValid()) {
JSScript *script = output.script();
if (IsScriptAboutToBeFinalized(&script))
output.invalidate();
else
output.setSweepIndex(newCompilerOutputCount++);
}
}
}
/*
* Sweep analysis information and everything depending on it from the
* compartment, including all remaining mjit code if inference is
* enabled in the compartment.
*/
if (inferenceEnabled) {
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI);
@ -4294,21 +4328,6 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
if (releaseTypes) {
script->types->destroy();
script->types = nullptr;
/*
* Freeze constraints on stack type sets need to be
* regenerated the next time the script is analyzed.
*/
script->clearHasFreezeConstraints();
JS_ASSERT(!script->hasIonScript());
JS_ASSERT(!script->hasParallelIonScript());
} else {
/* Update the recompile indexes in any IonScripts still on the script. */
if (script->hasIonScript())
script->ionScript()->recompileInfoRef().shouldSweep(*this);
if (script->hasParallelIonScript())
script->parallelIonScript()->recompileInfoRef().shouldSweep(*this);
}
}
}
@ -4328,20 +4347,6 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
comp->types.sweep(fop);
}
if (compilerOutputs) {
size_t sweepIndex = 0;
for (size_t i = 0; i < compilerOutputs->length(); i++) {
CompilerOutput output = (*compilerOutputs)[i];
if (output.isValid()) {
JS_ASSERT(sweepIndex == output.sweepIndex());
output.setSweepIndex(0);
(*compilerOutputs)[sweepIndex++] = output;
}
}
JS_ASSERT(sweepIndex == newCompilerOutputCount);
JS_ALWAYS_TRUE(compilerOutputs->resize(newCompilerOutputCount));
}
{
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS);
for (CellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) {

View File

@ -177,7 +177,7 @@ namespace analyze {
namespace types {
class TypeZone;
class TypeCompartment;
class TypeSet;
class TypeObjectKey;
@ -278,10 +278,28 @@ inline Type GetValueType(const Value &val);
* Type information about the values observed within scripts and about the
* contents of the heap is accumulated as the program executes. Compilation
* accumulates constraints relating type information on the heap with the
* compilations that should be invalidated when those types change. Type
* information and constraints are allocated in the zone's typeLifoAlloc,
* and on GC all data referring to live things is copied into a new allocator.
* Thus, type set and constraints only hold weak references.
* compilations that should be invalidated when those types change. This data
* is periodically cleared to reduce memory usage.
*
* GCs may clear both analysis information and jitcode. Sometimes GCs will
* preserve all information and code, and will not collect any scripts, type
* objects or singleton JS objects.
*
* The following data is cleared by all non-preserving GCs:
*
* - The ScriptAnalysis for each analyzed script and data from each analysis
* pass performed.
*
* - Property type sets for singleton JS objects.
*
* - Type constraints and dead references in all type sets.
*
* The following data is occasionally cleared by non-preserving GCs:
*
* - TypeScripts and their type sets are occasionally destroyed, per a timer.
*
* - When a JSScript or TypeObject is swept, type information for its contents
* is destroyed.
*/
/*
@ -316,12 +334,6 @@ public:
* state.
*/
virtual void newObjectState(JSContext *cx, TypeObject *object) {}
/*
* If the data this constraint refers to is still live, copy it into the
* zone's new allocator. Type constraints only hold weak references.
*/
virtual TypeConstraint *sweep(TypeZone &zone) = 0;
};
/* Flags and other state stored in TypeSet::flags */
@ -382,6 +394,13 @@ enum {
/* If set, addendum information should not be installed on this object. */
OBJECT_FLAG_ADDENDUM_CLEARED = 0x2,
/*
* If set, type constraints covering the correctness of the newScript
* definite properties need to be regenerated before compiling any jitcode
* which depends on this information.
*/
OBJECT_FLAG_NEW_SCRIPT_REGENERATE = 0x4,
/*
* Whether we have ensured all type sets in the compartment contain
* ANYOBJECT instead of this object.
@ -850,6 +869,12 @@ struct TypeTypedObject : public TypeObjectAddendum
* information is sensitive to changes in the property's type. Future changes
* to the property (whether those uncovered by analysis or those occurring
* in the VM) will treat these properties like those of any other type object.
*
* When a GC occurs, we wipe out all analysis information for all the
* compartment's scripts, so can destroy all properties on singleton type
* objects at the same time. If there is no reference on the stack to the
* type object itself, the type object is also destroyed, and the JS object
* reverts to having a lazy type.
*/
/* Type information about an object accessed by a script. */
@ -1291,7 +1316,7 @@ class HeapTypeSetKey
void freeze(CompilerConstraintList *constraints);
JSValueType knownTypeTag(CompilerConstraintList *constraints);
bool configured(CompilerConstraintList *constraints);
bool configured(CompilerConstraintList *constraints, TypeObjectKey *type);
bool isOwnProperty(CompilerConstraintList *constraints);
bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
JSObject *singleton(CompilerConstraintList *constraints);
@ -1314,10 +1339,6 @@ class CompilerOutput
// Whether this compilation is about to be invalidated.
bool pendingInvalidation_ : 1;
// During sweeping, the list of compiler outputs is compacted and invalidated
// outputs are removed. This gives the new index for a valid compiler output.
uint32_t sweepIndex_ : 29;
public:
CompilerOutput()
: script_(nullptr), mode_(SequentialExecution), pendingInvalidation_(false)
@ -1345,15 +1366,6 @@ class CompilerOutput
bool pendingInvalidation() {
return pendingInvalidation_;
}
void setSweepIndex(uint32_t index) {
if (index >= 1 << 29)
MOZ_CRASH();
sweepIndex_ = index;
}
uint32_t sweepIndex() {
return sweepIndex_;
}
};
class RecompileInfo
@ -1368,9 +1380,8 @@ class RecompileInfo
bool operator == (const RecompileInfo &o) const {
return outputIndex == o.outputIndex;
}
CompilerOutput *compilerOutput(TypeZone &types) const;
CompilerOutput *compilerOutput(TypeCompartment &types) const;
CompilerOutput *compilerOutput(JSContext *cx) const;
bool shouldSweep(TypeZone &types);
};
/* Type information for a compartment. */
@ -1378,9 +1389,32 @@ struct TypeCompartment
{
/* Constraint solving worklist structures. */
/*
* Worklist of types which need to be propagated to constraints. We use a
* worklist to avoid blowing the native stack.
*/
struct PendingWork
{
TypeConstraint *constraint;
ConstraintTypeSet *source;
Type type;
};
PendingWork *pendingArray;
unsigned pendingCount;
unsigned pendingCapacity;
/* Whether we are currently resolving the pending worklist. */
bool resolving;
/* Number of scripts in this compartment. */
unsigned scriptCount;
/* Valid & Invalid script referenced by type constraints. */
Vector<CompilerOutput> *constrainedOutputs;
/* Pending recompilations to perform before execution of JIT code can resume. */
Vector<RecompileInfo> *pendingRecompiles;
/* Table for referencing types of objects keyed to an allocation site. */
AllocationSiteTable *allocationSiteTable;
@ -1404,6 +1438,14 @@ struct TypeCompartment
inline JSCompartment *compartment();
/* Add a type to register with a list of constraints. */
inline void addPending(JSContext *cx, TypeConstraint *constraint,
ConstraintTypeSet *source, Type type);
bool growPendingArray(JSContext *cx);
/* Resolve pending type registrations, excluding delayed ones. */
inline void resolvePending(JSContext *cx);
/* Prints results of this compartment if spew is enabled or force is set. */
void print(JSContext *cx, bool force);
@ -1419,16 +1461,26 @@ struct TypeCompartment
/* Get or make an object for an allocation site, and add to the allocation site table. */
TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
void processPendingRecompiles(FreeOp *fop);
/* Mark all types as needing destruction once inference has 'finished'. */
void setPendingNukeTypes(ExclusiveContext *cx);
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
void addPendingRecompile(JSContext *cx, JSScript *script);
/* Mark any type set containing obj as having a generic object type. */
void markSetsUnknown(JSContext *cx, TypeObject *obj);
void sweep(FreeOp *fop);
void sweepShapes(FreeOp *fop);
void clearCompilerOutputs(FreeOp *fop);
void finalizeObjects();
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *pendingArrays,
size_t *allocationSiteTables,
size_t *arrayTypeTables,
size_t *objectTypeTables);
@ -1444,16 +1496,6 @@ struct TypeZone
static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
js::LifoAlloc typeLifoAlloc;
/*
* All Ion compilations that have occured in this zone, for indexing via
* RecompileInfo. This includes both valid and invalid compilations, though
* invalidated compilations are swept on GC.
*/
Vector<CompilerOutput> *compilerOutputs;
/* Pending recompilations to perform before execution of JIT code can resume. */
Vector<RecompileInfo> *pendingRecompiles;
/*
* Bit set if all current types must be marked as unknown, and all scripts
* recompiled. Caused by OOM failure within inference operations.
@ -1474,12 +1516,6 @@ struct TypeZone
/* Mark all types as needing destruction once inference has 'finished'. */
void setPendingNukeTypes();
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
void addPendingRecompile(JSContext *cx, JSScript *script);
void processPendingRecompiles(FreeOp *fop);
void nukeTypes(FreeOp *fop);
};

View File

@ -104,29 +104,17 @@ CompilerOutput::ion() const
}
inline CompilerOutput*
RecompileInfo::compilerOutput(TypeZone &types) const
RecompileInfo::compilerOutput(TypeCompartment &types) const
{
if (!types.compilerOutputs || outputIndex >= types.compilerOutputs->length())
if (!types.constrainedOutputs || outputIndex >= types.constrainedOutputs->length())
return nullptr;
return &(*types.compilerOutputs)[outputIndex];
return &(*types.constrainedOutputs)[outputIndex];
}
inline CompilerOutput*
RecompileInfo::compilerOutput(JSContext *cx) const
{
return compilerOutput(cx->zone()->types);
}
inline bool
RecompileInfo::shouldSweep(TypeZone &types)
{
CompilerOutput *output = compilerOutput(types);
if (!output || !output->isValid())
return true;
// Update this info for the output's new index in the zone's compiler outputs.
outputIndex = output->sweepIndex();
return false;
return compilerOutput(cx->compartment()->types);
}
/////////////////////////////////////////////////////////////////////
@ -300,13 +288,14 @@ struct AutoEnterAnalysis
* If there are no more type inference activations on the stack,
* process any triggered recompilations. Note that we should not be
* invoking any scripted code while type inference is running.
* :TODO: assert this.
*/
if (!compartment->activeAnalysis) {
TypeZone &types = compartment->zone()->types;
if (types.pendingNukeTypes)
types.nukeTypes(freeOp);
else if (types.pendingRecompiles)
types.processPendingRecompiles(freeOp);
TypeCompartment *types = &compartment->types;
if (compartment->zone()->types.pendingNukeTypes)
compartment->zone()->types.nukeTypes(freeOp);
else if (types->pendingRecompiles)
types->processPendingRecompiles(freeOp);
}
}
@ -863,6 +852,50 @@ TypeCompartment::compartment()
return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
}
inline void
TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint,
ConstraintTypeSet *source, Type type)
{
JS_ASSERT(this == &cx->compartment()->types);
JS_ASSERT(!cx->runtime()->isHeapBusy());
InferSpew(ISpewOps, "pending: %sC%p%s %s",
InferSpewColor(constraint), constraint, InferSpewColorReset(),
TypeString(type));
if ((pendingCount == pendingCapacity) && !growPendingArray(cx))
return;
PendingWork &pending = pendingArray[pendingCount++];
pending.constraint = constraint;
pending.source = source;
pending.type = type;
}
inline void
TypeCompartment::resolvePending(JSContext *cx)
{
JS_ASSERT(this == &cx->compartment()->types);
if (resolving) {
/* There is an active call further up resolving the worklist. */
return;
}
resolving = true;
/* Handle all pending type registrations. */
while (pendingCount) {
const PendingWork &pending = pendingArray[--pendingCount];
InferSpew(ISpewOps, "resolve: %sC%p%s %s",
InferSpewColor(pending.constraint), pending.constraint,
InferSpewColorReset(), TypeString(pending.type));
pending.constraint->newType(cx, pending.source, pending.type);
}
resolving = false;
}
/////////////////////////////////////////////////////////////////////
// TypeSet
/////////////////////////////////////////////////////////////////////
@ -1186,9 +1219,10 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
if (JSContext *cx = cxArg->maybeJSContext()) {
TypeConstraint *constraint = constraintList;
while (constraint) {
constraint->newType(cx, this, type);
cx->compartment()->types.addPending(cx, constraint, this, type);
constraint = constraint->next;
}
cx->compartment()->types.resolvePending(cx);
} else {
JS_ASSERT(!constraintList);
}

View File

@ -215,6 +215,7 @@ StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
// Measure the compartment object itself, and things hanging off it.
compartment->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
&cStats.typeInferencePendingArrays,
&cStats.typeInferenceAllocationSiteTables,
&cStats.typeInferenceArrayTypeTables,
&cStats.typeInferenceObjectTypeTables,

View File

@ -2122,6 +2122,10 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
cStats.typeInferenceTypeScripts,
"Memory used by type sets associated with scripts.");
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/pending-arrays"),
cStats.typeInferencePendingArrays,
"Memory used for solving constraints during type inference.");
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/allocation-site-tables"),
cStats.typeInferenceAllocationSiteTables,
"Memory indexing type objects associated with allocation sites.");