From 20579b54c2712fad22b0638e819ed6e6e5850d41 Mon Sep 17 00:00:00 2001 From: "Nicholas D. Matsakis" Date: Wed, 20 Nov 2013 15:11:45 -0500 Subject: [PATCH] Bug 938728 - Add float32x4 and int32x4 data constructors r=till --- js/src/builtin/TypeRepresentation.cpp | 127 +++++++--- js/src/builtin/TypeRepresentation.h | 58 ++++- js/src/builtin/TypedObject.cpp | 226 +++++++++++++++++- js/src/builtin/TypedObject.h | 12 + js/src/builtin/TypedObject.js | 111 ++++++++- js/src/builtin/TypedObjectConstants.h | 20 +- js/src/jit/IonBuilder.cpp | 18 +- js/src/jsapi.cpp | 76 +++++- js/src/jsapi.h | 18 +- .../TypedObject/simd/float32x4alignment.js | 30 +++ .../TypedObject/simd/float32x4getters.js | 51 ++++ .../TypedObject/simd/float32x4handle.js | 49 ++++ .../ecma_6/TypedObject/simd/float32x4reify.js | 36 +++ .../TypedObject/simd/float32x4setter.js | 45 ++++ .../TypedObject/simd/int32x4alignment.js | 30 +++ .../ecma_6/TypedObject/simd/int32x4getters.js | 51 ++++ .../ecma_6/TypedObject/simd/int32x4handle.js | 49 ++++ .../ecma_6/TypedObject/simd/int32x4reify.js | 36 +++ .../ecma_6/TypedObject/simd/int32x4setter.js | 45 ++++ js/src/tests/ecma_6/TypedObject/simd/shell.js | 0 js/src/vm/CommonPropertyNames.h | 6 + 21 files changed, 1035 insertions(+), 59 deletions(-) create mode 100644 js/src/tests/ecma_6/TypedObject/simd/float32x4alignment.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/float32x4getters.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/float32x4handle.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/float32x4reify.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/float32x4setter.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/int32x4alignment.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/int32x4getters.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/int32x4handle.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/int32x4reify.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/int32x4setter.js create mode 100644 js/src/tests/ecma_6/TypedObject/simd/shell.js diff --git a/js/src/builtin/TypeRepresentation.cpp b/js/src/builtin/TypeRepresentation.cpp index 26db68d5910..09af8fd2c23 100644 --- a/js/src/builtin/TypeRepresentation.cpp +++ b/js/src/builtin/TypeRepresentation.cpp @@ -62,6 +62,9 @@ TypeRepresentationHasher::match(TypeRepresentation *key1, case TypeRepresentation::Reference: return matchReferences(key1->asReference(), key2->asReference()); + case TypeRepresentation::X4: + return matchX4s(key1->asX4(), key2->asX4()); + case TypeRepresentation::Struct: return matchStructs(key1->asStruct(), key2->asStruct()); @@ -86,6 +89,13 @@ TypeRepresentationHasher::matchReferences(ReferenceTypeRepresentation *key1, return key1->type() == key2->type(); } +bool +TypeRepresentationHasher::matchX4s(X4TypeRepresentation *key1, + X4TypeRepresentation *key2) +{ + return key1->type() == key2->type(); +} + bool TypeRepresentationHasher::matchStructs(StructTypeRepresentation *key1, StructTypeRepresentation *key2) @@ -122,6 +132,9 @@ TypeRepresentationHasher::hash(TypeRepresentation *key) { case TypeRepresentation::Reference: return hashReference(key->asReference()); + case TypeRepresentation::X4: + return hashX4(key->asX4()); + case TypeRepresentation::Struct: return hashStruct(key->asStruct()); @@ -144,6 +157,12 @@ TypeRepresentationHasher::hashReference(ReferenceTypeRepresentation *key) return HashGeneric(key->kind(), key->type()); } +HashNumber +TypeRepresentationHasher::hashX4(X4TypeRepresentation *key) +{ + return HashGeneric(key->kind(), key->type()); +} + HashNumber TypeRepresentationHasher::hashStruct(StructTypeRepresentation *key) { @@ -172,32 +191,30 @@ TypeRepresentation::TypeRepresentation(Kind kind, size_t size, opaque_(opaque) {} +static size_t ScalarSizes[] = { +#define SCALAR_SIZE(_kind, _type, _name) \ + sizeof(_type), + JS_FOR_EACH_SCALAR_TYPE_REPR(SCALAR_SIZE) 0 +#undef SCALAR_SIZE +}; + ScalarTypeRepresentation::ScalarTypeRepresentation(Type type) - : TypeRepresentation(Scalar, 0, 1, false), + : TypeRepresentation(Scalar, ScalarSizes[type], ScalarSizes[type], false), type_(type) { - switch (type) { - case TYPE_INT8: - case TYPE_UINT8: - case TYPE_UINT8_CLAMPED: - size_ = alignment_ = 1; - break; +} - case TYPE_INT16: - case TYPE_UINT16: - size_ = alignment_ = 2; - break; +static size_t X4Sizes[] = { +#define X4_SIZE(_kind, _type, _name) \ + sizeof(_type) * 4, + JS_FOR_EACH_X4_TYPE_REPR(X4_SIZE) 0 +#undef X4_SIZE +}; - case TYPE_INT32: - case TYPE_UINT32: - case TYPE_FLOAT32: - size_ = alignment_ = 4; - break; - - case TYPE_FLOAT64: - size_ = alignment_ = 8; - break; - } +X4TypeRepresentation::X4TypeRepresentation(Type type) + : TypeRepresentation(X4, X4Sizes[type], X4Sizes[type], false), + type_(type) +{ } ReferenceTypeRepresentation::ReferenceTypeRepresentation(Type type) @@ -358,6 +375,11 @@ TypeRepresentation::addToTableOrFree(JSContext *cx, Int32Value(asReference()->type())); break; + case X4: + ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_TYPE, + Int32Value(asX4()->type())); + break; + case Struct: break; } @@ -366,27 +388,43 @@ TypeRepresentation::addToTableOrFree(JSContext *cx, return &*ownerObject; } +namespace js { +class TypeRepresentationHelper { + public: + template + static JSObject *CreateSimple(JSContext *cx, typename T::Type type) { + JSCompartment *comp = cx->compartment(); + + T sample(type); + TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample); + if (p) + return (*p)->ownerObject(); + + // Note: cannot use cx->new_ because constructor is private. + T *ptr = (T *) cx->malloc_(sizeof(T)); + if (!ptr) + return nullptr; + new(ptr) T(type); + + return ptr->addToTableOrFree(cx, p); + } +}; +} // namespace js + /*static*/ JSObject * ScalarTypeRepresentation::Create(JSContext *cx, ScalarTypeRepresentation::Type type) { - JSCompartment *comp = cx->compartment(); + return TypeRepresentationHelper::CreateSimple(cx, type); +} - ScalarTypeRepresentation sample(type); - TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample); - if (p) - return (*p)->ownerObject(); - - // Note: cannot use cx->new_ because constructor is private. - ScalarTypeRepresentation *ptr = - (ScalarTypeRepresentation *) cx->malloc_( - sizeof(ScalarTypeRepresentation)); - if (!ptr) - return nullptr; - new(ptr) ScalarTypeRepresentation(type); - - return ptr->addToTableOrFree(cx, p); +/*static*/ +JSObject * +X4TypeRepresentation::Create(JSContext *cx, + X4TypeRepresentation::Type type) +{ + return TypeRepresentationHelper::CreateSimple(cx, type); } /*static*/ @@ -499,6 +537,7 @@ TypeRepresentation::traceFields(JSTracer *trace) switch (kind()) { case Scalar: case Reference: + case X4: break; case Struct: @@ -552,6 +591,9 @@ TypeRepresentation::appendString(JSContext *cx, StringBuffer &contents) case Reference: return asReference()->appendStringReference(cx, contents); + case X4: + return asX4()->appendStringX4(cx, contents); + case Array: return asArray()->appendStringArray(cx, contents); @@ -607,6 +649,18 @@ ReferenceTypeRepresentation::appendStringReference(JSContext *cx, StringBuffer & MOZ_ASSUME_UNREACHABLE("Invalid type"); } +bool +X4TypeRepresentation::appendStringX4(JSContext *cx, StringBuffer &contents) +{ + switch (type()) { + case TYPE_FLOAT32: + return contents.append("float32x4"); + case TYPE_INT32: + return contents.append("int32x4"); + } + MOZ_ASSUME_UNREACHABLE("Invalid type"); +} + bool ArrayTypeRepresentation::appendStringArray(JSContext *cx, StringBuffer &contents) { @@ -672,6 +726,7 @@ visitReferences(TypeRepresentation *repr, uint8_t *mem, V& visitor) switch (repr->kind()) { case TypeRepresentation::Scalar: + case TypeRepresentation::X4: return; case TypeRepresentation::Reference: diff --git a/js/src/builtin/TypeRepresentation.h b/js/src/builtin/TypeRepresentation.h index 4dce2f90265..33b3d39b910 100644 --- a/js/src/builtin/TypeRepresentation.h +++ b/js/src/builtin/TypeRepresentation.h @@ -68,6 +68,7 @@ namespace js { class TypeRepresentation; class ScalarTypeRepresentation; class ReferenceTypeRepresentation; +class X4TypeRepresentation; class ArrayTypeRepresentation; class StructTypeRepresentation; @@ -83,6 +84,7 @@ struct TypeRepresentationHasher private: static HashNumber hashScalar(ScalarTypeRepresentation *key); static HashNumber hashReference(ReferenceTypeRepresentation *key); + static HashNumber hashX4(X4TypeRepresentation *key); static HashNumber hashStruct(StructTypeRepresentation *key); static HashNumber hashArray(ArrayTypeRepresentation *key); @@ -90,6 +92,8 @@ struct TypeRepresentationHasher ScalarTypeRepresentation *key2); static bool matchReferences(ReferenceTypeRepresentation *key1, ReferenceTypeRepresentation *key2); + static bool matchX4s(X4TypeRepresentation *key1, + X4TypeRepresentation *key2); static bool matchStructs(StructTypeRepresentation *key1, StructTypeRepresentation *key2); static bool matchArrays(ArrayTypeRepresentation *key1, @@ -100,11 +104,14 @@ typedef js::HashSet TypeRepresentationHash; +class TypeRepresentationHelper; + class TypeRepresentation { public: enum Kind { Scalar = JS_TYPEREPR_SCALAR_KIND, Reference = JS_TYPEREPR_REFERENCE_KIND, + X4 = JS_TYPEREPR_X4_KIND, Struct = JS_TYPEREPR_STRUCT_KIND, Array = JS_TYPEREPR_ARRAY_KIND }; @@ -112,6 +119,9 @@ class TypeRepresentation { protected: TypeRepresentation(Kind kind, size_t size, size_t align, bool opaque); + // in order to call addToTableOrFree() + friend class TypeRepresentationHelper; + size_t size_; size_t alignment_; Kind kind_; @@ -167,6 +177,15 @@ class TypeRepresentation { return (ReferenceTypeRepresentation*) this; } + bool isX4() const { + return kind() == X4; + } + + X4TypeRepresentation *asX4() { + JS_ASSERT(isX4()); + return (X4TypeRepresentation*) this; + } + bool isArray() const { return kind() == Array; } @@ -213,7 +232,10 @@ class ScalarTypeRepresentation : public TypeRepresentation { // so TypeRepresentation can call appendStringScalar() etc friend class TypeRepresentation; - Type type_; + // in order to call constructor + friend class TypeRepresentationHelper; + + const Type type_; explicit ScalarTypeRepresentation(Type type); @@ -290,6 +312,40 @@ class ReferenceTypeRepresentation : public TypeRepresentation { macro_(ReferenceTypeRepresentation::TYPE_OBJECT, HeapPtrObject, Object) \ macro_(ReferenceTypeRepresentation::TYPE_STRING, HeapPtrString, string) +class X4TypeRepresentation : public TypeRepresentation { + public: + enum Type { + TYPE_INT32 = JS_X4TYPEREPR_INT32, + TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32, + }; + + private: + // so TypeRepresentation can call appendStringScalar() etc + friend class TypeRepresentation; + + // in order to call constructor + friend class TypeRepresentationHelper; + + const Type type_; + + explicit X4TypeRepresentation(Type type); + + // See TypeRepresentation::appendString() + bool appendStringX4(JSContext *cx, StringBuffer &buffer); + + public: + Type type() const { + return type_; + } + + static JSObject *Create(JSContext *cx, Type type); +}; + +// Must be in same order as the enum ScalarTypeRepresentation::Type: +#define JS_FOR_EACH_X4_TYPE_REPR(macro_) \ + macro_(X4TypeRepresentation::TYPE_INT32, int32_t, int32) \ + macro_(X4TypeRepresentation::TYPE_FLOAT32, float, float32) + class ArrayTypeRepresentation : public TypeRepresentation { private: // so TypeRepresentation can call appendStringArray() etc diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 4da2c76d402..f82a2421d71 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -134,11 +134,25 @@ IsStructTypeObject(JSObject &type) return type.hasClass(&StructType::class_); } +static inline bool +IsX4TypeObject(JSObject &type) +{ + return type.hasClass(&X4Type::class_); +} + +static inline bool +IsComplexTypeObject(JSObject &type) +{ + return IsArrayTypeObject(type) || IsStructTypeObject(type); +} + static inline bool IsTypeObject(JSObject &type) { - return IsScalarTypeObject(type) || IsArrayTypeObject(type) || - IsStructTypeObject(type) || IsReferenceTypeObject(type); + return IsScalarTypeObject(type) || + IsReferenceTypeObject(type) || + IsX4TypeObject(type) || + IsComplexTypeObject(type); } static inline bool @@ -1270,6 +1284,164 @@ DefineSimpleTypeObject(JSContext *cx, return true; } +/////////////////////////////////////////////////////////////////////////// +// X4 + +const Class X4Type::class_ = { + "X4", + JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_X4_SLOTS), + JS_PropertyStub, + JS_DeletePropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + nullptr, + nullptr, + call, + nullptr, + nullptr, + nullptr +}; + +// These classes just exist to group together various properties and so on. +namespace js { +class Int32x4Defn { + public: + static const X4TypeRepresentation::Type type = X4TypeRepresentation::TYPE_INT32; + static const JSPropertySpec TypedObjectProperties[]; + static const JSFunctionSpec TypedObjectMethods[]; +}; +class Float32x4Defn { + public: + static const X4TypeRepresentation::Type type = X4TypeRepresentation::TYPE_FLOAT32; + static const JSPropertySpec TypedObjectProperties[]; + static const JSFunctionSpec TypedObjectMethods[]; +}; +} // namespace js + +const JSPropertySpec js::Int32x4Defn::TypedObjectProperties[] = { + JS_SELF_HOSTED_GET("x", "Int32x4Lane0", JSPROP_PERMANENT), + JS_SELF_HOSTED_GET("y", "Int32x4Lane1", JSPROP_PERMANENT), + JS_SELF_HOSTED_GET("z", "Int32x4Lane2", JSPROP_PERMANENT), + JS_SELF_HOSTED_GET("w", "Int32x4Lane3", JSPROP_PERMANENT), + JS_PS_END +}; + +const JSFunctionSpec js::Int32x4Defn::TypedObjectMethods[] = { + JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0), + JS_FS_END +}; + +const JSPropertySpec js::Float32x4Defn::TypedObjectProperties[] = { + JS_SELF_HOSTED_GET("x", "Float32x4Lane0", JSPROP_PERMANENT), + JS_SELF_HOSTED_GET("y", "Float32x4Lane1", JSPROP_PERMANENT), + JS_SELF_HOSTED_GET("z", "Float32x4Lane2", JSPROP_PERMANENT), + JS_SELF_HOSTED_GET("w", "Float32x4Lane3", JSPROP_PERMANENT), + JS_PS_END +}; + +const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = { + JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0), + JS_FS_END +}; + +template +static JSObject * +CreateX4Class(JSContext *cx, Handle global) +{ + RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + if (!funcProto) + return nullptr; + + // Create type representation + + RootedObject typeReprObj(cx); + typeReprObj = X4TypeRepresentation::Create(cx, T::type); + if (!typeReprObj) + return nullptr; + + // Create prototype property, which inherits from Object.prototype + + RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + if (!objProto) + return nullptr; + RootedObject proto(cx); + proto = NewObjectWithGivenProto(cx, &JSObject::class_, objProto, global, SingletonObject); + if (!proto) + return nullptr; + + // Create type constructor itself + + RootedObject x4(cx); + x4 = NewObjectWithClassProto(cx, &X4Type::class_, funcProto, global); + if (!x4 || + !InitializeCommonTypeDescriptorProperties(cx, x4, typeReprObj) || + !DefinePropertiesAndBrand(cx, proto, nullptr, nullptr)) + { + return nullptr; + } + + // Link type constructor to the type representation + + x4->initReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR, ObjectValue(*typeReprObj)); + + // Link constructor to prototype and install properties + + if (!LinkConstructorAndPrototype(cx, x4, proto) || + !DefinePropertiesAndBrand(cx, proto, T::TypedObjectProperties, + T::TypedObjectMethods)) + { + return nullptr; + } + + return x4; +} + +bool +X4Type::call(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + const uint32_t LANES = 4; + + if (args.length() < LANES) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, + args.callee().getClass()->name, "3", "s"); + return false; + } + + double values[LANES]; + for (uint32_t i = 0; i < LANES; i++) { + if (!ToNumber(cx, args[i], &values[i])) + return false; + } + + RootedObject typeObj(cx, &args.callee()); + RootedObject result(cx, TypedObject::createZeroed(cx, typeObj)); + if (!result) + return false; + + X4TypeRepresentation *typeRepr = typeRepresentation(*typeObj)->asX4(); + switch (typeRepr->type()) { +#define STORE_LANES(_constant, _type, _name) \ + case _constant: \ + { \ + _type *mem = (_type*) TypedMem(*result); \ + for (uint32_t i = 0; i < LANES; i++) { \ + mem[i] = values[i]; \ + } \ + break; \ + } + JS_FOR_EACH_X4_TYPE_REPR(STORE_LANES) +#undef STORE_LANES + } + args.rval().setObject(*result); + return true; +} + +/////////////////////////////////////////////////////////////////////////// + template static JSObject * DefineMetaTypeObject(JSContext *cx, @@ -1377,6 +1549,38 @@ js_InitTypedObjectClass(JSContext *cx, HandleObject obj) JS_FOR_EACH_REFERENCE_TYPE_REPR(BINARYDATA_REFERENCE_DEFINE) #undef BINARYDATA_REFERENCE_DEFINE + // float32x4 + + RootedObject float32x4Object(cx); + float32x4Object = CreateX4Class(cx, global); + if (!float32x4Object) + return nullptr; + + RootedValue float32x4Value(cx, ObjectValue(*float32x4Object)); + if (!JSObject::defineProperty(cx, module, cx->names().float32x4, + float32x4Value, + nullptr, nullptr, + JSPROP_READONLY | JSPROP_PERMANENT)) + { + return nullptr; + } + + // int32x4 + + RootedObject int32x4Object(cx); + int32x4Object = CreateX4Class(cx, global); + if (!int32x4Object) + return nullptr; + + RootedValue int32x4Value(cx, ObjectValue(*int32x4Object)); + if (!JSObject::defineProperty(cx, module, cx->names().int32x4, + int32x4Value, + nullptr, nullptr, + JSPROP_READONLY | JSPROP_PERMANENT)) + { + return nullptr; + } + // ArrayType. RootedObject arrayType(cx, DefineMetaTypeObject(cx, global)); @@ -1617,7 +1821,7 @@ TypedDatum::obj_finalize(js::FreeOp *op, JSObject *obj) bool TypedDatum::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, - MutableHandleObject objp, MutableHandleShape propp) + MutableHandleObject objp, MutableHandleShape propp) { JS_ASSERT(IsTypedDatum(*obj)); @@ -1627,6 +1831,7 @@ TypedDatum::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, switch (typeRepr->kind()) { case TypeRepresentation::Scalar: case TypeRepresentation::Reference: + case TypeRepresentation::X4: break; case TypeRepresentation::Array: @@ -1805,6 +2010,9 @@ TypedDatum::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receive case TypeRepresentation::Reference: break; + case TypeRepresentation::X4: + break; + case TypeRepresentation::Array: if (JSID_IS_ATOM(id, cx->names().length)) { vp.setInt32(typeRepr->asArray()->length()); @@ -1862,6 +2070,7 @@ TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj, switch (typeRepr->kind()) { case TypeRepresentation::Scalar: case TypeRepresentation::Reference: + case TypeRepresentation::X4: case TypeRepresentation::Struct: break; @@ -1915,6 +2124,9 @@ TypedDatum::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id, case TypeRepresentation::Reference: break; + case ScalarTypeRepresentation::X4: + break; + case ScalarTypeRepresentation::Array: if (JSID_IS_ATOM(id, cx->names().length)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, @@ -1958,6 +2170,7 @@ TypedDatum::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index, switch (typeRepr->kind()) { case TypeRepresentation::Scalar: case TypeRepresentation::Reference: + case TypeRepresentation::X4: case TypeRepresentation::Struct: break; @@ -1990,7 +2203,7 @@ TypedDatum::obj_setSpecial(JSContext *cx, HandleObject obj, bool TypedDatum::obj_getGenericAttributes(JSContext *cx, HandleObject obj, - HandleId id, unsigned *attrsp) + HandleId id, unsigned *attrsp) { uint32_t index; RootedObject type(cx, GetType(*obj)); @@ -2001,6 +2214,9 @@ TypedDatum::obj_getGenericAttributes(JSContext *cx, HandleObject obj, case TypeRepresentation::Reference: break; + case TypeRepresentation::X4: + break; + case TypeRepresentation::Array: if (js_IdIsIndex(id, &index)) { *attrsp = JSPROP_ENUMERATE | JSPROP_PERMANENT; @@ -2039,6 +2255,7 @@ IsOwnId(JSContext *cx, HandleObject obj, HandleId id) switch (typeRepr->kind()) { case TypeRepresentation::Scalar: case TypeRepresentation::Reference: + case TypeRepresentation::X4: return false; case TypeRepresentation::Array: @@ -2131,6 +2348,7 @@ TypedDatum::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, switch (typeRepr->kind()) { case TypeRepresentation::Scalar: case TypeRepresentation::Reference: + case TypeRepresentation::X4: switch (enum_op) { case JSENUMERATE_INIT_ALL: case JSENUMERATE_INIT: diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index d99c9efb3c3..b678914c239 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -130,6 +130,18 @@ class ReferenceType static bool call(JSContext *cx, unsigned argc, Value *vp); }; +/* + * Type descriptors `float32x4` and `int32x4` + */ +class X4Type : public JSObject +{ + private: + public: + static const Class class_; + + static bool call(JSContext *cx, unsigned argc, Value *vp); +}; + /* * Type descriptor created by `new ArrayType(...)` */ diff --git a/js/src/builtin/TypedObject.js b/js/src/builtin/TypedObject.js index 052acb0bb89..99162d28e6e 100644 --- a/js/src/builtin/TypedObject.js +++ b/js/src/builtin/TypedObject.js @@ -107,6 +107,7 @@ TypedObjectPointer.prototype.moveTo = function(propName) { switch (this.kind()) { case JS_TYPEREPR_SCALAR_KIND: case JS_TYPEREPR_REFERENCE_KIND: + case JS_TYPEREPR_X4_KIND: break; case JS_TYPEREPR_ARRAY_KIND: @@ -188,13 +189,22 @@ TypedObjectPointer.prototype.moveToField = function(propName) { TypedObjectPointer.prototype.get = function() { assert(ObjectIsAttached(this.datum), "get() called with unattached datum"); - if (REPR_KIND(this.typeRepr) == JS_TYPEREPR_SCALAR_KIND) + switch (REPR_KIND(this.typeRepr)) { + case JS_TYPEREPR_SCALAR_KIND: return this.getScalar(); - if (REPR_KIND(this.typeRepr) == JS_TYPEREPR_REFERENCE_KIND) + case JS_TYPEREPR_REFERENCE_KIND: return this.getReference(); - return NewDerivedTypedDatum(this.typeObj, this.datum, this.offset); + case JS_TYPEREPR_X4_KIND: + return this.getX4(); + + case JS_TYPEREPR_ARRAY_KIND: + case JS_TYPEREPR_STRUCT_KIND: + return NewDerivedTypedDatum(this.typeObj, this.datum, this.offset); + } + + assert(false, "Unhandled kind: " + REPR_KIND(this.typeRepr)); } TypedObjectPointer.prototype.getScalar = function() { @@ -245,6 +255,27 @@ TypedObjectPointer.prototype.getReference = function() { assert(false, "Unhandled scalar type: " + type); } +TypedObjectPointer.prototype.getX4 = function() { + var type = REPR_TYPE(this.typeRepr); + var T = StandardTypeObjectDescriptors(); + switch (type) { + case JS_X4TYPEREPR_FLOAT32: + var x = Load_float32(this.datum, this.offset + 0); + var y = Load_float32(this.datum, this.offset + 4); + var z = Load_float32(this.datum, this.offset + 8); + var w = Load_float32(this.datum, this.offset + 12); + return T.float32x4(x, y, z, w); + + case JS_X4TYPEREPR_INT32: + var x = Load_int32(this.datum, this.offset + 0); + var y = Load_int32(this.datum, this.offset + 4); + var z = Load_int32(this.datum, this.offset + 8); + var w = Load_int32(this.datum, this.offset + 12); + return T.int32x4(x, y, z, w); + } + assert(false, "Unhandled x4 type: " + type); +} + /////////////////////////////////////////////////////////////////////////// // Setting values // @@ -281,6 +312,10 @@ TypedObjectPointer.prototype.set = function(fromValue) { this.setReference(fromValue); return; + case JS_TYPEREPR_X4_KIND: + this.setX4(fromValue); + return; + case JS_TYPEREPR_ARRAY_KIND: if (!IsObject(fromValue)) break; @@ -382,6 +417,17 @@ TypedObjectPointer.prototype.setReference = function(fromValue) { assert(false, "Unhandled scalar type: " + type); } +// Sets `fromValue` to `this` assuming that `this` is a scalar type. +TypedObjectPointer.prototype.setX4 = function(fromValue) { + // It is only permitted to set a float32x4/int32x4 value from another + // float32x4/int32x4; in that case, the "fast path" that uses memcopy will + // have already matched. So if we get to this point, we're supposed + // to "adapt" fromValue, but there are no legal adaptions. + ThrowError(JSMSG_CANT_CONVERT_TO, + typeof(fromValue), + this.typeRepr.toSource()) +} + /////////////////////////////////////////////////////////////////////////// // C++ Wrappers // @@ -605,6 +651,65 @@ function HandleTest(obj) { return IsObject(obj) && ObjectIsTypedHandle(obj); } +/////////////////////////////////////////////////////////////////////////// +// X4 + +function X4ProtoString(type) { + switch (type) { + case JS_X4TYPEREPR_INT32: + return "int32x4"; + case JS_X4TYPEREPR_FLOAT32: + return "float32x4"; + } + assert(false, "Unhandled type constant"); +} + +X4LaneStrings = ["x", "y", "z", "w"]; + +// Generalized handler for the various properties for accessing a +// single lane of an X4 vector value. Note that this is the slow path; +// the fast path will be inlined into ion code. +function X4GetLane(datum, type, lane) { + if (!IsObject(datum) || !ObjectIsTypedDatum(datum)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, X4ProtoString(type), + X4LaneStrings[lane], typeof this); + + var repr = DATUM_TYPE_REPR(datum); + if (REPR_KIND(repr) != JS_TYPEREPR_X4_KIND || REPR_TYPE(repr) != type) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, X4ProtoString(type), + X4LaneStrings[lane], typeof this); + + switch (type) { + case JS_X4TYPEREPR_INT32: + return Load_int32(datum, lane * 4); + case JS_X4TYPEREPR_FLOAT32: + return Load_float32(datum, lane * 4); + } + assert(false, "Unhandled type constant"); +} + +function Float32x4Lane0() { return X4GetLane(this, JS_X4TYPEREPR_FLOAT32, 0); } +function Float32x4Lane1() { return X4GetLane(this, JS_X4TYPEREPR_FLOAT32, 1); } +function Float32x4Lane2() { return X4GetLane(this, JS_X4TYPEREPR_FLOAT32, 2); } +function Float32x4Lane3() { return X4GetLane(this, JS_X4TYPEREPR_FLOAT32, 3); } + +function Int32x4Lane0() { return X4GetLane(this, JS_X4TYPEREPR_INT32, 0); } +function Int32x4Lane1() { return X4GetLane(this, JS_X4TYPEREPR_INT32, 1); } +function Int32x4Lane2() { return X4GetLane(this, JS_X4TYPEREPR_INT32, 2); } +function Int32x4Lane3() { return X4GetLane(this, JS_X4TYPEREPR_INT32, 3); } + +function X4ToSource() { + if (!IsObject(this) || !ObjectIsTypedDatum(this)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this); + + var repr = DATUM_TYPE_REPR(this); + if (REPR_KIND(repr) != JS_TYPEREPR_X4_KIND) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this); + + var type = REPR_TYPE(repr); + return X4ProtoString(type)+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")"; +} + /////////////////////////////////////////////////////////////////////////// // Miscellaneous diff --git a/js/src/builtin/TypedObjectConstants.h b/js/src/builtin/TypedObjectConstants.h index 0da7bee5533..2c47dbbc53e 100644 --- a/js/src/builtin/TypedObjectConstants.h +++ b/js/src/builtin/TypedObjectConstants.h @@ -26,6 +26,9 @@ // Slots on references #define JS_TYPEOBJ_REFERENCE_SLOTS 1 // Maximum number +// Slots on x4s +#define JS_TYPEOBJ_X4_SLOTS 1 // Maximum number + // Slots on arrays #define JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE 1 #define JS_TYPEOBJ_ARRAY_SLOTS 2 // Maximum number @@ -34,7 +37,6 @@ #define JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES 1 #define JS_TYPEOBJ_STRUCT_SLOTS 2 // Maximum number - /////////////////////////////////////////////////////////////////////////// // Slots for type representation objects // @@ -52,7 +54,7 @@ // Slots on arrays: #define JS_TYPEREPR_SLOT_LENGTH 3 // Length of the array -// Slots on scalars and references: +// Slots on scalars, references, and X4s: #define JS_TYPEREPR_SLOT_TYPE 3 // One of the constants below // Maximum number of slots for any type representation @@ -61,10 +63,11 @@ // These constants are for use exclusively in JS code. In C++ code, // prefer TypeRepresentation::Scalar etc, which allows you to // write a switch which will receive a warning if you omit a case. -#define JS_TYPEREPR_SCALAR_KIND 0 +#define JS_TYPEREPR_SCALAR_KIND 0 #define JS_TYPEREPR_REFERENCE_KIND 1 -#define JS_TYPEREPR_STRUCT_KIND 2 -#define JS_TYPEREPR_ARRAY_KIND 3 +#define JS_TYPEREPR_X4_KIND 2 +#define JS_TYPEREPR_STRUCT_KIND 3 +#define JS_TYPEREPR_ARRAY_KIND 4 // These constants are for use exclusively in JS code. In C++ code, // prefer ScalarTypeRepresentation::TYPE_INT8 etc, which allows @@ -88,6 +91,13 @@ #define JS_REFERENCETYPEREPR_OBJECT 1 #define JS_REFERENCETYPEREPR_STRING 2 +// These constants are for use exclusively in JS code. In C++ code, +// prefer X4TypeRepresentation::TYPE_INT32 etc, since that allows +// you to write a switch which will receive a warning if you omit a +// case. +#define JS_X4TYPEREPR_INT32 0 +#define JS_X4TYPEREPR_FLOAT32 1 + /////////////////////////////////////////////////////////////////////////// // Slots for typed objects (actually, any TypedContents objects) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index d4b24b6edc8..aa69f2dba4e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -6533,15 +6533,19 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition * return true; switch (elemTypeReprs.kind()) { - case TypeRepresentation::Struct: - case TypeRepresentation::Array: + case TypeRepresentation::X4: + // FIXME (bug 894104): load into a MIRType_float32x4 etc + return true; + + case TypeRepresentation::Struct: + case TypeRepresentation::Array: return getElemTryComplexElemOfTypedObject(emitted, obj, index, objTypeReprs, elemTypeReprs, elemSize); - case TypeRepresentation::Scalar: + case TypeRepresentation::Scalar: return getElemTryScalarElemOfTypedObject(emitted, obj, index, @@ -8208,6 +8212,10 @@ IonBuilder::getPropTryTypedObject(bool *emitted, PropertyName *name, case TypeRepresentation::Reference: return true; + case TypeRepresentation::X4: + // FIXME (bug 894104): load into a MIRType_float32x4 etc + return true; + case TypeRepresentation::Struct: case TypeRepresentation::Array: return getPropTryComplexPropOfTypedObject(emitted, @@ -8741,6 +8749,10 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj, return true; switch (fieldTypeReprs.kind()) { + case TypeRepresentation::X4: + // FIXME (bug 894104): store into a MIRType_float32x4 etc + return true; + case TypeRepresentation::Reference: case TypeRepresentation::Struct: case TypeRepresentation::Array: diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index ae3364209d9..c6f99bd722a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3085,10 +3085,10 @@ DefineProperty(JSContext *cx, HandleObject obj, const char *name, const Value &v RootedValue value(cx, value_); AutoRooterGetterSetter gsRoot(cx, attrs, const_cast(&getter.op), const_cast(&setter.op)); - RootedId id(cx); + RootedId id(cx); if (attrs & JSPROP_INDEX) { - id = INT_TO_JSID(intptr_t(name)); + id.set(INT_TO_JSID(intptr_t(name))); attrs &= ~JSPROP_INDEX; } else { JSAtom *atom = Atomize(cx, name, strlen(name)); @@ -3100,6 +3100,57 @@ DefineProperty(JSContext *cx, HandleObject obj, const char *name, const Value &v return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid); } + +static bool +DefineSelfHostedProperty(JSContext *cx, + HandleObject obj, + const char *name, + const char *getterName, + const char *setterName, + unsigned attrs, + unsigned flags, + int tinyid) +{ + RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name))); + if (!nameAtom) + return false; + + RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName))); + if (!getterNameAtom) + return false; + + RootedValue getterValue(cx); + if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom, + 0, &getterValue)) + { + return false; + } + JS_ASSERT(getterValue.isObject() && getterValue.toObject().is()); + RootedFunction getterFunc(cx, &getterValue.toObject().as()); + JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get()); + + RootedFunction setterFunc(cx); + if (setterName) { + RootedAtom setterNameAtom(cx, Atomize(cx, setterName, strlen(setterName))); + if (!setterNameAtom) + return false; + + RootedValue setterValue(cx); + if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom, + 0, &setterValue)) + { + return false; + } + JS_ASSERT(setterValue.isObject() && setterValue.toObject().is()); + setterFunc = &getterValue.toObject().as(); + } + JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get()); + + return DefineProperty(cx, obj, name, UndefinedValue(), + GetterWrapper(getterOp), SetterWrapper(setterOp), + attrs, flags, tinyid); +} + JS_PUBLIC_API(bool) JS_DefineProperty(JSContext *cx, JSObject *objArg, const char *name, jsval valueArg, PropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) @@ -3224,8 +3275,25 @@ JS_DefineProperties(JSContext *cx, JSObject *objArg, const JSPropertySpec *ps) RootedObject obj(cx, objArg); bool ok; for (ok = true; ps->name; ps++) { - ok = DefineProperty(cx, obj, ps->name, UndefinedValue(), ps->getter, ps->setter, - ps->flags, Shape::HAS_SHORTID, ps->tinyid); + if (ps->selfHostedGetter) { + // If you have self-hosted getter/setter, you can't have a + // native one. + JS_ASSERT(!ps->getter.op && !ps->setter.op); + + ok = DefineSelfHostedProperty(cx, obj, ps->name, + ps->selfHostedGetter, + ps->selfHostedSetter, + ps->flags, Shape::HAS_SHORTID, + ps->tinyid); + } else { + // If you do not have a self-hosted getter, you should + // have a native getter; and you should not have a + // self-hosted setter. + JS_ASSERT(ps->getter.op && !ps->selfHostedSetter); + + ok = DefineProperty(cx, obj, ps->name, UndefinedValue(), ps->getter, ps->setter, + ps->flags, Shape::HAS_SHORTID, ps->tinyid); + } if (!ok) break; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index bee0b4f9abc..0802ac9b562 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2406,6 +2406,8 @@ struct JSPropertySpec { uint8_t flags; JSPropertyOpWrapper getter; JSStrictPropertyOpWrapper setter; + const char *selfHostedGetter; + const char *selfHostedSetter; }; namespace JS { @@ -2436,13 +2438,23 @@ inline int CheckIsNative(JSNative native); {name, 0, \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS), \ JSOP_WRAPPER(JS_CAST_NATIVE_TO(getter, JSPropertyOp)), \ - JSOP_NULLWRAPPER} + JSOP_NULLWRAPPER, nullptr, nullptr} #define JS_PSGS(name, getter, setter, flags) \ {name, 0, \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS), \ JSOP_WRAPPER(JS_CAST_NATIVE_TO(getter, JSPropertyOp)), \ - JSOP_WRAPPER(JS_CAST_NATIVE_TO(setter, JSStrictPropertyOp))} -#define JS_PS_END {0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER} + JSOP_WRAPPER(JS_CAST_NATIVE_TO(setter, JSStrictPropertyOp)), \ + nullptr, nullptr} +#define JS_SELF_HOSTED_GET(name, getterName, flags) \ + {name, 0, \ + uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ + JSOP_NULLWRAPPER, JSOP_NULLWRAPPER, getterName, nullptr} +#define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ + {name, 0, \ + uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER), \ + JSOP_NULLWRAPPER, JSOP_NULLWRAPPER, getterName, setterName} +#define JS_PS_END {0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER, \ + nullptr, nullptr} /* * To define a native function, set call to a JSNativeWrapper. To define a diff --git a/js/src/tests/ecma_6/TypedObject/simd/float32x4alignment.js b/js/src/tests/ecma_6/TypedObject/simd/float32x4alignment.js new file mode 100644 index 00000000000..6fa650e57f8 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/float32x4alignment.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'float32x4 alignment'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var StructType = TypedObject.StructType; +var uint8 = TypedObject.uint8; +var float32x4 = TypedObject.float32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + assertEq(float32x4.byteLength, 16); + assertEq(float32x4.byteAlignment, 16); + + var Compound = new StructType({c: uint8, d: uint8, f: float32x4}); + assertEq(Compound.fieldOffsets["c"], 0); + assertEq(Compound.fieldOffsets["d"], 1); + assertEq(Compound.fieldOffsets["f"], 16); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/float32x4getters.js b/js/src/tests/ecma_6/TypedObject/simd/float32x4getters.js new file mode 100644 index 00000000000..51b69837465 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/float32x4getters.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'float32x4 getters'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var float32x4 = TypedObject.float32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + // Create a float32x4 and check that the getters work: + var f = float32x4(11, 22, 33, 44); + assertEq(f.x, 11); + assertEq(f.y, 22); + assertEq(f.z, 33); + assertEq(f.w, 44); + + // Test that the getters work when called reflectively: + var g = f.__lookupGetter__("x"); + assertEq(g.call(f), 11); + + // Test that getters cannot be applied to various incorrect things: + assertThrowsInstanceOf(function() { + g.call({}) + }, TypeError, "Getter applicable to random objects"); + assertThrowsInstanceOf(function() { + g.call(0xDEADBEEF) + }, TypeError, "Getter applicable to integers"); + assertThrowsInstanceOf(function() { + var T = new TypedObject.StructType({x: TypedObject.float32, + y: TypedObject.float32, + z: TypedObject.float32, + w: TypedObject.float32}); + var v = new T({x: 11, y: 22, z: 33, w: 44}); + g.call(v) + }, TypeError, "Getter applicable to structs"); + assertThrowsInstanceOf(function() { + var t = new TypedObject.int32x4(1, 2, 3, 4); + g.call(t) + }, TypeError, "Getter applicable to int32x4"); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/float32x4handle.js b/js/src/tests/ecma_6/TypedObject/simd/float32x4handle.js new file mode 100644 index 00000000000..5f5cfc5f3c5 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/float32x4handle.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'float32x4 handles'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var ArrayType = TypedObject.ArrayType; +var float32x4 = TypedObject.float32x4; +var float32 = TypedObject.float32; +var Handle = TypedObject.Handle; + +function test() { + print(BUGNUMBER + ": " + summary); + + var Array = new ArrayType(float32x4, 3); + var array = new Array([float32x4(1, 2, 3, 4), + float32x4(5, 6, 7, 8), + float32x4(9, 10, 11, 12)]); + + // Test that trying to create handle into the interior of a + // float32x4 fails. + + assertThrowsInstanceOf(function() { + var h = float32.handle(array, 1, "w"); + }, TypeError, "Creating a float32 handle to prop via ctor"); + + assertThrowsInstanceOf(function() { + var h = float32.handle(); + Handle.move(h, array, 1, "w"); + }, TypeError, "Creating a float32 handle to prop via move"); + + assertThrowsInstanceOf(function() { + var h = float32.handle(array, 1, 0); + }, TypeError, "Creating a float32 handle to elem via ctor"); + + assertThrowsInstanceOf(function() { + var h = float32.handle(); + Handle.move(h, array, 1, 0); + }, TypeError, "Creating a float32 handle to elem via move"); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/float32x4reify.js b/js/src/tests/ecma_6/TypedObject/simd/float32x4reify.js new file mode 100644 index 00000000000..e33813d24e7 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/float32x4reify.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'float32x4 reify'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var ArrayType = TypedObject.ArrayType; +var float32x4 = TypedObject.float32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + var Array = new ArrayType(float32x4, 3); + var array = new Array([float32x4(1, 2, 3, 4), + float32x4(5, 6, 7, 8), + float32x4(9, 10, 11, 12)]); + + // Test that reading array[1] produces a *copy* of float32x4, not an + // alias into the array. + + var f = array[1]; + assertEq(f.w, 8); + assertEq(array[1].w, 8); + array[1] = float32x4(15, 16, 17, 18); + assertEq(f.w, 8); + assertEq(array[1].w, 18); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/float32x4setter.js b/js/src/tests/ecma_6/TypedObject/simd/float32x4setter.js new file mode 100644 index 00000000000..0867c18be9f --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/float32x4setter.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'float32x4 setting'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var ArrayType = TypedObject.ArrayType; +var float32x4 = TypedObject.float32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + var Array = new ArrayType(float32x4, 3); + var array = new Array([float32x4(1, 2, 3, 4), + float32x4(5, 6, 7, 8), + float32x4(9, 10, 11, 12)]); + assertEq(array[1].w, 8); + + // Test that we are allowed to write float32x4 values into array, + // but not other things. + + array[1] = float32x4(15, 16, 17, 18); + assertEq(array[1].w, 18); + + assertThrowsInstanceOf(function() { + array[1] = {x: 15, y: 16, z: 17, w: 18}; + }, TypeError, "Setting float32x4 from an object"); + + assertThrowsInstanceOf(function() { + array[1] = [15, 16, 17, 18]; + }, TypeError, "Setting float32x4 from an array"); + + assertThrowsInstanceOf(function() { + array[1] = 22; + }, TypeError, "Setting float32x4 from a number"); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/int32x4alignment.js b/js/src/tests/ecma_6/TypedObject/simd/int32x4alignment.js new file mode 100644 index 00000000000..7a427cf10d7 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/int32x4alignment.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'int32x4 alignment'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var StructType = TypedObject.StructType; +var uint8 = TypedObject.uint8; +var int32x4 = TypedObject.int32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + assertEq(int32x4.byteLength, 16); + assertEq(int32x4.byteAlignment, 16); + + var Compound = new StructType({c: uint8, d: uint8, f: int32x4}); + assertEq(Compound.fieldOffsets["c"], 0); + assertEq(Compound.fieldOffsets["d"], 1); + assertEq(Compound.fieldOffsets["f"], 16); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/int32x4getters.js b/js/src/tests/ecma_6/TypedObject/simd/int32x4getters.js new file mode 100644 index 00000000000..4b99f13761a --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/int32x4getters.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'int32x4 getters'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var int32x4 = TypedObject.int32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + // Create a int32x4 and check that the getters work: + var f = int32x4(11, 22, 33, 44); + assertEq(f.x, 11); + assertEq(f.y, 22); + assertEq(f.z, 33); + assertEq(f.w, 44); + + // Test that the getters work when called reflectively: + var g = f.__lookupGetter__("x"); + assertEq(g.call(f), 11); + + // Test that getters cannot be applied to various incorrect things: + assertThrowsInstanceOf(function() { + g.call({}) + }, TypeError, "Getter applicable to random objects"); + assertThrowsInstanceOf(function() { + g.call(0xDEADBEEF) + }, TypeError, "Getter applicable to integers"); + assertThrowsInstanceOf(function() { + var T = new TypedObject.StructType({x: TypedObject.int32, + y: TypedObject.int32, + z: TypedObject.int32, + w: TypedObject.int32}); + var v = new T({x: 11, y: 22, z: 33, w: 44}); + g.call(v) + }, TypeError, "Getter applicable to structs"); + assertThrowsInstanceOf(function() { + var t = new TypedObject.float32x4(1, 2, 3, 4); + g.call(t) + }, TypeError, "Getter applicable to float32x4"); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/int32x4handle.js b/js/src/tests/ecma_6/TypedObject/simd/int32x4handle.js new file mode 100644 index 00000000000..bb64c14390c --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/int32x4handle.js @@ -0,0 +1,49 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'int32x4 handles'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var ArrayType = TypedObject.ArrayType; +var int32x4 = TypedObject.int32x4; +var int32 = TypedObject.int32; +var Handle = TypedObject.Handle; + +function test() { + print(BUGNUMBER + ": " + summary); + + var Array = new ArrayType(int32x4, 3); + var array = new Array([int32x4(1, 2, 3, 4), + int32x4(5, 6, 7, 8), + int32x4(9, 10, 11, 12)]); + + // Test that trying to create handle into the interior of a + // int32x4 fails. + + assertThrowsInstanceOf(function() { + var h = int32.handle(array, 1, "w"); + }, TypeError, "Creating a int32 handle to prop via ctor"); + + assertThrowsInstanceOf(function() { + var h = int32.handle(); + Handle.move(h, array, 1, "w"); + }, TypeError, "Creating a int32 handle to prop via move"); + + assertThrowsInstanceOf(function() { + var h = int32.handle(array, 1, 0); + }, TypeError, "Creating a int32 handle to elem via ctor"); + + assertThrowsInstanceOf(function() { + var h = int32.handle(); + Handle.move(h, array, 1, 0); + }, TypeError, "Creating a int32 handle to elem via move"); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/int32x4reify.js b/js/src/tests/ecma_6/TypedObject/simd/int32x4reify.js new file mode 100644 index 00000000000..a7854c8578f --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/int32x4reify.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'int32x4 reify'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var ArrayType = TypedObject.ArrayType; +var int32x4 = TypedObject.int32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + var Array = new ArrayType(int32x4, 3); + var array = new Array([int32x4(1, 2, 3, 4), + int32x4(5, 6, 7, 8), + int32x4(9, 10, 11, 12)]); + + // Test that reading array[1] produces a *copy* of int32x4, not an + // alias into the array. + + var f = array[1]; + assertEq(f.w, 8); + assertEq(array[1].w, 8); + array[1] = int32x4(15, 16, 17, 18); + assertEq(f.w, 8); + assertEq(array[1].w, 18); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/int32x4setter.js b/js/src/tests/ecma_6/TypedObject/simd/int32x4setter.js new file mode 100644 index 00000000000..18bdf79d4ed --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/simd/int32x4setter.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 938728; +var summary = 'int32x4 setting'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var ArrayType = TypedObject.ArrayType; +var int32x4 = TypedObject.int32x4; + +function test() { + print(BUGNUMBER + ": " + summary); + + var Array = new ArrayType(int32x4, 3); + var array = new Array([int32x4(1, 2, 3, 4), + int32x4(5, 6, 7, 8), + int32x4(9, 10, 11, 12)]); + assertEq(array[1].w, 8); + + // Test that we are allowed to write int32x4 values into array, + // but not other things. + + array[1] = int32x4(15, 16, 17, 18); + assertEq(array[1].w, 18); + + assertThrowsInstanceOf(function() { + array[1] = {x: 15, y: 16, z: 17, w: 18}; + }, TypeError, "Setting int32x4 from an object"); + + assertThrowsInstanceOf(function() { + array[1] = [15, 16, 17, 18]; + }, TypeError, "Setting int32x4 from an array"); + + assertThrowsInstanceOf(function() { + array[1] = 22; + }, TypeError, "Setting int32x4 from a number"); + + if (typeof reportCompare === "function") + reportCompare(true, true); + print("Tests complete"); +} + +test(); diff --git a/js/src/tests/ecma_6/TypedObject/simd/shell.js b/js/src/tests/ecma_6/TypedObject/simd/shell.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 2bf8c7c0e94..d1fbd61086d 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -69,6 +69,7 @@ macro(FillTypedArrayWithValue, FillTypedArrayWithValue, "FillTypedArrayWithValue") \ macro(fix, fix, "fix") \ macro(float32, float32, "float32") \ + macro(float32x4, float32x4, "float32x4") \ macro(float64, float64, "float64") \ macro(format, format, "format") \ macro(from, from, "from") \ @@ -90,6 +91,7 @@ macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \ macro(innermost, innermost, "innermost") \ macro(input, input, "input") \ + macro(int32x4, int32x4, "int32x4") \ macro(isFinite, isFinite, "isFinite") \ macro(isNaN, isNaN, "isNaN") \ macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \ @@ -177,7 +179,11 @@ macro(void0, void0, "(void 0)") \ macro(watch, watch, "watch") \ macro(writable, writable, "writable") \ + macro(w, w, "w") \ + macro(x, x, "x") \ + macro(y, y, "y") \ macro(yield, yield, "yield") \ + macro(z, z, "z") \ /* Type names must be contiguous and ordered; see js::TypeName. */ \ macro(undefined, undefined, "undefined") \ macro(object, object, "object") \