Bug 807237. Add 'data' parameter to JS_StealArrayBufferContents. r=sfink
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 02 Nov 2012 23:42:59 +1300
changeset 112158 e89f3933239117e7cadc2dc7618aaf4bb78f1b50
parent 112157 4d0cfc4fd49f0c7356cd34af8188002089a44957
child 112159 38d7dcc623a5b1f6121cf1aed0ff106e3829e7cf
push id23798
push userryanvm@gmail.com
push dateSat, 03 Nov 2012 00:06:35 +0000
treeherdermozilla-central@6134edeea902 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs807237
milestone19.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 807237. Add 'data' parameter to JS_StealArrayBufferContents. r=sfink
js/src/jsapi-tests/testArrayBuffer.cpp
js/src/jsapi.h
js/src/jsclone.cpp
js/src/jstypedarray.cpp
js/src/jstypedarray.h
--- a/js/src/jsapi-tests/testArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testArrayBuffer.cpp
@@ -47,18 +47,19 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste
         uint8_t *data = JS_GetArrayBufferData(obj, cx);
         CHECK(data != NULL);
         *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
         CHECK(JS_GetElement(cx, view, 0, &v));
         CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
 
         // Steal the contents
         void *contents;
-        CHECK(JS_StealArrayBufferContents(cx, obj, &contents));
+        CHECK(JS_StealArrayBufferContents(cx, obj, &contents, &data));
         CHECK(contents != NULL);
+        CHECK(data != NULL);
 
         // Check that the original ArrayBuffer is neutered
         CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0);
         CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "byteLength", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "byteOffset", &v));
