2f8b0337e4d8112074c01b8cafef14b2f90867b0
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSDataViewPrototype.cpp
1 /*
2  * Copyright (C) 2013, 2016 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 "JSDataViewPrototype.h"
28
29 #include "Error.h"
30 #include "JSArrayBuffer.h"
31 #include "JSDataView.h"
32 #include "Lookup.h"
33 #include "JSCInlines.h"
34 #include "ToNativeFromValue.h"
35 #include "TypedArrayAdaptors.h"
36 #include <wtf/FlipBytes.h>
37
38 namespace JSC {
39
40 /* Source for JSDataViewPrototype.lut.h
41 @begin dataViewTable
42   getInt8               dataViewProtoFuncGetInt8             DontEnum|Function       1
43   getUint8              dataViewProtoFuncGetUint8            DontEnum|Function       1
44   getInt16              dataViewProtoFuncGetInt16            DontEnum|Function       1
45   getUint16             dataViewProtoFuncGetUint16           DontEnum|Function       1
46   getInt32              dataViewProtoFuncGetInt32            DontEnum|Function       1
47   getUint32             dataViewProtoFuncGetUint32           DontEnum|Function       1
48   getFloat32            dataViewProtoFuncGetFloat32          DontEnum|Function       1
49   getFloat64            dataViewProtoFuncGetFloat64          DontEnum|Function       1
50   setInt8               dataViewProtoFuncSetInt8             DontEnum|Function       2
51   setUint8              dataViewProtoFuncSetUint8            DontEnum|Function       2
52   setInt16              dataViewProtoFuncSetInt16            DontEnum|Function       2
53   setUint16             dataViewProtoFuncSetUint16           DontEnum|Function       2
54   setInt32              dataViewProtoFuncSetInt32            DontEnum|Function       2
55   setUint32             dataViewProtoFuncSetUint32           DontEnum|Function       2
56   setFloat32            dataViewProtoFuncSetFloat32          DontEnum|Function       2
57   setFloat64            dataViewProtoFuncSetFloat64          DontEnum|Function       2
58   buffer                dataViewProtoGetterBuffer            DontEnum|Accessor       0
59   byteLength            dataViewProtoGetterByteLength        DontEnum|Accessor       0
60   byteOffset            dataViewProtoGetterByteOffset        DontEnum|Accessor       0
61 @end
62 */
63
64 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState*);
65 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState*);
66 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState*);
67 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState*);
68 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState*);
69 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState*);
70 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState*);
71 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState*);
72 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState*);
73 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState*);
74 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState*);
75 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState*);
76 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState*);
77 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState*);
78 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState*);
79 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState*);
80 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterBuffer(ExecState*);
81 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteLength(ExecState*);
82 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteOffset(ExecState*);
83
84 }
85
86 #include "JSDataViewPrototype.lut.h"
87
88 namespace JSC {
89
90 const ClassInfo JSDataViewPrototype::s_info = {
91     "DataViewPrototype", &Base::s_info, &dataViewTable,
92     CREATE_METHOD_TABLE(JSDataViewPrototype)
93 };
94
95 JSDataViewPrototype::JSDataViewPrototype(VM& vm, Structure* structure)
96     : Base(vm, structure)
97 {
98 }
99
100 JSDataViewPrototype* JSDataViewPrototype::create(VM& vm, Structure* structure)
101 {
102     JSDataViewPrototype* prototype =
103         new (NotNull, allocateCell<JSDataViewPrototype>(vm.heap))
104         JSDataViewPrototype(vm, structure);
105     prototype->finishCreation(vm);
106     return prototype;
107 }
108
109 void JSDataViewPrototype::finishCreation(JSC::VM& vm)
110 {
111     Base::finishCreation(vm);
112     putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "DataView"), DontEnum | ReadOnly);
113 }
114
115 Structure* JSDataViewPrototype::createStructure(
116     VM& vm, JSGlobalObject* globalObject, JSValue prototype)
117 {
118     return Structure::create(
119         vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
120 }
121
122 template<typename Adaptor>
123 EncodedJSValue getData(ExecState* exec)
124 {
125     VM& vm = exec->vm();
126     auto scope = DECLARE_THROW_SCOPE(vm);
127
128     JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue());
129     if (!dataView)
130         return throwVMTypeError(exec, scope, ASCIILiteral("Receiver of DataView method must be a DataView"));
131     
132     if (!exec->argumentCount())
133         return throwVMTypeError(exec, scope, ASCIILiteral("Need at least one argument (the byteOffset)"));
134     
135     unsigned byteOffset = exec->uncheckedArgument(0).toIndex(exec, "byteOffset");
136     RETURN_IF_EXCEPTION(scope, encodedJSValue());
137     
138     bool littleEndian = false;
139     unsigned elementSize = sizeof(typename Adaptor::Type);
140     if (elementSize > 1 && exec->argumentCount() >= 2) {
141         littleEndian = exec->uncheckedArgument(1).toBoolean(exec);
142         RETURN_IF_EXCEPTION(scope, encodedJSValue());
143     }
144     
145     unsigned byteLength = dataView->length();
146     if (elementSize > byteLength || byteOffset > byteLength - elementSize)
147         return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("Out of bounds access")));
148
149     const unsigned dataSize = sizeof(typename Adaptor::Type);
150     union {
151         typename Adaptor::Type value;
152         uint8_t rawBytes[dataSize];
153     } u = { };
154
155     uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
156
157     if (needToFlipBytesIfLittleEndian(littleEndian)) {
158         for (unsigned i = dataSize; i--;)
159             u.rawBytes[i] = *dataPtr++;
160     } else {
161         for (unsigned i = 0; i < dataSize; i++)
162             u.rawBytes[i] = *dataPtr++;
163     }
164
165     return JSValue::encode(Adaptor::toJSValue(u.value));
166 }
167
168 template<typename Adaptor>
169 EncodedJSValue setData(ExecState* exec)
170 {
171     VM& vm = exec->vm();
172     auto scope = DECLARE_THROW_SCOPE(vm);
173
174     JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue());
175     if (!dataView)
176         return throwVMTypeError(exec, scope, ASCIILiteral("Receiver of DataView method must be a DataView"));
177     
178     if (exec->argumentCount() < 2)
179         return throwVMTypeError(exec, scope, ASCIILiteral("Need at least two argument (the byteOffset and value)"));
180     
181     unsigned byteOffset = exec->uncheckedArgument(0).toIndex(exec, "byteOffset");
182     RETURN_IF_EXCEPTION(scope, encodedJSValue());
183
184     const unsigned dataSize = sizeof(typename Adaptor::Type);
185     union {
186         typename Adaptor::Type value;
187         uint8_t rawBytes[dataSize];
188     } u;
189
190     u.value = toNativeFromValue<Adaptor>(exec, exec->uncheckedArgument(1));
191     RETURN_IF_EXCEPTION(scope, encodedJSValue());
192     
193     bool littleEndian = false;
194     unsigned elementSize = sizeof(typename Adaptor::Type);
195     if (elementSize > 1 && exec->argumentCount() >= 3) {
196         littleEndian = exec->uncheckedArgument(2).toBoolean(exec);
197         RETURN_IF_EXCEPTION(scope, encodedJSValue());
198     }
199     
200     unsigned byteLength = dataView->length();
201     if (elementSize > byteLength || byteOffset > byteLength - elementSize)
202         return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("Out of bounds access")));
203
204     uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
205
206     if (needToFlipBytesIfLittleEndian(littleEndian)) {
207         for (unsigned i = dataSize; i--;)
208             *dataPtr++ = u.rawBytes[i];
209     } else {
210         for (unsigned i = 0; i < dataSize; i++)
211             *dataPtr++ = u.rawBytes[i];
212     }
213
214     return JSValue::encode(jsUndefined());
215 }
216
217 #if COMPILER(CLANG)
218 #pragma clang diagnostic push
219 #pragma clang diagnostic ignored "-Wmissing-prototypes"
220 #endif
221
222 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterBuffer(ExecState* exec)
223 {
224     VM& vm = exec->vm();
225     auto scope = DECLARE_THROW_SCOPE(vm);
226
227     JSDataView* view = jsDynamicCast<JSDataView*>(exec->thisValue());
228     if (!view)
229         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
230
231     return JSValue::encode(view->possiblySharedJSBuffer(exec));
232 }
233
234 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteLength(ExecState* exec)
235 {
236     VM& vm = exec->vm();
237     auto scope = DECLARE_THROW_SCOPE(vm);
238
239     JSDataView* view = jsDynamicCast<JSDataView*>(exec->thisValue());
240     if (!view)
241         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
242
243     return JSValue::encode(jsNumber(view->length()));
244 }
245
246 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteOffset(ExecState* exec)
247 {
248     VM& vm = exec->vm();
249     auto scope = DECLARE_THROW_SCOPE(vm);
250
251     JSDataView* view = jsDynamicCast<JSDataView*>(exec->thisValue());
252     if (!view)
253         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
254
255     return JSValue::encode(jsNumber(view->byteOffset()));
256 }
257
258 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec)
259 {
260     return getData<Int8Adaptor>(exec);
261 }
262
263 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec)
264 {
265     return getData<Int16Adaptor>(exec);
266 }
267
268 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec)
269 {
270     return getData<Int32Adaptor>(exec);
271 }
272
273 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec)
274 {
275     return getData<Uint8Adaptor>(exec);
276 }
277
278 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec)
279 {
280     return getData<Uint16Adaptor>(exec);
281 }
282
283 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec)
284 {
285     return getData<Uint32Adaptor>(exec);
286 }
287
288 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec)
289 {
290     return getData<Float32Adaptor>(exec);
291 }
292
293 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec)
294 {
295     return getData<Float64Adaptor>(exec);
296 }
297
298 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec)
299 {
300     return setData<Int8Adaptor>(exec);
301 }
302
303 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec)
304 {
305     return setData<Int16Adaptor>(exec);
306 }
307
308 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec)
309 {
310     return setData<Int32Adaptor>(exec);
311 }
312
313 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec)
314 {
315     return setData<Uint8Adaptor>(exec);
316 }
317
318 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec)
319 {
320     return setData<Uint16Adaptor>(exec);
321 }
322
323 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec)
324 {
325     return setData<Uint32Adaptor>(exec);
326 }
327
328 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec)
329 {
330     return setData<Float32Adaptor>(exec);
331 }
332
333 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec)
334 {
335     return setData<Float64Adaptor>(exec);
336 }
337 #if COMPILER(CLANG)
338 #pragma clang diagnostic pop
339 #endif
340
341 } // namespace JSC