Bug 1180990 - Add checks for nursery objects when building MIR. r=jandem

CLOSED TREE
This commit is contained in:
Brian Hackett 2015-07-14 17:11:46 -04:00
parent 26efda25bf
commit 42223df470
6 changed files with 74 additions and 85 deletions

View File

@ -8154,7 +8154,7 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index)
// Don't generate a fast path if there have been bounds check failures
// and this access might be on a sparse property.
if (ElementAccessHasExtraIndexedProperty(constraints(), obj) && failedBoundsCheck_) {
if (ElementAccessHasExtraIndexedProperty(this, obj) && failedBoundsCheck_) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return true;
}
@ -8188,7 +8188,7 @@ IonBuilder::getStaticTypedArrayObject(MDefinition* obj, MDefinition* index)
return nullptr;
}
if (ElementAccessHasExtraIndexedProperty(constraints(), obj)) {
if (ElementAccessHasExtraIndexedProperty(this, obj)) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return nullptr;
}
@ -8536,7 +8536,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
// cannot hit another indexed property on the object or its prototypes.
bool readOutOfBounds =
types->hasType(TypeSet::UndefinedType()) &&
!ElementAccessHasExtraIndexedProperty(constraints(), obj);
!ElementAccessHasExtraIndexedProperty(this, obj);
MIRType knownType = MIRType_Value;
if (unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier)
@ -9097,7 +9097,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
// Don't generate a fast path if there have been bounds check failures
// and this access might be on a sparse property.
if (ElementAccessHasExtraIndexedProperty(constraints(), object) && failedBoundsCheck_) {
if (ElementAccessHasExtraIndexedProperty(this, object) && failedBoundsCheck_) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return true;
}
@ -9163,7 +9163,7 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
// from them. If TI can guard that there are no indexed properties on the prototype
// chain, we know that we anen't missing any setters by overwriting the hole with
// another value.
bool guardHoles = ElementAccessHasExtraIndexedProperty(constraints(), object);
bool guardHoles = ElementAccessHasExtraIndexedProperty(this, object);
// Make sure the object being written to doesn't have copy on write elements.
const Class* clasp = object->resultTypeSet() ? object->resultTypeSet()->getKnownClass(constraints()) : nullptr;
@ -9199,7 +9199,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
// Writes which are on holes in the object do not have to bail out if they
// cannot hit another indexed property on the object or its prototypes.
bool writeOutOfBounds = !ElementAccessHasExtraIndexedProperty(constraints(), obj);
bool writeOutOfBounds = !ElementAccessHasExtraIndexedProperty(this, obj);
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
@ -11068,7 +11068,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
// reflect such possible values.
if (barrier != BarrierKind::TypeSet) {
BarrierKind protoBarrier =
PropertyReadOnPrototypeNeedsTypeBarrier(this, constraints(), obj, name, types);
PropertyReadOnPrototypeNeedsTypeBarrier(this, obj, name, types);
if (protoBarrier != BarrierKind::NoBarrier) {
MOZ_ASSERT(barrier <= protoBarrier);
barrier = protoBarrier;
@ -12373,7 +12373,7 @@ IonBuilder::jsop_in()
break;
}
if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
if (ElementAccessHasExtraIndexedProperty(this, obj))
break;
return jsop_in_dense(obj, id, unboxedType);

View File

@ -649,7 +649,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
return InliningStatus_NotInlined;
}
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -791,7 +791,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -890,7 +890,7 @@ IonBuilder::inlineArrayConcat(CallInfo& callInfo)
}
// Watch out for indexed properties on the prototype.
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -1006,7 +1006,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
}
// Watch out for indexed properties on the prototype.
if (ArrayPrototypeHasIndexedProperty(constraints(), script())) {
if (ArrayPrototypeHasIndexedProperty(this, script())) {
trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
return InliningStatus_NotInlined;
}
@ -2127,7 +2127,7 @@ IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
MDefinition* id = callInfo.getArg(1);
MDefinition* value = callInfo.getArg(2);
if (ElementAccessHasExtraIndexedProperty(constraints(), obj))
if (ElementAccessHasExtraIndexedProperty(this, obj))
return InliningStatus_NotInlined;
// setElemTryDense will push the value as the result of the define instead

View File

@ -4884,15 +4884,14 @@ jit::ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefin
}
bool
jit::ElementAccessHasExtraIndexedProperty(CompilerConstraintList* constraints,
MDefinition* obj)
jit::ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj)
{
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->hasObjectFlags(constraints, OBJECT_FLAG_LENGTH_OVERFLOW))
if (!types || types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_LENGTH_OVERFLOW))
return true;
return TypeCanHaveExtraIndexedProperties(constraints, types);
return TypeCanHaveExtraIndexedProperties(builder, types);
}
MIRType
@ -5056,7 +5055,6 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
BarrierKind
jit::PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
CompilerConstraintList* constraints,
MDefinition* obj, PropertyName* name,
TemporaryTypeSet* observed)
{
@ -5074,13 +5072,14 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
if (!key)
continue;
while (true) {
if (!key->hasStableClassAndProto(constraints))
if (!key->hasStableClassAndProto(builder->constraints()))
return BarrierKind::TypeSet;
if (!key->proto().isObject())
break;
JSObject* proto = builder->checkNurseryObject(key->proto().toObject());
key = TypeSet::ObjectKey::get(proto);
BarrierKind kind = PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
BarrierKind kind = PropertyReadNeedsTypeBarrier(builder->constraints(),
key, name, observed);
if (kind == BarrierKind::TypeSet)
return BarrierKind::TypeSet;
@ -5164,6 +5163,58 @@ jit::AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
}
}
static bool
PrototypeHasIndexedProperty(IonBuilder* builder, JSObject* obj)
{
do {
TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(builder->checkNurseryObject(obj));
if (ClassCanHaveExtraProperties(key->clasp()))
return true;
if (key->unknownProperties())
return true;
HeapTypeSetKey index = key->property(JSID_VOID);
if (index.nonData(builder->constraints()) || index.isOwnProperty(builder->constraints()))
return true;
obj = obj->getProto();
} while (obj);
return false;
}
// Whether Array.prototype, or an object on its proto chain, has an indexed property.
bool
jit::ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script)
{
if (JSObject* proto = script->global().maybeGetArrayPrototype())
return PrototypeHasIndexedProperty(builder, proto);
return true;
}
// Whether obj or any of its prototypes have an indexed property.
bool
jit::TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types)
{
const Class* clasp = types->getKnownClass(builder->constraints());
// Note: typed arrays have indexed properties not accounted for by type
// information, though these are all in bounds and will be accounted for
// by JIT paths.
if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsAnyTypedArrayClass(clasp)))
return true;
if (types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_SPARSE_INDEXES))
return true;
JSObject* proto;
if (!types->getCommonPrototype(builder->constraints(), &proto))
return true;
if (!proto)
return false;
return PrototypeHasIndexedProperty(builder, proto);
}
static bool
PropertyTypeIncludes(TempAllocator& alloc, HeapTypeSetKey property,
MDefinition* value, MIRType implicitType)

