Bug 1669784 - Disallow setting fields/elements of TypedObjects from JS. r=jandem

For now it's sufficient to only support mutating these objects from
Wasm. This will make it so we only need to support type checks on entry
to Wasm functions for now.

Differential Revision: https://phabricator.services.mozilla.com/D92852
This commit is contained in:
Ryan Hunt 2020-10-09 15:42:56 +00:00
parent 1abe7bced9
commit 1681495267
8 changed files with 53 additions and 552 deletions

View file

@ -104,57 +104,6 @@ static inline CheckedInt32 RoundUpToAlignment(CheckedInt32 address,
return ((address + (align - 1)) / align) * align;
}
/*
* Overwrites the contents of `typedObj` at offset `offset` with `val`
* converted to the type `typeObj`. This is done by delegating to
* self-hosted code. This is used for assignments and initializations.
*
* For example, consider the final assignment in this snippet:
*
* var Point = new StructType({x: float32, y: float32});
* var Line = new StructType({from: Point, to: Point});
* var line = new Line();
* line.to = {x: 22, y: 44};
*
* This would result in a call to `ConvertAndCopyTo`
* where:
* - typeObj = Point
* - typedObj = line
* - offset = sizeof(Point) == 8
* - val = {x: 22, y: 44}
* This would result in loading the value of `x`, converting
* it to a float32, and hen storing it at the appropriate offset,
* and then doing the same for `y`.
*
* Note that the type of `typeObj` may not be the
* type of `typedObj` but rather some subcomponent of `typedObj`.
*/
static bool ConvertAndCopyTo(JSContext* cx, HandleTypeDescr typeObj,
HandleTypedObject typedObj, int32_t offset,
HandleAtom name, HandleValue val) {
FixedInvokeArgs<5> args(cx);
args[0].setObject(*typeObj);
args[1].setObject(*typedObj);
args[2].setInt32(offset);
if (name) {
args[3].setString(name);
} else {
args[3].setNull();
}
args[4].set(val);
RootedValue dummy(cx); // ignored by ConvertAndCopyTo
return CallSelfHostedFunction(cx, cx->names().ConvertAndCopyTo, dummy, args,
&dummy);
}
static bool ConvertAndCopyTo(JSContext* cx, HandleTypedObject typedObj,
HandleValue val) {
Rooted<TypeDescr*> type(cx, &typedObj->typeDescr());
return ConvertAndCopyTo(cx, type, typedObj, 0, nullptr, val);
}
/*
* Overwrites the contents of `typedObj` at offset `offset` with `val`
* converted to the type `typeObj`
@ -251,6 +200,25 @@ uint32_t ScalarTypeDescr::alignment(Type t) {
MOZ_CRASH("Invalid type");
}
/*
* Helper method for converting a double into other scalar
* types in the same way that JavaScript would. In particular,
* simple C casting from double to int32_t gets things wrong
* for values like 0xF0000000.
*/
template <typename T>
static T ConvertScalar(double d) {
if (TypeIsFloatingPoint<T>()) {
return T(d);
}
if (TypeIsUnsigned<T>()) {
uint32_t n = JS::ToUint32(d);
return T(n);
}
int32_t n = JS::ToInt32(d);
return T(n);
}
bool ScalarTypeDescr::call(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, args.callee().getClass()->name, 1)) {
@ -553,8 +521,6 @@ ArrayTypeDescr* ArrayMetaTypeDescr::create(JSContext* cx,
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(JS_DESCR_FLAG_ALLOW_CONSTRUCT));
RootedValue elementTypeVal(cx, ObjectValue(*elementType));
if (!DefineDataProperty(cx, obj, cx->names().elementType, elementTypeVal,
@ -807,16 +773,14 @@ JSObject* StructMetaTypeDescr::create(JSContext* cx, HandleObject metaTypeDescr,
return nullptr;
}
return createFromArrays(cx, structTypePrototype,
/* allowConstruct= */ true, ids, fieldTypeObjs,
return createFromArrays(cx, structTypePrototype, ids, fieldTypeObjs,
fieldProps);
}
/* static */
StructTypeDescr* StructMetaTypeDescr::createFromArrays(
JSContext* cx, HandleObject structTypePrototype, bool allowConstruct,
HandleIdVector ids, JS::HandleValueVector fieldTypeObjs,
Vector<StructFieldProps>& fieldProps) {
JSContext* cx, HandleObject structTypePrototype, HandleIdVector ids,
JS::HandleValueVector fieldTypeObjs, Vector<StructFieldProps>& fieldProps) {
StringBuffer stringBuffer(cx); // Canonical string repr
RootedValueVector fieldNames(cx); // Name of each field.
RootedValueVector fieldOffsets(cx); // Offset of each field field.
@ -936,9 +900,6 @@ StructTypeDescr* StructMetaTypeDescr::createFromArrays(
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_FLAGS,
Int32Value(allowConstruct ? JS_DESCR_FLAG_ALLOW_CONSTRUCT : 0));
// Construct for internal use an array with the name for each field.
{
@ -1186,7 +1147,6 @@ static bool DefineSimpleTypeDescr(JSContext* cx, Handle<GlobalObject*> global,
descr->initReservedSlot(JS_DESCR_SLOT_SIZE,
Int32Value(AssertedCast<int32_t>(T::size(type))));
descr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(int32_t(type)));
descr->initReservedSlot(JS_DESCR_SLOT_FLAGS, Int32Value(0));
if (!JS_DefineFunctions(cx, descr, T::typeObjectMethods)) {
return false;
@ -1824,14 +1784,10 @@ bool TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id,
return false;
}
Rooted<TypeDescr*> elementType(cx);
elementType = &typedObj->typeDescr().as<ArrayTypeDescr>().elementType();
size_t offset = elementType->size() * index;
if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, nullptr, v)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE);
return false;
}
return result.succeed();
}
break;
}
@ -1854,14 +1810,10 @@ bool TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id,
return SetPropertyByDefining(cx, id, v, receiver, result);
}
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
RootedAtom fieldName(cx, &descr->fieldName(fieldIndex));
if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, v)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE);
return false;
}
return result.succeed();
}
}
return SetPropertyOnProto(cx, obj, id, v, receiver, result);
@ -2115,51 +2067,9 @@ bool TypedObject::construct(JSContext* cx, unsigned int argc, Value* vp) {
Rooted<TypeDescr*> callee(cx, &args.callee().as<TypeDescr>());
MOZ_ASSERT(cx->realm() == callee->realm());
// Types created by Wasm may not be constructible from JS due to field types
// that are not expressible in the current TypedObject system.
if (callee->is<ComplexTypeDescr>() &&
!callee->as<ComplexTypeDescr>().allowConstruct()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_NOT_CONSTRUCTIBLE);
return false;
}
// Typed object constructors are overloaded in two ways:
//
// new TypeObj()
// new TypeObj(data)
// Zero argument constructor:
if (args.length() == 0) {
Rooted<TypedObject*> obj(cx, createZeroed(cx, callee));
if (!obj) {
return false;
}
args.rval().setObject(*obj);
return true;
}
// Data constructor.
if (args[0].isObject()) {
// Create the typed object.
Rooted<TypedObject*> obj(cx, createZeroed(cx, callee));
if (!obj) {
return false;
}
// Initialize from `arg`.
if (!ConvertAndCopyTo(cx, obj, args[0])) {
return false;
}
args.rval().setObject(*obj);
return true;
}
// Something bogus.
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
/* static */ JS::Result<TypedObject*, JS::OOM> TypedObject::create(
@ -2216,77 +2126,6 @@ bool js::ClampToUint8(JSContext*, unsigned argc, Value* vp) {
return true;
}
#define JS_STORE_NUMBER_CLASS_IMPL(_constant, T, _name) \
bool js::StoreScalar##T::Func(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<TypedObject>()); \
MOZ_RELEASE_ASSERT(args[1].isInt32()); \
MOZ_ASSERT(args[2].isNumber()); \
\
TypedObject& typedObj = args[0].toObject().as<TypedObject>(); \
int32_t offset = args[1].toInt32(); \
\
/* Should be guaranteed by the typed objects API: */ \
MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
\
JS::AutoCheckCannotGC nogc(cx); \
T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc)); \
double d = args[2].toNumber(); \
*target = ConvertScalar<T>(d); \
args.rval().setUndefined(); \
return true; \
}
#define JS_STORE_BIGINT_CLASS_IMPL(_constant, T, _name) \
bool js::StoreScalar##T::Func(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<TypedObject>()); \
MOZ_RELEASE_ASSERT(args[1].isInt32()); \
int32_t offset = args[1].toInt32(); \
BigInt* bi = ToBigInt(cx, args[2]); \
if (!bi) { \
return false; \
} \
TypedObject& typedObj = args[0].toObject().as<TypedObject>(); \
\
/* Should be guaranteed by the typed objects API: */ \
MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
\
JS::AutoCheckCannotGC nogc(cx); \
T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc)); \
*target = ConvertBigInt<T>(bi); \
args.rval().setUndefined(); \
return true; \
}
#define JS_STORE_REFERENCE_CLASS_IMPL(_constant, T, _name) \
bool js::StoreReference##_name::Func(JSContext* cx, unsigned argc, \
Value* vp) { \
CallArgs args = CallArgsFromVp(argc, vp); \
MOZ_ASSERT(args.length() == 4); \
MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>()); \
MOZ_RELEASE_ASSERT(args[1].isInt32()); \
MOZ_ASSERT(args[2].isString() || args[2].isNull()); \
\
TypedObject& typedObj = args[0].toObject().as<TypedObject>(); \
int32_t offset = args[1].toInt32(); \
\
jsid id = args[2].isString() \
? IdToTypeId(AtomToId(&args[2].toString()->asAtom())) \
: JSID_VOID; \
\
/* Should be guaranteed by the typed objects API: */ \
MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
\
JS::AutoCheckCannotGC nogc(cx); \
T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc)); \
if (!store(cx, target, args[3], &typedObj, id)) return false; \
args.rval().setUndefined(); \
return true; \
}
#define JS_LOAD_NUMBER_CLASS_IMPL(_constant, T, _name) \
bool js::LoadScalar##T::Func(JSContext* cx, unsigned argc, Value* vp) { \
CallArgs args = CallArgsFromVp(argc, vp); \
@ -2352,75 +2191,6 @@ bool js::ClampToUint8(JSContext*, unsigned argc, Value* vp) {
return true; \
}
// Because the precise syntax for storing values/objects/strings
// differs, we abstract it away using specialized variants of the
// private methods `store()` and `load()`.
bool StoreReferenceAny::store(JSContext* cx, GCPtrValue* heap, const Value& v,
TypedObject* obj, jsid id) {
// Undefined values are not included in type inference information for
// value properties of typed objects, as these properties are always
// considered to contain undefined.
if (!v.isUndefined()) {
if (!cx->isHelperThreadContext()) {
AddTypePropertyId(cx, obj, id, v);
} else if (!HasTypePropertyId(obj, id, v)) {
return false;
}
}
*heap = v;
return true;
}
bool StoreReferenceObject::store(JSContext* cx, GCPtrObject* heap,
const Value& v, TypedObject* obj, jsid id) {
MOZ_ASSERT(v.isObjectOrNull()); // or else Store_object is being misused
// Null pointers are not included in type inference information for
// object properties of typed objects, as these properties are always
// considered to contain null.
if (v.isObject()) {
if (!cx->isHelperThreadContext()) {
AddTypePropertyId(cx, obj, id, v);
} else if (!HasTypePropertyId(obj, id, v)) {
return false;
}
}
*heap = v.toObjectOrNull();
return true;
}
bool StoreReferenceWasmAnyRef::store(JSContext* cx, GCPtrObject* heap,
const Value& v, TypedObject* obj,
jsid id) {
// At the moment, we allow:
// - null
// - a WasmValueBox object (a NativeObject subtype)
// - any other JSObject* that JS can talk about
//
// TODO/AnyRef-boxing: With boxed immediates and strings this will change.
MOZ_ASSERT(v.isObjectOrNull());
// We do not add any type information for anyref at this time.
*heap = v.toObjectOrNull();
return true;
}
bool StoreReferencestring::store(JSContext* cx, GCPtrString* heap,
const Value& v, TypedObject* obj, jsid id) {
MOZ_ASSERT(v.isString()); // or else Store_string is being misused
// Note: string references are not reflected in type information for the
// object.
*heap = v.toString();
return true;
}
void LoadReferenceAny::load(GCPtrValue* heap, MutableHandleValue v) {
v.set(*heap);
}
@ -2449,11 +2219,8 @@ void LoadReferencestring::load(GCPtrString* heap, MutableHandleValue v) {
// I was using templates for this stuff instead of macros, but ran
// into problems with the Unagi compiler.
JS_FOR_EACH_UNIQUE_SCALAR_NUMBER_TYPE_REPR_CTYPE(JS_STORE_NUMBER_CLASS_IMPL)
JS_FOR_EACH_UNIQUE_SCALAR_NUMBER_TYPE_REPR_CTYPE(JS_LOAD_NUMBER_CLASS_IMPL)
JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(JS_STORE_BIGINT_CLASS_IMPL)
JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(JS_LOAD_BIGINT_CLASS_IMPL)
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_IMPL)
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_IMPL)
///////////////////////////////////////////////////////////////////////////

