JSArrayBufferView.h
1 /* 2 * Copyright (C) 2013-2020 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 32 namespace JSC { 33 34 class 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 detaching capabilities. 57 enum TypedArrayMode : uint32_t { 58 // Legend: 59 // B: JSArrayBufferView::m_butterfly pointer 60 // V: JSArrayBufferView::m_vector pointer 61 // M: JSArrayBufferView::m_mode 62 63 // Small and fast typed array. B is unused, V points to a vector 64 // allocated in the primitive Gigacage, and M = FastTypedArray. V's 65 // liveness is determined entirely by the view's liveness. 66 FastTypedArray, 67 68 // A large typed array that still attempts not to waste too much 69 // memory. B is unused, V points to a vector allocated using 70 // Gigacage::tryMalloc(), and M = OversizeTypedArray. V's liveness is 71 // determined entirely by the view's liveness, and the view will add a 72 // finalizer to delete V. 73 OversizeTypedArray, 74 75 // A typed array that was used in some crazy way. B's IndexingHeader 76 // is hijacked to contain a reference to the native array buffer. The 77 // native typed array view points back to the JS view. V points to a 78 // vector allocated using who-knows-what, and M = WastefulTypedArray. 79 // The view does not own the vector. 80 WastefulTypedArray, 81 82 // A data view. B is unused, V points to a vector allocated using who- 83 // knows-what, and M = DataViewMode. The view does not own the vector. 84 // There is an extra field (in JSDataView) that points to the 85 // ArrayBuffer. 86 DataViewMode 87 }; 88 89 inline bool hasArrayBuffer(TypedArrayMode mode) 90 { 91 return mode >= WastefulTypedArray; 92 } 93 94 // When WebCore uses a JSArrayBufferView, it expects to be able to get the native 95 // ArrayBuffer and little else. This requires slowing down and wasting memory, 96 // and then accessing things via the Butterfly. When JS uses a JSArrayBufferView 97 // it is always via the usual methods in the MethodTable, so this class's 98 // implementation of those has no need to even exist - we could at any time sink 99 // code into JSGenericTypedArrayView if it was convenient. 100 101 class JSArrayBufferView : public JSNonFinalObject { 102 public: 103 using Base = JSNonFinalObject; 104 105 template<typename, SubspaceAccess> 106 static void subspaceFor(VM&) 107 { 108 RELEASE_ASSERT_NOT_REACHED(); 109 } 110 111 static constexpr unsigned fastSizeLimit = 1000; 112 using VectorPtr = CagedBarrierPtr<Gigacage::Primitive, void, tagCagedPtr>; 113 114 static void* nullVectorPtr() 115 { 116 VectorPtr null { }; 117 return null.rawBits(); 118 } 119 120 static size_t sizeOf(uint32_t length, uint32_t elementSize) 121 { 122 return (static_cast<size_t>(length) * elementSize + sizeof(EncodedJSValue) - 1) 123 & ~(sizeof(EncodedJSValue) - 1); 124 } 125 126 static size_t allocationSize(Checked<size_t> inlineCapacity) 127 { 128 ASSERT_UNUSED(inlineCapacity, !inlineCapacity); 129 return sizeof(JSArrayBufferView); 130 } 131 132 protected: 133 class ConstructionContext { 134 WTF_MAKE_NONCOPYABLE(ConstructionContext); 135 136 public: 137 enum InitializationMode { ZeroFill, DontInitialize }; 138 139 JS_EXPORT_PRIVATE ConstructionContext(VM&, Structure*, uint32_t length, uint32_t elementSize, InitializationMode = ZeroFill); 140 141 // This is only for constructing fast typed arrays. It's used by the JIT's slow path. 142 ConstructionContext(Structure*, uint32_t length, void* vector); 143 144 JS_EXPORT_PRIVATE ConstructionContext( 145 VM&, Structure*, RefPtr<ArrayBuffer>&&, 146 unsigned byteOffset, unsigned length); 147 148 enum DataViewTag { DataView }; 149 ConstructionContext( 150 Structure*, RefPtr<ArrayBuffer>&&, 151 unsigned byteOffset, unsigned length, DataViewTag); 152 153 bool operator!() const { return !m_structure; } 154 155 Structure* structure() const { return m_structure; } 156 void* vector() const { return m_vector.getMayBeNull(m_length); } 157 uint32_t length() const { return m_length; } 158 TypedArrayMode mode() const { return m_mode; } 159 Butterfly* butterfly() const { return m_butterfly; } 160 161 private: 162 Structure* m_structure; 163 using VectorType = CagedPtr<Gigacage::Primitive, void, tagCagedPtr>; 164 VectorType m_vector; 165 uint32_t m_length; 166 TypedArrayMode m_mode; 167 Butterfly* m_butterfly; 168 }; 169 170 JS_EXPORT_PRIVATE JSArrayBufferView(VM&, ConstructionContext&); 171 JS_EXPORT_PRIVATE void finishCreation(VM&); 172 173 static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&); 174 175 static void visitChildren(JSCell*, SlotVisitor&); 176 177 public: 178 TypedArrayMode mode() const { return m_mode; } 179 bool hasArrayBuffer() const { return JSC::hasArrayBuffer(mode()); } 180 181 bool isShared(); 182 JS_EXPORT_PRIVATE ArrayBuffer* unsharedBuffer(); 183 inline ArrayBuffer* possiblySharedBuffer(); 184 JSArrayBuffer* unsharedJSBuffer(JSGlobalObject* globalObject); 185 JSArrayBuffer* possiblySharedJSBuffer(JSGlobalObject* globalObject); 186 RefPtr<ArrayBufferView> unsharedImpl(); 187 JS_EXPORT_PRIVATE RefPtr<ArrayBufferView> possiblySharedImpl(); 188 bool isDetached() { return hasArrayBuffer() && !hasVector(); } 189 void detach(); 190 191 bool hasVector() const { return !!m_vector; } 192 void* vector() const { return m_vector.getMayBeNull(length()); } 193 194 inline unsigned byteOffset(); 195 inline Optional<unsigned> byteOffsetConcurrently(); 196 197 unsigned length() const { return m_length; } 198 unsigned byteLength() const; 199 200 DECLARE_EXPORT_INFO; 201 202 static ptrdiff_t offsetOfVector() { return OBJECT_OFFSETOF(JSArrayBufferView, m_vector); } 203 static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSArrayBufferView, m_length); } 204 static ptrdiff_t offsetOfMode() { return OBJECT_OFFSETOF(JSArrayBufferView, m_mode); } 205 206 static RefPtr<ArrayBufferView> toWrapped(VM&, JSValue); 207 static RefPtr<ArrayBufferView> toWrappedAllowShared(VM&, JSValue); 208 209 private: 210 enum Requester { Mutator, ConcurrentThread }; 211 template<Requester, typename ResultType> ResultType byteOffsetImpl(); 212 template<Requester> ArrayBuffer* possiblySharedBufferImpl(); 213 214 JS_EXPORT_PRIVATE ArrayBuffer* slowDownAndWasteMemory(); 215 static void finalize(JSCell*); 216 217 protected: 218 friend class LLIntOffsetsExtractor; 219 220 ArrayBuffer* existingBufferInButterfly(); 221 222 VectorPtr m_vector; 223 uint32_t m_length; 224 TypedArrayMode m_mode; 225 }; 226 227 } // namespace JSC 228 229 namespace WTF { 230 231 JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::TypedArrayMode); 232 233 } // namespace WTF