Bug 920689 - Only include types for 'own' properties in heap type sets, r=jandem.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 27 Sep 2013 11:29:35 -0600
changeset 149027 3f8e57e07eee72c5ec94b53c7ca4f955c95657e1
parent 149026 19af7baaf26e984eceec910174b968386bbd7ed2
child 149028 3ed8d1a1b5942d8bf44fa9c6f9fed537fc2f670e
push id34413
push userbhackett@mozilla.com
push dateFri, 27 Sep 2013 17:29:45 +0000
treeherdermozilla-inbound@3f8e57e07eee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs920689
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 920689 - Only include types for 'own' properties in heap type sets, r=jandem.
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jsarray.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsobj.cpp
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4639,17 +4639,17 @@ IonBuilder::getSingletonPrototype(JSFunc
 {
     if (!target || !target->hasSingletonType())
         return NULL;
     types::TypeObject *targetType = target->getType(cx);
     if (targetType->unknownProperties())
         return NULL;
 
     jsid protoid = NameToId(cx->names().classPrototype);
-    types::HeapTypeSet *protoTypes = targetType->getProperty(cx, protoid, false);
+    types::HeapTypeSet *protoTypes = targetType->getProperty(cx, protoid);
     if (!protoTypes)
         return NULL;
 
     return protoTypes->getSingleton(cx);
 }
 
 MDefinition *
 IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
@@ -5495,17 +5495,17 @@ IonBuilder::jsop_initelem_array()
     // intializer, and that arrays are marked as non-packed when writing holes
     // to them during initialization.
     bool needStub = false;
     types::TypeObject *initializer = obj->resultTypeSet()->getTypeObject(0);
     if (value->isConstant() && value->toConstant()->value().isMagic(JS_ELEMENTS_HOLE)) {
         if (!(initializer->flags & types::OBJECT_FLAG_NON_PACKED))
             needStub = true;
     } else if (!initializer->unknownProperties()) {
-        types::HeapTypeSet *elemTypes = initializer->getProperty(cx, JSID_VOID, false);
+        types::HeapTypeSet *elemTypes = initializer->getProperty(cx, JSID_VOID);
         if (!elemTypes)
             return false;
         if (!TypeSetIncludes(elemTypes, value->type(), value->resultTypeSet())) {
             elemTypes->addFreeze(cx);
             needStub = true;
         }
     }
 
@@ -6046,28 +6046,41 @@ TestSingletonProperty(JSContext *cx, JSO
 
     if (!shape->hasDefaultGetter())
         return true;
     if (!shape->hasSlot())
         return true;
     if (holder->getSlot(shape->slot()).isUndefined())
         return true;
 
-    types::TypeObject *objType = obj->getType(cx);
-    if (!objType)
-        return false;
-    if (objType->unknownProperties())
-        return true;
-
-    types::HeapTypeSet *property = objType->getProperty(cx, id, false);
-    if (!property)
-        return false;
-    objType->getFromPrototypes(cx, id, property);
-    if (property->getSingleton(cx) != singleton)
-        return true;
+    // Ensure the property does not appear anywhere on the prototype chain
+    // before |holder|, and that |holder| only has the result object for its
+    // property.
+    while (true) {
+        types::TypeObject *objType = obj->getType(cx);
+        if (!objType)
+            return false;
+        if (objType->unknownProperties())
+            return true;
+
+        types::HeapTypeSet *property = objType->getProperty(cx, id);
+        if (!property)
+            return false;
+        if (obj != holder) {
+            if (!property->empty())
+                return true;
+            property->addFreeze(cx);
+        } else {
+            if (property->getSingleton(cx) != singleton)
+                return true;
+            break;
+        }
+
+        obj = obj->getProto();
+    }
 
     *isKnownConstant = true;
     return true;
 }
 
 static inline bool
 TestSingletonPropertyTypes(JSContext *cx, MDefinition *obj, JSObject *singleton,
                            JSObject *globalObj, jsid id,
@@ -6140,22 +6153,22 @@ TestSingletonPropertyTypes(JSContext *cx
                     continue;
                 object = curObj->getType(cx);
                 if (!object)
                     return false;
             }
 
             if (object->unknownProperties())
                 return true;
-            types::HeapTypeSet *property = object->getProperty(cx, id, false);
+            types::HeapTypeSet *property = object->getProperty(cx, id);
             if (!property)
                 return false;
-            object->getFromPrototypes(cx, id, property);
-            if (property->getSingleton(cx) != singleton)
+            if (!property->empty())
                 return true;
+            property->addFreeze(cx);
 
             if (object->proto) {
                 // Test this type.
                 bool thoughtConstant = false;
                 if (!TestSingletonProperty(cx, object->proto, singleton, id, &thoughtConstant))
                     return false;
                 if (!thoughtConstant)
                     return true;
@@ -6282,21 +6295,21 @@ IonBuilder::getStaticName(JSObject *stat
         return true;
     }
 
     types::TypeObject *staticType = staticObject->getType(cx);
     if (!staticType)
         return false;
     types::HeapTypeSet *propertyTypes = NULL;
     if (!staticType->unknownProperties()) {
-        propertyTypes = staticType->getProperty(cx, id, false);
+        propertyTypes = staticType->getProperty(cx, id);
         if (!propertyTypes)
             return false;
     }
-    if (propertyTypes && propertyTypes->isOwnProperty(cx, staticType, true)) {
+    if (propertyTypes && propertyTypes->isConfiguredProperty(cx, staticType)) {
         // The property has been reconfigured as non-configurable, non-enumerable
         // or non-writable.
         *psucceeded = false;
         return true;
     }
 
     types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
     bool barrier;
@@ -6393,21 +6406,21 @@ IonBuilder::setStaticName(JSObject *stat
     if (!shape || !shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot())
         return jsop_setprop(name);
 
     types::TypeObject *staticType = staticObject->getType(cx);
     if (!staticType)
         return false;
     types::HeapTypeSet *propertyTypes = NULL;
     if (!staticType->unknownProperties()) {
-        propertyTypes = staticType->getProperty(cx, id, false);
+        propertyTypes = staticType->getProperty(cx, id);
         if (!propertyTypes)
             return false;
     }
-    if (!propertyTypes || propertyTypes->isOwnProperty(cx, staticType, true)) {
+    if (!propertyTypes || propertyTypes->isConfiguredProperty(cx, staticType)) {
         // The property has been reconfigured as non-configurable, non-enumerable
         // or non-writable.
         return jsop_setprop(name);
     }
     if (!TypeSetIncludes(propertyTypes, value->type(), value->resultTypeSet()))
         return jsop_setprop(name);
 
     current->pop();
@@ -6424,25 +6437,18 @@ IonBuilder::setStaticName(JSObject *stat
 
     if (NeedsPostBarrier(info(), value))
         current->add(MPostWriteBarrier::New(obj, value));
 
     // If the property has a known type, we may be able to optimize typed stores by not
     // storing the type tag. This only works if the property does not have its initial
     // |undefined| value; if |undefined| is assigned at a later point, it will be added
     // to the type set.
-    //
-    // We also need to make sure the typeset reflects the inherited types from
-    // the prototype by calling getFromPrototype. Otherwise we may specialize
-    // on a typeset that changes before compilation ends, which would mean the
-    // current script wouldn't be recompiled even when our assumption here is
-    // made false.
     MIRType slotType = MIRType_None;
     if (propertyTypes && !staticObject->getSlot(shape->slot()).isUndefined()) {
-        staticType->getFromPrototypes(cx, id, propertyTypes);
         JSValueType knownType = propertyTypes->getKnownTypeTag(cx);
         if (knownType != JSVAL_TYPE_UNKNOWN)
             slotType = MIRTypeFromValueType(knownType);
     }
 
     bool needsBarrier = !propertyTypes || propertyTypes->needsBarrier(cx);
     return storeSlot(obj, shape, value, needsBarrier, slotType);
 }
@@ -7680,20 +7686,20 @@ GetDefiniteSlot(JSContext *cx, types::Te
     types::TypeObject *type = types->getTypeObject(0);
     if (!type || type->unknownProperties())
         return NULL;
 
     jsid id = AtomToId(atom);
     if (id != types::IdToTypeId(id))
         return NULL;
 
-    types::HeapTypeSet *propertyTypes = type->getProperty(cx, id, false);
+    types::HeapTypeSet *propertyTypes = type->getProperty(cx, id);
     if (!propertyTypes ||
         !propertyTypes->definiteProperty() ||
-        propertyTypes->isOwnProperty(cx, type, true))
+        propertyTypes->isConfiguredProperty(cx, type))
     {
         return NULL;
     }
 
     return propertyTypes;
 }
 
 bool
@@ -7725,21 +7731,22 @@ TestClassHasAccessorHook(const Class *cl
         return true;
     return false;
 }
 
 inline bool
 TestTypeHasOwnProperty(JSContext *cx, types::TypeObject *typeObj, jsid id, bool &cont)
 {
     cont = true;
-    types::HeapTypeSet *propSet = typeObj->getProperty(cx, types::IdToTypeId(id), false);
+    types::HeapTypeSet *propSet = typeObj->getProperty(cx, types::IdToTypeId(id));
     if (!propSet)
         return false;
-    if (propSet->ownProperty(false))
+    if (!propSet->empty())
         cont = false;
+    // Note: Callers must explicitly freeze the property type set later on if optimizing.
     return true;
 }
 
 inline bool
 TestCommonAccessorProtoChain(JSContext *cx, jsid id, bool isGetter, JSObject *foundProto,
                              JSObject *obj, bool &cont)
 {
     cont = false;
@@ -7900,23 +7907,21 @@ FreezePropTypeSets(JSContext *cx, types:
 
         // If we found a Singleton object's own-property, there's nothing to
         // freeze.
         if (obj != foundProto) {
             // Walk the prototype chain. Everyone has to have the property, since we
             // just checked, so propSet cannot be NULL.
             jsid typeId = types::IdToTypeId(id);
             while (true) {
-                types::HeapTypeSet *propSet = curType->getProperty(cx, typeId, false);
+                types::HeapTypeSet *propSet = curType->getProperty(cx, typeId);
                 // This assert is now assured, since we have faulted them in
                 // above.
-                JS_ASSERT(propSet);
-                // Asking, freeze by asking.
-                DebugOnly<bool> isOwn = propSet->isOwnProperty(cx, curType, false);
-                JS_ASSERT(!isOwn);
+                JS_ASSERT(propSet && propSet->empty());
+                propSet->addFreeze(cx);
                 // Don't mark the proto. It will be held down by the shape
                 // guard. This allows us tp use properties found on prototypes
                 // with properties unknown to TI.
                 if (curType->proto == foundProto)
                     break;
                 curType = curType->proto->getType(cx);
                 if (!curType)
                     return false;
@@ -8011,47 +8016,59 @@ IonBuilder::annotateGetPropertyCache(JSC
 
     // Ensure that the relevant property typeset for each type object is
     // is a single-object typeset containing a JSFunction
     for (unsigned int i = 0; i < objCount; i++) {
         types::TypeObject *typeObj = objTypes->getTypeObject(i);
         if (!typeObj || typeObj->unknownProperties() || !typeObj->proto)
             continue;
 
-        types::HeapTypeSet *ownTypes = typeObj->getProperty(cx, id, false);
+        types::HeapTypeSet *ownTypes = typeObj->getProperty(cx, id);
         if (!ownTypes)
             continue;
 
-        if (ownTypes->isOwnProperty(cx, typeObj, false))
+        if (!ownTypes->empty())
             continue;
-
-        RootedObject proto(cx, typeObj->proto);
-        types::TypeObject *protoType = proto->getType(cx);
-        if (!protoType)
-            return false;
-        if (protoType->unknownProperties())
-            continue;
-
-        types::HeapTypeSet *protoTypes = protoType->getProperty(cx, id, false);
-        if (!protoTypes)
-            return false;
-
-        JSObject *obj = protoTypes->getSingleton(cx);
-        if (!obj || !obj->is<JSFunction>())
+        ownTypes->addFreeze(cx);
+
+        JSObject *singleton = NULL;
+        JSObject *proto = typeObj->proto;
+        while (true) {
+            types::TypeObject *protoType = proto->getType(cx);
+            if (!protoType)
+                return false;
+            if (!protoType->unknownProperties()) {
+                types::HeapTypeSet *protoTypes = protoType->getProperty(cx, id);
+                if (!protoTypes)
+                    return false;
+
+                singleton = protoTypes->getSingleton(cx);
+                if (singleton) {
+                    if (singleton->is<JSFunction>())
+                        break;
+                    singleton = NULL;
+                }
+            }
+            TaggedProto taggedProto = proto->getTaggedProto();
+            if (!taggedProto.isObject())
+                break;
+            proto = taggedProto.toObject();
+        }
+        if (!singleton)
             continue;
 
         bool knownConstant = false;
-        if (!TestSingletonProperty(cx, proto, obj, id, &knownConstant))
+        if (!TestSingletonProperty(cx, proto, singleton, id, &knownConstant))
             return false;
 
         // Don't add cases corresponding to non-observed pushes
-        if (!pushedTypes->hasType(types::Type::ObjectType(obj)))
+        if (!pushedTypes->hasType(types::Type::ObjectType(singleton)))
             continue;
 
-        if (!inlinePropTable->addEntry(typeObj, &obj->as<JSFunction>()))
+        if (!inlinePropTable->addEntry(typeObj, &singleton->as<JSFunction>()))
             return false;
     }
 
     if (inlinePropTable->numEntries() == 0) {
         getPropCache->clearInlinePropertyTable();
         return true;
     }
 
@@ -8186,17 +8203,17 @@ IonBuilder::jsop_getprop(PropertyName *n
     if (!getPropTryTypedObject(&emitted, id, types) || emitted)
         return emitted;
 
     // Try to emit loads from definite slots.
     if (!getPropTryDefiniteSlot(&emitted, name, barrier, types) || emitted)
         return emitted;
 
     // Try to inline a common property getter, or make a call.
-    if (!getPropTryCommonGetter(&emitted, id, barrier, types) || emitted)
+    if (!getPropTryCommonGetter(&emitted, id, types) || emitted)
         return emitted;
 
     // Try to emit a monomorphic/polymorphic access based on baseline caches.
     if (!getPropTryInlineAccess(&emitted, name, id, barrier, types) || emitted)
         return emitted;
 
     // Try to emit a polymorphic cache.
     if (!getPropTryCache(&emitted, name, id, barrier, types) || emitted)
@@ -8409,18 +8426,17 @@ IonBuilder::getPropTryDefiniteSlot(bool 
     if (!pushTypeBarrier(fixed, types, barrier))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
-IonBuilder::getPropTryCommonGetter(bool *emitted, jsid id,
-                                   bool barrier, types::TemporaryTypeSet *types)
+IonBuilder::getPropTryCommonGetter(bool *emitted, jsid id, types::TemporaryTypeSet *types)
 {
     JS_ASSERT(*emitted == false);
     JSFunction *commonGetter;
     bool isDOM;
     MDefinition *guard;
 
     types::TemporaryTypeSet *objTypes = current->peek(-1)->resultTypeSet();
 
@@ -8434,18 +8450,17 @@ IonBuilder::getPropTryCommonGetter(bool 
     if (isDOM && TestShouldDOMCall(cx, objTypes, commonGetter, JSJitInfo::Getter)) {
         const JSJitInfo *jitinfo = commonGetter->jitInfo();
         MGetDOMProperty *get = MGetDOMProperty::New(jitinfo, obj, guard);
         current->add(get);
         current->push(get);
 
         if (get->isEffectful() && !resumeAfter(get))
             return false;
-        if (!DOMCallNeedsBarrier(jitinfo, types))
-            barrier = false;
+        bool barrier = DOMCallNeedsBarrier(jitinfo, types);
         if (!pushTypeBarrier(get, types, barrier))
             return false;
 
         *emitted = true;
         return true;
     }
 
     // Don't call the getter with a primitive value.
@@ -8570,19 +8585,17 @@ IonBuilder::getPropTryCache(bool *emitte
         types::TemporaryTypeSet *types = obj->resultTypeSet();
         if (!types || !types->objectOrSentinel())
             return true;
     }
 
     current->pop();
     MGetPropertyCache *load = MGetPropertyCache::New(obj, name);
 
-    // Try to mark the cache as idempotent. We only do this if JM is enabled
-    // (its ICs are used to mark property reads as likely non-idempotent) or
-    // if we are compiling eagerly (to improve test coverage).
+    // Try to mark the cache as idempotent.
     //
     // In parallel execution, idempotency of caches is ignored, since we
     // repeat the entire ForkJoin workload if we bail out. Note that it's
     // overly restrictive to mark everything as idempotent, because we can
     // treat non-idempotent caches in parallel as repeatable.
     if (obj->type() == MIRType_Object && !invalidatedIdempotentCache() &&
         info().executionMode() != ParallelExecution)
     {
@@ -8610,16 +8623,21 @@ IonBuilder::getPropTryCache(bool *emitte
         return false;
 
     if (accessGetter)
         barrier = true;
 
     if (needsToMonitorMissingProperties(types))
         barrier = true;
 
+    // Caches can read values from prototypes, so update the barrier to
+    // reflect such possible values.
+    if (!barrier && !PropertyReadOnPrototypeNeedsTypeBarrier(cx, obj, name, types, &barrier))
+        return false;
+
     MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
     if (barrier || IsNullOrUndefined(rvalType))
         rvalType = MIRType_Value;
     load->setResultType(rvalType);
 
     if (!pushTypeBarrier(load, types, barrier))
         return false;
 
@@ -9463,17 +9481,17 @@ IonBuilder::jsop_instanceof()
         if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
             break;
 
         types::TypeObject *rhsType = rhsObject->getType(cx);
         if (!rhsType || rhsType->unknownProperties())
             break;
 
         types::HeapTypeSet *protoTypes =
-            rhsType->getProperty(cx, NameToId(cx->names().classPrototype), false);
+            rhsType->getProperty(cx, NameToId(cx->names().classPrototype));
         JSObject *protoObject = protoTypes ? protoTypes->getSingleton(cx) : NULL;
         if (!protoObject)
             break;
 
         rhs->setFoldedUnchecked();
 
         MInstanceOf *ins = new MInstanceOf(obj, protoObject);
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -356,18 +356,17 @@ class IonBuilder : public MIRGenerator
     bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
                    MIRType slotType = MIRType_None);
 
     // jsop_getprop() helpers.
     bool getPropTryArgumentsLength(bool *emitted);
     bool getPropTryConstant(bool *emitted, jsid id, types::TemporaryTypeSet *types);
     bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
                                 bool barrier, types::TemporaryTypeSet *types);
-    bool getPropTryCommonGetter(bool *emitted, jsid id,
-                                bool barrier, types::TemporaryTypeSet *types);
+    bool getPropTryCommonGetter(bool *emitted, jsid id, types::TemporaryTypeSet *types);
     bool getPropTryInlineAccess(bool *emitted, PropertyName *name, jsid id,
                                 bool barrier, types::TemporaryTypeSet *types);
     bool getPropTryTypedObject(bool *emitted, jsid id,
                                types::TemporaryTypeSet *resultTypes);
     bool getPropTryScalarPropOfTypedObject(bool *emitted,
                                            int32_t fieldOffset,
                                            TypeRepresentationSet fieldTypeReprs,
                                            types::TemporaryTypeSet *resultTypes);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -213,17 +213,17 @@ IonBuilder::inlineArray(CallInfo &callIn
     if (callInfo.argc() >= 2) {
         initLength = callInfo.argc();
         allocating = MNewArray::NewArray_Allocating;
 
         types::TypeObject *type = types::TypeScript::InitObject(cx, script(), pc, JSProto_Array);
         if (!type)
             return InliningStatus_Error;
         if (!type->unknownProperties()) {
-            types::HeapTypeSet *elemTypes = type->getProperty(cx, JSID_VOID, false);
+            types::HeapTypeSet *elemTypes = type->getProperty(cx, JSID_VOID);
             if (!elemTypes)
                 return InliningStatus_Error;
 
             for (uint32_t i = 0; i < initLength; i++) {
                 MDefinition *value = callInfo.getArg(i);
                 if (!TypeSetIncludes(elemTypes, value->type(), value->resultTypeSet())) {
                     elemTypes->addFreeze(cx);
                     return InliningStatus_NotInlined;
@@ -480,17 +480,17 @@ IonBuilder::inlineArrayConcat(CallInfo &
         argTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED))
     {
         return InliningStatus_NotInlined;
     }
 
     // Constraints modeling this concat have not been generated by inference,
     // so check that type information already reflects possible side effects of
     // this call.
-    types::HeapTypeSet *thisElemTypes = thisType->getProperty(cx, JSID_VOID, false);
+    types::HeapTypeSet *thisElemTypes = thisType->getProperty(cx, JSID_VOID);
     if (!thisElemTypes)
         return InliningStatus_Error;
 
     types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet();
     if (!resTypes->hasType(types::Type::ObjectType(thisType)))
         return InliningStatus_NotInlined;
 
     for (unsigned i = 0; i < argTypes->getObjectCount(); i++) {
@@ -499,17 +499,17 @@ IonBuilder::inlineArrayConcat(CallInfo &
 
         types::TypeObject *argType = argTypes->getTypeObject(i);
         if (!argType)
             continue;
 
         if (argType->unknownProperties())
             return InliningStatus_NotInlined;
 
-        types::HeapTypeSet *elemTypes = argType->getProperty(cx, JSID_VOID, false);
+        types::HeapTypeSet *elemTypes = argType->getProperty(cx, JSID_VOID);
         if (!elemTypes)
             return InliningStatus_Error;
 
         if (!elemTypes->knownSubset(cx, thisElemTypes))
             return InliningStatus_NotInlined;
     }
 
     // Inline the call.
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -16,16 +16,17 @@
 #include "jit/BaselineInspector.h"
 #include "jit/IonBuilder.h"
 #include "jit/IonSpewer.h"
 #include "jit/MIRGraph.h"
 #include "jit/RangeAnalysis.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
+#include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DoublesAreIdentical;
 
 void
 MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op)
@@ -2725,17 +2726,17 @@ jit::DenseNativeElementType(JSContext *c
             return false;
 
         if (!object)
             continue;
 
         if (object->unknownProperties())
             return true;
 
-        types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID, false);
+        types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID);
         if (!elementTypes)
             return true;
 
         MIRType type = MIRTypeFromValueType(elementTypes->getKnownTypeTag(cx));
         if (type == MIRType_None)
             return true;
 
         if (elementType == MIRType_None)
@@ -2743,68 +2744,41 @@ jit::DenseNativeElementType(JSContext *c
         else if (elementType != type)
             return true;
     }
 
     *result = elementType;
     return true;
 }
 
-bool
-jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
-                                  types::StackTypeSet *observed, bool updateObserved, bool *result)
+static bool
+PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
+                             types::TypeSet *observed, bool *result)
 {
+    jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
+
     // 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.
     JS_ASSERT(result);
     *result = false;
 
     if (object->unknownProperties()) {
         *result = true;
         return true;
     }
 
-    jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
-
-    // If this access has never executed, try to add types to the observed set
-    // according to any property which exists on the object or its prototype.
-    if (updateObserved && observed->empty() && observed->noConstraints() && !JSID_IS_VOID(id)) {
-        JSObject *obj = object->singleton ? object->singleton : object->proto;
-
-        while (obj) {
-            if (!obj->isNative())
-                break;
-
-            Value v;
-            if (HasDataProperty(cx, obj, id, &v)) {
-                if (v.isUndefined())
-                    break;
-                observed->addType(cx, types::GetValueType(v));
-            }
-
-            obj = obj->getProto();
-        }
-    }
-
-    types::HeapTypeSet *property = object->getProperty(cx, id, false);
+    types::HeapTypeSet *property = object->getProperty(cx, id);
     if (!property) {
         *result = true;
         return true;
     }
 
-    // We need to consider possible types for the property both as an 'own'
-    // property on the object and as inherited from any prototype. Type sets
-    // for a property do not, however, reflect inherited types until a
-    // getFromPrototypes() call has been performed.
-    if (!property->hasPropagatedProperty())
-        object->getFromPrototypes(cx, id, property);
-
     if (!TypeSetIncludes(observed, MIRType_Value, property)) {
         *result = true;
         return true;
     }
 
     // Type information for singleton objects is not required to reflect the
     // initial 'undefined' value for native properties, in particular global
     // variables declared with 'var'. Until the property is assigned a value
@@ -2821,16 +2795,45 @@ jit::PropertyReadNeedsTypeBarrier(JSCont
     }
 
     property->addFreeze(cx);
     *result = false;
     return true;
 }
 
 bool
+jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
+                                  types::StackTypeSet *observed, bool updateObserved, bool *result)
+{
+    jsid id = name ? types::IdToTypeId(NameToId(name)) : JSID_VOID;
+
+    // If this access has never executed, try to add types to the observed set
+    // according to any property which exists on the object or its prototype.
+    if (updateObserved && observed->empty() && observed->noConstraints() && !JSID_IS_VOID(id)) {
+        JSObject *obj = object->singleton ? object->singleton : object->proto;
+
+        while (obj) {
+            if (!obj->isNative())
+                break;
+
+            Value v;
+            if (HasDataProperty(cx, obj, id, &v)) {
+                if (v.isUndefined())
+                    break;
+                observed->addType(cx, types::GetValueType(v));
+            }
+
+            obj = obj->getProto();
+        }
+    }
+
+    return PropertyReadNeedsTypeBarrier(cx, object, name, observed, result);
+}
+
+bool
 jit::PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
                                   types::StackTypeSet *observed, bool *result)
 {
     JS_ASSERT(result);
     *result = false;
 
     if (observed->unknown())
         return true;
@@ -2851,17 +2854,54 @@ jit::PropertyReadNeedsTypeBarrier(JSCont
             if (!PropertyReadNeedsTypeBarrier(cx, object, name, observed, updateObserved, result))
                 return false;
 
             if (*result)
                 return true;
         }
     }
 
+    return true;
+}
+
+bool
+jit::PropertyReadOnPrototypeNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
+                                             types::TemporaryTypeSet *observed, bool *result)
+{
+    JS_ASSERT(result);
     *result = false;
+
+    if (observed->unknown())
+        return true;
+
+    types::TypeSet *types = obj->resultTypeSet();
+    if (!types || types->unknownObject()) {
+        *result = true;
+        return true;
+    }
+
+    for (size_t i = 0; i < types->getObjectCount(); i++) {
+        types::TypeObject *object;
+        if (!types->getTypeOrSingleObject(cx, i, &object))
+            return false;
+
+        if (!object)
+            continue;
+        while (object->proto) {
+            object = object->proto->getType(cx);
+            if (!object)
+                return false;
+
+            if (!PropertyReadNeedsTypeBarrier(cx, object, name, observed, result))
+                return false;
+            if (*result)
+                return true;
+        }
+    }
+
     return true;
 }
 
 bool
 jit::PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name, bool *result)
 {
     JS_ASSERT(result);
     *result = false;
@@ -2878,18 +2918,18 @@ jit::PropertyReadIsIdempotent(JSContext 
         if (!types->getTypeOrSingleObject(cx, i, &object))
             return false;
 
         if (object) {
             if (object->unknownProperties())
                 return true;
 
             // Check if the property has been reconfigured or is a getter.
-            types::HeapTypeSet *property = object->getProperty(cx, id, false);
-            if (!property || property->isOwnProperty(cx, object, true))
+            types::HeapTypeSet *property = object->getProperty(cx, id);
+            if (!property || property->isConfiguredProperty(cx, object))
                 return true;
         }
     }
 
     *result = true;
     return true;
 }
 
@@ -2918,17 +2958,17 @@ jit::AddObjectsForPropertyRead(JSContext
         if (!object)
             continue;
 
         if (object->unknownProperties()) {
             observed->addType(cx, types::Type::AnyObjectType());
             return true;
         }
 
-        types::HeapTypeSet *property = object->getProperty(cx, id, false);
+        types::HeapTypeSet *property = object->getProperty(cx, id);
         if (property->unknownObject()) {
             observed->addType(cx, types::Type::AnyObjectType());
             return true;
         }
 
         for (size_t i = 0; i < property->getObjectCount(); i++) {
             if (types::TypeObject *object = property->getTypeObject(i))
                 observed->addType(cx, types::Type::ObjectType(object));
@@ -2959,17 +2999,17 @@ TryAddTypeBarrierForWrite(JSContext *cx,
             return false;
 
         if (!object)
             continue;
 
         if (object->unknownProperties())
             return false;
 
-        types::HeapTypeSet *property = object->getProperty(cx, id, false);
+        types::HeapTypeSet *property = object->getProperty(cx, id);
         if (!property)
             return false;
 
         if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
             return false;
 
         // This freeze is not required for correctness, but ensures that we
         // will recompile if the property types change and the barrier can
@@ -3069,17 +3109,17 @@ jit::PropertyWriteNeedsTypeBarrier(JSCon
         if (!object || object->unknownProperties())
             continue;
 
         // TI doesn't track TypedArray objects and should never insert a type
         // barrier for them.
         if (object->getTypedArrayType() < ScalarTypeRepresentation::TYPE_MAX)
             continue;
 
-        types::HeapTypeSet *property = object->getProperty(cx, id, false);
+        types::HeapTypeSet *property = object->getProperty(cx, id);
         if (!property) {
             success = false;
             break;
         }
         if (!TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
             // Either pobj or pvalue needs to be modified to filter out the
             // types which the value could have but are not in the property,
             // or a VM call is required. A VM call is always required if pobj
@@ -3111,17 +3151,17 @@ jit::PropertyWriteNeedsTypeBarrier(JSCon
         if (!types->getTypeOrSingleObject(cx, i, &object))
             return false;
 
         if (!object || object->unknownProperties())
             continue;
         if (object->getTypedArrayType() < ScalarTypeRepresentation::TYPE_MAX)
             continue;
 
-        types::HeapTypeSet *property = object->getProperty(cx, id, false);
+        types::HeapTypeSet *property = object->getProperty(cx, id);
         if (!property) {
             *result = true;
             return true;
         }
 
         if (TypeSetIncludes(property, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
             continue;
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8937,16 +8937,18 @@ bool ElementAccessIsTypedArray(MDefiniti
                                ScalarTypeRepresentation::Type *arrayType);
 bool ElementAccessIsPacked(JSContext *cx, MDefinition *obj);
 bool ElementAccessHasExtraIndexedProperty(JSContext *cx, MDefinition *obj);
 bool DenseNativeElementType(JSContext *cx, MDefinition *obj, MIRType *result);
 bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, PropertyName *name,
                                   types::StackTypeSet *observed, bool updateObserved, bool *result);
 bool PropertyReadNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
                                   types::StackTypeSet *observed, bool *result);
+bool PropertyReadOnPrototypeNeedsTypeBarrier(JSContext *cx, MDefinition *obj, PropertyName *name,
+                                             types::TemporaryTypeSet *observed, bool *result);
 bool PropertyReadIsIdempotent(JSContext *cx, MDefinition *obj, PropertyName *name, bool *result);
 bool AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *name,
                                types::StackTypeSet *observed);
 bool PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinition **pobj,
                                    PropertyName *name, MDefinition **pvalue,
                                    bool canModify, bool *result);
 
 } // namespace jit
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1129,17 +1129,17 @@ array_join(JSContext *cx, unsigned argc,
 }
 
 static inline bool
 InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned count)
 {
     if (cx->typeInferenceEnabled() && !type->unknownProperties()) {
         AutoEnterAnalysis enter(cx);
 
-        TypeSet *types = type->getProperty(cx, JSID_VOID, true);
+        TypeSet *types = type->getProperty(cx, JSID_VOID);
         if (!types)
             return false;
 
         for (unsigned i = 0; i < count; i++) {
             if (vector[i].isMagic(JS_ELEMENTS_HOLE))
                 continue;
             Type valtype = GetValueType(vector[i]);
             types->addType(cx, valtype);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -258,24 +258,16 @@ types::TypeHasProperty(JSContext *cx, Ty
          * We don't track types for properties inherited from prototypes which
          * haven't yet been accessed during analysis of the inheriting object.
          * Don't do the property instantiation now.
          */
         TypeSet *types = obj->maybeGetProperty(cx, id);
         if (!types)
             return true;
 
-        /*
-         * If the types inherited from prototypes are not being propagated into
-         * this set (because we haven't analyzed code which accesses the
-         * property), skip.
-         */
-        if (!types->hasPropagatedProperty())
-            return true;
-
         if (!types->hasType(type)) {
             TypeFailure(cx, "Missing type in object %s %s: %s",
                         TypeObjectString(obj), TypeIdString(id), TypeString(type));
         }
     }
     return true;
 }
 
@@ -412,18 +404,16 @@ TypeSet::add(JSContext *cx, TypeConstrai
 
     if (callExisting)
         addTypesToConstraint(cx, constraint);
 }
 
 void
 TypeSet::print()
 {
-    if (flags & TYPE_FLAG_OWN_PROPERTY)
-        fprintf(stderr, " [own]");
     if (flags & TYPE_FLAG_CONFIGURED_PROPERTY)
         fprintf(stderr, " [configured]");
 
     if (definiteProperty())
         fprintf(stderr, " [definite:%d]", definiteSlot());
 
     if (baseFlags() == 0 && !baseObjectCount()) {
         fprintf(stderr, " missing");
@@ -527,57 +517,16 @@ TypeSet::unionSets(TypeSet *a, TypeSet *
                 return NULL;
         }
     }
 
     return res;
 }
 
 /////////////////////////////////////////////////////////////////////
-// TypeSet constraints
-/////////////////////////////////////////////////////////////////////
-
-namespace {
-
-/* Standard subset constraint, propagate all types from one set to another. */
-class TypeConstraintSubset : public TypeConstraint
-{
-  public:
-    TypeSet *target;
-
-    TypeConstraintSubset(TypeSet *target)
-        : target(target)
-    {
-        JS_ASSERT(target);
-    }
-
-    const char *kind() { return "subset"; }
-
-    void newType(JSContext *cx, TypeSet *source, Type type)
-    {
-        /* Basic subset constraint, move all types to the target. */
-        target->addType(cx, type);
-    }
-};
-
-} /* anonymous namespace */
-
-void
-StackTypeSet::addSubset(JSContext *cx, StackTypeSet *target)
-{
-    add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubset>(target));
-}
-
-void
-HeapTypeSet::addSubset(JSContext *cx, HeapTypeSet *target)
-{
-    add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubset>(target));
-}
-
-/////////////////////////////////////////////////////////////////////
 // Freeze constraints
 /////////////////////////////////////////////////////////////////////
 
 namespace {
 
 /* Constraint which triggers recompilation of a script if any type is added to a type set. */
 class TypeConstraintFreeze : public TypeConstraint
 {
@@ -759,33 +708,33 @@ TemporaryTypeSet::hasObjectFlags(JSConte
         }
         if (object->hasAnyFlags(flags))
             return true;
 
         /*
          * Add a constraint on the the object to pick up changes in the
          * object's properties.
          */
-        HeapTypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
+        HeapTypeSet *types = object->getProperty(cx, JSID_EMPTY);
         if (!types)
             return true;
         types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
                           cx->compartment()->types.compiledInfo, flags), false);
     }
 
     return false;
 }
 
 bool
 HeapTypeSet::HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags)
 {
     if (object->hasAnyFlags(flags))
         return true;
 
-    HeapTypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
+    HeapTypeSet *types = object->getProperty(cx, JSID_EMPTY);
     if (!types)
         return true;
     types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
                       cx->compartment()->types.compiledInfo, flags), false);
     return false;
 }
 
 static inline void
@@ -813,55 +762,48 @@ ObjectStateChange(ExclusiveContext *cxAr
         }
     }
 }
 
 void
 HeapTypeSet::WatchObjectStateChange(JSContext *cx, TypeObject *obj)
 {
     JS_ASSERT(!obj->unknownProperties());
-    HeapTypeSet *types = obj->getProperty(cx, JSID_EMPTY, false);
+    HeapTypeSet *types = obj->getProperty(cx, JSID_EMPTY);
     if (!types)
         return;
 
     /*
      * Use a constraint which triggers recompilation when markStateChange is
      * called, which will set 'force' to true.
      */
     types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
                      cx->compartment()->types.compiledInfo,
                      0));
 }
 
 namespace {
 
-class TypeConstraintFreezeOwnProperty : public TypeConstraint
+class TypeConstraintFreezeConfiguredProperty : public TypeConstraint
 {
   public:
     RecompileInfo info;
 
-    bool updated;
-    bool configurable;
-
-    TypeConstraintFreezeOwnProperty(RecompileInfo info, bool configurable)
-        : info(info), updated(false), configurable(configurable)
+    TypeConstraintFreezeConfiguredProperty(RecompileInfo info)
+      : info(info)
     {}
 
     const char *kind() { return "freezeOwnProperty"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type) {}
 
     void newPropertyState(JSContext *cx, TypeSet *source)
     {
-        if (updated)
-            return;
-        if (source->ownProperty(configurable)) {
-            updated = true;
+        if (source->configuredProperty())
             cx->compartment()->types.addPendingRecompile(cx, info);
-        }
     }
 };
 
 } /* anonymous namespace */
 
 static void
 CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, HandleFunction fun);
 
@@ -876,17 +818,17 @@ TypeObject::incrementTenureCount()
 
     flags = (flags & ~OBJECT_FLAG_TENURE_COUNT_MASK)
           | ((count + 1) << OBJECT_FLAG_TENURE_COUNT_SHIFT);
 
     return count >= MaxJITAllocTenures;
 }
 
 bool