View file

@ -97,25 +97,6 @@
namespace js {
/*
* Helper method for converting a double into other scalar
* types in the same way that JavaScript would. In particular,
* simple C casting from double to int32_t gets things wrong
* for values like 0xF0000000.
*/
template <typename T>
static T ConvertScalar(double d) {
if (TypeIsFloatingPoint<T>()) {
return T(d);
}
if (TypeIsUnsigned<T>()) {
uint32_t n = JS::ToUint32(d);
return T(n);
}
int32_t n = JS::ToInt32(d);
return T(n);
}
namespace type {
enum Kind {
@ -130,11 +111,6 @@ enum Kind {
///////////////////////////////////////////////////////////////////////////
// Typed Prototypes
class SimpleTypeDescr;
class ComplexTypeDescr;
class StructTypeDescr;
class TypedProto;
/*
* The prototype for a typed object.
*/
@ -203,6 +179,9 @@ class TypeDescr : public NativeObject {
using HandleTypeDescr = Handle<TypeDescr*>;
class SimpleTypeDescr : public TypeDescr {};
// Type descriptors whose instances are objects and hence which have
// an associated `prototype` property.
class ComplexTypeDescr : public TypeDescr {};
// Type for scalar type constructors like `uint8`. All such type
// constructors share a common JSClass and JSFunctionSpec. Scalar
@ -332,18 +311,6 @@ class ReferenceTypeDescr : public SimpleTypeDescr {
MACRO_(ReferenceType::TYPE_OBJECT, GCPtrObject, Object) \
MACRO_(ReferenceType::TYPE_STRING, GCPtrString, string)
// Type descriptors whose instances are objects and hence which have
// an associated `prototype` property.
class ComplexTypeDescr : public TypeDescr {
public:
bool allowConstruct() const {
return getReservedSlot(JS_DESCR_SLOT_FLAGS).toInt32() &
JS_DESCR_FLAG_ALLOW_CONSTRUCT;
}
};
bool IsTypedObjectClass(const JSClass* clasp); // Defined below
class ArrayTypeDescr;
/*
@ -412,6 +379,8 @@ struct StructFieldProps {
uint32_t alignAsV128 : 1;
};
class StructTypeDescr;
/*
* Properties and methods of the `StructType` meta type object. There
* is no `class_` field because `StructType` is just a native
@ -427,9 +396,8 @@ class StructMetaTypeDescr : public NativeObject {
// The names in `ids` must all be non-numeric.
// The type objects in `fieldTypeObjs` must all be TypeDescr objects.
static StructTypeDescr* createFromArrays(
JSContext* cx, HandleObject structTypePrototype, bool allowConstruct,
HandleIdVector ids, HandleValueVector fieldTypeObjs,
Vector<StructFieldProps>& fieldProps);
JSContext* cx, HandleObject structTypePrototype, HandleIdVector ids,
HandleValueVector fieldTypeObjs, Vector<StructFieldProps>& fieldProps);
// Properties and methods to be installed on StructType.prototype,
// and hence inherited by all struct type objects:
@ -752,14 +720,6 @@ MOZ_MUST_USE bool IsBoxedWasmAnyRef(JSContext* cx, unsigned argc, Value* vp);
*/
MOZ_MUST_USE bool IsBoxableWasmAnyRef(JSContext* cx, unsigned argc, Value* vp);
/*
* Usage: BoxWasmAnyRef(Value) -> Object
*
* Return a new WasmValueBox that holds `value`. The value can be any value at
* all.
*/
MOZ_MUST_USE bool BoxWasmAnyRef(JSContext* cx, unsigned argc, Value* vp);
/*
* Usage: UnboxBoxedWasmAnyRef(Object) -> Value
*
@ -768,53 +728,6 @@ MOZ_MUST_USE bool BoxWasmAnyRef(JSContext* cx, unsigned argc, Value* vp);
*/
MOZ_MUST_USE bool UnboxBoxedWasmAnyRef(JSContext* cx, unsigned argc, Value* vp);
/*
* Usage: Store_int8(targetDatum, targetOffset, value)
* ...
* Store_uint8(targetDatum, targetOffset, value)
* ...
* Store_float32(targetDatum, targetOffset, value)
* Store_float64(targetDatum, targetOffset, value)
*
* Intrinsic function. Stores `value` into the memory referenced by
* `targetDatum` at the offset `targetOffset`.
*
* Assumes (and asserts) that:
* - `targetDatum` is attached
* - `targetOffset` is a valid offset within the bounds of `targetDatum`
* - `value` is a number
*/
#define JS_STORE_SCALAR_CLASS_DEFN(_constant, T, _name) \
class StoreScalar##T { \
public: \
static MOZ_MUST_USE bool Func(JSContext* cx, unsigned argc, Value* vp); \
static const JSJitInfo JitInfo; \
};
/*
* Usage: Store_Any(targetDatum, targetOffset, fieldName, value)
* Store_Object(targetDatum, targetOffset, fieldName, value)
* Store_string(targetDatum, targetOffset, fieldName, value)
*
* Intrinsic function. Stores `value` into the memory referenced by
* `targetDatum` at the offset `targetOffset`.
*
* Assumes (and asserts) that:
* - `targetDatum` is attached
* - `targetOffset` is a valid offset within the bounds of `targetDatum`
* - `value` is an object or null (`Store_Object`) or string (`Store_string`).
*/
#define JS_STORE_REFERENCE_CLASS_DEFN(_constant, T, _name) \
class StoreReference##_name { \
private: \
static MOZ_MUST_USE bool store(JSContext* cx, T* heap, const Value& v, \
TypedObject* obj, jsid id); \
\
public: \
static MOZ_MUST_USE bool Func(JSContext* cx, unsigned argc, Value* vp); \
static const JSJitInfo JitInfo; \
};
/*
* Usage: LoadScalar(targetDatum, targetOffset, value)
*
@ -850,11 +763,8 @@ MOZ_MUST_USE bool UnboxBoxedWasmAnyRef(JSContext* cx, unsigned argc, Value* vp);
// I was using templates for this stuff instead of macros, but ran
// into problems with the Unagi compiler.
JS_FOR_EACH_UNIQUE_SCALAR_NUMBER_TYPE_REPR_CTYPE(JS_STORE_SCALAR_CLASS_DEFN)
JS_FOR_EACH_UNIQUE_SCALAR_NUMBER_TYPE_REPR_CTYPE(JS_LOAD_SCALAR_CLASS_DEFN)
JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(JS_STORE_SCALAR_CLASS_DEFN)
JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(JS_LOAD_SCALAR_CLASS_DEFN)
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_DEFN)
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_DEFN)
inline bool IsTypedObjectClass(const JSClass* class_) {

View file

@ -119,168 +119,12 @@ function TypedObjectGetReference(descr, typedObj, offset) {
return undefined;
}
///////////////////////////////////////////////////////////////////////////
// Setting values
//
// The methods in this section modify the data pointed at by `this`.
// Writes `fromValue` into the `typedObj` at offset `offset`, adapting
// it to `descr` as needed. This is the most general entry point
// and works for any type.
function TypedObjectSet(descr, typedObj, offset, name, fromValue) {
switch (DESCR_KIND(descr)) {
case JS_TYPEREPR_SCALAR_KIND:
TypedObjectSetScalar(descr, typedObj, offset, fromValue);
return;
case JS_TYPEREPR_REFERENCE_KIND:
TypedObjectSetReference(descr, typedObj, offset, name, fromValue);
return;
case JS_TYPEREPR_ARRAY_KIND:
var length = DESCR_ARRAY_LENGTH(descr);
if (TypedObjectSetArray(descr, length, typedObj, offset, fromValue))
return;
break;
case JS_TYPEREPR_STRUCT_KIND:
if (!IsObject(fromValue))
break;
// Adapt each field.
var fieldNames = DESCR_STRUCT_FIELD_NAMES(descr);
var fieldDescrs = DESCR_STRUCT_FIELD_TYPES(descr);
var fieldOffsets = DESCR_STRUCT_FIELD_OFFSETS(descr);
for (var i = 0; i < fieldNames.length; i++) {
var fieldName = fieldNames[i];
var fieldDescr = fieldDescrs[i];
var fieldOffset = fieldOffsets[i];
var fieldValue = fromValue[fieldName];
TypedObjectSet(fieldDescr, typedObj, offset + fieldOffset, fieldName, fieldValue);
}
return;
}
ThrowTypeError(JSMSG_CANT_CONVERT_TO,
typeof(fromValue),
DESCR_STRING_REPR(descr));
}
function TypedObjectSetArray(descr, length, typedObj, offset, fromValue) {
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 elemDescr = DESCR_ARRAY_ELEMENT_TYPE(descr);
var elemSize = DESCR_SIZE(elemDescr);
var elemOffset = offset;
for (var i = 0; i < length; i++) {
TypedObjectSet(elemDescr, typedObj, elemOffset, null, fromValue[i]);
elemOffset += elemSize;
}
}
return true;
}
// Sets `fromValue` to `this` assuming that `this` is a scalar type.
function TypedObjectSetScalar(descr, typedObj, offset, fromValue) {
assert(DESCR_KIND(descr) === JS_TYPEREPR_SCALAR_KIND,
"Expected scalar type descriptor");
var type = DESCR_TYPE(descr);
switch (type) {
case JS_SCALARTYPEREPR_INT8:
return Store_int8(typedObj, offset | 0,
TO_INT32(fromValue) & 0xFF);
case JS_SCALARTYPEREPR_UINT8:
return Store_uint8(typedObj, offset | 0,
TO_UINT32(fromValue) & 0xFF);
case JS_SCALARTYPEREPR_UINT8_CLAMPED:
var v = ClampToUint8(+fromValue);
return Store_int8(typedObj, offset | 0, v);
case JS_SCALARTYPEREPR_INT16:
return Store_int16(typedObj, offset | 0,
TO_INT32(fromValue) & 0xFFFF);
case JS_SCALARTYPEREPR_UINT16:
return Store_uint16(typedObj, offset | 0,
TO_UINT32(fromValue) & 0xFFFF);
case JS_SCALARTYPEREPR_INT32:
return Store_int32(typedObj, offset | 0,
TO_INT32(fromValue));
case JS_SCALARTYPEREPR_UINT32:
return Store_uint32(typedObj, offset | 0,
TO_UINT32(fromValue));
case JS_SCALARTYPEREPR_FLOAT32:
return Store_float32(typedObj, offset | 0, +fromValue);
case JS_SCALARTYPEREPR_FLOAT64:
return Store_float64(typedObj, offset | 0, +fromValue);
case JS_SCALARTYPEREPR_BIGINT64:
return Store_bigint64(typedObj, offset | 0, fromValue);
case JS_SCALARTYPEREPR_BIGUINT64:
return Store_biguint64(typedObj, offset | 0, fromValue);
}
assert(false, "Unhandled scalar type: " + type);
return undefined;
}
function TypedObjectSetReference(descr, typedObj, offset, name, fromValue) {
var type = DESCR_TYPE(descr);
switch (type) {
case JS_REFERENCETYPEREPR_ANY:
return Store_Any(typedObj, offset | 0, name, fromValue);
case JS_REFERENCETYPEREPR_OBJECT:
var value = (fromValue === null ? fromValue : ToObject(fromValue));
return Store_Object(typedObj, offset | 0, name, value);
case JS_REFERENCETYPEREPR_WASM_ANYREF:
var value = (IsBoxableWasmAnyRef(fromValue) ? BoxWasmAnyRef(fromValue) : fromValue);
return Store_WasmAnyRef(typedObj, offset | 0, name, value);
case JS_REFERENCETYPEREPR_STRING:
return Store_string(typedObj, offset | 0, name, ToString(fromValue));
}
assert(false, "Unhandled scalar type: " + type);
return undefined;
}
// Sets `fromValue` to `this` assuming that `this` is a scalar type.
///////////////////////////////////////////////////////////////////////////
// C++ Wrappers
//
// These helpers are invoked by C++ code or used as method bodies.
// Wrapper for use from C++ code.
function ConvertAndCopyTo(destDescr,
destTypedObj,
destOffset,
fieldName,
fromValue)
{
assert(IsObject(destDescr) && ObjectIsTypeDescr(destDescr),
"ConvertAndCopyTo: not type obj");
assert(IsObject(destTypedObj) && ObjectIsTypedObject(destTypedObj),
"ConvertAndCopyTo: not type typedObj");
TypedObjectSet(destDescr, destTypedObj, destOffset, fieldName, fromValue);
}
// Wrapper for use from C++ code.
function Reify(sourceDescr,
sourceTypedObj,

View file

@ -44,25 +44,22 @@
#define JS_DESCR_SLOT_TYPROTO 4 // Prototype for instances, if any
#define JS_DESCR_SLOT_ARRAYPROTO 5 // Lazily created prototype for arrays
#define JS_DESCR_SLOT_TRACE_LIST 6 // List of references for use in tracing
#define JS_DESCR_SLOT_FLAGS 7 // int32 bitvector of JS_DESCR_FLAG_*
// Slots on scalars, references
#define JS_DESCR_SLOT_TYPE 8 // Type code
#define JS_DESCR_SLOT_TYPE 7 // 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 7
#define JS_DESCR_SLOT_ARRAY_LENGTH 8
// 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_MUTS 11
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 7
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 8
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 9
#define JS_DESCR_SLOT_STRUCT_FIELD_MUTS 10
// Maximum number of slots for any descriptor
#define JS_DESCR_SLOTS 12
#define JS_DESCR_FLAG_ALLOW_CONSTRUCT 1 // Allow structure to be constructed
#define JS_DESCR_SLOTS 11
// These constants are for use exclusively in JS code. In C++ code,
// prefer TypeRepresentation::Scalar etc, which allows you to

View file

@ -95,7 +95,6 @@
"constructContentFunction") \
MACRO(constructor, constructor, "constructor") \
MACRO(continue, continue_, "continue") \
MACRO(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \
MACRO(CopyDataProperties, CopyDataProperties, "CopyDataProperties") \
MACRO(CopyDataPropertiesUnfiltered, CopyDataPropertiesUnfiltered, \
"CopyDataPropertiesUnfiltered") \

View file

@ -2443,25 +2443,22 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("IsBoxedWasmAnyRef", js::IsBoxedWasmAnyRef, 1, 0),
JS_FN("IsBoxableWasmAnyRef", js::IsBoxableWasmAnyRef, 1, 0),
JS_FN("BoxWasmAnyRef", js::BoxWasmAnyRef, 1, 0),
JS_FN("UnboxBoxedWasmAnyRef", js::UnboxBoxedWasmAnyRef, 1, 0),
// clang-format off
#define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name) \
JS_FN("Store_" #_name, js::StoreScalar##_type::Func, 3, 0), \
#define LOAD_SCALAR_FN_DECLS(_constant, _type, _name) \
JS_FN("Load_" #_name, js::LoadScalar##_type::Func, 3, 0),
JS_FOR_EACH_UNIQUE_SCALAR_NUMBER_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(LOAD_AND_STORE_SCALAR_FN_DECLS)
JS_FOR_EACH_UNIQUE_SCALAR_NUMBER_TYPE_REPR_CTYPE(LOAD_SCALAR_FN_DECLS)
JS_FOR_EACH_SCALAR_BIGINT_TYPE_REPR(LOAD_SCALAR_FN_DECLS)
// clang-format on
#undef LOAD_AND_STORE_SCALAR_FN_DECLS
#undef LOAD_SCALAR_FN_DECLS
// clang-format off
#define LOAD_AND_STORE_REFERENCE_FN_DECLS(_constant, _type, _name) \
JS_FN("Store_" #_name, js::StoreReference##_name::Func, 3, 0), \
#define LOAD_REFERENCE_FN_DECLS(_constant, _type, _name) \
JS_FN("Load_" #_name, js::LoadReference##_name::Func, 3, 0),
JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_AND_STORE_REFERENCE_FN_DECLS)
JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_REFERENCE_FN_DECLS)
// clang-format on
#undef LOAD_AND_STORE_REFERENCE_FN_DECLS
#undef LOAD_REFERENCE_FN_DECLS
#ifdef JS_HAS_INTL_API
// See builtin/intl/*.h for descriptions of the intl_* functions.

View file

@ -1266,7 +1266,6 @@ bool Module::makeStructTypeDescrs(
RootedIdVector ids(cx);
RootedValueVector fieldTypeObjs(cx);
Vector<StructFieldProps> fieldProps(cx);
bool allowConstruct = true;
uint32_t k = 0;
for (StructField sf : structType.fields_) {
@ -1279,7 +1278,6 @@ bool Module::makeStructTypeDescrs(
// from JS. Wasm however sees one i64 field with appropriate
// mutability.
sf.isMutable = false;
allowConstruct = false;
if (!MakeStructField(cx, ValType::I64, sf.isMutable, "_%d_low", k, &ids,
&fieldTypeObjs, &fieldProps)) {
@ -1293,7 +1291,6 @@ bool Module::makeStructTypeDescrs(
// Ditto v128 fields. These turn into four adjacent i32 fields, using
// the standard xyzw convention.
sf.isMutable = false;
allowConstruct = false;
if (!MakeStructField(cx, ValType::V128, sf.isMutable, "_%d_x", k, &ids,
&fieldTypeObjs, &fieldProps)) {
@ -1321,7 +1318,6 @@ bool Module::makeStructTypeDescrs(
if (v.isTypeIndex()) {
// Validation ensures that v references a struct type here.
sf.isMutable = false;
allowConstruct = false;
}
if (!MakeStructField(cx, v, sf.isMutable, "_%d", k++, &ids,
@ -1336,8 +1332,8 @@ bool Module::makeStructTypeDescrs(
// prevent JS from constructing instances of them.
Rooted<StructTypeDescr*> structTypeDescr(
cx, StructMetaTypeDescr::createFromArrays(
cx, prototype, allowConstruct, ids, fieldTypeObjs, fieldProps));
cx, StructMetaTypeDescr::createFromArrays(cx, prototype, ids,
fieldTypeObjs, fieldProps));
if (!structTypeDescr || !structTypeDescrs.append(structTypeDescr)) {
return false;

View file

@ -178,15 +178,6 @@ bool js::IsBoxableWasmAnyRef(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
bool js::BoxWasmAnyRef(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
WasmValueBox* box = WasmValueBox::create(cx, args[0]);
if (!box) return false;
args.rval().setObject(*box);
return true;
}
bool js::UnboxBoxedWasmAnyRef(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);