Bug 966575 part 03 -- Extend Type Descr to include all data from type repr r=sfink

This commit is contained in:
Nicholas D. Matsakis 2014-01-27 19:49:36 -05:00
parent 89a94ef82e
commit af656b7f6b
7 changed files with 124 additions and 81 deletions

View File

@ -99,7 +99,7 @@ extern const JSFunctionSpec Int32x4Methods[];
const Class X4TypeDescr::class_ = {
"X4",
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_X4_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub, /* addProperty */
JS_DeletePropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
@ -201,16 +201,14 @@ CreateX4Class(JSContext *cx, Handle<GlobalObject*> global)
if (!proto)
return nullptr;
// Create type constructor itself.
// Create type constructor itself and initialize its reserved slots.
Rooted<X4TypeDescr*> x4(cx);
x4 = NewObjectWithProto<X4TypeDescr>(cx, funcProto, global);
if (!x4 || !InitializeCommonTypeDescriptorProperties(cx, x4, typeReprObj))
return nullptr;
// Link type constructor to the type representation.
x4->initReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
x4->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
// Link constructor to prototype and install properties.

View File

@ -186,7 +186,7 @@ GetPrototype(JSContext *cx, HandleObject obj)
const Class js::ScalarTypeDescr::class_ = {
"Scalar",
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_SCALAR_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub, /* addProperty */
JS_DeletePropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
@ -257,7 +257,7 @@ ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
const Class js::ReferenceTypeDescr::class_ = {
"Reference",
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_REFERENCE_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub, /* addProperty */
JS_DeletePropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
@ -375,7 +375,7 @@ CreatePrototypeObjectForComplexTypeInstance(JSContext *cx,
const Class UnsizedArrayTypeDescr::class_ = {
"ArrayType",
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_ARRAY_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
@ -392,7 +392,7 @@ const Class UnsizedArrayTypeDescr::class_ = {
const Class SizedArrayTypeDescr::class_ = {
"ArrayType",
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_ARRAY_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
@ -450,6 +450,17 @@ js::InitializeCommonTypeDescriptorProperties(JSContext *cx,
TypeRepresentation *typeRepr =
TypeRepresentation::fromOwnerObject(*typeReprOwnerObj);
// Regardless of whether the data is transparent, we always
// store the internal size/alignment slots.
if (typeRepr->isSized()) {
SizedTypeRepresentation *sizedTypeRepr = typeRepr->asSized();
obj->initReservedSlot(JS_DESCR_SLOT_SIZE,
Int32Value(sizedTypeRepr->size()));
obj->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT,
Int32Value(sizedTypeRepr->alignment()));
}
// If data is transparent, also store the public slots.
if (typeRepr->transparent() && typeRepr->isSized()) {
SizedTypeRepresentation *sizedTypeRepr = typeRepr->asSized();
@ -518,7 +529,7 @@ ArrayMetaTypeDescr::create(JSContext *cx,
Rooted<T*> obj(cx, NewObjectWithProto<T>(cx, arrayTypePrototype, nullptr));
if (!obj)
return nullptr;
obj->initReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR,
obj->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR,
ObjectValue(*arrayTypeReprObj));
RootedValue elementTypeVal(cx, ObjectValue(*elementType));
@ -527,7 +538,7 @@ ArrayMetaTypeDescr::create(JSContext *cx,
JSPROP_READONLY | JSPROP_PERMANENT))
return nullptr;
obj->initReservedSlot(JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE, elementTypeVal);
obj->initReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE, elementTypeVal);
if (!InitializeCommonTypeDescriptorProperties(cx, obj, arrayTypeReprObj))
return nullptr;
@ -634,7 +645,7 @@ UnsizedArrayTypeDescr::dimension(JSContext *cx, unsigned int argc, jsval *vp)
// Create the sized type object.
Rooted<SizedTypeDescr*> elementType(cx, &unsizedTypeDescr->elementType());
RootedObject obj(cx);
Rooted<SizedArrayTypeDescr*> obj(cx);
obj = ArrayMetaTypeDescr::create<SizedArrayTypeDescr>(
cx, unsizedTypeDescr, sizedTypeReprObj, elementType);
if (!obj)
@ -665,7 +676,7 @@ UnsizedArrayTypeDescr::dimension(JSContext *cx, unsigned int argc, jsval *vp)
const Class StructTypeDescr::class_ = {
"StructType",
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEOBJ_STRUCT_SLOTS) |
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) |
JSCLASS_HAS_PRIVATE, // used to store FieldList
JS_PropertyStub,
JS_DeletePropertyStub,
@ -765,7 +776,7 @@ StructMetaTypeDescr::layout(JSContext *cx,
return false;
StructTypeRepresentation *typeRepr =
TypeRepresentation::fromOwnerObject(*typeReprObj)->asStruct();
structType->initReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR,
structType->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR,
ObjectValue(*typeReprObj));
// Construct for internal use an array with the type object for each field.
@ -775,7 +786,7 @@ StructMetaTypeDescr::layout(JSContext *cx,
if (!fieldTypeVec)
return false;
structType->initReservedSlot(JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES,
structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES,
ObjectValue(*fieldTypeVec));
// Construct the fieldNames vector
@ -966,12 +977,14 @@ DefineSimpleTypeDescr(JSContext *cx,
if (!typeReprObj)
return false;
numFun->initReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR,
numFun->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR,
ObjectValue(*typeReprObj));
if (!InitializeCommonTypeDescriptorProperties(cx, numFun, typeReprObj))
return false;
numFun->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(type));
if (!JS_DefineFunctions(cx, numFun, T::typeObjectMethods))
return false;
@ -1603,7 +1616,7 @@ StructFieldType(JSContext *cx,
// In this scenario, line1.start.type() === Point1 and
// line2.start.type() === Point2.
RootedObject fieldTypes(
cx, &type->getReservedSlot(JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES).toObject());
cx, &type->getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject());
RootedValue fieldTypeVal(cx);
if (!JSObject::getElement(cx, fieldTypes, fieldTypes,
fieldIndex, &fieldTypeVal))

View File

@ -143,7 +143,7 @@ class TypeDescr : public JSObject
{
public:
JSObject &typeRepresentationOwnerObj() const {
return getReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR).toObject();
return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
}
TypeRepresentation *typeRepresentation() const {
@ -274,7 +274,7 @@ class UnsizedArrayTypeDescr : public TypeDescr
static bool dimension(JSContext *cx, unsigned int argc, jsval *vp);
SizedTypeDescr &elementType() {
return getReservedSlot(JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
}
};
@ -287,7 +287,7 @@ class SizedArrayTypeDescr : public SizedTypeDescr
static const Class class_;
SizedTypeDescr &elementType() {
return getReservedSlot(JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
}
};

View File

@ -17,15 +17,13 @@
// Type object slots
#define DESCR_TYPE_REPR(obj) \
UnsafeGetReservedSlot(obj, JS_TYPEOBJ_SLOT_TYPE_REPR)
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE_REPR)
#define DESCR_KIND(obj) \
REPR_KIND(DESCR_TYPE_REPR(obj))
#define DESCR_SIZE(obj) \
REPR_SIZE(DESCR_TYPE_REPR(obj))
#define DESCR_LENGTH(obj) \
REPR_LENGTH(DESCR_TYPE_REPR(obj))
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZE)
#define DESCR_TYPE(obj) \
REPR_TYPE(DESCR_TYPE_REPR(obj))
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE)
// Typed object slots
@ -118,7 +116,7 @@ function DescrToSource(descr) {
var result = ".array";
var sep = "(";
while (DESCR_KIND(descr) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
result += sep + DESCR_LENGTH(descr);
result += sep + descr.length;
descr = descr.elementType;
sep = ", ";
}
@ -149,6 +147,10 @@ function DescrToSource(descr) {
// code.
function TypedObjectPointer(descr, datum, offset) {
assert(IsObject(descr) && ObjectIsTypeDescr(descr), "Not descr");
assert(IsObject(datum) && ObjectIsTypedDatum(datum), "Not datum");
assert(TO_INT32(offset) === offset, "offset not int");
this.descr = descr;
this.datum = datum;
this.offset = offset;
@ -181,16 +183,18 @@ TypedObjectPointer.prototype.kind = function() {
return DESCR_KIND(this.descr);
}
// Extract the length. This does a switch on kind, so it's
// best if we can avoid it.
TypedObjectPointer.prototype.length = function() {
switch (this.kind()) {
case JS_TYPEREPR_SIZED_ARRAY_KIND:
return DESCR_LENGTH(this.descr);
return this.descr.length;
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
return DATUM_LENGTH(this.datum);
return this.datum.length;
}
assert(false, "length() invoked on non-array-type");
return 0;
assert(false, "Invalid kind for length");
return false;
}
///////////////////////////////////////////////////////////////////////////
@ -209,15 +213,10 @@ TypedObjectPointer.prototype.moveTo = function(propName) {
break;
case JS_TYPEREPR_SIZED_ARRAY_KIND:
return this.moveToArray(propName, this.descr.length);
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
// For an array, property must be an element. Note that we use the
// length as loaded from the type *representation* as opposed to
// the type *object*; this is because some type objects represent
// unsized arrays and hence do not have a length.
var index = TO_INT32(propName);
if (index === propName && index >= 0 && index < this.length())
return this.moveToElem(index);
break;
return this.moveToArray(propName, this.datum.length);
case JS_TYPEREPR_STRUCT_KIND:
if (HAS_PROPERTY(this.descr.fieldTypes, propName))
@ -229,6 +228,20 @@ TypedObjectPointer.prototype.moveTo = function(propName) {
return undefined;
};
TypedObjectPointer.prototype.moveToArray = function(propName, length) {
// For an array, property must be an element. Note that we take
// the length as an argument rather than loading it from the descriptor.
// This is because this same helper is used for *unsized arrays*, where
// the length is drawn from the datum, and *sized arrays*, where the
// length is drawn from the type.
var index = TO_INT32(propName);
if (index === propName && index >= 0 && index < length)
return this.moveToElem(index);
ThrowError(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, propName);
return undefined;
}
// Adjust `this` in place to point at the element `index`. `this`
// must be a array type and `index` must be within bounds. Returns
// `this`.
@ -239,7 +252,7 @@ TypedObjectPointer.prototype.moveToElem = function(index) {
assert(TO_INT32(index) === index,
"moveToElem invoked with non-integer index");
assert(index >= 0 && index < this.length(),
"moveToElem invoked with out-of-bounds index: " + index);
"moveToElem invoked with negative index: " + index);
var elementDescr = this.descr.elementType;
this.descr = elementDescr;
@ -261,12 +274,21 @@ TypedObjectPointer.prototype.moveToField = function(propName) {
assert(HAS_PROPERTY(this.descr.fieldTypes, propName),
"moveToField invoked with undefined field");
// FIXME(Bug 966575) -- the fieldOffsets array that we are using
// below is only available on transparent types. This is fixed
// in part 6 of this patch series.
var fieldDescr = this.descr.fieldTypes[propName];
var fieldOffset = TO_INT32(this.descr.fieldOffsets[propName]);
this.descr = fieldDescr;
// Note: we do not allow construction of structs where the
// offset of a field cannot be represented by an int32.
assert(IsObject(fieldDescr) && ObjectIsTypeDescr(fieldDescr),
"bad field descr");
assert(TO_INT32(fieldOffset) === fieldOffset,
"bad field offset");
assert(fieldOffset >= 0 && fieldOffset < DESCR_SIZE(this.descr),
"out of bounds field offset");
this.descr = fieldDescr;
this.offset += fieldOffset;
return this;
@ -423,25 +445,14 @@ TypedObjectPointer.prototype.set = function(fromValue) {
return;
case JS_TYPEREPR_SIZED_ARRAY_KIND:
if (this.setArray(fromValue, this.descr.length))
return;
break;
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
if (!IsObject(fromValue))
break;
// Check that "array-like" fromValue has an appropriate length.
var length = this.length();
if (fromValue.length !== length)
break;
// Adapt each element.
if (length > 0) {
var tempPtr = this.copy().moveToElem(0);
var size = DESCR_SIZE(tempPtr.descr);
for (var i = 0; i < length; i++) {
tempPtr.set(fromValue[i]);
tempPtr.offset += size;
}
}
return;
if (this.setArray(fromValue, this.datum.length))
return;
break;
case JS_TYPEREPR_STRUCT_KIND:
if (!IsObject(fromValue))
@ -462,6 +473,27 @@ TypedObjectPointer.prototype.set = function(fromValue) {
DescrToSource(this.descr));
}
TypedObjectPointer.prototype.setArray = function(fromValue, length) {
if (!IsObject(fromValue))
return false;
// Check that "array-like" fromValue has an appropriate length.
if (fromValue.length !== length)
return false;
// Adapt each element.
if (length > 0) {
var tempPtr = this.copy().moveToElem(0);
var size = DESCR_SIZE(tempPtr.descr);
for (var i = 0; i < length; i++) {
tempPtr.set(fromValue[i]);
tempPtr.offset += size;
}
}
return true;
}
// Sets `fromValue` to `this` assuming that `this` is a scalar type.
TypedObjectPointer.prototype.setScalar = function(fromValue) {
assert(this.kind() == JS_TYPEREPR_SCALAR_KIND,
@ -582,7 +614,7 @@ function FillTypedArrayWithValue(destArray, fromValue) {
"FillTypedArrayWithValue: not typed handle");
var descr = DATUM_TYPE_DESCR(destArray);
var length = DESCR_LENGTH(descr);
var length = descr.length;
if (length === 0)
return;

View File

@ -13,29 +13,26 @@
// Slots for type objects
//
// Some slots apply to all type objects and some are specific to
// particular kinds of type objects. Because all type objects, at
// least for now, have a distinct class, we can assign them distinct
// numbers of slots depending on their kind.
// particular kinds of type objects. For simplicity we use the same
// number of slots no matter what kind of type descriptor we are
// working with, even though this is mildly wasteful.
// Slots on all type objects
#define JS_TYPEOBJ_SLOT_TYPE_REPR 0 // Associated Type Representation
#define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation
#define JS_DESCR_SLOT_SIZE 1 // Size in bytes, if sized
#define JS_DESCR_SLOT_ALIGNMENT 2 // Alignment in bytes, if sized
// Slots on scalars
#define JS_TYPEOBJ_SCALAR_SLOTS 1 // Maximum number
// Slots on scalars, references, and x4s
#define JS_DESCR_SLOT_TYPE 3 // Type code
// Slots on references
#define JS_TYPEOBJ_REFERENCE_SLOTS 1 // Maximum number
// Slots on all array descriptors
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 3
// Slots on x4s
#define JS_TYPEOBJ_X4_SLOTS 1 // Maximum number
// Slots on struct type objects
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 3
// Slots on array type objects
#define JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE 1
#define JS_TYPEOBJ_ARRAY_SLOTS 3 // Maximum number
// Slots on structs
#define JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES 1
#define JS_TYPEOBJ_STRUCT_SLOTS 2 // Maximum number
// Maximum number of slots for any descriptor
#define JS_DESCR_SLOTS 4
///////////////////////////////////////////////////////////////////////////
// Slots for type representation objects

View File

@ -9994,7 +9994,7 @@ IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
MDefinition *
IonBuilder::typeObjectForElementFromArrayStructType(MDefinition *typeObj)
{
MInstruction *elemType = MLoadFixedSlot::New(alloc(), typeObj, JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE);
MInstruction *elemType = MLoadFixedSlot::New(alloc(), typeObj, JS_DESCR_SLOT_ARRAY_ELEM_TYPE);
current->add(elemType);
MInstruction *unboxElemType = MUnbox::New(alloc(), elemType, MIRType_Object, MUnbox::Infallible);
@ -10009,7 +10009,7 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
{
// Load list of field type objects.
MInstruction *fieldTypes = MLoadFixedSlot::New(alloc(), typeObj, JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES);
MInstruction *fieldTypes = MLoadFixedSlot::New(alloc(), typeObj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
current->add(fieldTypes);
MInstruction *unboxFieldTypes = MUnbox::New(alloc(), fieldTypes, MIRType_Object, MUnbox::Infallible);

View File

@ -14,6 +14,7 @@ function runTests() {
print(BUGNUMBER + ": " + summary);
(function SimpleArrayOfTwoObjects() {
print("SimpleArrayOfTwoObjects");
var Objects = new ArrayType(ObjectType);
var objects2 = new Objects(2, [{f: "Hello"},
{f: "World"}]);
@ -23,12 +24,14 @@ function runTests() {
})();
(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)});