b3744542040d925fa5999dfc519f219dcdeded13
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSArrayBufferView.cpp
1 /*
2  * Copyright (C) 2013-2017 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 #include "config.h"
27 #include "JSArrayBufferView.h"
28
29 #include "JSArrayBuffer.h"
30 #include "JSCInlines.h"
31 #include "TypeError.h"
32 #include "TypedArrayController.h"
33 #include <wtf/Gigacage.h>
34
35 namespace JSC {
36
37 const ClassInfo JSArrayBufferView::s_info = {
38     "ArrayBufferView", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSArrayBufferView)
39 };
40
41 String JSArrayBufferView::toStringName(const JSObject*, ExecState*)
42 {
43     return ASCIILiteral("Object");
44 }
45
46 JSArrayBufferView::ConstructionContext::ConstructionContext(
47     Structure* structure, uint32_t length, void* vector)
48     : m_structure(structure)
49     , m_vector(vector)
50     , m_length(length)
51     , m_mode(FastTypedArray)
52     , m_butterfly(nullptr)
53 {
54     RELEASE_ASSERT(length <= fastSizeLimit);
55 }
56
57 JSArrayBufferView::ConstructionContext::ConstructionContext(
58     VM& vm, Structure* structure, uint32_t length, uint32_t elementSize,
59     InitializationMode mode)
60     : m_structure(0)
61     , m_length(length)
62     , m_butterfly(0)
63 {
64     if (length <= fastSizeLimit) {
65         // Attempt GC allocation.
66         void* temp;
67         size_t size = sizeOf(length, elementSize);
68         if (size) {
69             temp = vm.primitiveGigacageAuxiliarySpace.allocateNonVirtual(vm, size, nullptr, AllocationFailureMode::ReturnNull);
70             if (!temp)
71                 return;
72         } else
73             temp = nullptr;
74
75         m_structure = structure;
76         m_vector = temp;
77         m_mode = FastTypedArray;
78
79         if (mode == ZeroFill) {
80             uint64_t* asWords = static_cast<uint64_t*>(m_vector.getMayBeNull());
81             for (unsigned i = size / sizeof(uint64_t); i--;)
82                 asWords[i] = 0;
83         }
84         
85         return;
86     }
87
88     // Don't allow a typed array to use more than 2GB.
89     if (length > static_cast<unsigned>(INT_MAX) / elementSize)
90         return;
91     
92     size_t size = static_cast<size_t>(length) * static_cast<size_t>(elementSize);
93     m_vector = Gigacage::tryMalloc(Gigacage::Primitive, size);
94     if (!m_vector)
95         return;
96     if (mode == ZeroFill)
97         memset(m_vector.get(), 0, size);
98     
99     vm.heap.reportExtraMemoryAllocated(static_cast<size_t>(length) * elementSize);
100     
101     m_structure = structure;
102     m_mode = OversizeTypedArray;
103 }
104
105 JSArrayBufferView::ConstructionContext::ConstructionContext(
106     VM& vm, Structure* structure, RefPtr<ArrayBuffer>&& arrayBuffer,
107     unsigned byteOffset, unsigned length)
108     : m_structure(structure)
109     , m_length(length)
110     , m_mode(WastefulTypedArray)
111 {
112     m_vector = static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset;
113     IndexingHeader indexingHeader;
114     indexingHeader.setArrayBuffer(arrayBuffer.get());
115     m_butterfly = Butterfly::create(vm, 0, 0, 0, true, indexingHeader, 0);
116 }
117
118 JSArrayBufferView::ConstructionContext::ConstructionContext(
119     Structure* structure, RefPtr<ArrayBuffer>&& arrayBuffer,
120     unsigned byteOffset, unsigned length, DataViewTag)
121     : m_structure(structure)
122     , m_length(length)
123     , m_mode(DataViewMode)
124     , m_butterfly(0)
125 {
126     m_vector = static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset;
127 }
128
129 JSArrayBufferView::JSArrayBufferView(VM& vm, ConstructionContext& context)
130     : Base(vm, context.structure(), nullptr)
131     , m_length(context.length())
132     , m_mode(context.mode())
133 {
134     setButterfly(vm, context.butterfly());
135     m_vector.setWithoutBarrier(context.vector());
136 }
137
138 void JSArrayBufferView::finishCreation(VM& vm)
139 {
140     Base::finishCreation(vm);
141     ASSERT(jsDynamicCast<JSArrayBufferView*>(vm, this));
142     switch (m_mode) {
143     case FastTypedArray:
144         return;
145     case OversizeTypedArray:
146         vm.heap.addFinalizer(this, finalize);
147         return;
148     case WastefulTypedArray:
149         vm.heap.addReference(this, butterfly()->indexingHeader()->arrayBuffer());
150         return;
151     case DataViewMode:
152         ASSERT(!butterfly());
153         vm.heap.addReference(this, jsCast<JSDataView*>(this)->possiblySharedBuffer());
154         return;
155     }
156     RELEASE_ASSERT_NOT_REACHED();
157 }
158
159 void JSArrayBufferView::visitChildren(JSCell* cell, SlotVisitor& visitor)
160 {
161     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
162
163     if (thisObject->hasArrayBuffer()) {
164         WTF::loadLoadFence();
165         ArrayBuffer* buffer = thisObject->possiblySharedBuffer();
166         RELEASE_ASSERT(buffer);
167         visitor.addOpaqueRoot(buffer);
168     }
169     
170     Base::visitChildren(thisObject, visitor);
171 }
172
173 bool JSArrayBufferView::put(
174     JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value,
175     PutPropertySlot& slot)
176 {
177     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
178
179     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
180         return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
181     
182     return Base::put(thisObject, exec, propertyName, value, slot);
183 }
184
185 ArrayBuffer* JSArrayBufferView::unsharedBuffer()
186 {
187     ArrayBuffer* result = possiblySharedBuffer();
188     RELEASE_ASSERT(!result->isShared());
189     return result;
190 }
191     
192 void JSArrayBufferView::finalize(JSCell* cell)
193 {
194     JSArrayBufferView* thisObject = static_cast<JSArrayBufferView*>(cell);
195     ASSERT(thisObject->m_mode == OversizeTypedArray || thisObject->m_mode == WastefulTypedArray);
196     if (thisObject->m_mode == OversizeTypedArray)
197         Gigacage::free(Gigacage::Primitive, thisObject->m_vector.get());
198 }
199
200 JSArrayBuffer* JSArrayBufferView::unsharedJSBuffer(ExecState* exec)
201 {
202     return exec->vm().m_typedArrayController->toJS(exec, globalObject(), unsharedBuffer());
203 }
204
205 JSArrayBuffer* JSArrayBufferView::possiblySharedJSBuffer(ExecState* exec)
206 {
207     return exec->vm().m_typedArrayController->toJS(exec, globalObject(), possiblySharedBuffer());
208 }
209
210 void JSArrayBufferView::neuter()
211 {
212     RELEASE_ASSERT(hasArrayBuffer());
213     RELEASE_ASSERT(!isShared());
214     m_length = 0;
215     m_vector.clear();
216 }
217
218 } // namespace JSC
219
220 namespace WTF {
221
222 using namespace JSC;
223
224 void printInternal(PrintStream& out, TypedArrayMode mode)
225 {
226     switch (mode) {
227     case FastTypedArray:
228         out.print("FastTypedArray");
229         return;
230     case OversizeTypedArray:
231         out.print("OversizeTypedArray");
232         return;
233     case WastefulTypedArray:
234         out.print("WastefulTypedArray");
235         return;
236     case DataViewMode:
237         out.print("DataViewMode");
238         return;
239     }
240     RELEASE_ASSERT_NOT_REACHED();
241 }
242
243 } // namespace WTF
244