Bug 1832850 - Part 5: Move the allocateObject definition into gc/Nursery.h r=jandem
[gecko.git] / js / src / jsapi-tests / testMappedArrayBuffer.cpp
blobb07303f1bdc12c4dd4dde7801096dd8e95bb71cd
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 */
5 #include <fcntl.h>
6 #include <stdio.h>
8 #include "js/Array.h" // JS::NewArrayObject
9 #include "js/ArrayBuffer.h" // JS::{{Create,Release}MappedArrayBufferContents,DetachArrayBuffer,GetArrayBuffer{ByteLength,Data},Is{,Detached,Mapped}ArrayBufferObject,NewMappedArrayBufferWithContents,StealArrayBufferContents}
10 #include "js/StructuredClone.h"
11 #include "jsapi-tests/tests.h"
12 #include "vm/ArrayBufferObject.h"
14 #ifdef XP_WIN
15 # include <io.h>
16 # define GET_OS_FD(a) int(_get_osfhandle(a))
17 #else
18 # include <unistd.h>
19 # define GET_OS_FD(a) (a)
20 #endif
22 const char test_data[] =
23 "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
24 const char test_filename[] = "temp-bug945152_MappedArrayBuffer";
26 BEGIN_TEST(testMappedArrayBuffer_bug945152) {
27 TempFile test_file;
28 FILE* test_stream = test_file.open(test_filename);
29 CHECK(fputs(test_data, test_stream) != EOF);
30 test_file.close();
32 // Offset 0.
33 CHECK(TestCreateObject(0, 12));
35 // Aligned offset.
36 CHECK(TestCreateObject(8, 12));
38 // Unaligned offset.
39 CHECK(CreateNewObject(11, 12) == nullptr);
41 // Offset + length greater than file size.
42 CHECK(CreateNewObject(8, sizeof(test_data) - 7) == nullptr);
44 // Release the mapped content.
45 CHECK(TestReleaseContents());
47 // Detach mapped array buffer.
48 CHECK(TestDetachObject());
50 // Clone mapped array buffer.
51 CHECK(TestCloneObject());
53 // Steal mapped array buffer contents.
54 CHECK(TestStealContents());
56 // Transfer mapped array buffer contents.
57 CHECK(TestTransferObject());
59 // GC so we can remove the file we created.
60 GC(cx);
62 test_file.remove();
64 return true;
67 JSObject* CreateNewObject(const int offset, const int length) {
68 int fd = open(test_filename, O_RDONLY);
69 void* ptr =
70 JS::CreateMappedArrayBufferContents(GET_OS_FD(fd), offset, length);
71 close(fd);
72 if (!ptr) {
73 return nullptr;
75 JSObject* obj = JS::NewMappedArrayBufferWithContents(cx, length, ptr);
76 if (!obj) {
77 JS::ReleaseMappedArrayBufferContents(ptr, length);
78 return nullptr;
80 return obj;
83 bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length,
84 const bool mapped) {
85 JS::AutoCheckCannotGC nogc;
87 CHECK(obj);
88 CHECK(JS::IsArrayBufferObject(obj));
89 CHECK_EQUAL(JS::GetArrayBufferByteLength(obj), length);
90 if (mapped) {
91 CHECK(JS::IsMappedArrayBufferObject(obj));
92 } else {
93 CHECK(!JS::IsMappedArrayBufferObject(obj));
95 bool sharedDummy;
96 const char* data = reinterpret_cast<const char*>(
97 JS::GetArrayBufferData(obj, &sharedDummy, nogc));
98 CHECK(data);
99 CHECK(memcmp(data, test_data + offset, length) == 0);
101 return true;
104 bool TestCreateObject(uint32_t offset, uint32_t length) {
105 JS::RootedObject obj(cx, CreateNewObject(offset, length));
106 CHECK(VerifyObject(obj, offset, length, true));
108 return true;
111 bool TestReleaseContents() {
112 int fd = open(test_filename, O_RDONLY);
113 void* ptr = JS::CreateMappedArrayBufferContents(GET_OS_FD(fd), 0, 12);
114 close(fd);
115 if (!ptr) {
116 return false;
118 JS::ReleaseMappedArrayBufferContents(ptr, 12);
120 return true;
123 bool TestDetachObject() {
124 JS::RootedObject obj(cx, CreateNewObject(8, 12));
125 CHECK(obj);
126 JS::DetachArrayBuffer(cx, obj);
127 CHECK(JS::IsDetachedArrayBufferObject(obj));
129 return true;
132 bool TestCloneObject() {
133 JS::RootedObject obj1(cx, CreateNewObject(8, 12));
134 CHECK(obj1);
135 JSAutoStructuredCloneBuffer cloned_buffer(
136 JS::StructuredCloneScope::SameProcess, nullptr, nullptr);
137 JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
138 CHECK(cloned_buffer.write(cx, v1, nullptr, nullptr));
139 JS::RootedValue v2(cx);
140 CHECK(cloned_buffer.read(cx, &v2, JS::CloneDataPolicy(), nullptr, nullptr));
141 JS::RootedObject obj2(cx, v2.toObjectOrNull());
142 CHECK(VerifyObject(obj2, 8, 12, false));
144 return true;
147 bool TestStealContents() {
148 JS::RootedObject obj(cx, CreateNewObject(8, 12));
149 CHECK(obj);
150 void* contents = JS::StealArrayBufferContents(cx, obj);
151 CHECK(contents);
152 CHECK(memcmp(contents, test_data + 8, 12) == 0);
153 CHECK(JS::IsDetachedArrayBufferObject(obj));
155 return true;
158 bool TestTransferObject() {
159 JS::RootedObject obj1(cx, CreateNewObject(8, 12));
160 CHECK(obj1);
161 JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
163 // Create an Array of transferable values.
164 JS::RootedValueVector argv(cx);
165 if (!argv.append(v1)) {
166 return false;
169 JS::RootedObject obj(
170 cx, JS::NewArrayObject(cx, JS::HandleValueArray::subarray(argv, 0, 1)));
171 CHECK(obj);
172 JS::RootedValue transferable(cx, JS::ObjectValue(*obj));
174 JSAutoStructuredCloneBuffer cloned_buffer(
175 JS::StructuredCloneScope::SameProcess, nullptr, nullptr);
176 JS::CloneDataPolicy policy;
177 CHECK(cloned_buffer.write(cx, v1, transferable, policy, nullptr, nullptr));
178 JS::RootedValue v2(cx);
179 CHECK(cloned_buffer.read(cx, &v2, policy, nullptr, nullptr));
180 JS::RootedObject obj2(cx, v2.toObjectOrNull());
181 CHECK(VerifyObject(obj2, 8, 12, true));
182 CHECK(JS::IsDetachedArrayBufferObject(obj1));
184 return true;
187 static void GC(JSContext* cx) {
188 JS_GC(cx);
189 // Trigger another to wait for background finalization to end.
190 JS_GC(cx);
193 END_TEST(testMappedArrayBuffer_bug945152)
195 #undef GET_OS_FD