-HeapTypeSet::isOwnProperty(JSContext *cx, TypeObject *object, bool configurable)
+HeapTypeSet::isConfiguredProperty(JSContext *cx, TypeObject *object)
 {
     /*
      * Everywhere compiled code depends on definite properties associated with
      * a type object's newScript, we need to make sure there are constraints
      * in place which will mark those properties as configured should the
      * definite properties be invalidated.
      */
     if (object->flags & OBJECT_FLAG_NEW_SCRIPT_REGENERATE) {
@@ -896,22 +838,21 @@ HeapTypeSet::isOwnProperty(JSContext *cx
             RootedFunction fun(cx, object->newScript()->fun);
             CheckNewScriptProperties(cx, typeObj, fun);
         } else {
             JS_ASSERT(object->flags & OBJECT_FLAG_ADDENDUM_CLEARED);
             object->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
         }
     }
 
-    if (ownProperty(configurable))
+    if (configuredProperty())
         return true;
 
-    add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeOwnProperty>(
-                                                      cx->compartment()->types.compiledInfo,
-                                                      configurable), false);
+    add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeConfiguredProperty>(
+                cx->compartment()->types.compiledInfo), false);
     return false;
 }
 
 bool
 HeapTypeSet::knownNonEmpty(JSContext *cx)
 {
     if (baseFlags() != 0 || baseObjectCount() != 0)
         return true;
@@ -970,17 +911,17 @@ TemporaryTypeSet::convertDoubleElements(
             }
         }
 
         if (type->unknownProperties()) {
             alwaysConvert = false;
             continue;
         }
 
