1/*
2 * Copyright (C) 2013-2019 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 "AuxiliaryBarrier.h"
29#include "JSObject.h"
30#include <wtf/TaggedArrayStoragePtr.h>
31
32namespace JSC {
33
34class LLIntOffsetsExtractor;
35
36// This class serves two purposes:
37//
38// 1) It provides those parts of JSGenericTypedArrayView that don't depend
39// on template parameters.
40//
41// 2) It represents the DOM/WebCore-visible "JSArrayBufferView" type, which
42// C++ code uses when it wants to pass around a view of an array buffer
43// without concern for the actual type of the view.
44//
45// These two roles are quite different. (1) is just a matter of optimizing
46// compile and link times by having as much code and data as possible not
47// be subject to template specialization. (2) is *almost* a matter of
48// semantics; indeed at the very least it is a matter of obeying a contract
49// that we have with WebCore right now.
50//
51// One convenient thing that saves us from too much crazy is that
52// ArrayBufferView is not instantiable.
53
54// Typed array views have different modes depending on how big they are and
55// whether the user has done anything that requires a separate backing
56// buffer or the DOM-specified neutering capabilities.
57enum TypedArrayMode : uint32_t {
58 // Small and fast typed array. B is unused, V points to a vector
59 // allocated in copied space, and M = FastTypedArray. V's liveness is
60 // determined entirely by the view's liveness.
61 FastTypedArray,
62
63 // A large typed array that still attempts not to waste too much
64 // memory. B is initialized to point to a slot that could hold a
65 // buffer pointer, V points to a vector allocated using fastCalloc(),
66 // and M = OversizeTypedArray. V's liveness is determined entirely by
67 // the view's liveness, and the view will add a finalizer to delete V.
68 OversizeTypedArray,
69
70 // A typed array that was used in some crazy way. B's IndexingHeader
71 // is hijacked to contain a reference to the native array buffer. The
72 // native typed array view points back to the JS view. V points to a
73 // vector allocated using who-knows-what, and M = WastefulTypedArray.
74 // The view does not own the vector.
75 WastefulTypedArray,
76
77 // A data view. B is unused, V points to a vector allocated using who-
78 // knows-what, and M = DataViewMode. The view does not own the vector.
79 // There is an extra field (in JSDataView) that points to the
80 // ArrayBuffer.
81 DataViewMode
82};
83
84inline bool hasArrayBuffer(TypedArrayMode mode)
85{
86 return mode >= WastefulTypedArray;
87}
88
89// When WebCore uses a JSArrayBufferView, it expects to be able to get the native
90// ArrayBuffer and little else. This requires slowing down and wasting memory,
91// and then accessing things via the Butterfly. When JS uses a JSArrayBufferView
92// it is always via the usual methods in the MethodTable, so this class's
93// implementation of those has no need to even exist - we could at any time sink
94// code into JSGenericTypedArrayView if it was convenient.
95
96class JSArrayBufferView : public JSNonFinalObject {
97public:
98 typedef JSNonFinalObject Base;
99 static const unsigned fastSizeLimit = 1000;
100 using VectorPtr = CagedBarrierPtr<Gigacage::Primitive, void, tagCagedPtr>;
101
102 static size_t sizeOf(uint32_t length, uint32_t elementSize)
103 {
104 return (length * elementSize + sizeof(EncodedJSValue) - 1)
105 & ~(sizeof(EncodedJSValue) - 1);
106 }
107
108 static size_t allocationSize(Checked<size_t> inlineCapacity)
109 {
110 ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
111 return sizeof(JSArrayBufferView);
112 }
113
114protected:
115 class ConstructionContext {
116 WTF_MAKE_NONCOPYABLE(ConstructionContext);
117
118 public:
119 enum InitializationMode { ZeroFill, DontInitialize };
120
121 JS_EXPORT_PRIVATE ConstructionContext(VM&, Structure*, uint32_t length, uint32_t elementSize, InitializationMode = ZeroFill);
122
123 // This is only for constructing fast typed arrays. It's used by the JIT's slow path.
124 ConstructionContext(Structure*, uint32_t length, void* vector);
125
126 JS_EXPORT_PRIVATE ConstructionContext(
127 VM&, Structure*, RefPtr<ArrayBuffer>&&,
128 unsigned byteOffset, unsigned length);
129
130 enum DataViewTag { DataView };
131 ConstructionContext(
132 Structure*, RefPtr<ArrayBuffer>&&,
133 unsigned byteOffset, unsigned length, DataViewTag);
134
135 bool operator!() const { return !m_structure; }
136
137 Structure* structure() const { return m_structure; }
138 void* vector() const { return m_vector.getMayBeNull(m_length); }
139 uint32_t length() const { return m_length; }
140 TypedArrayMode mode() const { return m_mode; }
141 Butterfly* butterfly() const { return m_butterfly; }
142
143 private:
144 Structure* m_structure;
145 using VectorType = CagedPtr<Gigacage::Primitive, void, tagCagedPtr>;
146 VectorType m_vector;
147 uint32_t m_length;
148 TypedArrayMode m_mode;
149 Butterfly* m_butterfly;
150 };
151
152 JS_EXPORT_PRIVATE JSArrayBufferView(VM&, ConstructionContext&);
153 JS_EXPORT_PRIVATE void finishCreation(VM&);
154
155 static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
156
157 static void visitChildren(JSCell*, SlotVisitor&);
158
159public:
160 TypedArrayMode mode() const { return m_mode; }
161 bool hasArrayBuffer() const { return JSC::hasArrayBuffer(mode()); }
162
163 bool isShared();
164 JS_EXPORT_PRIVATE ArrayBuffer* unsharedBuffer();
165 ArrayBuffer* possiblySharedBuffer();
166 JSArrayBuffer* unsharedJSBuffer(ExecState* exec);
167 JSArrayBuffer* possiblySharedJSBuffer(ExecState* exec);
168 RefPtr<ArrayBufferView> unsharedImpl();
169 JS_EXPORT_PRIVATE RefPtr<ArrayBufferView> possiblySharedImpl();
170 bool isNeutered() { return hasArrayBuffer() && !hasVector(); }
171 void neuter();
172
173 bool hasVector() const { return !!m_vector; }
174 void* vector() const { return m_vector.getMayBeNull(length()); }
175
176 unsigned byteOffset();
177 unsigned length() const { return m_length; }
178
179 DECLARE_EXPORT_INFO;
180
181 static ptrdiff_t offsetOfVector() { return OBJECT_OFFSETOF(JSArrayBufferView, m_vector); }
182 static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSArrayBufferView, m_length); }
183 static ptrdiff_t offsetOfMode() { return OBJECT_OFFSETOF(JSArrayBufferView, m_mode); }
184
185 static RefPtr<ArrayBufferView> toWrapped(VM&, JSValue);
186
187private:
188 JS_EXPORT_PRIVATE ArrayBuffer* slowDownAndWasteMemory();
189 static void finalize(JSCell*);
190
191protected:
192 friend class LLIntOffsetsExtractor;
193
194 ArrayBuffer* existingBufferInButterfly();
195
196 static String toStringName(const JSObject*, ExecState*);
197
198 VectorPtr m_vector;
199 uint32_t m_length;
200 TypedArrayMode m_mode;
201};
202
203} // namespace JSC
204
205namespace WTF {
206
207JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::TypedArrayMode);
208
209} // namespace WTF
210