mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1073766 - Guard on the global's shape, when optimizing on its proto-chain. r=bhackett
This commit is contained in:
parent
1a481b0b30
commit
3d3db0eaa4
@ -479,8 +479,20 @@ BaselineInspector::templateCallObject()
|
|||||||
return &res->as<CallObject>();
|
return &res->as<CallObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Shape *GlobalShapeForGetPropFunction(ICStub *stub)
|
||||||
|
{
|
||||||
|
if (stub->isGetProp_CallNativePrototype()) {
|
||||||
|
ICGetProp_CallNativePrototype *nstub =
|
||||||
|
stub->toGetProp_CallNativePrototype();
|
||||||
|
if (nstub->receiverShape()->getObjectClass()->flags & JSCLASS_IS_GLOBAL)
|
||||||
|
return nstub->receiverShape();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
|
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
|
||||||
|
Shape **globalShape)
|
||||||
{
|
{
|
||||||
if (!hasBaselineScript())
|
if (!hasBaselineScript())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -489,6 +501,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
|||||||
JSObject* holder = nullptr;
|
JSObject* holder = nullptr;
|
||||||
Shape *holderShape = nullptr;
|
Shape *holderShape = nullptr;
|
||||||
JSFunction *getter = nullptr;
|
JSFunction *getter = nullptr;
|
||||||
|
Shape *global = nullptr;
|
||||||
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
|
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||||
if (stub->isGetProp_CallScripted() ||
|
if (stub->isGetProp_CallScripted() ||
|
||||||
stub->isGetProp_CallNative() ||
|
stub->isGetProp_CallNative() ||
|
||||||
@ -499,7 +512,10 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
|||||||
holder = nstub->holder();
|
holder = nstub->holder();
|
||||||
holderShape = nstub->holderShape();
|
holderShape = nstub->holderShape();
|
||||||
getter = nstub->getter();
|
getter = nstub->getter();
|
||||||
} else if (nstub->holderShape() != holderShape) {
|
global = GlobalShapeForGetPropFunction(nstub);
|
||||||
|
} else if (nstub->holderShape() != holderShape ||
|
||||||
|
GlobalShapeForGetPropFunction(nstub) != global)
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(getter == nstub->getter());
|
MOZ_ASSERT(getter == nstub->getter());
|
||||||
@ -513,6 +529,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
|||||||
}
|
}
|
||||||
*lastProperty = holderShape;
|
*lastProperty = holderShape;
|
||||||
*commonGetter = getter;
|
*commonGetter = getter;
|
||||||
|
*globalShape = global;
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,8 @@ class BaselineInspector
|
|||||||
DeclEnvObject *templateDeclEnvObject();
|
DeclEnvObject *templateDeclEnvObject();
|
||||||
CallObject *templateCallObject();
|
CallObject *templateCallObject();
|
||||||
|
|
||||||
JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter);
|
JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
|
||||||
|
Shape **globalShape);
|
||||||
JSObject *commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter);
|
JSObject *commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8770,7 +8770,7 @@ IonBuilder::jsop_not()
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||||
bool isGetter, JSObject *foundProto)
|
bool isGetter, JSObject *foundProto, bool *guardGlobal)
|
||||||
{
|
{
|
||||||
// With foundProto a prototype with a getter or setter for name, return
|
// With foundProto a prototype with a getter or setter for name, return
|
||||||
// whether looking up name on any object in |types| will go through
|
// whether looking up name on any object in |types| will go through
|
||||||
@ -8780,6 +8780,7 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
|||||||
// No sense looking if we don't know what's going on.
|
// No sense looking if we don't know what's going on.
|
||||||
if (!types || types->unknownObject())
|
if (!types || types->unknownObject())
|
||||||
return false;
|
return false;
|
||||||
|
*guardGlobal = false;
|
||||||
|
|
||||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||||
if (types->getSingleObject(i) == foundProto)
|
if (types->getSingleObject(i) == foundProto)
|
||||||
@ -8794,8 +8795,14 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Class *clasp = type->clasp();
|
const Class *clasp = type->clasp();
|
||||||
if (!ClassHasEffectlessLookup(clasp, name) || ClassHasResolveHook(compartment, clasp, name))
|
if (!ClassHasEffectlessLookup(clasp, name))
|
||||||
return false;
|
return false;
|
||||||
|
JSObject *singleton = type->singleton();
|
||||||
|
if (ClassHasResolveHook(compartment, clasp, name)) {
|
||||||
|
if (!singleton || !singleton->is<GlobalObject>())
|
||||||
|
return false;
|
||||||
|
*guardGlobal = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Look for a getter/setter on the class itself which may need
|
// Look for a getter/setter on the class itself which may need
|
||||||
// to be called. Ignore the getGeneric hook for typed arrays, it
|
// to be called. Ignore the getGeneric hook for typed arrays, it
|
||||||
@ -8813,9 +8820,11 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
|||||||
if (!types->empty() || types->nonDataProperty())
|
if (!types->empty() || types->nonDataProperty())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (JSObject *obj = type->singleton()) {
|
if (singleton) {
|
||||||
if (types::CanHaveEmptyPropertyTypesForOwnProperty(obj))
|
if (types::CanHaveEmptyPropertyTypesForOwnProperty(singleton)) {
|
||||||
return false;
|
MOZ_ASSERT(singleton->is<GlobalObject>());
|
||||||
|
*guardGlobal = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!type->hasTenuredProto())
|
if (!type->hasTenuredProto())
|
||||||
@ -8837,7 +8846,8 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
|||||||
|
|
||||||
void
|
void
|
||||||
IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||||
JSObject *foundProto)
|
JSObject *foundProto,
|
||||||
|
bool allowEmptyTypesforGlobal/* = false*/)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||||
// If we found a Singleton object's own-property, there's nothing to
|
// If we found a Singleton object's own-property, there's nothing to
|
||||||
@ -8851,7 +8861,7 @@ IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, P
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
types::HeapTypeSetKey property = type->property(NameToId(name));
|
types::HeapTypeSetKey property = type->property(NameToId(name));
|
||||||
JS_ALWAYS_TRUE(!property.isOwnProperty(constraints()));
|
JS_ALWAYS_TRUE(!property.isOwnProperty(constraints(), allowEmptyTypesforGlobal));
|
||||||
|
|
||||||
// Don't mark the proto. It will be held down by the shape
|
// Don't mark the proto. It will be held down by the shape
|
||||||
// guard. This allows us to use properties found on prototypes
|
// guard. This allows us to use properties found on prototypes
|
||||||
@ -8865,21 +8875,34 @@ IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, P
|
|||||||
|
|
||||||
inline MDefinition *
|
inline MDefinition *
|
||||||
IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
||||||
bool isGetter, JSObject *foundProto, Shape *lastProperty)
|
bool isGetter, JSObject *foundProto, Shape *lastProperty,
|
||||||
|
Shape *globalShape/* = nullptr*/)
|
||||||
{
|
{
|
||||||
|
bool guardGlobal;
|
||||||
|
|
||||||
// Check if all objects being accessed will lookup the name through foundProto.
|
// Check if all objects being accessed will lookup the name through foundProto.
|
||||||
if (!objectsHaveCommonPrototype(types, name, isGetter, foundProto))
|
if (!objectsHaveCommonPrototype(types, name, isGetter, foundProto, &guardGlobal) ||
|
||||||
|
(guardGlobal && !globalShape))
|
||||||
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// We can optimize the getter/setter, so freeze all involved properties to
|
// We can optimize the getter/setter, so freeze all involved properties to
|
||||||
// ensure there isn't a lower shadowing getter or setter installed in the
|
// ensure there isn't a lower shadowing getter or setter installed in the
|
||||||
// future.
|
// future.
|
||||||
freezePropertiesForCommonPrototype(types, name, foundProto);
|
freezePropertiesForCommonPrototype(types, name, foundProto, guardGlobal);
|
||||||
|
|
||||||
// Add a shape guard on the prototype we found the property on. The rest of
|
// Add a shape guard on the prototype we found the property on. The rest of
|
||||||
// the prototype chain is guarded by TI freezes. Note that a shape guard is
|
// the prototype chain is guarded by TI freezes, except when name is a global
|
||||||
// good enough here, even in the proxy case, because we have ensured there
|
// name. In this case, we also have to guard on the globals shape to be able
|
||||||
// are no lookup hooks for this property.
|
// to optimize. Note that a shape guard is good enough here, even in the proxy
|
||||||
|
// case, because we have ensured there are no lookup hooks for this property.
|
||||||
|
if (guardGlobal) {
|
||||||
|
JSObject *obj = &script()->global();
|
||||||
|
MDefinition *globalObj = constant(ObjectValue(*obj));
|
||||||
|
addShapeGuard(globalObj, globalShape, Bailout_ShapeGuard);
|
||||||
|
}
|
||||||
|
|
||||||
MInstruction *wrapper = constant(ObjectValue(*foundProto));
|
MInstruction *wrapper = constant(ObjectValue(*foundProto));
|
||||||
return addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
|
return addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
|
||||||
}
|
}
|
||||||
@ -9407,13 +9430,14 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
|||||||
|
|
||||||
Shape *lastProperty = nullptr;
|
Shape *lastProperty = nullptr;
|
||||||
JSFunction *commonGetter = nullptr;
|
JSFunction *commonGetter = nullptr;
|
||||||
JSObject *foundProto = inspector->commonGetPropFunction(pc, &lastProperty, &commonGetter);
|
Shape *globalShape = nullptr;
|
||||||
|
JSObject *foundProto = inspector->commonGetPropFunction(pc, &lastProperty, &commonGetter, &globalShape);
|
||||||
if (!foundProto)
|
if (!foundProto)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||||
MDefinition *guard = testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
|
MDefinition *guard = testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
|
||||||
foundProto, lastProperty);
|
foundProto, lastProperty, globalShape);
|
||||||
if (!guard)
|
if (!guard)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -807,11 +807,12 @@ class IonBuilder
|
|||||||
MBasicBlock *bottom);
|
MBasicBlock *bottom);
|
||||||
|
|
||||||
bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||||
bool isGetter, JSObject *foundProto);
|
bool isGetter, JSObject *foundProto, bool *guardGlobal);
|
||||||
void freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
void freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||||
JSObject *foundProto);
|
JSObject *foundProto, bool allowEmptyTypesForGlobal = false);
|
||||||
MDefinition *testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
MDefinition *testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name,
|
||||||
bool isGetter, JSObject *foundProto, Shape *lastProperty);
|
bool isGetter, JSObject *foundProto, Shape *lastProperty,
|
||||||
|
Shape *globalShape = nullptr);
|
||||||
bool testShouldDOMCall(types::TypeSet *inTypes,
|
bool testShouldDOMCall(types::TypeSet *inTypes,
|
||||||
JSFunction *func, JSJitInfo::OpType opType);
|
JSFunction *func, JSJitInfo::OpType opType);
|
||||||
|
|
||||||
|
@ -1446,11 +1446,14 @@ HeapTypeSetKey::knownMIRType(CompilerConstraintList *constraints)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints)
|
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints,
|
||||||
|
bool allowEmptyTypesForGlobal/* = false*/)
|
||||||
{
|
{
|
||||||
if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->nonDataProperty()))
|
if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->nonDataProperty()))
|
||||||
return true;
|
return true;
|
||||||
if (JSObject *obj = object()->singleton()) {
|
JSObject *obj = object()->singleton();
|
||||||
|
MOZ_ASSERT_IF(obj, CanHaveEmptyPropertyTypesForOwnProperty(obj) == obj->is<GlobalObject>());
|
||||||
|
if (obj && !allowEmptyTypesForGlobal) {
|
||||||
if (CanHaveEmptyPropertyTypesForOwnProperty(obj))
|
if (CanHaveEmptyPropertyTypesForOwnProperty(obj))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1566,7 +1566,7 @@ class HeapTypeSetKey
|
|||||||
jit::MIRType knownMIRType(CompilerConstraintList *constraints);
|
jit::MIRType knownMIRType(CompilerConstraintList *constraints);
|
||||||
bool nonData(CompilerConstraintList *constraints);
|
bool nonData(CompilerConstraintList *constraints);
|
||||||
bool nonWritable(CompilerConstraintList *constraints);
|
bool nonWritable(CompilerConstraintList *constraints);
|
||||||
bool isOwnProperty(CompilerConstraintList *constraints);
|
bool isOwnProperty(CompilerConstraintList *constraints, bool allowEmptyTypesForGlobal = false);
|
||||||
bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
|
bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
|
||||||
JSObject *singleton(CompilerConstraintList *constraints);
|
JSObject *singleton(CompilerConstraintList *constraints);
|
||||||
bool needsBarrier(CompilerConstraintList *constraints);
|
bool needsBarrier(CompilerConstraintList *constraints);
|
||||||
|
Loading…
Reference in New Issue
Block a user