-        HeapTypeSet *types = type->getProperty(cx, JSID_VOID, false);
+        HeapTypeSet *types = type->getProperty(cx, JSID_VOID);
         if (!types)
             return AmbiguousDoubleConversion;
 
         types->addFreeze(cx);
 
         // We can't convert to double elements for objects which do not have
         // double in their element types (as the conversion may render the type
         // information incorrect), nor for non-array objects (as their elements
@@ -1535,18 +1476,18 @@ PrototypeHasIndexedProperty(JSContext *c
     do {
         TypeObject *type = obj->getType(cx);
         if (!type)
             return true;
         if (ClassCanHaveExtraProperties(type->clasp))
             return true;
         if (type->unknownProperties())
             return true;
-        HeapTypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
-        if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
+        HeapTypeSet *indexTypes = type->getProperty(cx, JSID_VOID);
+        if (!indexTypes || indexTypes->isConfiguredProperty(cx, type) || indexTypes->knownNonEmpty(cx))
             return true;
         obj = obj->getProto();
     } while (obj);
 
     return false;
 }
 
 bool
@@ -2241,57 +2182,25 @@ TypeCompartment::newTypedObject(JSContex
     obj->setType(p->value.object);
     return obj;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
-void
-TypeObject::getFromPrototypes(JSContext *cx, jsid id, HeapTypeSet *types, bool force)
-{
-    if (!force && types->hasPropagatedProperty())
-        return;
-
-    types->setPropagatedProperty();
-
-    if (!proto)
-        return;
-
-    if (proto == Proxy::LazyProto) {
-        JS_ASSERT(unknownProperties());
-        return;
-    }
-
-    types::TypeObject *protoType = proto->getType(cx);
-    if (!protoType || protoType->unknownProperties()) {
-        types->addType(cx, Type::UnknownType());
-        return;
-    }
-
-    HeapTypeSet *protoTypes = protoType->getProperty(cx, id, false);
-    if (!protoTypes)
-        return;
-
-    protoTypes->addSubset(cx, types);
-
-    protoType->getFromPrototypes(cx, id, protoTypes);
-}
-
 static inline void
 UpdatePropertyType(ExclusiveContext *cx, TypeSet *types, JSObject *obj, Shape *shape,
                    bool force)
 {
-    types->setOwnProperty(cx, false);
     if (!shape->writable())
-        types->setOwnProperty(cx, true);
+        types->setConfiguredProperty(cx);
 
     if (shape->hasGetterValue() || shape->hasSetterValue()) {
-        types->setOwnProperty(cx, true);
+        types->setConfiguredProperty(cx);
         types->addType(cx, Type::UnknownType());
     } else if (shape->hasDefaultGetter() && shape->hasSlot()) {
         const Value &value = obj->nativeGetSlot(shape->slot());
 
         /*
          * Don't add initial undefined types for singleton properties that are
          * not collated into the JSID_VOID property (see propertySet comment).
          */
@@ -2330,33 +2239,32 @@ TypeObject::addProperty(ExclusiveContext
                 shape = shape->previous();
             }
 
             /* Also get values of any dense elements in the object. */
             for (size_t i = 0; i < singleton->getDenseInitializedLength(); i++) {
                 const Value &value = singleton->getDenseElement(i);
                 if (!value.isMagic(JS_ELEMENTS_HOLE)) {
                     Type type = GetValueType(value);
-                    base->types.setOwnProperty(cx, false);
                     base->types.addType(cx, type);
                 }
             }
         } else if (!JSID_IS_EMPTY(id)) {
             RootedId rootedId(cx, id);
             Shape *shape = singleton->nativeLookup(cx, rootedId);
             if (shape)
                 UpdatePropertyType(cx, &base->types, rSingleton, shape, false);
         }
 
         if (singleton->watched()) {
             /*
              * Mark the property as configured, to inhibit optimizations on it
              * and avoid bypassing the watchpoint handler.
              */
-            base->types.setOwnProperty(cx, true);
+            base->types.setConfiguredProperty(cx);
         }
     }
 
     *pprop = base;
 
     InferSpew(ISpewOps, "typeSet: %sT%p%s property %s %s",
               InferSpewColor(&base->types), &base->types, InferSpewColorReset(),
               TypeObjectString(this), TypeIdString(id));
@@ -2372,18 +2280,19 @@ TypeObject::addDefiniteProperties(Exclus
 
     /* Mark all properties of obj as definite properties of this type. */
     AutoEnterAnalysis enter(cx);
 
     RootedShape shape(cx, obj->lastProperty());
     while (!shape->isEmptyShape()) {
         jsid id = IdToTypeId(shape->propid());
         if (!JSID_IS_VOID(id) && obj->isFixedSlot(shape->slot()) &&
-            shape->slot() <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT)) {
-            TypeSet *types = getProperty(cx, id, true);
+            shape->slot() <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT))
+        {
+            TypeSet *types = getProperty(cx, id);
             if (!types)
                 return false;
             types->setDefinite(shape->slot());
         }
         shape = shape->previous();
     }
 
     return true;
