Bug 932982 - Trace type constraints and allow preserving jitcode in GCs without also marking all type information, r=billm, r=jandem

This commit is contained in:
Brian Hackett 2013-12-12 13:10:54 -08:00
parent 34b77c2df7
commit 6844e7e5ca
23 changed files with 260 additions and 437 deletions

View File

@ -21,6 +21,5 @@
# Are you updating CLOBBER because you think it's needed for your WebIDL
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 928195 rewrote WebIDL build system integration from the ground up. This
will hopefully be the last required clobber due to WebIDLs poorly interacting
with the build system.
Bug 932982 apparently requires a clobber or else we get B2G mochitest-2 failures.

View File

@ -393,7 +393,6 @@ 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,14 +1122,11 @@ gc::MarkCycleCollectorChildren(JSTracer *trc, Shape *shape)
static void
ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
{
/* 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));
}
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())
@ -1350,7 +1347,7 @@ GCMarker::restoreValueArray(JSObject *obj, void **vpp, void **endp)
}
void
GCMarker::processMarkStackOther(SliceBudget &budget, uintptr_t tag, uintptr_t addr)
GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
{
if (tag == TypeTag) {
ScanTypeObject(this, reinterpret_cast<types::TypeObject *>(addr));
@ -1364,35 +1361,6 @@ GCMarker::processMarkStackOther(SliceBudget &budget, uintptr_t tag, uintptr_t ad
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;
}
}
}
}
@ -1430,7 +1398,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
goto scan_obj;
}
processMarkStackOther(budget, tag, addr);
processMarkStackOther(tag, addr);
return;
scan_value_array:

View File

@ -726,11 +726,6 @@ 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,7 +276,6 @@ 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,7 +28,6 @@ enum Phase {
PHASE_PURGE,
PHASE_MARK,
PHASE_MARK_ROOTS,
PHASE_MARK_TYPES,
PHASE_MARK_DELAYED,
PHASE_SWEEP,
PHASE_SWEEP_MARK,

View File

@ -80,35 +80,6 @@ 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()
{
@ -144,7 +115,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,8 +310,6 @@ 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

@ -5825,7 +5825,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
safepoints_.size(), callTargets.length(),
patchableBackedges_.length());
if (!ionScript) {
recompileInfo.compilerOutput(cx->compartment()->types)->invalidate();
recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
return false;
}
@ -5850,7 +5850,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->compartment()->types)->invalidate();
recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
return false;
}
@ -5871,7 +5871,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
/* resetUses */ false, /* cancelOffThread*/ false))
{
js_free(ionScript);
recompileInfo.compilerOutput(cx->compartment()->types)->invalidate();
recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
return false;
}
}

View File

@ -2481,7 +2481,7 @@ jit::InvalidateAll(FreeOp *fop, Zone *zone)
void
jit::Invalidate(types::TypeCompartment &types, FreeOp *fop,
jit::Invalidate(types::TypeZone &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->compartment()->types, cx->runtime()->defaultFreeOp(), invalid, resetUses,
jit::Invalidate(cx->zone()->types, cx->runtime()->defaultFreeOp(), invalid, resetUses,
cancelOffThread);
}
@ -2611,14 +2611,13 @@ FinishInvalidationOf(FreeOp *fop, JSScript *script, IonScript *ionScript, bool p
else
script->setIonScript(nullptr);
// 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()) {
types::TypeCompartment &types = script->compartment()->types;
ionScript->recompileInfo().compilerOutput(types)->invalidate();
types::TypeZone &types = script->zone()->types;
ionScript->recompileInfo().compilerOutput(types)->invalidate();
// If this script has Ion code on the stack, invalidated() will return
// true. In this case we have to wait until destroying it.
if (!ionScript->invalidated())
jit::IonScript::Destroy(fop, ionScript);
}
}
void
@ -2637,8 +2636,6 @@ 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::TypeCompartment &types, FreeOp *fop,
void Invalidate(types::TypeZone &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

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

View File

@ -526,6 +526,9 @@ 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, object))
if (property.configured(constraints))
return false;
}
}

View File

