зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1478982 - Allow TypedObject fields to be flagged immutable. r=till
This allows internal clients (notably Wasm) to flag TO fields as immutable; we need this both to provide immutability for fields that are declared immutable in wasm structs, and to temporarily avoid the need for type constraints on assignments to Ref-typed pointer fields. --HG-- extra : rebase_source : 19d1b1bf81396ca305b699cda0277fd8e41f5fe9 extra : intermediate-source : d219c9587f920a0f5924dbdab3e8cf5dfecf3f75 extra : source : f1161dd31ac1cf6f050315d04b978b9d6c0c824a
This commit is contained in:
Родитель
39bda38c95
Коммит
27be8bc412
|
@ -547,6 +547,7 @@ ArrayMetaTypeDescr::create(JSContext* cx,
|
|||
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));
|
||||
obj->initReservedSlot(JS_DESCR_SLOT_FLAGS, Int32Value(0));
|
||||
|
||||
RootedValue elementTypeVal(cx, ObjectValue(*elementType));
|
||||
if (!DefineDataProperty(cx, obj, cx->names().elementType, elementTypeVal,
|
||||
|
@ -767,6 +768,8 @@ StructMetaTypeDescr::create(JSContext* cx,
|
|||
AutoValueVector fieldTypeObjs(cx); // Type descriptor of each field.
|
||||
bool opaque = false; // Opacity of struct.
|
||||
|
||||
Vector<bool> fieldMutabilities(cx);
|
||||
|
||||
RootedValue fieldTypeVal(cx);
|
||||
RootedId id(cx);
|
||||
Rooted<TypeDescr*> fieldType(cx);
|
||||
|
@ -796,6 +799,10 @@ StructMetaTypeDescr::create(JSContext* cx,
|
|||
if (!fieldTypeObjs.append(ObjectValue(*fieldType)))
|
||||
return nullptr;
|
||||
|
||||
// Along this path everything is mutable
|
||||
if (!fieldMutabilities.append(true))
|
||||
return nullptr;
|
||||
|
||||
// Struct is opaque if any field is opaque
|
||||
if (fieldType->opaque())
|
||||
opaque = true;
|
||||
|
@ -805,7 +812,7 @@ StructMetaTypeDescr::create(JSContext* cx,
|
|||
if (!structTypePrototype)
|
||||
return nullptr;
|
||||
|
||||
return createFromArrays(cx, structTypePrototype, opaque, ids, fieldTypeObjs);
|
||||
return createFromArrays(cx, structTypePrototype, opaque, ids, fieldTypeObjs, fieldMutabilities);
|
||||
}
|
||||
|
||||
/* static */ StructTypeDescr*
|
||||
|
@ -813,11 +820,13 @@ StructMetaTypeDescr::createFromArrays(JSContext* cx,
|
|||
HandleObject structTypePrototype,
|
||||
bool opaque,
|
||||
AutoIdVector& ids,
|
||||
AutoValueVector& fieldTypeObjs)
|
||||
AutoValueVector& fieldTypeObjs,
|
||||
Vector<bool>& fieldMutabilities)
|
||||
{
|
||||
StringBuffer stringBuffer(cx); // Canonical string repr
|
||||
AutoValueVector fieldNames(cx); // Name of each field.
|
||||
AutoValueVector fieldOffsets(cx); // Offset of each field field.
|
||||
AutoValueVector fieldMuts(cx); // Mutability of each field.
|
||||
RootedObject userFieldOffsets(cx); // User-exposed {f:offset} object
|
||||
RootedObject userFieldTypes(cx); // User-exposed {f:descr} object.
|
||||
Layout layout; // Field offsetter
|
||||
|
@ -872,6 +881,9 @@ StructMetaTypeDescr::createFromArrays(JSContext* cx,
|
|||
if (!fieldOffsets.append(Int32Value(offset.value())))
|
||||
return nullptr;
|
||||
|
||||
if (!fieldMuts.append(BooleanValue(fieldMutabilities[i])))
|
||||
return nullptr;
|
||||
|
||||
// userFieldOffsets[id] = offset
|
||||
RootedValue offsetValue(cx, Int32Value(offset.value()));
|
||||
if (!DefineDataProperty(cx, userFieldOffsets, id, offsetValue,
|
||||
|
@ -908,6 +920,7 @@ StructMetaTypeDescr::createFromArrays(JSContext* cx,
|
|||
descr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(AssertedCast<int32_t>(alignment)));
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(totalSize.value()));
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(opaque));
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_FLAGS, Int32Value(0));
|
||||
|
||||
// Construct for internal use an array with the name for each field.
|
||||
{
|
||||
|
@ -940,7 +953,19 @@ StructMetaTypeDescr::createFromArrays(JSContext* cx,
|
|||
descr->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS, ObjectValue(*fieldOffsetsVec));
|
||||
}
|
||||
|
||||
// Construct for internal use an array with the mutability for each field.
|
||||
{
|
||||
RootedObject fieldMutsVec(cx);
|
||||
fieldMutsVec = NewDenseCopiedArray(cx, fieldMuts.length(),
|
||||
fieldMuts.begin(), nullptr,
|
||||
TenuredObject);
|
||||
if (!fieldMutsVec)
|
||||
return nullptr;
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_MUTS, ObjectValue(*fieldMutsVec));
|
||||
}
|
||||
|
||||
// Create data properties fieldOffsets and fieldTypes
|
||||
// TODO: Probably also want to track mutability here, but not important yet.
|
||||
if (!FreezeObject(cx, userFieldOffsets))
|
||||
return nullptr;
|
||||
if (!FreezeObject(cx, userFieldTypes))
|
||||
|
@ -1041,6 +1066,14 @@ StructTypeDescr::fieldOffset(size_t index) const
|
|||
return AssertedCast<size_t>(fieldOffsets.getDenseElement(index).toInt32());
|
||||
}
|
||||
|
||||
bool
|
||||
StructTypeDescr::fieldIsMutable(size_t index) const
|
||||
{
|
||||
ArrayObject& fieldMuts = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_MUTS);
|
||||
MOZ_ASSERT(index < fieldMuts.getDenseInitializedLength());
|
||||
return fieldMuts.getDenseElement(index).toBoolean();
|
||||
}
|
||||
|
||||
TypeDescr&
|
||||
StructTypeDescr::fieldDescr(size_t index) const
|
||||
{
|
||||
|
@ -1133,6 +1166,7 @@ DefineSimpleTypeDescr(JSContext* cx,
|
|||
descr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(AssertedCast<int32_t>(T::size(type))));
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(T::Opaque));
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(int32_t(type)));
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_FLAGS, Int32Value(0));
|
||||
|
||||
if (!CreateUserSizeAndAlignmentProperties(cx, descr))
|
||||
return false;
|
||||
|
@ -1874,6 +1908,12 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl
|
|||
if (!descr->fieldIndex(id, &fieldIndex))
|
||||
break;
|
||||
|
||||
if (!descr->fieldIsMutable(fieldIndex)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!receiver.isObject() || obj != &receiver.toObject())
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
|
||||
|
|
|
@ -417,7 +417,8 @@ class StructMetaTypeDescr : public NativeObject
|
|||
HandleObject structTypePrototype,
|
||||
bool opaque,
|
||||
AutoIdVector& ids,
|
||||
AutoValueVector& fieldTypeObjs);
|
||||
AutoValueVector& fieldTypeObjs,
|
||||
Vector<bool>& fieldMutabilities);
|
||||
|
||||
// Properties and methods to be installed on StructType.prototype,
|
||||
// and hence inherited by all struct type objects:
|
||||
|
@ -476,6 +477,9 @@ class StructTypeDescr : public ComplexTypeDescr
|
|||
// Return the offset of the field at index `index`.
|
||||
size_t fieldOffset(size_t index) const;
|
||||
|
||||
// Return the mutability of the field at index `index`.
|
||||
bool fieldIsMutable(size_t index) const;
|
||||
|
||||
static bool call(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
private:
|
||||
|
|
|
@ -52,21 +52,23 @@
|
|||
#define JS_DESCR_SLOT_TYPROTO 5 // Prototype for instances, if any
|
||||
#define JS_DESCR_SLOT_ARRAYPROTO 6 // Lazily created prototype for arrays
|
||||
#define JS_DESCR_SLOT_TRACE_LIST 7 // List of references for use in tracing
|
||||
#define JS_DESCR_SLOT_FLAGS 8 // int32 bitvector of JS_DESCR_FLAG_*
|
||||
|
||||
// Slots on scalars, references
|
||||
#define JS_DESCR_SLOT_TYPE 8 // Type code
|
||||
#define JS_DESCR_SLOT_TYPE 9 // Type code
|
||||
|
||||
// Slots on array descriptors
|
||||
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 8
|
||||
#define JS_DESCR_SLOT_ARRAY_LENGTH 9
|
||||
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 9
|
||||
#define JS_DESCR_SLOT_ARRAY_LENGTH 10
|
||||
|
||||
// Slots on struct type objects
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 8
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 9
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 10
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 9
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 10
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 11
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_MUTS 12
|
||||
|
||||
// Maximum number of slots for any descriptor
|
||||
#define JS_DESCR_SLOTS 11
|
||||
#define JS_DESCR_SLOTS 13
|
||||
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer TypeRepresentation::Scalar etc, which allows you to
|
||||
|
|
|
@ -10574,7 +10574,8 @@ IonBuilder::getPropTryTypedObject(bool* emitted,
|
|||
TypedObjectPrediction fieldPrediction;
|
||||
size_t fieldOffset;
|
||||
size_t fieldIndex;
|
||||
if (!typedObjectHasField(obj, name, &fieldOffset, &fieldPrediction, &fieldIndex))
|
||||
bool fieldMutable;
|
||||
if (!typedObjectHasField(obj, name, &fieldOffset, &fieldPrediction, &fieldIndex, &fieldMutable))
|
||||
return Ok();
|
||||
|
||||
switch (fieldPrediction.kind()) {
|
||||
|
@ -11716,7 +11717,11 @@ IonBuilder::setPropTryTypedObject(bool* emitted, MDefinition* obj,
|
|||
TypedObjectPrediction fieldPrediction;
|
||||
size_t fieldOffset;
|
||||
size_t fieldIndex;
|
||||
if (!typedObjectHasField(obj, name, &fieldOffset, &fieldPrediction, &fieldIndex))
|
||||
bool fieldMutable;
|
||||
if (!typedObjectHasField(obj, name, &fieldOffset, &fieldPrediction, &fieldIndex, &fieldMutable))
|
||||
return Ok();
|
||||
|
||||
if (!fieldMutable)
|
||||
return Ok();
|
||||
|
||||
switch (fieldPrediction.kind()) {
|
||||
|
@ -13486,7 +13491,8 @@ IonBuilder::typedObjectHasField(MDefinition* typedObj,
|
|||
PropertyName* name,
|
||||
size_t* fieldOffset,
|
||||
TypedObjectPrediction* fieldPrediction,
|
||||
size_t* fieldIndex)
|
||||
size_t* fieldIndex,
|
||||
bool* fieldMutable)
|
||||
{
|
||||
TypedObjectPrediction objPrediction = typedObjectPrediction(typedObj);
|
||||
if (objPrediction.isUseless()) {
|
||||
|
@ -13502,7 +13508,7 @@ IonBuilder::typedObjectHasField(MDefinition* typedObj,
|
|||
|
||||
// Determine the type/offset of the field `name`, if any.
|
||||
if (!objPrediction.hasFieldNamed(NameToId(name), fieldOffset,
|
||||
fieldPrediction, fieldIndex))
|
||||
fieldPrediction, fieldIndex, fieldMutable))
|
||||
{
|
||||
trackOptimizationOutcome(TrackedOutcome::StructNoField);
|
||||
return false;
|
||||
|
|
|
@ -357,7 +357,8 @@ class IonBuilder
|
|||
PropertyName* name,
|
||||
size_t* fieldOffset,
|
||||
TypedObjectPrediction* fieldTypeReprs,
|
||||
size_t* fieldIndex);
|
||||
size_t* fieldIndex,
|
||||
bool* fieldMutable);
|
||||
MDefinition* loadTypedObjectType(MDefinition* value);
|
||||
AbortReasonOr<Ok> loadTypedObjectData(MDefinition* typedObj,
|
||||
MDefinition** owner,
|
||||
|
|
|
@ -256,7 +256,8 @@ TypedObjectPrediction::hasFieldNamedPrefix(const StructTypeDescr& descr,
|
|||
jsid id,
|
||||
size_t* fieldOffset,
|
||||
TypedObjectPrediction* out,
|
||||
size_t* index) const
|
||||
size_t* index,
|
||||
bool* isMutable) const
|
||||
{
|
||||
// Find the index of the field |id| if any.
|
||||
if (!descr.fieldIndex(id, index))
|
||||
|
@ -269,6 +270,7 @@ TypedObjectPrediction::hasFieldNamedPrefix(const StructTypeDescr& descr,
|
|||
// Load the offset and type.
|
||||
*fieldOffset = descr.fieldOffset(*index);
|
||||
*out = TypedObjectPrediction(descr.fieldDescr(*index));
|
||||
*isMutable = descr.fieldIsMutable(*index);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -276,7 +278,8 @@ bool
|
|||
TypedObjectPrediction::hasFieldNamed(jsid id,
|
||||
size_t* fieldOffset,
|
||||
TypedObjectPrediction* fieldType,
|
||||
size_t* fieldIndex) const
|
||||
size_t* fieldIndex,
|
||||
bool* fieldMutable) const
|
||||
{
|
||||
MOZ_ASSERT(kind() == type::Struct);
|
||||
|
||||
|
@ -288,12 +291,12 @@ TypedObjectPrediction::hasFieldNamed(jsid id,
|
|||
case TypedObjectPrediction::Descr:
|
||||
return hasFieldNamedPrefix(
|
||||
descr().as<StructTypeDescr>(), ALL_FIELDS,
|
||||
id, fieldOffset, fieldType, fieldIndex);
|
||||
id, fieldOffset, fieldType, fieldIndex, fieldMutable);
|
||||
|
||||
case TypedObjectPrediction::Prefix:
|
||||
return hasFieldNamedPrefix(
|
||||
*prefix().descr, prefix().fields,
|
||||
id, fieldOffset, fieldType, fieldIndex);
|
||||
id, fieldOffset, fieldType, fieldIndex, fieldMutable);
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad prediction kind");
|
||||
|
|
|
@ -110,7 +110,8 @@ class TypedObjectPrediction {
|
|||
jsid id,
|
||||
size_t* fieldOffset,
|
||||
TypedObjectPrediction* out,
|
||||
size_t* index) const;
|
||||
size_t* index,
|
||||
bool* isMutable) const;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -192,7 +193,8 @@ class TypedObjectPrediction {
|
|||
bool hasFieldNamed(jsid id,
|
||||
size_t* fieldOffset,
|
||||
TypedObjectPrediction* fieldType,
|
||||
size_t* fieldIndex) const;
|
||||
size_t* fieldIndex,
|
||||
bool* fieldMutable) const;
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -543,6 +543,7 @@ MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattache
|
|||
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_NOT_CALLABLE, 0, JSEXN_TYPEERR, "not callable")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 0, JSEXN_ERR, "Type is too large to allocate")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE, 0, JSEXN_ERR, "setting immutable field")
|
||||
|
||||
// Array
|
||||
MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array")
|
||||
|
|
Загрузка…
Ссылка в новой задаче