js/src/jsapi-tests/testArrayBuffer.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 */
michael@0 4
michael@0 5 #include "jsfriendapi.h"
michael@0 6
michael@0 7 #include "jsapi-tests/tests.h"
michael@0 8
michael@0 9 BEGIN_TEST(testArrayBuffer_bug720949_steal)
michael@0 10 {
michael@0 11 static const unsigned NUM_TEST_BUFFERS = 2;
michael@0 12 static const unsigned MAGIC_VALUE_1 = 3;
michael@0 13 static const unsigned MAGIC_VALUE_2 = 17;
michael@0 14
michael@0 15 JS::RootedObject buf_len1(cx), buf_len200(cx);
michael@0 16 JS::RootedObject tarray_len1(cx), tarray_len200(cx);
michael@0 17
michael@0 18 uint32_t sizes[NUM_TEST_BUFFERS] = { sizeof(uint32_t), 200 * sizeof(uint32_t) };
michael@0 19 JS::HandleObject testBuf[NUM_TEST_BUFFERS] = { buf_len1, buf_len200 };
michael@0 20 JS::HandleObject testArray[NUM_TEST_BUFFERS] = { tarray_len1, tarray_len200 };
michael@0 21
michael@0 22 // Single-element ArrayBuffer (uses fixed slots for storage)
michael@0 23 CHECK(buf_len1 = JS_NewArrayBuffer(cx, sizes[0]));
michael@0 24 CHECK(tarray_len1 = JS_NewInt32ArrayWithBuffer(cx, testBuf[0], 0, -1));
michael@0 25
michael@0 26 JS_SetElement(cx, testArray[0], 0, MAGIC_VALUE_1);
michael@0 27
michael@0 28 // Many-element ArrayBuffer (uses dynamic storage)
michael@0 29 CHECK(buf_len200 = JS_NewArrayBuffer(cx, 200 * sizeof(uint32_t)));
michael@0 30 CHECK(tarray_len200 = JS_NewInt32ArrayWithBuffer(cx, testBuf[1], 0, -1));
michael@0 31
michael@0 32 for (unsigned i = 0; i < NUM_TEST_BUFFERS; i++) {
michael@0 33 JS::HandleObject obj = testBuf[i];
michael@0 34 JS::HandleObject view = testArray[i];
michael@0 35 uint32_t size = sizes[i];
michael@0 36 JS::RootedValue v(cx);
michael@0 37
michael@0 38 // Byte lengths should all agree
michael@0 39 CHECK(JS_IsArrayBufferObject(obj));
michael@0 40 CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), size);
michael@0 41 JS_GetProperty(cx, obj, "byteLength", &v);
michael@0 42 CHECK_SAME(v, INT_TO_JSVAL(size));
michael@0 43 JS_GetProperty(cx, view, "byteLength", &v);
michael@0 44 CHECK_SAME(v, INT_TO_JSVAL(size));
michael@0 45
michael@0 46 // Modifying the underlying data should update the value returned through the view
michael@0 47 uint8_t *data = JS_GetStableArrayBufferData(cx, obj);
michael@0 48 CHECK(data != nullptr);
michael@0 49 *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
michael@0 50 CHECK(JS_GetElement(cx, view, 0, &v));
michael@0 51 CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
michael@0 52
michael@0 53 // Steal the contents
michael@0 54 void *contents = JS_StealArrayBufferContents(cx, obj);
michael@0 55 CHECK(contents != nullptr);
michael@0 56 CHECK(data != nullptr);
michael@0 57
michael@0 58 // Check that the original ArrayBuffer is neutered
michael@0 59 CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0);
michael@0 60 CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
michael@0 61 CHECK_SAME(v, INT_TO_JSVAL(0));
michael@0 62 CHECK(JS_GetProperty(cx, view, "byteLength", &v));
michael@0 63 CHECK_SAME(v, INT_TO_JSVAL(0));
michael@0 64 CHECK(JS_GetProperty(cx, view, "byteOffset", &v));
michael@0 65 CHECK_SAME(v, INT_TO_JSVAL(0));
michael@0 66 CHECK(JS_GetProperty(cx, view, "length", &v));
michael@0 67 CHECK_SAME(v, INT_TO_JSVAL(0));
michael@0 68 CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0);
michael@0 69 v = JSVAL_VOID;
michael@0 70 JS_GetElement(cx, obj, 0, &v);
michael@0 71 CHECK_SAME(v, JSVAL_VOID);
michael@0 72
michael@0 73 // Transfer to a new ArrayBuffer
michael@0 74 JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents));
michael@0 75 CHECK(JS_IsArrayBufferObject(dst));
michael@0 76 data = JS_GetStableArrayBufferData(cx, obj);
michael@0 77
michael@0 78 JS::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1));
michael@0 79 CHECK(dstview != nullptr);
michael@0 80
michael@0 81 CHECK_EQUAL(JS_GetArrayBufferByteLength(dst), size);
michael@0 82 data = JS_GetStableArrayBufferData(cx, dst);
michael@0 83 CHECK(data != nullptr);
michael@0 84 CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
michael@0 85 CHECK(JS_GetElement(cx, dstview, 0, &v));
michael@0 86 CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
michael@0 87 }
michael@0 88
michael@0 89 return true;
michael@0 90 }
michael@0 91 END_TEST(testArrayBuffer_bug720949_steal)
michael@0 92
michael@0 93 // Varying number of views of a buffer, to test the neutering weak pointers
michael@0 94 BEGIN_TEST(testArrayBuffer_bug720949_viewList)
michael@0 95 {
michael@0 96 JS::RootedObject buffer(cx);
michael@0 97
michael@0 98 // No views
michael@0 99 buffer = JS_NewArrayBuffer(cx, 2000);
michael@0 100 buffer = nullptr;
michael@0 101 GC(cx);
michael@0 102
michael@0 103 // One view.
michael@0 104 {
michael@0 105 buffer = JS_NewArrayBuffer(cx, 2000);
michael@0 106 JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
michael@0 107 void *contents = JS_StealArrayBufferContents(cx, buffer);
michael@0 108 CHECK(contents != nullptr);
michael@0 109 JS_free(nullptr, contents);
michael@0 110 GC(cx);
michael@0 111 CHECK(isNeutered(view));
michael@0 112 CHECK(isNeutered(buffer));
michael@0 113 view = nullptr;
michael@0 114 GC(cx);
michael@0 115 buffer = nullptr;
michael@0 116 GC(cx);
michael@0 117 }
michael@0 118
michael@0 119 // Two views
michael@0 120 {
michael@0 121 buffer = JS_NewArrayBuffer(cx, 2000);
michael@0 122
michael@0 123 JS::RootedObject view1(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
michael@0 124 JS::RootedObject view2(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200));
michael@0 125
michael@0 126 // Remove, re-add a view
michael@0 127 view2 = nullptr;
michael@0 128 GC(cx);
michael@0 129 view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200);
michael@0 130
michael@0 131 // Neuter
michael@0 132 void *contents = JS_StealArrayBufferContents(cx, buffer);
michael@0 133 CHECK(contents != nullptr);
michael@0 134 JS_free(nullptr, contents);
michael@0 135
michael@0 136 CHECK(isNeutered(view1));
michael@0 137 CHECK(isNeutered(view2));
michael@0 138 CHECK(isNeutered(buffer));
michael@0 139
michael@0 140 view1 = nullptr;
michael@0 141 GC(cx);
michael@0 142 view2 = nullptr;
michael@0 143 GC(cx);
michael@0 144 buffer = nullptr;
michael@0 145 GC(cx);
michael@0 146 }
michael@0 147
michael@0 148 return true;
michael@0 149 }
michael@0 150
michael@0 151 static void GC(JSContext *cx)
michael@0 152 {
michael@0 153 JS_GC(JS_GetRuntime(cx));
michael@0 154 JS_GC(JS_GetRuntime(cx)); // Trigger another to wait for background finalization to end
michael@0 155 }
michael@0 156
michael@0 157 bool isNeutered(JS::HandleObject obj) {
michael@0 158 JS::RootedValue v(cx);
michael@0 159 return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0;
michael@0 160 }
michael@0 161
michael@0 162 END_TEST(testArrayBuffer_bug720949_viewList)

mercurial