@@ -2419,17 +2328,17 @@ TypeObject::matchDefiniteProperties(Hand
 
 inline void
 InlineAddTypeProperty(ExclusiveContext *cx, TypeObject *obj, jsid id, Type type)
 {
     JS_ASSERT(id == IdToTypeId(id));
 
     AutoEnterAnalysis enter(cx);
 
-    TypeSet *types = obj->getProperty(cx, id, true);
+    TypeSet *types = obj->getProperty(cx, id);
     if (!types || types->hasType(type))
         return;
 
     InferSpew(ISpewOps, "externalType: property %s %s: %s",
               TypeObjectString(obj), TypeIdString(id), TypeString(type));
     types->addType(cx, type);
 }
 
@@ -2469,19 +2378,19 @@ TypeObject::addPropertyType(ExclusiveCon
 
 void
 TypeObject::markPropertyConfigured(ExclusiveContext *cx, jsid id)
 {
     AutoEnterAnalysis enter(cx);
 
     id = IdToTypeId(id);
 
-    TypeSet *types = getProperty(cx, id, true);
+    TypeSet *types = getProperty(cx, id);
     if (types)
-        types->setOwnProperty(cx, true);
+        types->setConfiguredProperty(cx);
 }
 
 void
 TypeObject::markStateChange(ExclusiveContext *cxArg)
 {
     if (unknownProperties())
         return;
 
@@ -2545,17 +2454,17 @@ TypeObject::markUnknown(ExclusiveContext
      * any properties accessed already accounts for possible values read from them.
      */
 
     unsigned count = getPropertyCount();
     for (unsigned i = 0; i < count; i++) {
         Property *prop = getProperty(i);
         if (prop) {
             prop->types.addType(cx, Type::UnknownType());
-            prop->types.setOwnProperty(cx, true);
+            prop->types.setConfiguredProperty(cx);
         }
     }
 }
 
 void
 TypeObject::clearAddendum(ExclusiveContext *cx)
 {
     JS_ASSERT(!(flags & OBJECT_FLAG_ADDENDUM_CLEARED));
@@ -2606,17 +2515,17 @@ TypeObject::clearNewScriptAddendum(Exclu
      * been deleted/reconfigured, which will have the same effect on JITs
      * wanting to use the definite bits to optimize property accesses.
      */
     for (unsigned i = 0; i < getPropertyCount(); i++) {
         Property *prop = getProperty(i);
         if (!prop)
             continue;
         if (prop->types.definiteProperty())
-            prop->types.setOwnProperty(cx, true);
+            prop->types.setConfiguredProperty(cx);
     }
 
     /*
      * If we cleared the new script while in the middle of initializing an
      * object, it will still have the new script's shape and reflect the no
      * longer correct state of the object once its initialization is completed.
      * We can't really detect the possibility of this statically, but the new
      * script keeps track of where each property is initialized so we can walk
@@ -2769,17 +2678,17 @@ class TypeConstraintClearDefiniteGetterS
         if (!object->hasNewScript())
             return;
         /*
          * Clear out the newScript shape and definite property information from
          * an object if the source type set could be a setter or could be
          * non-writable, both of which are indicated by the source type set
          * being marked as configured.
          */
-        if (!(object->flags & OBJECT_FLAG_ADDENDUM_CLEARED) && source->ownProperty(true))
+        if (!(object->flags & OBJECT_FLAG_ADDENDUM_CLEARED) && source->configuredProperty())
             object->clearAddendum(cx);
     }
 
     void newType(JSContext *cx, TypeSet *source, Type type) {}
 };
 
 bool
 types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, jsid id)
@@ -2789,18 +2698,18 @@ types::AddClearDefiniteGetterSetterForPr
      * a permanent property in any transitive prototype, the definite
      * properties get cleared from the type.
      */
     RootedObject parent(cx, type->proto);
     while (parent) {
         TypeObject *parentObject = parent->getType(cx);
         if (!parentObject || parentObject->unknownProperties())
             return false;
-        HeapTypeSet *parentTypes = parentObject->getProperty(cx, id, false);
-        if (!parentTypes || parentTypes->ownProperty(true))
+        HeapTypeSet *parentTypes = parentObject->getProperty(cx, id);
+        if (!parentTypes || parentTypes->configuredProperty())
             return false;
         parentTypes->add(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type));
         parent = parent->getProto();
     }
     return true;
 }
 
 /*
@@ -3221,34 +3130,16 @@ JSScript::makeTypes(JSContext *cx)
 
     new(types) TypeScript();
 
     TypeSet *typeArray = types->typeArray();
 
     for (unsigned i = 0; i < count; i++)
         new (&typeArray[i]) StackTypeSet();
 
-    if (isCallsiteClone) {
-        /*
-         * For callsite clones, flow the types from the specific clone back to
-         * the original function.
-         */
-        JS_ASSERT(function());
-        JS_ASSERT(originalFunction());
-        JS_ASSERT(function()->nargs == originalFunction()->nargs);
-
-        JSScript *original = originalFunction()->nonLazyScript();
-        if (!original->ensureHasTypes(cx))
-            return false;
-
-        TypeScript::ThisTypes(this)->addSubset(cx, TypeScript::ThisTypes(original));
-        for (unsigned i = 0; i < function()->nargs; i++)
-            TypeScript::ArgTypes(this, i)->addSubset(cx, TypeScript::ArgTypes(original, i));
-    }
-
 #ifdef DEBUG
     for (unsigned i = 0; i < nTypeSets; i++)
         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
                   i, id());
     TypeSet *thisTypes = TypeScript::ThisTypes(this);
     InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
               InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