@ -48,7 +48,6 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
#endif
global_(nullptr),
enterCompartmentDepth(0),
lastCodeRelease(0),
data(nullptr),
objectMetadataCallback(nullptr),
lastAnimationTime(0),
@ -545,13 +544,6 @@ 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,7 +848,6 @@ JSCompartment::clearTraps(FreeOp *fop)
void
JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *tiPendingArrays,
size_t *tiAllocationSiteTables,
size_t *tiArrayTypeTables,
size_t *tiObjectTypeTables,
@ -868,7 +859,7 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t *baselineStubsOptimized)
{
*compartmentObject += mallocSizeOf(this);
types.addSizeOfExcludingThis(mallocSizeOf, tiPendingArrays, tiAllocationSiteTables,
types.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
tiArrayTypeTables, tiObjectTypeTables);
*shapesCompartmentTables += baseShapes.sizeOfExcludingThis(mallocSizeOf)
+ initialShapes.sizeOfExcludingThis(mallocSizeOf)

View File

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

View File

@ -2857,13 +2857,9 @@ ShouldPreserveJITCode(JSCompartment *comp, int64_t currentTime)
if (rt->alwaysPreserveCode)
return true;
if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime &&
comp->lastCodeRelease + (PRMJ_USEC_PER_SEC * 300) >= currentTime)
{
if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime)
return true;
}
comp->lastCodeRelease = currentTime;
return false;
}
@ -3942,12 +3938,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->sweep(&fop, releaseTypes && !c->zone()->isPreservingCode());
}
for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex);
zone->sweep(&fop, releaseTypes);
zone->sweep(&fop, releaseTypes && !zone->isPreservingCode());
}
}
@ -5304,10 +5300,6 @@ 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,7 +1091,6 @@ struct GCMarker : public JSTracer {
ObjectTag,
TypeTag,
XmlTag,
ArenaTag,
SavedValueArrayTag,
IonCodeTag,
LastTag = IonCodeTag
@ -1119,10 +1118,6 @@ struct GCMarker : public JSTracer {
pushTaggedPtr(ObjectTag, obj);
}
void pushArenaList(gc::ArenaHeader *firstArena) {
pushTaggedPtr(ArenaTag, firstArena);
}
void pushType(types::TypeObject *type) {
pushTaggedPtr(TypeTag, type);
}
@ -1229,7 +1224,7 @@ struct GCMarker : public JSTracer {
bool restoreValueArray(JSObject *obj, void **vpp, void **endp);
void saveValueRanges();
inline void processMarkStackTop(SliceBudget &budget);
void processMarkStackOther(SliceBudget &budget, uintptr_t tag, uintptr_t addr);
void processMarkStackOther(uintptr_t tag, uintptr_t addr);
void appendGrayRoot(void *thing, JSGCTraceKind kind);

View File

@ -243,14 +243,6 @@ 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);
@ -742,12 +734,12 @@ class TypeCompilerConstraint : public TypeConstraint
void newType(JSContext *cx, TypeSet *source, Type type) {
if (data.invalidateOnNewType(type))
cx->compartment()->types.addPendingRecompile(cx, compilation);
cx->zone()->types.addPendingRecompile(cx, compilation);
}
void newPropertyState(JSContext *cx, TypeSet *source) {
if (data.invalidateOnNewPropertyState(source))
cx->compartment()->types.addPendingRecompile(cx, compilation);
cx->zone()->types.addPendingRecompile(cx, compilation);
}
void newObjectState(JSContext *cx, TypeObject *object) {
@ -755,7 +747,16 @@ 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->compartment()->types.addPendingRecompile(cx, compilation);
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;
}
};
@ -908,13 +909,21 @@ 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->compartment()->types.addPendingRecompile(cx, script_);
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;
}
};
@ -929,15 +938,22 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
CompilerOutput co(script, executionMode);
TypeCompartment &types = cx->compartment()->types;
if (!types.constrainedOutputs) {
types.constrainedOutputs = cx->new_< Vector<CompilerOutput> >(cx);
if (!types.constrainedOutputs)
TypeZone &types = cx->zone()->types;
if (!types.compilerOutputs) {
types.compilerOutputs = cx->new_< Vector<CompilerOutput> >(cx);
if (!types.compilerOutputs)
return false;
}
uint32_t index = types.constrainedOutputs->length();
if (!types.constrainedOutputs->append(co))
#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))
return false;
*precompileInfo = RecompileInfo(index);
@ -979,8 +995,8 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
array[i].add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false);
}
if (!succeeded || types.constrainedOutputs->back().pendingInvalidation()) {
types.constrainedOutputs->back().invalidate();
if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
types.compilerOutputs->back().invalidate();
script->resetUseCount();
return false;
}
@ -1009,6 +1025,8 @@ class ConstraintDataFreeze
? property.maybeTypes()->isSubset(expected)
: property.maybeTypes()->empty();
}
bool shouldSweep() { return false; }
};
} /* anonymous namespace */
@ -1195,6 +1213,8 @@ class ConstraintDataFreezeObjectFlags
{
return !invalidateOnNewObjectState(property.object()->maybeType());
}
bool shouldSweep() { return false; }
};
} /* anonymous namespace */
@ -1289,6 +1309,8 @@ class ConstraintDataFreezeObjectForInlinedCall
{
return true;
}
bool shouldSweep() { return false; }
};
// Constraint which triggers recompilation when the template object for a
@ -1315,6 +1337,11 @@ 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
@ -1341,6 +1368,11 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer
{
return !invalidateOnNewObjectState(property.object()->maybeType());
}
bool shouldSweep() {
// Note: |viewData| is only used for equality testing.
return false;
}
};
} /* anonymous namespace */
@ -1413,10 +1445,7 @@ namespace {
class ConstraintDataFreezeConfiguredProperty
{
public:
TypeObjectKey *object;
ConstraintDataFreezeConfiguredProperty(TypeObjectKey *object)
: object(object)
ConstraintDataFreezeConfiguredProperty()
{}
const char *kind() { return "freezeConfiguredProperty"; }
@ -1430,31 +1459,16 @@ 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, TypeObjectKey *type)
HeapTypeSetKey::configured(CompilerConstraintList *constraints)
{
if (maybeTypes() && maybeTypes()->configuredProperty())
return true;
@ -1463,7 +1477,7 @@ HeapTypeSetKey::configured(CompilerConstraintList *constraints, TypeObjectKey *t
typedef CompilerConstraintInstance<ConstraintDataFreezeConfiguredProperty> T;
constraints->add(alloc->new_<T>(alloc, *this,
ConstraintDataFreezeConfiguredProperty(type)));
ConstraintDataFreezeConfiguredProperty()));
return false;
}
@ -1986,7 +2000,7 @@ PrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSObject *obj)
if (type->unknownProperties())
return true;
HeapTypeSetKey index = type->property(JSID_VOID);
if (index.configured(constraints, type) || index.isOwnProperty(constraints))
if (index.configured(constraints) || index.isOwnProperty(constraints))
return true;
obj = obj->getProto();
} while (obj);
@ -2024,27 +2038,8 @@ 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
TypeCompartment::processPendingRecompiles(FreeOp *fop)
TypeZone::processPendingRecompiles(FreeOp *fop)
{
if (!pendingRecompiles)
return;
@ -2095,11 +2090,9 @@ TypeZone::nukeTypes(FreeOp *fop)
*/
JS_ASSERT(pendingNukeTypes);
for (CompartmentsInZoneIter comp(zone()); !comp.done(); comp.next()) {
if (comp->types.pendingRecompiles) {
fop->free_(comp->types.pendingRecompiles);
comp->types.pendingRecompiles = nullptr;
}
if (pendingRecompiles) {
fop->free_(pendingRecompiles);
pendingRecompiles = nullptr;
}
inferenceEnabled = false;
@ -2119,7 +2112,7 @@ TypeZone::nukeTypes(FreeOp *fop)
}
void
TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
{
CompilerOutput *co = info.compilerOutput(cx);
if (!co || !co->isValid() || co->pendingInvalidation())
@ -2145,7 +2138,7 @@ TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
}
void
TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
TypeZone::addPendingRecompile(JSContext *cx, JSScript *script)
{
JS_ASSERT(script);
@ -3146,6 +3139,15 @@ 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
@ -3192,6 +3194,15 @@ 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
@ -3941,8 +3952,19 @@ ConstraintTypeSet::sweep(Zone *zone)
}
}
/* All constraints are wiped out on each GC. */
/*
* Type constraints only hold weak references. Copy constraints referring
* to data that is still live into the zone's new arena.
*/
TypeConstraint *constraint = constraintList;
constraintList = nullptr;
while (constraint) {
if (TypeConstraint *copy = constraint->sweep(zone->types)) {
copy->next = constraintList;
constraintList = copy;
}
constraint = constraint->next;
}
}
inline void
@ -3962,18 +3984,6 @@ 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);
@ -3996,6 +4006,14 @@ 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 =
@ -4015,12 +4033,17 @@ TypeObject::sweep(FreeOp *fop)
setBasePropertyCount(propertyCount);
} else if (propertyCount == 1) {
Property *prop = (Property *) propertySet;
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
propertySet = (Property **) newProp;
newProp->types.sweep(zone());
if (singleton && !prop->types.constraintList) {
// Skip, as above.
clearProperties();
} else {
zone()->types.setPendingNukeTypes();
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
propertySet = (Property **) newProp;
newProp->types.sweep(zone());
} else {
zone()->types.setPendingNukeTypes();
}
}
}
@ -4028,14 +4051,6 @@ 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
@ -4119,52 +4134,6 @@ 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
@ -4193,7 +4162,6 @@ JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
TypeCompartment::~TypeCompartment()
{
js_free(pendingArray);
js_delete(arrayTypeTable);
js_delete(objectTypeTable);
js_delete(allocationSiteTable);
@ -4212,12 +4180,6 @@ 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
@ -4234,20 +4196,10 @@ 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);
@ -4289,6 +4241,8 @@ 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)
{
@ -4296,6 +4250,8 @@ TypeZone::TypeZone(Zone *zone)
TypeZone::~TypeZone()
{
js_delete(compilerOutputs);
js_delete(pendingRecompiles);
}
void
@ -4312,11 +4268,21 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes)
LifoAlloc oldAlloc(typeLifoAlloc.defaultChunkSize());
oldAlloc.steal(&typeLifoAlloc);
/*
* Sweep analysis information and everything depending on it from the
* compartment, including all remaining mjit code if inference is
* enabled in the compartment.
*/
/* 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++);
}
}
}
if (inferenceEnabled) {
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI);
@ -4328,6 +4294,21 @@ 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);
}
}
}
@ -4347,6 +4328,20 @@ 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 TypeCompartment;
class TypeZone;
class TypeSet;
class TypeObjectKey;
@ -278,28 +278,10 @@ 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. 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.
* 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.
*/
/*
@ -334,6 +316,12 @@ 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 */
@ -394,13 +382,6 @@ 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.
@ -869,12 +850,6 @@ 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. */
@ -1316,7 +1291,7 @@ class HeapTypeSetKey
void freeze(CompilerConstraintList *constraints);
JSValueType knownTypeTag(CompilerConstraintList *constraints);
bool configured(CompilerConstraintList *constraints, TypeObjectKey *type);
bool configured(CompilerConstraintList *constraints);
bool isOwnProperty(CompilerConstraintList *constraints);
bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
JSObject *singleton(CompilerConstraintList *constraints);
@ -1339,6 +1314,10 @@ 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)
@ -1366,6 +1345,15 @@ 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
@ -1380,8 +1368,9 @@ class RecompileInfo
bool operator == (const RecompileInfo &o) const {
return outputIndex == o.outputIndex;
}
CompilerOutput *compilerOutput(TypeCompartment &types) const;
CompilerOutput *compilerOutput(TypeZone &types) const;
CompilerOutput *compilerOutput(JSContext *cx) const;
bool shouldSweep(TypeZone &types);
};
/* Type information for a compartment. */
@ -1389,32 +1378,9 @@ 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;
@ -1438,14 +1404,6 @@ 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);
@ -1461,26 +1419,16 @@ 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);
@ -1496,6 +1444,16 @@ 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.
@ -1516,6 +1474,12 @@ 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

