зеркало из https://github.com/mozilla/gecko-dev.git
Bug 980630 - Remove type nuking, r=jandem.
This commit is contained in:
Родитель
f745bb2ae1
Коммит
3899368c4e
|
@ -152,9 +152,6 @@ struct AutoStopVerifyingBarriers
|
|||
};
|
||||
#endif /* JS_GC_ZEAL */
|
||||
|
||||
void
|
||||
CrashAtUnhandlableOOM(const char *reason);
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -24,10 +24,11 @@
|
|||
#include "js/Tracer.h"
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
extern void
|
||||
CrashAtUnhandlableOOM(const char *);
|
||||
void
|
||||
CrashAtUnhandlableOOM(const char *reason);
|
||||
|
||||
namespace gc {
|
||||
|
||||
/*
|
||||
* BufferableRef represents an abstract reference for use in the generational
|
||||
|
|
|
@ -882,12 +882,3 @@ js::gc::FinishVerifier(JSRuntime *rt)
|
|||
}
|
||||
|
||||
#endif /* JS_GC_ZEAL */
|
||||
|
||||
void
|
||||
js::gc::CrashAtUnhandlableOOM(const char *reason)
|
||||
{
|
||||
char msgbuf[1024];
|
||||
JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
|
||||
MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// |jit-test| allow-oom
|
||||
if (typeof oomAfterAllocations == 'function') {
|
||||
gczeal(4);
|
||||
oomAfterAllocations(1);
|
||||
var s = new Set;
|
||||
}
|
|
@ -2065,7 +2065,8 @@ AnalyzePoppedThis(JSContext *cx, types::TypeObject *type,
|
|||
block = rp->block(), rp = block->callerResumePoint())
|
||||
{
|
||||
JSScript *script = rp->block()->info().script();
|
||||
types::AddClearDefiniteFunctionUsesInScript(cx, type, script, block->info().script());
|
||||
if (!types::AddClearDefiniteFunctionUsesInScript(cx, type, script, block->info().script()))
|
||||
return true;
|
||||
if (!callerResumePoints.append(rp))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -617,8 +617,7 @@ IonBuilder::build()
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!initParameters())
|
||||
return false;
|
||||
initParameters();
|
||||
|
||||
// Initialize local variables.
|
||||
for (uint32_t i = 0; i < info().nlocals(); i++) {
|
||||
|
@ -910,20 +909,18 @@ IonBuilder::rewriteParameters()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
IonBuilder::initParameters()
|
||||
{
|
||||
if (!info().funMaybeLazy())
|
||||
return true;
|
||||
return;
|
||||
|
||||
// If we are doing OSR on a frame which initially executed in the
|
||||
// interpreter and didn't accumulate type information, try to use that OSR
|
||||
// frame to determine possible initial types for 'this' and parameters.
|
||||
|
||||
if (thisTypes->empty() && baselineFrame_) {
|
||||
if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
|
||||
return false;
|
||||
}
|
||||
if (thisTypes->empty() && baselineFrame_)
|
||||
thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc());
|
||||
|
||||
MParameter *param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
|
||||
current->add(param);
|
||||
|
@ -934,16 +931,13 @@ IonBuilder::initParameters()
|
|||
if (types->empty() && baselineFrame_ &&
|
||||
!script_->baselineScript()->modifiesArguments())
|
||||
{
|
||||
if (!types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc()))
|
||||
return false;
|
||||
types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc());
|
||||
}
|
||||
|
||||
param = MParameter::New(alloc(), i, types);
|
||||
current->add(param);
|
||||
current->initSlot(info().argSlotUnchecked(i), param);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4971,14 +4965,12 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
|||
types::TemporaryTypeSet *observed = bytecodeTypes(pc);
|
||||
if (observed->empty()) {
|
||||
if (BytecodeFlowsToBitop(pc)) {
|
||||
if (!observed->addType(types::Type::Int32Type(), alloc_->lifoAlloc()))
|
||||
return false;
|
||||
observed->addType(types::Type::Int32Type(), alloc_->lifoAlloc());
|
||||
} else if (*GetNextPc(pc) == JSOP_POS) {
|
||||
// Note: this is lame, overspecialized on the code patterns used
|
||||
// by asm.js and should be replaced by a more general mechanism.
|
||||
// See bug 870847.
|
||||
if (!observed->addType(types::Type::DoubleType(), alloc_->lifoAlloc()))
|
||||
return false;
|
||||
observed->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7091,8 +7083,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
|||
// Indexed call on an element of an array. Populate the observed types
|
||||
// with any objects that could be in the array, to avoid extraneous
|
||||
// type barriers.
|
||||
if (!AddObjectsForPropertyRead(obj, nullptr, types))
|
||||
return false;
|
||||
AddObjectsForPropertyRead(obj, nullptr, types);
|
||||
}
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types);
|
||||
|
@ -9288,8 +9279,7 @@ IonBuilder::jsop_setarg(uint32_t arg)
|
|||
}
|
||||
if (!otherUses) {
|
||||
JS_ASSERT(op->resultTypeSet() == &argTypes[arg]);
|
||||
if (!argTypes[arg].addType(types::Type::UnknownType(), alloc_->lifoAlloc()))
|
||||
return false;
|
||||
argTypes[arg].addType(types::Type::UnknownType(), alloc_->lifoAlloc());
|
||||
if (val->isMul()) {
|
||||
val->setResultType(MIRType_Double);
|
||||
val->toMul()->setSpecialization(MIRType_Double);
|
||||
|
|
|
@ -327,7 +327,7 @@ class IonBuilder : public MIRGenerator
|
|||
|
||||
void insertRecompileCheck();
|
||||
|
||||
bool initParameters();
|
||||
void initParameters();
|
||||
void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
|
||||
void rewriteParameters();
|
||||
bool initScopeChain(MDefinition *callee = nullptr);
|
||||
|
|
|
@ -940,8 +940,7 @@ IonBuilder::inlineMathFRound(CallInfo &callInfo)
|
|||
if (returned->empty()) {
|
||||
// As there's only one possible returned type, just add it to the observed
|
||||
// returned typeset
|
||||
if (!returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc()))
|
||||
return InliningStatus_Error;
|
||||
returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
|
||||
} else {
|
||||
MIRType returnType = getInlineReturnType();
|
||||
if (!IsNumberType(returnType))
|
||||
|
|
|
@ -2765,10 +2765,8 @@ InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
|
|||
if (!types)
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < numEntries(); i++) {
|
||||
if (entries_[i]->func == func) {
|
||||
if (!types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc))
|
||||
return nullptr;
|
||||
}
|
||||
if (entries_[i]->func == func)
|
||||
types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
@ -3172,7 +3170,7 @@ jit::PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed)
|
||||
{
|
||||
|
@ -3182,16 +3180,20 @@ jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
|
|||
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
|
||||
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
if (!types || types->unknownObject())
|
||||
return observed->addType(types::Type::AnyObjectType(), alloc);
|
||||
if (!types || types->unknownObject()) {
|
||||
observed->addType(types::Type::AnyObjectType(), alloc);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
types::TypeObjectKey *object = types->getObject(i);
|
||||
if (!object)
|
||||
continue;
|
||||
|
||||
if (object->unknownProperties())
|
||||
return observed->addType(types::Type::AnyObjectType(), alloc);
|
||||
if (object->unknownProperties()) {
|
||||
observed->addType(types::Type::AnyObjectType(), alloc);
|
||||
return;
|
||||
}
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
|
@ -3199,17 +3201,17 @@ jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
|
|||
if (!types)
|
||||
continue;
|
||||
|
||||
if (types->unknownObject())
|
||||
return observed->addType(types::Type::AnyObjectType(), alloc);
|
||||
if (types->unknownObject()) {
|
||||
observed->addType(types::Type::AnyObjectType(), alloc);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
types::TypeObjectKey *object = types->getObject(i);
|
||||
if (object && !observed->addType(types::Type::ObjectType(object), alloc))
|
||||
return false;
|
||||
if (object)
|
||||
observed->addType(types::Type::ObjectType(object), alloc);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
@ -9866,7 +9866,7 @@ bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons
|
|||
types::TemporaryTypeSet *observed);
|
||||
bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name);
|
||||
bool AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
|
||||
void AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed);
|
||||
bool PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints,
|
||||
MBasicBlock *current, MDefinition **pobj,
|
||||
|
|
|
@ -2206,10 +2206,8 @@ ScriptAnalysis::needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v)
|
|||
if (v == seen[i])
|
||||
return false;
|
||||
}
|
||||
if (!seen.append(v)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!seen.append(v))
|
||||
return true;
|
||||
}
|
||||
|
||||
SSAUseChain *use = useChain(v);
|
||||
while (use) {
|
||||
|
|
|
@ -1365,3 +1365,11 @@ void CompartmentChecker::check(AbstractFramePtr frame)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
js::CrashAtUnhandlableOOM(const char *reason)
|
||||
{
|
||||
char msgbuf[1024];
|
||||
JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
|
||||
MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
|
|
@ -374,7 +374,7 @@ TypeSet::enumerateTypes(TypeList *list)
|
|||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
inline bool
|
||||
TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
|
||||
{
|
||||
/*
|
||||
|
@ -383,19 +383,20 @@ TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
|
|||
*/
|
||||
TypeList types;
|
||||
if (!enumerateTypes(&types))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < types.length(); i++)
|
||||
constraint->newType(cx, this, types[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintTypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExisting)
|
||||
bool
|
||||
ConstraintTypeSet::addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting)
|
||||
{
|
||||
if (!constraint) {
|
||||
/* OOM failure while constructing the constraint. */
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
JS_ASSERT(cx->compartment()->activeAnalysis);
|
||||
|
@ -410,7 +411,8 @@ ConstraintTypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExist
|
|||
constraintList = constraint;
|
||||
|
||||
if (callExisting)
|
||||
addTypesToConstraint(cx, constraint);
|
||||
return addTypesToConstraint(cx, constraint);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -502,14 +504,12 @@ TypeSet::unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc)
|
|||
|
||||
if (!res->unknownObject()) {
|
||||
for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) {
|
||||
TypeObjectKey *key = a->getObject(i);
|
||||
if (key && !res->addType(Type::ObjectType(key), alloc))
|
||||
return nullptr;
|
||||
if (TypeObjectKey *key = a->getObject(i))
|
||||
res->addType(Type::ObjectType(key), alloc);
|
||||
}
|
||||
for (size_t i = 0; i < b->getObjectCount() && !res->unknownObject(); i++) {
|
||||
TypeObjectKey *key = b->getObject(i);
|
||||
if (key && !res->addType(Type::ObjectType(key), alloc))
|
||||
return nullptr;
|
||||
if (TypeObjectKey *key = b->getObject(i))
|
||||
res->addType(Type::ObjectType(key), alloc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -761,13 +761,11 @@ class TypeCompilerConstraint : public TypeConstraint
|
|||
cx->zone()->types.addPendingRecompile(cx, compilation);
|
||||
}
|
||||
|
||||
TypeConstraint *sweep(TypeZone &zone) {
|
||||
bool sweep(TypeZone &zone, TypeConstraint **res) {
|
||||
if (data.shouldSweep() || compilation.shouldSweep(zone))
|
||||
return nullptr;
|
||||
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
|
||||
if (!res)
|
||||
zone.setPendingNukeTypes();
|
||||
return res;
|
||||
return false;
|
||||
*res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -784,9 +782,8 @@ CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileIn
|
|||
if (!data.constraintHolds(cx, property, expected))
|
||||
return false;
|
||||
|
||||
property.maybeTypes()->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
|
||||
/* callExisting = */ false);
|
||||
return true;
|
||||
return property.maybeTypes()->addConstraint(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
|
||||
/* callExisting = */ false);
|
||||
}
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
@ -941,13 +938,11 @@ class TypeConstraintFreezeStack : public TypeConstraint
|
|||
cx->zone()->types.addPendingRecompile(cx, script_);
|
||||
}
|
||||
|
||||
TypeConstraint *sweep(TypeZone &zone) {
|
||||
bool sweep(TypeZone &zone, TypeConstraint **res) {
|
||||
if (IsScriptAboutToBeFinalized(&script_))
|
||||
return nullptr;
|
||||
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
|
||||
if (!res)
|
||||
zone.setPendingNukeTypes();
|
||||
return res;
|
||||
return false;
|
||||
*res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1017,8 +1012,10 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
|
|||
size_t count = TypeScript::NumTypeSets(entry.script);
|
||||
|
||||
StackTypeSet *array = entry.script->types->typeArray();
|
||||
for (size_t i = 0; i < count; i++)
|
||||
array[i].add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!array[i].addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false))
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
|
||||
|
@ -1976,7 +1973,7 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
|
|||
if (!allocationSiteTable) {
|
||||
allocationSiteTable = cx->new_<AllocationSiteTable>();
|
||||
if (!allocationSiteTable || !allocationSiteTable->init()) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
js_delete(allocationSiteTable);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -2012,10 +2009,8 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
|
|||
|
||||
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
|
||||
res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE);
|
||||
if (!res) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
}
|
||||
key.script = keyScript;
|
||||
}
|
||||
|
||||
|
@ -2031,10 +2026,8 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!allocationSiteTable->add(p, key, res)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!allocationSiteTable->add(p, key, res))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -2209,60 +2202,6 @@ TypeZone::processPendingRecompiles(FreeOp *fop)
|
|||
fop->delete_(pending);
|
||||
}
|
||||
|
||||
void
|
||||
TypeCompartment::setPendingNukeTypes(ExclusiveContext *cx)
|
||||
{
|
||||
TypeZone *zone = &compartment()->zone()->types;
|
||||
if (!zone->pendingNukeTypes) {
|
||||
if (cx->compartment())
|
||||
js_ReportOutOfMemory(cx);
|
||||
zone->pendingNukeTypes = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeZone::setPendingNukeTypes()
|
||||
{
|
||||
pendingNukeTypes = true;
|
||||
}
|
||||
|
||||
void
|
||||
TypeZone::nukeTypes(FreeOp *fop)
|
||||
{
|
||||
/*
|
||||
* This is the usual response if we encounter an OOM while adding a type
|
||||
* or resolving type constraints. Reset the compartment to not use type
|
||||
* inference, and recompile all scripts.
|
||||
*
|
||||
* Because of the nature of constraint-based analysis (add constraints, and
|
||||
* iterate them until reaching a fixpoint), we can't undo an add of a type set,
|
||||
* and merely aborting the operation which triggered the add will not be
|
||||
* sufficient for correct behavior as we will be leaving the types in an
|
||||
* inconsistent state.
|
||||
*/
|
||||
JS_ASSERT(pendingNukeTypes);
|
||||
|
||||
if (pendingRecompiles) {
|
||||
fop->free_(pendingRecompiles);
|
||||
pendingRecompiles = nullptr;
|
||||
}
|
||||
|
||||
inferenceEnabled = false;
|
||||
|
||||
#ifdef JS_ION
|
||||
jit::InvalidateAll(fop, zone());
|
||||
|
||||
/* Throw away all JIT code in the compartment, but leave everything else alone. */
|
||||
|
||||
for (gc::CellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
jit::FinishInvalidation(fop, script);
|
||||
}
|
||||
#endif /* JS_ION */
|
||||
|
||||
pendingNukeTypes = false;
|
||||
}
|
||||
|
||||
void
|
||||
TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
|
||||
{
|
||||
|
@ -2270,23 +2209,19 @@ TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
|
|||
if (!co || !co->isValid() || co->pendingInvalidation())
|
||||
return;
|
||||
|
||||
if (!pendingRecompiles) {
|
||||
pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
|
||||
if (!pendingRecompiles) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pendingRecompiles->append(info)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
InferSpew(ISpewOps, "addPendingRecompile: %p:%s:%d",
|
||||
co->script(), co->script()->filename(), co->script()->lineno());
|
||||
|
||||
co->setPendingInvalidation();
|
||||
|
||||
if (!pendingRecompiles) {
|
||||
pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
|
||||
if (!pendingRecompiles)
|
||||
CrashAtUnhandlableOOM("Could not update pendingRecompiles");
|
||||
}
|
||||
|
||||
if (!pendingRecompiles->append(info))
|
||||
CrashAtUnhandlableOOM("Could not update pendingRecompiles");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2325,32 +2260,18 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
|
|||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
/*
|
||||
* Mark both persistent and transient type sets which contain obj as having
|
||||
* a generic object type. It is not sufficient to mark just the persistent
|
||||
* sets, as analysis of individual opcodes can pull type objects from
|
||||
* static information (like initializer objects at various offsets).
|
||||
*
|
||||
* We make a list of properties to update and fix them afterwards, as adding
|
||||
* types can't be done while iterating over cells as it can potentially make
|
||||
* new type objects as well or trigger GC.
|
||||
*/
|
||||
Vector<ConstraintTypeSet *> pending(cx);
|
||||
/* Mark type sets which contain obj as having a generic object types. */
|
||||
|
||||
for (gc::CellIter i(cx->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
|
||||
TypeObject *object = i.get<TypeObject>();
|
||||
unsigned count = object->getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = object->getProperty(i);
|
||||
if (prop && prop->types.hasType(Type::ObjectType(target))) {
|
||||
if (!pending.append(&prop->types))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
if (prop && prop->types.hasType(Type::ObjectType(target)))
|
||||
prop->types.addType(cx, Type::AnyObjectType());
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < pending.length(); i++)
|
||||
pending[i]->addType(cx, Type::AnyObjectType());
|
||||
|
||||
for (gc::CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
RootedScript script(cx, i.get<JSScript>());
|
||||
if (script->types) {
|
||||
|
@ -2461,7 +2382,6 @@ TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx,
|
|||
arrayTypeTable = cx->new_<ArrayTypeTable>();
|
||||
if (!arrayTypeTable || !arrayTypeTable->init()) {
|
||||
arrayTypeTable = nullptr;
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2474,20 +2394,15 @@ TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx,
|
|||
/* Make a new type to use for future arrays with the same elements. */
|
||||
RootedObject objProto(cx, obj->getProto());
|
||||
TypeObject *objType = newTypeObject(cx, &ArrayObject::class_, objProto);
|
||||
if (!objType) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!objType)
|
||||
return;
|
||||
}
|
||||
obj->setType(objType);
|
||||
|
||||
if (!objType->unknownProperties())
|
||||
objType->addPropertyType(cx, JSID_VOID, elementType);
|
||||
|
||||
key.proto = objProto;
|
||||
if (!p.add(cx, *arrayTypeTable, key, objType)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
(void) p.add(cx, *arrayTypeTable, key, objType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2625,8 +2540,8 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
|
|||
if (!objectTypeTable) {
|
||||
objectTypeTable = cx->new_<ObjectTypeTable>();
|
||||
if (!objectTypeTable || !objectTypeTable->init()) {
|
||||
js_delete(objectTypeTable);
|
||||
objectTypeTable = nullptr;
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2646,10 +2561,8 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
|
|||
return;
|
||||
|
||||
Vector<IdValuePair> properties(cx);
|
||||
if (!properties.resize(obj->slotSpan())) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!properties.resize(obj->slotSpan()))
|
||||
return;
|
||||
}
|
||||
|
||||
Shape *shape = obj->lastProperty();
|
||||
while (!shape->isEmptyShape()) {
|
||||
|
@ -2674,25 +2587,19 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
|
|||
/* Make a new type to use for the object and similar future ones. */
|
||||
Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
|
||||
TypeObject *objType = newTypeObject(cx, &JSObject::class_, objProto);
|
||||
if (!objType || !objType->addDefiniteProperties(cx, obj)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!objType || !objType->addDefiniteProperties(cx, obj))
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj->isIndexed())
|
||||
objType->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES);
|
||||
|
||||
jsid *ids = cx->pod_calloc<jsid>(properties.length());
|
||||
if (!ids) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
ScopedJSFreePtr<jsid> ids(cx->pod_calloc<jsid>(properties.length()));
|
||||
if (!ids)
|
||||
return;
|
||||
}
|
||||
|
||||
Type *types = cx->pod_calloc<Type>(properties.length());
|
||||
if (!types) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
ScopedJSFreePtr<Type> types(cx->pod_calloc<Type>(properties.length()));
|
||||
if (!types)
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < properties.length(); i++) {
|
||||
ids[i] = properties[i].id;
|
||||
|
@ -2712,13 +2619,13 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
|
|||
entry.shape = obj->lastProperty();
|
||||
entry.types = types;
|
||||
|
||||
p = objectTypeTable->lookupForAdd(lookup);
|
||||
if (!objectTypeTable->add(p, key, entry)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
obj->setType(objType);
|
||||
|
||||
p = objectTypeTable->lookupForAdd(lookup);
|
||||
if (objectTypeTable->add(p, key, entry)) {
|
||||
ids.forget();
|
||||
types.forget();
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -2729,8 +2636,8 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
|
|||
if (!objectTypeTable) {
|
||||
objectTypeTable = cx->new_<ObjectTypeTable>();
|
||||
if (!objectTypeTable || !objectTypeTable->init()) {
|
||||
js_delete(objectTypeTable);
|
||||
objectTypeTable = nullptr;
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -2807,8 +2714,7 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
|
|||
|
||||
if (shape->hasGetterValue() || shape->hasSetterValue()) {
|
||||
types->setNonDataProperty(cx);
|
||||
if (!types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc());
|
||||
} else if (shape->hasDefaultGetter() && shape->hasSlot()) {
|
||||
if (!indexed && types->canSetDefinite(shape->slot()))
|
||||
types->setDefinite(shape->slot());
|
||||
|
@ -2822,8 +2728,7 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
|
|||
*/
|
||||
if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
|
||||
Type type = GetValueType(value);
|
||||
if (!types->TypeSet::addType(type, &cx->typeLifoAlloc()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
types->TypeSet::addType(type, &cx->typeLifoAlloc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2833,10 +2738,8 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
|
|||
{
|
||||
JS_ASSERT(!*pprop);
|
||||
Property *base = cx->typeLifoAlloc().new_<Property>(id);
|
||||
if (!base) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!base)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (singleton() && singleton()->isNative()) {
|
||||
/*
|
||||
|
@ -2860,8 +2763,7 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
|
|||
const Value &value = singleton()->getDenseElement(i);
|
||||
if (!value.isMagic(JS_ELEMENTS_HOLE)) {
|
||||
Type type = GetValueType(value);
|
||||
if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc()))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
base->types.TypeSet::addType(type, &cx->typeLifoAlloc());
|
||||
}
|
||||
}
|
||||
} else if (!JSID_IS_EMPTY(id)) {
|
||||
|
@ -2969,28 +2871,6 @@ TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, const Value &value)
|
|||
InlineAddTypeProperty(cx, this, id, GetValueType(value));
|
||||
}
|
||||
|
||||
void
|
||||
TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, Type type)
|
||||
{
|
||||
jsid id = JSID_VOID;
|
||||
if (name) {
|
||||
JSAtom *atom = Atomize(cx, name, strlen(name));
|
||||
if (!atom) {
|
||||
AutoEnterAnalysis enter(cx);
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
id = AtomToId(atom);
|
||||
}
|
||||
InlineAddTypeProperty(cx, this, id, type);
|
||||
}
|
||||
|
||||
void
|
||||
TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, const Value &value)
|
||||
{
|
||||
addPropertyType(cx, name, GetValueType(value));
|
||||
}
|
||||
|
||||
void
|
||||
TypeObject::markPropertyNonData(ExclusiveContext *cx, jsid id)
|
||||
{
|
||||
|
@ -3242,10 +3122,8 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
|
|||
}
|
||||
}
|
||||
|
||||
if (!finished) {
|
||||
if (!JSObject::rollbackProperties(cx, obj, numProperties))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
if (!finished)
|
||||
(void) JSObject::rollbackProperties(cx, obj, numProperties);
|
||||
}
|
||||
} else {
|
||||
// Threads with an ExclusiveContext are not allowed to run scripts.
|
||||
|
@ -3339,13 +3217,11 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
|
|||
|
||||
void newType(JSContext *cx, TypeSet *source, Type type) {}
|
||||
|
||||
TypeConstraint *sweep(TypeZone &zone) {
|
||||
bool sweep(TypeZone &zone, TypeConstraint **res) {
|
||||
if (IsTypeObjectAboutToBeFinalized(&object))
|
||||
return nullptr;
|
||||
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
|
||||
if (!res)
|
||||
zone.setPendingNukeTypes();
|
||||
return res;
|
||||
return false;
|
||||
*res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3365,7 +3241,8 @@ types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *
|
|||
HeapTypeSet *parentTypes = parentObject->getProperty(cx, id);
|
||||
if (!parentTypes || parentTypes->nonDataProperty() || parentTypes->nonWritableProperty())
|
||||
return false;
|
||||
parentTypes->add(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type));
|
||||
if (!parentTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type)))
|
||||
return false;
|
||||
parent = parent->getProto();
|
||||
}
|
||||
return true;
|
||||
|
@ -3394,17 +3271,15 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint
|
|||
object->clearAddendum(cx);
|
||||
}
|
||||
|
||||
TypeConstraint *sweep(TypeZone &zone) {
|
||||
bool sweep(TypeZone &zone, TypeConstraint **res) {
|
||||
if (IsTypeObjectAboutToBeFinalized(&object))
|
||||
return nullptr;
|
||||
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
|
||||
if (!res)
|
||||
zone.setPendingNukeTypes();
|
||||
return res;
|
||||
return false;
|
||||
*res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
bool
|
||||
types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
|
||||
JSScript *script, JSScript *calleeScript)
|
||||
{
|
||||
|
@ -3437,10 +3312,12 @@ types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
|
|||
}
|
||||
// This is a type set that might have been used when inlining
|
||||
// |calleeScript| into |script|.
|
||||
types->add(cx,
|
||||
cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
|
||||
if (!types->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3464,12 +3341,8 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
|
|||
|
||||
Vector<TypeNewScript::Initializer> initializerList(cx);
|
||||
|
||||
if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (baseobj->slotSpan() == 0 ||
|
||||
if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList) ||
|
||||
baseobj->slotSpan() == 0 ||
|
||||
!!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
|
||||
{
|
||||
if (type->hasNewScript())
|
||||
|
@ -3509,7 +3382,6 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
|
|||
!type->addDefiniteProperties(cx, baseobj) ||
|
||||
!initializerList.append(done))
|
||||
{
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3526,15 +3398,13 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
|
|||
#else
|
||||
newScript = (TypeNewScript *) cx->calloc_(numBytes);
|
||||
#endif
|
||||
if (!newScript)
|
||||
return;
|
||||
|
||||
new (newScript) TypeNewScript();
|
||||
|
||||
type->setAddendum(newScript);
|
||||
|
||||
if (!newScript) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
newScript->fun = fun;
|
||||
newScript->templateObject = baseobj;
|
||||
|
||||
|
@ -3684,10 +3554,8 @@ JSScript::makeTypes(JSContext *cx)
|
|||
unsigned count = TypeScript::NumTypeSets(this);
|
||||
|
||||
TypeScript *typeScript = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(StackTypeSet) * count));
|
||||
if (!typeScript) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!typeScript)
|
||||
return false;
|
||||
}
|
||||
|
||||
new(typeScript) TypeScript();
|
||||
|
||||
|
@ -3836,6 +3704,7 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
|
|||
{
|
||||
JS_ASSERT(obj->hasLazyType());
|
||||
JS_ASSERT(cx->compartment() == obj->compartment());
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
|
||||
/* De-lazification of functions can GC, so we need to do it up here. */
|
||||
if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
|
||||
|
@ -3859,17 +3728,8 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
|
|||
|
||||
Rooted<TaggedProto> proto(cx, obj->getTaggedProto());
|
||||
TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto, initialFlags);
|
||||
if (!type) {
|
||||
if (cx->typeInferenceEnabled())
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
if (!type)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!cx->typeInferenceEnabled()) {
|
||||
/* This can only happen if types were previously nuked. */
|
||||
obj->type_ = type;
|
||||
return type;
|
||||
}
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
|
@ -4048,22 +3908,22 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
|
|||
*/
|
||||
|
||||
if (obj->is<RegExpObject>()) {
|
||||
AddTypeProperty(this, type, "source", types::Type::StringType());
|
||||
AddTypeProperty(this, type, "global", types::Type::BooleanType());
|
||||
AddTypeProperty(this, type, "ignoreCase", types::Type::BooleanType());
|
||||
AddTypeProperty(this, type, "multiline", types::Type::BooleanType());
|
||||
AddTypeProperty(this, type, "sticky", types::Type::BooleanType());
|
||||
AddTypeProperty(this, type, "lastIndex", types::Type::Int32Type());
|
||||
type->addPropertyType(this, NameToId(names().source), Type::StringType());
|
||||
type->addPropertyType(this, NameToId(names().global), Type::BooleanType());
|
||||
type->addPropertyType(this, NameToId(names().ignoreCase), Type::BooleanType());
|
||||
type->addPropertyType(this, NameToId(names().multiline), Type::BooleanType());
|
||||
type->addPropertyType(this, NameToId(names().sticky), Type::BooleanType());
|
||||
type->addPropertyType(this, NameToId(names().lastIndex), Type::Int32Type());
|
||||
}
|
||||
|
||||
if (obj->is<StringObject>())
|
||||
AddTypeProperty(this, type, "length", Type::Int32Type());
|
||||
type->addPropertyType(this, NameToId(names().length), Type::Int32Type());
|
||||
|
||||
if (obj->is<ErrorObject>()) {
|
||||
AddTypeProperty(this, type, "fileName", types::Type::StringType());
|
||||
AddTypeProperty(this, type, "lineNumber", types::Type::Int32Type());
|
||||
AddTypeProperty(this, type, "columnNumber", types::Type::Int32Type());
|
||||
AddTypeProperty(this, type, "stack", types::Type::StringType());
|
||||
type->addPropertyType(this, NameToId(names().fileName), Type::StringType());
|
||||
type->addPropertyType(this, NameToId(names().lineNumber), Type::Int32Type());
|
||||
type->addPropertyType(this, NameToId(names().columnNumber), Type::Int32Type());
|
||||
type->addPropertyType(this, NameToId(names().stack), Type::StringType());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4152,10 +4012,9 @@ ConstraintTypeSet::sweep(Zone *zone)
|
|||
TypeObjectKey **pentry =
|
||||
HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(zone->types.typeLifoAlloc, objectSet, objectCount, object);
|
||||
if (pentry)
|
||||
*pentry = object;
|
||||
else
|
||||
zone->types.setPendingNukeTypes();
|
||||
if (!pentry)
|
||||
CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
|
||||
*pentry = object;
|
||||
}
|
||||
}
|
||||
setBaseObjectCount(objectCount);
|
||||
|
@ -4174,7 +4033,10 @@ ConstraintTypeSet::sweep(Zone *zone)
|
|||
TypeConstraint *constraint = constraintList;
|
||||
constraintList = nullptr;
|
||||
while (constraint) {
|
||||
if (TypeConstraint *copy = constraint->sweep(zone->types)) {
|
||||
TypeConstraint *copy;
|
||||
if (constraint->sweep(zone->types, ©)) {
|
||||
if (!copy)
|
||||
CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
|
||||
copy->next = constraintList;
|
||||
constraintList = copy;
|
||||
}
|
||||
|
@ -4230,20 +4092,19 @@ TypeObject::sweep(FreeOp *fop)
|
|||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
|
||||
if (newProp) {
|
||||
Property **pentry =
|
||||
HashSetInsert<jsid,Property,Property>
|
||||
(typeLifoAlloc, propertySet, propertyCount, prop->id);
|
||||
if (pentry) {
|
||||
*pentry = newProp;
|
||||
newProp->types.sweep(zone());
|
||||
} else {
|
||||
zone()->types.setPendingNukeTypes();
|
||||
}
|
||||
} else {
|
||||
zone()->types.setPendingNukeTypes();
|
||||
}
|
||||
if (!newProp)
|
||||
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
|
||||
|
||||
Property **pentry =
|
||||
HashSetInsert<jsid,Property,Property>
|
||||
(typeLifoAlloc, propertySet, propertyCount, prop->id);
|
||||
if (!pentry)
|
||||
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
|
||||
|
||||
*pentry = newProp;
|
||||
newProp->types.sweep(zone());
|
||||
}
|
||||
}
|
||||
setBasePropertyCount(propertyCount);
|
||||
|
@ -4254,12 +4115,11 @@ TypeObject::sweep(FreeOp *fop)
|
|||
clearProperties();
|
||||
} else {
|
||||
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
|
||||
if (newProp) {
|
||||
propertySet = (Property **) newProp;
|
||||
newProp->types.sweep(zone());
|
||||
} else {
|
||||
zone()->types.setPendingNukeTypes();
|
||||
}
|
||||
if (!newProp)
|
||||
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
|
||||
|
||||
propertySet = (Property **) newProp;
|
||||
newProp->types.sweep(zone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4449,7 +4309,6 @@ TypeZone::TypeZone(Zone *zone)
|
|||
typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
compilerOutputs(nullptr),
|
||||
pendingRecompiles(nullptr),
|
||||
pendingNukeTypes(false),
|
||||
inferenceEnabled(false)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -242,6 +242,10 @@ class Type
|
|||
return data > JSVAL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
bool isObjectUnchecked() const {
|
||||
return data > JSVAL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
inline TypeObjectKey *objectKey() const;
|
||||
|
||||
/* Accessors for JSObject types */
|
||||
|
@ -335,7 +339,7 @@ public:
|
|||
* 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;
|
||||
virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0;
|
||||
};
|
||||
|
||||
/* Flags and other state stored in TypeSet::flags */
|
||||
|
@ -528,7 +532,7 @@ class TypeSet
|
|||
static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
|
||||
|
||||
/* Add a type to this set using the specified allocator. */
|
||||
inline bool addType(Type type, LifoAlloc *alloc);
|
||||
inline void addType(Type type, LifoAlloc *alloc);
|
||||
|
||||
/* Get a list of all types in this set. */
|
||||
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
|
||||
|
@ -543,7 +547,6 @@ class TypeSet
|
|||
inline TypeObjectKey *getObject(unsigned i) const;
|
||||
inline JSObject *getSingleObject(unsigned i) const;
|
||||
inline TypeObject *getTypeObject(unsigned i) const;
|
||||
inline bool getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **obj) const;
|
||||
|
||||
/* The Class of an object in this set. */
|
||||
inline const Class *getObjectClass(unsigned i) const;
|
||||
|
@ -568,7 +571,7 @@ class TypeSet
|
|||
bool isSubset(TypeSet *other);
|
||||
|
||||
/* Forward all types in this set to the specified constraint. */
|
||||
void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
|
||||
bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
|
||||
|
||||
// Clone a type set into an arbitrary allocator.
|
||||
TemporaryTypeSet *clone(LifoAlloc *alloc) const;
|
||||
|
@ -599,7 +602,7 @@ class ConstraintTypeSet : public TypeSet
|
|||
inline void addType(ExclusiveContext *cx, Type type);
|
||||
|
||||
/* Add a new constraint to this set. */
|
||||
void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
|
||||
inline void sweep(JS::Zone *zone);
|
||||
};
|
||||
|
@ -739,7 +742,7 @@ class TemporaryTypeSet : public TypeSet
|
|||
bool
|
||||
AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id);
|
||||
|
||||
void
|
||||
bool
|
||||
AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
|
||||
JSScript *script, JSScript *calleeScript);
|
||||
|
||||
|
@ -1108,8 +1111,6 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
|||
void addPrototype(JSContext *cx, TypeObject *proto);
|
||||
void addPropertyType(ExclusiveContext *cx, jsid id, Type type);
|
||||
void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value);
|
||||
void addPropertyType(ExclusiveContext *cx, const char *name, Type type);
|
||||
void addPropertyType(ExclusiveContext *cx, const char *name, const Value &value);
|
||||
void markPropertyNonData(ExclusiveContext *cx, jsid id);
|
||||
void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
|
||||
void markStateChange(ExclusiveContext *cx);
|
||||
|
@ -1527,9 +1528,6 @@ struct TypeCompartment
|
|||
/* Get or make an object for an allocation site, and add to the allocation site table. */
|
||||
TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
|
||||
|
||||
/* Mark all types as needing destruction once inference has 'finished'. */
|
||||
void setPendingNukeTypes(ExclusiveContext *cx);
|
||||
|
||||
/* Mark any type set containing obj as having a generic object type. */
|
||||
void markSetsUnknown(JSContext *cx, TypeObject *obj);
|
||||
|
||||
|
@ -1562,12 +1560,6 @@ struct TypeZone
|
|||
/* 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.
|
||||
*/
|
||||
bool pendingNukeTypes;
|
||||
|
||||
/* Whether type inference is enabled in this compartment. */
|
||||
bool inferenceEnabled;
|
||||
|
||||
|
@ -1579,16 +1571,11 @@ struct TypeZone
|
|||
|
||||
void sweep(FreeOp *fop, bool releaseTypes);
|
||||
|
||||
/* 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);
|
||||
};
|
||||
|
||||
enum SpewChannel {
|
||||
|
|
|
@ -247,9 +247,7 @@ struct AutoEnterAnalysis
|
|||
*/
|
||||
if (!compartment->activeAnalysis) {
|
||||
TypeZone &types = compartment->zone()->types;
|
||||
if (types.pendingNukeTypes)
|
||||
types.nukeTypes(freeOp);
|
||||
else if (types.pendingRecompiles)
|
||||
if (types.pendingRecompiles)
|
||||
types.processPendingRecompiles(freeOp);
|
||||
}
|
||||
}
|
||||
|
@ -385,12 +383,11 @@ EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
|
|||
if (obj->hasSingletonType()) {
|
||||
AutoEnterAnalysis enter(cx);
|
||||
if (obj->hasLazyType() && !obj->getType(cx)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
cx->clearPendingException();
|
||||
CrashAtUnhandlableOOM("Could not allocate TypeObject in EnsureTrackPropertyTypes");
|
||||
return;
|
||||
}
|
||||
if (!obj->type()->unknownProperties() && !obj->type()->getProperty(cx, id)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
obj->type()->markUnknown(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -450,17 +447,17 @@ AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, const Value &val
|
|||
}
|
||||
|
||||
inline void
|
||||
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, Type type)
|
||||
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, jsid id, Type type)
|
||||
{
|
||||
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
|
||||
obj->addPropertyType(cx, name, type);
|
||||
obj->addPropertyType(cx, id, type);
|
||||
}
|
||||
|
||||
inline void
|
||||
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, const Value &value)
|
||||
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, jsid id, const Value &value)
|
||||
{
|
||||
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
|
||||
obj->addPropertyType(cx, name, value);
|
||||
obj->addPropertyType(cx, id, value);
|
||||
}
|
||||
|
||||
/* Set one or more dynamic flags on a type object. */
|
||||
|
@ -1055,34 +1052,34 @@ TypeSet::clearObjects()
|
|||
objectSet = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
TypeSet::addType(Type type, LifoAlloc *alloc)
|
||||
{
|
||||
if (unknown())
|
||||
return true;
|
||||
return;
|
||||
|
||||
if (type.isUnknown()) {
|
||||
flags |= TYPE_FLAG_BASE_MASK;
|
||||
clearObjects();
|
||||
JS_ASSERT(unknown());
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.isPrimitive()) {
|
||||
TypeFlags flag = PrimitiveTypeFlag(type.primitive());
|
||||
if (flags & flag)
|
||||
return true;
|
||||
return;
|
||||
|
||||
/* If we add float to a type set it is also considered to contain int. */
|
||||
if (flag == TYPE_FLAG_DOUBLE)
|
||||
flag |= TYPE_FLAG_INT32;
|
||||
|
||||
flags |= flag;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & TYPE_FLAG_ANYOBJECT)
|
||||
return true;
|
||||
return;
|
||||
if (type.isAnyObject())
|
||||
goto unknownObject;
|
||||
|
||||
|
@ -1092,9 +1089,9 @@ TypeSet::addType(Type type, LifoAlloc *alloc)
|
|||
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(*alloc, objectSet, objectCount, object);
|
||||
if (!pentry)
|
||||
return false;
|
||||
goto unknownObject;
|
||||
if (*pentry)
|
||||
return true;
|
||||
return;
|
||||
*pentry = object;
|
||||
|
||||
setBaseObjectCount(objectCount);
|
||||
|
@ -1116,8 +1113,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc)
|
|||
flags |= TYPE_FLAG_ANYOBJECT;
|
||||
clearObjects();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -1128,10 +1123,10 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
|
|||
if (hasType(type))
|
||||
return;
|
||||
|
||||
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
|
||||
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
|
||||
return;
|
||||
}
|
||||
TypeSet::addType(type, &cxArg->typeLifoAlloc());
|
||||
|
||||
if (type.isObjectUnchecked() && unknownObject())
|
||||
type = Type::AnyObjectType();
|
||||
|
||||
InferSpew(ISpewOps, "addType: %sT%p%s %s",
|
||||
InferSpewColor(this), this, InferSpewColorReset(),
|
||||
|
@ -1219,30 +1214,6 @@ TypeSet::getTypeObject(unsigned i) const
|
|||
return (key && key->isTypeObject()) ? key->asTypeObject() : nullptr;
|
||||
}
|
||||
|
||||
inline bool
|
||||
TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **result) const
|
||||
{
|
||||
JS_ASSERT(result);
|
||||
JS_ASSERT(cx->compartment()->activeAnalysis);
|
||||
|
||||
*result = nullptr;
|
||||
|
||||
TypeObject *type = getTypeObject(i);
|
||||
if (!type) {
|
||||
JSObject *singleton = getSingleObject(i);
|
||||
if (!singleton)
|
||||
return true;
|
||||
|
||||
type = singleton->uninlinedGetType(cx);
|
||||
if (!type) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*result = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline const Class *
|
||||
TypeSet::getObjectClass(unsigned i) const
|
||||
{
|
||||
|
@ -1302,7 +1273,7 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id)
|
|||
Property **pprop = HashSetInsert<jsid,Property,Property>
|
||||
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
|
||||
if (!pprop) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
markUnknown(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1310,8 +1281,7 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id)
|
|||
|
||||
setBasePropertyCount(propertyCount);
|
||||
if (!addProperty(cx, id, pprop)) {
|
||||
setBasePropertyCount(0);
|
||||
propertySet = nullptr;
|
||||
markUnknown(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -3209,7 +3209,7 @@ SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Ma
|
|||
return nullptr;
|
||||
} else {
|
||||
/* Only string entries have been accounted for so far. */
|
||||
AddTypeProperty(cx, type, nullptr, UndefinedValue());
|
||||
AddTypeProperty(cx, type, JSID_VOID, UndefinedValue());
|
||||
if (!splits.append(UndefinedValue()))
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3344,7 +3344,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
|
|||
RootedTypeObject type(cx, GetTypeCallerInitObject(cx, JSProto_Array));
|
||||
if (!type)
|
||||
return false;
|
||||
AddTypeProperty(cx, type, nullptr, Type::StringType());
|
||||
AddTypeProperty(cx, type, JSID_VOID, Type::StringType());
|
||||
|
||||
/* Step 5: Use the second argument as the split limit, if given. */
|
||||
uint32_t limit;
|
||||
|
|
Загрузка…
Ссылка в новой задаче