View File

@ -13719,8 +13719,7 @@ bool ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
Scalar::Type* arrayType);
bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
bool ElementAccessHasExtraIndexedProperty(CompilerConstraintList* constraints,
MDefinition* obj);
bool ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
CompilerConstraintList* constraints,
@ -13731,7 +13730,6 @@ BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
MDefinition* obj, PropertyName* name,
TemporaryTypeSet* observed);
BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
CompilerConstraintList* constraints,
MDefinition* obj, PropertyName* name,
TemporaryTypeSet* observed);
bool PropertyReadIsIdempotent(CompilerConstraintList* constraints,
@ -13745,6 +13743,8 @@ bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
MBasicBlock* current, MDefinition** pobj,
PropertyName* name, MDefinition** pvalue,
bool canModify, MIRType implicitType = MIRType_None);
bool ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script);
bool TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types);
} // namespace jit
} // namespace js

View File

@ -2449,57 +2449,6 @@ js::ClassCanHaveExtraProperties(const Class* clasp)
|| IsAnyTypedArrayClass(clasp);
}
static bool
PrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSObject* obj)
{
do {
TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(obj);
if (ClassCanHaveExtraProperties(key->clasp()))
return true;
if (key->unknownProperties())
return true;
HeapTypeSetKey index = key->property(JSID_VOID);
if (index.nonData(constraints) || index.isOwnProperty(constraints))
return true;
obj = obj->getProto();
} while (obj);
return false;
}
bool
js::ArrayPrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSScript* script)
{
if (JSObject* proto = script->global().maybeGetArrayPrototype())
return PrototypeHasIndexedProperty(constraints, proto);
return true;
}
bool
js::TypeCanHaveExtraIndexedProperties(CompilerConstraintList* constraints,
TemporaryTypeSet* types)
{
const Class* clasp = types->getKnownClass(constraints);
// Note: typed arrays have indexed properties not accounted for by type
// information, though these are all in bounds and will be accounted for
// by JIT paths.
if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsAnyTypedArrayClass(clasp)))
return true;
if (types->hasObjectFlags(constraints, OBJECT_FLAG_SPARSE_INDEXES))
return true;
JSObject* proto;
if (!types->getCommonPrototype(constraints, &proto))
return true;
if (!proto)
return false;
return PrototypeHasIndexedProperty(constraints, proto);
}
void
TypeZone::processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles)
{

View File

@ -974,17 +974,6 @@ inline bool isInlinableCall(jsbytecode* pc);
bool
ClassCanHaveExtraProperties(const Class* clasp);
/*
* Whether Array.prototype, or an object on its proto chain, has an
* indexed property.
*/
bool
ArrayPrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSScript* script);
/* Whether obj or any of its prototypes have an indexed property. */
bool
TypeCanHaveExtraIndexedProperties(CompilerConstraintList* constraints, TemporaryTypeSet* types);
/* Persistent type information for a script, retained across GCs. */
class TypeScript
{