Bug 993768. Patch is sort of a tag-team effort from jwalden and jonco. r=jwalden, r=jonco, a=lsblakk
authorJeff Walden <jwalden@mit.edu>
Mon, 02 Jun 2014 11:18:35 -0700
changeset 193450 92b1334cfdc41070bad5896618e8e6d8ab7ef8dc
parent 193449 df926801dfb769862b9fec376b164886246d40e9
child 193451 ba4a8f81efdcf000414f192342ccbd14c9626c36
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden, jonco, lsblakk
bugs993768
milestone30.0
Bug 993768. Patch is sort of a tag-team effort from jwalden and jonco. r=jwalden, r=jonco, a=lsblakk
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -416,16 +416,40 @@ ArrayBufferObject::neuterViews(JSContext
 uint8_t *
 ArrayBufferObject::dataPointer() const {
     if (isSharedArrayBuffer())
         return (uint8_t *)this->as<SharedArrayBufferObject>().dataPointer();
     return (uint8_t *)elements;
 }
 
 void
+ArrayBufferObject::setNewData(ObjectElements *newHeader, uint32_t byteLength)
+{
+    JS_ASSERT(!isAsmJSArrayBuffer());
+    JS_ASSERT(!isSharedArrayBuffer());
+
+#ifdef JSGC_GENERATIONAL
+    ObjectElements *oldHeader = ObjectElements::fromElements(elements);
+    JS_ASSERT(oldHeader != newHeader);
+    JSRuntime *rt = runtimeFromMainThread();
+    if (hasDynamicElements())
+        rt->gcNursery.notifyRemovedElements(this, oldHeader);
+#endif
+
+    elements = newHeader->elements();
+
+#ifdef JSGC_GENERATIONAL
+    if (hasDynamicElements())
+        rt->gcNursery.notifyNewElements(this, newHeader);
+#endif
+
+    initElementsHeader(newHeader, byteLength);
+}
+
+void
 ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
 {
     JS_ASSERT(!isAsmJSArrayBuffer());
     JS_ASSERT(!isSharedArrayBuffer());
 
     // Grab out data before invalidating it.
     uint32_t byteLengthCopy = byteLength();
     uintptr_t oldDataPointer = uintptr_t(dataPointer());
@@ -446,45 +470,31 @@ ArrayBufferObject::changeContents(JSCont
         // Notify compiled jit code that the base pointer has moved.
         MarkObjectStateChange(cx, view);
     }
 
     // The list of views in the old header is reachable if the contents are
     // being transferred, so null it out
     SetViewList(this, nullptr);
 
-#ifdef JSGC_GENERATIONAL
-    ObjectElements *oldHeader = ObjectElements::fromElements(elements);
-    JS_ASSERT(oldHeader != newHeader);
-    JSRuntime *rt = runtimeFromMainThread();
-    if (hasDynamicElements())
-        rt->gcNursery.notifyRemovedElements(this, oldHeader);
-#endif
+    setNewData(newHeader, byteLengthCopy);
 
-    elements = newHeader->elements();
-
-#ifdef JSGC_GENERATIONAL
-    if (hasDynamicElements())
-        rt->gcNursery.notifyNewElements(this, newHeader);
-#endif
-
-    initElementsHeader(newHeader, byteLengthCopy);
     InitViewList(this, viewListHead);
 }
 
 void
 ArrayBufferObject::neuter(ObjectElements *newHeader, JSContext *cx)
 {
     MOZ_ASSERT(!isSharedArrayBuffer());
 
     ObjectElements *oldHeader = getElementsHeader();
     if (hasStealableContents() && oldHeader != newHeader) {
         MOZ_ASSERT(newHeader);
 
-        changeContents(cx, newHeader);
+        setNewData(newHeader, byteLength());
 
         FreeOp fop(cx->runtime(), false);
         fop.free_(oldHeader);
     } else {
         elements = newHeader->elements();
     }
 
     uint32_t byteLen = 0;
@@ -792,19 +802,26 @@ ArrayBufferObject::stealContents(JSConte
 
     // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do
     // it after copying out the data.
     if (!ArrayBufferObject::neuterViews(cx, buffer, newHeader->elements()))
         return false;
 
     // If the elements were transferrable, revert the buffer back to using
     // inline storage so it doesn't attempt to free the stolen elements when
-    // finalized.
-    if (stolen)
-        buffer->changeContents(cx, ObjectElements::fromElements(buffer->fixedElements()));
+    // finalized.  Be careful to preserve the view list in the process.
+    if (stolen) {
+        ArrayBufferViewObject *viewListHead = GetViewList(buffer);
+
+        SetViewList(buffer, nullptr);
+
+        buffer->setNewData(ObjectElements::fromElements(buffer->fixedElements()), 0);
+
+        InitViewList(buffer, viewListHead);
+    }
 
     buffer->neuter(newHeader, cx);
     return true;
 }
 
 void
 ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
 {
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -169,16 +169,17 @@ class ArrayBufferObject : public JSObjec
     }
 
     static uint32_t headerInitializedLength(const js::ObjectElements *header) {
         return header->initializedLength;
     }
 
     void addView(ArrayBufferViewObject *view);
 
+    void setNewData(ObjectElements *newHeader, uint32_t byteLength);
     void changeContents(JSContext *cx, ObjectElements *newHeader);
 
     /*
      * Ensure data is not stored inline in the object. Used when handing back a
      * GC-safe pointer.
      */
     static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);