Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * JS SIMD pseudo-module.
9 : * Specification matches polyfill:
10 : * https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js
11 : * The objects float32x4 and int32x4 are installed on the SIMD pseudo-module.
12 : */
13 :
14 : #include "builtin/SIMD.h"
15 :
16 : #include "mozilla/FloatingPoint.h"
17 : #include "mozilla/IntegerTypeTraits.h"
18 : #include "mozilla/Sprintf.h"
19 :
20 : #include "jsapi.h"
21 : #include "jsfriendapi.h"
22 : #include "jsnum.h"
23 : #include "jsprf.h"
24 :
25 : #include "builtin/TypedObject.h"
26 : #include "jit/AtomicOperations.h"
27 : #include "jit/InlinableNatives.h"
28 : #include "js/GCAPI.h"
29 : #include "js/Value.h"
30 :
31 : #include "jsobjinlines.h"
32 :
33 : using namespace js;
34 :
35 : using mozilla::ArrayLength;
36 : using mozilla::IsFinite;
37 : using mozilla::IsNaN;
38 : using mozilla::FloorLog2;
39 : using mozilla::NumberIsInt32;
40 :
41 : ///////////////////////////////////////////////////////////////////////////
42 : // SIMD
43 :
44 : static_assert(unsigned(SimdType::Count) == 12, "sync with TypedObjectConstants.h");
45 :
46 : static bool ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane);
47 :
48 : static bool
49 0 : CheckVectorObject(HandleValue v, SimdType expectedType)
50 : {
51 0 : if (!v.isObject())
52 0 : return false;
53 :
54 0 : JSObject& obj = v.toObject();
55 0 : if (!obj.is<TypedObject>())
56 0 : return false;
57 :
58 0 : TypeDescr& typeRepr = obj.as<TypedObject>().typeDescr();
59 0 : if (typeRepr.kind() != type::Simd)
60 0 : return false;
61 :
62 0 : return typeRepr.as<SimdTypeDescr>().type() == expectedType;
63 : }
64 :
65 : template<class V>
66 : bool
67 0 : js::IsVectorObject(HandleValue v)
68 : {
69 0 : return CheckVectorObject(v, V::type);
70 : }
71 :
72 : #define FOR_EACH_SIMD(macro) \
73 : macro(Int8x16) \
74 : macro(Int16x8) \
75 : macro(Int32x4) \
76 : macro(Uint8x16) \
77 : macro(Uint16x8) \
78 : macro(Uint32x4) \
79 : macro(Float32x4) \
80 : macro(Float64x2) \
81 : macro(Bool8x16) \
82 : macro(Bool16x8) \
83 : macro(Bool32x4) \
84 : macro(Bool64x2)
85 :
86 : #define InstantiateIsVectorObject_(T) \
87 : template bool js::IsVectorObject<T>(HandleValue v);
88 : FOR_EACH_SIMD(InstantiateIsVectorObject_)
89 : #undef InstantiateIsVectorObject_
90 :
91 : const char*
92 0 : js::SimdTypeToString(SimdType type)
93 : {
94 0 : switch (type) {
95 : #define RETSTR_(TYPE) case SimdType::TYPE: return #TYPE;
96 0 : FOR_EACH_SIMD(RETSTR_)
97 : #undef RETSTR_
98 0 : case SimdType::Count: break;
99 : }
100 0 : return "<bad SimdType>";
101 : }
102 :
103 : PropertyName*
104 0 : js::SimdTypeToName(const JSAtomState& atoms, SimdType type)
105 : {
106 0 : switch (type) {
107 : #define CASE_(TypeName) case SimdType::TypeName: return atoms.TypeName;
108 0 : FOR_EACH_SIMD(CASE_)
109 : #undef CASE_
110 0 : case SimdType::Count: break;
111 : }
112 0 : MOZ_CRASH("bad SIMD type");
113 : }
114 :
115 : bool
116 0 : js::IsSimdTypeName(const JSAtomState& atoms, const PropertyName* name, SimdType* type)
117 : {
118 : #define CHECK_(TypeName) if (name == atoms.TypeName) { \
119 : *type = SimdType::TypeName; \
120 : return true; \
121 : }
122 0 : FOR_EACH_SIMD(CHECK_)
123 : #undef CHECK_
124 0 : return false;
125 : }
126 :
127 : static inline bool
128 0 : ErrorBadArgs(JSContext* cx)
129 : {
130 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
131 0 : return false;
132 : }
133 :
134 : static inline bool
135 0 : ErrorWrongTypeArg(JSContext* cx, unsigned argIndex, Handle<TypeDescr*> typeDescr)
136 : {
137 0 : MOZ_ASSERT(argIndex < 10);
138 : char charArgIndex[2];
139 0 : SprintfLiteral(charArgIndex, "%u", argIndex);
140 :
141 0 : HeapSlot& typeNameSlot = typeDescr->getReservedSlotRef(JS_DESCR_SLOT_STRING_REPR);
142 0 : char* typeNameStr = JS_EncodeString(cx, typeNameSlot.toString());
143 0 : if (!typeNameStr)
144 0 : return false;
145 :
146 : JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR,
147 0 : typeNameStr, charArgIndex);
148 0 : JS_free(cx, typeNameStr);
149 0 : return false;
150 : }
151 :
152 : static inline bool
153 0 : ErrorBadIndex(JSContext* cx)
154 : {
155 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
156 0 : return false;
157 : }
158 :
159 : /* Non-standard: convert and range check an index value for SIMD operations.
160 : *
161 : * 1. numericIndex = ToNumber(argument) (may throw TypeError)
162 : * 2. intIndex = ToInteger(numericIndex)
163 : * 3. if intIndex != numericIndex throw RangeError
164 : *
165 : * This function additionally bounds the range to the non-negative contiguous
166 : * integers:
167 : *
168 : * 4. if intIndex < 0 or intIndex > 2^53 throw RangeError
169 : *
170 : * Return true and set |*index| to the integer value if |argument| is a valid
171 : * array index argument. Otherwise report an TypeError or RangeError and return
172 : * false.
173 : *
174 : * The returned index will always be in the range 0 <= *index <= 2^53.
175 : */
176 : static bool
177 0 : NonStandardToIndex(JSContext* cx, HandleValue v, uint64_t* index)
178 : {
179 : // Fast common case.
180 0 : if (v.isInt32()) {
181 0 : int32_t i = v.toInt32();
182 0 : if (i >= 0) {
183 0 : *index = i;
184 0 : return true;
185 : }
186 : }
187 :
188 : // Slow case. Use ToNumber() to coerce. This may throw a TypeError.
189 : double d;
190 0 : if (!ToNumber(cx, v, &d))
191 0 : return false;
192 :
193 : // Check that |d| is an integer in the valid range.
194 : //
195 : // Not all floating point integers fit in the range of a uint64_t, so we
196 : // need a rough range check before the real range check in our caller. We
197 : // could limit indexes to UINT64_MAX, but this would mean that our callers
198 : // have to be very careful about integer overflow. The contiguous integer
199 : // floating point numbers end at 2^53, so make that our upper limit. If we
200 : // ever support arrays with more than 2^53 elements, this will need to
201 : // change.
202 : //
203 : // Reject infinities, NaNs, and numbers outside the contiguous integer range
204 : // with a RangeError.
205 :
206 : // Write relation so NaNs throw a RangeError.
207 0 : if (!(0 <= d && d <= (uint64_t(1) << 53))) {
208 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
209 0 : return false;
210 : }
211 :
212 : // Check that d is an integer, throw a RangeError if not.
213 : // Note that this conversion could invoke undefined behaviour without the
214 : // range check above.
215 0 : uint64_t i(d);
216 0 : if (d != double(i)) {
217 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
218 0 : return false;
219 : }
220 :
221 0 : *index = i;
222 0 : return true;
223 : }
224 :
225 : template<typename T>
226 : static SimdTypeDescr*
227 0 : GetTypeDescr(JSContext* cx)
228 : {
229 0 : RootedGlobalObject global(cx, cx->global());
230 0 : return GlobalObject::getOrCreateSimdTypeDescr(cx, global, T::type);
231 : }
232 :
233 : template<typename V>
234 : bool
235 0 : js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out)
236 : {
237 : typedef typename V::Elem Elem;
238 0 : Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
239 0 : if (!typeDescr)
240 0 : return false;
241 0 : if (!IsVectorObject<V>(v))
242 0 : return ErrorWrongTypeArg(cx, 1, typeDescr);
243 :
244 0 : JS::AutoCheckCannotGC nogc(cx);
245 0 : Elem* mem = reinterpret_cast<Elem*>(v.toObject().as<TypedObject>().typedMem(nogc));
246 0 : *out = jit::SimdConstant::CreateSimd128(mem);
247 0 : return true;
248 : }
249 :
250 : template bool js::ToSimdConstant<Int8x16>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
251 : template bool js::ToSimdConstant<Int16x8>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
252 : template bool js::ToSimdConstant<Int32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
253 : template bool js::ToSimdConstant<Float32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
254 : template bool js::ToSimdConstant<Bool8x16>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
255 : template bool js::ToSimdConstant<Bool16x8>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
256 : template bool js::ToSimdConstant<Bool32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
257 :
258 : template<typename Elem>
259 : static Elem
260 0 : TypedObjectMemory(HandleValue v, const JS::AutoRequireNoGC& nogc)
261 : {
262 0 : TypedObject& obj = v.toObject().as<TypedObject>();
263 0 : return reinterpret_cast<Elem>(obj.typedMem(nogc));
264 : }
265 :
266 : static const ClassOps SimdTypeDescrClassOps = {
267 : nullptr, /* addProperty */
268 : nullptr, /* delProperty */
269 : nullptr, /* getProperty */
270 : nullptr, /* setProperty */
271 : nullptr, /* enumerate */
272 : nullptr, /* newEnumerate */
273 : nullptr, /* resolve */
274 : nullptr, /* mayResolve */
275 : TypeDescr::finalize,
276 : SimdTypeDescr::call
277 : };
278 :
279 : const Class SimdTypeDescr::class_ = {
280 : "SIMD",
281 : JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
282 : &SimdTypeDescrClassOps
283 : };
284 :
285 : namespace {
286 :
287 : // Define classes (Int8x16Defn, Int16x8Defn, etc.) to group together various
288 : // properties and so on.
289 : #define DEFINE_DEFN_(TypeName) \
290 : class TypeName##Defn { \
291 : public: \
292 : static const JSFunctionSpec Methods[]; \
293 : };
294 :
295 : FOR_EACH_SIMD(DEFINE_DEFN_)
296 : #undef DEFINE_DEFN_
297 :
298 : } // namespace
299 :
300 : // Shared type descriptor methods for all SIMD types.
301 : static const JSFunctionSpec TypeDescriptorMethods[] = {
302 : JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
303 : JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
304 : JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
305 : JS_FS_END
306 : };
307 :
308 : // Shared TypedObject methods for all SIMD types.
309 : static const JSFunctionSpec SimdTypedObjectMethods[] = {
310 : JS_SELF_HOSTED_FN("toString", "SimdToString", 0, 0),
311 : JS_SELF_HOSTED_FN("valueOf", "SimdValueOf", 0, 0),
312 : JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0),
313 : JS_FS_END
314 : };
315 :
316 : // Provide JSJitInfo structs for those types that are supported by Ion.
317 : // The controlling SIMD type is encoded as the InlinableNative primary opcode.
318 : // The SimdOperation within the type is encoded in the .depth field.
319 : //
320 : // The JS_INLINABLE_FN macro refers to js::JitInfo_##native which we provide as
321 : // Simd##Type##_##Operation
322 : //
323 : // /!\ Don't forget to keep this list in sync with the SIMD instrinics used in
324 : // SelfHosting.cpp.
325 :
326 : namespace js {
327 : namespace jit {
328 :
329 : static_assert(uint64_t(SimdOperation::Last) <= UINT16_MAX, "SimdOperation must fit in uint16_t");
330 :
331 : // See also JitInfo_* in MCallOptimize.cpp. We provide a JSJitInfo for all the
332 : // named functions here. The default JitInfo_SimdInt32x4 etc structs represent the
333 : // SimdOperation::Constructor.
334 : #define DEFN(TYPE, OP) const JSJitInfo JitInfo_Simd##TYPE##_##OP = { \
335 : /* .getter, unused for inlinable natives. */ \
336 : { nullptr }, \
337 : /* .inlinableNative, but we have to init first union member: .protoID. */ \
338 : { uint16_t(InlinableNative::Simd##TYPE) }, \
339 : /* .nativeOp. Actually initializing first union member .depth. */ \
340 : { uint16_t(SimdOperation::Fn_##OP) }, \
341 : /* .type_ bitfield says this in an inlinable native function. */ \
342 : JSJitInfo::InlinableNative \
343 : /* Remaining fields are not used for inlinable natives. They are zero-initialized. */ \
344 : };
345 :
346 : // This list of inlinable types should match the one in jit/InlinableNatives.h.
347 : #define TDEFN(Name, Func, Operands) DEFN(Float32x4, Name)
348 : FLOAT32X4_FUNCTION_LIST(TDEFN)
349 : #undef TDEFN
350 :
351 : #define TDEFN(Name, Func, Operands) DEFN(Int8x16, Name)
352 : INT8X16_FUNCTION_LIST(TDEFN)
353 : #undef TDEFN
354 :
355 : #define TDEFN(Name, Func, Operands) DEFN(Uint8x16, Name)
356 : UINT8X16_FUNCTION_LIST(TDEFN)
357 : #undef TDEFN
358 :
359 : #define TDEFN(Name, Func, Operands) DEFN(Int16x8, Name)
360 : INT16X8_FUNCTION_LIST(TDEFN)
361 : #undef TDEFN
362 :
363 : #define TDEFN(Name, Func, Operands) DEFN(Uint16x8, Name)
364 : UINT16X8_FUNCTION_LIST(TDEFN)
365 : #undef TDEFN
366 :
367 : #define TDEFN(Name, Func, Operands) DEFN(Int32x4, Name)
368 : INT32X4_FUNCTION_LIST(TDEFN)
369 : #undef TDEFN
370 :
371 : #define TDEFN(Name, Func, Operands) DEFN(Uint32x4, Name)
372 : UINT32X4_FUNCTION_LIST(TDEFN)
373 : #undef TDEFN
374 :
375 : #define TDEFN(Name, Func, Operands) DEFN(Bool8x16, Name)
376 : BOOL8X16_FUNCTION_LIST(TDEFN)
377 : #undef TDEFN
378 :
379 : #define TDEFN(Name, Func, Operands) DEFN(Bool16x8, Name)
380 : BOOL16X8_FUNCTION_LIST(TDEFN)
381 : #undef TDEFN
382 :
383 : #define TDEFN(Name, Func, Operands) DEFN(Bool32x4, Name)
384 : BOOL32X4_FUNCTION_LIST(TDEFN)
385 : #undef TDEFN
386 :
387 : } // namespace jit
388 : } // namespace js
389 :
390 : const JSFunctionSpec Float32x4Defn::Methods[] = {
391 : #define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands) \
392 : JS_INLINABLE_FN(#Name, js::simd_float32x4_##Name, Operands, 0, SimdFloat32x4_##Name),
393 : FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM)
394 : #undef SIMD_FLOAT32x4_FUNCTION_ITEM
395 : JS_FS_END
396 : };
397 :
398 : const JSFunctionSpec Float64x2Defn::Methods[] = {
399 : #define SIMD_FLOAT64X2_FUNCTION_ITEM(Name, Func, Operands) \
400 : JS_FN(#Name, js::simd_float64x2_##Name, Operands, 0),
401 : FLOAT64X2_FUNCTION_LIST(SIMD_FLOAT64X2_FUNCTION_ITEM)
402 : #undef SIMD_FLOAT64X2_FUNCTION_ITEM
403 : JS_FS_END
404 : };
405 :
406 : const JSFunctionSpec Int8x16Defn::Methods[] = {
407 : #define SIMD_INT8X16_FUNCTION_ITEM(Name, Func, Operands) \
408 : JS_INLINABLE_FN(#Name, js::simd_int8x16_##Name, Operands, 0, SimdInt8x16_##Name),
409 : INT8X16_FUNCTION_LIST(SIMD_INT8X16_FUNCTION_ITEM)
410 : #undef SIMD_INT8X16_FUNCTION_ITEM
411 : JS_FS_END
412 : };
413 :
414 : const JSFunctionSpec Int16x8Defn::Methods[] = {
415 : #define SIMD_INT16X8_FUNCTION_ITEM(Name, Func, Operands) \
416 : JS_INLINABLE_FN(#Name, js::simd_int16x8_##Name, Operands, 0, SimdInt16x8_##Name),
417 : INT16X8_FUNCTION_LIST(SIMD_INT16X8_FUNCTION_ITEM)
418 : #undef SIMD_INT16X8_FUNCTION_ITEM
419 : JS_FS_END
420 : };
421 :
422 : const JSFunctionSpec Int32x4Defn::Methods[] = {
423 : #define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands) \
424 : JS_INLINABLE_FN(#Name, js::simd_int32x4_##Name, Operands, 0, SimdInt32x4_##Name),
425 : INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM)
426 : #undef SIMD_INT32X4_FUNCTION_ITEM
427 : JS_FS_END
428 : };
429 :
430 : const JSFunctionSpec Uint8x16Defn::Methods[] = {
431 : #define SIMD_UINT8X16_FUNCTION_ITEM(Name, Func, Operands) \
432 : JS_INLINABLE_FN(#Name, js::simd_uint8x16_##Name, Operands, 0, SimdUint8x16_##Name),
433 : UINT8X16_FUNCTION_LIST(SIMD_UINT8X16_FUNCTION_ITEM)
434 : #undef SIMD_UINT8X16_FUNCTION_ITEM
435 : JS_FS_END
436 : };
437 :
438 : const JSFunctionSpec Uint16x8Defn::Methods[] = {
439 : #define SIMD_UINT16X8_FUNCTION_ITEM(Name, Func, Operands) \
440 : JS_INLINABLE_FN(#Name, js::simd_uint16x8_##Name, Operands, 0, SimdUint16x8_##Name),
441 : UINT16X8_FUNCTION_LIST(SIMD_UINT16X8_FUNCTION_ITEM)
442 : #undef SIMD_UINT16X8_FUNCTION_ITEM
443 : JS_FS_END
444 : };
445 :
446 : const JSFunctionSpec Uint32x4Defn::Methods[] = {
447 : #define SIMD_UINT32X4_FUNCTION_ITEM(Name, Func, Operands) \
448 : JS_INLINABLE_FN(#Name, js::simd_uint32x4_##Name, Operands, 0, SimdUint32x4_##Name),
449 : UINT32X4_FUNCTION_LIST(SIMD_UINT32X4_FUNCTION_ITEM)
450 : #undef SIMD_UINT32X4_FUNCTION_ITEM
451 : JS_FS_END
452 : };
453 :
454 : const JSFunctionSpec Bool8x16Defn::Methods[] = {
455 : #define SIMD_BOOL8X16_FUNCTION_ITEM(Name, Func, Operands) \
456 : JS_INLINABLE_FN(#Name, js::simd_bool8x16_##Name, Operands, 0, SimdBool8x16_##Name),
457 : BOOL8X16_FUNCTION_LIST(SIMD_BOOL8X16_FUNCTION_ITEM)
458 : #undef SIMD_BOOL8X16_FUNCTION_ITEM
459 : JS_FS_END
460 : };
461 :
462 : const JSFunctionSpec Bool16x8Defn::Methods[] = {
463 : #define SIMD_BOOL16X8_FUNCTION_ITEM(Name, Func, Operands) \
464 : JS_INLINABLE_FN(#Name, js::simd_bool16x8_##Name, Operands, 0, SimdBool16x8_##Name),
465 : BOOL16X8_FUNCTION_LIST(SIMD_BOOL16X8_FUNCTION_ITEM)
466 : #undef SIMD_BOOL16X8_FUNCTION_ITEM
467 : JS_FS_END
468 : };
469 :
470 : const JSFunctionSpec Bool32x4Defn::Methods[] = {
471 : #define SIMD_BOOL32X4_FUNCTION_ITEM(Name, Func, Operands) \
472 : JS_INLINABLE_FN(#Name, js::simd_bool32x4_##Name, Operands, 0, SimdBool32x4_##Name),
473 : BOOL32X4_FUNCTION_LIST(SIMD_BOOL32X4_FUNCTION_ITEM)
474 : #undef SIMD_BOOL32X4_FUNCTION_ITEM
475 : JS_FS_END
476 : };
477 :
478 : const JSFunctionSpec Bool64x2Defn::Methods[] = {
479 : #define SIMD_BOOL64X2_FUNCTION_ITEM(Name, Func, Operands) \
480 : JS_FN(#Name, js::simd_bool64x2_##Name, Operands, 0),
481 : BOOL64X2_FUNCTION_LIST(SIMD_BOOL64X2_FUNCTION_ITEM)
482 : #undef SIMD_BOOL64x2_FUNCTION_ITEM
483 : JS_FS_END
484 : };
485 :
486 : template <typename T>
487 : static bool
488 0 : FillLanes(JSContext* cx, Handle<TypedObject*> result, const CallArgs& args)
489 : {
490 : typedef typename T::Elem Elem;
491 : Elem tmp;
492 0 : for (unsigned i = 0; i < T::lanes; i++) {
493 0 : if (!T::Cast(cx, args.get(i), &tmp))
494 0 : return false;
495 : // Reassure typedMem() that we won't GC while holding onto the returned
496 : // pointer, even though we could GC on every iteration of this loop
497 : // (but it is safe because we re-fetch each time.)
498 0 : JS::AutoCheckCannotGC nogc(cx);
499 0 : reinterpret_cast<Elem*>(result->typedMem(nogc))[i] = tmp;
500 : }
501 0 : args.rval().setObject(*result);
502 0 : return true;
503 : }
504 :
505 : bool
506 0 : SimdTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
507 : {
508 0 : CallArgs args = CallArgsFromVp(argc, vp);
509 :
510 0 : Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
511 0 : Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0));
512 0 : if (!result)
513 0 : return false;
514 :
515 : #define CASE_CALL_(Type) \
516 : case SimdType::Type: return FillLanes< ::Type>(cx, result, args);
517 :
518 0 : switch (descr->type()) {
519 0 : FOR_EACH_SIMD(CASE_CALL_)
520 0 : case SimdType::Count: break;
521 : }
522 :
523 : #undef CASE_CALL_
524 0 : MOZ_CRASH("unexpected SIMD descriptor");
525 : return false;
526 : }
527 :
528 : ///////////////////////////////////////////////////////////////////////////
529 : // SIMD class
530 :
531 : static const ClassOps SimdObjectClassOps = {
532 : nullptr, /* addProperty */
533 : nullptr, /* delProperty */
534 : nullptr, /* getProperty */
535 : nullptr, /* setProperty */
536 : nullptr, /* enumerate */
537 : nullptr, /* newEnumerate */
538 : SimdObject::resolve
539 : };
540 :
541 : const Class SimdObject::class_ = {
542 : "SIMD",
543 : JSCLASS_HAS_RESERVED_SLOTS(uint32_t(SimdType::Count)),
544 : &SimdObjectClassOps
545 : };
546 :
547 : /* static */ bool
548 6 : GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global)
549 : {
550 : // SIMD relies on the TypedObject module being initialized.
551 : // In particular, the self-hosted code for array() wants
552 : // to be able to call GetTypedObjectModule(). It is NOT necessary
553 : // to install the TypedObjectModule global, but at the moment
554 : // those two things are not separable.
555 6 : if (!GlobalObject::getOrCreateTypedObjectModule(cx, global))
556 0 : return false;
557 :
558 12 : RootedObject globalSimdObject(cx);
559 12 : RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
560 6 : if (!objProto)
561 0 : return false;
562 :
563 6 : globalSimdObject = NewObjectWithGivenProto(cx, &SimdObject::class_, objProto, SingletonObject);
564 6 : if (!globalSimdObject)
565 0 : return false;
566 :
567 12 : RootedValue globalSimdValue(cx, ObjectValue(*globalSimdObject));
568 6 : if (!DefineProperty(cx, global, cx->names().SIMD, globalSimdValue, nullptr, nullptr,
569 : JSPROP_RESOLVING))
570 : {
571 0 : return false;
572 : }
573 :
574 6 : global->setConstructor(JSProto_SIMD, globalSimdValue);
575 6 : return true;
576 : }
577 :
578 : static bool
579 0 : CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr,
580 : SimdType simdType, const JSFunctionSpec* methods)
581 : {
582 0 : RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global));
583 0 : if (!funcProto)
584 0 : return false;
585 :
586 : // Create type constructor itself and initialize its reserved slots.
587 0 : Rooted<SimdTypeDescr*> typeDescr(cx);
588 0 : typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject);
589 0 : if (!typeDescr)
590 0 : return false;
591 :
592 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd));
593 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
594 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(simdType)));
595 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(simdType)));
596 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
597 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(uint8_t(simdType)));
598 :
599 0 : if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
600 0 : return false;
601 :
602 : // Create prototype property, which inherits from Object.prototype.
603 0 : RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
604 0 : if (!objProto)
605 0 : return false;
606 0 : Rooted<TypedProto*> proto(cx);
607 0 : proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, SingletonObject);
608 0 : if (!proto)
609 0 : return false;
610 0 : typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
611 :
612 : // Link constructor to prototype and install properties.
613 0 : if (!JS_DefineFunctions(cx, typeDescr, TypeDescriptorMethods))
614 0 : return false;
615 :
616 0 : if (!LinkConstructorAndPrototype(cx, typeDescr, proto) ||
617 0 : !JS_DefineFunctions(cx, proto, SimdTypedObjectMethods))
618 : {
619 0 : return false;
620 : }
621 :
622 : // Bind type descriptor to the global SIMD object
623 0 : RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global));
624 0 : MOZ_ASSERT(globalSimdObject);
625 :
626 0 : RootedValue typeValue(cx, ObjectValue(*typeDescr));
627 0 : if (!JS_DefineFunctions(cx, typeDescr, methods) ||
628 0 : !DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr,
629 0 : JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING))
630 : {
631 0 : return false;
632 : }
633 :
634 0 : uint32_t slot = uint32_t(typeDescr->type());
635 0 : MOZ_ASSERT(globalSimdObject->as<NativeObject>().getReservedSlot(slot).isUndefined());
636 0 : globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr));
637 0 : return !!typeDescr;
638 : }
639 :
640 : /* static */ bool
641 0 : GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType)
642 : {
643 : #define CREATE_(Type) \
644 : case SimdType::Type: \
645 : return CreateSimdType(cx, global, cx->names().Type, simdType, Type##Defn::Methods);
646 :
647 0 : switch (simdType) {
648 0 : FOR_EACH_SIMD(CREATE_)
649 0 : case SimdType::Count: break;
650 : }
651 0 : MOZ_CRASH("unexpected simd type");
652 :
653 : #undef CREATE_
654 : }
655 :
656 : /* static */ SimdTypeDescr*
657 0 : GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global,
658 : SimdType simdType)
659 : {
660 0 : MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type");
661 :
662 0 : RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global));
663 0 : if (!globalSimdObject)
664 0 : return nullptr;
665 :
666 0 : uint32_t typeSlotIndex = uint32_t(simdType);
667 0 : if (globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex).isUndefined() &&
668 0 : !GlobalObject::initSimdType(cx, global, simdType))
669 : {
670 0 : return nullptr;
671 : }
672 :
673 0 : const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex);
674 0 : MOZ_ASSERT(slot.isObject());
675 0 : return &slot.toObject().as<SimdTypeDescr>();
676 : }
677 :
678 : bool
679 0 : SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved)
680 : {
681 0 : *resolved = false;
682 0 : if (!JSID_IS_ATOM(id))
683 0 : return true;
684 0 : JSAtom* str = JSID_TO_ATOM(id);
685 0 : Rooted<GlobalObject*> global(cx, cx->global());
686 : #define TRY_RESOLVE_(Type) \
687 : if (str == cx->names().Type) { \
688 : *resolved = CreateSimdType(cx, global, cx->names().Type, \
689 : SimdType::Type, Type##Defn::Methods); \
690 : return *resolved; \
691 : }
692 0 : FOR_EACH_SIMD(TRY_RESOLVE_)
693 : #undef TRY_RESOLVE_
694 0 : return true;
695 : }
696 :
697 : JSObject*
698 6 : js::InitSimdClass(JSContext* cx, HandleObject obj)
699 : {
700 6 : Handle<GlobalObject*> global = obj.as<GlobalObject>();
701 6 : return GlobalObject::getOrCreateSimdGlobalObject(cx, global);
702 : }
703 :
704 : template<typename V>
705 : JSObject*
706 0 : js::CreateSimd(JSContext* cx, const typename V::Elem* data)
707 : {
708 : typedef typename V::Elem Elem;
709 0 : Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
710 0 : if (!typeDescr)
711 0 : return nullptr;
712 :
713 0 : Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
714 0 : if (!result)
715 0 : return nullptr;
716 :
717 0 : JS::AutoCheckCannotGC nogc(cx);
718 0 : Elem* resultMem = reinterpret_cast<Elem*>(result->typedMem(nogc));
719 0 : memcpy(resultMem, data, sizeof(Elem) * V::lanes);
720 0 : return result;
721 : }
722 :
723 : #define InstantiateCreateSimd_(Type) \
724 : template JSObject* js::CreateSimd<Type>(JSContext* cx, const Type::Elem* data);
725 :
726 : FOR_EACH_SIMD(InstantiateCreateSimd_)
727 :
728 : #undef InstantiateCreateSimd_
729 :
730 : #undef FOR_EACH_SIMD
731 :
732 : namespace js {
733 : // Unary SIMD operators
734 : template<typename T>
735 : struct Identity {
736 0 : static T apply(T x) { return x; }
737 : };
738 : template<typename T>
739 : struct Abs {
740 0 : static T apply(T x) { return mozilla::Abs(x); }
741 : };
742 : template<typename T>
743 : struct Neg {
744 0 : static T apply(T x) { return -1 * x; }
745 : };
746 : template<typename T>
747 : struct Not {
748 0 : static T apply(T x) { return ~x; }
749 : };
750 : template<typename T>
751 : struct LogicalNot {
752 0 : static T apply(T x) { return !x; }
753 : };
754 : template<typename T>
755 : struct RecApprox {
756 0 : static T apply(T x) { return 1 / x; }
757 : };
758 : template<typename T>
759 : struct RecSqrtApprox {
760 0 : static T apply(T x) { return 1 / sqrt(x); }
761 : };
762 : template<typename T>
763 : struct Sqrt {
764 0 : static T apply(T x) { return sqrt(x); }
765 : };
766 :
767 : // Binary SIMD operators
768 : template<typename T>
769 : struct Add {
770 0 : static T apply(T l, T r) { return l + r; }
771 : };
772 : template<typename T>
773 : struct Sub {
774 0 : static T apply(T l, T r) { return l - r; }
775 : };
776 : template<typename T>
777 : struct Div {
778 0 : static T apply(T l, T r) { return l / r; }
779 : };
780 : template<typename T>
781 : struct Mul {
782 0 : static T apply(T l, T r) { return l * r; }
783 : };
784 : template<typename T>
785 : struct Minimum {
786 0 : static T apply(T l, T r) { return math_min_impl(l, r); }
787 : };
788 : template<typename T>
789 : struct MinNum {
790 0 : static T apply(T l, T r) { return IsNaN(l) ? r : (IsNaN(r) ? l : math_min_impl(l, r)); }
791 : };
792 : template<typename T>
793 : struct Maximum {
794 0 : static T apply(T l, T r) { return math_max_impl(l, r); }
795 : };
796 : template<typename T>
797 : struct MaxNum {
798 0 : static T apply(T l, T r) { return IsNaN(l) ? r : (IsNaN(r) ? l : math_max_impl(l, r)); }
799 : };
800 : template<typename T>
801 : struct LessThan {
802 0 : static bool apply(T l, T r) { return l < r; }
803 : };
804 : template<typename T>
805 : struct LessThanOrEqual {
806 0 : static bool apply(T l, T r) { return l <= r; }
807 : };
808 : template<typename T>
809 : struct GreaterThan {
810 0 : static bool apply(T l, T r) { return l > r; }
811 : };
812 : template<typename T>
813 : struct GreaterThanOrEqual {
814 0 : static bool apply(T l, T r) { return l >= r; }
815 : };
816 : template<typename T>
817 : struct Equal {
818 0 : static bool apply(T l, T r) { return l == r; }
819 : };
820 : template<typename T>
821 : struct NotEqual {
822 0 : static bool apply(T l, T r) { return l != r; }
823 : };
824 : template<typename T>
825 : struct Xor {
826 0 : static T apply(T l, T r) { return l ^ r; }
827 : };
828 : template<typename T>
829 : struct And {
830 0 : static T apply(T l, T r) { return l & r; }
831 : };
832 : template<typename T>
833 : struct Or {
834 0 : static T apply(T l, T r) { return l | r; }
835 : };
836 :
837 : // For the following three operators, if the value v we're trying to shift is
838 : // such that v << bits can't fit in the int32 range, then we have undefined
839 : // behavior, according to C++11 [expr.shift]p2. However, left-shifting an
840 : // unsigned type is well-defined.
841 : //
842 : // In C++, shifting by an amount outside the range [0;N-1] is undefined
843 : // behavior. SIMD.js reduces the shift amount modulo the number of bits in a
844 : // lane and has defined behavior for all shift amounts.
845 : template<typename T>
846 : struct ShiftLeft {
847 0 : static T apply(T v, int32_t bits) {
848 : typedef typename mozilla::MakeUnsigned<T>::Type UnsignedT;
849 0 : uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8);
850 0 : return UnsignedT(v) << maskedBits;
851 : }
852 : };
853 : template<typename T>
854 : struct ShiftRightArithmetic {
855 0 : static T apply(T v, int32_t bits) {
856 : typedef typename mozilla::MakeSigned<T>::Type SignedT;
857 0 : uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8);
858 0 : return SignedT(v) >> maskedBits;
859 : }
860 : };
861 : template<typename T>
862 : struct ShiftRightLogical {
863 0 : static T apply(T v, int32_t bits) {
864 : typedef typename mozilla::MakeUnsigned<T>::Type UnsignedT;
865 0 : uint32_t maskedBits = uint32_t(bits) % (sizeof(T) * 8);
866 0 : return UnsignedT(v) >> maskedBits;
867 : }
868 : };
869 :
870 : // Saturating arithmetic is only defined on types smaller than int.
871 : // Clamp `x` into the range supported by the integral type T.
872 : template<typename T>
873 : static T
874 0 : Saturate(int x)
875 : {
876 : static_assert(mozilla::IsIntegral<T>::value, "Only integer saturation supported");
877 : static_assert(sizeof(T) < sizeof(int), "Saturating int-sized arithmetic is not safe");
878 0 : const T lower = mozilla::MinValue<T>::value;
879 0 : const T upper = mozilla::MaxValue<T>::value;
880 0 : if (x > int(upper))
881 0 : return upper;
882 0 : if (x < int(lower))
883 0 : return lower;
884 0 : return T(x);
885 : }
886 :
887 : // Since signed integer overflow is undefined behavior in C++, it would be
888 : // wildly irresponsible to attempt something as dangerous as adding two numbers
889 : // coming from user code. However, in this case we know that T is smaller than
890 : // int, so there is no way these operations can cause overflow. The
891 : // static_assert in Saturate() enforces this for us.
892 : template<typename T>
893 : struct AddSaturate {
894 0 : static T apply(T l, T r) { return Saturate<T>(l + r); }
895 : };
896 : template<typename T>
897 : struct SubSaturate {
898 0 : static T apply(T l, T r) { return Saturate<T>(l - r); }
899 : };
900 :
901 : } // namespace js
902 :
903 : template<typename Out>
904 : static bool
905 0 : StoreResult(JSContext* cx, CallArgs& args, typename Out::Elem* result)
906 : {
907 0 : RootedObject obj(cx, CreateSimd<Out>(cx, result));
908 0 : if (!obj)
909 0 : return false;
910 0 : args.rval().setObject(*obj);
911 0 : return true;
912 : }
913 :
914 : // StoreResult can GC, and it is commonly used after pulling something out of a
915 : // TypedObject:
916 : //
917 : // Elem result = op(TypedObjectMemory<Elem>(args[0]));
918 : // StoreResult<Out>(..., result);
919 : //
920 : // The pointer extracted from the typed object in args[0] in the above example
921 : // could be an interior pointer, and therefore be invalidated by GC.
922 : // TypedObjectMemory() requires an assertion token to be passed in to prove
923 : // that we won't GC, but the scope of eg an AutoCheckCannotGC RAII object
924 : // extends to the end of its containing scope -- which would include the call
925 : // to StoreResult, resulting in a rooting hazard.
926 : //
927 : // TypedObjectElemArray fixes this by wrapping the problematic pointer in a
928 : // type, and the analysis is able to see that it is dead before calling
929 : // StoreResult. (But if another GC called is made before the pointer is dead,
930 : // it will correctly report a hazard.)
931 : //
932 : template <typename Elem>
933 : class TypedObjectElemArray {
934 : Elem* elements;
935 : public:
936 0 : explicit TypedObjectElemArray(HandleValue objVal) {
937 0 : JS::AutoCheckCannotGC nogc;
938 0 : elements = TypedObjectMemory<Elem*>(objVal, nogc);
939 0 : }
940 0 : Elem& operator[](int i) { return elements[i]; }
941 : } JS_HAZ_GC_POINTER;
942 :
943 : // Coerces the inputs of type In to the type Coercion, apply the operator Op
944 : // and converts the result to the type Out.
945 : template<typename In, typename Coercion, template<typename C> class Op, typename Out>
946 : static bool
947 0 : CoercedUnaryFunc(JSContext* cx, unsigned argc, Value* vp)
948 : {
949 : typedef typename Coercion::Elem CoercionElem;
950 : typedef typename Out::Elem RetElem;
951 :
952 0 : CallArgs args = CallArgsFromVp(argc, vp);
953 0 : if (args.length() != 1 || !IsVectorObject<In>(args[0]))
954 0 : return ErrorBadArgs(cx);
955 :
956 : CoercionElem result[Coercion::lanes];
957 0 : TypedObjectElemArray<CoercionElem> val(args[0]);
958 0 : for (unsigned i = 0; i < Coercion::lanes; i++)
959 0 : result[i] = Op<CoercionElem>::apply(val[i]);
960 0 : return StoreResult<Out>(cx, args, (RetElem*) result);
961 : }
962 :
963 : // Coerces the inputs of type In to the type Coercion, apply the operator Op
964 : // and converts the result to the type Out.
965 : template<typename In, typename Coercion, template<typename C> class Op, typename Out>
966 : static bool
967 0 : CoercedBinaryFunc(JSContext* cx, unsigned argc, Value* vp)
968 : {
969 : typedef typename Coercion::Elem CoercionElem;
970 : typedef typename Out::Elem RetElem;
971 :
972 0 : CallArgs args = CallArgsFromVp(argc, vp);
973 0 : if (args.length() != 2 || !IsVectorObject<In>(args[0]) || !IsVectorObject<In>(args[1]))
974 0 : return ErrorBadArgs(cx);
975 :
976 : CoercionElem result[Coercion::lanes];
977 0 : TypedObjectElemArray<CoercionElem> left(args[0]);
978 0 : TypedObjectElemArray<CoercionElem> right(args[1]);
979 0 : for (unsigned i = 0; i < Coercion::lanes; i++)
980 0 : result[i] = Op<CoercionElem>::apply(left[i], right[i]);
981 0 : return StoreResult<Out>(cx, args, (RetElem*) result);
982 : }
983 :
984 : // Same as above, with no coercion, i.e. Coercion == In.
985 : template<typename In, template<typename C> class Op, typename Out>
986 : static bool
987 0 : UnaryFunc(JSContext* cx, unsigned argc, Value* vp)
988 : {
989 0 : return CoercedUnaryFunc<In, Out, Op, Out>(cx, argc, vp);
990 : }
991 :
992 : template<typename In, template<typename C> class Op, typename Out>
993 : static bool
994 0 : BinaryFunc(JSContext* cx, unsigned argc, Value* vp)
995 : {
996 0 : return CoercedBinaryFunc<In, Out, Op, Out>(cx, argc, vp);
997 : }
998 :
999 : template<typename V>
1000 : static bool
1001 0 : ExtractLane(JSContext* cx, unsigned argc, Value* vp)
1002 : {
1003 : typedef typename V::Elem Elem;
1004 :
1005 0 : CallArgs args = CallArgsFromVp(argc, vp);
1006 0 : if (args.length() < 2 || !IsVectorObject<V>(args[0]))
1007 0 : return ErrorBadArgs(cx);
1008 :
1009 : unsigned lane;
1010 0 : if (!ArgumentToLaneIndex(cx, args[1], V::lanes, &lane))
1011 0 : return false;
1012 :
1013 0 : JS::AutoCheckCannotGC nogc(cx);
1014 0 : Elem* vec = TypedObjectMemory<Elem*>(args[0], nogc);
1015 0 : Elem val = vec[lane];
1016 0 : args.rval().set(V::ToValue(val));
1017 0 : return true;
1018 : }
1019 :
1020 : template<typename V>
1021 : static bool
1022 0 : AllTrue(JSContext* cx, unsigned argc, Value* vp)
1023 : {
1024 : typedef typename V::Elem Elem;
1025 :
1026 0 : CallArgs args = CallArgsFromVp(argc, vp);
1027 0 : if (args.length() < 1 || !IsVectorObject<V>(args[0]))
1028 0 : return ErrorBadArgs(cx);
1029 :
1030 0 : JS::AutoCheckCannotGC nogc(cx);
1031 0 : Elem* vec = TypedObjectMemory<Elem*>(args[0], nogc);
1032 0 : bool allTrue = true;
1033 0 : for (unsigned i = 0; allTrue && i < V::lanes; i++)
1034 0 : allTrue = vec[i];
1035 :
1036 0 : args.rval().setBoolean(allTrue);
1037 0 : return true;
1038 : }
1039 :
1040 : template<typename V>
1041 : static bool
1042 0 : AnyTrue(JSContext* cx, unsigned argc, Value* vp)
1043 : {
1044 : typedef typename V::Elem Elem;
1045 :
1046 0 : CallArgs args = CallArgsFromVp(argc, vp);
1047 0 : if (args.length() < 1 || !IsVectorObject<V>(args[0]))
1048 0 : return ErrorBadArgs(cx);
1049 :
1050 0 : JS::AutoCheckCannotGC nogc(cx);
1051 0 : Elem* vec = TypedObjectMemory<Elem*>(args[0], nogc);
1052 0 : bool anyTrue = false;
1053 0 : for (unsigned i = 0; !anyTrue && i < V::lanes; i++)
1054 0 : anyTrue = vec[i];
1055 :
1056 0 : args.rval().setBoolean(anyTrue);
1057 0 : return true;
1058 : }
1059 :
1060 : template<typename V>
1061 : static bool
1062 0 : ReplaceLane(JSContext* cx, unsigned argc, Value* vp)
1063 : {
1064 : typedef typename V::Elem Elem;
1065 :
1066 0 : CallArgs args = CallArgsFromVp(argc, vp);
1067 : // Only the first and second arguments are mandatory
1068 0 : if (args.length() < 2 || !IsVectorObject<V>(args[0]))
1069 0 : return ErrorBadArgs(cx);
1070 :
1071 : unsigned lane;
1072 0 : if (!ArgumentToLaneIndex(cx, args[1], V::lanes, &lane))
1073 0 : return false;
1074 :
1075 : Elem value;
1076 0 : if (!V::Cast(cx, args.get(2), &value))
1077 0 : return false;
1078 :
1079 0 : TypedObjectElemArray<Elem> vec(args[0]);
1080 : Elem result[V::lanes];
1081 0 : for (unsigned i = 0; i < V::lanes; i++)
1082 0 : result[i] = i == lane ? value : vec[i];
1083 :
1084 0 : return StoreResult<V>(cx, args, result);
1085 : }
1086 :
1087 : template<typename V>
1088 : static bool
1089 0 : Swizzle(JSContext* cx, unsigned argc, Value* vp)
1090 : {
1091 : typedef typename V::Elem Elem;
1092 :
1093 0 : CallArgs args = CallArgsFromVp(argc, vp);
1094 0 : if (args.length() != (V::lanes + 1) || !IsVectorObject<V>(args[0]))
1095 0 : return ErrorBadArgs(cx);
1096 :
1097 : unsigned lanes[V::lanes];
1098 0 : for (unsigned i = 0; i < V::lanes; i++) {
1099 0 : if (!ArgumentToLaneIndex(cx, args[i + 1], V::lanes, &lanes[i]))
1100 0 : return false;
1101 : }
1102 :
1103 0 : TypedObjectElemArray<Elem> val(args[0]);
1104 : Elem result[V::lanes];
1105 0 : for (unsigned i = 0; i < V::lanes; i++)
1106 0 : result[i] = val[lanes[i]];
1107 :
1108 0 : return StoreResult<V>(cx, args, result);
1109 : }
1110 :
1111 : template<typename V>
1112 : static bool
1113 0 : Shuffle(JSContext* cx, unsigned argc, Value* vp)
1114 : {
1115 : typedef typename V::Elem Elem;
1116 :
1117 0 : CallArgs args = CallArgsFromVp(argc, vp);
1118 0 : if (args.length() != (V::lanes + 2) || !IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]))
1119 0 : return ErrorBadArgs(cx);
1120 :
1121 : unsigned lanes[V::lanes];
1122 0 : for (unsigned i = 0; i < V::lanes; i++) {
1123 0 : if (!ArgumentToLaneIndex(cx, args[i + 2], 2 * V::lanes, &lanes[i]))
1124 0 : return false;
1125 : }
1126 :
1127 : Elem result[V::lanes];
1128 : {
1129 0 : JS::AutoCheckCannotGC nogc(cx);
1130 0 : Elem* lhs = TypedObjectMemory<Elem*>(args[0], nogc);
1131 0 : Elem* rhs = TypedObjectMemory<Elem*>(args[1], nogc);
1132 :
1133 0 : for (unsigned i = 0; i < V::lanes; i++) {
1134 0 : Elem* selectedInput = lanes[i] < V::lanes ? lhs : rhs;
1135 0 : result[i] = selectedInput[lanes[i] % V::lanes];
1136 : }
1137 : }
1138 :
1139 0 : return StoreResult<V>(cx, args, result);
1140 : }
1141 :
1142 : template<typename V, template<typename T> class Op>
1143 : static bool
1144 0 : BinaryScalar(JSContext* cx, unsigned argc, Value* vp)
1145 : {
1146 : typedef typename V::Elem Elem;
1147 :
1148 0 : CallArgs args = CallArgsFromVp(argc, vp);
1149 0 : if (args.length() != 2)
1150 0 : return ErrorBadArgs(cx);
1151 :
1152 0 : if (!IsVectorObject<V>(args[0]))
1153 0 : return ErrorBadArgs(cx);
1154 :
1155 : int32_t bits;
1156 0 : if (!ToInt32(cx, args[1], &bits))
1157 0 : return false;
1158 :
1159 0 : TypedObjectElemArray<Elem> val(args[0]);
1160 : Elem result[V::lanes];
1161 0 : for (unsigned i = 0; i < V::lanes; i++)
1162 0 : result[i] = Op<Elem>::apply(val[i], bits);
1163 :
1164 0 : return StoreResult<V>(cx, args, result);
1165 : }
1166 :
1167 : template<typename In, template<typename C> class Op, typename Out>
1168 : static bool
1169 0 : CompareFunc(JSContext* cx, unsigned argc, Value* vp)
1170 : {
1171 : typedef typename In::Elem InElem;
1172 : typedef typename Out::Elem OutElem;
1173 :
1174 0 : CallArgs args = CallArgsFromVp(argc, vp);
1175 0 : if (args.length() != 2 || !IsVectorObject<In>(args[0]) || !IsVectorObject<In>(args[1]))
1176 0 : return ErrorBadArgs(cx);
1177 :
1178 : OutElem result[Out::lanes];
1179 0 : TypedObjectElemArray<InElem> left(args[0]);
1180 0 : TypedObjectElemArray<InElem> right(args[1]);
1181 0 : for (unsigned i = 0; i < Out::lanes; i++) {
1182 0 : unsigned j = (i * In::lanes) / Out::lanes;
1183 0 : result[i] = Op<InElem>::apply(left[j], right[j]) ? -1 : 0;
1184 : }
1185 :
1186 0 : return StoreResult<Out>(cx, args, result);
1187 : }
1188 :
1189 : // This struct defines whether we should throw during a conversion attempt,
1190 : // when trying to convert a value of type from From to the type To. This
1191 : // happens whenever a C++ conversion would have undefined behavior (and perhaps
1192 : // be platform-dependent).
1193 : template<typename From, typename To>
1194 : struct ThrowOnConvert;
1195 :
1196 : struct NeverThrow
1197 : {
1198 0 : static bool value(int32_t v) {
1199 0 : return false;
1200 : }
1201 : };
1202 :
1203 : // While int32 to float conversions can be lossy, these conversions have
1204 : // defined behavior in C++, so we don't need to care about them here. In practice,
1205 : // this means round to nearest, tie with even (zero bit in significand).
1206 : template<>
1207 : struct ThrowOnConvert<int32_t, float> : public NeverThrow {};
1208 :
1209 : template<>
1210 : struct ThrowOnConvert<uint32_t, float> : public NeverThrow {};
1211 :
1212 : // All int32 can be safely converted to doubles.
1213 : template<>
1214 : struct ThrowOnConvert<int32_t, double> : public NeverThrow {};
1215 :
1216 : template<>
1217 : struct ThrowOnConvert<uint32_t, double> : public NeverThrow {};
1218 :
1219 : // All floats can be safely converted to doubles.
1220 : template<>
1221 : struct ThrowOnConvert<float, double> : public NeverThrow {};
1222 :
1223 : // Double to float conversion for inputs which aren't in the float range are
1224 : // undefined behavior in C++, but they're defined in IEEE754.
1225 : template<>
1226 : struct ThrowOnConvert<double, float> : public NeverThrow {};
1227 :
1228 : // Float to integer conversions have undefined behavior if the float value
1229 : // is out of the representable integer range (on x86, will yield the undefined
1230 : // value pattern, namely 0x80000000; on arm, will clamp the input value), so
1231 : // check this here.
1232 : template<typename From, typename IntegerType>
1233 : struct ThrowIfNotInRange
1234 : {
1235 : static_assert(mozilla::IsIntegral<IntegerType>::value, "bad destination type");
1236 :
1237 0 : static bool value(From v) {
1238 : // Truncate to integer value before the range check.
1239 0 : double d = trunc(double(v));
1240 : // Arrange relations so NaN returns true (i.e., it throws a RangeError).
1241 0 : return !(d >= double(mozilla::MinValue<IntegerType>::value) &&
1242 0 : d <= double(mozilla::MaxValue<IntegerType>::value));
1243 : }
1244 : };
1245 :
1246 : template<>
1247 : struct ThrowOnConvert<double, int32_t> : public ThrowIfNotInRange<double, int32_t> {};
1248 :
1249 : template<>
1250 : struct ThrowOnConvert<double, uint32_t> : public ThrowIfNotInRange<double, uint32_t> {};
1251 :
1252 : template<>
1253 : struct ThrowOnConvert<float, int32_t> : public ThrowIfNotInRange<float, int32_t> {};
1254 :
1255 : template<>
1256 : struct ThrowOnConvert<float, uint32_t> : public ThrowIfNotInRange<float, uint32_t> {};
1257 :
1258 : template<typename V, typename Vret>
1259 : static bool
1260 0 : FuncConvert(JSContext* cx, unsigned argc, Value* vp)
1261 : {
1262 : typedef typename V::Elem Elem;
1263 : typedef typename Vret::Elem RetElem;
1264 :
1265 : static_assert(!mozilla::IsSame<V,Vret>::value, "Can't convert SIMD type to itself");
1266 : static_assert(V::lanes == Vret::lanes, "Can only convert from same number of lanes");
1267 : static_assert(!mozilla::IsIntegral<Elem>::value || !mozilla::IsIntegral<RetElem>::value,
1268 : "Cannot convert between integer SIMD types");
1269 :
1270 0 : CallArgs args = CallArgsFromVp(argc, vp);
1271 0 : if (args.length() != 1 || !IsVectorObject<V>(args[0]))
1272 0 : return ErrorBadArgs(cx);
1273 :
1274 0 : TypedObjectElemArray<Elem> val(args[0]);
1275 : RetElem result[Vret::lanes];
1276 0 : for (unsigned i = 0; i < V::lanes; i++) {
1277 0 : if (ThrowOnConvert<Elem, RetElem>::value(val[i])) {
1278 0 : JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SIMD_FAILED_CONVERSION);
1279 0 : return false;
1280 : }
1281 0 : result[i] = ConvertScalar<RetElem>(val[i]);
1282 : }
1283 :
1284 0 : return StoreResult<Vret>(cx, args, result);
1285 : }
1286 :
1287 : template<typename V, typename Vret>
1288 : static bool
1289 0 : FuncConvertBits(JSContext* cx, unsigned argc, Value* vp)
1290 : {
1291 : typedef typename V::Elem Elem;
1292 : typedef typename Vret::Elem RetElem;
1293 :
1294 : static_assert(!mozilla::IsSame<V, Vret>::value, "Can't convert SIMD type to itself");
1295 : static_assert(V::lanes * sizeof(Elem) == Vret::lanes * sizeof(RetElem),
1296 : "Can only bitcast from the same number of bits");
1297 :
1298 0 : CallArgs args = CallArgsFromVp(argc, vp);
1299 0 : if (args.length() != 1 || !IsVectorObject<V>(args[0]))
1300 0 : return ErrorBadArgs(cx);
1301 :
1302 : // While we could just pass the typedMem of args[0] as StoreResults' last
1303 : // argument, a GC could move the pointer to its memory in the meanwhile.
1304 : // For consistency with other SIMD functions, simply copy the input in a
1305 : // temporary array.
1306 : RetElem copy[Vret::lanes];
1307 : {
1308 0 : JS::AutoCheckCannotGC nogc(cx);
1309 0 : memcpy(copy, TypedObjectMemory<RetElem*>(args[0], nogc), Vret::lanes * sizeof(RetElem));
1310 : }
1311 0 : return StoreResult<Vret>(cx, args, copy);
1312 : }
1313 :
1314 : template<typename Vret>
1315 : static bool
1316 0 : FuncSplat(JSContext* cx, unsigned argc, Value* vp)
1317 : {
1318 : typedef typename Vret::Elem RetElem;
1319 :
1320 0 : CallArgs args = CallArgsFromVp(argc, vp);
1321 : RetElem arg;
1322 0 : if (!Vret::Cast(cx, args.get(0), &arg))
1323 0 : return false;
1324 :
1325 : RetElem result[Vret::lanes];
1326 0 : for (unsigned i = 0; i < Vret::lanes; i++)
1327 0 : result[i] = arg;
1328 0 : return StoreResult<Vret>(cx, args, result);
1329 : }
1330 :
1331 : template<typename V>
1332 : static bool
1333 : Bool(JSContext* cx, unsigned argc, Value* vp)
1334 : {
1335 : typedef typename V::Elem Elem;
1336 :
1337 : CallArgs args = CallArgsFromVp(argc, vp);
1338 :
1339 : Elem result[V::lanes];
1340 : for (unsigned i = 0; i < V::lanes; i++)
1341 : result[i] = ToBoolean(args.get(i)) ? -1 : 0;
1342 : return StoreResult<V>(cx, args, result);
1343 : }
1344 :
1345 : template<typename V, typename MaskType>
1346 : static bool
1347 : SelectBits(JSContext* cx, unsigned argc, Value* vp)
1348 : {
1349 : typedef typename V::Elem Elem;
1350 : typedef typename MaskType::Elem MaskTypeElem;
1351 :
1352 : CallArgs args = CallArgsFromVp(argc, vp);
1353 : if (args.length() != 3 || !IsVectorObject<MaskType>(args[0]) ||
1354 : !IsVectorObject<V>(args[1]) || !IsVectorObject<V>(args[2]))
1355 : {
1356 : return ErrorBadArgs(cx);
1357 : }
1358 :
1359 : TypedObjectElemArray<MaskTypeElem> val(args[0]);
1360 : TypedObjectElemArray<MaskTypeElem> tv(args[1]);
1361 : TypedObjectElemArray<MaskTypeElem> fv(args[2]);
1362 :
1363 : MaskTypeElem tr[MaskType::lanes];
1364 : for (unsigned i = 0; i < MaskType::lanes; i++)
1365 : tr[i] = And<MaskTypeElem>::apply(val[i], tv[i]);
1366 :
1367 : MaskTypeElem fr[MaskType::lanes];
1368 : for (unsigned i = 0; i < MaskType::lanes; i++)
1369 : fr[i] = And<MaskTypeElem>::apply(Not<MaskTypeElem>::apply(val[i]), fv[i]);
1370 :
1371 : MaskTypeElem orInt[MaskType::lanes];
1372 : for (unsigned i = 0; i < MaskType::lanes; i++)
1373 : orInt[i] = Or<MaskTypeElem>::apply(tr[i], fr[i]);
1374 :
1375 : Elem* result = reinterpret_cast<Elem*>(orInt);
1376 : return StoreResult<V>(cx, args, result);
1377 : }
1378 :
1379 : template<typename V, typename MaskType>
1380 : static bool
1381 0 : Select(JSContext* cx, unsigned argc, Value* vp)
1382 : {
1383 : typedef typename V::Elem Elem;
1384 : typedef typename MaskType::Elem MaskTypeElem;
1385 :
1386 0 : CallArgs args = CallArgsFromVp(argc, vp);
1387 0 : if (args.length() != 3 || !IsVectorObject<MaskType>(args[0]) ||
1388 0 : !IsVectorObject<V>(args[1]) || !IsVectorObject<V>(args[2]))
1389 : {
1390 0 : return ErrorBadArgs(cx);
1391 : }
1392 :
1393 0 : TypedObjectElemArray<MaskTypeElem> mask(args[0]);
1394 0 : TypedObjectElemArray<Elem> tv(args[1]);
1395 0 : TypedObjectElemArray<Elem> fv(args[2]);
1396 :
1397 : Elem result[V::lanes];
1398 0 : for (unsigned i = 0; i < V::lanes; i++)
1399 0 : result[i] = mask[i] ? tv[i] : fv[i];
1400 :
1401 0 : return StoreResult<V>(cx, args, result);
1402 : }
1403 :
1404 : // Extract an integer lane index from a function argument.
1405 : //
1406 : // Register an exception and return false if the argument is not suitable.
1407 : static bool
1408 0 : ArgumentToLaneIndex(JSContext* cx, JS::HandleValue v, unsigned limit, unsigned* lane)
1409 : {
1410 : uint64_t arg;
1411 0 : if (!NonStandardToIndex(cx, v, &arg))
1412 0 : return false;
1413 0 : if (arg >= limit)
1414 0 : return ErrorBadIndex(cx);
1415 :
1416 0 : *lane = unsigned(arg);
1417 0 : return true;
1418 : }
1419 :
1420 : // Look for arguments (ta, idx) where ta is a TypedArray and idx is a
1421 : // non-negative integer.
1422 : // Check that accessBytes can be accessed starting from index idx in the array.
1423 : // Return the array handle in typedArray and idx converted to a byte offset in byteStart.
1424 : static bool
1425 0 : TypedArrayFromArgs(JSContext* cx, const CallArgs& args, uint32_t accessBytes,
1426 : MutableHandleObject typedArray, size_t* byteStart)
1427 : {
1428 0 : if (!args[0].isObject())
1429 0 : return ErrorBadArgs(cx);
1430 :
1431 0 : JSObject& argobj = args[0].toObject();
1432 0 : if (!argobj.is<TypedArrayObject>())
1433 0 : return ErrorBadArgs(cx);
1434 :
1435 0 : typedArray.set(&argobj);
1436 :
1437 : uint64_t index;
1438 0 : if (!NonStandardToIndex(cx, args[1], &index))
1439 0 : return false;
1440 :
1441 : // Do the range check in 64 bits even when size_t is 32 bits.
1442 : // This can't overflow because index <= 2^53.
1443 0 : uint64_t bytes = index * typedArray->as<TypedArrayObject>().bytesPerElement();
1444 : // Keep in sync with AsmJS OnOutOfBounds function.
1445 0 : if ((bytes + accessBytes) > typedArray->as<TypedArrayObject>().byteLength())
1446 0 : return ErrorBadIndex(cx);
1447 :
1448 0 : *byteStart = bytes;
1449 :
1450 0 : return true;
1451 : }
1452 :
1453 : template<class V, unsigned NumElem>
1454 : static bool
1455 0 : Load(JSContext* cx, unsigned argc, Value* vp)
1456 : {
1457 : typedef typename V::Elem Elem;
1458 :
1459 0 : CallArgs args = CallArgsFromVp(argc, vp);
1460 0 : if (args.length() != 2)
1461 0 : return ErrorBadArgs(cx);
1462 :
1463 : size_t byteStart;
1464 0 : RootedObject typedArray(cx);
1465 0 : if (!TypedArrayFromArgs(cx, args, sizeof(Elem) * NumElem, &typedArray, &byteStart))
1466 0 : return false;
1467 :
1468 0 : Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
1469 0 : if (!typeDescr)
1470 0 : return false;
1471 :
1472 0 : Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
1473 0 : if (!result)
1474 0 : return false;
1475 :
1476 0 : JS::AutoCheckCannotGC nogc(cx);
1477 : SharedMem<Elem*> src =
1478 0 : typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>();
1479 0 : Elem* dst = reinterpret_cast<Elem*>(result->typedMem(nogc));
1480 0 : jit::AtomicOperations::podCopySafeWhenRacy(SharedMem<Elem*>::unshared(dst), src, NumElem);
1481 :
1482 0 : args.rval().setObject(*result);
1483 0 : return true;
1484 : }
1485 :
1486 : template<class V, unsigned NumElem>
1487 : static bool
1488 0 : Store(JSContext* cx, unsigned argc, Value* vp)
1489 : {
1490 : typedef typename V::Elem Elem;
1491 :
1492 0 : CallArgs args = CallArgsFromVp(argc, vp);
1493 0 : if (args.length() != 3)
1494 0 : return ErrorBadArgs(cx);
1495 :
1496 : size_t byteStart;
1497 0 : RootedObject typedArray(cx);
1498 0 : if (!TypedArrayFromArgs(cx, args, sizeof(Elem) * NumElem, &typedArray, &byteStart))
1499 0 : return false;
1500 :
1501 0 : if (!IsVectorObject<V>(args[2]))
1502 0 : return ErrorBadArgs(cx);
1503 :
1504 0 : JS::AutoCheckCannotGC nogc(cx);
1505 0 : Elem* src = TypedObjectMemory<Elem*>(args[2], nogc);
1506 : SharedMem<Elem*> dst =
1507 0 : typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>();
1508 0 : js::jit::AtomicOperations::podCopySafeWhenRacy(dst, SharedMem<Elem*>::unshared(src), NumElem);
1509 :
1510 0 : args.rval().setObject(args[2].toObject());
1511 0 : return true;
1512 : }
1513 :
1514 : #define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands) \
1515 : bool \
1516 : js::simd_float32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \
1517 : { \
1518 : return Func(cx, argc, vp); \
1519 : }
1520 0 : FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION)
1521 : #undef DEFINE_SIMD_FLOAT32X4_FUNCTION
1522 :
1523 : #define DEFINE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands) \
1524 : bool \
1525 : js::simd_float64x2_##Name(JSContext* cx, unsigned argc, Value* vp) \
1526 : { \
1527 : return Func(cx, argc, vp); \
1528 : }
1529 0 : FLOAT64X2_FUNCTION_LIST(DEFINE_SIMD_FLOAT64X2_FUNCTION)
1530 : #undef DEFINE_SIMD_FLOAT64X2_FUNCTION
1531 :
1532 : #define DEFINE_SIMD_INT8X16_FUNCTION(Name, Func, Operands) \
1533 : bool \
1534 : js::simd_int8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \
1535 : { \
1536 : return Func(cx, argc, vp); \
1537 : }
1538 0 : INT8X16_FUNCTION_LIST(DEFINE_SIMD_INT8X16_FUNCTION)
1539 : #undef DEFINE_SIMD_INT8X16_FUNCTION
1540 :
1541 : #define DEFINE_SIMD_INT16X8_FUNCTION(Name, Func, Operands) \
1542 : bool \
1543 : js::simd_int16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \
1544 : { \
1545 : return Func(cx, argc, vp); \
1546 : }
1547 0 : INT16X8_FUNCTION_LIST(DEFINE_SIMD_INT16X8_FUNCTION)
1548 : #undef DEFINE_SIMD_INT16X8_FUNCTION
1549 :
1550 : #define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands) \
1551 : bool \
1552 : js::simd_int32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \
1553 : { \
1554 : return Func(cx, argc, vp); \
1555 : }
1556 0 : INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION)
1557 : #undef DEFINE_SIMD_INT32X4_FUNCTION
1558 :
1559 : #define DEFINE_SIMD_UINT8X16_FUNCTION(Name, Func, Operands) \
1560 : bool \
1561 : js::simd_uint8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \
1562 : { \
1563 : return Func(cx, argc, vp); \
1564 : }
1565 0 : UINT8X16_FUNCTION_LIST(DEFINE_SIMD_UINT8X16_FUNCTION)
1566 : #undef DEFINE_SIMD_UINT8X16_FUNCTION
1567 :
1568 : #define DEFINE_SIMD_UINT16X8_FUNCTION(Name, Func, Operands) \
1569 : bool \
1570 : js::simd_uint16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \
1571 : { \
1572 : return Func(cx, argc, vp); \
1573 : }
1574 0 : UINT16X8_FUNCTION_LIST(DEFINE_SIMD_UINT16X8_FUNCTION)
1575 : #undef DEFINE_SIMD_UINT16X8_FUNCTION
1576 :
1577 : #define DEFINE_SIMD_UINT32X4_FUNCTION(Name, Func, Operands) \
1578 : bool \
1579 : js::simd_uint32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \
1580 : { \
1581 : return Func(cx, argc, vp); \
1582 : }
1583 0 : UINT32X4_FUNCTION_LIST(DEFINE_SIMD_UINT32X4_FUNCTION)
1584 : #undef DEFINE_SIMD_UINT32X4_FUNCTION
1585 :
1586 : #define DEFINE_SIMD_BOOL8X16_FUNCTION(Name, Func, Operands) \
1587 : bool \
1588 : js::simd_bool8x16_##Name(JSContext* cx, unsigned argc, Value* vp) \
1589 : { \
1590 : return Func(cx, argc, vp); \
1591 : }
1592 :
1593 0 : BOOL8X16_FUNCTION_LIST(DEFINE_SIMD_BOOL8X16_FUNCTION)
1594 : #undef DEFINE_SIMD_BOOL8X16_FUNCTION
1595 :
1596 : #define DEFINE_SIMD_BOOL16X8_FUNCTION(Name, Func, Operands) \
1597 : bool \
1598 : js::simd_bool16x8_##Name(JSContext* cx, unsigned argc, Value* vp) \
1599 : { \
1600 : return Func(cx, argc, vp); \
1601 : }
1602 0 : BOOL16X8_FUNCTION_LIST(DEFINE_SIMD_BOOL16X8_FUNCTION)
1603 : #undef DEFINE_SIMD_BOOL16X8_FUNCTION
1604 :
1605 : #define DEFINE_SIMD_BOOL32X4_FUNCTION(Name, Func, Operands) \
1606 : bool \
1607 : js::simd_bool32x4_##Name(JSContext* cx, unsigned argc, Value* vp) \
1608 : { \
1609 : return Func(cx, argc, vp); \
1610 : }
1611 0 : BOOL32X4_FUNCTION_LIST(DEFINE_SIMD_BOOL32X4_FUNCTION)
1612 : #undef DEFINE_SIMD_BOOL32X4_FUNCTION
1613 :
1614 : #define DEFINE_SIMD_BOOL64X2_FUNCTION(Name, Func, Operands) \
1615 : bool \
1616 : js::simd_bool64x2_##Name(JSContext* cx, unsigned argc, Value* vp) \
1617 : { \
1618 : return Func(cx, argc, vp); \
1619 : }
1620 0 : BOOL64X2_FUNCTION_LIST(DEFINE_SIMD_BOOL64X2_FUNCTION)
1621 : #undef DEFINE_SIMD_BOOL64X2_FUNCTION
|