Bug 1497107: Add ensureBallast call to freezePropertiesForCommonPrototype r=nbp
authorIain Ireland <iireland@mozilla.com>
Mon, 19 Nov 2018 12:54:06 +0000
changeset 503675 136188d4f9281e3cec98699de83accbb0ad79439
parent 503674 2d8d64aff05a9af6af00a99c7922b86ad9d1bb55
child 503676 e71f2bd051cf58c2fa805d8dce0032a6c5e77af8
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1497107
milestone65.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 1497107: Add ensureBallast call to freezePropertiesForCommonPrototype r=nbp Differential Revision: https://phabricator.services.mozilla.com/D12184
js/src/jit-test/tests/ion/bug1497107.js
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1497107.js
@@ -0,0 +1,37 @@
+function makeChain(n, base) {
+    var curr = base;
+    for (var i = 0; i < n; i++) {
+	curr = Object.create(curr);
+	var propname = "level" + i;
+	curr[propname] = true;
+    }
+    return curr;
+}
+
+function BaseClass() {
+    this.base = true;
+}
+
+Object.defineProperty(BaseClass.prototype, "getter", {get: function() { with({}){}; return this.base; }});
+
+function victim(arg) {
+    if (arg.getter) {
+	return 3;
+    } else {
+	return 4;
+    }
+}
+
+let root = new BaseClass();
+let chains = [];
+for (var i = 0; i < 6; i++) {
+    chains.push(makeChain(500, root));
+}
+
+with({}){};
+for (var i = 0; i < 1000 / 6; i++) {
+    with({}){};
+    for (var j = 0; j < chains.length; j++) {
+	victim(chains[j]);
+    }
+}
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10396,17 +10396,17 @@ IonBuilder::commonPrototypeWithGetterSet
             }
             key = TypeSet::ObjectKey::get(proto);
         }
     }
 
     return foundProto;
 }
 
-void
+AbortReasonOr<Ok>
 IonBuilder::freezePropertiesForCommonPrototype(TemporaryTypeSet* types, PropertyName* name,
                                                JSObject* foundProto,
                                                bool allowEmptyTypesforGlobal/* = false*/)
 {
     for (unsigned i = 0; i < types->getObjectCount(); i++) {
         // If we found a Singleton object's own-property, there's nothing to
         // freeze.
         if (types->getSingleton(i) == foundProto) {
@@ -10414,31 +10414,36 @@ IonBuilder::freezePropertiesForCommonPro
         }
 
         TypeSet::ObjectKey* key = types->getObject(i);
         if (!key) {
             continue;
         }
 
         while (true) {
+            if (!alloc().ensureBallast()) {
+                return abort(AbortReason::Alloc);
+            }
+
             HeapTypeSetKey property = key->property(NameToId(name));
             MOZ_ALWAYS_TRUE(!property.isOwnProperty(constraints(), allowEmptyTypesforGlobal));
 
             // Don't mark the proto. It will be held down by the shape
             // guard. This allows us to use properties found on prototypes
             // with properties unknown to TI.
             if (key->proto() == TaggedProto(foundProto)) {
                 break;
             }
             key = TypeSet::ObjectKey::get(key->proto().toObjectOrNull());
         }
     }
-}
-
-bool
+    return Ok();
+}
+
+AbortReasonOr<bool>
 IonBuilder::testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name,
                                    bool isGetter, JSFunction* getterOrSetter,
                                    MDefinition** guard,
                                    Shape* globalShape/* = nullptr*/,
                                    MDefinition** globalGuard/* = nullptr */)
 {
     MOZ_ASSERT(getterOrSetter);
     MOZ_ASSERT_IF(globalShape, globalGuard);
@@ -10450,17 +10455,17 @@ IonBuilder::testCommonGetterSetter(Tempo
     if (!foundProto || (guardGlobal && !globalShape)) {
         trackOptimizationOutcome(TrackedOutcome::MultiProtoPaths);
         return false;
     }
 
     // We can optimize the getter/setter, so freeze all involved properties to
     // ensure there isn't a lower shadowing getter or setter installed in the
     // future.
-    freezePropertiesForCommonPrototype(types, name, foundProto, guardGlobal);
+    MOZ_TRY(freezePropertiesForCommonPrototype(types, name, foundProto, guardGlobal));
 
     // Add a shape guard on the prototype we found the property on. The rest of
     // the prototype chain is guarded by TI freezes, except when name is a global
     // name. In this case, we also have to guard on the globals shape to be able
     // to optimize, because the way global property sets are handled means
     // freezing doesn't work for what we want here. Note that a shape guard is
     // good enough here, even in the proxy case, because we have ensured there
     // are no lookup hooks for this property.
@@ -11513,37 +11518,40 @@ IonBuilder::getPropTryCommonGetter(bool*
         if (inspector->commonGetPropFunction(pc, innerized, &foundProto, &lastProperty, &commonGetter,
                                               &globalShape, &isOwnProperty,
                                               receivers, convertUnboxedGroups))
         {
             bool canUseTIForGetter = false;
             if (!isOwnProperty) {
                 // If it's not an own property, try to use TI to avoid shape guards.
                 // For own properties we use the path below.
-                canUseTIForGetter = testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
-                                                           commonGetter, &guard,
-                                                           globalShape, &globalGuard);
+                MOZ_TRY_VAR(canUseTIForGetter,
+                            testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
+                                                   commonGetter, &guard,
+                                                   globalShape, &globalGuard));
             }
             if (!canUseTIForGetter) {
                 // If it's an own property or type information is bad, we can still
                 // optimize the getter if we shape guard.
                 obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
                                                     receivers, convertUnboxedGroups,
                                                     isOwnProperty);
                 if (!obj) {
                     return abort(AbortReason::Alloc);
                 }
             }
         } else if (inspector->megamorphicGetterSetterFunction(pc, /* isGetter = */ true,
                                                               &commonGetter))
         {
             // Try to use TI to guard on this getter.
-            if (!testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
-                                        commonGetter, &guard))
-            {
+            bool canUseTIForGetter = false;
+            MOZ_TRY_VAR(canUseTIForGetter,
+                        testCommonGetterSetter(objTypes, name, /* isGetter = */ true,
+                                               commonGetter, &guard));
+            if (!canUseTIForGetter) {
                 return Ok();
             }
         } else {
             // The Baseline IC didn't have any information we can use.
             return Ok();
         }
     }
 
