Bug 861439 - Add type barriers when reading from undefined properties of singleton objects.

This commit is contained in:
Brian Hackett 2013-04-15 05:16:23 -06:00
parent 433f02381c
commit dd96bb8cec
3 changed files with 56 additions and 24 deletions

View File

@ -5636,15 +5636,11 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
// or non-writable.
return jsop_getname(name);
}
if (!propertyTypes->hasPropagatedProperty())
globalType->getFromPrototypes(cx, id, propertyTypes);
// If the property is permanent, a shape guard isn't necessary.
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
bool barrier = !propertyTypes || !propertyTypes->isSubset(types);
if (!barrier)
propertyTypes->addFreeze(cx);
bool barrier = propertyReadNeedsTypeBarrier(globalType, name, types);
// If the property is permanent, a shape guard isn't necessary.
JSObject *singleton = types->getSingleton();
@ -5945,15 +5941,49 @@ IonBuilder::elementAccessHasExtraIndexedProperty(MDefinition *obj)
}
bool
IonBuilder::propertyReadNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
IonBuilder::propertyReadNeedsTypeBarrier(types::TypeObject *object, PropertyName *name,
types::StackTypeSet *observed)
{
// If any value being read from has types for the property which haven't
// If the object being read from has types for the property which haven't
// been observed at this access site, the read could produce a new type and
// a barrier is needed. Note that this only covers reads from properties
// which are accounted for by type information, i.e. native data properties
// and elements.
if (object->unknownProperties())
return true;
jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return true;
if (!property->hasPropagatedProperty())
object->getFromPrototypes(cx, id, property);
if (!TypeSetIncludes(observed, MIRType_Value, property))
return true;
// Type information for global objects does not reflect the initial
// 'undefined' value of variables declared with 'var'. Until the variable
// is assigned a value other than undefined, a barrier is required.
if (property->empty() && name && object->singleton) {
Shape *shape = object->singleton->nativeLookup(cx, name);
if (shape && shape->hasDefaultGetter()) {
JS_ASSERT(object->singleton->nativeGetSlot(shape->slot()).isUndefined());
return true;
}
}
property->addFreeze(cx);
return false;
}
bool
IonBuilder::propertyReadNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed)
{
if (observed->unknown())
return false;
@ -5961,8 +5991,6 @@ IonBuilder::propertyReadNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
if (!types || types->unknownObject())
return true;
jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObject *object = types->getTypeObject(i);
if (!object) {
@ -5974,20 +6002,8 @@ IonBuilder::propertyReadNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
return true;
}
if (object->unknownProperties())
if (propertyReadNeedsTypeBarrier(object, name, observed))
return true;
types::HeapTypeSet *property = object->getProperty(cx, id, false);
if (!property)
return true;
if (!property->hasPropagatedProperty())
object->getFromPrototypes(cx, id, property);
if (!TypeSetIncludes(observed, MIRType_Value, property))
return true;
property->addFreeze(cx);
}
return false;

View File

@ -418,6 +418,8 @@ class IonBuilder : public MIRGenerator
bool elementAccessIsPacked(MDefinition *obj);
bool elementAccessHasExtraIndexedProperty(MDefinition *obj);
MIRType denseNativeElementType(MDefinition *obj);
bool propertyReadNeedsTypeBarrier(types::TypeObject *object, PropertyName *name,
types::StackTypeSet *observed);
bool propertyReadNeedsTypeBarrier(MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed);
bool propertyReadIsIdempotent(MDefinition *obj, PropertyName *name);

View File

@ -0,0 +1,14 @@
try {
x = evalcx('')
toSource = (function() {
x = (new WeakMap).get(function() {})
})
valueOf = (function() {
schedulegc(x)
})
this + ''
for (v of this) {}
} catch (e) {}
gc()
this + 1