mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 923693 - Distinguish different kinds of object state changes in type information, r=jandem.
This commit is contained in:
parent
0d6798ee41
commit
8e039761d9
@ -3960,7 +3960,7 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo)
|
||||
|
||||
// TI calls ObjectStateChange to trigger invalidation of the caller.
|
||||
types::TypeObjectKey *targetType = types::TypeObjectKey::get(target);
|
||||
targetType->watchStateChange(constraints());
|
||||
targetType->watchStateChangeForInlinedCall(constraints());
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -4643,7 +4643,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
|
||||
// Trigger recompilation if the templateObject changes.
|
||||
types::TypeObjectKey *templateType = types::TypeObjectKey::get(templateObject);
|
||||
if (templateType->newScript())
|
||||
templateType->watchStateChange(constraints());
|
||||
templateType->watchStateChangeForNewScriptTemplate(constraints());
|
||||
|
||||
MCreateThisWithTemplate *createThis = MCreateThisWithTemplate::New(templateObject);
|
||||
current->add(createThis);
|
||||
@ -6886,7 +6886,7 @@ IonBuilder::getTypedArrayElements(MDefinition *obj)
|
||||
// The 'data' pointer can change in rare circumstances
|
||||
// (ArrayBufferObject::changeContents).
|
||||
types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
|
||||
tarrType->watchStateChange(constraints());
|
||||
tarrType->watchStateChangeForTypedArrayBuffer(constraints());
|
||||
|
||||
obj->setFoldedUnchecked();
|
||||
return MConstantElements::New(data);
|
||||
|
@ -628,8 +628,11 @@ class TypeCompilerConstraint : public TypeConstraint
|
||||
cx->compartment()->types.addPendingRecompile(cx, compilation);
|
||||
}
|
||||
|
||||
void newObjectState(JSContext *cx, TypeObject *object, bool force) {
|
||||
if (data.invalidateOnNewObjectState(object, force))
|
||||
void newObjectState(JSContext *cx, TypeObject *object) {
|
||||
// Note: Once the object has unknown properties, no more notifications
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
@ -638,6 +641,9 @@ template <typename T>
|
||||
bool
|
||||
CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo)
|
||||
{
|
||||
if (property.actualObject->unknownProperties())
|
||||
return false;
|
||||
|
||||
if (!data.constraintHolds(cx, property, expected))
|
||||
return false;
|
||||
|
||||
@ -700,6 +706,7 @@ TypeObjectKey::property(jsid id)
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
HeapTypeSetKey property;
|
||||
property.actualObject = type;
|
||||
property.actualTypes = type->getProperty(cx, id);
|
||||
if (!property.actualTypes)
|
||||
MOZ_CRASH();
|
||||
@ -754,7 +761,7 @@ class ConstraintDataFreeze
|
||||
|
||||
bool invalidateOnNewType(Type type) { return true; }
|
||||
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object, bool force) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object) { return false; }
|
||||
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
@ -919,33 +926,27 @@ namespace {
|
||||
class ConstraintDataFreezeObjectFlags
|
||||
{
|
||||
public:
|
||||
// Object being queried.
|
||||
TypeObjectKey *object;
|
||||
|
||||
// Flags we are watching for on this object.
|
||||
TypeObjectFlags flags;
|
||||
|
||||
ConstraintDataFreezeObjectFlags(TypeObjectKey *object, TypeObjectFlags flags)
|
||||
: object(object), flags(flags)
|
||||
{}
|
||||
ConstraintDataFreezeObjectFlags(TypeObjectFlags flags)
|
||||
: flags(flags)
|
||||
{
|
||||
JS_ASSERT(flags);
|
||||
}
|
||||
|
||||
const char *kind() { return "freezeObjectFlags"; }
|
||||
|
||||
bool invalidateOnNewType(Type type) { return false; }
|
||||
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object, bool force) {
|
||||
return flags ? object->hasAnyFlags(flags) : force;
|
||||
bool invalidateOnNewObjectState(TypeObject *object) {
|
||||
return object->hasAnyFlags(flags);
|
||||
}
|
||||
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
// FIXME: There is not yet any way to test if constraints with no
|
||||
// associated flags (i.e. those invalidated via |force|) still hold.
|
||||
TypeObject *type = object->isSingleObject()
|
||||
? object->asSingleObject()->type()
|
||||
: object->asTypeObject();
|
||||
return !type->hasAnyFlags(flags);
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
}
|
||||
};
|
||||
|
||||
@ -965,20 +966,13 @@ TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags fla
|
||||
return true;
|
||||
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(this, flags)));
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(flags)));
|
||||
return false;
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
TypeObjectKey::watchStateChange(CompilerConstraintList *constraints)
|
||||
{
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(this, 0)));
|
||||
}
|
||||
|
||||
bool
|
||||
TemporaryTypeSet::hasObjectFlags(CompilerConstraintList *constraints, TypeObjectFlags flags)
|
||||
{
|
||||
@ -1002,8 +996,114 @@ TemporaryTypeSet::hasObjectFlags(CompilerConstraintList *constraints, TypeObject
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnknown, bool force)
|
||||
namespace {
|
||||
|
||||
// Constraint which triggers recompilation on any type change in an inlined
|
||||
// script. The freeze constraints added to stack type sets will only directly
|
||||
// invalidate the script containing those stack type sets. To invalidate code
|
||||
// for scripts into which the base script was inlined, ObjectStateChange is used.
|
||||
class ConstraintDataFreezeObjectForInlinedCall
|
||||
{
|
||||
public:
|
||||
ConstraintDataFreezeObjectForInlinedCall()
|
||||
{}
|
||||
|
||||
const char *kind() { return "freezeObjectForInlinedCall"; }
|
||||
|
||||
bool invalidateOnNewType(Type type) { return false; }
|
||||
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object) {
|
||||
// We don't keep track of the exact dependencies the caller has on its
|
||||
// inlined scripts' type sets, so always invalidate the caller.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Constraint which triggers recompilation when the allocation kind of the
|
||||
// template object for a type's new script changes.
|
||||
class ConstraintDataFreezeObjectForNewScriptTemplate
|
||||
{
|
||||
gc::AllocKind allocKind;
|
||||
|
||||
public:
|
||||
ConstraintDataFreezeObjectForNewScriptTemplate(gc::AllocKind allocKind)
|
||||
: allocKind(allocKind)
|
||||
{}
|
||||
|
||||
const char *kind() { return "freezeObjectForNewScriptTemplate"; }
|
||||
|
||||
bool invalidateOnNewType(Type type) { return false; }
|
||||
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object) {
|
||||
return !object->hasNewScript() || object->newScript()->allocKind != allocKind;
|
||||
}
|
||||
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
}
|
||||
};
|
||||
|
||||
// Constraint which triggers recompilation when the underlying data pointer for
|
||||
// a typed array changes.
|
||||
class ConstraintDataFreezeObjectForTypedArrayBuffer
|
||||
{
|
||||
void *viewData;
|
||||
|
||||
public:
|
||||
ConstraintDataFreezeObjectForTypedArrayBuffer(void *viewData)
|
||||
: viewData(viewData)
|
||||
{}
|
||||
|
||||
const char *kind() { return "freezeObjectForTypedArrayBuffer"; }
|
||||
|
||||
bool invalidateOnNewType(Type type) { return false; }
|
||||
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object) {
|
||||
return object->singleton->as<TypedArrayObject>().viewData() != viewData;
|
||||
}
|
||||
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
}
|
||||
};
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
void
|
||||
TypeObjectKey::watchStateChangeForInlinedCall(CompilerConstraintList *constraints)
|
||||
{
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForInlinedCall> >(objectProperty, ConstraintDataFreezeObjectForInlinedCall()));
|
||||
}
|
||||
|
||||
void
|
||||
TypeObjectKey::watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints)
|
||||
{
|
||||
gc::AllocKind kind = asTypeObject()->newScript()->allocKind;
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForNewScriptTemplate> >(objectProperty, ConstraintDataFreezeObjectForNewScriptTemplate(kind)));
|
||||
}
|
||||
|
||||
void
|
||||
TypeObjectKey::watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints)
|
||||
{
|
||||
void *viewData = asSingleObject()->as<TypedArrayObject>().viewData();
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForTypedArrayBuffer> >(objectProperty, ConstraintDataFreezeObjectForTypedArrayBuffer(viewData)));
|
||||
}
|
||||
|
||||
static void
|
||||
ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnknown)
|
||||
{
|
||||
if (object->unknownProperties())
|
||||
return;
|
||||
@ -1019,7 +1119,7 @@ ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnkno
|
||||
if (JSContext *cx = cxArg->maybeJSContext()) {
|
||||
TypeConstraint *constraint = types->constraintList;
|
||||
while (constraint) {
|
||||
constraint->newObjectState(cx, object, force);
|
||||
constraint->newObjectState(cx, object);
|
||||
constraint = constraint->next;
|
||||
}
|
||||
} else {
|
||||
@ -1048,7 +1148,7 @@ class ConstraintDataFreezeConfiguredProperty
|
||||
bool invalidateOnNewPropertyState(TypeSet *property) {
|
||||
return property->configuredProperty();
|
||||
}
|
||||
bool invalidateOnNewObjectState(TypeObject *object, bool force) { return false; }
|
||||
bool invalidateOnNewObjectState(TypeObject *object) { return false; }
|
||||
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
@ -1328,16 +1428,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList *constraints, jsid
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force recompilation of any jitcode for the script, or of any other script
|
||||
* which this script was inlined into.
|
||||
*/
|
||||
static inline void
|
||||
AddPendingRecompile(JSContext *cx, JSScript *script)
|
||||
{
|
||||
cx->compartment()->types.addPendingRecompile(cx, script);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
@ -1362,7 +1452,7 @@ class TypeConstraintFreezeStack : public TypeConstraint
|
||||
* Unlike TypeConstraintFreeze, triggering this constraint once does
|
||||
* not disable it on future changes to the type set.
|
||||
*/
|
||||
AddPendingRecompile(cx, script_);
|
||||
cx->compartment()->types.addPendingRecompile(cx, script_);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1851,7 +1941,7 @@ TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
|
||||
// changes on the callee's script, so trigger these to force recompilation
|
||||
// of any such callers.
|
||||
if (script->function() && !script->function()->hasLazyType())
|
||||
ObjectStateChange(cx, script->function()->type(), false, true);
|
||||
ObjectStateChange(cx, script->function()->type(), false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2538,7 +2628,7 @@ TypeObject::markStateChange(ExclusiveContext *cxArg)
|
||||
if (JSContext *cx = cxArg->maybeJSContext()) {
|
||||
TypeConstraint *constraint = types->constraintList;
|
||||
while (constraint) {
|
||||
constraint->newObjectState(cx, this, true);
|
||||
constraint->newObjectState(cx, this);
|
||||
constraint = constraint->next;
|
||||
}
|
||||
} else {
|
||||
@ -2565,7 +2655,7 @@ TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags)
|
||||
|
||||
InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
|
||||
|
||||
ObjectStateChange(cx, this, false, false);
|
||||
ObjectStateChange(cx, this, false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2581,7 +2671,7 @@ TypeObject::markUnknown(ExclusiveContext *cx)
|
||||
|
||||
InferSpew(ISpewOps, "UnknownProperties: %s", TypeObjectString(this));
|
||||
|
||||
ObjectStateChange(cx, this, true, true);
|
||||
ObjectStateChange(cx, this, true);
|
||||
|
||||
/*
|
||||
* Existing constraints may have already been added to this object, which we need
|
||||
|
@ -324,11 +324,11 @@ public:
|
||||
virtual void newPropertyState(JSContext *cx, TypeSet *source) {}
|
||||
|
||||
/*
|
||||
* For constraints attached to the JSID_EMPTY type set on an object, mark a
|
||||
* change in one of the object's dynamic property flags. If force is set,
|
||||
* recompilation is always triggered.
|
||||
* For constraints attached to the JSID_EMPTY type set on an object,
|
||||
* indicate a change in one of the object's dynamic property flags or other
|
||||
* state.
|
||||
*/
|
||||
virtual void newObjectState(JSContext *cx, TypeObject *object, bool force) {}
|
||||
virtual void newObjectState(JSContext *cx, TypeObject *object) {}
|
||||
};
|
||||
|
||||
/* Flags and other state stored in TypeSet::flags */
|
||||
@ -1256,13 +1256,16 @@ struct TypeObjectKey {
|
||||
|
||||
bool unknownProperties();
|
||||
bool hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags);
|
||||
void watchStateChange(CompilerConstraintList *constraints);
|
||||
void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
|
||||
void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints);
|
||||
void watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints);
|
||||
HeapTypeSetKey property(jsid id);
|
||||
};
|
||||
|
||||
class HeapTypeSetKey
|
||||
{
|
||||
public:
|
||||
TypeObject *actualObject;
|
||||
HeapTypeSet *actualTypes;
|
||||
|
||||
void freeze(CompilerConstraintList *constraints);
|
||||
|
Loading…
Reference in New Issue
Block a user