js/src/builtin/SIMD.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     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  */
    14 #include "builtin/SIMD.h"
    16 #include "jsapi.h"
    17 #include "jsfriendapi.h"
    19 #include "builtin/TypedObject.h"
    20 #include "js/Value.h"
    22 #include "jsobjinlines.h"
    24 using namespace js;
    26 using mozilla::ArrayLength;
    27 using mozilla::IsFinite;
    28 using mozilla::IsNaN;
    30 namespace js {
    31 extern const JSFunctionSpec Float32x4Methods[];
    32 extern const JSFunctionSpec Int32x4Methods[];
    33 }
    35 ///////////////////////////////////////////////////////////////////////////
    36 // X4
    38 static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"};
    40 template<typename Type32x4, int lane>
    41 static bool GetX4Lane(JSContext *cx, unsigned argc, Value *vp) {
    42     typedef typename Type32x4::Elem Elem;
    44     CallArgs args = CallArgsFromVp(argc, vp);
    45     if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {
    46         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
    47                              X4TypeDescr::class_.name, laneNames[lane],
    48                              InformalValueTypeName(args.thisv()));
    49         return false;
    50     }
    52     TypedObject &typedObj = args.thisv().toObject().as<TypedObject>();
    53     TypeDescr &descr = typedObj.typeDescr();
    54     if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) {
    55         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
    56                              X4TypeDescr::class_.name, laneNames[lane],
    57                              InformalValueTypeName(args.thisv()));
    58         return false;
    59     }
    61     MOZ_ASSERT(!typedObj.owner().isNeutered());
    62     Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
    63     Type32x4::setReturn(args, data[lane]);
    64     return true;
    65 }
    67 #define LANE_ACCESSOR(type, lane) \
    68 static bool type##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \
    69     return GetX4Lane<type, lane>(cx, argc, vp);\
    70 }
    72 #define FOUR_LANES_ACCESSOR(type) \
    73     LANE_ACCESSOR(type, 0); \
    74     LANE_ACCESSOR(type, 1); \
    75     LANE_ACCESSOR(type, 2); \
    76     LANE_ACCESSOR(type, 3);
    78     FOUR_LANES_ACCESSOR(Int32x4);
    79     FOUR_LANES_ACCESSOR(Float32x4);
    80 #undef FOUR_LANES_ACCESSOR
    81 #undef LANE_ACCESSOR
    83 template<typename Type32x4>
    84 static bool SignMask(JSContext *cx, unsigned argc, Value *vp) {
    85     typedef typename Type32x4::Elem Elem;
    87     CallArgs args = CallArgsFromVp(argc, vp);
    88     if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {
    89         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
    90                              X4TypeDescr::class_.name, "signMask",
    91                              InformalValueTypeName(args.thisv()));
    92         return false;
    93     }
    95     TypedObject &typedObj = args.thisv().toObject().as<TypedObject>();
    96     TypeDescr &descr = typedObj.typeDescr();
    97     if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) {
    98         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
    99                              X4TypeDescr::class_.name, "signMask",
   100                              InformalValueTypeName(args.thisv()));
   101         return false;
   102     }
   104     MOZ_ASSERT(!typedObj.owner().isNeutered());
   105     Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
   106     int32_t mx = data[0] < 0.0 ? 1 : 0;
   107     int32_t my = data[1] < 0.0 ? 1 : 0;
   108     int32_t mz = data[2] < 0.0 ? 1 : 0;
   109     int32_t mw = data[3] < 0.0 ? 1 : 0;
   110     int32_t result = mx | my << 1 | mz << 2 | mw << 3;
   111     args.rval().setInt32(result);
   112     return true;
   113 }
   115 #define SIGN_MASK(type) \
   116 static bool type##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
   117     return SignMask<Int32x4>(cx, argc, vp); \
   118 }
   119     SIGN_MASK(Float32x4);
   120     SIGN_MASK(Int32x4);
   121 #undef SIGN_MASK
   123 const Class X4TypeDescr::class_ = {
   124     "X4",
   125     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
   126     JS_PropertyStub,         /* addProperty */
   127     JS_DeletePropertyStub,   /* delProperty */
   128     JS_PropertyStub,         /* getProperty */
   129     JS_StrictPropertyStub,   /* setProperty */
   130     JS_EnumerateStub,
   131     JS_ResolveStub,
   132     JS_ConvertStub,
   133     nullptr,             /* finalize    */
   134     call,                /* call        */
   135     nullptr,             /* hasInstance */
   136     nullptr,             /* construct   */
   137     nullptr
   138 };
   140 // These classes just exist to group together various properties and so on.
   141 namespace js {
   142 class Int32x4Defn {
   143   public:
   144     static const X4TypeDescr::Type type = X4TypeDescr::TYPE_INT32;
   145     static const JSFunctionSpec TypeDescriptorMethods[];
   146     static const JSPropertySpec TypedObjectProperties[];
   147     static const JSFunctionSpec TypedObjectMethods[];
   148 };
   149 class Float32x4Defn {
   150   public:
   151     static const X4TypeDescr::Type type = X4TypeDescr::TYPE_FLOAT32;
   152     static const JSFunctionSpec TypeDescriptorMethods[];
   153     static const JSPropertySpec TypedObjectProperties[];
   154     static const JSFunctionSpec TypedObjectMethods[];
   155 };
   156 } // namespace js
   158 const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
   159     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
   160     JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
   161     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
   162     JS_FS_END
   163 };
   165 const JSPropertySpec js::Float32x4Defn::TypedObjectProperties[] = {
   166     JS_PSG("x", Float32x4Lane0, JSPROP_PERMANENT),
   167     JS_PSG("y", Float32x4Lane1, JSPROP_PERMANENT),
   168     JS_PSG("z", Float32x4Lane2, JSPROP_PERMANENT),
   169     JS_PSG("w", Float32x4Lane3, JSPROP_PERMANENT),
   170     JS_PSG("signMask", Float32x4SignMask, JSPROP_PERMANENT),
   171     JS_PS_END
   172 };
   174 const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = {
   175     JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
   176     JS_FS_END
   177 };
   179 const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = {
   180     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
   181     JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
   182     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
   183     JS_FS_END,
   184 };
   186 const JSPropertySpec js::Int32x4Defn::TypedObjectProperties[] = {
   187     JS_PSG("x", Int32x4Lane0, JSPROP_PERMANENT),
   188     JS_PSG("y", Int32x4Lane1, JSPROP_PERMANENT),
   189     JS_PSG("z", Int32x4Lane2, JSPROP_PERMANENT),
   190     JS_PSG("w", Int32x4Lane3, JSPROP_PERMANENT),
   191     JS_PSG("signMask", Int32x4SignMask, JSPROP_PERMANENT),
   192     JS_PS_END
   193 };
   195 const JSFunctionSpec js::Int32x4Defn::TypedObjectMethods[] = {
   196     JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
   197     JS_FS_END
   198 };
   200 template<typename T>
   201 static JSObject *
   202 CreateX4Class(JSContext *cx,
   203               Handle<GlobalObject*> global,
   204               HandlePropertyName stringRepr)
   205 {
   206     const X4TypeDescr::Type type = T::type;
   208     RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
   209     if (!funcProto)
   210         return nullptr;
   212     // Create type constructor itself and initialize its reserved slots.
   214     Rooted<X4TypeDescr*> x4(cx);
   215     x4 = NewObjectWithProto<X4TypeDescr>(cx, funcProto, global, TenuredObject);
   216     if (!x4)
   217         return nullptr;
   219     x4->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(TypeDescr::X4));
   220     x4->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
   221     x4->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(X4TypeDescr::size(type)));
   222     x4->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(X4TypeDescr::alignment(type)));
   223     x4->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
   224     x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
   226     if (!CreateUserSizeAndAlignmentProperties(cx, x4))
   227         return nullptr;
   229     // Create prototype property, which inherits from Object.prototype.
   231     RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
   232     if (!objProto)
   233         return nullptr;
   234     Rooted<TypedProto*> proto(cx);
   235     proto = NewObjectWithProto<TypedProto>(cx, objProto, nullptr, TenuredObject);
   236     if (!proto)
   237         return nullptr;
   238     proto->initTypeDescrSlot(*x4);
   239     x4->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
   241     // Link constructor to prototype and install properties.
   243     if (!JS_DefineFunctions(cx, x4, T::TypeDescriptorMethods))
   244         return nullptr;
   246     if (!LinkConstructorAndPrototype(cx, x4, proto) ||
   247         !DefinePropertiesAndBrand(cx, proto, T::TypedObjectProperties,
   248                                   T::TypedObjectMethods))
   249     {
   250         return nullptr;
   251     }
   253     return x4;
   254 }
   256 bool
   257 X4TypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
   258 {
   259     CallArgs args = CallArgsFromVp(argc, vp);
   260     const uint32_t LANES = 4;
   262     if (args.length() < LANES) {
   263         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
   264                              args.callee().getClass()->name, "3", "s");
   265         return false;
   266     }
   268     double values[LANES];
   269     for (uint32_t i = 0; i < LANES; i++) {
   270         if (!ToNumber(cx, args[i], &values[i]))
   271             return false;
   272     }
   274     Rooted<X4TypeDescr*> descr(cx, &args.callee().as<X4TypeDescr>());
   275     Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0));
   276     if (!result)
   277         return false;
   279     MOZ_ASSERT(!result->owner().isNeutered());
   280     switch (descr->type()) {
   281 #define STORE_LANES(_constant, _type, _name)                                  \
   282       case _constant:                                                         \
   283       {                                                                       \
   284         _type *mem = reinterpret_cast<_type*>(result->typedMem());            \
   285         for (uint32_t i = 0; i < LANES; i++) {                                \
   286             mem[i] = ConvertScalar<_type>(values[i]);                         \
   287         }                                                                     \
   288         break;                                                                \
   289       }
   290       JS_FOR_EACH_X4_TYPE_REPR(STORE_LANES)
   291 #undef STORE_LANES
   292     }
   293     args.rval().setObject(*result);
   294     return true;
   295 }
   297 ///////////////////////////////////////////////////////////////////////////
   298 // SIMD class
   300 const Class SIMDObject::class_ = {
   301         "SIMD",
   302         JSCLASS_HAS_CACHED_PROTO(JSProto_SIMD),
   303         JS_PropertyStub,         /* addProperty */
   304         JS_DeletePropertyStub,   /* delProperty */
   305         JS_PropertyStub,         /* getProperty */
   306         JS_StrictPropertyStub,   /* setProperty */
   307         JS_EnumerateStub,
   308         JS_ResolveStub,
   309         JS_ConvertStub,
   310         nullptr,             /* finalize    */
   311         nullptr,             /* call        */
   312         nullptr,             /* hasInstance */
   313         nullptr,             /* construct   */
   314         nullptr
   315 };
   317 JSObject *
   318 SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
   319 {
   320     // SIMD relies on having the TypedObject module initialized.
   321     // In particular, the self-hosted code for array() wants
   322     // to be able to call GetTypedObjectModule(). It is NOT necessary
   323     // to install the TypedObjectModule global, but at the moment
   324     // those two things are not separable.
   325     if (!global->getOrCreateTypedObjectModule(cx))
   326         return nullptr;
   328     // Create SIMD Object.
   329     RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
   330     if(!objProto)
   331         return nullptr;
   332     RootedObject SIMD(cx, NewObjectWithGivenProto(cx, &SIMDObject::class_, objProto,
   333                                                   global, SingletonObject));
   334     if (!SIMD)
   335         return nullptr;
   337     // float32x4
   339     RootedObject float32x4Object(cx);
   340     float32x4Object = CreateX4Class<Float32x4Defn>(cx, global,
   341                                                    cx->names().float32x4);
   342     if (!float32x4Object)
   343         return nullptr;
   345     RootedValue float32x4Value(cx, ObjectValue(*float32x4Object));
   346     if (!JS_DefineFunctions(cx, float32x4Object, Float32x4Methods) ||
   347         !JSObject::defineProperty(cx, SIMD, cx->names().float32x4,
   348                                   float32x4Value, nullptr, nullptr,
   349                                   JSPROP_READONLY | JSPROP_PERMANENT))
   350     {
   351         return nullptr;
   352     }
   354     // int32x4
   356     RootedObject int32x4Object(cx);
   357     int32x4Object = CreateX4Class<Int32x4Defn>(cx, global,
   358                                                cx->names().int32x4);
   359     if (!int32x4Object)
   360         return nullptr;
   362     RootedValue int32x4Value(cx, ObjectValue(*int32x4Object));
   363     if (!JS_DefineFunctions(cx, int32x4Object, Int32x4Methods) ||
   364         !JSObject::defineProperty(cx, SIMD, cx->names().int32x4,
   365                                   int32x4Value, nullptr, nullptr,
   366                                   JSPROP_READONLY | JSPROP_PERMANENT))
   367     {
   368         return nullptr;
   369     }
   371     RootedValue SIMDValue(cx, ObjectValue(*SIMD));
   373     // Everything is set up, install SIMD on the global object.
   374     if (!JSObject::defineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0))
   375         return nullptr;
   377     global->setConstructor(JSProto_SIMD, SIMDValue);
   379     // Define float32x4 functions and install as a property of the SIMD object.
   380     global->setFloat32x4TypeDescr(*float32x4Object);
   382     // Define int32x4 functions and install as a property of the SIMD object.
   383     global->setInt32x4TypeDescr(*int32x4Object);
   385     return SIMD;
   386 }
   388 JSObject *
   389 js_InitSIMDClass(JSContext *cx, HandleObject obj)
   390 {
   391     JS_ASSERT(obj->is<GlobalObject>());
   392     Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
   393     return SIMDObject::initClass(cx, global);
   394 }
   396 template<typename V>
   397 static bool
   398 IsVectorObject(HandleValue v)
   399 {
   400     if (!v.isObject())
   401         return false;
   403     JSObject &obj = v.toObject();
   404     if (!obj.is<TypedObject>())
   405         return false;
   407     TypeDescr &typeRepr = obj.as<TypedObject>().typeDescr();
   408     if (typeRepr.kind() != TypeDescr::X4)
   409         return false;
   411     return typeRepr.as<X4TypeDescr>().type() == V::type;
   412 }
   414 template<typename Elem>
   415 static Elem
   416 TypedObjectMemory(HandleValue v)
   417 {
   418     TypedObject &obj = v.toObject().as<TypedObject>();
   419     MOZ_ASSERT(!obj.owner().isNeutered());
   420     return reinterpret_cast<Elem>(obj.typedMem());
   421 }
   423 template<typename V>
   424 JSObject *
   425 js::Create(JSContext *cx, typename V::Elem *data)
   426 {
   427     typedef typename V::Elem Elem;
   428     Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global()));
   429     JS_ASSERT(typeDescr);
   431     Rooted<TypedObject *> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
   432     if (!result)
   433         return nullptr;
   435     MOZ_ASSERT(!result->owner().isNeutered());
   436     Elem *resultMem = reinterpret_cast<Elem *>(result->typedMem());
   437     memcpy(resultMem, data, sizeof(Elem) * V::lanes);
   438     return result;
   439 }
   441 template JSObject *js::Create<Float32x4>(JSContext *cx, Float32x4::Elem *data);
   442 template JSObject *js::Create<Int32x4>(JSContext *cx, Int32x4::Elem *data);
   444 namespace js {
   445 template<typename T, typename V>
   446 struct Abs {
   447     static inline T apply(T x, T zero) { return V::toType(x < 0 ? -1 * x : x); }
   448 };
   449 template<typename T, typename V>
   450 struct Neg {
   451     static inline T apply(T x, T zero) { return V::toType(-1 * x); }
   452 };
   453 template<typename T, typename V>
   454 struct Not {
   455     static inline T apply(T x, T zero) { return V::toType(~x); }
   456 };
   457 template<typename T, typename V>
   458 struct Rec {
   459     static inline T apply(T x, T zero) { return V::toType(1 / x); }
   460 };
   461 template<typename T, typename V>
   462 struct RecSqrt {
   463     static inline T apply(T x, T zero) { return V::toType(1 / sqrt(x)); }
   464 };
   465 template<typename T, typename V>
   466 struct Sqrt {
   467     static inline T apply(T x, T zero) { return V::toType(sqrt(x)); }
   468 };
   469 template<typename T, typename V>
   470 struct Add {
   471     static inline T apply(T l, T r) { return V::toType(l + r); }
   472 };
   473 template<typename T, typename V>
   474 struct Sub {
   475     static inline T apply(T l, T r) { return V::toType(l - r); }
   476 };
   477 template<typename T, typename V>
   478 struct Div {
   479     static inline T apply(T l, T r) { return V::toType(l / r); }
   480 };
   481 template<typename T, typename V>
   482 struct Mul {
   483     static inline T apply(T l, T r) { return V::toType(l * r); }
   484 };
   485 template<typename T, typename V>
   486 struct Minimum {
   487     static inline T apply(T l, T r) { return V::toType(l < r ? l : r); }
   488 };
   489 template<typename T, typename V>
   490 struct Maximum {
   491     static inline T apply(T l, T r) { return V::toType(l > r ? l : r); }
   492 };
   493 template<typename T, typename V>
   494 struct LessThan {
   495     static inline T apply(T l, T r) { return V::toType(l < r ? 0xFFFFFFFF : 0x0); }
   496 };
   497 template<typename T, typename V>
   498 struct LessThanOrEqual {
   499     static inline T apply(T l, T r) { return V::toType(l <= r ? 0xFFFFFFFF : 0x0); }
   500 };
   501 template<typename T, typename V>
   502 struct GreaterThan {
   503     static inline T apply(T l, T r) { return V::toType(l > r ? 0xFFFFFFFF : 0x0); }
   504 };
   505 template<typename T, typename V>
   506 struct GreaterThanOrEqual {
   507     static inline T apply(T l, T r) { return V::toType(l >= r ? 0xFFFFFFFF : 0x0); }
   508 };
   509 template<typename T, typename V>
   510 struct Equal {
   511     static inline T apply(T l, T r) { return V::toType(l == r ? 0xFFFFFFFF : 0x0); }
   512 };
   513 template<typename T, typename V>
   514 struct NotEqual {
   515     static inline T apply(T l, T r) { return V::toType(l != r ? 0xFFFFFFFF : 0x0); }
   516 };
   517 template<typename T, typename V>
   518 struct Xor {
   519     static inline T apply(T l, T r) { return V::toType(l ^ r); }
   520 };
   521 template<typename T, typename V>
   522 struct And {
   523     static inline T apply(T l, T r) { return V::toType(l & r); }
   524 };
   525 template<typename T, typename V>
   526 struct Or {
   527     static inline T apply(T l, T r) { return V::toType(l | r); }
   528 };
   529 template<typename T, typename V>
   530 struct Scale {
   531     static inline T apply(int32_t lane, T scalar, T x) { return V::toType(scalar * x); }
   532 };
   533 template<typename T, typename V>
   534 struct WithX {
   535     static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 0 ? scalar : x); }
   536 };
   537 template<typename T, typename V>
   538 struct WithY {
   539     static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 1 ? scalar : x); }
   540 };
   541 template<typename T, typename V>
   542 struct WithZ {
   543     static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 2 ? scalar : x); }
   544 };
   545 template<typename T, typename V>
   546 struct WithW {
   547     static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 3 ? scalar : x); }
   548 };
   549 template<typename T, typename V>
   550 struct WithFlagX {
   551     static inline T apply(T l, T f, T x) { return V::toType(l == 0 ? (f ? 0xFFFFFFFF : 0x0) : x); }
   552 };
   553 template<typename T, typename V>
   554 struct WithFlagY {
   555     static inline T apply(T l, T f, T x) { return V::toType(l == 1 ? (f ? 0xFFFFFFFF : 0x0) : x); }
   556 };
   557 template<typename T, typename V>
   558 struct WithFlagZ {
   559     static inline T apply(T l, T f, T x) { return V::toType(l == 2 ? (f ? 0xFFFFFFFF : 0x0) : x); }
   560 };
   561 template<typename T, typename V>
   562 struct WithFlagW {
   563     static inline T apply(T l, T f, T x) { return V::toType(l == 3 ? (f ? 0xFFFFFFFF : 0x0) : x); }
   564 };
   565 template<typename T, typename V>
   566 struct Shuffle {
   567     static inline int32_t apply(int32_t l, int32_t mask) { return V::toType((mask >> l) & 0x3); }
   568 };
   569 }
   571 template<typename V, typename Op, typename Vret>
   572 static bool
   573 Func(JSContext *cx, unsigned argc, Value *vp)
   574 {
   575     typedef typename V::Elem Elem;
   576     typedef typename Vret::Elem RetElem;
   578     CallArgs args = CallArgsFromVp(argc, vp);
   579     if (args.length() != 1 && args.length() != 2) {
   580         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   581         return false;
   582     }
   584     RetElem result[Vret::lanes];
   585     if (args.length() == 1) {
   586         if (!IsVectorObject<V>(args[0])) {
   587             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   588             return false;
   589         }
   591         Elem *val = TypedObjectMemory<Elem *>(args[0]);
   592         for (int32_t i = 0; i < Vret::lanes; i++)
   593             result[i] = Op::apply(val[i], 0);
   594     } else {
   595         JS_ASSERT(args.length() == 2);
   596         if(!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]))
   597         {
   598             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   599             return false;
   600         }
   602         Elem *left = TypedObjectMemory<Elem *>(args[0]);
   603         Elem *right = TypedObjectMemory<Elem *>(args[1]);
   604         for (int32_t i = 0; i < Vret::lanes; i++)
   605             result[i] = Op::apply(left[i], right[i]);
   606     }
   608     RootedObject obj(cx, Create<Vret>(cx, result));
   609     if (!obj)
   610         return false;
   612     args.rval().setObject(*obj);
   613     return true;
   614 }
   616 template<typename V, typename OpWith, typename Vret>
   617 static bool
   618 FuncWith(JSContext *cx, unsigned argc, Value *vp)
   619 {
   620     typedef typename V::Elem Elem;
   621     typedef typename Vret::Elem RetElem;
   623     CallArgs args = CallArgsFromVp(argc, vp);
   624     if (args.length() != 2 || !IsVectorObject<V>(args[0]) ||
   625         (!args[1].isNumber() && !args[1].isBoolean()))
   626     {
   627         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   628         return false;
   629     }
   631     Elem *val = TypedObjectMemory<Elem *>(args[0]);
   632     RetElem result[Vret::lanes];
   634     if (args[1].isNumber()) {
   635         Elem withAsNumber;
   636         if (!Vret::toType(cx, args[1], &withAsNumber))
   637             return false;
   638         for (int32_t i = 0; i < Vret::lanes; i++)
   639             result[i] = OpWith::apply(i, withAsNumber, val[i]);
   640     } else if (args[1].isBoolean()) {
   641         bool withAsBool = args[1].toBoolean();
   642         for (int32_t i = 0; i < Vret::lanes; i++)
   643             result[i] = OpWith::apply(i, withAsBool, val[i]);
   644     }
   646     RootedObject obj(cx, Create<Vret>(cx, result));
   647     if (!obj)
   648         return false;
   650     args.rval().setObject(*obj);
   651     return true;
   652 }
   654 template<typename V, typename OpShuffle, typename Vret>
   655 static bool
   656 FuncShuffle(JSContext *cx, unsigned argc, Value *vp)
   657 {
   658     typedef typename V::Elem Elem;
   659     typedef typename Vret::Elem RetElem;
   661     CallArgs args = CallArgsFromVp(argc, vp);
   662     if (args.length() != 2 && args.length() != 3) {
   663         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   664         return false;
   665     }
   667     RetElem result[Vret::lanes];
   668     if (args.length() == 2) {
   669         if (!IsVectorObject<V>(args[0]) || !args[1].isNumber())
   670         {
   671             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   672             return false;
   673         }
   675         Elem *val = TypedObjectMemory<Elem *>(args[0]);;
   676         Elem arg1;
   677         if (!Vret::toType(cx, args[1], &arg1))
   678             return false;
   680         for (int32_t i = 0; i < Vret::lanes; i++)
   681             result[i] = val[OpShuffle::apply(i * 2, arg1)];
   682     } else {
   683         JS_ASSERT(args.length() == 3);
   684         if (!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]) || !args[2].isNumber())
   685         {
   686             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   687             return false;
   688         }
   690         Elem *val1 = TypedObjectMemory<Elem *>(args[0]);
   691         Elem *val2 = TypedObjectMemory<Elem *>(args[1]);
   692         Elem arg2;
   693         if (!Vret::toType(cx, args[2], &arg2))
   694             return false;
   696         for (int32_t i = 0; i < Vret::lanes; i++) {
   697             if (i < Vret::lanes / 2)
   698                 result[i] = val1[OpShuffle::apply(i * 2, arg2)];
   699             else
   700                 result[i] = val2[OpShuffle::apply(i * 2, arg2)];
   701         }
   702     }
   704     RootedObject obj(cx, Create<Vret>(cx, result));
   705     if (!obj)
   706         return false;
   708     args.rval().setObject(*obj);
   709     return true;
   710 }
   712 template<typename V, typename Vret>
   713 static bool
   714 FuncConvert(JSContext *cx, unsigned argc, Value *vp)
   715 {
   716     typedef typename V::Elem Elem;
   717     typedef typename Vret::Elem RetElem;
   719     CallArgs args = CallArgsFromVp(argc, vp);
   720     if (args.length() != 1 || !IsVectorObject<V>(args[0]))
   721     {
   722         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   723         return false;
   724     }
   726     Elem *val = TypedObjectMemory<Elem *>(args[0]);
   727     RetElem result[Vret::lanes];
   728     for (int32_t i = 0; i < Vret::lanes; i++)
   729         result[i] = RetElem(val[i]);
   731     RootedObject obj(cx, Create<Vret>(cx, result));
   732     if (!obj)
   733         return false;
   735     args.rval().setObject(*obj);
   736     return true;
   737 }
   739 template<typename V, typename Vret>
   740 static bool
   741 FuncConvertBits(JSContext *cx, unsigned argc, Value *vp)
   742 {
   743     typedef typename Vret::Elem RetElem;
   745     CallArgs args = CallArgsFromVp(argc, vp);
   746     if (args.length() != 1 || !IsVectorObject<V>(args[0]))
   747     {
   748         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   749         return false;
   750     }
   752     RetElem *val = TypedObjectMemory<RetElem *>(args[0]);
   753     RootedObject obj(cx, Create<Vret>(cx, val));
   754     if (!obj)
   755         return false;
   757     args.rval().setObject(*obj);
   758     return true;
   759 }
   761 template<typename Vret>
   762 static bool
   763 FuncZero(JSContext *cx, unsigned argc, Value *vp)
   764 {
   765     typedef typename Vret::Elem RetElem;
   767     CallArgs args = CallArgsFromVp(argc, vp);
   768     if (args.length() != 0) {
   769         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   770         return false;
   771     }
   773     RetElem result[Vret::lanes];
   774     for (int32_t i = 0; i < Vret::lanes; i++)
   775         result[i] = RetElem(0);
   777     RootedObject obj(cx, Create<Vret>(cx, result));
   778     if (!obj)
   779         return false;
   781     args.rval().setObject(*obj);
   782     return true;
   783 }
   785 template<typename Vret>
   786 static bool
   787 FuncSplat(JSContext *cx, unsigned argc, Value *vp)
   788 {
   789     typedef typename Vret::Elem RetElem;
   791     CallArgs args = CallArgsFromVp(argc, vp);
   792     if (args.length() != 1 || !args[0].isNumber()) {
   793         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   794         return false;
   795     }
   797     RetElem arg;
   798     if (!Vret::toType(cx, args[0], &arg))
   799         return false;
   801     RetElem result[Vret::lanes];
   802     for (int32_t i = 0; i < Vret::lanes; i++)
   803         result[i] = arg;
   805     RootedObject obj(cx, Create<Vret>(cx, result));
   806     if (!obj)
   807         return false;
   809     args.rval().setObject(*obj);
   810     return true;
   811 }
   813 static bool
   814 Int32x4Bool(JSContext *cx, unsigned argc, Value *vp)
   815 {
   816     CallArgs args = CallArgsFromVp(argc, vp);
   817     if (args.length() != 4 ||
   818         !args[0].isBoolean() || !args[1].isBoolean() ||
   819         !args[2].isBoolean() || !args[3].isBoolean())
   820     {
   821         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   822         return false;
   823     }
   825     int32_t result[Int32x4::lanes];
   826     for (int32_t i = 0; i < Int32x4::lanes; i++)
   827         result[i] = args[i].toBoolean() ? 0xFFFFFFFF : 0x0;
   829     RootedObject obj(cx, Create<Int32x4>(cx, result));
   830     if (!obj)
   831         return false;
   833     args.rval().setObject(*obj);
   834     return true;
   835 }
   837 static bool
   838 Float32x4Clamp(JSContext *cx, unsigned argc, Value *vp)
   839 {
   840     CallArgs args = CallArgsFromVp(argc, vp);
   841     if (args.length() != 3 || !IsVectorObject<Float32x4>(args[0]) ||
   842         !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
   843     {
   844         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   845         return false;
   846     }
   848     float *val = TypedObjectMemory<float *>(args[0]);
   849     float *lowerLimit = TypedObjectMemory<float *>(args[1]);
   850     float *upperLimit = TypedObjectMemory<float *>(args[2]);
   852     float result[Float32x4::lanes];
   853     for (int32_t i = 0; i < Float32x4::lanes; i++) {
   854         result[i] = val[i] < lowerLimit[i] ? lowerLimit[i] : val[i];
   855         result[i] = result[i] > upperLimit[i] ? upperLimit[i] : result[i];
   856     }
   858     RootedObject obj(cx, Create<Float32x4>(cx, result));
   859     if (!obj)
   860         return false;
   862     args.rval().setObject(*obj);
   863     return true;
   864 }
   866 static bool
   867 Int32x4Select(JSContext *cx, unsigned argc, Value *vp)
   868 {
   869     CallArgs args = CallArgsFromVp(argc, vp);
   870     if (args.length() != 3 || !IsVectorObject<Int32x4>(args[0]) ||
   871         !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
   872     {
   873         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
   874         return false;
   875     }
   877     int32_t *val = TypedObjectMemory<int32_t *>(args[0]);
   878     int32_t *tv = TypedObjectMemory<int32_t *>(args[1]);
   879     int32_t *fv = TypedObjectMemory<int32_t *>(args[2]);
   881     int32_t tr[Int32x4::lanes];
   882     for (int32_t i = 0; i < Int32x4::lanes; i++)
   883         tr[i] = And<int32_t, Int32x4>::apply(val[i], tv[i]);
   885     int32_t fr[Int32x4::lanes];
   886     for (int32_t i = 0; i < Int32x4::lanes; i++)
   887         fr[i] = And<int32_t, Int32x4>::apply(Not<int32_t, Int32x4>::apply(val[i], 0), fv[i]);
   889     int32_t orInt[Int32x4::lanes];
   890     for (int32_t i = 0; i < Int32x4::lanes; i++)
   891         orInt[i] = Or<int32_t, Int32x4>::apply(tr[i], fr[i]);
   893     float *result = reinterpret_cast<float *>(orInt);
   894     RootedObject obj(cx, Create<Float32x4>(cx, result));
   895     if (!obj)
   896         return false;
   898     args.rval().setObject(*obj);
   899     return true;
   900 }
   902 #define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId)     \
   903 bool                                                                           \
   904 js::simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp)             \
   905 {                                                                              \
   906     return Func(cx, argc, vp);                                                 \
   907 }
   908 FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION)
   909 #undef DEFINE_SIMD_FLOAT32x4_FUNCTION
   911 #define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId)       \
   912 bool                                                                           \
   913 js::simd_int32x4_##Name(JSContext *cx, unsigned argc, Value *vp)               \
   914 {                                                                              \
   915     return Func(cx, argc, vp);                                                 \
   916 }
   917 INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION)
   918 #undef DEFINE_SIMD_INT32X4_FUNCTION
   920 const JSFunctionSpec js::Float32x4Methods[] = {
   921 #define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags, MIRId)       \
   922         JS_FN(#Name, js::simd_float32x4_##Name, Operands, Flags),
   923         FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM)
   924 #undef SIMD_FLOAT32x4_FUNCTION_ITEM
   925         JS_FS_END
   926 };
   928 const JSFunctionSpec js::Int32x4Methods[] = {
   929 #define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags, MIRId)         \
   930         JS_FN(#Name, js::simd_int32x4_##Name, Operands, Flags),
   931         INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM)
   932 #undef SIMD_INT32X4_FUNCTION_ITEM
   933         JS_FS_END
   934 };

mercurial