mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 21:55:31 +00:00
Bug 793212 - Refactor IonBuilder::TestCommonPropFunc. r=efaust
This commit is contained in:
parent
38d7cba888
commit
5eeca09525
@ -7636,24 +7636,81 @@ IonBuilder::jsop_not()
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
TestClassHasAccessorHook(Class *clasp, bool isGetter)
|
||||
{
|
||||
if (isGetter && clasp->ops.getGeneric)
|
||||
return true;
|
||||
if (!isGetter && clasp->ops.setGeneric)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id,
|
||||
JSFunction **funcp, bool isGetter, bool *isDOM,
|
||||
MDefinition **guardOut)
|
||||
TestTypeHasOwnProperty(JSContext *cx, types::TypeObject *typeObj, HandleId id, bool &cont)
|
||||
{
|
||||
JSObject *found = NULL;
|
||||
JSObject *foundProto = NULL;
|
||||
cont = true;
|
||||
types::HeapTypeSet *propSet = typeObj->getProperty(cx, types::IdToTypeId(id), false);
|
||||
if (!propSet)
|
||||
return false;
|
||||
if (propSet->ownProperty(false))
|
||||
cont = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
*funcp = NULL;
|
||||
*isDOM = false;
|
||||
inline bool
|
||||
TestCommonAccessorProtoChain(JSContext *cx, HandleId id, bool isGetter, JSObject *foundProto,
|
||||
JSObject *obj, bool &cont)
|
||||
{
|
||||
cont = false;
|
||||
RootedObject curObj(cx, obj);
|
||||
JSObject *stopAt = foundProto->getProto();
|
||||
while (curObj != stopAt) {
|
||||
// Don't optimize if we have a hook that would have to be called.
|
||||
if (TestClassHasAccessorHook(curObj->getClass(), isGetter))
|
||||
return true;
|
||||
|
||||
// No sense looking if we don't know what's going on.
|
||||
if (!types || types->unknownObject())
|
||||
return true;
|
||||
// Check here to make sure that everyone has Type Objects with known
|
||||
// properties between them and the proto we found the accessor on. We
|
||||
// need those to add freezes safely. NOTE: We do not do this above, as
|
||||
// we may be able to freeze all the types up to where we found the
|
||||
// property, even if there are unknown types higher in the prototype
|
||||
// chain.
|
||||
if (curObj != foundProto) {
|
||||
types::TypeObject *typeObj = curObj->getType(cx);
|
||||
if (!typeObj)
|
||||
return false;
|
||||
|
||||
// Iterate down all the types to see if they all have the same getter or
|
||||
// setter.
|
||||
if (typeObj->unknownProperties())
|
||||
return true;
|
||||
|
||||
// Check here to make sure that nobody on the prototype chain is
|
||||
// marked as having the property as an "own property". This can
|
||||
// happen in cases of |delete| having been used, or cases with
|
||||
// watched objects. If TI ever decides to be more accurate about
|
||||
// |delete| handling, this should go back to curObj->watched().
|
||||
|
||||
// Even though we are not directly accessing the properties on the whole
|
||||
// prototype chain, we need to fault in the sets anyway, as we need
|
||||
// to freeze on them.
|
||||
bool lcont;
|
||||
if (!TestTypeHasOwnProperty(cx, typeObj, id, lcont))
|
||||
return false;
|
||||
if (!lcont)
|
||||
return true;
|
||||
}
|
||||
|
||||
curObj = curObj->getProto();
|
||||
}
|
||||
cont = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
SearchCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id, bool isGetter,
|
||||
JSObject *&found, JSObject *&foundProto, bool &cont)
|
||||
{
|
||||
cont = false;
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
RootedObject curObj(cx, types->getSingleObject(i));
|
||||
|
||||
@ -7669,17 +7726,15 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
|
||||
|
||||
// If the class of the object has a hook, we can't
|
||||
// inline, as we would need to call the hook.
|
||||
if (isGetter && typeObj->clasp->ops.getGeneric)
|
||||
return true;
|
||||
if (!isGetter && typeObj->clasp->ops.setGeneric)
|
||||
if (TestClassHasAccessorHook(typeObj->clasp, isGetter))
|
||||
return true;
|
||||
|
||||
// If the type has an own property, we can't be sure we don't shadow
|
||||
// the chain.
|
||||
types::HeapTypeSet *propSet = typeObj->getProperty(cx, types::IdToTypeId(id), false);
|
||||
if (!propSet)
|
||||
bool lcont;
|
||||
if (!TestTypeHasOwnProperty(cx, typeObj, id, lcont))
|
||||
return false;
|
||||
if (propSet->ownProperty(false))
|
||||
if (!lcont)
|
||||
return true;
|
||||
|
||||
// Otherwise try using the prototype.
|
||||
@ -7735,71 +7790,19 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
|
||||
else if (foundProto != proto)
|
||||
return true;
|
||||
|
||||
JSObject *stopAt = foundProto->getProto();
|
||||
while (curObj != stopAt) {
|
||||
// Don't optimize if we have a hook that would have to be called.
|
||||
if (isGetter && curObj->getClass()->ops.getGeneric)
|
||||
return true;
|
||||
if (!isGetter && curObj->getClass()->ops.setGeneric)
|
||||
return true;
|
||||
|
||||
// Check here to make sure that everyone has Type Objects with known
|
||||
// properties between them and the proto we found the accessor on. We
|
||||
// need those to add freezes safely. NOTE: We do not do this above, as
|
||||
// we may be able to freeze all the types up to where we found the
|
||||
// property, even if there are unknown types higher in the prototype
|
||||
// chain.
|
||||
if (curObj != foundProto) {
|
||||
types::TypeObject *typeObj = curObj->getType(cx);
|
||||
if (!typeObj)
|
||||
return false;
|
||||
|
||||
if (typeObj->unknownProperties())
|
||||
return true;
|
||||
|
||||
// Check here to make sure that nobody on the prototype chain is
|
||||
// marked as having the property as an "own property". This can
|
||||
// happen in cases of |delete| having been used, or cases with
|
||||
// watched objects. If TI ever decides to be more accurate about
|
||||
// |delete| handling, this should go back to curObj->watched().
|
||||
|
||||
// Even though we are not directly accessing the properties on the whole
|
||||
// prototype chain, we need to fault in the sets anyway, as we need
|
||||
// to freeze on them.
|
||||
types::HeapTypeSet *propSet =
|
||||
typeObj->getProperty(cx, types::IdToTypeId(id), false);
|
||||
if (!propSet)
|
||||
return false;
|
||||
if (propSet->ownProperty(false))
|
||||
return true;
|
||||
}
|
||||
|
||||
curObj = curObj->getProto();
|
||||
}
|
||||
bool lcont;
|
||||
if (!TestCommonAccessorProtoChain(cx, id, isGetter, foundProto, curObj, lcont))
|
||||
return false;
|
||||
if (!lcont)
|
||||
return true;
|
||||
}
|
||||
cont = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// No need to add a freeze if we didn't find anything
|
||||
if (!found)
|
||||
return true;
|
||||
|
||||
JS_ASSERT(foundProto);
|
||||
|
||||
// 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.
|
||||
MInstruction *wrapper = MConstant::New(ObjectValue(*foundProto));
|
||||
current->add(wrapper);
|
||||
wrapper = addShapeGuard(wrapper, foundProto->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
// Pass the guard back so it can be an operand.
|
||||
if (isGetter) {
|
||||
JS_ASSERT(wrapper->isGuardShape());
|
||||
*guardOut = wrapper;
|
||||
}
|
||||
|
||||
// Now we have to freeze all the property typesets to ensure there isn't a
|
||||
// lower shadowing getter or setter installed in the future.
|
||||
inline bool
|
||||
FreezePropTypeSets(JSContext *cx, types::StackTypeSet *types, JSObject *foundProto, HandleId id)
|
||||
{
|
||||
types::TypeObject *curType;
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
curType = types->getTypeObject(i);
|
||||
@ -7839,6 +7842,56 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id,
|
||||
JSFunction **funcp, bool isGetter, bool *isDOM,
|
||||
MDefinition **guardOut)
|
||||
{
|
||||
JSObject *found = NULL;
|
||||
JSObject *foundProto = NULL;
|
||||
|
||||
*funcp = NULL;
|
||||
*isDOM = false;
|
||||
|
||||
// No sense looking if we don't know what's going on.
|
||||
if (!types || types->unknownObject())
|
||||
return true;
|
||||
|
||||
// Iterate down all the types to see if they all have the same getter or
|
||||
// setter.
|
||||
bool cont;
|
||||
if (!SearchCommonPropFunc(cx, types, id, isGetter, found, foundProto, cont))
|
||||
return false;
|
||||
if (!cont)
|
||||
return true;
|
||||
|
||||
// No need to add a freeze if we didn't find anything
|
||||
if (!found)
|
||||
return true;
|
||||
|
||||
JS_ASSERT(foundProto);
|
||||
|
||||
// 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.
|
||||
MInstruction *wrapper = MConstant::New(ObjectValue(*foundProto));
|
||||
current->add(wrapper);
|
||||
wrapper = addShapeGuard(wrapper, foundProto->lastProperty(), Bailout_ShapeGuard);
|
||||
|
||||
// Pass the guard back so it can be an operand.
|
||||
if (guardOut) {
|
||||
JS_ASSERT(wrapper->isGuardShape());
|
||||
*guardOut = wrapper;
|
||||
}
|
||||
|
||||
// Now we have to freeze all the property typesets to ensure there isn't a
|
||||
// lower shadowing getter or setter installed in the future.
|
||||
if (!FreezePropTypeSets(cx, types, foundProto, id))
|
||||
return false;
|
||||
|
||||
*funcp = &found->as<JSFunction>();
|
||||
*isDOM = types->isDOMClass();
|
||||
|
Loading…
Reference in New Issue
Block a user