This commit is contained in:
John Daggett 2014-11-06 13:44:43 +09:00
Родитель 7e06312fa6 9a58cdc67e
Коммит 8400dfe655
53 изменённых файлов: 1078 добавлений и 248 удалений

Просмотреть файл

@ -505,7 +505,7 @@ CreatePrototypeObjectForComplexTypeInstance(JSContext *cx,
return result;
}
const Class ArrayTypeDescr::class_ = {
const Class UnsizedArrayTypeDescr::class_ = {
"ArrayType",
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub,
@ -518,7 +518,24 @@ const Class ArrayTypeDescr::class_ = {
nullptr,
nullptr,
nullptr,
TypedObject::construct,
OutlineTypedObject::constructUnsized,
nullptr
};
const Class SizedArrayTypeDescr::class_ = {
"ArrayType",
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
nullptr,
nullptr,
nullptr,
TypedObject::constructSized,
nullptr
};
@ -528,6 +545,7 @@ const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = {
const JSFunctionSpec ArrayMetaTypeDescr::typeObjectMethods[] = {
{"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
JS_FN("dimension", UnsizedArrayTypeDescr::dimension, 1, 0),
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
{"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
JS_SELF_HOSTED_FN("build", "TypedObjectArrayTypeBuild", 3, 0),
@ -559,9 +577,11 @@ bool
js::CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr descr)
{
// If data is transparent, also store the public slots.
if (descr->transparent()) {
if (descr->transparent() && descr->is<SizedTypeDescr>()) {
Rooted<SizedTypeDescr*> sizedDescr(cx, &descr->as<SizedTypeDescr>());
// byteLength
RootedValue typeByteLength(cx, Int32Value(descr->size()));
RootedValue typeByteLength(cx, Int32Value(sizedDescr->size()));
if (!JSObject::defineProperty(cx, descr, cx->names().byteLength,
typeByteLength,
nullptr, nullptr,
@ -571,7 +591,7 @@ js::CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr descr)
}
// byteAlignment
RootedValue typeByteAlignment(cx, Int32Value(descr->alignment()));
RootedValue typeByteAlignment(cx, Int32Value(sizedDescr->alignment()));
if (!JSObject::defineProperty(cx, descr, cx->names().byteAlignment,
typeByteAlignment,
nullptr, nullptr,
@ -599,29 +619,38 @@ js::CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr descr)
}
}
// variable -- true for unsized arrays
RootedValue variable(cx, BooleanValue(!descr->is<SizedTypeDescr>()));
if (!JSObject::defineProperty(cx, descr, cx->names().variable,
variable,
nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
{
return false;
}
return true;
}
ArrayTypeDescr *
template<class T>
T *
ArrayMetaTypeDescr::create(JSContext *cx,
HandleObject arrayTypePrototype,
HandleTypeDescr elementType,
HandleSizedTypeDescr elementType,
HandleAtom stringRepr,
int32_t size,
int32_t length)
int32_t size)
{
Rooted<ArrayTypeDescr*> obj(cx);
obj = NewObjectWithProto<ArrayTypeDescr>(cx, arrayTypePrototype, nullptr, SingletonObject);
Rooted<T*> obj(cx);
obj = NewObjectWithProto<T>(cx, arrayTypePrototype, nullptr, SingletonObject);
if (!obj)
return nullptr;
obj->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(ArrayTypeDescr::Kind));
obj->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(T::Kind));
obj->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
obj->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(elementType->alignment()));
obj->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(size));
obj->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(elementType->opaque()));
obj->initReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE, ObjectValue(*elementType));
obj->initReservedSlot(JS_DESCR_SLOT_ARRAY_LENGTH, Int32Value(length));
RootedValue elementTypeVal(cx, ObjectValue(*elementType));
if (!JSObject::defineProperty(cx, obj, cx->names().elementType,
@ -629,12 +658,6 @@ ArrayMetaTypeDescr::create(JSContext *cx,
JSPROP_READONLY | JSPROP_PERMANENT))
return nullptr;
RootedValue lengthValue(cx, NumberValue(length));
if (!JSObject::defineProperty(cx, obj, cx->names().length,
lengthValue, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
return nullptr;
if (!CreateUserSizeAndAlignmentProperties(cx, obj))
return nullptr;
@ -664,42 +687,25 @@ ArrayMetaTypeDescr::construct(JSContext *cx, unsigned argc, Value *vp)
RootedObject arrayTypeGlobal(cx, &args.callee());
// Expect two arguments. The first is a type object, the second is a length.
if (args.length() < 2) {
// Expect one argument which is a sized type object
if (args.length() < 1) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"ArrayType", "1", "");
"ArrayType", "0", "");
return false;
}
if (!args[0].isObject() || !args[0].toObject().is<TypeDescr>()) {
if (!args[0].isObject() || !args[0].toObject().is<SizedTypeDescr>()) {
ReportCannotConvertTo(cx, args[0], "ArrayType element specifier");
return false;
}
if (!args[1].isInt32() || args[1].toInt32() < 0) {
ReportCannotConvertTo(cx, args[1], "ArrayType length specifier");
return false;
}
Rooted<SizedTypeDescr*> elementType(cx);
elementType = &args[0].toObject().as<SizedTypeDescr>();
Rooted<TypeDescr*> elementType(cx, &args[0].toObject().as<TypeDescr>());
int32_t length = args[1].toInt32();
// Compute the byte size.
CheckedInt32 size = CheckedInt32(elementType->size()) * length;
if (!size.isValid()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return false;
}
// Construct a canonical string `new ArrayType(<elementType>, N)`:
// Construct a canonical string `new ArrayType(<elementType>)`:
StringBuffer contents(cx);
contents.append("new ArrayType(");
contents.append(&elementType->stringRepr());
contents.append(", ");
if (!NumberValueToStringBuffer(cx, NumberValue(length), contents))
return false;
contents.append(")");
RootedAtom stringRepr(cx, contents.finishAtom());
if (!stringRepr)
@ -711,11 +717,91 @@ ArrayMetaTypeDescr::construct(JSContext *cx, unsigned argc, Value *vp)
return false;
// Create the instance of ArrayType
Rooted<ArrayTypeDescr *> obj(cx);
obj = create(cx, arrayTypePrototype, elementType, stringRepr, size.value(), length);
Rooted<UnsizedArrayTypeDescr *> obj(cx);
obj = create<UnsizedArrayTypeDescr>(cx, arrayTypePrototype, elementType,
stringRepr, 0);
if (!obj)
return false;
// Add `length` property, which is undefined for an unsized array.
if (!JSObject::defineProperty(cx, obj, cx->names().length,
UndefinedHandleValue, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
return false;
args.rval().setObject(*obj);
return true;
}
/*static*/ bool
UnsizedArrayTypeDescr::dimension(JSContext *cx, unsigned int argc, jsval *vp)
{
// Expect that the `this` pointer is an unsized array type
// and the first argument is an integer size.
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1 ||
!args.thisv().isObject() ||
!args.thisv().toObject().is<UnsizedArrayTypeDescr>() ||
!args[0].isInt32() ||
args[0].toInt32() < 0)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
return false;
}
// Extract arguments.
Rooted<UnsizedArrayTypeDescr*> unsizedTypeDescr(cx);
unsizedTypeDescr = &args.thisv().toObject().as<UnsizedArrayTypeDescr>();
int32_t length = args[0].toInt32();
Rooted<SizedTypeDescr*> elementType(cx, &unsizedTypeDescr->elementType());
// Compute the size.
CheckedInt32 size = CheckedInt32(elementType->size()) * length;
if (!size.isValid()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return false;
}
// Construct a canonical string `new ArrayType(<elementType>).dimension(N)`:
StringBuffer contents(cx);
contents.append("new ArrayType(");
contents.append(&elementType->stringRepr());
contents.append(").dimension(");
if (!NumberValueToStringBuffer(cx, NumberValue(length), contents))
return false;
contents.append(")");
RootedAtom stringRepr(cx, contents.finishAtom());
if (!stringRepr)
return false;
// Create the sized type object.
Rooted<SizedArrayTypeDescr*> obj(cx);
obj = ArrayMetaTypeDescr::create<SizedArrayTypeDescr>(cx, unsizedTypeDescr,
elementType,
stringRepr, size.value());
if (!obj)
return false;
obj->initReservedSlot(JS_DESCR_SLOT_SIZED_ARRAY_LENGTH,
Int32Value(length));
// Add `length` property.
RootedValue lengthVal(cx, Int32Value(length));
if (!JSObject::defineProperty(cx, obj, cx->names().length,
lengthVal, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
return false;
// Add `unsized` property, which is a link from the sized
// array to the unsized array.
RootedValue unsizedTypeDescrValue(cx, ObjectValue(*unsizedTypeDescr));
if (!JSObject::defineProperty(cx, obj, cx->names().unsized,
unsizedTypeDescrValue, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
return false;
args.rval().setObject(*obj);
return true;
}
@ -726,7 +812,7 @@ js::IsTypedObjectArray(JSObject &obj)
if (!obj.is<TypedObject>())
return false;
TypeDescr& d = obj.as<TypedObject>().typeDescr();
return d.is<ArrayTypeDescr>();
return d.is<SizedArrayTypeDescr>() || d.is<UnsizedArrayTypeDescr>();
}
/*********************************
@ -746,7 +832,7 @@ const Class StructTypeDescr::class_ = {
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
TypedObject::construct,
TypedObject::constructSized,
nullptr /* trace */
};
@ -807,7 +893,7 @@ StructMetaTypeDescr::create(JSContext *cx,
RootedValue fieldTypeVal(cx);
RootedId id(cx);
Rooted<TypeDescr*> fieldType(cx);
Rooted<SizedTypeDescr*> fieldType(cx);
for (unsigned int i = 0; i < ids.length(); i++) {
id = ids[i];
@ -823,7 +909,7 @@ StructMetaTypeDescr::create(JSContext *cx,
// The value should be a type descriptor.
if (!JSObject::getGeneric(cx, fields, fields, id, &fieldTypeVal))
return nullptr;
fieldType = ToObjectIf<TypeDescr>(fieldTypeVal);
fieldType = ToObjectIf<SizedTypeDescr>(fieldTypeVal);
if (!fieldType) {
ReportCannotConvertTo(cx, fieldTypeVal, "StructType field specifier");
return nullptr;
@ -1082,22 +1168,22 @@ StructTypeDescr::maybeForwardedFieldOffset(size_t index) const
return AssertedCast<size_t>(fieldOffsets.getDenseElement(index).toInt32());
}
TypeDescr&
SizedTypeDescr&
StructTypeDescr::fieldDescr(size_t index) const
{
NativeObject &fieldDescrs = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
MOZ_ASSERT(index < fieldDescrs.getDenseInitializedLength());
return fieldDescrs.getDenseElement(index).toObject().as<TypeDescr>();
return fieldDescrs.getDenseElement(index).toObject().as<SizedTypeDescr>();
}
TypeDescr&
SizedTypeDescr&
StructTypeDescr::maybeForwardedFieldDescr(size_t index) const
{
NativeObject &fieldDescrs = maybeForwardedFieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
MOZ_ASSERT(index < fieldDescrs.getDenseInitializedLength());
JSObject &descr =
*MaybeForwarded(&fieldDescrs.getDenseElement(index).toObject());
return descr.as<TypeDescr>();
return descr.as<SizedTypeDescr>();
}
/******************************************************************************
@ -1382,7 +1468,9 @@ TypedObject::offset() const
int32_t
TypedObject::length() const
{
return typeDescr().as<ArrayTypeDescr>().length();
if (typeDescr().is<SizedArrayTypeDescr>())
return typeDescr().as<SizedArrayTypeDescr>().length();
return as<OutlineTypedObject>().unsizedLength();
}
uint8_t *
@ -1529,14 +1617,18 @@ OutlineTypedObject::createUnattachedWithClass(JSContext *cx,
if (!proto)
return nullptr;
gc::AllocKind allocKind = allocKindForTypeDescriptor(type);
NewObjectKind newKind = (heap == gc::TenuredHeap) ? MaybeSingletonObject : GenericObject;
JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, nullptr, gc::FINALIZE_OBJECT0, newKind);
JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, nullptr, allocKind, newKind);
if (!obj)
return nullptr;
OutlineTypedObject *typedObj = &obj->as<OutlineTypedObject>();
typedObj->setOwnerAndData(nullptr, nullptr);
if (type->kind() == type::UnsizedArray)
typedObj->setUnsizedLength(length);
return typedObj;
}
@ -1576,7 +1668,7 @@ OutlineTypedObject::attach(JSContext *cx, TypedObject &typedObj, int32_t offset)
}
// Returns a suitable JS_TYPEDOBJ_SLOT_LENGTH value for an instance of
// the type `type`.
// the type `type`. `type` must not be an unsized array.
static int32_t
TypedObjLengthFromType(TypeDescr &descr)
{
@ -1587,14 +1679,17 @@ TypedObjLengthFromType(TypeDescr &descr)
case type::Simd:
return 0;
case type::Array:
return descr.as<ArrayTypeDescr>().length();
case type::SizedArray:
return descr.as<SizedArrayTypeDescr>().length();
case type::UnsizedArray:
MOZ_CRASH("TypedObjLengthFromType() invoked on unsized type");
}
MOZ_CRASH("Invalid kind");
}
/*static*/ OutlineTypedObject *
OutlineTypedObject::createDerived(JSContext *cx, HandleTypeDescr type,
OutlineTypedObject::createDerived(JSContext *cx, HandleSizedTypeDescr type,
HandleTypedObject typedObj, int32_t offset)
{
MOZ_ASSERT(offset <= typedObj->size());
@ -1618,9 +1713,11 @@ OutlineTypedObject::createDerived(JSContext *cx, HandleTypeDescr type,
TypedObject::createZeroed(JSContext *cx, HandleTypeDescr descr, int32_t length, gc::InitialHeap heap)
{
// If possible, create an object with inline data.
if ((size_t) descr->size() <= InlineTypedObject::MaximumSize) {
if (descr->is<SizedTypeDescr>() &&
(size_t) descr->as<SizedTypeDescr>().size() <= InlineTypedObject::MaximumSize)
{
InlineTypedObject *obj = InlineTypedObject::create(cx, descr, heap);
descr->initInstances(cx->runtime(), obj->inlineTypedMem(), 1);
descr->as<SizedTypeDescr>().initInstances(cx->runtime(), obj->inlineTypedMem(), 1);
return obj;
}
@ -1630,14 +1727,49 @@ TypedObject::createZeroed(JSContext *cx, HandleTypeDescr descr, int32_t length,
return nullptr;
// Allocate and initialize the memory for this instance.
size_t totalSize = descr->size();
Rooted<ArrayBufferObject*> buffer(cx);
buffer = ArrayBufferObject::create(cx, totalSize);
if (!buffer)
return nullptr;
descr->initInstances(cx->runtime(), buffer->dataPointer(), 1);
obj->attach(cx, *buffer, 0);
return obj;
// Also initialize the JS_TYPEDOBJ_SLOT_LENGTH slot.
switch (descr->kind()) {
case type::Scalar:
case type::Reference:
case type::Struct:
case type::Simd:
case type::SizedArray:
{
size_t totalSize = descr->as<SizedTypeDescr>().size();
Rooted<ArrayBufferObject*> buffer(cx);
buffer = ArrayBufferObject::create(cx, totalSize);
if (!buffer)
return nullptr;
descr->as<SizedTypeDescr>().initInstances(cx->runtime(), buffer->dataPointer(), 1);
obj->attach(cx, *buffer, 0);
return obj;
}
case type::UnsizedArray:
{
Rooted<SizedTypeDescr*> elementTypeRepr(cx);
elementTypeRepr = &descr->as<UnsizedArrayTypeDescr>().elementType();
CheckedInt32 totalSize = CheckedInt32(elementTypeRepr->size()) * length;
if (!totalSize.isValid()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return nullptr;
}
Rooted<ArrayBufferObject*> buffer(cx);
buffer = ArrayBufferObject::create(cx, totalSize.value());
if (!buffer)
return nullptr;
if (length)
elementTypeRepr->initInstances(cx->runtime(), buffer->dataPointer(), length);
obj->attach(cx, *buffer, 0);
return obj;
}
}
MOZ_CRASH("Bad TypeRepresentation Kind");
}
static bool
@ -1691,7 +1823,22 @@ OutlineTypedObject::obj_trace(JSTracer *trc, JSObject *object)
if (!descr.opaque() || !typedObj.maybeForwardedIsAttached())
return;
descr.traceInstances(trc, mem, 1);
switch (descr.kind()) {
case type::Scalar:
case type::Reference:
case type::Struct:
case type::SizedArray:
case type::Simd:
descr.as<SizedTypeDescr>().traceInstances(trc, mem, 1);
break;
case type::UnsizedArray:
{
SizedTypeDescr &elemType = descr.as<UnsizedArrayTypeDescr>().maybeForwardedElementType();
elemType.traceInstances(trc, mem, typedObj.unsizedLength());
break;
}
}
}
bool
@ -1707,7 +1854,8 @@ TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
case type::Simd:
break;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
{
uint32_t index;
if (js_IdIsIndex(id, &index))
@ -1834,7 +1982,8 @@ TypedObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiv
case type::Simd:
break;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
if (JSID_IS_ATOM(id, cx->names().length)) {
if (!typedObj->isAttached()) {
JS_ReportErrorNumber(
@ -1856,7 +2005,7 @@ TypedObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiv
break;
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
return Reify(cx, fieldType, typedObj, offset, vp);
}
}
@ -1893,8 +2042,13 @@ TypedObject::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiv
case type::Struct:
break;
case type::Array:
return obj_getArrayElement(cx, typedObj, descr, index, vp);
case type::SizedArray:
return obj_getArrayElement<SizedArrayTypeDescr>(cx, typedObj, descr,
index, vp);
case type::UnsizedArray:
return obj_getArrayElement<UnsizedArrayTypeDescr>(cx, typedObj, descr,
index, vp);
}
RootedObject proto(cx, obj->getProto());
@ -1906,6 +2060,7 @@ TypedObject::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiv
return JSObject::getElement(cx, proto, receiver, index, vp);
}
template<class T>
/*static*/ bool
TypedObject::obj_getArrayElement(JSContext *cx,
Handle<TypedObject*> typedObj,
@ -1913,12 +2068,14 @@ TypedObject::obj_getArrayElement(JSContext *cx,
uint32_t index,
MutableHandleValue vp)
{
MOZ_ASSERT(typeDescr->is<T>());
if (index >= (size_t) typedObj->length()) {
vp.setUndefined();
return true;
}
Rooted<TypeDescr*> elementType(cx, &typeDescr->as<ArrayTypeDescr>().elementType());
Rooted<SizedTypeDescr*> elementType(cx, &typeDescr->as<T>().elementType());
size_t offset = elementType->size() * index;
return Reify(cx, elementType, typedObj, offset, vp);
}
@ -1942,7 +2099,8 @@ TypedObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
case type::Simd:
break;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
if (JSID_IS_ATOM(id, cx->names().length)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
@ -1958,7 +2116,7 @@ TypedObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
break;
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
return ConvertAndCopyTo(cx, fieldType, typedObj, offset, vp);
}
}
@ -1990,13 +2148,17 @@ TypedObject::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
case type::Struct:
break;
case type::Array:
return obj_setArrayElement(cx, typedObj, descr, index, vp);
case type::SizedArray:
return obj_setArrayElement<SizedArrayTypeDescr>(cx, typedObj, descr, index, vp);
case type::UnsizedArray:
return obj_setArrayElement<UnsizedArrayTypeDescr>(cx, typedObj, descr, index, vp);
}
return ReportTypedObjTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, typedObj);
}
template<class T>
/*static*/ bool
TypedObject::obj_setArrayElement(JSContext *cx,
Handle<TypedObject*> typedObj,
@ -2004,14 +2166,16 @@ TypedObject::obj_setArrayElement(JSContext *cx,
uint32_t index,
MutableHandleValue vp)
{
MOZ_ASSERT(descr->is<T>());
if (index >= (size_t) typedObj->length()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX);
return false;
}
Rooted<TypeDescr*> elementType(cx);
elementType = &descr->as<ArrayTypeDescr>().elementType();
Rooted<SizedTypeDescr*> elementType(cx);
elementType = &descr->as<T>().elementType();
size_t offset = elementType->size() * index;
return ConvertAndCopyTo(cx, elementType, typedObj, offset, vp);
}
@ -2030,7 +2194,8 @@ TypedObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
case type::Simd:
break;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
if (js_IdIsIndex(id, &index)) {
*attrsp = JSPROP_ENUMERATE | JSPROP_PERMANENT;
return true;
@ -2070,7 +2235,8 @@ IsOwnId(JSContext *cx, HandleObject obj, HandleId id)
case type::Simd:
return false;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
return js_IdIsIndex(id, &index) || JSID_IS_ATOM(id, cx->names().length);
case type::Struct:
@ -2139,7 +2305,8 @@ TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
}
break;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
switch (enum_op) {
case JSENUMERATE_INIT_ALL:
case JSENUMERATE_INIT:
@ -2199,6 +2366,8 @@ TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
void
OutlineTypedObject::neuter(void *newData)
{
if (typeDescr().kind() == type::UnsizedArray)
setUnsizedLength(0);
setData(reinterpret_cast<uint8_t *>(newData));
}
@ -2249,7 +2418,7 @@ InlineTypedObject::obj_trace(JSTracer *trc, JSObject *object)
// may not have had their slots updated yet.
TypeDescr &descr = typedObj.maybeForwardedTypeDescr();
descr.traceInstances(trc, typedObj.inlineTypedMem(), 1);
descr.as<SizedTypeDescr>().traceInstances(trc, typedObj.inlineTypedMem(), 1);
}
ArrayBufferObject *
@ -2268,7 +2437,7 @@ InlineTransparentTypedObject::getOrCreateBuffer(JSContext *cx)
ArrayBufferObject::BufferContents contents =
ArrayBufferObject::BufferContents::createPlain(inlineTypedMem());
size_t nbytes = typeDescr().size();
size_t nbytes = typeDescr().as<SizedTypeDescr>().size();
// Prevent GC under ArrayBufferObject::create, which might move this object
// and its contents.
@ -2425,8 +2594,11 @@ LengthForType(TypeDescr &descr)
case type::Simd:
return 0;
case type::Array:
return descr.as<ArrayTypeDescr>().length();
case type::SizedArray:
return descr.as<SizedArrayTypeDescr>().length();
case type::UnsizedArray:
return 0;
}
MOZ_CRASH("Invalid kind");
@ -2461,15 +2633,15 @@ CheckOffset(int32_t offset,
}
/*static*/ bool
TypedObject::construct(JSContext *cx, unsigned int argc, Value *vp)
TypedObject::constructSized(JSContext *cx, unsigned int argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.callee().is<TypeDescr>());
Rooted<TypeDescr*> callee(cx, &args.callee().as<TypeDescr>());
MOZ_ASSERT(args.callee().is<SizedTypeDescr>());
Rooted<SizedTypeDescr*> callee(cx, &args.callee().as<SizedTypeDescr>());
// Typed object constructors are overloaded in three ways, in order of
// precedence:
// Typed object constructors for sized types are overloaded in
// three ways, in order of precedence:
//
// new TypeObj()
// new TypeObj(buffer, [offset])
@ -2554,6 +2726,162 @@ TypedObject::construct(JSContext *cx, unsigned int argc, Value *vp)
return false;
}
/*static*/ bool
TypedObject::constructUnsized(JSContext *cx, unsigned int argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.callee().is<TypeDescr>());
Rooted<UnsizedArrayTypeDescr*> callee(cx);
callee = &args.callee().as<UnsizedArrayTypeDescr>();
// Typed object constructors for unsized arrays are overloaded in
// four ways, in order of precedence:
//
// new TypeObj(buffer, [offset, [length]]) // [1]
// new TypeObj(length) // [1]
// new TypeObj(data)
// new TypeObj()
//
// [1] Explicit lengths only available for unsized arrays.
// Zero argument constructor:
if (args.length() == 0) {
Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, 0));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
// Length constructor.
if (args[0].isInt32()) {
int32_t length = args[0].toInt32();
if (length < 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
// Buffer constructor.
if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
Rooted<ArrayBufferObject*> buffer(cx);
buffer = &args[0].toObject().as<ArrayBufferObject>();
if (callee->opaque()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
int32_t offset;
if (args.length() >= 2 && !args[1].isUndefined()) {
if (!args[1].isInt32()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
offset = args[1].toInt32();
} else {
offset = 0;
}
if (!CheckOffset(offset, 0, callee->alignment(), buffer->byteLength())) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
int32_t elemSize = callee->elementType().size();
int32_t bytesRemaining = buffer->byteLength() - offset;
int32_t maximumLength = bytesRemaining / elemSize;
int32_t length;
if (args.length() >= 3 && !args[2].isUndefined()) {
if (!args[2].isInt32()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
length = args[2].toInt32();
if (length < 0 || length > maximumLength) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
} else {
if ((bytesRemaining % elemSize) != 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
length = maximumLength;
}
if (buffer->isNeutered()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
Rooted<OutlineTypedObject*> obj(cx);
obj = OutlineTypedObject::createUnattached(cx, callee, length);
if (!obj)
return false;
obj->attach(cx, args[0].toObject().as<ArrayBufferObject>(), offset);
}
// Data constructor for unsized values
if (args[0].isObject()) {
// Read length out of the object.
RootedObject arg(cx, &args[0].toObject());
RootedValue lengthVal(cx);
if (!JSObject::getProperty(cx, arg, arg, cx->names().length, &lengthVal))
return false;
if (!lengthVal.isInt32()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
int32_t length = lengthVal.toInt32();
// Check that length * elementSize does not overflow.
int32_t elementSize = callee->elementType().size();
int32_t byteLength;
if (!SafeMul(elementSize, length, &byteLength)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
// Create the unsized array.
Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
if (!obj)
return false;
// Initialize from `arg`
if (!ConvertAndCopyTo(cx, obj, args[0]))
return false;
args.rval().setObject(*obj);
return true;
}
// Something bogus.
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
/******************************************************************************
* Intrinsics
*/
@ -2563,9 +2891,9 @@ js::NewOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypeDescr>());
MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<SizedTypeDescr>());
Rooted<TypeDescr*> descr(cx, &args[0].toObject().as<TypeDescr>());
Rooted<SizedTypeDescr*> descr(cx, &args[0].toObject().as<SizedTypeDescr>());
int32_t length = TypedObjLengthFromType(*descr);
Rooted<OutlineTypedObject*> obj(cx);
obj = OutlineTypedObject::createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr, length);
@ -2580,11 +2908,11 @@ js::NewDerivedTypedObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3);
MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypeDescr>());
MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<SizedTypeDescr>());
MOZ_ASSERT(args[1].isObject() && args[1].toObject().is<TypedObject>());
MOZ_ASSERT(args[2].isInt32());
Rooted<TypeDescr*> descr(cx, &args[0].toObject().as<TypeDescr>());
Rooted<SizedTypeDescr*> descr(cx, &args[0].toObject().as<SizedTypeDescr>());
Rooted<TypedObject*> typedObj(cx, &args[1].toObject().as<TypedObject>());
int32_t offset = args[2].toInt32();
@ -2729,7 +3057,8 @@ js::TypeDescrIsArrayType(ThreadSafeContext *, unsigned argc, Value *vp)
MOZ_ASSERT(args[0].isObject());
MOZ_ASSERT(args[0].toObject().is<js::TypeDescr>());
JSObject& obj = args[0].toObject();
args.rval().setBoolean(obj.is<js::ArrayTypeDescr>());
args.rval().setBoolean(obj.is<js::SizedArrayTypeDescr>() ||
obj.is<js::UnsizedArrayTypeDescr>());
return true;
}
@ -2737,6 +3066,36 @@ JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::TypeDescrIsArrayTypeJitInfo,
TypeDescrIsArrayTypeJitInfo,
js::TypeDescrIsArrayType);
bool
js::TypeDescrIsSizedArrayType(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
MOZ_ASSERT(args[0].toObject().is<js::TypeDescr>());
args.rval().setBoolean(args[0].toObject().is<js::SizedArrayTypeDescr>());
return true;
}
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::TypeDescrIsSizedArrayTypeJitInfo,
TypeDescrIsSizedArrayTypeJitInfo,
js::TypeDescrIsSizedArrayType);
bool
js::TypeDescrIsUnsizedArrayType(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
MOZ_ASSERT(args[0].toObject().is<js::TypeDescr>());
args.rval().setBoolean(args[0].toObject().is<js::UnsizedArrayTypeDescr>());
return true;
}
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::TypeDescrIsUnsizedArrayTypeJitInfo,
TypeDescrIsUnsizedArrayTypeJitInfo,
js::TypeDescrIsUnsizedArrayType);
bool
js::TypedObjectIsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp)
{
@ -2952,7 +3311,7 @@ JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_IMPL)
template<typename V>
static void
visitReferences(TypeDescr &descr,
visitReferences(SizedTypeDescr &descr,
uint8_t *mem,
V& visitor)
{
@ -2968,10 +3327,10 @@ visitReferences(TypeDescr &descr,
visitor.visitReference(descr.as<ReferenceTypeDescr>(), mem);
return;
case type::Array:
case type::SizedArray:
{
ArrayTypeDescr &arrayDescr = descr.as<ArrayTypeDescr>();
TypeDescr &elementDescr = arrayDescr.maybeForwardedElementType();
SizedArrayTypeDescr &arrayDescr = descr.as<SizedArrayTypeDescr>();
SizedTypeDescr &elementDescr = arrayDescr.maybeForwardedElementType();
for (int32_t i = 0; i < arrayDescr.length(); i++) {
visitReferences(elementDescr, mem, visitor);
mem += elementDescr.size();
@ -2979,11 +3338,16 @@ visitReferences(TypeDescr &descr,
return;
}
case type::UnsizedArray:
{
MOZ_CRASH("Only Sized Type representations");
}
case type::Struct:
{
StructTypeDescr &structDescr = descr.as<StructTypeDescr>();
for (size_t i = 0; i < structDescr.maybeForwardedFieldCount(); i++) {
TypeDescr &descr = structDescr.maybeForwardedFieldDescr(i);
SizedTypeDescr &descr = structDescr.maybeForwardedFieldDescr(i);
size_t offset = structDescr.maybeForwardedFieldOffset(i);
visitReferences(descr, mem + offset, visitor);
}
@ -3042,7 +3406,7 @@ js::MemoryInitVisitor::visitReference(ReferenceTypeDescr &descr, uint8_t *mem)
}
void
TypeDescr::initInstances(const JSRuntime *rt, uint8_t *mem, size_t length)
SizedTypeDescr::initInstances(const JSRuntime *rt, uint8_t *mem, size_t length)
{
MOZ_ASSERT(length >= 1);
@ -3112,7 +3476,7 @@ js::MemoryTracingVisitor::visitReference(ReferenceTypeDescr &descr, uint8_t *mem
}
void
TypeDescr::traceInstances(JSTracer *trace, uint8_t *mem, size_t length)
SizedTypeDescr::traceInstances(JSTracer *trace, uint8_t *mem, size_t length)
{
MemoryTracingVisitor visitor(trace);

Просмотреть файл

@ -119,19 +119,25 @@ enum Kind {
Reference = JS_TYPEREPR_REFERENCE_KIND,
Simd = JS_TYPEREPR_SIMD_KIND,
Struct = JS_TYPEREPR_STRUCT_KIND,
Array = JS_TYPEREPR_ARRAY_KIND
SizedArray = JS_TYPEREPR_SIZED_ARRAY_KIND,
UnsizedArray = JS_TYPEREPR_UNSIZED_ARRAY_KIND,
};
static inline bool isSized(type::Kind kind) {
return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
}
}
///////////////////////////////////////////////////////////////////////////
// Typed Prototypes
class SizedTypeDescr;
class SimpleTypeDescr;
class ComplexTypeDescr;
class SimdTypeDescr;
class StructTypeDescr;
class TypedProto;
class SizedTypedProto;
/*
* The prototype for a typed object. Currently, carries a link to the
@ -168,6 +174,10 @@ class TypeDescr : public NativeObject
static const Class class_;
public:
static bool isSized(type::Kind kind) {
return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
}
TypedProto &typedProto() const {
return getReservedSlot(JS_DESCR_SLOT_TYPROTO).toObject().as<TypedProto>();
}
@ -191,7 +201,13 @@ class TypeDescr : public NativeObject
int32_t alignment() const {
return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
}
};
typedef Handle<TypeDescr*> HandleTypeDescr;
class SizedTypeDescr : public TypeDescr
{
public:
int32_t size() const {
return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
}
@ -200,9 +216,9 @@ class TypeDescr : public NativeObject
void traceInstances(JSTracer *trace, uint8_t *mem, size_t length);
};
typedef Handle<TypeDescr*> HandleTypeDescr;
typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
class SimpleTypeDescr : public TypeDescr
class SimpleTypeDescr : public SizedTypeDescr
{
};
@ -312,7 +328,7 @@ class ReferenceTypeDescr : public SimpleTypeDescr
// Type descriptors whose instances are objects and hence which have
// an associated `prototype` property.
class ComplexTypeDescr : public TypeDescr
class ComplexTypeDescr : public SizedTypeDescr
{
public:
// Returns the prototype that instances of this type descriptor
@ -356,8 +372,6 @@ bool IsTypedObjectArray(JSObject& obj);
bool CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr obj);
class ArrayTypeDescr;
/*
* Properties and methods of the `ArrayType` meta type object. There
* is no `class_` field because `ArrayType` is just a native
@ -366,18 +380,25 @@ class ArrayTypeDescr;
class ArrayMetaTypeDescr : public JSObject
{
private:
// Helper for creating a new ArrayType object.
friend class UnsizedArrayTypeDescr;
// Helper for creating a new ArrayType object, either sized or unsized.
// The template parameter `T` should be either `UnsizedArrayTypeDescr`
// or `SizedArrayTypeDescr`.
//
// - `arrayTypePrototype` - prototype for the new object to be created
// - `arrayTypePrototype` - prototype for the new object to be created,
// either ArrayType.prototype or
// unsizedArrayType.__proto__ depending on
// whether this is a sized or unsized array
// - `elementType` - type object for the elements in the array
// - `stringRepr` - canonical string representation for the array
// - `size` - length of the array
static ArrayTypeDescr *create(JSContext *cx,
HandleObject arrayTypePrototype,
HandleTypeDescr elementType,
HandleAtom stringRepr,
int32_t size,
int32_t length);
// - `size` - length of the array (0 if unsized)
template<class T>
static T *create(JSContext *cx,
HandleObject arrayTypePrototype,
HandleSizedTypeDescr elementType,
HandleAtom stringRepr,
int32_t size);
public:
// Properties and methods to be installed on ArrayType.prototype,
@ -396,25 +417,54 @@ class ArrayMetaTypeDescr : public JSObject
};
/*
* Type descriptor created by `new ArrayType(type, n)`
* Type descriptor created by `new ArrayType(typeObj)`
*
* These have a prototype, and hence *could* be a subclass of
* `ComplexTypeDescr`, but it would require some reshuffling of the
* hierarchy, and it's not worth the trouble since they will be going
* away as part of bug 973238.
*/
class ArrayTypeDescr : public ComplexTypeDescr
class UnsizedArrayTypeDescr : public TypeDescr
{
public:
static const Class class_;
static const type::Kind Kind = type::Array;
static const type::Kind Kind = type::UnsizedArray;
TypeDescr &elementType() const {
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<TypeDescr>();
// This is the sized method on unsized array type objects. It
// produces a sized variant.
static bool dimension(JSContext *cx, unsigned int argc, jsval *vp);
SizedTypeDescr &elementType() const {
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
}
TypeDescr &maybeForwardedElementType() const {
SizedTypeDescr &maybeForwardedElementType() const {
JSObject *elemType =
MaybeForwarded(&getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject());
return elemType->as<SizedTypeDescr>();
}
};
/*
* Type descriptor created by `unsizedArrayTypeObj.dimension()`
*/
class SizedArrayTypeDescr : public ComplexTypeDescr
{
public:
static const Class class_;
static const type::Kind Kind = type::SizedArray;
SizedTypeDescr &elementType() const {
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
}
SizedTypeDescr &maybeForwardedElementType() const {
JSObject *elemType = &getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject();
return MaybeForwarded(elemType)->as<TypeDescr>();
return MaybeForwarded(elemType)->as<SizedTypeDescr>();
}
int32_t length() const {
return getReservedSlot(JS_DESCR_SLOT_ARRAY_LENGTH).toInt32();
return getReservedSlot(JS_DESCR_SLOT_SIZED_ARRAY_LENGTH).toInt32();
}
};
@ -462,8 +512,8 @@ class StructTypeDescr : public ComplexTypeDescr
JSAtom &fieldName(size_t index) const;
// Return the type descr of the field at index `index`.
TypeDescr &fieldDescr(size_t index) const;
TypeDescr &maybeForwardedFieldDescr(size_t index) const;
SizedTypeDescr &fieldDescr(size_t index) const;
SizedTypeDescr &maybeForwardedFieldDescr(size_t index) const;
// Return the offset of the field at index `index`.
size_t fieldOffset(size_t index) const;
@ -503,12 +553,14 @@ class TypedObject : public JSObject
private:
static const bool IsTypedObjectClass = true;
template<class T>
static bool obj_getArrayElement(JSContext *cx,
Handle<TypedObject*> typedObj,
Handle<TypeDescr*> typeDescr,
uint32_t index,
MutableHandleValue vp);
template<class T>
static bool obj_setArrayElement(JSContext *cx,
Handle<TypedObject*> typedObj,
Handle<TypeDescr*> typeDescr,
@ -548,6 +600,9 @@ class TypedObject : public JSObject
static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp);
static bool obj_getUnsizedArrayElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp);
static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, bool strict);
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
@ -590,7 +645,20 @@ class TypedObject : public JSObject
bool maybeForwardedIsAttached() const;
int32_t size() const {
return typeDescr().size();
switch (typeDescr().kind()) {
case type::Scalar:
case type::Simd:
case type::Reference:
case type::Struct:
case type::SizedArray:
return typeDescr().as<SizedTypeDescr>().size();
case type::UnsizedArray: {
SizedTypeDescr &elementType = typeDescr().as<UnsizedArrayTypeDescr>().elementType();
return elementType.size() * length();
}
}
MOZ_CRASH("unhandled typerepresentation kind");
}
uint8_t *typedMem(size_t offset) const {
@ -611,9 +679,12 @@ class TypedObject : public JSObject
static TypedObject *createZeroed(JSContext *cx, HandleTypeDescr typeObj, int32_t length,
gc::InitialHeap heap = gc::DefaultHeap);
// User-accessible constructor (`new TypeDescriptor(...)`). Note that the
// callee here is the type descriptor.
static bool construct(JSContext *cx, unsigned argc, Value *vp);
// User-accessible constructor (`new TypeDescriptor(...)`) used for sized
// types. Note that the callee here is the type descriptor.
static bool constructSized(JSContext *cx, unsigned argc, Value *vp);
// As `constructSized`, but for unsized array types.
static bool constructUnsized(JSContext *cx, unsigned argc, Value *vp);
/* Accessors for self hosted code. */
static bool GetBuffer(JSContext *cx, unsigned argc, Value *vp);
@ -632,12 +703,30 @@ class OutlineTypedObject : public TypedObject
// Data pointer to some offset in the owner's contents.
uint8_t *data_;
// The length for unsized array objects. For other outline objects the
// space for this field is not allocated and cannot be accessed.
uint32_t unsizedLength_;
void setOwnerAndData(JSObject *owner, uint8_t *data);
void setUnsizedLength(uint32_t length) {
MOZ_ASSERT(typeDescr().is<UnsizedArrayTypeDescr>());
unsizedLength_ = length;
}
public:
static gc::AllocKind allocKindForTypeDescriptor(TypeDescr *descr) {
// Use a larger allocation kind for unsized arrays, to accommodate the
// unsized length.
if (descr->is<UnsizedArrayTypeDescr>())
return gc::FINALIZE_OBJECT2;
return gc::FINALIZE_OBJECT0;
}
// JIT accessors.
static size_t offsetOfData() { return offsetof(OutlineTypedObject, data_); }
static size_t offsetOfOwner() { return offsetof(OutlineTypedObject, owner_); }
static size_t offsetOfUnsizedLength() { return offsetof(OutlineTypedObject, unsizedLength_); }
JSObject &owner() const {
MOZ_ASSERT(owner_);
@ -652,6 +741,11 @@ class OutlineTypedObject : public TypedObject
return data_;
}
int32_t unsizedLength() const {
MOZ_ASSERT(typeDescr().is<UnsizedArrayTypeDescr>());
return unsizedLength_;
}
void setData(uint8_t *data) {
data_ = data;
}
@ -678,7 +772,7 @@ class OutlineTypedObject : public TypedObject
// at the given offset. The typedObj will be a handle iff type is a
// handle and a typed object otherwise.
static OutlineTypedObject *createDerived(JSContext *cx,
HandleTypeDescr type,
HandleSizedTypeDescr type,
Handle<TypedObject*> typedContents,
int32_t offset);
@ -722,7 +816,7 @@ class InlineTypedObject : public TypedObject
sizeof(NativeObject) - sizeof(TypedObject) + NativeObject::MAX_FIXED_SLOTS * sizeof(Value);
static gc::AllocKind allocKindForTypeDescriptor(TypeDescr *descr) {
size_t nbytes = descr->size();
size_t nbytes = descr->as<SizedTypeDescr>().size();
MOZ_ASSERT(nbytes <= MaximumSize);
size_t dataSlots = AlignBytes(nbytes, sizeof(Value) / sizeof(Value));
@ -838,6 +932,12 @@ extern const JSJitInfo TypeDescrIsSimpleTypeJitInfo;
bool TypeDescrIsArrayType(ThreadSafeContext *, unsigned argc, Value *vp);
extern const JSJitInfo TypeDescrIsArrayTypeJitInfo;
bool TypeDescrIsSizedArrayType(ThreadSafeContext *, unsigned argc, Value *vp);
extern const JSJitInfo TypeDescrIsSizedArrayTypeJitInfo;
bool TypeDescrIsUnsizedArrayType(ThreadSafeContext *, unsigned argc, Value *vp);
extern const JSJitInfo TypeDescrIsUnsizedArrayTypeJitInfo;
/*
* Usage: TypedObjectIsAttached(obj)
*
@ -1001,15 +1101,22 @@ inline bool
IsComplexTypeDescrClass(const Class* clasp)
{
return clasp == &StructTypeDescr::class_ ||
clasp == &ArrayTypeDescr::class_ ||
clasp == &SizedArrayTypeDescr::class_ ||
clasp == &SimdTypeDescr::class_;
}
inline bool
IsSizedTypeDescrClass(const Class* clasp)
{
return IsSimpleTypeDescrClass(clasp) ||
IsComplexTypeDescrClass(clasp);
}
inline bool
IsTypeDescrClass(const Class* clasp)
{
return IsSimpleTypeDescrClass(clasp) ||
IsComplexTypeDescrClass(clasp);
return IsSizedTypeDescrClass(clasp) ||
clasp == &UnsizedArrayTypeDescr::class_;
}
inline bool
@ -1054,6 +1161,13 @@ JSObject::is<js::SimpleTypeDescr>() const
return IsSimpleTypeDescrClass(getClass());
}
template <>
inline bool
JSObject::is<js::SizedTypeDescr>() const
{
return IsSizedTypeDescrClass(getClass());
}
template <>
inline bool
JSObject::is<js::ComplexTypeDescr>() const

Просмотреть файл

@ -19,8 +19,8 @@
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE)
#define DESCR_ARRAY_ELEMENT_TYPE(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_ARRAY_ELEM_TYPE)
#define DESCR_ARRAY_LENGTH(obj) \
TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_ARRAY_LENGTH))
#define DESCR_SIZED_ARRAY_LENGTH(obj) \
TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZED_ARRAY_LENGTH))
#define DESCR_STRUCT_FIELD_NAMES(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_NAMES)
#define DESCR_STRUCT_FIELD_TYPES(obj) \
@ -70,9 +70,12 @@ function TypedObjectGet(descr, typedObj, offset) {
case JS_TYPEREPR_SIMD_KIND:
return TypedObjectGetSimd(descr, typedObj, offset);
case JS_TYPEREPR_ARRAY_KIND:
case JS_TYPEREPR_SIZED_ARRAY_KIND:
case JS_TYPEREPR_STRUCT_KIND:
return TypedObjectGetDerived(descr, typedObj, offset);
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
assert(false, "Unhandled repr kind: " + DESCR_KIND(descr));
}
assert(false, "Unhandled kind: " + DESCR_KIND(descr));
@ -198,8 +201,14 @@ function TypedObjectSet(descr, typedObj, offset, fromValue) {
TypedObjectSetSimd(descr, typedObj, offset, fromValue);
return;
case JS_TYPEREPR_ARRAY_KIND:
var length = DESCR_ARRAY_LENGTH(descr);
case JS_TYPEREPR_SIZED_ARRAY_KIND:
var length = DESCR_SIZED_ARRAY_LENGTH(descr);
if (TypedObjectSetArray(descr, length, typedObj, offset, fromValue))
return;
break;
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
var length = typedObj.length;
if (TypedObjectSetArray(descr, length, typedObj, offset, fromValue))
return;
break;
@ -418,13 +427,22 @@ function TypedArrayRedimension(newArrayType) {
// Peel away the outermost array layers from the type of `this` to find
// the core element type. In the process, count the number of elements.
var oldArrayType = TypedObjectTypeDescr(this);
var oldArrayReprKind = DESCR_KIND(oldArrayType);
var oldElementType = oldArrayType;
var oldElementCount = 1;
switch (oldArrayReprKind) {
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
oldElementCount *= this.length;
oldElementType = oldElementType.elementType;
break;
if (DESCR_KIND(oldArrayType) != JS_TYPEREPR_ARRAY_KIND)
case JS_TYPEREPR_SIZED_ARRAY_KIND:
break;
default:
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
while (DESCR_KIND(oldElementType) === JS_TYPEREPR_ARRAY_KIND) {
}
while (DESCR_KIND(oldElementType) === JS_TYPEREPR_SIZED_ARRAY_KIND) {
oldElementCount *= oldElementType.length;
oldElementType = oldElementType.elementType;
}
@ -433,7 +451,7 @@ function TypedArrayRedimension(newArrayType) {
// process, count the number of elements.
var newElementType = newArrayType;
var newElementCount = 1;
while (DESCR_KIND(newElementType) == JS_TYPEREPR_ARRAY_KIND) {
while (DESCR_KIND(newElementType) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
newElementCount *= newElementType.length;
newElementType = newElementType.elementType;
}
@ -518,11 +536,11 @@ function ArrayShorthand(...dims) {
var T = GetTypedObjectModule();
if (dims.length == 0)
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return new T.ArrayType(this);
var accum = this;
for (var i = dims.length - 1; i >= 0; i--)
accum = new T.ArrayType(accum, dims[i]);
accum = new T.ArrayType(accum).dimension(dims[i]);
return accum;
}
@ -542,7 +560,11 @@ function StorageOfTypedObject(obj) {
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
var descr = TypedObjectTypeDescr(obj);
var byteLength = DESCR_SIZE(descr);
var byteLength;
if (DESCR_KIND(descr) == JS_TYPEREPR_UNSIZED_ARRAY_KIND)
byteLength = DESCR_SIZE(descr.elementType) * obj.length;
else
byteLength = DESCR_SIZE(descr);
return { buffer: TypedObjectBuffer(obj),
byteLength: byteLength,
@ -583,13 +605,14 @@ function TypeOfTypedObject(obj) {
// Warning: user exposed!
function TypedObjectArrayTypeBuild(a,b,c) {
// Arguments : [depth], func
// Arguments (this sized) : [depth], func
// Arguments (this unsized) : length, [depth], func
if (!IsObject(this) || !ObjectIsTypeDescr(this))
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var kind = DESCR_KIND(this);
switch (kind) {
case JS_TYPEREPR_ARRAY_KIND:
case JS_TYPEREPR_SIZED_ARRAY_KIND:
if (typeof a === "function") // XXX here and elsewhere: these type dispatches are fragile at best.
return BuildTypedSeqImpl(this, this.length, 1, a);
else if (typeof a === "number" && typeof b === "function")
@ -598,6 +621,16 @@ function TypedObjectArrayTypeBuild(a,b,c) {
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
else
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
var len = a;
if (typeof b === "function")
return BuildTypedSeqImpl(this, len, 1, b);
else if (typeof b === "number" && typeof c === "function")
return BuildTypedSeqImpl(this, len, b, c);
else if (typeof b === "number")
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
else
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
default:
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
@ -698,7 +731,7 @@ function TypedArrayScatter(a, b, c, d) {
if (!TypeDescrIsArrayType(thisType))
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (!IsObject(a) || !ObjectIsTypeDescr(a) || !TypeDescrIsArrayType(a))
if (!IsObject(a) || !ObjectIsTypeDescr(a) || !TypeDescrIsSizedArrayType(a))
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (d !== undefined && typeof d !== "function")
@ -795,7 +828,7 @@ function BuildTypedSeqImpl(arrayType, len, depth, func) {
ComputeIterationSpace(arrayType, depth, len);
// Create a zeroed instance with no data
var result = new arrayType();
var result = arrayType.variable ? new arrayType(len) : new arrayType();
var indices = NewDenseArray(depth);
for (var i = 0; i < depth; i++) {
@ -888,11 +921,11 @@ function MapUntypedSeqImpl(inArray, outputType, maybeFunc) {
// Skip check for compatible iteration spaces; any normal JS array
// is trivially compatible with any iteration space of depth 1.
var outLength = outputType.length;
var outLength = outputType.variable ? inArray.length : outputType.length;
var outGrainType = outputType.elementType;
// Create a zeroed instance with no data
var result = new outputType();
var result = outputType.variable ? new outputType(inArray.length) : new outputType();
var outUnitSize = DESCR_SIZE(outGrainType);
var outGrainTypeIsComplex = !TypeDescrIsSimpleType(outGrainType);
@ -942,14 +975,14 @@ function MapTypedSeqImpl(inArray, depth, outputType, func) {
if (!IsObject(inGrainType) || !ObjectIsTypeDescr(inGrainType))
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var [iterationSpace, outGrainType, totalLength] =
ComputeIterationSpace(outputType, depth, outputType.length);
ComputeIterationSpace(outputType, depth, outputType.variable ? inArray.length : outputType.length);
for (var i = 0; i < depth; i++)
if (inIterationSpace[i] !== iterationSpace[i])
// TypeError("Incompatible iteration space in input and output type");
ThrowError(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
// Create a zeroed instance with no data
var result = new outputType();
var result = outputType.variable ? new outputType(inArray.length) : new outputType();
var inGrainTypeIsComplex = !TypeDescrIsSimpleType(inGrainType);
var outGrainTypeIsComplex = !TypeDescrIsSimpleType(outGrainType);
@ -1050,7 +1083,7 @@ function MapTypedParImpl(inArray, depth, outputType, func) {
depth <= 0 ||
TO_INT32(depth) !== depth ||
!TypeDescrIsArrayType(inArrayType) ||
!TypeDescrIsArrayType(outputType))
!TypeDescrIsUnsizedArrayType(outputType))
{
// defer error cases to seq implementation:
return MapTypedSeqImpl(inArray, depth, outputType, func);
@ -1128,7 +1161,7 @@ function MapTypedParImplDepth1(inArray, inArrayType, outArrayType, func) {
const length = inArray.length;
const mode = undefined;
const outArray = new outArrayType();
const outArray = new outArrayType(length);
if (length === 0)
return outArray;
@ -1274,7 +1307,7 @@ function ReduceTypedSeqImpl(array, outputType, func, initial) {
function ScatterTypedSeqImpl(array, outputType, indices, defaultValue, conflictFunc) {
assert(IsObject(array) && ObjectIsTypedObject(array), "Scatter called on non-object or untyped input array.");
assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "Scatter called on non-type-object outputType");
assert(TypeDescrIsArrayType(outputType), "Scatter called on non-array type");
assert(TypeDescrIsSizedArrayType(outputType), "Scatter called on non-sized array type");
assert(conflictFunc === undefined || typeof conflictFunc === "function", "Scatter called with invalid conflictFunc");
var result = new outputType();
@ -1323,10 +1356,8 @@ function FilterTypedSeqImpl(array, func) {
inOffset += size;
}
var T = GetTypedObjectModule();
var resultType = new T.ArrayType(elementType, count);
var result = new resultType();
var resultType = (arrayType.variable ? arrayType : arrayType.unsized);
var result = new resultType(count);
for (var i = 0, j = 0; i < array.length; i++) {
if (GET_BIT(flags, i))
result[j++] = array[i];

Просмотреть файл

@ -27,7 +27,7 @@
#define JS_DESCR_SLOT_KIND 0 // Atomized string representation
#define JS_DESCR_SLOT_STRING_REPR 1 // Atomized string representation
#define JS_DESCR_SLOT_ALIGNMENT 2 // Alignment in bytes
#define JS_DESCR_SLOT_SIZE 3 // Size in bytes, else 0
#define JS_DESCR_SLOT_SIZE 3 // Size in bytes, if sized, else 0
#define JS_DESCR_SLOT_OPAQUE 4 // Atomized string representation
#define JS_DESCR_SLOT_TYPROTO 5 // Prototype for instances, if any
@ -37,8 +37,8 @@
// Slots on all array descriptors
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 6
// Slots on array descriptors
#define JS_DESCR_SLOT_ARRAY_LENGTH 7
// Slots on sized array descriptors
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 7
// Slots on struct type objects
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 6
@ -51,10 +51,12 @@
// 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_UNSIZED_ARRAY_KIND 0
#define JS_TYPEREPR_MAX_UNSIZED_KIND 0 // Unsized kinds go above here
#define JS_TYPEREPR_SCALAR_KIND 1
#define JS_TYPEREPR_REFERENCE_KIND 2
#define JS_TYPEREPR_STRUCT_KIND 3
#define JS_TYPEREPR_ARRAY_KIND 4
#define JS_TYPEREPR_SIZED_ARRAY_KIND 4
#define JS_TYPEREPR_SIMD_KIND 5
// These constants are for use exclusively in JS code. In C++ code,

Просмотреть файл

@ -404,9 +404,11 @@ GetObjectAllocKindForCopy(const Nursery &nursery, JSObject *obj)
return InlineTypedObject::allocKindForTypeDescriptor(descr);
}
// Outline typed objects use the minimum allocation kind.
if (obj->is<OutlineTypedObject>())
return FINALIZE_OBJECT0;
// Outline typed objects have special requirements for their allocation kind.
if (obj->is<OutlineTypedObject>()) {
TypeDescr *descr = &obj->as<OutlineTypedObject>().typeDescr();
return OutlineTypedObject::allocKindForTypeDescriptor(descr);
}
// The only non-native objects in existence are proxies and typed objects.
MOZ_ASSERT(obj->isNative());

Просмотреть файл

@ -1,9 +1,10 @@
// Fuzz bug 981650: Test creating an array type based on an instance of
// Fuzz bug 981650: Test creating an unsized array type based on an instance of
// that same type.
if (typeof TypedObject === "undefined")
quit();
var T = TypedObject;
var v = new T.ArrayType(T.int32, 10);
new v(v);
var AT = new T.ArrayType(T.int32);
var v = new AT(10);
new AT(v);

Просмотреть файл

@ -9,14 +9,14 @@ load(libdir + "asserts.js")
var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
function main(variant) { // once a C programmer, always a C programmer.
var Uints = uint32.array(0);
var Uints = uint32.array();
var Unit = new StructType({}); // Empty struct type
var buffer = new ArrayBuffer(0); // Empty buffer
var p = new Unit(buffer); // OK
neuter(buffer, variant);
assertThrowsInstanceOf(() => new Unit(buffer), TypeError,
"Able to instantiate atop neutered buffer");
assertThrowsInstanceOf(() => new Uints(buffer), TypeError,
assertThrowsInstanceOf(() => new Uints(buffer, 0), TypeError,
"Able to instantiate atop neutered buffer");
}

Просмотреть файл

@ -13,11 +13,11 @@ if (!this.hasOwnProperty("TypedObject"))
var N = 100;
var T = TypedObject;
var Point = new T.StructType({x: T.uint32, y: T.uint32, z: T.uint32});
var PointArray = Point.array(N);
var PointArray = Point.array();
function foo(arr) {
var sum = 0;
for (var i = 0; i < N; i++) {
sum += arr[i].x + arr[i].y + arr[i].z;
}
}
foo(new PointArray());
foo(new PointArray(N));

Просмотреть файл

@ -8,11 +8,11 @@ if (!this.hasOwnProperty("TypedObject"))
// bug 953111
var A = TypedObject.uint8.array(0);
var a = new A();
var A = TypedObject.uint8.array();
var a = new A(0);
a.forEach(function(val, i) {});
// bug 951356 (dup, but a dup that is more likely to crash)
var AA = TypedObject.uint8.array(2147483647).array(0);
var aa = new AA();
var AA = TypedObject.uint8.array(2147483647).array();
var aa = new AA(0);

Просмотреть файл

@ -11,7 +11,7 @@ setJitCompilerOption("ion.warmup.trigger", 30);
var N = 100;
var T = TypedObject;
var Point = new T.StructType({x: T.uint32, y: T.uint32, z: T.uint32});
var PointArray = Point.array(N);
var PointArray = Point.array();
function bar(array, i, x, y, z) {
assertEq(array[i].x, x);
@ -20,7 +20,7 @@ function bar(array, i, x, y, z) {
}
function foo() {
var array = new PointArray();
var array = new PointArray(N);
for (var i = 0; i < N; i++) {
array[i].x = i + 0;
array[i].y = i + 1;

Просмотреть файл

@ -6,14 +6,14 @@ if (!this.hasOwnProperty("TypedObject"))
var {StructType, uint32, storage} = TypedObject;
var S = new StructType({f: uint32, g: uint32});
var A = S.array(10);
var A = S.array();
function readFrom(a) {
return a[2].f + a[2].g;
}
function main(variant) {
var a = new A();
var a = new A(10);
a[2].f = 22;
a[2].g = 44;

Просмотреть файл

@ -14,6 +14,11 @@ var Unit = new StructType(({ f : Object, } ));
assertThrowsInstanceOf(() => new Unit(buffer), TypeError,
"Able to instantiate opaque type atop buffer");
var Units = new ArrayType(Unit, 2);
var Units = new ArrayType(Unit);
assertThrowsInstanceOf(() => new Units(buffer), TypeError,
"Able to instantiate opaque type atop buffer");
var Units2 = Units.dimension(2);
assertThrowsInstanceOf(() => new Units2(buffer), TypeError,
"Able to instantiate opaque type atop buffer");

Просмотреть файл

@ -8,7 +8,8 @@ var uint32 = TypedObject.uint32;
var ObjectType = TypedObject.Object;
function runTests() {
(function DimensionLinkedToUndimension() {
var FiveUintsA = uint32.array(5);
var UintsA = uint32.array();
var FiveUintsA = UintsA.dimension(5);
var FiveUintsB = uint32.array(5);
assertEq(true,
FiveUintsA.equivalent(FiveUintsB)
@ -16,7 +17,7 @@ function runTests() {
})();
(function PrototypeHierarchy() {
schedulegc(3);
var Uint8s = uint8.array(5);
var Uint8s = uint8.array();
})();
}

Просмотреть файл

@ -29,14 +29,14 @@ if (!this.TypedObject) {
}
var T = TypedObject;
var AT = new T.ArrayType(T.int32, 100);
var AT = new T.ArrayType(T.int32);
function check(v) {
return v.map(x => x+1);
}
function test() {
var w1 = AT.build(x => x+1);
var w1 = AT.build(100, x => x+1);
var w2 = Array.build(100, x => x+1);
w2.map = w1.map;
var a = [ w1, w2 ];

Просмотреть файл

@ -25,14 +25,14 @@ if (!this.TypedObject) {
}
var T = TypedObject;
var AT = new T.ArrayType(T.int32, 100);
var AT = new T.ArrayType(T.int32);
function check(v) {
return v.map(x => x+1);
}
function test() {
var w = new AT();
var w = new AT(100);
for ( var i=0 ; i < 1000 ; i++ )
w = check(w);
return w;

Просмотреть файл

@ -23,10 +23,10 @@ if (!this.TypedObject) {
}
var T = TypedObject;
var AT = new T.ArrayType(T.uint32, 100);
var AT = new T.ArrayType(T.uint32);
function check() {
return AT.build(x => x+1);
return AT.build(100, x => x+1);
}
function test() {

Просмотреть файл

@ -21,8 +21,9 @@ if (!this.TypedObject) {
}
var T = TypedObject;
var IT = new T.ArrayType(T.int32, 100);
var ix = IT.build(x => x == 0 ? 99 : x-1); // [99, 0, 1, ..., 98]
var AT = new T.ArrayType(T.int32);
var IT = AT.dimension(100);
var ix = AT.build(100, x => x == 0 ? 99 : x-1); // [99, 0, 1, ..., 98]
// This is a left-rotate by one place
function check(v) {
@ -30,7 +31,7 @@ function check(v) {
}
function test() {
var w = IT.build(x => x);
var w = AT.build(100, x => x);
for ( var i=0 ; i < 77 ; i++ )
w = check(w);
return w;

Просмотреть файл

@ -27,7 +27,7 @@ function check(v) {
function test() {
var AT = new T.ArrayType(T.Any,10);
var v = new AT();
var v = new AT(10);
for ( var i=0 ; i < 1000 ; i++ )
check(v);
return check(v);

Просмотреть файл

@ -26,8 +26,8 @@ function check(v) {
}
function test() {
var AT = new T.ArrayType(T.int32, 10);
var v = new AT();
var AT = new T.ArrayType(T.int32,10);
var v = new AT(10);
for ( var i=0 ; i < 1000 ; i++ )
check(v);
return check(v);

Просмотреть файл

@ -29,7 +29,7 @@ function check(v) {
function test() {
var AT = new T.ArrayType(T.int32,10);
var v = new Object; // Not actually a typed object
var w = new AT(); // Actually a typed object
var w = new AT(10); // Actually a typed object
var a = [v,w];
for ( var i=0 ; i < 1000 ; i++ )
try { check(a[i%2]); } catch (e) {}

Просмотреть файл

@ -17,7 +17,7 @@ function test() {
matrix[i][0] = i;
var Point = new StructType({x: uint32, y: uint32});
var Points = Point.array(L);
var Points = Point.array();
assertParallelExecSucceeds(
// FIXME Bug 983692 -- no where to pass `m` to

Просмотреть файл

@ -10,7 +10,7 @@ var { uint8, uint32 } = TypedObject;
function test() {
var L = minItemsTestingThreshold;
var Uints = uint32.array(L);
var Uint8s = uint8.array(L);
var Uint8s = uint8.array();
var uint32s = new Uints();

Просмотреть файл

@ -11,8 +11,8 @@ var { ArrayType, StructType, uint32 } = TypedObject;
function test() {
var L = minItemsTestingThreshold;
var Point = new StructType({x: uint32, y: uint32});
var Points = Point.array(L);
var points = new Points();
var Points = Point.array();
var points = new Points(L);
for (var i = 0; i < L; i++)
points[i].x = i;

Просмотреть файл

@ -6,7 +6,7 @@ if (!this.hasOwnProperty("TypedObject"))
var { ArrayType, StructType, uint32 } = TypedObject;
var Point = new StructType({x: uint32, y: uint32});
var Points = Point.array(0);
var Points = Point.array();
var points = new Points();
points.mapPar(function() {});

Просмотреть файл

@ -8593,7 +8593,7 @@ static bool
GetTemplateObjectForClassHook(JSContext *cx, JSNative hook, CallArgs &args,
MutableHandleObject templateObject)
{
if (hook == TypedObject::construct) {
if (hook == TypedObject::constructSized) {
Rooted<TypeDescr *> descr(cx, &args.callee().as<TypeDescr>());
JSObject *obj = TypedObject::createZeroed(cx, descr, 1, gc::TenuredHeap);
if (!obj)

Просмотреть файл

@ -5097,6 +5097,16 @@ CodeGenerator::visitTypedObjectProto(LTypedObjectProto *lir)
return true;
}
bool
CodeGenerator::visitTypedObjectUnsizedLength(LTypedObjectUnsizedLength *lir)
{
Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output());
masm.load32(Address(obj, OutlineTypedObject::offsetOfUnsizedLength()), out);
return true;
}
bool
CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
{

Просмотреть файл

@ -186,6 +186,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitTypedObjectElements(LTypedObjectElements *lir);
bool visitSetTypedObjectOffset(LSetTypedObjectOffset *lir);
bool visitTypedObjectProto(LTypedObjectProto *ins);
bool visitTypedObjectUnsizedLength(LTypedObjectUnsizedLength *ins);
bool visitStringLength(LStringLength *lir);
bool visitInitializedLength(LInitializedLength *lir);
bool visitSetInitializedLength(LSetInitializedLength *lir);

Просмотреть файл

@ -7235,6 +7235,8 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *
if (elemPrediction.isUseless())
return true;
MOZ_ASSERT(TypeDescr::isSized(elemPrediction.kind()));
int32_t elemSize;
if (!elemPrediction.hasKnownSize(&elemSize))
return true;
@ -7245,7 +7247,7 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *
return true;
case type::Struct:
case type::Array:
case type::SizedArray:
return getElemTryComplexElemOfTypedObject(emitted,
obj,
index,
@ -7266,6 +7268,9 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *
index,
objPrediction,
elemPrediction);
case type::UnsizedArray:
MOZ_CRASH("Unsized arrays cannot be element types");
}
MOZ_CRASH("Bad kind");
@ -7299,6 +7304,12 @@ IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
return false;
} else if (objPrediction.kind() == type::UnsizedArray) {
// Note: unsized arrays will have their length set to zero if they are
// neutered, so we don't need to make sure that no neutering has
// occurred which affects this object.
length = MTypedObjectUnsizedLength::New(alloc(), obj);
current->add(length->toInstruction());
} else {
return false;
}
@ -8191,6 +8202,8 @@ IonBuilder::setElemTryTypedObject(bool *emitted, MDefinition *obj,
if (elemPrediction.isUseless())
return true;
MOZ_ASSERT(TypeDescr::isSized(elemPrediction.kind()));
int32_t elemSize;
if (!elemPrediction.hasKnownSize(&elemSize))
return true;
@ -8214,7 +8227,8 @@ IonBuilder::setElemTryTypedObject(bool *emitted, MDefinition *obj,
elemSize);
case type::Struct:
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
// Not yet optimized.
return true;
}
@ -8706,6 +8720,8 @@ IonBuilder::jsop_length_fastPath()
if (prediction.hasKnownArrayLength(&sizedLength)) {
obj->setImplicitlyUsedUnchecked();
length = MConstant::New(alloc(), Int32Value(sizedLength));
} else if (prediction.kind() == type::UnsizedArray) {
length = MTypedObjectUnsizedLength::New(alloc(), obj);
} else {
return false;
}
@ -9433,7 +9449,7 @@ IonBuilder::getPropTryTypedObject(bool *emitted,
return true;
case type::Struct:
case type::Array:
case type::SizedArray:
return getPropTryComplexPropOfTypedObject(emitted,
obj,
fieldOffset,
@ -9454,6 +9470,9 @@ IonBuilder::getPropTryTypedObject(bool *emitted,
fieldOffset,
fieldPrediction,
resultTypes);
case type::UnsizedArray:
MOZ_CRASH("Field of unsized array type");
}
MOZ_CRASH("Bad kind");
@ -10147,7 +10166,8 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
value, fieldPrediction);
case type::Struct:
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
return true;
}

Просмотреть файл

@ -777,7 +777,7 @@ class IonBuilder
InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
ScalarTypeDescr::Type *arrayType);
InliningStatus inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *target);
InliningStatus inlineConstructTypedObject(CallInfo &callInfo, SizedTypeDescr *target);
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);

Просмотреть файл

@ -4231,6 +4231,20 @@ class LTypedObjectProto : public LCallInstructionHelper<1, 1, 1>
}
};
// Load an unsized typed object's length.
class LTypedObjectUnsizedLength : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(TypedObjectUnsizedLength)
explicit LTypedObjectUnsizedLength(const LAllocation &object) {
setOperand(0, object);
}
const LAllocation *object() {
return getOperand(0);
}
};
// Load a typed object's elements vector.
class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
{

Просмотреть файл

@ -284,6 +284,7 @@
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectProto) \
_(TypedObjectUnsizedLength) \
_(TypedObjectElements) \
_(SetTypedObjectOffset) \
_(StringLength) \

Просмотреть файл

@ -2522,6 +2522,13 @@ LIRGenerator::visitTypedObjectProto(MTypedObjectProto *ins)
ins);
}
bool
LIRGenerator::visitTypedObjectUnsizedLength(MTypedObjectUnsizedLength *ins)
{
MOZ_ASSERT(ins->type() == MIRType_Int32);
return define(new(alloc()) LTypedObjectUnsizedLength(useRegisterAtStart(ins->object())), ins);
}
bool
LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
{

Просмотреть файл

@ -192,6 +192,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitTypedObjectElements(MTypedObjectElements *ins);
bool visitSetTypedObjectOffset(MSetTypedObjectOffset *ins);
bool visitTypedObjectProto(MTypedObjectProto *ins);
bool visitTypedObjectUnsizedLength(MTypedObjectUnsizedLength *ins);
bool visitInitializedLength(MInitializedLength *ins);
bool visitSetInitializedLength(MSetInitializedLength *ins);
bool visitNot(MNot *ins);

Просмотреть файл

@ -219,7 +219,12 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
return inlineHasClass(callInfo,
&ScalarTypeDescr::class_, &ReferenceTypeDescr::class_);
if (native == intrinsic_TypeDescrIsArrayType)
return inlineHasClass(callInfo, &ArrayTypeDescr::class_);
return inlineHasClass(callInfo,
&SizedArrayTypeDescr::class_, &UnsizedArrayTypeDescr::class_);
if (native == intrinsic_TypeDescrIsSizedArrayType)
return inlineHasClass(callInfo, &SizedArrayTypeDescr::class_);
if (native == intrinsic_TypeDescrIsUnsizedArrayType)
return inlineHasClass(callInfo, &UnsizedArrayTypeDescr::class_);
if (native == intrinsic_SetTypedObjectOffset)
return inlineSetTypedObjectOffset(callInfo);
@ -281,8 +286,8 @@ IonBuilder::inlineNonFunctionCall(CallInfo &callInfo, JSObject *target)
// Inline a call to a non-function object, invoking the object's call or
// construct hook.
if (callInfo.constructing() && target->constructHook() == TypedObject::construct)
return inlineConstructTypedObject(callInfo, &target->as<TypeDescr>());
if (callInfo.constructing() && target->constructHook() == TypedObject::constructSized)
return inlineConstructTypedObject(callInfo, &target->as<SizedTypeDescr>());
return InliningStatus_NotInlined;
}
@ -1647,6 +1652,7 @@ IonBuilder::elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefin
if (elemPrediction.isUseless() || elemPrediction.kind() != type::Scalar)
return false;
MOZ_ASSERT(type::isSized(elemPrediction.kind()));
*arrayType = elemPrediction.scalarType();
return true;
}
@ -2513,7 +2519,7 @@ IonBuilder::inlineIsConstructing(CallInfo &callInfo)
}
IonBuilder::InliningStatus
IonBuilder::inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *descr)
IonBuilder::inlineConstructTypedObject(CallInfo &callInfo, SizedTypeDescr *descr)
{
// Only inline default constructors for now.
if (callInfo.argc() != 0)

Просмотреть файл

@ -2807,6 +2807,36 @@ class MTypedObjectProto
}
};
class MTypedObjectUnsizedLength
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
private:
explicit MTypedObjectUnsizedLength(MDefinition *object)
: MUnaryInstruction(object)
{
setResultType(MIRType_Int32);
setMovable();
}
public:
INSTRUCTION_HEADER(TypedObjectUnsizedLength)
static MTypedObjectUnsizedLength *New(TempAllocator &alloc, MDefinition *object) {
return new(alloc) MTypedObjectUnsizedLength(object);
}
MDefinition *object() const {
return getOperand(0);
}
bool congruentTo(const MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
// Creates a new derived type object. At runtime, this is just a call
// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
// compile to particularly optimized code. However, using a distinct

Просмотреть файл

@ -163,6 +163,7 @@ namespace jit {
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectProto) \
_(TypedObjectUnsizedLength) \
_(TypedObjectElements) \
_(SetTypedObjectOffset) \
_(InitializedLength) \

Просмотреть файл

@ -249,6 +249,7 @@ class ParallelSafetyVisitor : public MDefinitionVisitor
SAFE_OP(TypedArrayLength)
SAFE_OP(TypedArrayElements)
SAFE_OP(TypedObjectProto)
SAFE_OP(TypedObjectUnsizedLength)
SAFE_OP(TypedObjectElements)
SAFE_OP(SetTypedObjectOffset)
SAFE_OP(InitializedLength)

Просмотреть файл

@ -1113,7 +1113,7 @@ RNewDerivedTypedObject::RNewDerivedTypedObject(CompactBufferReader &reader)
bool
RNewDerivedTypedObject::recover(JSContext *cx, SnapshotIterator &iter) const
{
Rooted<TypeDescr *> descr(cx, &iter.read().toObject().as<TypeDescr>());
Rooted<SizedTypeDescr *> descr(cx, &iter.read().toObject().as<SizedTypeDescr>());
Rooted<TypedObject *> owner(cx, &iter.read().toObject().as<TypedObject>());
int32_t offset = iter.read().toInt32();

Просмотреть файл

@ -123,13 +123,24 @@ TypedObjectPrediction::ofArrayKind() const
case type::Struct:
return false;
case type::Array:
case type::SizedArray:
case type::UnsizedArray:
return true;
}
MOZ_CRASH("Bad kind");
}
static bool
DescrHasKnownSize(const TypeDescr &descr, int32_t *out)
{
if (!descr.is<SizedTypeDescr>())
return false;
*out = descr.as<SizedTypeDescr>().size();
return true;
}
bool
TypedObjectPrediction::hasKnownSize(int32_t *out) const
{
@ -139,8 +150,7 @@ TypedObjectPrediction::hasKnownSize(int32_t *out) const
break;
case TypedObjectPrediction::Descr:
*out = descr().size();
return true;
return DescrHasKnownSize(descr(), out);
case TypedObjectPrediction::Prefix:
// We only know a prefix of the struct fields, hence we do not
@ -223,8 +233,8 @@ TypedObjectPrediction::hasKnownArrayLength(int32_t *length) const
case TypedObjectPrediction::Descr:
// In later patches, this condition will always be true
// so long as this represents an array
if (descr().is<ArrayTypeDescr>()) {
*length = descr().as<ArrayTypeDescr>().length();
if (descr().is<SizedArrayTypeDescr>()) {
*length = descr().as<SizedArrayTypeDescr>().length();
return true;
}
return false;
@ -235,6 +245,13 @@ TypedObjectPrediction::hasKnownArrayLength(int32_t *length) const
MOZ_CRASH("Bad prediction kind");
}
static TypeDescr &
DescrArrayElementType(const TypeDescr &descr) {
return (descr.is<SizedArrayTypeDescr>()
? descr.as<SizedArrayTypeDescr>().elementType()
: descr.as<UnsizedArrayTypeDescr>().elementType());
}
TypedObjectPrediction
TypedObjectPrediction::arrayElementType() const
{
@ -245,7 +262,7 @@ TypedObjectPrediction::arrayElementType() const
break;
case TypedObjectPrediction::Descr:
return TypedObjectPrediction(descr().as<ArrayTypeDescr>().elementType());
return TypedObjectPrediction(DescrArrayElementType(descr()));
case TypedObjectPrediction::Prefix:
break; // Prefixes are always structs, never arrays

Просмотреть файл

@ -1014,9 +1014,9 @@ JSObject *
CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
HandleObject owner, int32_t offset)
{
MOZ_ASSERT(descr->is<TypeDescr>());
MOZ_ASSERT(descr->is<SizedTypeDescr>());
MOZ_ASSERT(owner->is<TypedObject>());
Rooted<TypeDescr*> descr1(cx, &descr->as<TypeDescr>());
Rooted<SizedTypeDescr*> descr1(cx, &descr->as<SizedTypeDescr>());
Rooted<TypedObject*> owner1(cx, &owner->as<TypedObject>());
return OutlineTypedObject::createDerived(cx, descr1, owner1, offset);
}

Просмотреть файл

@ -996,6 +996,8 @@ bool intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp
bool intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_TypeDescrIsSimpleType(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_TypeDescrIsArrayType(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_TypeDescrIsUnsizedArrayType(JSContext *cx, unsigned argc, Value *vp);
bool intrinsic_TypeDescrIsSizedArrayType(JSContext *cx, unsigned argc, Value *vp);
class AutoLockForExclusiveAccess
{

Просмотреть файл

@ -7,9 +7,9 @@ var StructType = TypedObject.StructType;
var float32 = TypedObject.float32;
function runTests() {
var Point = new ArrayType(float32, 3);
var Point = new ArrayType(float32).dimension(3);
var Line = new StructType({from: Point, to: Point});
var Lines = new ArrayType(Line, 3);
var Lines = new ArrayType(Line).dimension(3);
var lines = new Lines([
{from: [1, 2, 3], to: [4, 5, 6]},

Просмотреть файл

@ -28,14 +28,14 @@ function runTests() {
assertThrows(function() new ArrayType(""));
assertThrows(function() new ArrayType(5));
assertThrows(function() new ArrayType(uint8).dimension(-1));
var A = new ArrayType(uint8, 10);
//assertEq(A.__proto__.__proto__, ArrayType.prototype);
var A = new ArrayType(uint8).dimension(10);
assertEq(A.__proto__.__proto__, ArrayType.prototype);
assertEq(A.length, 10);
assertEq(A.elementType, uint8);
assertEq(A.byteLength, 10);
assertEq(A.toSource(), "new ArrayType(uint8, 10)");
assertEq(A.toSource(), "new ArrayType(uint8).dimension(10)");
//assertEq(A.prototype.__proto__.__proto__, ArrayType.prototype.prototype);
assertEq(A.prototype.__proto__.__proto__, ArrayType.prototype.prototype);
var a = new A();
assertEq(a.__proto__, A.prototype);
@ -74,8 +74,8 @@ function runTests() {
// Length different
assertThrows(function() new A([0, 1, 0, 1, 0, 1, 0, 1, 0]));
var Vec3 = new ArrayType(float32, 3);
var Sprite = new ArrayType(Vec3, 3); // say for position, velocity, and direction
var Vec3 = new ArrayType(float32).dimension(3);
var Sprite = new ArrayType(Vec3).dimension(3); // say for position, velocity, and direction
assertEq(Sprite.elementType, Vec3);
assertEq(Sprite.elementType.elementType, float32);
@ -96,7 +96,7 @@ function runTests() {
assertEq(Number.isNaN(mario[1][1]), true);
// ok this is just for kicks
var AllSprites = new ArrayType(Sprite, 65536);
var AllSprites = new ArrayType(Sprite).dimension(65536);
var as = new AllSprites();
assertEq(as.length, 65536);

Просмотреть файл

@ -0,0 +1,25 @@
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var BUGNUMBER = 922115;
var summary = 'check we cannot create handles to unsized arrays';
var T = TypedObject;
function runTests() {
var Line = new T.StructType({from: T.uint8, to: T.uint8});
var Lines = Line.array();
assertThrowsInstanceOf(function() Lines.handle(), TypeError,
"was able to create handle to unsized array");
reportCompare(true, true);
print("Tests complete");
}
runTests();

Просмотреть файл

@ -21,14 +21,31 @@ var float64 = TypedObject.float64;
var objectType = TypedObject.objectType;
function filterOdds() {
function filterOddsFromVariable() {
var length = 100;
var Uint32s = new ArrayType(uint32, 100);
var Uint32s = uint32.array();
var uint32s = new Uint32s(100);
for (var i = 0; i < length; i++)
uint32s[i] = i;
var odds = uint32s.filter(i => (i % 2) != 0);
assertEq(true, objectType(odds) == Uint32s);
assertEq(true, Uint32s.variable);
assertEq(50, odds.length);
for (var i = 0, j = 1; j < length; i++, j += 2)
assertEq(odds[i], j);
}
function filterOddsFromSized() {
var length = 100;
var Uint32s = uint32.array(100);
var uint32s = new Uint32s();
for (var i = 0; i < length; i++)
uint32s[i] = i;
var odds = uint32s.filter(i => (i % 2) != 0);
assertEq(true, objectType(odds) == Uint32s.unsized);
assertEq(true, objectType(odds).variable);
assertEq(50, odds.length);
for (var i = 0, j = 1; j < length; i++, j += 2)
assertEq(odds[i], j);
@ -37,7 +54,8 @@ function filterOdds() {
function runTests() {
print(BUGNUMBER + ": " + summary);
filterOdds();
filterOddsFromVariable();
filterOddsFromSized();
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -27,7 +27,7 @@ function TestValues(type, values) {
compare(struct.f, values[i]);
}
var Array = new ArrayType(type, 1);
var Array = new ArrayType(type).dimension(1);
for (var i = 0; i < values.length; i++) {
var array = new Array();
array[0] = values[i].input;

Просмотреть файл

@ -39,7 +39,16 @@ function TestStructFields(RefType) {
function TestArrayElements(RefType) {
var rabbit = {};
var S1 = new ArrayType(RefType, 1);
var S1 = new ArrayType(RefType).dimension(1);
var s1 = new S1([rabbit]);
assertCanReach(s1, rabbit);
s1[0] = null;
assertCannotReach(s1, rabbit);
}
function TestUnsizedArrayElements(RefType) {
var rabbit = {};
var S1 = new ArrayType(RefType);
var s1 = new S1([rabbit]);
assertCanReach(s1, rabbit);
s1[0] = null;
@ -49,7 +58,7 @@ function TestArrayElements(RefType) {
function TestStructInArray(RefType) {
var rabbit = {};
var S2 = new StructType({f: RefType, g: RefType});
var S1 = new ArrayType(S2, 1);
var S1 = new ArrayType(S2).dimension(1);
var s1 = new S1([{f: rabbit, g: {}}]);
assertCanReach(s1, rabbit);
s1[0].f = null;
@ -82,6 +91,9 @@ function runTests()
TestArrayElements(Object);
TestArrayElements(Any);
TestUnsizedArrayElements(Object);
TestUnsizedArrayElements(Any);
TestStructInArray(Object);
TestStructInArray(Any);

Просмотреть файл

@ -39,9 +39,9 @@ function runTests() {
{type: new StructType({a: uint8, b: uint8, c: uint16}), size: 4, alignment: 2},
{type: new ArrayType(uint8, 32), size: 32, alignment: 1},
{type: new ArrayType(uint16, 16), size: 32, alignment: 2},
{type: new ArrayType(uint32, 8), size: 32, alignment: 4},
{type: new ArrayType(uint8).dimension(32), size: 32, alignment: 1},
{type: new ArrayType(uint16).dimension(16), size: 32, alignment: 2},
{type: new ArrayType(uint32).dimension(8), size: 32, alignment: 4},
];
for (var i = 0; i < typesAndAlignments.length; i++) {

Просмотреть файл

@ -21,6 +21,7 @@ function runTests() {
assertEq(S.__proto__, StructType.prototype);
assertEq(S.prototype.__proto__, StructType.prototype.prototype);
assertEq(S.toSource(), "new StructType({x: int32, y: uint8, z: float64})");
assertEq(S.variable, false);
assertEq(S.byteLength, 16);
assertEq(S.byteAlignment, 8);
var fieldNames = Object.getOwnPropertyNames(S.fieldTypes);

Просмотреть файл

@ -0,0 +1,54 @@
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
var BUGNUMBER = 922115;
var summary = 'TypedObjects ArrayType implementation';
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var { ArrayType, StructType, uint8, float32, uint32 } = TypedObject;
var ObjectType = TypedObject.Object;
function runTests() {
print(BUGNUMBER + ": " + summary);
(function SimpleArrayOfTwoObjects() {
print("SimpleArrayOfTwoObjects");
var Objects = new ArrayType(ObjectType);
var objects2 = new Objects([{f: "Hello"},
{f: "World"}]);
assertEq(objects2[0].f, "Hello");
assertEq(objects2[1].f, "World");
assertEq(objects2.length, 2);
})();
(function EmbedUnsizedArraysBad() {
print("EmbedUnsizedArraysBad");
var Objects = new ArrayType(ObjectType);
assertThrows(() => new ArrayType(Objects));
assertThrows(() => new StructType({f: Objects}));
})();
(function MultipleSizes() {
print("MultipleSizes");
var Uints = new ArrayType(uint32);
var Point = new StructType({values: new ArrayType(uint32).dimension(3)});
var uints = new Uints([0, 1, 2]);
var point = new Point({values: uints});
assertEq(uints.length, point.values.length);
for (var i = 0; i < uints.length; i++) {
assertEq(uints[i], i);
assertEq(uints[i], point.values[i]);
}
})();
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");
}
runTests();

Просмотреть файл

@ -0,0 +1,47 @@
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
var BUGNUMBER = 922115;
var summary = 'TypedObjects ArrayType implementation';
var ArrayType = TypedObject.ArrayType;
var StructType = TypedObject.StructType;
var uint8 = TypedObject.uint8;
var float32 = TypedObject.float32;
var uint32 = TypedObject.uint32;
var ObjectType = TypedObject.Object;
function runTests() {
(function DimensionLinkedToUndimension() {
var UintsA = uint32.array();
var FiveUintsA = UintsA.dimension(5);
var FiveUintsB = uint32.array(5);
assertEq(true, FiveUintsA.equivalent(FiveUintsB));
assertEq(true, FiveUintsA.unsized === UintsA);
assertEq(true, FiveUintsB.unsized !== UintsA);
})();
(function PrototypeHierarchy() {
var Uint8s = uint8.array();
assertEq(Uint8s.prototype.__proto__, ArrayType.prototype.prototype);
Uint8s.prototype.sum = function() {
var r = 0;
for (var i = 0; i < this.length; i++)
r = uint8(r + this[i]);
return r;
};
var FiveUint8s = Uint8s.dimension(5);
assertEq(FiveUint8s.__proto__, Uint8s);
var fiveUint8s = new FiveUint8s([128, 128, 128, 128, 128]);
assertEq(128, fiveUint8s.sum());
})();
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");
}
runTests();

Просмотреть файл

@ -0,0 +1,23 @@
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
var BUGNUMBER = 922115;
var summary = 'cannot embed unsized array in a struct';
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var T = TypedObject;
function runTests() {
print(BUGNUMBER + ": " + summary);
var Uints = T.uint32.array();
assertThrowsInstanceOf(() => { new T.StructType({f: Uints}) }, TypeError);
assertThrowsInstanceOf(() => { Uints.array() }, TypeError);
reportCompare(true, true);
print("Tests complete");
}
runTests();

Просмотреть файл

@ -914,6 +914,18 @@ js::intrinsic_TypeDescrIsArrayType(JSContext *cx, unsigned argc, Value *vp)
return js::TypeDescrIsArrayType(cx, argc, vp);
}
bool
js::intrinsic_TypeDescrIsUnsizedArrayType(JSContext *cx, unsigned argc, Value *vp)
{
return js::TypeDescrIsUnsizedArrayType(cx, argc, vp);
}
bool
js::intrinsic_TypeDescrIsSizedArrayType(JSContext *cx, unsigned argc, Value *vp)
{
return js::TypeDescrIsSizedArrayType(cx, argc, vp);
}
/**
* Returns the default locale as a well-formed, but not necessarily canonicalized,
* BCP-47 language tag.
@ -1119,6 +1131,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FNINFO("TypeDescrIsArrayType",
intrinsic_TypeDescrIsArrayType,
&js::TypeDescrIsArrayTypeJitInfo, 1, 0),
JS_FNINFO("TypeDescrIsUnsizedArrayType",
intrinsic_TypeDescrIsUnsizedArrayType,
&js::TypeDescrIsUnsizedArrayTypeJitInfo, 1, 0),
JS_FNINFO("TypeDescrIsSizedArrayType",
intrinsic_TypeDescrIsSizedArrayType,
&js::TypeDescrIsSizedArrayTypeJitInfo, 1, 0),
JS_FNINFO("TypeDescrIsSimpleType",
intrinsic_TypeDescrIsSimpleType,
&js::TypeDescrIsSimpleTypeJitInfo, 1, 0),