@ -103,17 +103,29 @@ CompilerOutput::ion() const
}
inline CompilerOutput*
RecompileInfo::compilerOutput(TypeCompartment &types) const
RecompileInfo::compilerOutput(TypeZone &types) const
{
if (!types.constrainedOutputs || outputIndex >= types.constrainedOutputs->length())
if (!types.compilerOutputs || outputIndex >= types.compilerOutputs->length())
return nullptr;
return &(*types.constrainedOutputs)[outputIndex];
return &(*types.compilerOutputs)[outputIndex];
}
inline CompilerOutput*
RecompileInfo::compilerOutput(JSContext *cx) const
{
return compilerOutput(cx->compartment()->types);
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;
}
/////////////////////////////////////////////////////////////////////
@ -287,14 +299,13 @@ 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) {
TypeCompartment *types = &compartment->types;
if (compartment->zone()->types.pendingNukeTypes)
compartment->zone()->types.nukeTypes(freeOp);
else if (types->pendingRecompiles)
types->processPendingRecompiles(freeOp);
TypeZone &types = compartment->zone()->types;
if (types.pendingNukeTypes)
types.nukeTypes(freeOp);
else if (types.pendingRecompiles)
types.processPendingRecompiles(freeOp);
}
}
@ -848,50 +859,6 @@ 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
/////////////////////////////////////////////////////////////////////
@ -1215,10 +1182,9 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
if (JSContext *cx = cxArg->maybeJSContext()) {
TypeConstraint *constraint = constraintList;
while (constraint) {
cx->compartment()->types.addPending(cx, constraint, this, type);
constraint->newType(cx, this, type);
constraint = constraint->next;
}
cx->compartment()->types.resolvePending(cx);
} else {
JS_ASSERT(!constraintList);
}

View File

@ -215,7 +215,6 @@ 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

@ -2087,10 +2087,6 @@ 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.");