test262: DataView get methods should allow for missing offset, set methods should...
[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     unsigned byteOffset = exec->argument(0).toIndex(exec, "byteOffset");
133     RETURN_IF_EXCEPTION(scope, encodedJSValue());
134     
135     bool littleEndian = false;
136     unsigned elementSize = sizeof(typename Adaptor::Type);
137     if (elementSize > 1 && exec->argumentCount() >= 2) {
138         littleEndian = exec->uncheckedArgument(1).toBoolean(exec);
139         RETURN_IF_EXCEPTION(scope, encodedJSValue());
140     }
141     
142     unsigned byteLength = dataView->length();
143     if (elementSize > byteLength || byteOffset > byteLength - elementSize)
144         return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("Out of bounds access")));
145
146     const unsigned dataSize = sizeof(typename Adaptor::Type);
147     union {
148         typename Adaptor::Type value;
149         uint8_t rawBytes[dataSize];
150     } u = { };
151
152     uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
153
154     if (needToFlipBytesIfLittleEndian(littleEndian)) {
155         for (unsigned i = dataSize; i--;)
156             u.rawBytes[i] = *dataPtr++;
157     } else {
158         for (unsigned i = 0; i < dataSize; i++)
159             u.rawBytes[i] = *dataPtr++;
160     }
161
162     return JSValue::encode(Adaptor::toJSValue(u.value));
163 }
164
165 template<typename Adaptor>
166 EncodedJSValue setData(ExecState* exec)
167 {
168     VM& vm = exec->vm();
169     auto scope = DECLARE_THROW_SCOPE(vm);
170
171     JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue());
172     if (!dataView)
173         return throwVMTypeError(exec, scope, ASCIILiteral("Receiver of DataView method must be a DataView"));
174     
175     unsigned byteOffset = exec->uncheckedArgument(0).toIndex(exec, "byteOffset");
176     RETURN_IF_EXCEPTION(scope, encodedJSValue());
177
178     const unsigned dataSize = sizeof(typename Adaptor::Type);
179     union {
180         typename Adaptor::Type value;
181         uint8_t rawBytes[dataSize];
182     } u;
183
184     u.value = toNativeFromValue<Adaptor>(exec, exec->argument(1));
185     RETURN_IF_EXCEPTION(scope, encodedJSValue());
186     
187     bool littleEndian = false;
188     unsigned elementSize = sizeof(typename Adaptor::Type);
189     if (elementSize > 1 && exec->argumentCount() >= 3) {
190         littleEndian = exec->uncheckedArgument(2).toBoolean(exec);
191         RETURN_IF_EXCEPTION(scope, encodedJSValue());
192     }
193     
194     unsigned byteLength = dataView->length();
195     if (elementSize > byteLength || byteOffset > byteLength - elementSize)
196         return throwVMError(exec, scope, createRangeError(exec, ASCIILiteral("Out of bounds access")));
197
198     uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
199
200     if (needToFlipBytesIfLittleEndian(littleEndian)) {
201         for (unsigned i = dataSize; i--;)
202             *dataPtr++ = u.rawBytes[i];
203     } else {
204         for (unsigned i = 0; i < dataSize; i++)
205             *dataPtr++ = u.rawBytes[i];
206     }
207
208     return JSValue::encode(jsUndefined());
209 }
210
211 #if COMPILER(CLANG)
212 #pragma clang diagnostic push
213 #pragma clang diagnostic ignored "-Wmissing-prototypes"
214 #endif
215
216 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterBuffer(ExecState* exec)
217 {
218     VM& vm = exec->vm();
219     auto scope = DECLARE_THROW_SCOPE(vm);
220
221     JSDataView* view = jsDynamicCast<JSDataView*>(exec->thisValue());
222     if (!view)
223         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
224
225     return JSValue::encode(view->possiblySharedJSBuffer(exec));
226 }
227
228 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteLength(ExecState* exec)
229 {
230     VM& vm = exec->vm();
231     auto scope = DECLARE_THROW_SCOPE(vm);
232
233     JSDataView* view = jsDynamicCast<JSDataView*>(exec->thisValue());
234     if (!view)
235         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
236
237     return JSValue::encode(jsNumber(view->length()));
238 }
239
240 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteOffset(ExecState* exec)
241 {
242     VM& vm = exec->vm();
243     auto scope = DECLARE_THROW_SCOPE(vm);
244
245     JSDataView* view = jsDynamicCast<JSDataView*>(exec->thisValue());
246     if (!view)
247         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
248
249     return JSValue::encode(jsNumber(view->byteOffset()));
250 }
251
252 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec)
253 {
254     return getData<Int8Adaptor>(exec);
255 }
256
257 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec)
258 {
259     return getData<Int16Adaptor>(exec);
260 }
261
262 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec)
263 {
264     return getData<Int32Adaptor>(exec);
265 }
266
267 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec)
268 {
269     return getData<Uint8Adaptor>(exec);
270 }
271
272 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec)
273 {
274     return getData<Uint16Adaptor>(exec);
275 }
276
277 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec)
278 {
279     return getData<Uint32Adaptor>(exec);
280 }
281
282 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec)
283 {
284     return getData<Float32Adaptor>(exec);
285 }
286
287 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec)
288 {
289     return getData<Float64Adaptor>(exec);
290 }
291
292 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec)
293 {
294     return setData<Int8Adaptor>(exec);
295 }
296
297 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec)
298 {
299     return setData<Int16Adaptor>(exec);
300 }
301
302 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec)
303 {
304     return setData<Int32Adaptor>(exec);
305 }
306
307 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec)
308 {
309     return setData<Uint8Adaptor>(exec);
310 }
311
312 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec)
313 {
314     return setData<Uint16Adaptor>(exec);
315 }
316
317 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec)
318 {
319     return setData<Uint32Adaptor>(exec);
320 }
321
322 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec)
323 {
324     return setData<Float32Adaptor>(exec);
325 }
326
327 EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec)
328 {
329     return setData<Float64Adaptor>(exec);
330 }
331 #if COMPILER(CLANG)
332 #pragma clang diagnostic pop
333 #endif
334
335 } // namespace JSC