diff --git a/js/src/builtin/TypeRepresentation.cpp b/js/src/builtin/TypeRepresentation.cpp index a17be53d0b8..81d9abe6411 100644 --- a/js/src/builtin/TypeRepresentation.cpp +++ b/js/src/builtin/TypeRepresentation.cpp @@ -223,7 +223,7 @@ StructTypeRepresentation::init(JSContext *cx, uint32_t totalSize = 0; for (size_t i = 0; i < ids.length(); i++) { - TypeRepresentation *fieldTypeRepr = fromOwnerObject(typeReprOwners[i]); + TypeRepresentation *fieldTypeRepr = fromOwnerObject(*typeReprOwners[i]); uint32_t alignedSize = alignTo(totalSize, fieldTypeRepr->alignment()); if (alignedSize < totalSize) { @@ -412,7 +412,7 @@ TypeRepresentation::mark(JSTracer *trace) /*static*/ void TypeRepresentation::obj_trace(JSTracer *trace, JSObject *object) { - fromOwnerObject(object)->traceFields(trace); + fromOwnerObject(*object)->traceFields(trace); } void @@ -457,7 +457,7 @@ ArrayTypeRepresentation::traceArrayFields(JSTracer *trace) TypeRepresentation::obj_finalize(js::FreeOp *fop, JSObject *object) { JSCompartment *comp = object->compartment(); - TypeRepresentation *typeRepr = fromOwnerObject(object); + TypeRepresentation *typeRepr = fromOwnerObject(*object); comp->typeReprs.remove(typeRepr); js_free(typeRepr); } @@ -573,16 +573,16 @@ StructTypeRepresentation::fieldNamed(jsid id) const } /*static*/ bool -TypeRepresentation::isTypeRepresentationOwnerObject(JSObject *obj) +TypeRepresentation::isOwnerObject(JSObject &obj) { - return obj->getClass() == &class_; + return obj.getClass() == &class_; } /*static*/ TypeRepresentation * -TypeRepresentation::fromOwnerObject(JSObject *obj) +TypeRepresentation::fromOwnerObject(JSObject &obj) { - JS_ASSERT(obj->getClass() == &class_); - return (TypeRepresentation*) obj->getPrivate(); + JS_ASSERT(obj.getClass() == &class_); + return (TypeRepresentation*) obj.getPrivate(); } diff --git a/js/src/builtin/TypeRepresentation.h b/js/src/builtin/TypeRepresentation.h index e3103dfb738..865591b1586 100644 --- a/js/src/builtin/TypeRepresentation.h +++ b/js/src/builtin/TypeRepresentation.h @@ -123,8 +123,8 @@ class TypeRepresentation { // buffer, for use in error messages and the like. bool appendString(JSContext *cx, StringBuffer &buffer); - static bool isTypeRepresentationOwnerObject(JSObject *obj); - static TypeRepresentation *fromOwnerObject(JSObject *obj); + static bool isOwnerObject(JSObject &obj); + static TypeRepresentation *fromOwnerObject(JSObject &obj); bool isScalar() const { return kind() == Scalar; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index b81616bab37..6a51f634108 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -41,22 +41,6 @@ const Class js::TypedObjectClass = { JS_ConvertStub }; -/* - * Reify() converts a binary value into a JS Object. - * - * The type of the value to be converted is described by `typeRepr`, - * and `type` is an associated type descriptor object with that - * same representation (note that there may be many descriptors - * that all share the same `typeRepr`). - * - * The value is located at the offset `offset` in the binary block - * associated with `owner`, which must be a BinaryBlock object. - * - * Upon success, the result is stored in `vp`. - */ -static bool Reify(JSContext *cx, TypeRepresentation *typeRepr, HandleObject type, - HandleObject owner, size_t offset, MutableHandleValue vp); - static void ReportCannotConvertTo(JSContext *cx, HandleValue fromValue, const char *toType) { @@ -147,15 +131,15 @@ IsTypeObject(JSObject &type) } static inline bool -IsBlock(JSObject &obj) +IsTypedDatum(JSObject &obj) { - return obj.hasClass(&BinaryBlock::class_); + return obj.is() || obj.is(); } static inline uint8_t * -BlockMem(JSObject &val) +TypedMem(JSObject &val) { - JS_ASSERT(IsBlock(val)); + JS_ASSERT(IsTypedDatum(val)); return (uint8_t*) val.getPrivate(); } @@ -179,27 +163,51 @@ typeRepresentationOwnerObj(JSObject &typeObj) static TypeRepresentation * typeRepresentation(JSObject &typeObj) { - return TypeRepresentation::fromOwnerObject(typeRepresentationOwnerObj(typeObj)); + return TypeRepresentation::fromOwnerObject(*typeRepresentationOwnerObj(typeObj)); } static inline JSObject * -GetType(JSObject &block) +GetType(JSObject &datum) { - JS_ASSERT(IsBlock(block)); - return &block.getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_OBJ).toObject(); + JS_ASSERT(IsTypedDatum(datum)); + return &datum.getReservedSlot(JS_DATUM_SLOT_TYPE_OBJ).toObject(); } /* - * Overwrites the contents of `block` at offset `offset` with `val` - * converted to the type `typeObj` + * Overwrites the contents of `datum` at offset `offset` with `val` + * converted to the type `typeObj`. This is done by delegating to + * self-hosted code. This is used for assignments and initializations. + * + * For example, consider the final assignment in this snippet: + * + * var Point = new StructType({x: float32, y: float32}); + * var Line = new StructType({from: Point, to: Point}); + * var line = new Line(); + * line.to = {x: 22, y: 44}; + * + * This would result in a call to `ConvertAndCopyTo` + * where: + * - typeObj = Point + * - datum = line + * - offset = sizeof(Point) == 8 + * - val = {x: 22, y: 44} + * This would result in loading the value of `x`, converting + * it to a float32, and hen storing it at the appropriate offset, + * and then doing the same for `y`. + * + * Note that the type of `typeObj` may not be the + * type of `datum` but rather some subcomponent of `datum`. */ static bool ConvertAndCopyTo(JSContext *cx, HandleObject typeObj, - HandleObject block, + HandleObject datum, int32_t offset, HandleValue val) { + JS_ASSERT(IsTypeObject(*typeObj)); + JS_ASSERT(IsTypedDatum(*datum)); + RootedFunction func( cx, SelfHostedFunction(cx, cx->names().ConvertAndCopyTo)); if (!func) @@ -212,7 +220,7 @@ ConvertAndCopyTo(JSContext *cx, args.setCallee(ObjectValue(*func)); args[0].setObject(*typeRepresentationOwnerObj(*typeObj)); args[1].setObject(*typeObj); - args[2].setObject(*block); + args[2].setObject(*datum); args[3].setInt32(offset); args[4].set(val); @@ -220,10 +228,46 @@ ConvertAndCopyTo(JSContext *cx, } static bool -ConvertAndCopyTo(JSContext *cx, HandleObject block, HandleValue val) +ConvertAndCopyTo(JSContext *cx, HandleObject datum, HandleValue val) { - RootedObject type(cx, GetType(*block)); - return ConvertAndCopyTo(cx, type, block, 0, val); + RootedObject type(cx, GetType(*datum)); + return ConvertAndCopyTo(cx, type, datum, 0, val); +} + +/* + * Overwrites the contents of `datum` at offset `offset` with `val` + * converted to the type `typeObj` + */ +static bool +Reify(JSContext *cx, + TypeRepresentation *typeRepr, + HandleObject type, + HandleObject datum, + size_t offset, + MutableHandleValue to) +{ + JS_ASSERT(IsTypeObject(*type)); + JS_ASSERT(IsTypedDatum(*datum)); + + RootedFunction func(cx, SelfHostedFunction(cx, cx->names().Reify)); + if (!func) + return false; + + InvokeArgs args(cx); + if (!args.init(4)) + return false; + + args.setCallee(ObjectValue(*func)); + args[0].setObject(*typeRepr->ownerObject()); + args[1].setObject(*type); + args[2].setObject(*datum); + args[3].setInt32(offset); + + if (!Invoke(cx, args)) + return false; + + to.set(args.rval()); + return true; } static inline size_t @@ -233,32 +277,20 @@ TypeSize(JSObject &type) } static inline size_t -BlockSize(JSObject &val) +DatumSize(JSObject &val) { return TypeSize(*GetType(val)); } static inline bool -IsBlockOfKind(JSObject &obj, TypeRepresentation::Kind kind) +IsTypedDatumOfKind(JSObject &obj, TypeRepresentation::Kind kind) { - if (!IsBlock(obj)) + if (!IsTypedDatum(obj)) return false; TypeRepresentation *repr = typeRepresentation(*GetType(obj)); return repr->kind() == kind; } -static inline bool -IsBinaryArray(JSObject &obj) -{ - return IsBlockOfKind(obj, TypeRepresentation::Array); -} - -static inline bool -IsBinaryStruct(JSObject &obj) -{ - return IsBlockOfKind(obj, TypeRepresentation::Struct); -} - static bool TypeEquivalent(JSContext *cx, unsigned int argc, Value *vp) { @@ -310,18 +342,15 @@ TypeEquivalent(JSContext *cx, unsigned int argc, Value *vp) nullptr \ }, +static const JSFunctionSpec NumericTypeObjectMethods[] = { + {"handle", {NULL, NULL}, 2, 0, "HandleCreate"}, + JS_FS_END +}; + const Class js::NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX] = { JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_CLASSES) }; -#define BINARYDATA_TYPE_TO_CLASS(constant_, type_, name_) \ - template <> \ - const Class * \ - NumericType::typeToClass() \ - { \ - return &NumericTypeClasses[constant_]; \ - } - template static T ConvertScalar(double d) { @@ -336,25 +365,6 @@ static T ConvertScalar(double d) } } - -/** - * This namespace declaration is required because of a weird 'specialization in - * different namespace' error that happens in gcc, only on type specialized - * template functions. - */ -namespace js { -JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_TYPE_TO_CLASS); - -template -JS_ALWAYS_INLINE -bool NumericType::reify(JSContext *cx, void *mem, MutableHandleValue vp) -{ - vp.setNumber((double)*((T*)mem) ); - return true; -} - -} // namespace js - template static bool NumericTypeToString(JSContext *cx, unsigned int argc, Value *vp) @@ -368,26 +378,6 @@ NumericTypeToString(JSContext *cx, unsigned int argc, Value *vp) return true; } -static bool -ReifyScalar(JSContext *cx, ScalarTypeRepresentation *typeRepr, HandleObject type, - HandleObject owner, size_t offset, MutableHandleValue to) -{ - JS_ASSERT(&NumericTypeClasses[0] <= type->getClass() && - type->getClass() <= &NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX]); - - switch (typeRepr->type()) { -#define REIFY_CASES(constant_, type_, name_) \ - case constant_: \ - return NumericType::reify( \ - cx, BlockMem(*owner) + offset, to); - JS_FOR_EACH_SCALAR_TYPE_REPR(REIFY_CASES) - } -#undef REIFY_CASES - - MOZ_ASSUME_UNREACHABLE("Invalid type"); - return false; -} - template bool NumericType::call(JSContext *cx, unsigned argc, Value *vp) @@ -547,7 +537,7 @@ const Class ArrayType::class_ = { nullptr, nullptr, nullptr, - BinaryBlock::construct, + TypedObject::construct, nullptr }; @@ -556,6 +546,7 @@ const JSPropertySpec ArrayType::typeObjectProperties[] = { }; const JSFunctionSpec ArrayType::typeObjectMethods[] = { + {"handle", {NULL, NULL}, 2, 0, "HandleCreate"}, JS_FN("repeat", ArrayType::repeat, 1, 0), JS_FN("toSource", ArrayType::toSource, 0, 0), JS_FS_END @@ -581,7 +572,7 @@ ArrayElementType(HandleObject array) static bool FillTypedArrayWithValue(JSContext *cx, HandleObject array, HandleValue val) { - JS_ASSERT(IsBinaryArray(*array)); + JS_ASSERT(IsTypedDatumOfKind(*array, TypeRepresentation::Array)); RootedFunction func( cx, SelfHostedFunction(cx, cx->names().FillTypedArrayWithValue)); @@ -619,7 +610,7 @@ ArrayType::repeat(JSContext *cx, unsigned int argc, Value *vp) return false; } - RootedObject binaryArray(cx, BinaryBlock::createZeroed(cx, thisObj)); + RootedObject binaryArray(cx, TypedObject::createZeroed(cx, thisObj)); if (!binaryArray) return false; @@ -696,7 +687,7 @@ ArrayType::subarray(JSContext *cx, unsigned int argc, Value *vp) } RootedObject thisObj(cx, &args.thisv().toObject()); - if (!IsBinaryArray(*thisObj)) { + if (!IsTypedDatumOfKind(*thisObj, TypeRepresentation::Array)) { ReportCannotConvertTo(cx, thisObj, "binary array"); return false; } @@ -743,7 +734,8 @@ ArrayType::subarray(JSContext *cx, unsigned int argc, Value *vp) int32_t elementSize = typeRepr->element()->size(); size_t offset = elementSize * begin; - RootedObject subarray(cx, BinaryBlock::createDerived(cx, subArrayType, thisObj, offset)); + RootedObject subarray( + cx, TypedDatum::createDerived(cx, subArrayType, thisObj, offset)); if (!subarray) return false; @@ -764,7 +756,7 @@ ArrayFillSubarray(JSContext *cx, unsigned int argc, Value *vp) } RootedObject thisObj(cx, ToObjectIfObject(args.thisv())); - if (!thisObj || !IsBinaryArray(*thisObj)) { + if (!thisObj || !IsTypedDatumOfKind(*thisObj, TypeRepresentation::Array)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, "ArrayType", "fill", @@ -796,7 +788,7 @@ InitializeCommonTypeDescriptorProperties(JSContext *cx, HandleObject typeReprOwnerObj) { TypeRepresentation *typeRepr = - TypeRepresentation::fromOwnerObject(typeReprOwnerObj); + TypeRepresentation::fromOwnerObject(*typeReprOwnerObj); // equivalent() if (!JS_DefineFunction(cx, obj, "equivalent", @@ -977,7 +969,7 @@ const Class StructType::class_ = { nullptr, /* checkAccess */ nullptr, /* call */ nullptr, /* hasInstance */ - BinaryBlock::construct, + TypedObject::construct, nullptr /* trace */ }; @@ -986,6 +978,7 @@ const JSPropertySpec StructType::typeObjectProperties[] = { }; const JSFunctionSpec StructType::typeObjectMethods[] = { + {"handle", {NULL, NULL}, 2, 0, "HandleCreate"}, JS_FN("toSource", StructType::toSource, 0, 0), JS_FS_END }; @@ -1051,7 +1044,7 @@ StructType::layout(JSContext *cx, HandleObject structType, HandleObject fields) if (!typeReprObj) return false; StructTypeRepresentation *typeRepr = - TypeRepresentation::fromOwnerObject(typeReprObj)->asStruct(); + TypeRepresentation::fromOwnerObject(*typeReprObj)->asStruct(); structType->initReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR, ObjectValue(*typeReprObj)); @@ -1088,11 +1081,9 @@ StructType::layout(JSContext *cx, HandleObject structType, HandleObject fields) // fieldOffsets : { string: integer, ... } // fieldTypes : { string: Type, ... } RootedObject fieldOffsets( - cx, - NewObjectWithClassProto(cx, &JSObject::class_, nullptr, nullptr)); + cx, NewObjectWithClassProto(cx, &JSObject::class_, NULL, NULL)); RootedObject fieldTypes( - cx, - NewObjectWithClassProto(cx, &JSObject::class_, nullptr, nullptr)); + cx, NewObjectWithClassProto(cx, &JSObject::class_, NULL, NULL)); for (size_t i = 0; i < typeRepr->fieldCount(); i++) { const StructField &field = typeRepr->field(i); RootedId fieldId(cx, field.id); @@ -1218,32 +1209,6 @@ StructType::toSource(JSContext *cx, unsigned int argc, Value *vp) /////////////////////////////////////////////////////////////////////////// -static bool -ReifyComplex(JSContext *cx, HandleObject type, HandleObject owner, - size_t offset, MutableHandleValue to) -{ - RootedObject obj(cx, BinaryBlock::createDerived(cx, type, owner, offset)); - if (!obj) - return false; - to.setObject(*obj); - return true; -} - -static bool -Reify(JSContext *cx, TypeRepresentation *typeRepr, HandleObject type, - HandleObject owner, size_t offset, MutableHandleValue to) -{ - JS_ASSERT(typeRepr == typeRepresentation(*type)); - switch (typeRepr->kind()) { - case TypeRepresentation::Scalar: - return ReifyScalar(cx, typeRepr->asScalar(), type, owner, offset, to); - case TypeRepresentation::Struct: - case TypeRepresentation::Array: - return ReifyComplex(cx, type, owner, offset, to); - } - MOZ_ASSUME_UNREACHABLE("Invalid typeRepr kind"); -} - /////////////////////////////////////////////////////////////////////////// // Creating the TypedObject "module" // @@ -1369,6 +1334,24 @@ js_InitTypedObjectClass(JSContext *cx, HandleObject obj) global->setArrayType(arrayType); global->markStandardClassInitializedNoProto(&TypedObjectClass); + // Handle + + RootedObject handle(cx, NewBuiltinClassInstance(cx, &JSObject::class_)); + if (!module) + return NULL; + + if (!JS_DefineFunctions(cx, handle, TypedHandle::handleStaticMethods)) + return NULL; + + RootedValue handleValue(cx, ObjectValue(*handle)); + if (!JSObject::defineProperty(cx, module, cx->names().Handle, + handleValue, + NULL, NULL, + JSPROP_READONLY | JSPROP_PERMANENT)) + { + return NULL; + } + return module; } @@ -1410,6 +1393,9 @@ DefineNumericClass(JSContext *cx, if (!InitializeCommonTypeDescriptorProperties(cx, numFun, typeReprObj)) return false; + if (!JS_DefineFunctions(cx, numFun, NumericTypeObjectMethods)) + return false; + if (!JS_DefineFunction(cx, numFun, "toString", NumericTypeToString, 0, 0)) return false; @@ -1429,62 +1415,117 @@ DefineNumericClass(JSContext *cx, } /////////////////////////////////////////////////////////////////////////// -// Binary blocks +// Typed datums -const Class BinaryBlock::class_ = { - "BinaryBlock", - Class::NON_NATIVE | - JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEDOBJ_SLOTS) | - JSCLASS_HAS_PRIVATE | - JSCLASS_IMPLEMENTS_BARRIERS, - JS_PropertyStub, - JS_DeletePropertyStub, - JS_PropertyStub, - JS_StrictPropertyStub, - JS_EnumerateStub, - JS_ResolveStub, - JS_ConvertStub, - BinaryBlock::obj_finalize, - nullptr, /* checkAccess */ - nullptr, /* call */ - nullptr, /* construct */ - nullptr, /* hasInstance */ - BinaryBlock::obj_trace, - JS_NULL_CLASS_EXT, - { - BinaryBlock::obj_lookupGeneric, - BinaryBlock::obj_lookupProperty, - BinaryBlock::obj_lookupElement, - BinaryBlock::obj_lookupSpecial, - BinaryBlock::obj_defineGeneric, - BinaryBlock::obj_defineProperty, - BinaryBlock::obj_defineElement, - BinaryBlock::obj_defineSpecial, - BinaryBlock::obj_getGeneric, - BinaryBlock::obj_getProperty, - BinaryBlock::obj_getElement, - BinaryBlock::obj_getElementIfPresent, - BinaryBlock::obj_getSpecial, - BinaryBlock::obj_setGeneric, - BinaryBlock::obj_setProperty, - BinaryBlock::obj_setElement, - BinaryBlock::obj_setSpecial, - BinaryBlock::obj_getGenericAttributes, - BinaryBlock::obj_setGenericAttributes, - BinaryBlock::obj_deleteProperty, - BinaryBlock::obj_deleteElement, - BinaryBlock::obj_deleteSpecial, - BinaryBlock::obj_enumerate, - nullptr, /* thisObject */ +template +/*static*/ T * +TypedDatum::createUnattached(JSContext *cx, + HandleObject type) +{ + JS_STATIC_ASSERT(T::IsTypedDatumClass); + JS_ASSERT(IsTypeObject(*type)); + + RootedObject obj(cx, createUnattachedWithClass(cx, &T::class_, type)); + if (!obj) + return NULL; + + return &obj->as(); +} + +/*static*/ TypedDatum * +TypedDatum::createUnattachedWithClass(JSContext *cx, + const Class *clasp, + HandleObject type) +{ + JS_ASSERT(IsTypeObject(*type)); + JS_ASSERT(clasp == &TypedObject::class_ || clasp == &TypedHandle::class_); + JS_ASSERT(JSCLASS_RESERVED_SLOTS(clasp) == JS_DATUM_SLOTS); + JS_ASSERT(clasp->hasPrivate()); + + RootedObject proto(cx); + if (IsNumericTypeObject(*type)) { + // FIXME Bug 929651 -- What prototype to use? + proto = type->global().getOrCreateObjectPrototype(cx); + } else { + RootedValue protoVal(cx); + if (!JSObject::getProperty(cx, type, type, + cx->names().prototype, &protoVal)) + { + return nullptr; + } + proto = &protoVal.toObject(); } -}; + + RootedObject obj( + cx, NewObjectWithClassProto(cx, clasp, &*proto, NULL)); + if (!obj) + return NULL; + + obj->setPrivate(nullptr); + obj->initReservedSlot(JS_DATUM_SLOT_TYPE_OBJ, ObjectValue(*type)); + obj->initReservedSlot(JS_DATUM_SLOT_OWNER, NullValue()); + + // Tag the type object for this instance with the type + // representation, if that has not been done already. + if (cx->typeInferenceEnabled() && !IsNumericTypeObject(*type)) { + // FIXME Bug 929651 ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + RootedTypeObject typeObj(cx, obj->getType(cx)); + if (typeObj) { + TypeRepresentation *typeRepr = typeRepresentation(*type); + if (!typeObj->addTypedObjectAddendum(cx, typeRepr)) + return nullptr; + } + } + + return static_cast(&*obj); +} + +/* static */ void +TypedDatum::attach(void *memory) +{ + setPrivate(memory); + setReservedSlot(JS_DATUM_SLOT_OWNER, ObjectValue(*this)); +} + +/*static*/ void +TypedDatum::attach(JSObject &datum, uint32_t offset) +{ + JS_ASSERT(IsTypedDatum(datum)); + JS_ASSERT(datum.getReservedSlot(JS_DATUM_SLOT_OWNER).isObject()); + + // find the location in memory + uint8_t *mem = TypedMem(datum) + offset; + + // find the owner, which is often but not always `datum` + JSObject &owner = datum.getReservedSlot(JS_DATUM_SLOT_OWNER).toObject(); + + setPrivate(mem); + setReservedSlot(JS_DATUM_SLOT_OWNER, ObjectValue(owner)); +} + +/*static*/ TypedDatum * +TypedDatum::createDerived(JSContext *cx, HandleObject type, + HandleObject datum, size_t offset) +{ + JS_ASSERT(IsTypedDatum(*datum)); + JS_ASSERT(offset <= DatumSize(*datum)); + JS_ASSERT(offset + TypeSize(*type) <= DatumSize(*datum)); + + const js::Class *clasp = datum->getClass(); + Rooted obj(cx, createUnattachedWithClass(cx, clasp, type)); + if (!obj) + return nullptr; + + obj->attach(*datum, offset); + return obj; +} static bool -ReportBlockTypeError(JSContext *cx, +ReportDatumTypeError(JSContext *cx, const unsigned errorNumber, HandleObject obj) { - JS_ASSERT(IsBlock(*obj)); + JS_ASSERT(IsTypedDatum(*obj)); RootedObject type(cx, GetType(*obj)); TypeRepresentation *typeRepr = typeRepresentation(*type); @@ -1501,123 +1542,44 @@ ReportBlockTypeError(JSContext *cx, if (!typeReprStr) return false; - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, typeReprStr); JS_free(cx, (void *) typeReprStr); return false; } -/* static */ void -BinaryBlock::obj_trace(JSTracer *trace, JSObject *object) +/*static*/ void +TypedDatum::obj_trace(JSTracer *trace, JSObject *object) { - JS_ASSERT(object->hasClass(&class_)); + JS_ASSERT(IsTypedDatum(*object)); - for (size_t i = 0; i < JS_TYPEDOBJ_SLOTS; i++) - gc::MarkSlot(trace, &object->getReservedSlotRef(i), "BinaryBlockSlot"); + for (size_t i = 0; i < JS_DATUM_SLOTS; i++) + gc::MarkSlot(trace, &object->getReservedSlotRef(i), "TypedObjectSlot"); } -/* static */ void -BinaryBlock::obj_finalize(js::FreeOp *op, JSObject *obj) +/*static*/ void +TypedDatum::obj_finalize(js::FreeOp *op, JSObject *obj) { - if (!obj->getReservedSlot(JS_TYPEDOBJ_SLOT_OWNER).isNull()) - return; + // if the obj owns the memory, indicating by the owner slot being + // set to itself, then we must free it when finalized. - if (void *mem = obj->getPrivate()) - op->free_(mem); -} + JS_ASSERT(obj->getReservedSlotRef(JS_DATUM_SLOT_OWNER).isObjectOrNull()); -/* static */ JSObject * -BinaryBlock::createNull(JSContext *cx, HandleObject type, HandleValue owner) -{ - JS_ASSERT(IsTypeObject(*type)); + if (obj->getReservedSlot(JS_DATUM_SLOT_OWNER).isNull()) + return; // Unattached - RootedValue protoVal(cx); - if (!JSObject::getProperty(cx, type, type, - cx->names().prototype, &protoVal)) - return nullptr; - - RootedObject obj(cx, - NewObjectWithClassProto(cx, &class_, &protoVal.toObject(), nullptr)); - obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_OBJ, ObjectValue(*type)); - obj->initReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, owner); - - // Tag the type object for this instance with the type - // representation, if that has not been done already. - if (cx->typeInferenceEnabled()) { - RootedTypeObject typeObj(cx, obj->getType(cx)); - if (typeObj) { - TypeRepresentation *typeRepr = typeRepresentation(*type); - if (!typeObj->addTypedObjectAddendum(cx, typeRepr)) - return nullptr; - } + if (&obj->getReservedSlot(JS_DATUM_SLOT_OWNER).toObject() == obj) { + JS_ASSERT(obj->getPrivate()); + op->free_(obj->getPrivate()); } - - return obj; -} - -/* static */ JSObject * -BinaryBlock::createZeroed(JSContext *cx, HandleObject type) -{ - RootedValue owner(cx, NullValue()); - RootedObject obj(cx, createNull(cx, type, owner)); - if (!obj) - return nullptr; - - TypeRepresentation *typeRepr = typeRepresentation(*type); - size_t memsize = typeRepr->size(); - void *memory = JS_malloc(cx, memsize); - if (!memory) - return nullptr; - memset(memory, 0, memsize); - obj->setPrivate(memory); - return obj; -} - -/* static */ JSObject * -BinaryBlock::createDerived(JSContext *cx, HandleObject type, - HandleObject owner, size_t offset) -{ - JS_ASSERT(IsBlock(*owner)); - JS_ASSERT(offset <= BlockSize(*owner)); - JS_ASSERT(offset + TypeSize(*type) <= BlockSize(*owner)); - - RootedValue ownerValue(cx, ObjectValue(*owner)); - RootedObject obj(cx, createNull(cx, type, ownerValue)); - if (!obj) - return nullptr; - - obj->setPrivate(BlockMem(*owner) + offset); - return obj; -} - -/* static */ bool -BinaryBlock::construct(JSContext *cx, unsigned int argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - RootedObject callee(cx, &args.callee()); - JS_ASSERT(IsTypeObject(*callee)); - - RootedObject obj(cx, createZeroed(cx, callee)); - if (!obj) - return false; - - if (argc == 1) { - RootedValue initial(cx, args[0]); - if (!ConvertAndCopyTo(cx, obj, initial)) - return false; - } - - args.rval().setObject(*obj); - return true; } bool -BinaryBlock::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, +TypedDatum::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp, MutableHandleShape propp) { - JS_ASSERT(IsBlock(*obj)); + JS_ASSERT(IsTypedDatum(*obj)); RootedObject type(cx, GetType(*obj)); TypeRepresentation *typeRepr = typeRepresentation(*type); @@ -1665,7 +1627,7 @@ BinaryBlock::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, } bool -BinaryBlock::obj_lookupProperty(JSContext *cx, +TypedDatum::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleObject objp, @@ -1676,10 +1638,10 @@ BinaryBlock::obj_lookupProperty(JSContext *cx, } bool -BinaryBlock::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, +TypedDatum::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp, MutableHandleShape propp) { - JS_ASSERT(IsBlock(*obj)); + JS_ASSERT(IsTypedDatum(*obj)); MarkNonNativePropertyFound(propp); objp.set(obj); return true; @@ -1706,32 +1668,32 @@ ReportPropertyError(JSContext *cx, } bool -BinaryBlock::obj_lookupSpecial(JSContext *cx, HandleObject obj, - HandleSpecialId sid, MutableHandleObject objp, - MutableHandleShape propp) +TypedDatum::obj_lookupSpecial(JSContext *cx, HandleObject obj, + HandleSpecialId sid, MutableHandleObject objp, + MutableHandleShape propp) { RootedId id(cx, SPECIALID_TO_JSID(sid)); return obj_lookupGeneric(cx, obj, id, objp, propp); } bool -BinaryBlock::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs) +TypedDatum::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v, + PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { return ReportPropertyError(cx, JSMSG_UNDEFINED_PROP, id); } bool -BinaryBlock::obj_defineProperty(JSContext *cx, HandleObject obj, - HandlePropertyName name, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs) +TypedDatum::obj_defineProperty(JSContext *cx, HandleObject obj, + HandlePropertyName name, HandleValue v, + PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { Rooted id(cx, NameToId(name)); return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs); } bool -BinaryBlock::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v, +TypedDatum::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); @@ -1743,8 +1705,8 @@ BinaryBlock::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, } bool -BinaryBlock::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs) +TypedDatum::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v, + PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { Rooted id(cx, SPECIALID_TO_JSID(sid)); return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs); @@ -1781,10 +1743,10 @@ StructFieldType(JSContext *cx, } bool -BinaryBlock::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, - HandleId id, MutableHandleValue vp) +TypedDatum::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, + HandleId id, MutableHandleValue vp) { - JS_ASSERT(IsBlock(*obj)); + JS_ASSERT(IsTypedDatum(*obj)); // Dispatch elements to obj_getElement: uint32_t index; @@ -1830,7 +1792,7 @@ BinaryBlock::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiv } bool -BinaryBlock::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, +TypedDatum::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name, MutableHandleValue vp) { RootedId id(cx, NameToId(name)); @@ -1838,7 +1800,7 @@ BinaryBlock::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject recei } bool -BinaryBlock::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, +TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp) { bool present; @@ -1846,9 +1808,9 @@ BinaryBlock::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiv } bool -BinaryBlock::obj_getElementIfPresent(JSContext *cx, HandleObject obj, - HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present) +TypedDatum::obj_getElementIfPresent(JSContext *cx, HandleObject obj, + HandleObject receiver, uint32_t index, + MutableHandleValue vp, bool *present) { RootedObject type(cx, GetType(*obj)); TypeRepresentation *typeRepr = typeRepresentation(*type); @@ -1884,7 +1846,7 @@ BinaryBlock::obj_getElementIfPresent(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_getSpecial(JSContext *cx, HandleObject obj, +TypedDatum::obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, MutableHandleValue vp) { @@ -1893,7 +1855,7 @@ BinaryBlock::obj_getSpecial(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id, +TypedDatum::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, bool strict) { uint32_t index; @@ -1928,11 +1890,11 @@ BinaryBlock::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id, } } - return ReportBlockTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, obj); + return ReportDatumTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, obj); } bool -BinaryBlock::obj_setProperty(JSContext *cx, HandleObject obj, +TypedDatum::obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp, bool strict) { @@ -1941,7 +1903,7 @@ BinaryBlock::obj_setProperty(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index, +TypedDatum::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp, bool strict) { RootedObject type(cx, GetType(*obj)); @@ -1967,11 +1929,11 @@ BinaryBlock::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index, } } - return ReportBlockTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, obj); + return ReportDatumTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, obj); } bool -BinaryBlock::obj_setSpecial(JSContext *cx, HandleObject obj, +TypedDatum::obj_setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleValue vp, bool strict) { @@ -1980,7 +1942,7 @@ BinaryBlock::obj_setSpecial(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_getGenericAttributes(JSContext *cx, HandleObject obj, +TypedDatum::obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp) { uint32_t index; @@ -2041,7 +2003,7 @@ IsOwnId(JSContext *cx, HandleObject obj, HandleId id) } bool -BinaryBlock::obj_setGenericAttributes(JSContext *cx, HandleObject obj, +TypedDatum::obj_setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp) { RootedObject type(cx, GetType(*obj)); @@ -2059,7 +2021,7 @@ BinaryBlock::obj_setGenericAttributes(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_deleteProperty(JSContext *cx, HandleObject obj, +TypedDatum::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, bool *succeeded) { Rooted id(cx, NameToId(name)); @@ -2076,7 +2038,7 @@ BinaryBlock::obj_deleteProperty(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, +TypedDatum::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, bool *succeeded) { RootedId id(cx); @@ -2096,7 +2058,7 @@ BinaryBlock::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, } bool -BinaryBlock::obj_deleteSpecial(JSContext *cx, HandleObject obj, +TypedDatum::obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, bool *succeeded) { RootedObject proto(cx, obj->getProto()); @@ -2109,7 +2071,7 @@ BinaryBlock::obj_deleteSpecial(JSContext *cx, HandleObject obj, } bool -BinaryBlock::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, +TypedDatum::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, MutableHandleValue statep, MutableHandleId idp) { uint32_t index; @@ -2190,11 +2152,288 @@ BinaryBlock::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, } /* static */ size_t -BinaryBlock::dataOffset() +TypedDatum::dataOffset() { - return JSObject::getPrivateDataOffset(JS_TYPEDOBJ_SLOTS + 1); + return JSObject::getPrivateDataOffset(JS_DATUM_SLOTS + 1); } +/////////////////////////////////////////////////////////////////////////// +// Typed Objects + +const Class TypedObject::class_ = { + "TypedObject", + Class::NON_NATIVE | + JSCLASS_HAS_RESERVED_SLOTS(JS_DATUM_SLOTS) | + JSCLASS_HAS_PRIVATE | + JSCLASS_IMPLEMENTS_BARRIERS, + JS_PropertyStub, + JS_DeletePropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + TypedDatum::obj_finalize, + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* hasInstance */ + TypedDatum::obj_trace, + JS_NULL_CLASS_EXT, + { + TypedDatum::obj_lookupGeneric, + TypedDatum::obj_lookupProperty, + TypedDatum::obj_lookupElement, + TypedDatum::obj_lookupSpecial, + TypedDatum::obj_defineGeneric, + TypedDatum::obj_defineProperty, + TypedDatum::obj_defineElement, + TypedDatum::obj_defineSpecial, + TypedDatum::obj_getGeneric, + TypedDatum::obj_getProperty, + TypedDatum::obj_getElement, + TypedDatum::obj_getElementIfPresent, + TypedDatum::obj_getSpecial, + TypedDatum::obj_setGeneric, + TypedDatum::obj_setProperty, + TypedDatum::obj_setElement, + TypedDatum::obj_setSpecial, + TypedDatum::obj_getGenericAttributes, + TypedDatum::obj_setGenericAttributes, + TypedDatum::obj_deleteProperty, + TypedDatum::obj_deleteElement, + TypedDatum::obj_deleteSpecial, + TypedDatum::obj_enumerate, + NULL, /* thisObject */ + } +}; + +/*static*/ JSObject * +TypedObject::createZeroed(JSContext *cx, HandleObject type) +{ + Rooted obj(cx, createUnattached(cx, type)); + if (!obj) + return NULL; + + TypeRepresentation *typeRepr = typeRepresentation(*type); + size_t memsize = typeRepr->size(); + void *memory = JS_malloc(cx, memsize); + if (!memory) + return NULL; + memset(memory, 0, memsize); + obj->attach(memory); + return obj; +} + +/*static*/ bool +TypedObject::construct(JSContext *cx, unsigned int argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + RootedObject callee(cx, &args.callee()); + JS_ASSERT(IsTypeObject(*callee)); + + RootedObject obj(cx, createZeroed(cx, callee)); + if (!obj) + return false; + + if (argc == 1) { + RootedValue initial(cx, args[0]); + if (!ConvertAndCopyTo(cx, obj, initial)) + return false; + } + + args.rval().setObject(*obj); + return true; +} + +/////////////////////////////////////////////////////////////////////////// +// Handles + +const Class TypedHandle::class_ = { + "Handle", + Class::NON_NATIVE | + JSCLASS_HAS_RESERVED_SLOTS(JS_DATUM_SLOTS) | + JSCLASS_HAS_PRIVATE | + JSCLASS_IMPLEMENTS_BARRIERS, + JS_PropertyStub, + JS_DeletePropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + TypedDatum::obj_finalize, + NULL, /* checkAccess */ + NULL, /* call */ + NULL, /* construct */ + NULL, /* hasInstance */ + TypedDatum::obj_trace, + JS_NULL_CLASS_EXT, + { + TypedDatum::obj_lookupGeneric, + TypedDatum::obj_lookupProperty, + TypedDatum::obj_lookupElement, + TypedDatum::obj_lookupSpecial, + TypedDatum::obj_defineGeneric, + TypedDatum::obj_defineProperty, + TypedDatum::obj_defineElement, + TypedDatum::obj_defineSpecial, + TypedDatum::obj_getGeneric, + TypedDatum::obj_getProperty, + TypedDatum::obj_getElement, + TypedDatum::obj_getElementIfPresent, + TypedDatum::obj_getSpecial, + TypedDatum::obj_setGeneric, + TypedDatum::obj_setProperty, + TypedDatum::obj_setElement, + TypedDatum::obj_setSpecial, + TypedDatum::obj_getGenericAttributes, + TypedDatum::obj_setGenericAttributes, + TypedDatum::obj_deleteProperty, + TypedDatum::obj_deleteElement, + TypedDatum::obj_deleteSpecial, + TypedDatum::obj_enumerate, + NULL, /* thisObject */ + } +}; + +const JSFunctionSpec TypedHandle::handleStaticMethods[] = { + {"move", {NULL, NULL}, 3, 0, "HandleMove"}, + {"get", {NULL, NULL}, 1, 0, "HandleGet"}, + {"set", {NULL, NULL}, 2, 0, "HandleSet"}, + {"isHandle", {NULL, NULL}, 1, 0, "HandleTest"}, + JS_FS_END +}; + +/////////////////////////////////////////////////////////////////////////// +// Intrinsics + +bool +js::NewTypedHandle(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 1); + JS_ASSERT(args[0].isObject() && IsTypeObject(args[0].toObject())); + + RootedObject typeObj(cx, &args[0].toObject()); + Rooted obj( + cx, TypedDatum::createUnattached(cx, typeObj)); + if (!obj) + return false; + args.rval().setObject(*obj); + return true; +} + +bool +js::NewDerivedTypedDatum(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 3); + JS_ASSERT(args[0].isObject() && IsTypeObject(args[0].toObject())); + JS_ASSERT(args[1].isObject() && IsTypedDatum(args[1].toObject())); + JS_ASSERT(args[2].isInt32()); + + RootedObject typeObj(cx, &args[0].toObject()); + RootedObject datum(cx, &args[1].toObject()); + int32_t offset = args[2].toInt32(); + + Rooted obj( + cx, TypedDatum::createDerived(cx, typeObj, datum, offset)); + if (!obj) + return false; + + args.rval().setObject(*obj); + return true; +} + +bool +js::AttachHandle(ThreadSafeContext *, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 3); + JS_ASSERT(args[0].isObject() && args[0].toObject().is()); + JS_ASSERT(args[1].isObject() && IsTypedDatum(args[1].toObject())); + JS_ASSERT(args[2].isInt32()); + + TypedHandle &handle = args[0].toObject().as(); + handle.attach(args[1].toObject(), args[2].toInt32()); + return true; +} + +const JSJitInfo js::AttachHandleJitInfo = + JS_JITINFO_NATIVE_PARALLEL( + JSParallelNativeThreadSafeWrapper); + +bool +js::ObjectIsTypeObject(ThreadSafeContext *, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 1); + JS_ASSERT(args[0].isObject()); + args.rval().setBoolean(IsTypeObject(args[0].toObject())); + return true; +} + +const JSJitInfo js::ObjectIsTypeObjectJitInfo = + JS_JITINFO_NATIVE_PARALLEL( + JSParallelNativeThreadSafeWrapper); + +bool +js::ObjectIsTypeRepresentation(ThreadSafeContext *, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 1); + JS_ASSERT(args[0].isObject()); + args.rval().setBoolean(TypeRepresentation::isOwnerObject(args[0].toObject())); + return true; +} + +const JSJitInfo js::ObjectIsTypeRepresentationJitInfo = + JS_JITINFO_NATIVE_PARALLEL( + JSParallelNativeThreadSafeWrapper); + +bool +js::ObjectIsTypedHandle(ThreadSafeContext *, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 1); + JS_ASSERT(args[0].isObject()); + args.rval().setBoolean(args[0].toObject().is()); + return true; +} + +const JSJitInfo js::ObjectIsTypedHandleJitInfo = + JS_JITINFO_NATIVE_PARALLEL( + JSParallelNativeThreadSafeWrapper); + +bool +js::ObjectIsTypedObject(ThreadSafeContext *, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(argc == 1); + JS_ASSERT(args[0].isObject()); + args.rval().setBoolean(args[0].toObject().is()); + return true; +} + +const JSJitInfo js::ObjectIsTypedObjectJitInfo = + JS_JITINFO_NATIVE_PARALLEL( + JSParallelNativeThreadSafeWrapper); + +bool +js::IsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + JS_ASSERT(args[0].isObject() && IsTypedDatum(args[0].toObject())); + args.rval().setBoolean(TypedMem(args[0].toObject()) != NULL); + return true; +} + +const JSJitInfo js::IsAttachedJitInfo = + JS_JITINFO_NATIVE_PARALLEL( + JSParallelNativeThreadSafeWrapper); + bool js::ClampToUint8(ThreadSafeContext *, unsigned argc, Value *vp) { @@ -2214,14 +2453,14 @@ js::Memcpy(ThreadSafeContext *, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(args.length() == 5); - JS_ASSERT(args[0].isObject() && IsBlock(args[0].toObject())); + JS_ASSERT(args[0].isObject() && IsTypedDatum(args[0].toObject())); JS_ASSERT(args[1].isInt32()); - JS_ASSERT(args[2].isObject() && IsBlock(args[2].toObject())); + JS_ASSERT(args[2].isObject() && IsTypedDatum(args[2].toObject())); JS_ASSERT(args[3].isInt32()); JS_ASSERT(args[4].isInt32()); - uint8_t *target = BlockMem(args[0].toObject()) + args[1].toInt32(); - uint8_t *source = BlockMem(args[2].toObject()) + args[3].toInt32(); + uint8_t *target = TypedMem(args[0].toObject()) + args[1].toInt32(); + uint8_t *source = TypedMem(args[2].toObject()) + args[3].toInt32(); int32_t size = args[4].toInt32(); memcpy(target, source, size); args.rval().setUndefined(); @@ -2238,7 +2477,7 @@ js::StoreScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \ { \ CallArgs args = CallArgsFromVp(argc, vp); \ JS_ASSERT(args.length() == 3); \ - JS_ASSERT(args[0].isObject() && IsBlock(args[0].toObject())); \ + JS_ASSERT(args[0].isObject() && IsTypedDatum(args[0].toObject())); \ JS_ASSERT(args[1].isInt32()); \ JS_ASSERT(args[2].isNumber()); \ \ @@ -2247,7 +2486,7 @@ js::StoreScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \ /* Should be guaranteed by the typed objects API: */ \ JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \ \ - T *target = (T*) (BlockMem(args[0].toObject()) + offset); \ + T *target = (T*) (TypedMem(args[0].toObject()) + offset); \ double d = args[2].toNumber(); \ *target = ConvertScalar(d); \ args.rval().setUndefined(); \ @@ -2265,7 +2504,7 @@ js::LoadScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \ { \ CallArgs args = CallArgsFromVp(argc, vp); \ JS_ASSERT(args.length() == 2); \ - JS_ASSERT(args[0].isObject() && IsBlock(args[0].toObject())); \ + JS_ASSERT(args[0].isObject() && IsTypedDatum(args[0].toObject())); \ JS_ASSERT(args[1].isInt32()); \ \ int32_t offset = args[1].toInt32(); \ @@ -2273,7 +2512,7 @@ js::LoadScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \ /* Should be guaranteed by the typed objects API: */ \ JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \ \ - T *target = (T*) (BlockMem(args[0].toObject()) + offset); \ + T *target = (T*) (TypedMem(args[0].toObject()) + offset); \ args.rval().setNumber((double) *target); \ return true; \ } \ diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index cd59f826a28..2b1e19f5349 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -12,6 +12,88 @@ #include "builtin/TypedObjectConstants.h" #include "builtin/TypeRepresentation.h" +/* + * ------------- + * Typed Objects + * ------------- + * + * Typed objects are a special kind of JS object where the data is + * given well-structured form. To use a typed object, users first + * create *type objects* (no relation to the type objects used in TI) + * that define the type layout. For example, a statement like: + * + * var PointType = new StructType({x: uint8, y: uint8}); + * + * would create a type object PointType that is a struct with + * two fields, each of uint8 type. + * + * This comment typically assumes familiary with the API. For more + * info on the API itself, see the Harmony wiki page at + * http://wiki.ecmascript.org/doku.php?id=harmony:typed_objects or the + * ES6 spec (not finalized at the time of this writing). + * + * - Initialization: + * + * Currently, all "globals" related to typed objects are packaged + * within a single "module" object `TypedObject`. This module has its + * own js::Class and when that class is initialized, we also create + * and define all other values (in `js_InitTypedObjectClass()`). + * + * - Type objects, meta type objects, and type representations: + * + * There are a number of pre-defined type objects, one for each + * scalar type (`uint8` etc). Each of these has its own class_, + * defined in `DefineNumericClass()`. + * + * There are also meta type objects (`ArrayType`, `StructType`). + * These constructors are not themselves type objects but rather the + * means for the *user* to construct new typed objects. + * + * Each type object is associated with a *type representation* (see + * TypeRepresentation.h). Type representations are canonical versions + * of type objects. We attach them to TI type objects and (eventually) + * use them for shape guards etc. They are purely internal to the + * engine and are not exposed to end users (though self-hosted code + * sometimes accesses them). + * + * - Typed datums, objects, and handles: + * + * A typed object is an instance of a type object. A handle is a + * relocatable pointer that points into other typed objects. Both of them + * are basically represented the same way, though they have distinct + * js::Class entries. They are both subtypes of `TypedDatum`. + * + * Both typed objects and handles are non-native objects that fully + * override the property accessors etc. The overridden accessor + * methods are the same in each and are defined in methods of + * TypedDatum. + * + * Typed datums may be attached or unattached. An unattached typed + * datum has no memory associated with it; it is basically a null + * pointer. This can only happen when a new handle is created, since + * typed object instances are always associated with memory at the + * point of creation. + * + * When a new typed object instance is created, fresh memory is + * allocated and set as that typed object's private field. The object + * is then considered the *owner* of that memory: when the object is + * collected, its finalizer will free the memory. The fact that an + * object `o` owns its memory is indicated by setting its reserved + * slot JS_TYPEDOBJ_SLOT_OWNER to `o` (a trivial cycle, in other + * words). + * + * Later, *derived* typed objects can be created, typically via an + * access like `o.f` where `f` is some complex (non-scalar) type, but + * also explicitly via Handle objects. In those cases, the memory + * pointer of the derived object is set to alias the owner's memory + * pointer, and the owner slot for the derived object is set to the + * owner object, thus ensuring that the owner is not collected while + * the derived object is alive. We always maintain the invariant that + * JS_TYPEDOBJ_SLOT_OWNER is the true owner of the memory, meaning + * that there is a shallow tree. This prevents an access pattern like + * `a.b.c.d` from keeping all the intermediate objects alive. + */ + namespace js { /* @@ -79,7 +161,8 @@ class StructType : public JSObject private: static JSObject *create(JSContext *cx, HandleObject structTypeGlobal, HandleObject fields); - /** + + /* * Sets up structType slots based on calculated memory size * and alignment and stores fieldmap as well. */ @@ -110,135 +193,237 @@ class StructType : public JSObject HandleValue from, uint8_t *mem); }; -/* Binary data objects and handles */ -class BinaryBlock +/* + * Base type for typed objects and handles. Basically any type whose + * contents consist of typed memory. + */ +class TypedDatum : public JSObject { private: - // Creates a binary data object of the given type and class, but with - // a nullptr memory pointer. Caller must use setPrivate() to set the - // memory pointer properly. - static JSObject *createNull(JSContext *cx, HandleObject type, - HandleValue owner); + static const bool IsTypedDatumClass = true; + protected: static void obj_finalize(js::FreeOp *op, JSObject *obj); static void obj_trace(JSTracer *trace, JSObject *object); static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp); + HandleId id, MutableHandleObject objp, + MutableHandleShape propp); static bool obj_lookupProperty(JSContext *cx, HandleObject obj, - HandlePropertyName name, - MutableHandleObject objp, - MutableHandleShape propp); + HandlePropertyName name, + MutableHandleObject objp, + MutableHandleShape propp); static bool obj_lookupElement(JSContext *cx, HandleObject obj, - uint32_t index, MutableHandleObject objp, - MutableHandleShape propp); + uint32_t index, MutableHandleObject objp, + MutableHandleShape propp); static bool obj_lookupSpecial(JSContext *cx, HandleObject obj, - HandleSpecialId sid, - MutableHandleObject objp, - MutableHandleShape propp); + HandleSpecialId sid, + MutableHandleObject objp, + MutableHandleShape propp); static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs); + PropertyOp getter, StrictPropertyOp setter, unsigned attrs); static bool obj_defineProperty(JSContext *cx, HandleObject obj, - HandlePropertyName name, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs); + HandlePropertyName name, HandleValue v, + PropertyOp getter, StrictPropertyOp setter, unsigned attrs); static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs); + PropertyOp getter, StrictPropertyOp setter, unsigned attrs); static bool obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs); + PropertyOp getter, StrictPropertyOp setter, unsigned attrs); static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, - HandleId id, MutableHandleValue vp); + HandleId id, MutableHandleValue vp); static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, - HandlePropertyName name, MutableHandleValue vp); + HandlePropertyName name, MutableHandleValue vp); static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, - uint32_t index, MutableHandleValue vp); + uint32_t index, MutableHandleValue vp); static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, - HandleSpecialId sid, MutableHandleValue vp); + HandleSpecialId sid, MutableHandleValue vp); static bool obj_getElementIfPresent(JSContext *cx, HandleObject obj, - HandleObject receiver, uint32_t index, - MutableHandleValue vp, bool *present); + HandleObject receiver, uint32_t index, + MutableHandleValue vp, bool *present); static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id, - MutableHandleValue vp, bool strict); + MutableHandleValue vp, bool strict); static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, - MutableHandleValue vp, bool strict); + MutableHandleValue vp, bool strict); static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index, - MutableHandleValue vp, bool strict); + MutableHandleValue vp, bool strict); static bool obj_setSpecial(JSContext *cx, HandleObject obj, - HandleSpecialId sid, MutableHandleValue vp, bool strict); + HandleSpecialId sid, MutableHandleValue vp, bool strict); static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj, - HandleId id, unsigned *attrsp); + HandleId id, unsigned *attrsp); static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj, - HandleId id, unsigned *attrsp); + HandleId id, unsigned *attrsp); static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, - bool *succeeded); + bool *succeeded); static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, - bool *succeeded); + bool *succeeded); static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, - bool *succeeded); + bool *succeeded); static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, - MutableHandleValue statep, MutableHandleId idp); + MutableHandleValue statep, MutableHandleId idp); public: - static const Class class_; - // Returns the offset in bytes within the object where the `void*` // pointer can be found. static size_t dataOffset(); - static bool isBlock(HandleObject val); - static uint8_t *mem(HandleObject val); + static TypedDatum *createUnattachedWithClass(JSContext *cx, + const Class *clasp, + HandleObject type); + + // Creates an unattached typed object or handle (depending on the + // type parameter T). Note that it is only legal for unattached + // handles to escape to the end user; for non-handles, the caller + // should always invoke one of the `attach()` methods below. + // + // Arguments: + // - type: type object for resulting object + template + static T *createUnattached(JSContext *cx, HandleObject type); + + // Creates a datum that aliases the memory pointed at by `owner` + // at the given offset. The datum will be a handle iff type is a + // handle and a typed object otherwise. + static TypedDatum *createDerived(JSContext *cx, + HandleObject type, + HandleObject typedContents, + size_t offset); + + // If `this` is the owner of the memory, use this. + void attach(void *mem); + + // Otherwise, use this to attach to memory referenced by another datum. + void attach(JSObject &datum, uint32_t offset); +}; + +class TypedObject : public TypedDatum +{ + public: + static const Class class_; // creates zeroed memory of size of type static JSObject *createZeroed(JSContext *cx, HandleObject type); - // creates a block that aliases the memory owned by `owner` at the - // given offset - static JSObject *createDerived(JSContext *cx, HandleObject type, - HandleObject owner, size_t offset); - // user-accessible constructor (`new TypeDescriptor(...)`) static bool construct(JSContext *cx, unsigned argc, Value *vp); }; +class TypedHandle : public TypedDatum +{ + public: + static const Class class_; + static const JSFunctionSpec handleStaticMethods[]; +}; -// Usage: ClampToUint8(v) -// -// Same as the C function ClampDoubleToUint8. `v` must be a number. +/* + * Usage: NewTypedHandle(typeObj) + * + * Constructs a new, unattached instance of `Handle`. + */ +bool NewTypedHandle(JSContext *cx, unsigned argc, Value *vp); + +/* + * Usage: NewDerivedTypedDatum(typeObj, owner, offset) + * + * Constructs a new, unattached instance of `Handle`. + */ +bool NewDerivedTypedDatum(JSContext *cx, unsigned argc, Value *vp); + +/* + * Usage: AttachHandle(handle, newOwner, newOffset) + * + * Moves `handle` to point at the memory owned by `newOwner` with + * the offset `newOffset`. + */ +bool AttachHandle(ThreadSafeContext *cx, unsigned argc, Value *vp); +extern const JSJitInfo AttachHandleJitInfo; + +/* + * Usage: ObjectIsTypeObject(obj) + * + * True if `obj` is a type object. + */ +bool ObjectIsTypeObject(ThreadSafeContext *cx, unsigned argc, Value *vp); +extern const JSJitInfo ObjectIsTypeObjectJitInfo; + +/* + * Usage: ObjectIsTypeRepresentation(obj) + * + * True if `obj` is a type representation object. + */ +bool ObjectIsTypeRepresentation(ThreadSafeContext *cx, unsigned argc, Value *vp); +extern const JSJitInfo ObjectIsTypeRepresentationJitInfo; + +/* + * Usage: ObjectIsTypedHandle(obj) + * + * True if `obj` is a handle. + */ +bool ObjectIsTypedHandle(ThreadSafeContext *cx, unsigned argc, Value *vp); +extern const JSJitInfo ObjectIsTypedHandleJitInfo; + +/* + * Usage: ObjectIsTypedObject(obj) + * + * True if `obj` is a typed object. + */ +bool ObjectIsTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp); +extern const JSJitInfo ObjectIsTypedObjectJitInfo; + +/* + * Usage: IsAttached(obj) + * + * Given a TypedDatum `obj`, returns true if `obj` is + * "attached" (i.e., its data pointer is NULL). + */ +bool IsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp); +extern const JSJitInfo IsAttachedJitInfo; + +/* + * Usage: ClampToUint8(v) + * + * Same as the C function ClampDoubleToUint8. `v` must be a number. + */ bool ClampToUint8(ThreadSafeContext *cx, unsigned argc, Value *vp); extern const JSJitInfo ClampToUint8JitInfo; -// Usage: Memcpy(targetTypedObj, targetOffset, -// sourceTypedObj, sourceOffset, -// size) -// -// Intrinsic function. Copies size bytes from the data for -// `sourceTypedObj` at `sourceOffset` into the data for -// `targetTypedObj` at `targetOffset`. +/* + * Usage: Memcpy(targetDatum, targetOffset, + * sourceDatum, sourceOffset, + * size) + * + * Intrinsic function. Copies size bytes from the data for + * `sourceDatum` at `sourceOffset` into the data for + * `targetDatum` at `targetOffset`. + * + * Both `sourceDatum` and `targetDatum` must be attached. + */ bool Memcpy(ThreadSafeContext *cx, unsigned argc, Value *vp); - extern const JSJitInfo MemcpyJitInfo; -// Usage: StoreScalar(targetTypedObj, targetOffset, value) -// -// Intrinsic function. Stores value (which must be an int32 or uint32) -// by `scalarTypeRepr` (which must be a type repr obj) and stores the -// value at the memory for `targetTypedObj` at offset `targetOffset`. +/* + * Usage: StoreScalar(targetDatum, targetOffset, value) + * + * Intrinsic function. Stores value (which must be an int32 or uint32) + * by `scalarTypeRepr` (which must be a type repr obj) and stores the + * value at the memory for `targetDatum` at offset `targetOffset`. + * `targetDatum` must be attached. + */ #define JS_STORE_SCALAR_CLASS_DEFN(_constant, T, _name) \ class StoreScalar##T { \ public: \ @@ -246,12 +431,14 @@ class StoreScalar##T { \ static const JSJitInfo JitInfo; \ }; -// Usage: LoadScalar(targetTypedObj, targetOffset, value) -// -// Intrinsic function. Loads value (which must be an int32 or uint32) -// by `scalarTypeRepr` (which must be a type repr obj) and loads the -// value at the memory for `targetTypedObj` at offset `targetOffset`. -// `targetTypedObj` must be attached. +/* + * Usage: LoadScalar(targetDatum, targetOffset, value) + * + * Intrinsic function. Loads value (which must be an int32 or uint32) + * by `scalarTypeRepr` (which must be a type repr obj) and loads the + * value at the memory for `targetDatum` at offset `targetOffset`. + * `targetDatum` must be attached. + */ #define JS_LOAD_SCALAR_CLASS_DEFN(_constant, T, _name) \ class LoadScalar##T { \ public: \ diff --git a/js/src/builtin/TypedObject.js b/js/src/builtin/TypedObject.js index 0c7ba2268d3..8b69aae76ca 100644 --- a/js/src/builtin/TypedObject.js +++ b/js/src/builtin/TypedObject.js @@ -10,8 +10,10 @@ // Typed object slots -#define TYPED_TYPE_OBJ(obj) \ - UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_TYPE_OBJ) +#define DATUM_TYPE_OBJ(obj) \ + UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_TYPE_OBJ) +#define DATUM_OWNER(obj) \ + UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_OWNER) // Type repr slots @@ -29,9 +31,9 @@ #define HAS_PROPERTY(obj, prop) \ callFunction(std_Object_hasOwnProperty, obj, prop) -function TYPED_TYPE_REPR(obj) { +function DATUM_TYPE_REPR(obj) { // Eventually this will be a slot on typed objects - return TYPE_TYPE_REPR(TYPED_TYPE_OBJ(obj)); + return TYPE_TYPE_REPR(DATUM_TYPE_OBJ(obj)); } /////////////////////////////////////////////////////////////////////////// @@ -41,8 +43,8 @@ function TYPED_TYPE_REPR(obj) { // pointer into typed object memory. They pull together: // - typeRepr: the internal type representation // - typeObj: the user-visible type object -// - owner: the owner object that contains the allocated block of memory -// - offset: an offset into that owner object +// - datum: the typed object that contains the allocated block of memory +// - offset: an offset into that typed object // // They are basically equivalent to a typed object, except that they // offer lots of internal unsafe methods and are not native objects. @@ -54,15 +56,22 @@ function TYPED_TYPE_REPR(obj) { // they mutate the receiver in place, because it makes for prettier // code. -function TypedObjectPointer(typeRepr, typeObj, owner, offset) { +function TypedObjectPointer(typeRepr, typeObj, datum, offset) { this.typeRepr = typeRepr; this.typeObj = typeObj; - this.owner = owner; + this.datum = datum; this.offset = offset; } MakeConstructible(TypedObjectPointer, {}); +TypedObjectPointer.fromTypedDatum = function(typed) { + return new TypedObjectPointer(DATUM_TYPE_REPR(typed), + DATUM_TYPE_OBJ(typed), + typed, + 0); +} + #ifdef DEBUG TypedObjectPointer.prototype.toString = function() { return "Ptr(" + this.typeObj.toSource() + " @ " + this.offset + ")"; @@ -71,13 +80,13 @@ TypedObjectPointer.prototype.toString = function() { TypedObjectPointer.prototype.copy = function() { return new TypedObjectPointer(this.typeRepr, this.typeObj, - this.owner, this.offset); + this.datum, this.offset); }; TypedObjectPointer.prototype.reset = function(inPtr) { this.typeRepr = inPtr.typeRepr; this.typeObj = inPtr.typeObj; - this.owner = inPtr.owner; + this.datum = inPtr.datum; this.offset = inPtr.offset; return this; }; @@ -161,6 +170,60 @@ TypedObjectPointer.prototype.moveToField = function(propName) { return this; } +/////////////////////////////////////////////////////////////////////////// +// Getting values +// +// The methods in this section read from the memory pointed at +// by `this` and produce JS values. This process is called *reification* +// in the spec. + + +// Reifies the value referenced by the pointer, meaning that it +// returns a new object pointing at the value. If the value is +// a scalar, it will return a JS number, but otherwise the reified +// result will be a typed object or handle, depending on the type +// of the ptr's datum. +TypedObjectPointer.prototype.get = function() { + assert(ObjectIsAttached(this.datum), "get() called with unattached datum"); + + if (REPR_KIND(this.typeRepr) == JS_TYPEREPR_SCALAR_KIND) + return this.getScalar(); + + return NewDerivedTypedDatum(this.typeObj, this.datum, this.offset); +} + +TypedObjectPointer.prototype.getScalar = function() { + var type = REPR_TYPE(this.typeRepr); + switch (type) { + case JS_SCALARTYPEREPR_INT8: + return Load_int8(this.datum, this.offset); + + case JS_SCALARTYPEREPR_UINT8: + case JS_SCALARTYPEREPR_UINT8_CLAMPED: + return Load_uint8(this.datum, this.offset); + + case JS_SCALARTYPEREPR_INT16: + return Load_int16(this.datum, this.offset); + + case JS_SCALARTYPEREPR_UINT16: + return Load_uint16(this.datum, this.offset); + + case JS_SCALARTYPEREPR_INT32: + return Load_int32(this.datum, this.offset); + + case JS_SCALARTYPEREPR_UINT32: + return Load_uint32(this.datum, this.offset); + + case JS_SCALARTYPEREPR_FLOAT32: + return Load_float32(this.datum, this.offset); + + case JS_SCALARTYPEREPR_FLOAT64: + return Load_float64(this.datum, this.offset); + } + + assert(false, "Unhandled scalar type: " + type); +} + /////////////////////////////////////////////////////////////////////////// // Setting values // @@ -170,15 +233,20 @@ TypedObjectPointer.prototype.moveToField = function(propName) { // to `typeRepr` as needed. This is the most general entry point and // works for any type. TypedObjectPointer.prototype.set = function(fromValue) { + assert(ObjectIsAttached(this.datum), "set() called with unattached datum"); + var typeRepr = this.typeRepr; // Fast path: `fromValue` is a typed object with same type // representation as the destination. In that case, we can just do a // memcpy. - if (IsObject(fromValue) && HaveSameClass(fromValue, this.owner)) { - if (TYPED_TYPE_REPR(fromValue) === typeRepr) { + if (IsObject(fromValue) && HaveSameClass(fromValue, this.datum)) { + if (DATUM_TYPE_REPR(fromValue) === typeRepr) { + if (!ObjectIsAttached(fromValue)) + ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); + var size = REPR_SIZE(typeRepr); - Memcpy(this.owner, this.offset, fromValue, 0, size); + Memcpy(this.datum, this.offset, fromValue, 0, size); return; } } @@ -233,38 +301,38 @@ TypedObjectPointer.prototype.setScalar = function(fromValue) { var type = REPR_TYPE(this.typeRepr); switch (type) { case JS_SCALARTYPEREPR_INT8: - return Store_int8(this.owner, this.offset, + return Store_int8(this.datum, this.offset, TO_INT32(fromValue) & 0xFF); case JS_SCALARTYPEREPR_UINT8: - return Store_uint8(this.owner, this.offset, + return Store_uint8(this.datum, this.offset, TO_UINT32(fromValue) & 0xFF); case JS_SCALARTYPEREPR_UINT8_CLAMPED: var v = ClampToUint8(+fromValue); - return Store_int8(this.owner, this.offset, v); + return Store_int8(this.datum, this.offset, v); case JS_SCALARTYPEREPR_INT16: - return Store_int16(this.owner, this.offset, + return Store_int16(this.datum, this.offset, TO_INT32(fromValue) & 0xFFFF); case JS_SCALARTYPEREPR_UINT16: - return Store_uint16(this.owner, this.offset, + return Store_uint16(this.datum, this.offset, TO_UINT32(fromValue) & 0xFFFF); case JS_SCALARTYPEREPR_INT32: - return Store_int32(this.owner, this.offset, + return Store_int32(this.datum, this.offset, TO_INT32(fromValue)); case JS_SCALARTYPEREPR_UINT32: - return Store_uint32(this.owner, this.offset, + return Store_uint32(this.datum, this.offset, TO_UINT32(fromValue)); case JS_SCALARTYPEREPR_FLOAT32: - return Store_float32(this.owner, this.offset, +fromValue); + return Store_float32(this.datum, this.offset, +fromValue); case JS_SCALARTYPEREPR_FLOAT64: - return Store_float64(this.owner, this.offset, +fromValue); + return Store_float64(this.datum, this.offset, +fromValue); } assert(false, "Unhandled scalar type: " + type); @@ -278,26 +346,54 @@ TypedObjectPointer.prototype.setScalar = function(fromValue) { // Wrapper for use from C++ code. function ConvertAndCopyTo(destTypeRepr, destTypeObj, - destTypedObj, + destDatum, destOffset, fromValue) { + assert(IsObject(destTypeRepr) && ObjectIsTypeRepresentation(destTypeRepr), + "ConvertAndCopyTo: not type repr"); + assert(IsObject(destTypeObj) && ObjectIsTypeObject(destTypeObj), + "ConvertAndCopyTo: not type obj"); + assert(IsObject(destDatum) && ObjectIsTypedDatum(destDatum), + "ConvertAndCopyTo: not type datum"); + + if (!ObjectIsAttached(destDatum)) + ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); + var ptr = new TypedObjectPointer(destTypeRepr, destTypeObj, - destTypedObj, destOffset); + destDatum, destOffset); ptr.set(fromValue); } +// Wrapper for use from C++ code. +function Reify(sourceTypeRepr, + sourceTypeObj, + sourceDatum, + sourceOffset) { + assert(IsObject(sourceTypeRepr) && ObjectIsTypeRepresentation(sourceTypeRepr), + "Reify: not type repr"); + assert(IsObject(sourceTypeObj) && ObjectIsTypeObject(sourceTypeObj), + "Reify: not type obj"); + assert(IsObject(sourceDatum) && ObjectIsTypedDatum(sourceDatum), + "Reify: not type datum"); + + if (!ObjectIsAttached(sourceDatum)) + ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); + + var ptr = new TypedObjectPointer(sourceTypeRepr, sourceTypeObj, + sourceDatum, sourceOffset); + + return ptr.get(); +} + function FillTypedArrayWithValue(destArray, fromValue) { - var typeRepr = TYPED_TYPE_REPR(destArray); + var typeRepr = DATUM_TYPE_REPR(destArray); var length = REPR_LENGTH(typeRepr); if (length === 0) return; // Use convert and copy to to produce the first element: - var ptr = new TypedObjectPointer(typeRepr, - TYPED_TYPE_OBJ(destArray), - destArray, - 0); + var ptr = TypedObjectPointer.fromTypedDatum(destArray); ptr.moveToElem(0); ptr.set(fromValue); @@ -308,4 +404,96 @@ function FillTypedArrayWithValue(destArray, fromValue) { Memcpy(destArray, offset, destArray, 0, elementSize); } +/////////////////////////////////////////////////////////////////////////// +// Handles +// +// Note: these methods are directly invokable by users and so must be +// defensive. +// This is the `handle([obj, [...path]])` method on type objects. +// User exposed! +// +// FIXME bug 929656 -- label algorithms with steps from the spec +function HandleCreate(obj, ...path) { + if (!ObjectIsTypeObject(this)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Type", "handle", "value"); + + var handle = NewTypedHandle(this); + + if (obj !== undefined) + HandleMoveInternal(handle, obj, path) + + return handle; +} + +// Handle.move: user exposed! +// FIXME bug 929656 -- label algorithms with steps from the spec +function HandleMove(handle, obj, ...path) { + if (!ObjectIsTypedHandle(handle)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value); + + HandleMoveInternal(handle, obj, path); +} + +function HandleMoveInternal(handle, obj, path) { + assert(ObjectIsTypedHandle(handle), + "HandleMoveInternal: not typed handle"); + + if (!IsObject(obj) || !ObjectIsTypedDatum(obj)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO); + + var ptr = TypedObjectPointer.fromTypedDatum(obj); + for (var i = 0; i < path.length; i++) + ptr.moveTo(path[i]); + + // Check that the new destination is equivalent to the handle type. + if (ptr.typeRepr !== DATUM_TYPE_REPR(handle)) + ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE); + + AttachHandle(handle, ptr.datum, ptr.offset) +} + +// Handle.get: user exposed! +// FIXME bug 929656 -- label algorithms with steps from the spec +function HandleGet(handle) { + if (!IsObject(handle) || !ObjectIsTypedHandle(handle)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value); + + if (!ObjectIsAttached(handle)) + ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); + + var ptr = TypedObjectPointer.fromTypedDatum(handle); + return ptr.get(); +} + +// Handle.set: user exposed! +// FIXME bug 929656 -- label algorithms with steps from the spec +function HandleSet(handle, value) { + if (!IsObject(handle) || !ObjectIsTypedHandle(handle)) + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value); + + if (!ObjectIsAttached(handle)) + ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); + + var ptr = TypedObjectPointer.fromTypedDatum(handle); + ptr.set(value); +} + +// Handle.isHandle: user exposed! +// FIXME bug 929656 -- label algorithms with steps from the spec +function HandleTest(obj) { + return IsObject(obj) && ObjectIsTypedHandle(obj); +} + +/////////////////////////////////////////////////////////////////////////// +// Miscellaneous + +function ObjectIsTypedDatum(obj) { + return ObjectIsTypedObject(obj) || ObjectIsTypedHandle(obj); +} + +function ObjectIsAttached(obj) { + assert(ObjectIsTypedDatum(obj), + "ObjectIsAttached() invoked on invalid obj"); + return DATUM_OWNER(obj) != null; +} diff --git a/js/src/builtin/TypedObjectConstants.h b/js/src/builtin/TypedObjectConstants.h index 26e84ad43b5..8371d8d7d8f 100644 --- a/js/src/builtin/TypedObjectConstants.h +++ b/js/src/builtin/TypedObjectConstants.h @@ -77,10 +77,10 @@ #define JS_SCALARTYPEREPR_UINT8_CLAMPED 8 /////////////////////////////////////////////////////////////////////////// -// Slots for typed objects +// Slots for typed objects (actually, any TypedContents objects) -#define JS_TYPEDOBJ_SLOT_TYPE_OBJ 0 // Type object for a given typed object -#define JS_TYPEDOBJ_SLOT_OWNER 1 // Owner of data (if null, this is owner) -#define JS_TYPEDOBJ_SLOTS 2 // Number of slots for typed objs +#define JS_DATUM_SLOT_TYPE_OBJ 0 // Type object for a given typed object +#define JS_DATUM_SLOT_OWNER 1 // Owner of data (if null, this is owner) +#define JS_DATUM_SLOTS 2 // Number of slots for typed objs #endif diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index f06b2e50ccd..80863c69bd9 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3659,7 +3659,7 @@ CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir) { Register obj = ToRegister(lir->object()); Register out = ToRegister(lir->output()); - masm.loadPtr(Address(obj, BinaryBlock::dataOffset()), out); + masm.loadPtr(Address(obj, TypedObject::dataOffset()), out); return true; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index d25dd5fbd1a..10c57368f43 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -9559,7 +9559,7 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj) return typedObj->toNewDerivedTypedObject()->type(); MInstruction *load = MLoadFixedSlot::New(typedObj, - JS_TYPEDOBJ_SLOT_TYPE_OBJ); + JS_DATUM_SLOT_TYPE_OBJ); current->add(load); return load; } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 88b9f333b3a..97434aaca18 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -897,7 +897,7 @@ InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type, HandleObject owner, int32_t offset) { - return BinaryBlock::createDerived(cx, type, owner, offset); + return TypedObject::createDerived(cx, type, owner, offset); } diff --git a/js/src/js.msg b/js/src/js.msg index c2ecfaa37f8..b8f5d191d5a 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -417,3 +417,6 @@ MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 363, 0, JSEXN_RANGEERR, "too many functio MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE, 364, 2, JSEXN_ERR, "{0} is not a debuggee {1}") MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 365, 0, JSEXN_ERR, "Expected a typed object") MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 366, 1, JSEXN_TYPEERR, "No such property: {0}") +MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 367, 2, JSEXN_TYPEERR, "argument {0} invalid: expected {1}") +MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 368, 0, JSEXN_TYPEERR, "handle unattached") +MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 369, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type") diff --git a/js/src/tests/ecma_6/TypedObject/handle.js b/js/src/tests/ecma_6/TypedObject/handle.js new file mode 100644 index 00000000000..8469609209f --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/handle.js @@ -0,0 +1,60 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 898342; +var summary = 'Handles'; + +var T = TypedObject; + +function runTests() { + var Point = new T.ArrayType(T.float32, 3); + var Line = new T.StructType({from: Point, to: Point}); + var Lines = new T.ArrayType(Line, 3); + + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + var handle = Lines.handle(lines); + var handle0 = Line.handle(lines, 0); + var handle2 = Line.handle(lines, 2); + + // Reads from handles should see the correct data: + assertEq(handle[0].from[0], 1); + assertEq(handle0.from[0], 1); + assertEq(handle2.from[0], 13); + + // Writes to handles should modify the original: + handle2.from[0] = 22; + assertEq(lines[2].from[0], 22); + + // Reads from handles should see the updated data: + assertEq(handle[0].from[0], 1); + assertEq(handle0.from[0], 1); + assertEq(handle2.from[0], 22); + + // isHandle, when called on nonsense, returns false: + assertEq(T.Handle.isHandle(22), false); + assertEq(T.Handle.isHandle({}), false); + + // Derived handles should remain handles: + assertEq(T.Handle.isHandle(lines), false); + assertEq(T.Handle.isHandle(lines[0]), false); + assertEq(T.Handle.isHandle(lines[0].from), false); + assertEq(T.Handle.isHandle(handle), true); + assertEq(T.Handle.isHandle(handle[0]), true); + assertEq(T.Handle.isHandle(handle[0].from), true); + + reportCompare(true, true); + print("Tests complete"); +} + +runTests(); + + diff --git a/js/src/tests/ecma_6/TypedObject/handle_get_set.js b/js/src/tests/ecma_6/TypedObject/handle_get_set.js new file mode 100644 index 00000000000..63d71f63c87 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/handle_get_set.js @@ -0,0 +1,60 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 898342; +var summary = 'Handle Move'; + +var T = TypedObject; + +var Point = new T.ArrayType(T.float32, 3); +var Line = new T.StructType({from: Point, to: Point}); +var Lines = new T.ArrayType(Line, 3); + +function runTests() { + function testHandleGetSetWithScalarType() { + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + var handle = T.float32.handle(lines, 0, "to", 1); + assertEq(T.Handle.get(handle), 5); + T.Handle.set(handle, 22); + assertEq(T.Handle.get(handle), 22); + assertEq(lines[0].to[1], 22); + } + testHandleGetSetWithScalarType(); + + function testHandleGetSetWithComplexType() { + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + var handle = Point.handle(lines, 0, "to"); + + T.Handle.set(handle, [22, 23, 24]); + + assertEq(handle[0], 22); + assertEq(handle[1], 23); + assertEq(handle[2], 24); + + assertEq(T.Handle.get(handle)[0], 22); + assertEq(T.Handle.get(handle)[1], 23); + assertEq(T.Handle.get(handle)[2], 24); + } + testHandleGetSetWithComplexType(); + + reportCompare(true, true); + print("Tests complete"); +} + +runTests(); + + diff --git a/js/src/tests/ecma_6/TypedObject/handle_move.js b/js/src/tests/ecma_6/TypedObject/handle_move.js new file mode 100644 index 00000000000..8722d061d75 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/handle_move.js @@ -0,0 +1,157 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 898342; +var summary = 'Handle Move'; + +var T = TypedObject; + +var Point = new T.ArrayType(T.float32, 3); +var Line = new T.StructType({from: Point, to: Point}); +var Lines = new T.ArrayType(Line, 3); + +function runTests() { + function testHandleToPoint() { + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + function allPoints(lines, func) { + var handle = Point.handle(); + for (var i = 0; i < lines.length; i++) { + T.Handle.move(handle, lines, i, "from"); + func(handle); + + T.Handle.move(handle, lines, i, "to"); + func(handle); + } + } + + // Iterate over all ponts and mutate them in place: + allPoints(lines, function(p) { + p[0] += 100; + p[1] += 200; + p[2] += 300; + }); + + // Spot check the results + assertEq(lines[0].from[0], 101); + assertEq(lines[1].to[1], 211); + assertEq(lines[2].to[2], 318); + } + testHandleToPoint(); + + function testHandleToFloat() { + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + function allPoints(lines, func) { + var handle = T.float32.handle(); + for (var i = 0; i < lines.length; i++) { + T.Handle.move(handle, lines, i, "from", 0); + func(handle); + + T.Handle.move(handle, lines, i, "from", 1); + func(handle); + + T.Handle.move(handle, lines, i, "from", 2); + func(handle); + + T.Handle.move(handle, lines, i, "to", 0); + func(handle); + + T.Handle.move(handle, lines, i, "to", 1); + func(handle); + + T.Handle.move(handle, lines, i, "to", 2); + func(handle); + } + } + + // Iterate over all ponts and mutate them in place: + allPoints(lines, function(p) { + T.Handle.set(p, T.Handle.get(p) + 100); + }); + + // Spot check the results + assertEq(lines[0].from[0], 101); + assertEq(lines[1].to[1], 111); + assertEq(lines[2].to[2], 118); + } + testHandleToFloat(); + + function testHandleToEquivalentType() { + var Point2 = new T.ArrayType(T.float32, 3); + + assertEq(Point.equivalent(Point2), true); + + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + var handle = Point2.handle(lines, 0, "to"); + assertEq(handle[0], 4); + assertEq(handle[1], 5); + assertEq(handle[2], 6); + } + testHandleToEquivalentType(); + + function testHandleMoveToIllegalType() { + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + // Moving a handle to a value of incorrect type should report an error: + assertThrowsInstanceOf(function() { + Line.handle(lines); + }, TypeError, "handle moved to destination of incorrect type"); + assertThrowsInstanceOf(function() { + var h = Line.handle(); + T.Handle.move(h, lines); + }, TypeError, "handle moved to destination of incorrect type"); + assertThrowsInstanceOf(function() { + var h = T.float32.handle(); + T.Handle.move(h, lines, 0); + }, TypeError, "handle moved to destination of incorrect type"); + } + testHandleMoveToIllegalType(); + + function testHandleMoveToIllegalProperty() { + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + assertThrowsInstanceOf(function() { + var h = Point.handle(); + T.Handle.move(h, lines, 0, "foo"); + }, TypeError, "No such property: foo"); + + assertThrowsInstanceOf(function() { + var h = Point.handle(); + T.Handle.move(h, lines, 22, "to"); + }, TypeError, "No such property: 22"); + } + testHandleMoveToIllegalProperty(); + + reportCompare(true, true); + print("Tests complete"); +} + +runTests(); + + diff --git a/js/src/tests/ecma_6/TypedObject/handle_unattached.js b/js/src/tests/ecma_6/TypedObject/handle_unattached.js new file mode 100644 index 00000000000..21bbab45f57 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/handle_unattached.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var BUGNUMBER = 898342; +var summary = 'Unattached handles'; + +var T = TypedObject; + +function runTests() { + var Line = new T.StructType({from: T.uint8, to: T.uint8}); + var Lines = new T.ArrayType(Line, 3); + + // Create unattached handle to array, struct: + var handle = Lines.handle(); + var handle0 = Line.handle(); + + // Accessing properties throws: + assertThrowsInstanceOf(function() handle[0], TypeError, + "Unattached handle did not yield error"); + assertThrowsInstanceOf(function() handle0.from, TypeError, + "Unattached handle did not yield error"); + + // Handle.get() throws: + assertThrowsInstanceOf(function() T.Handle.get(handle), TypeError, + "Unattached handle did not yield error"); + assertThrowsInstanceOf(function() T.Handle.get(handle0), TypeError, + "Unattached handle did not yield error"); + + // Handle.set() throws: + assertThrowsInstanceOf(function() T.Handle.set(handle, [{},{},{}]), TypeError, + "Unattached handle did not yield error"); + assertThrowsInstanceOf(function() T.Handle.set(handle0, {}), TypeError, + "Unattached handle did not yield error"); + + reportCompare(true, true); + print("Tests complete"); +} + +runTests(); + + diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 6aadafb3239..f4f3e03ba8b 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -74,6 +74,7 @@ macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \ macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \ macro(global, global, "global") \ + macro(Handle, Handle, "Handle") \ macro(has, has, "has") \ macro(hasOwn, hasOwn, "hasOwn") \ macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \ @@ -132,6 +133,7 @@ macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \ macro(proto, proto, "__proto__") \ macro(prototype, prototype, "prototype") \ + macro(Reify, Reify, "Reify") \ macro(return, return_, "return") \ macro(sensitivity, sensitivity, "sensitivity") \ macro(set, set, "set") \ diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 7e19741e6a8..2d77a8f86c1 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -628,6 +628,30 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0), // See builtin/TypedObject.h for descriptors of the typedobj functions. + JS_FN("NewTypedHandle", + js::NewTypedHandle, + 1, 0), + JS_FN("NewDerivedTypedDatum", + js::NewDerivedTypedDatum, + 3, 0), + JS_FNINFO("AttachHandle", + JSNativeThreadSafeWrapper, + &js::AttachHandleJitInfo, 5, 0), + JS_FNINFO("ObjectIsTypeObject", + JSNativeThreadSafeWrapper, + &js::ObjectIsTypeObjectJitInfo, 5, 0), + JS_FNINFO("ObjectIsTypeRepresentation", + JSNativeThreadSafeWrapper, + &js::ObjectIsTypeRepresentationJitInfo, 5, 0), + JS_FNINFO("ObjectIsTypedObject", + JSNativeThreadSafeWrapper, + &js::ObjectIsTypedObjectJitInfo, 5, 0), + JS_FNINFO("ObjectIsTypedHandle", + JSNativeThreadSafeWrapper, + &js::ObjectIsTypedHandleJitInfo, 5, 0), + JS_FN("NewHandle", + js::NewTypedHandle, + 1, 0), JS_FNINFO("ClampToUint8", JSNativeThreadSafeWrapper, &js::ClampToUint8JitInfo, 1, 0),