LCOV - code coverage report
Current view: top level - js/src/builtin - SIMD.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 14 463 3.0 %
Date: 2017-07-14 16:53:18 Functions: 2 1054 0.2 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13