1/*
2 * Copyright (C) 2015-2019 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 "JSTypedArrayViewPrototype.h"
28
29#include "BuiltinNames.h"
30#include "CallFrame.h"
31#include "GetterSetter.h"
32#include "JSCInlines.h"
33#include "JSFunction.h"
34#include "JSGenericTypedArrayViewPrototypeFunctions.h"
35#include "JSObjectInlines.h"
36#include "TypedArrayAdaptors.h"
37
38namespace JSC {
39
40#define CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(functionName) do { \
41 switch (thisValue.getObject()->classInfo(vm)->typedArrayStorageType) { \
42 case TypeUint8Clamped: \
43 return functionName<JSUint8ClampedArray>(vm, globalObject, callFrame); \
44 case TypeInt32: \
45 return functionName<JSInt32Array>(vm, globalObject, callFrame); \
46 case TypeUint32: \
47 return functionName<JSUint32Array>(vm, globalObject, callFrame); \
48 case TypeFloat64: \
49 return functionName<JSFloat64Array>(vm, globalObject, callFrame); \
50 case TypeFloat32: \
51 return functionName<JSFloat32Array>(vm, globalObject, callFrame); \
52 case TypeInt8: \
53 return functionName<JSInt8Array>(vm, globalObject, callFrame); \
54 case TypeUint8: \
55 return functionName<JSUint8Array>(vm, globalObject, callFrame); \
56 case TypeInt16: \
57 return functionName<JSInt16Array>(vm, globalObject, callFrame); \
58 case TypeUint16: \
59 return functionName<JSUint16Array>(vm, globalObject, callFrame); \
60 case NotTypedArray: \
61 case TypeDataView: \
62 return throwVMTypeError(globalObject, scope, \
63 "Receiver should be a typed array view"_s); \
64 } \
65 RELEASE_ASSERT_NOT_REACHED(); \
66} while (false)
67
68EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncIsTypedArrayView(JSGlobalObject* globalObject, CallFrame* callFrame)
69{
70 JSValue value = callFrame->uncheckedArgument(0);
71 return JSValue::encode(jsBoolean(value.isCell() && isTypedView(value.asCell()->classInfo(globalObject->vm())->typedArrayStorageType)));
72}
73
74EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncLength(JSGlobalObject* globalObject, CallFrame* callFrame)
75{
76 VM& vm = globalObject->vm();
77 auto scope = DECLARE_THROW_SCOPE(vm);
78 JSValue argument = callFrame->argument(0);
79 if (!argument.isCell() || !isTypedView(argument.asCell()->classInfo(vm)->typedArrayStorageType))
80 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view"_s);
81
82 JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(argument);
83
84 if (thisObject->isNeutered())
85 return throwVMTypeError(globalObject, scope, "Underlying ArrayBuffer has been detached from the view"_s);
86
87 return JSValue::encode(jsNumber(thisObject->length()));
88}
89
90EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncGetOriginalConstructor(JSGlobalObject* globalObject, CallFrame* callFrame)
91{
92 VM& vm = globalObject->vm();
93 TypedArrayType type = callFrame->uncheckedArgument(0).getObject()->classInfo(vm)->typedArrayStorageType;
94 ASSERT(isTypedView(type));
95 return JSValue::encode(globalObject->typedArrayConstructor(type));
96}
97
98EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSort(JSGlobalObject* globalObject, CallFrame* callFrame)
99{
100 VM& vm = globalObject->vm();
101 auto scope = DECLARE_THROW_SCOPE(vm);
102 JSValue thisValue = callFrame->argument(0);
103 scope.release();
104 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewPrivateFuncSort);
105}
106
107static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSet(JSGlobalObject* globalObject, CallFrame* callFrame)
108{
109 VM& vm = globalObject->vm();
110 auto scope = DECLARE_THROW_SCOPE(vm);
111 JSValue thisValue = callFrame->thisValue();
112 if (UNLIKELY(!thisValue.isObject()))
113 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
114 scope.release();
115 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncSet);
116}
117
118static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncCopyWithin(JSGlobalObject* globalObject, CallFrame* callFrame)
119{
120 VM& vm = globalObject->vm();
121 auto scope = DECLARE_THROW_SCOPE(vm);
122 JSValue thisValue = callFrame->thisValue();
123 if (!thisValue.isObject())
124 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
125 scope.release();
126 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncCopyWithin);
127}
128
129static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncIncludes(JSGlobalObject* globalObject, CallFrame* callFrame)
130{
131 VM& vm = globalObject->vm();
132 auto scope = DECLARE_THROW_SCOPE(vm);
133 JSValue thisValue = callFrame->thisValue();
134 if (!thisValue.isObject())
135 return throwVMError(globalObject, scope, createTypeError(globalObject, "Receiver should be a typed array view but was not an object"));
136 scope.release();
137 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncIncludes);
138}
139
140static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncLastIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame)
141{
142 VM& vm = globalObject->vm();
143 auto scope = DECLARE_THROW_SCOPE(vm);
144 JSValue thisValue = callFrame->thisValue();
145 if (!thisValue.isObject())
146 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
147 scope.release();
148 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncLastIndexOf);
149}
150
151static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncIndexOf(JSGlobalObject* globalObject, CallFrame* callFrame)
152{
153 VM& vm = globalObject->vm();
154 auto scope = DECLARE_THROW_SCOPE(vm);
155 JSValue thisValue = callFrame->thisValue();
156 if (!thisValue.isObject())
157 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
158 scope.release();
159 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncIndexOf);
160}
161
162static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncJoin(JSGlobalObject* globalObject, CallFrame* callFrame)
163{
164 VM& vm = globalObject->vm();
165 auto scope = DECLARE_THROW_SCOPE(vm);
166 JSValue thisValue = callFrame->thisValue();
167 if (!thisValue.isObject())
168 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
169 scope.release();
170 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncJoin);
171}
172
173static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncBuffer(JSGlobalObject* globalObject, CallFrame* callFrame)
174{
175 VM& vm = globalObject->vm();
176 auto scope = DECLARE_THROW_SCOPE(vm);
177 JSValue thisValue = callFrame->thisValue();
178 if (!thisValue.isObject())
179 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
180 scope.release();
181 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncBuffer);
182}
183
184static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncLength(JSGlobalObject* globalObject, CallFrame* callFrame)
185{
186 VM& vm = globalObject->vm();
187 auto scope = DECLARE_THROW_SCOPE(vm);
188 JSValue thisValue = callFrame->thisValue();
189 if (!thisValue.isObject())
190 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
191 scope.release();
192 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncLength);
193}
194
195static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncByteLength(JSGlobalObject* globalObject, CallFrame* callFrame)
196{
197 VM& vm = globalObject->vm();
198 auto scope = DECLARE_THROW_SCOPE(vm);
199 JSValue thisValue = callFrame->thisValue();
200 if (!thisValue.isObject())
201 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
202 scope.release();
203 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncByteLength);
204}
205
206static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncByteOffset(JSGlobalObject* globalObject, CallFrame* callFrame)
207{
208 VM& vm = globalObject->vm();
209 auto scope = DECLARE_THROW_SCOPE(vm);
210 JSValue thisValue = callFrame->thisValue();
211 if (!thisValue.isObject())
212 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
213 scope.release();
214 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncByteOffset);
215}
216
217static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncReverse(JSGlobalObject* globalObject, CallFrame* callFrame)
218{
219 VM& vm = globalObject->vm();
220 auto scope = DECLARE_THROW_SCOPE(vm);
221 JSValue thisValue = callFrame->thisValue();
222 if (!thisValue.isObject())
223 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
224 scope.release();
225 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncReverse);
226}
227
228EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSubarrayCreate(JSGlobalObject* globalObject, CallFrame* callFrame)
229{
230 VM& vm = globalObject->vm();
231 auto scope = DECLARE_THROW_SCOPE(vm);
232 JSValue thisValue = callFrame->thisValue();
233 if (!thisValue.isObject())
234 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
235 scope.release();
236 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewPrivateFuncSubarrayCreate);
237}
238
239static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSlice(JSGlobalObject* globalObject, CallFrame* callFrame)
240{
241 VM& vm = globalObject->vm();
242 auto scope = DECLARE_THROW_SCOPE(vm);
243 JSValue thisValue = callFrame->thisValue();
244 if (!thisValue.isObject())
245 return throwVMTypeError(globalObject, scope, "Receiver should be a typed array view but was not an object"_s);
246 scope.release();
247 CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncSlice);
248}
249
250static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncToStringTag(JSGlobalObject* globalObject, CallFrame* callFrame)
251{
252 JSValue thisValue = callFrame->thisValue();
253 if (!thisValue.isObject())
254 return JSValue::encode(jsUndefined());
255
256 VM& vm = globalObject->vm();
257 switch (thisValue.getObject()->classInfo(vm)->typedArrayStorageType) {
258 case TypeUint8Clamped:
259 return JSValue::encode(jsString(vm, "Uint8ClampedArray"));
260 case TypeInt32:
261 return JSValue::encode(jsString(vm, "Int32Array"));
262 case TypeUint32:
263 return JSValue::encode(jsString(vm, "Uint32Array"));
264 case TypeFloat64:
265 return JSValue::encode(jsString(vm, "Float64Array"));
266 case TypeFloat32:
267 return JSValue::encode(jsString(vm, "Float32Array"));
268 case TypeInt8:
269 return JSValue::encode(jsString(vm, "Int8Array"));
270 case TypeUint8:
271 return JSValue::encode(jsString(vm, "Uint8Array"));
272 case TypeInt16:
273 return JSValue::encode(jsString(vm, "Int16Array"));
274 case TypeUint16:
275 return JSValue::encode(jsString(vm, "Uint16Array"));
276 case NotTypedArray:
277 case TypeDataView:
278 return JSValue::encode(jsUndefined());
279 }
280 RELEASE_ASSERT_NOT_REACHED();
281}
282
283
284#undef CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION
285
286JSTypedArrayViewPrototype::JSTypedArrayViewPrototype(VM& vm, Structure* structure)
287 : Base(vm, structure)
288{
289}
290
291void JSTypedArrayViewPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
292{
293 Base::finishCreation(vm);
294
295 ASSERT(inherits(vm, info()));
296
297 putDirectWithoutTransition(vm, vm.propertyNames->toString, globalObject->arrayProtoToStringFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
298
299 JSC_NATIVE_GETTER_WITHOUT_TRANSITION("buffer", typedArrayViewProtoGetterFuncBuffer, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
300 JSC_NATIVE_INTRINSIC_GETTER_WITHOUT_TRANSITION(vm.propertyNames->byteLength, typedArrayViewProtoGetterFuncByteLength, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, TypedArrayByteLengthIntrinsic);
301 JSC_NATIVE_INTRINSIC_GETTER_WITHOUT_TRANSITION(vm.propertyNames->byteOffset, typedArrayViewProtoGetterFuncByteOffset, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, TypedArrayByteOffsetIntrinsic);
302 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("copyWithin", typedArrayViewProtoFuncCopyWithin, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
303 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("every", typedArrayPrototypeEveryCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
304 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("filter", typedArrayPrototypeFilterCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
305 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort", typedArrayPrototypeSortCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
306 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().entriesPublicName(), typedArrayPrototypeEntriesCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
307 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("includes", typedArrayViewProtoFuncIncludes, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
308 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("fill", typedArrayPrototypeFillCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
309 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("find", typedArrayPrototypeFindCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
310 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("findIndex", typedArrayPrototypeFindIndexCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
311 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->forEach, typedArrayPrototypeForEachCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
312 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", typedArrayViewProtoFuncIndexOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
313 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->join, typedArrayViewProtoFuncJoin, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
314 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().keysPublicName(), typedArrayPrototypeKeysCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
315 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", typedArrayViewProtoFuncLastIndexOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
316 JSC_NATIVE_INTRINSIC_GETTER_WITHOUT_TRANSITION(vm.propertyNames->length, typedArrayViewProtoGetterFuncLength, static_cast<unsigned>(PropertyAttribute::DontEnum) | PropertyAttribute::ReadOnly, TypedArrayLengthIntrinsic);
317 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("map", typedArrayPrototypeMapCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
318 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("reduce", typedArrayPrototypeReduceCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
319 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("reduceRight", typedArrayPrototypeReduceRightCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
320 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("reverse", typedArrayViewProtoFuncReverse, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
321 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, typedArrayViewProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1);
322 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, typedArrayViewProtoFuncSlice, static_cast<unsigned>(PropertyAttribute::DontEnum), 2);
323 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("some", typedArrayPrototypeSomeCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
324 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->subarray, typedArrayPrototypeSubarrayCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
325 JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, typedArrayPrototypeToLocaleStringCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
326
327 JSFunction* toStringTagFunction = JSFunction::create(vm, globalObject, 0, "get [Symbol.toStringTag]"_s, typedArrayViewProtoGetterFuncToStringTag, NoIntrinsic);
328 GetterSetter* toStringTagAccessor = GetterSetter::create(vm, globalObject, toStringTagFunction, nullptr);
329 putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, toStringTagAccessor, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly | PropertyAttribute::Accessor);
330
331 JSFunction* valuesFunction = JSFunction::create(vm, typedArrayPrototypeValuesCodeGenerator(vm), globalObject);
332
333 putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().valuesPublicName(), valuesFunction, static_cast<unsigned>(PropertyAttribute::DontEnum));
334 putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, valuesFunction, static_cast<unsigned>(PropertyAttribute::DontEnum));
335
336}
337
338JSTypedArrayViewPrototype* JSTypedArrayViewPrototype::create(
339 VM& vm, JSGlobalObject* globalObject, Structure* structure)
340{
341 JSTypedArrayViewPrototype* prototype =
342 new (NotNull, allocateCell<JSTypedArrayViewPrototype>(vm.heap))
343 JSTypedArrayViewPrototype(vm, structure);
344 prototype->finishCreation(vm, globalObject);
345 return prototype;
346}
347
348Structure* JSTypedArrayViewPrototype::createStructure(
349 VM& vm, JSGlobalObject* globalObject, JSValue prototype)
350{
351 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
352}
353
354} // namespace JSC
355