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
38namespace JSC {
39
40/* Source for JSDataViewPrototype.lut.h
41@begin dataViewTable
42 getInt8 dataViewProtoFuncGetInt8 DontEnum|Function 1 DataViewGetInt8
43 getUint8 dataViewProtoFuncGetUint8 DontEnum|Function 1 DataViewGetUint8
44 getInt16 dataViewProtoFuncGetInt16 DontEnum|Function 1 DataViewGetInt16
45 getUint16 dataViewProtoFuncGetUint16 DontEnum|Function 1 DataViewGetUint16
46 getInt32 dataViewProtoFuncGetInt32 DontEnum|Function 1 DataViewGetInt32
47 getUint32 dataViewProtoFuncGetUint32 DontEnum|Function 1 DataViewGetUint32
48 getFloat32 dataViewProtoFuncGetFloat32 DontEnum|Function 1 DataViewGetFloat32
49 getFloat64 dataViewProtoFuncGetFloat64 DontEnum|Function 1 DataViewGetFloat64
50 setInt8 dataViewProtoFuncSetInt8 DontEnum|Function 2 DataViewSetInt8
51 setUint8 dataViewProtoFuncSetUint8 DontEnum|Function 2 DataViewSetUint8
52 setInt16 dataViewProtoFuncSetInt16 DontEnum|Function 2 DataViewSetInt16
53 setUint16 dataViewProtoFuncSetUint16 DontEnum|Function 2 DataViewSetUint16
54 setInt32 dataViewProtoFuncSetInt32 DontEnum|Function 2 DataViewSetInt32
55 setUint32 dataViewProtoFuncSetUint32 DontEnum|Function 2 DataViewSetUint32
56 setFloat32 dataViewProtoFuncSetFloat32 DontEnum|Function 2 DataViewSetFloat32
57 setFloat64 dataViewProtoFuncSetFloat64 DontEnum|Function 2 DataViewSetFloat64
58 buffer dataViewProtoGetterBuffer DontEnum|Accessor 0
59 byteLength dataViewProtoGetterByteLength DontEnum|Accessor 0
60 byteOffset dataViewProtoGetterByteOffset DontEnum|Accessor 0
61@end
62*/
63
64EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState*);
65EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState*);
66EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState*);
67EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState*);
68EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState*);
69EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState*);
70EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState*);
71EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState*);
72EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState*);
73EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState*);
74EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState*);
75EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState*);
76EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState*);
77EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState*);
78EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState*);
79EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState*);
80EncodedJSValue JSC_HOST_CALL dataViewProtoGetterBuffer(ExecState*);
81EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteLength(ExecState*);
82EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteOffset(ExecState*);
83
84}
85
86#include "JSDataViewPrototype.lut.h"
87
88namespace JSC {
89
90const ClassInfo JSDataViewPrototype::s_info = {
91 "DataViewPrototype", &Base::s_info, &dataViewTable, nullptr,
92 CREATE_METHOD_TABLE(JSDataViewPrototype)
93};
94
95JSDataViewPrototype::JSDataViewPrototype(VM& vm, Structure* structure)
96 : Base(vm, structure)
97{
98}
99
100JSDataViewPrototype* 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
109void JSDataViewPrototype::finishCreation(JSC::VM& vm)
110{
111 Base::finishCreation(vm);
112 putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "DataView"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
113}
114
115Structure* JSDataViewPrototype::createStructure(
116 VM& vm, JSGlobalObject* globalObject, JSValue prototype)
117{
118 return Structure::create(
119 vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
120}
121
122template<typename Adaptor>
123EncodedJSValue getData(ExecState* exec)
124{
125 VM& vm = exec->vm();
126 auto scope = DECLARE_THROW_SCOPE(vm);
127
128 JSDataView* dataView = jsDynamicCast<JSDataView*>(vm, exec->thisValue());
129 if (!dataView)
130 return throwVMTypeError(exec, scope, "Receiver of DataView method must be a DataView"_s);
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, "Out of bounds access"_s));
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
165template<typename Adaptor>
166EncodedJSValue setData(ExecState* exec)
167{
168 VM& vm = exec->vm();
169 auto scope = DECLARE_THROW_SCOPE(vm);
170
171 JSDataView* dataView = jsDynamicCast<JSDataView*>(vm, exec->thisValue());
172 if (!dataView)
173 return throwVMTypeError(exec, scope, "Receiver of DataView method must be a DataView"_s);
174
175 unsigned byteOffset = exec->argument(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, "Out of bounds access"_s));
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
211IGNORE_CLANG_WARNINGS_BEGIN("missing-prototypes")
212
213EncodedJSValue JSC_HOST_CALL dataViewProtoGetterBuffer(ExecState* exec)
214{
215 VM& vm = exec->vm();
216 auto scope = DECLARE_THROW_SCOPE(vm);
217
218 JSDataView* view = jsDynamicCast<JSDataView*>(vm, exec->thisValue());
219 if (!view)
220 return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
221
222 return JSValue::encode(view->possiblySharedJSBuffer(exec));
223}
224
225EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteLength(ExecState* exec)
226{
227 VM& vm = exec->vm();
228 auto scope = DECLARE_THROW_SCOPE(vm);
229
230 JSDataView* view = jsDynamicCast<JSDataView*>(vm, exec->thisValue());
231 if (!view)
232 return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
233
234 return JSValue::encode(jsNumber(view->length()));
235}
236
237EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteOffset(ExecState* exec)
238{
239 VM& vm = exec->vm();
240 auto scope = DECLARE_THROW_SCOPE(vm);
241
242 JSDataView* view = jsDynamicCast<JSDataView*>(vm, exec->thisValue());
243 if (!view)
244 return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
245
246 return JSValue::encode(jsNumber(view->byteOffset()));
247}
248
249EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec)
250{
251 return getData<Int8Adaptor>(exec);
252}
253
254EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec)
255{
256 return getData<Int16Adaptor>(exec);
257}
258
259EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec)
260{
261 return getData<Int32Adaptor>(exec);
262}
263
264EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec)
265{
266 return getData<Uint8Adaptor>(exec);
267}
268
269EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec)
270{
271 return getData<Uint16Adaptor>(exec);
272}
273
274EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec)
275{
276 return getData<Uint32Adaptor>(exec);
277}
278
279EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec)
280{
281 return getData<Float32Adaptor>(exec);
282}
283
284EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec)
285{
286 return getData<Float64Adaptor>(exec);
287}
288
289EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec)
290{
291 return setData<Int8Adaptor>(exec);
292}
293
294EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec)
295{
296 return setData<Int16Adaptor>(exec);
297}
298
299EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec)
300{
301 return setData<Int32Adaptor>(exec);
302}
303
304EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec)
305{
306 return setData<Uint8Adaptor>(exec);
307}
308
309EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec)
310{
311 return setData<Uint16Adaptor>(exec);
312}
313
314EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec)
315{
316 return setData<Uint32Adaptor>(exec);
317}
318
319EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec)
320{
321 return setData<Float32Adaptor>(exec);
322}
323
324EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec)
325{
326 return setData<Float64Adaptor>(exec);
327}
328IGNORE_CLANG_WARNINGS_END
329
330} // namespace JSC
331