@@ -12178,36 +12186,39 @@ IonBuilder::setPropTryCommonSetter(bool*
         if (inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, &commonSetter,
                                               &isOwnProperty,
                                               receivers, convertUnboxedGroups))
         {
             bool canUseTIForSetter = false;
             if (!isOwnProperty) {
                 // If it's not an own property, try to use TI to avoid shape guards.
                 // For own properties we use the path below.
-                canUseTIForSetter = testCommonGetterSetter(objTypes, name, /* isGetter = */ false,
-                                                           commonSetter, &guard);
+                MOZ_TRY_VAR(canUseTIForSetter,
+                            testCommonGetterSetter(objTypes, name, /* isGetter = */ false,
+                                                   commonSetter, &guard));
             }
             if (!canUseTIForSetter) {
                 // If it's an own property or type information is bad, we can still
                 // optimize the setter if we shape guard.
                 obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
                                                     receivers, convertUnboxedGroups,
                                                     isOwnProperty);
                 if (!obj) {
                     return abort(AbortReason::Alloc);
                 }
             }
         } else if (inspector->megamorphicGetterSetterFunction(pc, /* isGetter = */ false,
                                                               &commonSetter))
         {
             // Try to use TI to guard on this setter.
-            if (!testCommonGetterSetter(objTypes, name, /* isGetter = */ false,
-                                        commonSetter, &guard))
-            {
+            bool canUseTIForSetter = false;
+            MOZ_TRY_VAR(canUseTIForSetter,
+                        testCommonGetterSetter(objTypes, name, /* isGetter = */ false,
+                                               commonSetter, &guard));
+            if (!canUseTIForSetter) {
                 return Ok();
             }
         } else {
             // The Baseline IC didn't have any information we can use.
             return Ok();
         }
     }
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -803,25 +803,27 @@ class IonBuilder
     MDefinition* patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBlock* bottom);
     MDefinition* patchInlinedReturns(CallInfo& callInfo, MIRGraphReturns& returns,
                                      MBasicBlock* bottom);
     MDefinition* specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit);
 
     NativeObject* commonPrototypeWithGetterSetter(TemporaryTypeSet* types, PropertyName* name,
                                                   bool isGetter, JSFunction* getterOrSetter,
                                                   bool* guardGlobal);
-    void freezePropertiesForCommonPrototype(TemporaryTypeSet* types, PropertyName* name,
-                                            JSObject* foundProto, bool allowEmptyTypesForGlobal = false);
+    AbortReasonOr<Ok> freezePropertiesForCommonPrototype(TemporaryTypeSet* types,
+                                                         PropertyName* name, JSObject* foundProto,
+                                                         bool allowEmptyTypesForGlobal = false);
     /*
      * Callers must pass a non-null globalGuard if they pass a non-null globalShape.
      */
-    bool testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name,
-                                bool isGetter, JSFunction* getterOrSetter,
-                                MDefinition** guard, Shape* globalShape = nullptr,
-                                MDefinition** globalGuard = nullptr);
+    AbortReasonOr<bool> testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name,
+                                               bool isGetter, JSFunction* getterOrSetter,
+                                               MDefinition** guard,
+                                               Shape* globalShape = nullptr,
+                                               MDefinition** globalGuard = nullptr);
     AbortReasonOr<bool> testShouldDOMCall(TypeSet* inTypes,
                                           JSFunction* func, JSJitInfo::OpType opType);
 
     MDefinition*
     addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
                                   const BaselineInspector::ReceiverVector& receivers,
                                   const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
                                   bool isOwnProperty);