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