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>();
|
||||
}
|
||||
|
||||
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 *
|
||||
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
|
||||
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
|
||||
Shape **globalShape)
|
||||
{
|
||||
if (!hasBaselineScript())
|
||||
return nullptr;
|
||||
@ -489,6 +501,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
||||
JSObject* holder = nullptr;
|
||||
Shape *holderShape = nullptr;
|
||||
JSFunction *getter = nullptr;
|
||||
Shape *global = nullptr;
|
||||
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isGetProp_CallScripted() ||
|
||||
stub->isGetProp_CallNative() ||
|
||||
@ -499,7 +512,10 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
||||
holder = nstub->holder();
|
||||
holderShape = nstub->holderShape();
|
||||
getter = nstub->getter();
|
||||
} else if (nstub->holderShape() != holderShape) {
|
||||
global = GlobalShapeForGetPropFunction(nstub);
|
||||
} else if (nstub->holderShape() != holderShape ||
|
||||
GlobalShapeForGetPropFunction(nstub) != global)
|
||||
{
|
||||
return nullptr;
|
||||
} else {
|
||||
MOZ_ASSERT(getter == nstub->getter());
|
||||
@ -513,6 +529,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
|
||||
}
|
||||
*lastProperty = holderShape;
|
||||
*commonGetter = getter;
|
||||
*globalShape = global;
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,8 @@ class BaselineInspector
|
||||
DeclEnvObject *templateDeclEnvObject();
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -8770,7 +8770,7 @@ IonBuilder::jsop_not()
|
||||
|
||||
bool
|
||||
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
|
||||
// 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.
|
||||
if (!types || types->unknownObject())
|
||||
return false;
|
||||
*guardGlobal = false;
|
||||
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
if (types->getSingleObject(i) == foundProto)
|
||||
@ -8794,8 +8795,14 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
return false;
|
||||
|
||||
const Class *clasp = type->clasp();
|
||||
if (!ClassHasEffectlessLookup(clasp, name) || ClassHasResolveHook(compartment, clasp, name))
|
||||
if (!ClassHasEffectlessLookup(clasp, name))
|
||||
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
|
||||
// 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())
|
||||
return false;
|
||||
}
|
||||
if (JSObject *obj = type->singleton()) {
|
||||
if (types::CanHaveEmptyPropertyTypesForOwnProperty(obj))
|
||||
return false;
|
||||
if (singleton) {
|
||||
if (types::CanHaveEmptyPropertyTypesForOwnProperty(singleton)) {
|
||||
MOZ_ASSERT(singleton->is<GlobalObject>());
|
||||
*guardGlobal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!type->hasTenuredProto())
|
||||
@ -8837,7 +8846,8 @@ IonBuilder::objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyN
|
||||
|
||||
void
|
||||
IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
JSObject *foundProto)
|
||||
JSObject *foundProto,
|
||||
bool allowEmptyTypesforGlobal/* = false*/)
|
||||
{
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
// 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) {
|
||||
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
|
||||
// guard. This allows us to use properties found on prototypes
|
||||
@ -8865,21 +8875,34 @@ IonBuilder::freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, P
|
||||
|
||||
inline MDefinition *
|
||||
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.
|
||||
if (!objectsHaveCommonPrototype(types, name, isGetter, foundProto))
|
||||
if (!objectsHaveCommonPrototype(types, name, isGetter, foundProto, &guardGlobal) ||
|
||||
(guardGlobal && !globalShape))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// the prototype chain is guarded by TI freezes. 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.
|
||||
// the prototype chain is guarded by TI freezes, except when name is a global
|
||||
// name. In this case, we also have to guard on the globals shape to be able
|
||||
// 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));
|
||||
return addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
|
||||
}
|
||||
@ -9407,13 +9430,14 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
|
||||
|
||||
Shape *lastProperty = nullptr;
|
||||
JSFunction *commonGetter = nullptr;
|
||||
JSObject *foundProto = inspector->commonGetPropFunction(pc, &lastProperty, &commonGetter);
|
||||
Shape *globalShape = nullptr;
|
||||
JSObject *foundProto = inspector->commonGetPropFunction(pc, &lastProperty, &commonGetter, &globalShape);
|
||||
if (!foundProto)
|
||||
return true;
|
||||
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
MDefinition *guard = testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
|
||||
foundProto, lastProperty);
|
||||
foundProto, lastProperty, globalShape);
|
||||
if (!guard)
|
||||
return true;
|
||||
|
||||
|
@ -807,11 +807,12 @@ class IonBuilder
|
||||
MBasicBlock *bottom);
|
||||
|
||||
bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
bool isGetter, JSObject *foundProto);
|
||||
bool isGetter, JSObject *foundProto, bool *guardGlobal);
|
||||
void freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
JSObject *foundProto);
|
||||
JSObject *foundProto, bool allowEmptyTypesForGlobal = false);
|
||||
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,
|
||||
JSFunction *func, JSJitInfo::OpType opType);
|
||||
|
||||
|
@ -1446,11 +1446,14 @@ HeapTypeSetKey::knownMIRType(CompilerConstraintList *constraints)
|
||||
}
|
||||
|
||||
bool
|
||||
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints)
|
||||
HeapTypeSetKey::isOwnProperty(CompilerConstraintList *constraints,
|
||||
bool allowEmptyTypesForGlobal/* = false*/)
|
||||
{
|
||||
if (maybeTypes() && (!maybeTypes()->empty() || maybeTypes()->nonDataProperty()))
|
||||
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))
|
||||
return true;
|
||||
}
|
||||
|
@ -1566,7 +1566,7 @@ class HeapTypeSetKey
|
||||
jit::MIRType knownMIRType(CompilerConstraintList *constraints);
|
||||
bool nonData(CompilerConstraintList *constraints);
|
||||
bool nonWritable(CompilerConstraintList *constraints);
|
||||
bool isOwnProperty(CompilerConstraintList *constraints);
|
||||
bool isOwnProperty(CompilerConstraintList *constraints, bool allowEmptyTypesForGlobal = false);
|
||||
bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other);
|
||||
JSObject *singleton(CompilerConstraintList *constraints);
|
||||
bool needsBarrier(CompilerConstraintList *constraints);
|
||||
|
Loading…
Reference in New Issue
Block a user