Bug 1285217 - Handle OOM in IonBuilder::testNotDefinedProperty. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Wed, 13 Jul 2016 10:15:20 +0000
changeset 387161 393e8f9705751f7748d55a9d5c6f6242f38032af
parent 387160 2cfa9ffe77a49c573340dc5d8880bf8108be967a
child 387162 ff3c444a42ae082d1ad3fdfc1271ab4dd4428a48
push id22898
push userCallek@gmail.com
push dateWed, 13 Jul 2016 13:20:13 +0000
reviewersjandem
bugs1285217
milestone50.0a1
Bug 1285217 - Handle OOM in IonBuilder::testNotDefinedProperty. r=jandem
js/src/jit-test/tests/ion/bug1285217.js
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MIR.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1285217.js
@@ -0,0 +1,11 @@
+function f() {
+    var o = {
+        x: 1
+    };
+    for (var i = 0; i < 300; i++) o = Object.create(o);
+    for (var i = 0; i < 15; i++) {
+        assertEq(o.x, 1);
+        eval(o.y, undefined);
+    }
+}
+f();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -8265,58 +8265,61 @@ IonBuilder::testSingletonPropertyTypes(M
 
     JSObject* proto = GetBuiltinPrototypePure(&script()->global(), key);
     if (proto)
         return testSingletonProperty(proto, id);
 
     return nullptr;
 }
 
-bool
+ResultWithOOM<bool>
 IonBuilder::testNotDefinedProperty(MDefinition* obj, jsid id)
 {
     TemporaryTypeSet* types = obj->resultTypeSet();
     if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType::Object)
-        return false;
+        return ResultWithOOM<bool>::ok(false);
 
     for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) {
         TypeSet::ObjectKey* key = types->getObject(i);
         if (!key)
             continue;
 
         while (true) {
+            if (!alloc().ensureBallast())
+                return ResultWithOOM<bool>::fail();
+
             if (!key->hasStableClassAndProto(constraints()) || key->unknownProperties())
-                return false;
+                return ResultWithOOM<bool>::ok(false);
 
             const Class* clasp = key->clasp();
             if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, id))
-                return false;
+                return ResultWithOOM<bool>::ok(false);
 
             // If the object is a singleton, we can do a lookup now to avoid
             // unnecessary invalidations later on, in case the property types
             // have not yet been instantiated.
             if (key->isSingleton() &&
                 key->singleton()->is<NativeObject>() &&
                 key->singleton()->as<NativeObject>().lookupPure(id))
             {
-                return false;
+                return ResultWithOOM<bool>::ok(false);
             }
 
             HeapTypeSetKey property = key->property(id);
             if (property.isOwnProperty(constraints()))
-                return false;
+                return ResultWithOOM<bool>::ok(false);
 
             JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull());
             if (!proto)
                 break;
             key = TypeSet::ObjectKey::get(proto);
         }
     }
 
-    return true;
+    return ResultWithOOM<bool>::ok(true);
 }
 
 bool
 IonBuilder::pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, BarrierKind kind)
 {
     MOZ_ASSERT(def == current->peek(-1));
 
     MDefinition* replace = addTypeBarrier(current->pop(), observed, kind);
@@ -11681,17 +11684,20 @@ IonBuilder::getPropTryNotDefined(bool* e
     MOZ_ASSERT(*emitted == false);
 
     if (!types->mightBeMIRType(MIRType::Undefined)) {
         // Only optimize if we expect this property access to return undefined.
         trackOptimizationOutcome(TrackedOutcome::NotUndefined);
         return true;
     }
 
-    if (!testNotDefinedProperty(obj, id)) {
+    ResultWithOOM<bool> res = testNotDefinedProperty(obj, id);
+    if (res.oom)
+        return false;
+    if (!res.value) {
         trackOptimizationOutcome(TrackedOutcome::GenericFailure);
         return true;
     }
 
     obj->setImplicitlyUsedUnchecked();
     pushConstant(UndefinedValue());
 
     trackOptimizationSuccess();
@@ -13798,17 +13804,20 @@ IonBuilder::inTryFold(bool* emitted, MDe
     MConstant* idConst = id->maybeConstantValue();
     jsid propId;
     if (!idConst || !ValueToIdPure(idConst->toJSValue(), &propId))
         return true;
 
     if (propId != IdToTypeId(propId))
         return true;
 
-    if (!testNotDefinedProperty(obj, propId))
+    ResultWithOOM<bool> res = testNotDefinedProperty(obj, propId);
+    if (res.oom)
+        return false;
+    if (!res.value)
         return true;
 
     *emitted = true;
 
     pushConstant(BooleanValue(false));
     obj->setImplicitlyUsedUnchecked();
     id->setImplicitlyUsedUnchecked();
     return true;
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -1043,17 +1043,17 @@ class IonBuilder
 
     MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo);
 
     JSObject* testGlobalLexicalBinding(PropertyName* name);
 
     JSObject* testSingletonProperty(JSObject* obj, jsid id);
     JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
 
-    MOZ_MUST_USE bool testNotDefinedProperty(MDefinition* obj, jsid id);
+    ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
 
     uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
     MDefinition* convertUnboxedObjects(MDefinition* obj);
     MDefinition* convertUnboxedObjects(MDefinition* obj,
                                        const BaselineInspector::ObjectGroupVector& list);
     uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
                               JSValueType* punboxedType);
     MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -39,16 +39,29 @@ namespace js {
 
 class StringObject;
 
 namespace jit {
 
 class BaselineInspector;
 class Range;
 
+template <typename T>
+struct ResultWithOOM {
+    T value;
+    bool oom;
+
+    static ResultWithOOM<T> ok(T val) {
+        return { val, false };
+    }
+    static ResultWithOOM<T> fail() {
+        return { T(), true };
+    }
+};
+
 static inline
 MIRType MIRTypeFromValue(const js::Value& vp)
 {
     if (vp.isDouble())
         return MIRType::Double;
     if (vp.isMagic()) {
         switch (vp.whyMagic()) {
           case JS_OPTIMIZED_ARGUMENTS: