Bug 966575 part06 -- Move field info into reserved slots, remove non-standard fieldName r=sfink

This commit is contained in:
Nicholas D. Matsakis 2014-01-29 14:04:05 -05:00
Родитель 4716472758
Коммит c71ebdb102
7 изменённых файлов: 143 добавлений и 109 удалений

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

@ -130,7 +130,6 @@ ConvertAndCopyTo(JSContext *cx, HandleTypedDatum datum, HandleValue val)
*/
static bool
Reify(JSContext *cx,
TypeRepresentation *typeRepr,
HandleTypeDescr type,
HandleTypedDatum datum,
size_t offset,
@ -782,36 +781,52 @@ StructMetaTypeDescr::layout(JSContext *cx,
structType->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR,
ObjectValue(*typeReprObj));
// Construct for internal use an array with the type object for each field.
RootedObject fieldTypeVec(
cx, NewDenseCopiedArray(cx, fieldTypeObjs.length(),
fieldTypeObjs.begin()));
if (!fieldTypeVec)
return false;
structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES,
ObjectValue(*fieldTypeVec));
// Construct the fieldNames vector
AutoValueVector fieldNameValues(cx);
for (unsigned int i = 0; i < ids.length(); i++) {
RootedValue value(cx, IdToValue(ids[i]));
if (!fieldNameValues.append(value))
// Construct for internal use an array with names of each field
{
AutoValueVector fieldNameValues(cx);
for (unsigned int i = 0; i < ids.length(); i++) {
RootedValue value(cx, IdToValue(ids[i]));
if (!fieldNameValues.append(value))
return false;
}
RootedObject fieldNamesVec(
cx, NewDenseCopiedArray(cx, fieldNameValues.length(),
fieldNameValues.begin()));
if (!fieldNamesVec)
return false;
structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES,
ObjectValue(*fieldNamesVec));
}
RootedObject fieldNamesVec(
cx, NewDenseCopiedArray(cx, fieldNameValues.length(),
fieldNameValues.begin()));
if (!fieldNamesVec)
return false;
RootedValue fieldNamesVecValue(cx, ObjectValue(*fieldNamesVec));
if (!JSObject::defineProperty(cx, structType, cx->names().fieldNames,
fieldNamesVecValue, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
return false;
// Construct the fieldNames, fieldOffsets and fieldTypes objects:
// fieldNames : [ string ]
// Construct for internal use an array with the type object for each field.
{
RootedObject fieldTypeVec(cx);
fieldTypeVec = NewDenseCopiedArray(cx, fieldTypeObjs.length(),
fieldTypeObjs.begin());
if (!fieldTypeVec)
return false;
structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES,
ObjectValue(*fieldTypeVec));
}
// Construct for internal use an array with the offset for each field.
{
AutoValueVector fieldOffsets(cx);
for (size_t i = 0; i < typeRepr->fieldCount(); i++) {
const StructField &field = typeRepr->field(i);
if (!fieldOffsets.append(Int32Value(field.offset)))
return false;
}
RootedObject fieldOffsetsVec(cx);
fieldOffsetsVec = NewDenseCopiedArray(cx, fieldOffsets.length(),
fieldOffsets.begin());
if (!fieldOffsetsVec)
return false;
structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS,
ObjectValue(*fieldOffsetsVec));
}
// Construct the fieldOffsets and fieldTypes objects:
// fieldOffsets : { string: integer, ... }
// fieldTypes : { string: Type, ... }
RootedObject fieldOffsets(cx);
@ -914,6 +929,40 @@ StructMetaTypeDescr::construct(JSContext *cx, unsigned int argc, Value *vp)
return false;
}
bool
StructTypeDescr::fieldIndex(jsid id, size_t *out)
{
JSObject &fieldNames =
getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).toObject();
size_t l = fieldNames.getDenseInitializedLength();
for (size_t i = 0; i < l; i++) {
JSAtom &a = fieldNames.getDenseElement(i).toString()->asAtom();
if (JSID_IS_ATOM(id, &a)) {
*out = i;
return true;
}
}
return false;
}
size_t
StructTypeDescr::fieldOffset(size_t index)
{
JSObject &fieldOffsets =
getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS).toObject();
JS_ASSERT(index < fieldOffsets.getDenseInitializedLength());
return fieldOffsets.getDenseElement(index).toInt32();
}
SizedTypeDescr&
StructTypeDescr::fieldDescr(size_t index)
{
JSObject &fieldDescrs =
getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject();
JS_ASSERT(index < fieldDescrs.getDenseInitializedLength());
return fieldDescrs.getDenseElement(index).toObject().as<SizedTypeDescr>();
}
/******************************************************************************
* Creating the TypedObject "module"
*
@ -1597,34 +1646,6 @@ TypedDatum::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId s
return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
}
static SizedTypeDescr *
StructFieldType(JSContext *cx,
HandleStructTypeDescr type,
int32_t fieldIndex)
{
// Recover the original type object here (`field` contains
// only its canonical form). The difference is observable,
// e.g. in a program like:
//
// var Point1 = new StructType({x:uint8, y:uint8});
// var Point2 = new StructType({x:uint8, y:uint8});
// var Line1 = new StructType({start:Point1, end: Point1});
// var Line2 = new StructType({start:Point2, end: Point2});
// var line1 = new Line1(...);
// var line2 = new Line2(...);
//
// In this scenario, line1.start.type() === Point1 and
// line2.start.type() === Point2.
RootedObject fieldTypes(
cx, &type->getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject());
RootedValue fieldTypeVal(cx);
if (!JSObject::getElement(cx, fieldTypes, fieldTypes,
fieldIndex, &fieldTypeVal))
return nullptr;
return &fieldTypeVal.toObject().as<SizedTypeDescr>();
}
bool
TypedDatum::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp)
@ -1664,20 +1685,15 @@ TypedDatum::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receive
break;
case TypeRepresentation::Struct: {
Rooted<StructTypeDescr*> type(cx);
type = &datum->typeDescr().as<StructTypeDescr>();
Rooted<StructTypeDescr*> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
StructTypeRepresentation *structTypeRepr = typeRepr->asStruct();
const StructField *field = structTypeRepr->fieldNamed(id);
if (!field)
size_t fieldIndex;
if (!descr->fieldIndex(id, &fieldIndex))
break;
Rooted<SizedTypeDescr*> fieldType(cx);
fieldType = StructFieldType(cx, type, field->index);
if (!fieldType)
return false;
return Reify(cx, field->typeRepr, fieldType, datum, field->offset, vp);
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
return Reify(cx, fieldType, datum, offset, vp);
}
}
@ -1751,7 +1767,7 @@ TypedDatum::obj_getArrayElement(JSContext *cx,
elementType = &typeDescr->as<T>().elementType();
SizedTypeRepresentation *elementTypeRepr = elementType->typeRepresentation();
size_t offset = elementTypeRepr->size() * index;
return Reify(cx, elementTypeRepr, elementType, datum, offset, vp);
return Reify(cx, elementType, datum, offset, vp);
}
bool
@ -1793,17 +1809,15 @@ TypedDatum::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
break;
case ScalarTypeRepresentation::Struct: {
const StructField *field = typeRepr->asStruct()->fieldNamed(id);
if (!field)
Rooted<StructTypeDescr*> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
size_t fieldIndex;
if (!descr->fieldIndex(id, &fieldIndex))
break;
Rooted<StructTypeDescr *> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
Rooted<SizedTypeDescr*> fieldType(cx);
fieldType = StructFieldType(cx, descr, field->index);
if (!fieldType)
return false;
return ConvertAndCopyTo(cx, fieldType, datum, field->offset, vp);
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
return ConvertAndCopyTo(cx, fieldType, datum, offset, vp);
}
}

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

@ -337,6 +337,16 @@ class StructMetaTypeDescr : public JSObject
class StructTypeDescr : public SizedTypeDescr {
public:
static const Class class_;
// Set `*out` to the index of the field named `id` and returns true,
// or return false if no such field exists.
bool fieldIndex(jsid id, size_t *out);
// Return the type descr of the field at index `index`.
SizedTypeDescr &fieldDescr(size_t index);
// Return the offset of the field at index `index`.
size_t fieldOffset(size_t index);
};
typedef Handle<StructTypeDescr*> HandleStructTypeDescr;

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

@ -26,6 +26,12 @@
TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZED_ARRAY_LENGTH))
#define DESCR_TYPE(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE)
#define DESCR_STRUCT_FIELD_NAMES(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_NAMES)
#define DESCR_STRUCT_FIELD_TYPES(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES)
#define DESCR_STRUCT_FIELD_OFFSETS(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
// Typed object slots
@ -98,15 +104,15 @@ function DescrToSource(descr) {
case JS_TYPEREPR_STRUCT_KIND:
var result = "new StructType({";
for (var i = 0; i < descr.fieldNames.length; i++) {
var fieldNames = DESCR_STRUCT_FIELD_NAMES(descr);
var fieldTypes = DESCR_STRUCT_FIELD_TYPES(descr);
for (var i = 0; i < fieldNames.length; i++) {
if (i != 0)
result += ", ";
var fieldName = descr.fieldNames[i];
var fieldDescr = descr.fieldTypes[fieldName];
result += fieldName;
result += fieldNames[i];
result += ": ";
result += DescrToSource(fieldDescr);
result += DescrToSource(fieldTypes[i]);
}
result += "})";
return result;
@ -267,21 +273,27 @@ TypedObjectPointer.prototype.moveToElem = function(index) {
return this;
};
TypedObjectPointer.prototype.moveToField = function(propName) {
var fieldNames = DESCR_STRUCT_FIELD_NAMES(this.descr);
var index = fieldNames.indexOf(propName);
if (index != -1)
return this.moveToFieldIndex(index);
ThrowError(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, propName);
return undefined;
}
// Adjust `this` to point at the field `propName`. `this` must be a
// struct type and `propName` must be a valid field name. Returns
// `this`.
TypedObjectPointer.prototype.moveToField = function(propName) {
TypedObjectPointer.prototype.moveToFieldIndex = function(index) {
assert(this.kind() == JS_TYPEREPR_STRUCT_KIND,
"moveToField invoked on non-struct");
assert(HAS_PROPERTY(this.descr.fieldTypes, propName),
"moveToField invoked with undefined field");
"moveToFieldIndex invoked on non-struct");
assert(index >= 0 && index < DESCR_STRUCT_FIELD_NAMES(this.descr).length,
"moveToFieldIndex invoked with invalid field index " + index);
// 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]);
var fieldDescr = DESCR_STRUCT_FIELD_TYPES(this.descr)[index];
var fieldOffset = TO_INT32(DESCR_STRUCT_FIELD_OFFSETS(this.descr)[index]);
assert(IsObject(fieldDescr) && ObjectIsTypeDescr(fieldDescr),
"bad field descr");
@ -462,10 +474,10 @@ TypedObjectPointer.prototype.set = function(fromValue) {
// Adapt each field.
var tempPtr = this.copy();
var fieldNames = this.descr.fieldNames;
var fieldNames = DESCR_STRUCT_FIELD_NAMES(this.descr);
for (var i = 0; i < fieldNames.length; i++) {
var fieldName = fieldNames[i];
tempPtr.reset(this).moveToField(fieldName).set(fromValue[fieldName]);
tempPtr.reset(this).moveToFieldIndex(i).set(fromValue[fieldName]);
}
return;
}

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

@ -32,10 +32,12 @@
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 4
// Slots on struct type objects
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 3
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 3
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 4
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 5
// Maximum number of slots for any descriptor
#define JS_DESCR_SLOTS 5
#define JS_DESCR_SLOTS 6
///////////////////////////////////////////////////////////////////////////
// Slots for type representation objects

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

@ -17,14 +17,10 @@ function assertTypedEqual(type, a_orig, b_orig) {
for (var i = 0; i < type.length; i++)
recur(type.elementType, a[i], b[i]);
} else if (type instanceof StructType) {
for (var idx in type.fieldNames) {
var fieldName = type.fieldNames[idx];
if (type.fieldTypes[fieldName] !== undefined) {
recur(type.fieldTypes[fieldName], a[fieldName], b[fieldName]);
} else {
throw new Error("assertTypedEqual no type for "+
"fieldName: "+fieldName+" in type: "+type.toSource());
}
var fieldNames = Object.getOwnPropertyNames(type.fieldTypes);
for (var i = 0; i < fieldNames.length; i++) {
var fieldName = fieldNames[i];
recur(type.fieldTypes[fieldName], a[fieldName], b[fieldName]);
}
} else {
assertEq(a, b);

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

@ -24,10 +24,11 @@ function runTests() {
assertEq(S.variable, false);
assertEq(S.byteLength, 16);
assertEq(S.byteAlignment, 8);
assertEq(S.fieldNames[0], "x");
assertEq(S.fieldNames[1], "y");
assertEq(S.fieldNames[2], "z");
assertEq(S.fieldNames.length, 3);
var fieldNames = Object.getOwnPropertyNames(S.fieldTypes);
assertEq(fieldNames[0], "x");
assertEq(fieldNames[1], "y");
assertEq(fieldNames[2], "z");
assertEq(fieldNames.length, 3);
assertEq(S.fieldTypes.x, int32);
assertEq(S.fieldTypes.y, uint8);
assertEq(S.fieldTypes.z, float64);

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

@ -65,7 +65,6 @@
macro(escape, escape, "escape") \
macro(eval, eval, "eval") \
macro(false, false_, "false") \
macro(fieldNames, fieldNames, "fieldNames") \
macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
macro(fieldTypes, fieldTypes, "fieldTypes") \
macro(fileName, fileName, "fileName") \