@@ -3401,33 +3292,16 @@ JSObject::splicePrototype(JSContext *cx,
             return false;
         self->type_ = type;
         return true;
     }
 
     type->clasp = clasp;
     type->proto = proto.raw();
 
-    AutoEnterAnalysis enter(cx);
-
-    if (protoType && protoType->unknownProperties() && !type->unknownProperties()) {
-        type->markUnknown(cx);
-        return true;
-    }
-
-    if (!type->unknownProperties()) {
-        /* Update properties on this type with any shared with the prototype. */
-        unsigned count = type->getPropertyCount();
-        for (unsigned i = 0; i < count; i++) {
-            Property *prop = type->getProperty(i);
-            if (prop && prop->types.hasPropagatedProperty())
-                type->getFromPrototypes(cx, prop->id, &prop->types, true);
-        }
-    }
-
     return true;
 }
 
 /* static */ TypeObject *
 JSObject::makeLazyType(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->hasLazyType());
     JS_ASSERT(cx->compartment() == obj->compartment());
@@ -3744,22 +3618,18 @@ TypeSet::sweep(Zone *zone)
     } else if (objectCount == 1) {
         TypeObjectKey *object = (TypeObjectKey *) objectSet;
         if (IsAboutToBeFinalized(object)) {
             objectSet = NULL;
             setBaseObjectCount(0);
         }
     }
 
