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 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 | |
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, nullptr, |
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" ), PropertyAttribute::DontEnum | PropertyAttribute::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*>(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 | |
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*>(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 | |
211 | IGNORE_CLANG_WARNINGS_BEGIN("missing-prototypes" ) |
212 | |
213 | EncodedJSValue 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 | |
225 | EncodedJSValue 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 | |
237 | EncodedJSValue 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 | |
249 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec) |
250 | { |
251 | return getData<Int8Adaptor>(exec); |
252 | } |
253 | |
254 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec) |
255 | { |
256 | return getData<Int16Adaptor>(exec); |
257 | } |
258 | |
259 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec) |
260 | { |
261 | return getData<Int32Adaptor>(exec); |
262 | } |
263 | |
264 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec) |
265 | { |
266 | return getData<Uint8Adaptor>(exec); |
267 | } |
268 | |
269 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec) |
270 | { |
271 | return getData<Uint16Adaptor>(exec); |
272 | } |
273 | |
274 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec) |
275 | { |
276 | return getData<Uint32Adaptor>(exec); |
277 | } |
278 | |
279 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec) |
280 | { |
281 | return getData<Float32Adaptor>(exec); |
282 | } |
283 | |
284 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec) |
285 | { |
286 | return getData<Float64Adaptor>(exec); |
287 | } |
288 | |
289 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec) |
290 | { |
291 | return setData<Int8Adaptor>(exec); |
292 | } |
293 | |
294 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec) |
295 | { |
296 | return setData<Int16Adaptor>(exec); |
297 | } |
298 | |
299 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec) |
300 | { |
301 | return setData<Int32Adaptor>(exec); |
302 | } |
303 | |
304 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec) |
305 | { |
306 | return setData<Uint8Adaptor>(exec); |
307 | } |
308 | |
309 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec) |
310 | { |
311 | return setData<Uint16Adaptor>(exec); |
312 | } |
313 | |
314 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec) |
315 | { |
316 | return setData<Uint32Adaptor>(exec); |
317 | } |
318 | |
319 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec) |
320 | { |
321 | return setData<Float32Adaptor>(exec); |
322 | } |
323 | |
324 | EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec) |
325 | { |
326 | return setData<Float64Adaptor>(exec); |
327 | } |
328 | IGNORE_CLANG_WARNINGS_END |
329 | |
330 | } // namespace JSC |
331 | |