@@ -106,19 +107,21 @@ BEGIN_TEST(testArrayBuffer_bug720949_vie
     buffer = NULL;
     GC(cx);
 
     // One view.
     {
         buffer = JS_NewArrayBuffer(cx, 2000);
         js::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
         void *contents;
-        CHECK(JS_StealArrayBufferContents(cx, buffer, &contents));
+        uint8_t *data;
+        CHECK(JS_StealArrayBufferContents(cx, buffer, &contents, &data));
         CHECK(contents != NULL);
-        JS_free(cx, contents);
+        CHECK(data != NULL);
+        JS_free(NULL, contents);
         GC(cx);
         CHECK(isNeutered(view));
         CHECK(isNeutered(buffer));
         view = NULL;
         GC(cx);
         buffer = NULL;
         GC(cx);
     }
@@ -132,19 +135,21 @@ BEGIN_TEST(testArrayBuffer_bug720949_vie
 
         // Remove, re-add a view
         view2 = NULL;
         GC(cx);
         view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200);
 
         // Neuter
         void *contents;
-        CHECK(JS_StealArrayBufferContents(cx, buffer, &contents));
+        uint8_t *data;
+        CHECK(JS_StealArrayBufferContents(cx, buffer, &contents, &data));
         CHECK(contents != NULL);
-        JS_free(cx, contents);
+        CHECK(data != NULL);
+        JS_free(NULL, contents);
 
         CHECK(isNeutered(view1));
         CHECK(isNeutered(view2));
         CHECK(isNeutered(buffer));
 
         view1 = NULL;
         GC(cx);
         view2 = NULL;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3404,16 +3404,17 @@ extern JS_PUBLIC_API(void *)
 JS_malloc(JSContext *cx, size_t nbytes);
 
 extern JS_PUBLIC_API(void *)
 JS_realloc(JSContext *cx, void *p, size_t nbytes);
 
 /*
  * A wrapper for js_free(p) that may delay js_free(p) invocation as a
  * performance optimization.
+ * cx may be NULL.
  */
 extern JS_PUBLIC_API(void)
 JS_free(JSContext *cx, void *p);
 
 /*
  * A wrapper for js_free(p) that may delay js_free(p) invocation as a
  * performance optimization as specified by the given JSFreeOp instance.
  */
@@ -4612,21 +4613,25 @@ JS_SetAllNonReservedSlotsToUndefined(JSC
  * free |contents| or use |contents| from another thread.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_NewArrayBufferWithContents(JSContext *cx, void *contents);
 
 /*
  * Steal the contents of the given array buffer. The array buffer has its
  * length set to 0 and its contents array cleared. The caller takes ownership
- * of |contents| and must free it or transfer ownership via
+ * of |*contents| and must free it or transfer ownership via
  * JS_NewArrayBufferWithContents when done using it.
- */
-extern JS_PUBLIC_API(JSBool)
-JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents);
+ * To free |*contents|, call free().
+ * A pointer to the buffer's data is returned in |*data|. This pointer can
+ * be used until |*contents| is freed or has its ownership transferred.
+ */
+extern JS_PUBLIC_API(JSBool)
+JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
+                            uint8_t **data);
 
 /*
  * Allocate memory that may be eventually passed to
  * JS_NewArrayBufferWithContents. |nbytes| is the number of payload bytes
  * required. The pointer to pass to JS_NewArrayBufferWithContents is returned
  * in |contents|. The pointer to the |nbytes| of usable memory is returned in
  * |data|. (*|contents| will contain a header before |data|.) The only legal
  * operations on *|contents| is to free it or pass it to
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -727,17 +727,18 @@ JSStructuredCloneWriter::writeTransferMa
         for (HashSet<JSObject*>::Range r = transferableObjects.all();
              !r.empty(); r.popFront()) {
             JSObject *obj = r.front();
 
             if (!memory.put(obj, memory.count()))
                 return false;
 
             void *content;
-            if (!JS_StealArrayBufferContents(context(), obj, &content))
+            uint8_t *data;
+            if (!JS_StealArrayBufferContents(context(), obj, &content, &data))
                return false;
 
             if (!out.writePair(SCTAG_TRANSFER_MAP, 0) || !out.writePtr(content))
                 return false;
         }
     }
 
     return true;
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -456,37 +456,40 @@ ArrayBufferObject::createDataViewForThis
 JSBool
 ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
 }
 
 bool
-ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents)
+ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
+                                 uint8_t **data)
 {
     ArrayBufferObject &buffer = obj->asArrayBuffer();
     JSObject *views = *GetViewList(&buffer);
     js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
     if (buffer.hasDynamicElements()) {
         *contents = header;
+        *data = buffer.dataPointer();
 
         buffer.setFixedElements();
         header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
     } else {
         uint32_t length = buffer.byteLength();
         js::ObjectElements *newheader =
             AllocateArrayBufferContents(cx, length, buffer.dataPointer());
         if (!newheader) {
             js_ReportOutOfMemory(cx);
             return false;
         }
 
         ArrayBufferObject::setElementsHeader(newheader, length);
         *contents = newheader;
+        *data = reinterpret_cast<uint8_t *>(newheader + 1);
     }
 
     // Neuter the donor ArrayBuffer and all views of it
     ArrayBufferObject::setElementsHeader(header, 0);
     *GetViewList(&buffer) = views;
     for (JSObject *view = views; view; view = NextView(view))
         TypedArray::neuter(view);
 
@@ -3670,27 +3673,28 @@ JS_AllocateArrayBufferContents(JSContext
     ArrayBufferObject::setElementsHeader(header, nbytes);
 
     *contents = header;
     *data = reinterpret_cast<uint8_t*>(header->elements());
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents)
+JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
+                            uint8_t **data)
 {
     if (!(obj = UnwrapObjectChecked(cx, obj)))
         return false;
 
     if (!obj->isArrayBuffer()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
 
-    if (!ArrayBufferObject::stealContents(cx, obj, contents))
+    if (!ArrayBufferObject::stealContents(cx, obj, contents, data))
         return false;
 
     return true;
 }
 
 JS_FRIEND_API(uint32_t)
 JS_GetTypedArrayLength(JSObject *obj, JSContext *maybecx)
 {
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -127,17 +127,18 @@ class ArrayBufferObject : public JSObjec
                                     HandleSpecialId sid, MutableHandleValue rval,
                                     JSBool strict);
 
     static JSBool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
                                 MutableHandleValue statep, MutableHandleId idp);
 
     static void sweepAll(JSRuntime *rt);
 
-    static bool stealContents(JSContext *cx, JSObject *obj, void **contents);
+    static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
+                              uint8_t **data);
 
     static inline void setElementsHeader(js::ObjectElements *header, uint32_t bytes);
 
     void addView(RawObject view);
 
     bool allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
 
     /*