-    /*
-     * All constraints are wiped out on each GC, including those propagating
-     * into this type set from prototype properties.
-     */
+    /* All constraints are wiped out on each GC. */
     constraintList = NULL;
-    flags &= ~TYPE_FLAG_PROPAGATED_PROPERTY;
 }
 
 inline void
 TypeObject::clearProperties()
 {
     setBasePropertyCount(0);
     propertySet = NULL;
 }
@@ -3791,30 +3661,28 @@ TypeObject::sweep(FreeOp *fop)
             fop->free_(addendum);
         return;
     }
 
     js::LifoAlloc &typeLifoAlloc = zone()->types.typeLifoAlloc;
 
     /*
      * Properties were allocated from the old arena, and need to be copied over
-     * to the new one. Don't hang onto properties without the OWN_PROPERTY
-     * flag; these were never directly assigned, and get any possible values
-     * from the object's prototype.
+     * to the new one.
      */
     unsigned propertyCount = basePropertyCount();
     if (propertyCount >= 2) {
         unsigned oldCapacity = HashSetCapacity(propertyCount);
         Property **oldArray = propertySet;
 
         clearProperties();
         propertyCount = 0;
         for (unsigned i = 0; i < oldCapacity; i++) {
             Property *prop = oldArray[i];
-            if (prop && prop->types.ownProperty(false)) {
+            if (prop) {
                 Property *newProp = typeLifoAlloc.new_<Property>(*prop);
                 if (newProp) {
                     Property **pentry =
                         HashSetInsert<jsid,Property,Property>
                             (typeLifoAlloc, propertySet, propertyCount, prop->id);
                     if (pentry) {
                         *pentry = newProp;
                         newProp->types.sweep(zone());
@@ -3824,27 +3692,22 @@ TypeObject::sweep(FreeOp *fop)
                 } else {
                     zone()->types.setPendingNukeTypes();
                 }
             }
         }
         setBasePropertyCount(propertyCount);
     } else if (propertyCount == 1) {
         Property *prop = (Property *) propertySet;
-        if (prop->types.ownProperty(false)) {
-            Property *newProp = typeLifoAlloc.new_<Property>(*prop);
-            if (newProp) {
-                propertySet = (Property **) newProp;
-                newProp->types.sweep(zone());
-            } else {
-                zone()->types.setPendingNukeTypes();
-            }
+        Property *newProp = typeLifoAlloc.new_<Property>(*prop);
+        if (newProp) {
+            propertySet = (Property **) newProp;
+            newProp->types.sweep(zone());
         } else {
-            propertySet = NULL;
-            setBasePropertyCount(0);
+            zone()->types.setPendingNukeTypes();
         }
     }
 
     if (basePropertyCount() <= SET_ARRAY_SIZE) {
         for (unsigned i = 0; i < basePropertyCount(); i++)
             JS_ASSERT(propertySet[i]);
     }
 
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -303,37 +303,28 @@ enum {
     /*
      * Flags describing the kind of type set this is.
      *
      * - StackTypeSet are associated with TypeScripts, for arguments and values
      *   observed at property reads. These are implicitly frozen on compilation
      *   and do not have constraints attached to them.
      *
      * - HeapTypeSet are associated with the properties of TypeObjects. These
-     *   may have constraints added to them to propagate types around or to
-     *   trigger invalidation of compiled code.
+     *   may have constraints added to them to trigger invalidation of compiled
+     *   code.
      *
      * - TemporaryTypeSet are created during compilation and do not outlive
      *   that compilation.
      */
     TYPE_FLAG_STACK_SET           = 0x00020000,
     TYPE_FLAG_HEAP_SET            = 0x00040000,
 
     /* Additional flags for HeapTypeSet sets. */
 
     /*
-     * Whether there are subset constraints propagating the possible types
-     * for this property inherited from the object's prototypes. Reset on GC.
-     */
-    TYPE_FLAG_PROPAGATED_PROPERTY = 0x00080000,
-
-    /* Whether this property has ever been directly written. */
-    TYPE_FLAG_OWN_PROPERTY        = 0x00100000,
-
-    /*
      * Whether the property has ever been deleted or reconfigured to behave
      * differently from a normal native property (e.g. made non-writable or
      * given a scripted getter or setter).
      */
     TYPE_FLAG_CONFIGURED_PROPERTY = 0x00200000,
 
     /*
      * Whether the property is definitely in a particular inline slot on all
@@ -467,64 +458,59 @@ class TypeSet
     bool empty() const { return !baseFlags() && !baseObjectCount(); }
     bool noConstraints() const { return constraintList == NULL; }
 
     bool hasAnyFlag(TypeFlags flags) const {
         JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
         return !!(baseFlags() & flags);
     }
 
-    bool ownProperty(bool configurable) const {
-        return flags & (configurable ? TYPE_FLAG_CONFIGURED_PROPERTY : TYPE_FLAG_OWN_PROPERTY);
+    bool configuredProperty() const {
+        return flags & TYPE_FLAG_CONFIGURED_PROPERTY;
     }
     bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_PROPERTY; }
     unsigned definiteSlot() const {
         JS_ASSERT(definiteProperty());
         return flags >> TYPE_FLAG_DEFINITE_SHIFT;
     }
 
     /* Join two type sets into a new set. The result should not be modified further. */
     static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
 
     /*
      * Add a type to this set, calling any constraint handlers if this is a new
      * possible type.
      */
     inline void addType(ExclusiveContext *cx, Type type);
 
-    /* Mark this type set as representing an own property or configured property. */
-    inline void setOwnProperty(ExclusiveContext *cx, bool configured);
+    /* Mark this type set as representing a configured property. */
+    inline void setConfiguredProperty(ExclusiveContext *cx);
 
     /*
      * Iterate through the objects in this set. getObjectCount overapproximates
      * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
      * may return NULL.
      */
     inline unsigned getObjectCount() const;
     inline TypeObjectKey *getObject(unsigned i) const;
     inline JSObject *getSingleObject(unsigned i) const;
     inline TypeObject *getTypeObject(unsigned i) const;
     inline bool getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **obj) const;
 
     /* The Class of an object in this set. */
     inline const Class *getObjectClass(unsigned i) const;
 
-    void setOwnProperty(bool configurable) {
-        flags |= TYPE_FLAG_OWN_PROPERTY;
-        if (configurable)
-            flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
+    void setConfiguredProperty() {
+        flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
     }
     void setDefinite(unsigned slot) {
         JS_ASSERT(slot <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT));
         flags |= TYPE_FLAG_DEFINITE_PROPERTY | (slot << TYPE_FLAG_DEFINITE_SHIFT);
     }
 
-    bool hasPropagatedProperty() { return !!(flags & TYPE_FLAG_PROPAGATED_PROPERTY); }
-    void setPropagatedProperty() { flags |= TYPE_FLAG_PROPAGATED_PROPERTY; }
-
     bool isStackSet() {
         return flags & TYPE_FLAG_STACK_SET;
     }
     bool isHeapSet() {
         return flags & TYPE_FLAG_HEAP_SET;
     }
 
     /*
@@ -556,29 +542,23 @@ class TypeSet
 
     inline void clearObjects();
 };
 
 class StackTypeSet : public TypeSet
 {
   public:
     StackTypeSet() { flags |= TYPE_FLAG_STACK_SET; }
-
-    /* Propagate any types from this set into target. */
-    void addSubset(JSContext *cx, StackTypeSet *target);
 };
 
 class HeapTypeSet : public TypeSet
 {
   public:
     HeapTypeSet() { flags |= TYPE_FLAG_HEAP_SET; }
 
-    /* Propagate any types from this set into target. */
-    void addSubset(JSContext *cx, HeapTypeSet *target);
-
     /* Completely freeze the contents of this type set. */
     void addFreeze(JSContext *cx);
 
     /*
      * Watch for a generic object state change on a type object. This currently
      * includes reallocations of slot pointers for global objects, and changes
      * to newScript data on types.
      */
@@ -589,17 +569,17 @@ class HeapTypeSet : public TypeSet
 
     /*
      * For type sets on a property, return true if the property has any 'own'
      * values assigned. If configurable is set, return 'true' if the property
      * has additionally been reconfigured as non-configurable, non-enumerable
      * or non-writable (this only applies to properties that have changed after
      * having been created, not to e.g. properties non-writable on creation).
      */
-    bool isOwnProperty(JSContext *cx, TypeObject *object, bool configurable);
+    bool isConfiguredProperty(JSContext *cx, TypeObject *object);
 
     /* Get whether this type set is non-empty. */
     bool knownNonEmpty(JSContext *cx);
 
     /* Get whether this type set is known to be a subset of other. */
     bool knownSubset(JSContext *cx, HeapTypeSet *other);
 
     /* Get the single value which can appear in this type set, otherwise NULL. */
@@ -753,101 +733,16 @@ struct TypeResult
     TypeResult(uint32_t offset, Type type)
         : offset(offset), type(type), next(NULL)
     {}
 };
 
 /* Is this a reasonable PC to be doing inlining on? */
 inline bool isInlinableCall(jsbytecode *pc);
 
-/*
- * Type barriers overview.
- *
- * Type barriers are a technique for using dynamic type information to improve
- * the inferred types within scripts. At certain opcodes --- those with the
- * JOF_TYPESET format --- we will construct a type set storing the set of types
- * which we have observed to be pushed at that opcode, and will only use those
- * observed types when doing propagation downstream from the bytecode. For
- * example, in the following script:
- *
- * function foo(x) {
- *   return x.f + 10;
- * }
- *
- * Suppose we know the type of 'x' and that the type of its 'f' property is
- * either an int or float. To account for all possible behaviors statically,
- * we would mark the result of the 'x.f' access as an int or float, as well
- * as the result of the addition and the return value of foo (and everywhere
- * the result of 'foo' is used). When dealing with polymorphic code, this is
- * undesirable behavior --- the type imprecision surrounding the polymorphism
- * will tend to leak to many places in the program.
- *
- * Instead, we will keep track of the types that have been dynamically observed
- * to have been produced by the 'x.f', and only use those observed types
- * downstream from the access. If the 'x.f' has only ever produced integers,
- * we will treat its result as an integer and mark the result of foo as an
- * integer.
- *
- * The set of observed types will be a subset of the set of possible types,
- * and if the two sets are different, a type barriers will be added at the
- * bytecode which checks the dynamic result every time the bytecode executes
- * and makes sure it is in the set of observed types. If it is not, that
- * observed set is updated, and the new type information is automatically
- * propagated along the already-generated type constraints to the places
- * where the result of the bytecode is used.
- *
- * Observing new types at a bytecode removes type barriers at the bytecode
- * (this removal happens lazily, see ScriptAnalysis::pruneTypeBarriers), and if
- * all type barriers at a bytecode are removed --- the set of observed types
- * grows to match the set of possible types --- then the result of the bytecode
- * no longer needs to be dynamically checked (unless the set of possible types
- * grows, triggering the generation of new type barriers).
- *
- * Barriers are only relevant for accesses on properties whose types inference
- * actually tracks (see propertySet comment under TypeObject). Accesses on
- * other properties may be able to produce additional unobserved types even
- * without a barrier present, and can only be compiled to jitcode with special
- * knowledge of the property in question (e.g. for lengths of arrays, or
- * elements of typed arrays).
- */
-
-/*
- * Barrier introduced at some bytecode. These are added when, during inference,
- * we block a type from being propagated as would normally be done for a subset
- * constraint. The propagation is technically possible, but we suspect it will
- * not happen dynamically and this type needs to be watched for. These are only
- * added at reads of properties and at scripted call sites.
- */
-struct TypeBarrier
-{
-    /* Next barrier on the same bytecode. */
-    TypeBarrier *next;
-
-    /* Target type set into which propagation was blocked. */
-    TypeSet *target;
-
-    /*
-     * Type which was not added to the target. If target ends up containing the
-     * type somehow, this barrier can be removed.
-     */
-    Type type;
-
-    /*
-     * If specified, this barrier can be removed if object has a non-undefined
-     * value in property id.
-     */
-    JSObject *singleton;
-    jsid singletonId;
-
-    TypeBarrier(TypeSet *target, Type type, JSObject *singleton, jsid singletonId)
-        : next(NULL), target(target), type(type),
-          singleton(singleton), singletonId(singletonId)
-    {}
-};
-
 /* Type information about a property. */
 struct Property
 {
     /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
     HeapId id;
 
     /* Possible types for this property, including types inherited from prototypes. */
     HeapTypeSet types;
@@ -1102,21 +997,19 @@ struct TypeObject : gc::BarrieredCell<Ty
     bool unknownProperties() {
         JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES,
                      hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
         return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
     }
 
     /*
      * Get or create a property of this object. Only call this for properties which
-     * a script accesses explicitly. 'assign' indicates whether this is for an
-     * assignment, and the own types of the property will be used instead of
-     * aggregate types.
+     * a script accesses explicitly.
      */
-    inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id, bool own);
+    inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id);
 
     /* Get a property only if it already exists. */
     inline HeapTypeSet *maybeGetProperty(ExclusiveContext *cx, jsid id);
 
     inline unsigned getPropertyCount();
     inline Property *getProperty(unsigned i);
 
     /* Get the typed array element type if clasp is a typed array. */
@@ -1173,17 +1066,16 @@ struct TypeObject : gc::BarrieredCell<Ty
     void addPropertyType(ExclusiveContext *cx, const char *name, const Value &value);
     void markPropertyConfigured(ExclusiveContext *cx, jsid id);
     void markStateChange(ExclusiveContext *cx);
     void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
     void markUnknown(ExclusiveContext *cx);
     void clearAddendum(ExclusiveContext *cx);
     void clearNewScriptAddendum(ExclusiveContext *cx);
     void clearTypedObjectAddendum(ExclusiveContext *cx);
-    void getFromPrototypes(JSContext *cx, jsid id, HeapTypeSet *types, bool force = false);
 
     void print();
 
     inline void clearProperties();
     inline void sweep(FreeOp *fop);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -547,17 +547,17 @@ EnsureTrackPropertyTypes(JSContext *cx, 
 
     if (!cx->typeInferenceEnabled() || obj->type()->unknownProperties())
         return;
 
     id = IdToTypeId(id);
 
     if (obj->hasSingletonType()) {
         AutoEnterAnalysis enter(cx);
-        obj->type()->getProperty(cx, id, true);
+        obj->type()->getProperty(cx, id);
     }
 
     JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
 }
 
 /* Add a possible type for a property of obj. */
 inline void
 AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, Type type)
