Typed arrays should be rewritten
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSArrayBufferView.cpp
1 /*
2  * Copyright (C) 2013 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 "Operations.h"
31 #include "Reject.h"
32
33 namespace JSC {
34
35 const ClassInfo JSArrayBufferView::s_info = {
36     "ArrayBufferView", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBufferView)
37 };
38
39 JSArrayBufferView::ConstructionContext::ConstructionContext(
40     VM& vm, Structure* structure, uint32_t length, uint32_t elementSize,
41     InitializationMode mode)
42     : m_structure(0)
43     , m_length(length)
44     , m_butterfly(0)
45 {
46     if (length <= fastSizeLimit) {
47         // Attempt GC allocation.
48         void* temp;
49         size_t size = sizeOf(length, elementSize);
50         if (!vm.heap.tryAllocateStorage(0, size, &temp))
51             return;
52
53         m_structure = structure;
54         m_vector = temp;
55         m_mode = FastTypedArray;
56
57 #if USE(JSVALUE32_64)
58         if (mode == ZeroFill) {
59             uint64_t* asWords = static_cast<uint64_t*>(m_vector);
60             for (unsigned i = size / sizeof(uint64_t); i--;)
61                 asWords[i] = 0;
62         }
63 #endif // USE(JSVALUE32_64)
64         
65         return;
66     }
67
68     // Don't allow a typed array to use more than 2GB.
69     if (length > static_cast<unsigned>(INT_MAX) / elementSize)
70         return;
71     
72     if (mode == ZeroFill) {
73         if (!tryFastCalloc(length, elementSize).getValue(m_vector))
74             return;
75     } else {
76         if (!tryFastMalloc(length * elementSize).getValue(m_vector))
77             return;
78     }
79     
80     vm.heap.reportExtraMemoryCost(static_cast<size_t>(length) * elementSize);
81     
82     m_structure = structure;
83     m_mode = OversizeTypedArray;
84 }
85
86 JSArrayBufferView::ConstructionContext::ConstructionContext(
87     VM& vm, Structure* structure, PassRefPtr<ArrayBuffer> arrayBuffer,
88     unsigned byteOffset, unsigned length)
89     : m_structure(structure)
90     , m_vector(static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset)
91     , m_length(length)
92     , m_mode(WastefulTypedArray)
93 {
94     IndexingHeader indexingHeader;
95     indexingHeader.setArrayBuffer(arrayBuffer.get());
96     m_butterfly = Butterfly::create(vm, 0, 0, 0, true, indexingHeader, 0);
97 }
98
99 JSArrayBufferView::JSArrayBufferView(VM& vm, ConstructionContext& context)
100     : Base(vm, context.structure(), context.butterfly())
101     , m_vector(context.vector())
102     , m_length(context.length())
103     , m_mode(context.mode())
104 {
105 }
106
107 void JSArrayBufferView::finishCreation(VM& vm)
108 {
109     Base::finishCreation(vm);
110     switch (m_mode) {
111     case FastTypedArray:
112         return;
113     case OversizeTypedArray:
114         vm.heap.addFinalizer(this, finalize);
115         return;
116     case WastefulTypedArray:
117         vm.heap.addReference(this, butterfly()->indexingHeader()->arrayBuffer());
118         return;
119     }
120     RELEASE_ASSERT_NOT_REACHED();
121 }
122
123 bool JSArrayBufferView::getOwnPropertySlot(
124     JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
125 {
126     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
127     if (propertyName == exec->propertyNames().byteOffset) {
128         slot.setValue(thisObject, jsNumber(thisObject->byteOffset()));
129         return true;
130     }
131     
132     if (propertyName == exec->propertyNames().buffer) {
133         slot.setValue(
134             thisObject, exec->vm().m_typedArrayController->toJS(
135                 exec, thisObject->globalObject(), thisObject->buffer()));
136         return true;
137     }
138     
139     return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
140 }
141
142 bool JSArrayBufferView::getOwnPropertyDescriptor(
143     JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
144 {
145     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
146     if (propertyName == exec->propertyNames().byteOffset) {
147         descriptor.setDescriptor(jsNumber(thisObject->byteOffset()), DontDelete | ReadOnly);
148         return true;
149     }
150     
151     if (propertyName == exec->propertyNames().buffer) {
152         descriptor.setDescriptor(
153             exec->vm().m_typedArrayController->toJS(
154                 exec, thisObject->globalObject(), thisObject->buffer()),
155             DontDelete | ReadOnly);
156         return true;
157     }
158     
159     return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
160 }
161
162 void JSArrayBufferView::put(
163     JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value,
164     PutPropertySlot& slot)
165 {
166     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
167     if (propertyName == exec->propertyNames().byteLength
168         || propertyName == exec->propertyNames().byteOffset
169         || propertyName == exec->propertyNames().buffer) {
170         reject(exec, slot.isStrictMode(), "Attempting to write to read-only typed array property.");
171         return;
172     }
173     
174     Base::put(thisObject, exec, propertyName, value, slot);
175 }
176
177 bool JSArrayBufferView::defineOwnProperty(
178     JSObject* object, ExecState* exec, PropertyName propertyName,
179     PropertyDescriptor& descriptor, bool shouldThrow)
180 {
181     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
182     if (propertyName == exec->propertyNames().byteLength
183         || propertyName == exec->propertyNames().byteOffset
184         || propertyName == exec->propertyNames().buffer)
185         return reject(exec, shouldThrow, "Attempting to define read-only typed array property.");
186     
187     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
188 }
189
190 bool JSArrayBufferView::deleteProperty(
191     JSCell* cell, ExecState* exec, PropertyName propertyName)
192 {
193     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
194     if (propertyName == exec->propertyNames().byteLength
195         || propertyName == exec->propertyNames().byteOffset
196         || propertyName == exec->propertyNames().buffer)
197         return false;
198     
199     return Base::deleteProperty(thisObject, exec, propertyName);
200 }
201
202 void JSArrayBufferView::getOwnNonIndexPropertyNames(
203     JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
204 {
205     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
206     
207     // length/byteOffset/byteLength are DontEnum, at least in Firefox.
208     if (mode == IncludeDontEnumProperties) {
209         array.add(exec->propertyNames().byteOffset);
210         array.add(exec->propertyNames().byteLength);
211         array.add(exec->propertyNames().buffer);
212     }
213     
214     Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
215 }
216
217 void JSArrayBufferView::finalize(JSCell* cell)
218 {
219     JSArrayBufferView* thisObject = static_cast<JSArrayBufferView*>(cell);
220     ASSERT(thisObject->m_mode == OversizeTypedArray || thisObject->m_mode == WastefulTypedArray);
221     if (thisObject->m_mode == OversizeTypedArray)
222         fastFree(thisObject->m_vector);
223 }
224
225 } // namespace JSC
226