1/*
2 * Copyright (C) 2009-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "ArrayBufferSharingMode.h"
29#include "GCIncomingRefCounted.h"
30#include "Weak.h"
31#include <wtf/CagedPtr.h>
32#include <wtf/Function.h>
33#include <wtf/StdLibExtras.h>
34#include <wtf/ThreadSafeRefCounted.h>
35#include <wtf/text/WTFString.h>
36
37namespace JSC {
38
39#define MAX_ARRAY_BUFFER_SIZE 0x7fffffffu
40
41class VM;
42class ArrayBuffer;
43class ArrayBufferView;
44class JSArrayBuffer;
45
46typedef Function<void(void*)> ArrayBufferDestructorFunction;
47
48class SharedArrayBufferContents : public ThreadSafeRefCounted<SharedArrayBufferContents> {
49public:
50 SharedArrayBufferContents(void* data, ArrayBufferDestructorFunction&&);
51 ~SharedArrayBufferContents();
52
53 void* data() const { return m_data.getMayBeNull(); }
54
55private:
56 CagedPtr<Gigacage::Primitive, void> m_data;
57 ArrayBufferDestructorFunction m_destructor;
58};
59
60class ArrayBufferContents {
61 WTF_MAKE_NONCOPYABLE(ArrayBufferContents);
62public:
63 JS_EXPORT_PRIVATE ArrayBufferContents();
64 JS_EXPORT_PRIVATE ArrayBufferContents(void* data, unsigned sizeInBytes, ArrayBufferDestructorFunction&&);
65
66 JS_EXPORT_PRIVATE ArrayBufferContents(ArrayBufferContents&&);
67 JS_EXPORT_PRIVATE ArrayBufferContents& operator=(ArrayBufferContents&&);
68
69 JS_EXPORT_PRIVATE ~ArrayBufferContents();
70
71 JS_EXPORT_PRIVATE void clear();
72
73 explicit operator bool() { return !!m_data; }
74
75 void* data() const { return m_data.getMayBeNull(); }
76 unsigned sizeInBytes() const { return m_sizeInBytes; }
77
78 bool isShared() const { return m_shared; }
79
80private:
81 void destroy();
82 void reset();
83
84 friend class ArrayBuffer;
85
86 enum InitializationPolicy {
87 ZeroInitialize,
88 DontInitialize
89 };
90
91 void tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy);
92
93 void makeShared();
94 void transferTo(ArrayBufferContents&);
95 void copyTo(ArrayBufferContents&);
96 void shareWith(ArrayBufferContents&);
97
98 ArrayBufferDestructorFunction m_destructor;
99 RefPtr<SharedArrayBufferContents> m_shared;
100 CagedPtr<Gigacage::Primitive, void> m_data;
101 unsigned m_sizeInBytes;
102};
103
104class ArrayBuffer : public GCIncomingRefCounted<ArrayBuffer> {
105public:
106 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize);
107 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(ArrayBuffer&);
108 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(const void* source, unsigned byteLength);
109 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(ArrayBufferContents&&);
110 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> createAdopted(const void* data, unsigned byteLength);
111 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&&);
112 JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize);
113 JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreate(ArrayBuffer&);
114 JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreate(const void* source, unsigned byteLength);
115
116 // Only for use by Uint8ClampedArray::tryCreateUninitialized and SharedBuffer::tryCreateArrayBuffer.
117 JS_EXPORT_PRIVATE static Ref<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
118 JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreateUninitialized(unsigned numElements, unsigned elementByteSize);
119
120 inline void* data();
121 inline const void* data() const;
122 inline unsigned byteLength() const;
123
124 void makeShared();
125 void setSharingMode(ArrayBufferSharingMode);
126 inline bool isShared() const;
127 inline ArrayBufferSharingMode sharingMode() const { return isShared() ? ArrayBufferSharingMode::Shared : ArrayBufferSharingMode::Default; }
128
129 inline size_t gcSizeEstimateInBytes() const;
130
131 JS_EXPORT_PRIVATE Ref<ArrayBuffer> slice(double begin, double end) const;
132 JS_EXPORT_PRIVATE Ref<ArrayBuffer> slice(double begin) const;
133
134 inline void pin();
135 inline void unpin();
136 inline void pinAndLock();
137 inline bool isLocked();
138
139 void makeWasmMemory();
140 inline bool isWasmMemory();
141
142 JS_EXPORT_PRIVATE bool transferTo(VM&, ArrayBufferContents&);
143 JS_EXPORT_PRIVATE bool shareWith(ArrayBufferContents&);
144
145 void neuter(VM&);
146 bool isNeutered() { return !m_contents.m_data; }
147
148 static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer, m_contents) + OBJECT_OFFSETOF(ArrayBufferContents, m_data); }
149
150 ~ArrayBuffer() { }
151
152private:
153 static Ref<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
154 static Ref<ArrayBuffer> createInternal(ArrayBufferContents&&, const void*, unsigned);
155 static RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
156 ArrayBuffer(ArrayBufferContents&&);
157 Ref<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
158 inline unsigned clampIndex(double index) const;
159 static inline unsigned clampValue(double x, unsigned left, unsigned right);
160
161 void notifyIncommingReferencesOfTransfer(VM&);
162
163 ArrayBufferContents m_contents;
164 unsigned m_pinCount : 30;
165 bool m_isWasmMemory : 1;
166 // m_locked == true means that some API user fetched m_contents directly from a TypedArray object,
167 // the buffer is backed by a WebAssembly.Memory, or is a SharedArrayBuffer.
168 bool m_locked : 1;
169
170public:
171 Weak<JSArrayBuffer> m_wrapper;
172};
173
174void* ArrayBuffer::data()
175{
176 return m_contents.m_data.getMayBeNull();
177}
178
179const void* ArrayBuffer::data() const
180{
181 return m_contents.m_data.getMayBeNull();
182}
183
184unsigned ArrayBuffer::byteLength() const
185{
186 return m_contents.m_sizeInBytes;
187}
188
189bool ArrayBuffer::isShared() const
190{
191 return m_contents.isShared();
192}
193
194size_t ArrayBuffer::gcSizeEstimateInBytes() const
195{
196 // FIXME: We probably want to scale this by the shared ref count or something.
197 return sizeof(ArrayBuffer) + static_cast<size_t>(byteLength());
198}
199
200void ArrayBuffer::pin()
201{
202 m_pinCount++;
203}
204
205void ArrayBuffer::unpin()
206{
207 m_pinCount--;
208}
209
210void ArrayBuffer::pinAndLock()
211{
212 m_locked = true;
213}
214
215bool ArrayBuffer::isLocked()
216{
217 return m_locked;
218}
219
220bool ArrayBuffer::isWasmMemory()
221{
222 return m_isWasmMemory;
223}
224
225JS_EXPORT_PRIVATE ASCIILiteral errorMesasgeForTransfer(ArrayBuffer*);
226
227} // namespace JSC
228
229using JSC::ArrayBuffer;
230