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