Bug 1263884 - Don't report OOM when speculative shape table shrink fails r=jandem
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 18 Apr 2016 15:31:33 +0100
changeset 317383 77279d5587f2402ac9b24fde74d1cfacd29ad6bb
parent 317382 6d973d2f1bae985278756e086e7e8b5c094d0806
child 317384 f76c9c94629ca4f2936cf4602adf74e0491061c1
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1263884
milestone48.0a1
Bug 1263884 - Don't report OOM when speculative shape table shrink fails r=jandem
js/src/jit-test/tests/gc/bug-1263884.js
js/src/vm/Shape.cpp
js/src/vm/Shape.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1263884.js
@@ -0,0 +1,10 @@
+if (!('oomTest' in this))
+    quit();
+
+oomTest(function() {
+  eval(`
+    var argObj = function () { return arguments }()
+    for (var p in argObj);
+    delete argObj.callee;
+  `);
+});
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -42,20 +42,16 @@ ShapeTable::init(ExclusiveContext* cx, S
 {
     uint32_t sizeLog2 = CeilingLog2Size(entryCount_);
     uint32_t size = JS_BIT(sizeLog2);
     if (entryCount_ >= size - (size >> 2))
         sizeLog2++;
     if (sizeLog2 < MIN_SIZE_LOG2)
         sizeLog2 = MIN_SIZE_LOG2;
 
-    /*
-     * Use rt->calloc for memory accounting and overpressure handling
-     * without OOM reporting. See ShapeTable::change.
-     */
     size = JS_BIT(sizeLog2);
     entries_ = cx->pod_calloc<Entry>(size);
     if (!entries_)
         return false;
 
     MOZ_ASSERT(sizeLog2 <= HASH_BITS);
     hashShift_ = HASH_BITS - sizeLog2;
 
@@ -263,29 +259,29 @@ ShapeTable::search(jsid id)
 
     MOZ_CRASH("Shape::search failed to find an expected entry.");
 }
 
 template ShapeTable::Entry& ShapeTable::search<MaybeAdding::Adding>(jsid id);
 template ShapeTable::Entry& ShapeTable::search<MaybeAdding::NotAdding>(jsid id);
 
 bool
-ShapeTable::change(int log2Delta, ExclusiveContext* cx)
+ShapeTable::change(ExclusiveContext* cx, int log2Delta)
 {
     MOZ_ASSERT(entries_);
     MOZ_ASSERT(-1 <= log2Delta && log2Delta <= 1);
 
     /*
      * Grow, shrink, or compress by changing this->entries_.
      */
     uint32_t oldLog2 = HASH_BITS - hashShift_;
     uint32_t newLog2 = oldLog2 + log2Delta;
     uint32_t oldSize = JS_BIT(oldLog2);
     uint32_t newSize = JS_BIT(newLog2);
-    Entry* newTable = cx->pod_calloc<Entry>(newSize);
+    Entry* newTable = cx->maybe_pod_calloc<Entry>(newSize);
     if (!newTable)
         return false;
 
     /* Now that we have newTable allocated, update members. */
     MOZ_ASSERT(newLog2 <= HASH_BITS);
     hashShift_ = HASH_BITS - newLog2;
     removedCount_ = 0;
     Entry* oldTable = entries_;
@@ -313,21 +309,21 @@ ShapeTable::grow(ExclusiveContext* cx)
 {
     MOZ_ASSERT(needsToGrow());
 
     uint32_t size = capacity();
     int delta = removedCount_ < (size >> 2);
 
     MOZ_ASSERT(entryCount_ + removedCount_ <= size - 1);
 
-    if (!change(delta, cx)) {
-        if (entryCount_ + removedCount_ == size - 1)
+    if (!change(cx, delta)) {
+        if (entryCount_ + removedCount_ == size - 1) {
+            ReportOutOfMemory(cx);
             return false;
-
-        cx->recoverFromOutOfMemory();
+        }
     }
 
     return true;
 }
 
 void
 ShapeTable::trace(JSTracer* trc)
 {
@@ -1043,17 +1039,17 @@ NativeObject::removeProperty(ExclusiveCo
         }
 
         /* Generate a new shape for the object, infallibly. */
         JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
 
         /* Consider shrinking table if its load factor is <= .25. */
         uint32_t size = table.capacity();
         if (size > ShapeTable::MIN_SIZE && table.entryCount() <= size >> 2)
-            (void) table.change(-1, cx);
+            (void) table.change(cx, -1);
     } else {
         /*
          * Non-dictionary-mode shape tables are shared immutables, so all we
          * need do is retract the last property and we'll either get or else
          * lazily make via a later hashify the exact table for the new property
          * lineage.
          */
         MOZ_ASSERT(shape == self->lastProperty());
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -212,23 +212,21 @@ class ShapeTable {
     /*
      * This counts the ShapeTable object itself (which must be
      * heap-allocated) and its |entries| array.
      */
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
         return mallocSizeOf(this) + mallocSizeOf(entries_);
     }
 
-    /*
-     * NB: init and change are fallible but do not report OOM, so callers can
-     * cope or ignore. They do however use the context's calloc method in
-     * order to update the malloc counter on success.
-     */
+    // init() is fallible and reports OOM to the context.
     bool init(ExclusiveContext* cx, Shape* lastProp);
-    bool change(int log2Delta, ExclusiveContext* cx);
+
+    // change() is fallible but does not report OOM.
+    bool change(ExclusiveContext* cx, int log2Delta);
 
     template<MaybeAdding Adding>
     Entry& search(jsid id);
 
     void trace(JSTracer* trc);
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkAfterMovingGC();
 #endif