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:
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"
16 # define GET_OS_FD(a) int(_get_osfhandle(a))
19 # define GET_OS_FD(a) (a)
22 const char test_data
[] =
23 "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
24 const char test_filename
[] = "temp-bug945152_MappedArrayBuffer";
26 BEGIN_TEST(testMappedArrayBuffer_bug945152
) {
28 FILE* test_stream
= test_file
.open(test_filename
);
29 CHECK(fputs(test_data
, test_stream
) != EOF
);
33 CHECK(TestCreateObject(0, 12));
36 CHECK(TestCreateObject(8, 12));
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.
67 JSObject
* CreateNewObject(const int offset
, const int length
) {
68 int fd
= open(test_filename
, O_RDONLY
);
70 JS::CreateMappedArrayBufferContents(GET_OS_FD(fd
), offset
, length
);
75 JSObject
* obj
= JS::NewMappedArrayBufferWithContents(cx
, length
, ptr
);
77 JS::ReleaseMappedArrayBufferContents(ptr
, length
);
83 bool VerifyObject(JS::HandleObject obj
, uint32_t offset
, uint32_t length
,
85 JS::AutoCheckCannotGC nogc
;
88 CHECK(JS::IsArrayBufferObject(obj
));
89 CHECK_EQUAL(JS::GetArrayBufferByteLength(obj
), length
);
91 CHECK(JS::IsMappedArrayBufferObject(obj
));
93 CHECK(!JS::IsMappedArrayBufferObject(obj
));
96 const char* data
= reinterpret_cast<const char*>(
97 JS::GetArrayBufferData(obj
, &sharedDummy
, nogc
));
99 CHECK(memcmp(data
, test_data
+ offset
, length
) == 0);
104 bool TestCreateObject(uint32_t offset
, uint32_t length
) {
105 JS::RootedObject
obj(cx
, CreateNewObject(offset
, length
));
106 CHECK(VerifyObject(obj
, offset
, length
, true));
111 bool TestReleaseContents() {
112 int fd
= open(test_filename
, O_RDONLY
);
113 void* ptr
= JS::CreateMappedArrayBufferContents(GET_OS_FD(fd
), 0, 12);
118 JS::ReleaseMappedArrayBufferContents(ptr
, 12);
123 bool TestDetachObject() {
124 JS::RootedObject
obj(cx
, CreateNewObject(8, 12));
126 JS::DetachArrayBuffer(cx
, obj
);
127 CHECK(JS::IsDetachedArrayBufferObject(obj
));
132 bool TestCloneObject() {
133 JS::RootedObject
obj1(cx
, CreateNewObject(8, 12));
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));
147 bool TestStealContents() {
148 JS::RootedObject
obj(cx
, CreateNewObject(8, 12));
150 void* contents
= JS::StealArrayBufferContents(cx
, obj
);
152 CHECK(memcmp(contents
, test_data
+ 8, 12) == 0);
153 CHECK(JS::IsDetachedArrayBufferObject(obj
));
158 bool TestTransferObject() {
159 JS::RootedObject
obj1(cx
, CreateNewObject(8, 12));
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
)) {
169 JS::RootedObject
obj(
170 cx
, JS::NewArrayObject(cx
, JS::HandleValueArray::subarray(argv
, 0, 1)));
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
));
187 static void GC(JSContext
* cx
) {
189 // Trigger another to wait for background finalization to end.
193 END_TEST(testMappedArrayBuffer_bug945152
)