js/src/jsapi-tests/testArrayBuffer.cpp

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

mercurial