@@ -1332,24 +1332,22 @@ TypeSet::addType(ExclusiveContext *cxArg
         }
         cx->compartment()->types.resolvePending(cx);
     } else {
         JS_ASSERT(!constraintList);
     }
 }
 
 inline void
-TypeSet::setOwnProperty(ExclusiveContext *cxArg, bool configured)
+TypeSet::setConfiguredProperty(ExclusiveContext *cxArg)
 {
-    TypeFlags nflags = TYPE_FLAG_OWN_PROPERTY | (configured ? TYPE_FLAG_CONFIGURED_PROPERTY : 0);
-
-    if ((flags & nflags) == nflags)
+    if (flags & TYPE_FLAG_CONFIGURED_PROPERTY)
         return;
 
-    flags |= nflags;
+    flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
 
     /* Propagate the change to all constraints. */
     if (JSContext *cx = cxArg->maybeJSContext()) {
         TypeConstraint *constraint = constraintList;
         while (constraint) {
             constraint->newPropertyState(cx, this);
             constraint = constraint->next;
         }
@@ -1459,17 +1457,17 @@ inline void
 TypeObject::setBasePropertyCount(uint32_t count)
 {
     JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
     flags = (flags & ~OBJECT_FLAG_PROPERTY_COUNT_MASK)
           | (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
 }
 
 inline HeapTypeSet *
-TypeObject::getProperty(ExclusiveContext *cx, jsid id, bool own)
+TypeObject::getProperty(ExclusiveContext *cx, jsid id)
 {
     JS_ASSERT(cx->compartment()->activeAnalysis);
 
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
 
     uint32_t propertyCount = basePropertyCount();
@@ -1499,21 +1497,17 @@ TypeObject::getProperty(ExclusiveContext
                 if (Property *prop = getProperty(i))
                     return &prop->types;
             }
 
             MOZ_ASSUME_UNREACHABLE("Missing property");
         }
     }
 
-    HeapTypeSet *types = &(*pprop)->types;
-    if (own)
-        types->setOwnProperty(cx, false);
-
-    return types;
+    return &(*pprop)->types;
 }
 
 inline HeapTypeSet *
 TypeObject::maybeGetProperty(ExclusiveContext *cx, jsid id)
 {
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -4023,17 +4023,19 @@ NativeGetInline(JSContext *cx,
                 typename MaybeRooted<Shape*, allowGC>::HandleType shape,
                 typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
     JS_ASSERT(pobj->isNative());
 
     if (shape->hasSlot()) {
         vp.set(pobj->nativeGetSlot(shape->slot()));
         JS_ASSERT(!vp.isMagic());
-        JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetter(),
+        JS_ASSERT_IF(!pobj->hasSingletonType() &&
+                     !pobj->template is<ScopeObject>() &&
+                     shape->hasDefaultGetter(),
                      js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp));
     } else {
         vp.setUndefined();
     }
     if (shape->hasDefaultGetter())
         return true;
 
     {