High CVSS 9.8 firefox Type Confusion 🔧 Commit mapped

Overview

High
Severity
9.8
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionA difference in the handling of StructFields and ArrayTypes in WASM could be used to trigger an exploitable type confusion vulnerability.
ComponentSpiderMonkey
Bug ClassType Confusion
Tracker1911909
Fix commit2b52328447f7 (firefox) +144/-160
CWECWE-843 (Type confusion)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedSeunghyun Lee
Disclosed2024-09-03

Background

WASM GC
A SpiderMonkey feature that lets WebAssembly modules define managed heap objects such as structs and arrays, whose fields are described by type metadata.
`StructType`
The type descriptor for a WASM struct that holds a fields_ vector describing each field’s StorageType and its byte layout within inline or outline storage.
`FieldType` / `StructField`
Two distinct representations of a field descriptor; the fix migrates code to FieldType and computes offsets via structType.fieldOffset() rather than reading a raw offset member.
`BaseCompiler`
The WASM baseline (fast, non-optimizing) code generator whose emit* methods lower GC struct/array opcodes directly to machine code.

Root Cause Analysis

The baseline compiler’s GC struct and array emitters accessed field and element metadata through a stale representation, reading arrayType.elementType_ directly and computing a struct field’s location from a raw field.offset / structType.fields_[fieldIndex].offset member instead of the canonical structType.fieldOffset(fieldIndex) accessor. Because StructField and ArrayType/FieldType layouts diverged, the raw elementType_ and offset values no longer described the true in-memory layout of the object, so the invariant that the compiler’s computed offset and element size match the actual allocated object layout was violated. An attacker-controlled combination of struct/array type definitions could therefore make emitStructGet, emitStructSet, emitArrayGet, and emitArraySet read or write at a mismatched offset or with a mismatched element size, producing type confusion between a scalar and a reference field.

The fix replaces every direct elementType_ access with the elementType() accessor and every raw offset read with structType.fieldOffset(fieldIndex), and retypes the field variables from StructField to FieldType, so all layout decisions flow through the single authoritative source.

Key insight
The core mistake was that the baseline compiler trusted a raw, out-of-sync offset/elementType_ field descriptor instead of the canonical layout accessors, allowing a scalar field to be treated as a reference (or vice versa); the fix routes every layout query through elementType() and fieldOffset(), eliminating the divergence that enabled type confusion.

Attack Path

  1. Define crafted GC types The attacker authors a WASM module declaring StructType and array types whose FieldType layout differs from what the stale StructField::offset / elementType_ members report.
  2. Trigger baseline compilation Execution routes the module through BaseCompiler, whose emitStructNew, emitStructGet, emitStructSet, and array emitters lower field accesses using the mismatched raw offsets and element size.
  3. Induce type confusion A read or write via emitStructGet/emitArraySet lands at the wrong offset or misinterprets a reference slot as a scalar (or the reverse), so a controlled integer is treated as a managed pointer.
  4. Corrupt object state By writing a chosen value into a slot the engine believes holds a ref, the attacker forges an object pointer or otherwise gains an out-of-bounds/mistyped access primitive.
  5. Escalate The forged pointer is leveraged into arbitrary read/write within the content process, leading to code execution.

Impact Assessment

An attacker who can run WebAssembly in the browser gains a type-confusion primitive that lets them read and write memory with a mismatched interpretation of struct fields or array elements, ultimately enabling arbitrary code execution inside the content (renderer) process. Exploitation runs in the sandboxed content process and requires only that the victim load an attacker-controlled page whose WASM module reaches the baseline compiler, with no further user interaction. The bug is rated high impact because it is remotely reachable and yields a reliable memory-corruption foothold.

Changed Functions

FunctionChangeNotes
while
js/src/wasm/WasmBaselineCompile.cpp
modified
if
js/src/wasm/WasmBaselineCompile.cpp
modified
for
js/src/wasm/WasmDump.cpp
modified
if
js/src/wasm/WasmDump.cpp
modified
for
js/src/wasm/WasmGcObject.cpp
modified

Files Changed

  • js/src/wasm/WasmBaselineCompile.cpp
  • js/src/wasm/WasmDump.cpp
  • js/src/wasm/WasmGcObject-inl.h
  • js/src/wasm/WasmGcObject.cpp
  • js/src/wasm/WasmGcObject.h
  • js/src/wasm/WasmInstance.cpp
  • js/src/wasm/WasmIonCompile.cpp
  • js/src/wasm/WasmOpIter.h
  • js/src/wasm/WasmPI.cpp
  • js/src/wasm/WasmSerialize.cpp
  • js/src/wasm/WasmTypeDef.cpp
  • js/src/wasm/WasmTypeDef.h
  • js/src/wasm/WasmValidate.cpp

Audit Directions

  • Duplicate layout sources
    Search for any remaining direct reads of elementType_ or a raw offset/fields_[...].offset member and require all layout queries to go through elementType() and fieldOffset().
  • Baseline vs. Ion parity
    Compare BaseCompiler GC emitters against WasmIonCompile.cpp to confirm both compilers derive struct/array offsets and element sizes from the same canonical accessors.
  • Type-descriptor migrations
    When StructField, FieldType, and ArrayType representations are refactored, audit every consumer for stale members that were left pointing at the old layout, since divergence there reintroduces type confusion.
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index 3e92169aa25..816309e359d 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -7376,7 +7376,7 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
   // shift immediate. If not we shift the index manually and then unshift
   // it after the store. We don't use an extra register for this because we
   // don't have any to spare on x86.
-  uint32_t shift = arrayType.elementType_.indexingShift();
+  uint32_t shift = arrayType.elementType().indexingShift();
   Scale scale;
   bool shiftedIndex = false;
   if (IsShiftInScaleRange(shift)) {
@@ -7393,9 +7393,9 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
   });
 
   // Easy path if the field is a scalar
-  if (!arrayType.elementType_.isRefRepr()) {
+  if (!arrayType.elementType().isRefRepr()) {
     emitGcSetScalar<BaseIndex, NoNullCheck>(BaseIndex(data, index, scale, 0),
-                                            arrayType.elementType_, value);
+                                            arrayType.elementType(), value);
     return true;
   }
 
@@ -7537,9 +7537,9 @@ bool BaseCompiler::emitStructNew() {
 
   uint32_t fieldIndex = structType.fields_.length();
   while (fieldIndex-- > 0) {
-    const StructField& field = structType.fields_[fieldIndex];
+    const FieldType& field = structType.fields_[fieldIndex];
     StorageType type = field.type;
-    uint32_t fieldOffset = field.offset;
+    uint32_t fieldOffset = structType.fieldOffset(fieldIndex);
 
     bool areaIsOutline;
     uint32_t areaOffset;
@@ -7626,7 +7626,7 @@ bool BaseCompiler::emitStructGet(FieldWideningOp wideningOp) {
 
   // Decide whether we're accessing inline or outline, and at what offset
   StorageType fieldType = structType.fields_[fieldIndex].type;
-  uint32_t fieldOffset = structType.fields_[fieldIndex].offset;
+  uint32_t fieldOffset = structType.fieldOffset(fieldIndex);
 
   bool areaIsOutline;
   uint32_t areaOffset;
@@ -7667,11 +7667,11 @@ bool BaseCompiler::emitStructSet() {
   }
 
   const StructType& structType = (*codeMeta_.types)[typeIndex].structType();
-  const StructField& structField = structType.fields_[fieldIndex];
+  const FieldType& structField = structType.fields_[fieldIndex];
 
   // Decide whether we're accessing inline or outline, and at what offset
   StorageType fieldType = structType.fields_[fieldIndex].type;
-  uint32_t fieldOffset = structType.fields_[fieldIndex].offset;
+  uint32_t fieldOffset = structType.fieldOffset(fieldIndex);
 
   bool areaIsOutline;
   uint32_t areaOffset;
@@ -7845,14 +7845,14 @@ bool BaseCompiler::emitArrayNew() {
 
   // Reserve this register early if we will need it so that it is not taken by
   // any register used in this function.
-  if (arrayType.elementType_.isRefRepr()) {
+  if (arrayType.elementType().isRefRepr()) {
     needPtr(RegPtr(PreBarrierReg));
   }
 
   RegRef object = needRef();
   RegI32 numElements = popI32();
   if (!emitArrayAlloc<false>(typeIndex, object, numElements,
-                             arrayType.elementType_.size())) {
+                             arrayType.elementType().size())) {
     return false;
   }
 
@@ -7865,7 +7865,7 @@ bool BaseCompiler::emitArrayNew() {
   numElements = emitGcArrayGetNumElements<NoNullCheck>(object);
 
   // Free the barrier reg after we've allocated all registers
-  if (arrayType.elementType_.isRefRepr()) {
+  if (arrayType.elementType().isRefRepr()) {
     freePtr(RegPtr(PreBarrierReg));
   }
 
@@ -7913,14 +7913,14 @@ bool BaseCompiler::emitArrayNewFixed() {
 
   // Reserve this register early if we will need it so that it is not taken by
   // any register used in this function.
-  bool avoidPreBarrierReg = arrayType.elementType_.isRefRepr();
+  bool avoidPreBarrierReg = arrayType.elementType().isRefRepr();
   if (avoidPreBarrierReg) {
     needPtr(RegPtr(PreBarrierReg));
   }
 
   RegRef object = needRef();
   if (!emitArrayAllocFixed<false>(typeIndex, object, numElements,
-                                  arrayType.elementType_.size())) {
+                                  arrayType.elementType().size())) {
     return false;
   }
 
@@ -7983,7 +7983,7 @@ bool BaseCompiler::emitArrayNewDefault() {
   RegRef object = needRef();
   RegI32 numElements = popI32();
   if (!emitArrayAlloc<true>(typeIndex, object, numElements,
-                            arrayType.elementType_.size())) {
+                            arrayType.elementType().size())) {
     return false;
   }
 
@@ -8100,14 +8100,14 @@ bool BaseCompiler::emitArrayGet(FieldWideningOp wideningOp) {
   RegPtr rdata = emitGcArrayGetData<NoNullCheck>(rp);
 
   // Load the value
-  uint32_t shift = arrayType.elementType_.indexingShift();
+  uint32_t shift = arrayType.elementType().indexingShift();
   if (IsShiftInScaleRange(shift)) {
     emitGcGet<BaseIndex, NoNullCheck>(
-        arrayType.elementType_, wideningOp,
+        arrayType.elementType(), wideningOp,
         BaseIndex(rdata, index, ShiftToScale(shift), 0));
   } else {
     masm.lshiftPtr(Imm32(shift), index);
-    emitGcGet<BaseIndex, NoNullCheck>(arrayType.elementType_, wideningOp,
+    emitGcGet<BaseIndex, NoNullCheck>(arrayType.elementType(), wideningOp,
                                       BaseIndex(rdata, index, TimesOne, 0));
   }
 
@@ -8133,7 +8133,7 @@ bool BaseCompiler::emitArraySet() {
 
   // Reserve this register early if we will need it so that it is not taken by
   // any register used in this function.
-  if (arrayType.elementType_.isRefRepr()) {
+  if (arrayType.elementType().isRefRepr()) {
     needPtr(RegPtr(PreBarrierReg));
   }
 
@@ -8152,7 +8152,7 @@ bool BaseCompiler::emitArraySet() {
   RegPtr rdata = emitGcArrayGetData<NoNullCheck>(rp);
 
   // Free the barrier reg after we've allocated all registers
-  if (arrayType.elementType_.isRefRepr()) {
+  if (arrayType.elementType().isRefRepr()) {
     freePtr(RegPtr(PreBarrierReg));
   }
 
@@ -8229,7 +8229,7 @@ bool BaseCompiler::emitArrayFill() {
 
   const TypeDef& typeDef = codeMeta_.types->type(typeIndex);
   const ArrayType& arrayType = typeDef.arrayType();
-  StorageType elementType = arrayType.elementType_;
+  StorageType elementType = arrayType.elementType();
 
   // On x86 (32-bit), we are very short of registers, hence the code
   // generation scheme is less straightforward than it might otherwise be.
@@ -8388,7 +8388,7 @@ bool BaseCompiler::emitArrayFill() {
   // Currently `rdata` points at the start of the array data area.  Move it
   // forwards by `index` units so as to make it point at the start of the area
   // to be filled.
-  uint32_t shift = arrayType.elementType_.indexingShift();
+  uint32_t shift = arrayType.elementType().indexingShift();
   if (shift > 0) {
     masm.lshift32(Imm32(shift), index);
     // `index` is a 32 bit value, so we must zero-extend it to 64 bits before
diff --git a/js/src/wasm/WasmDump.cpp b/js/src/wasm/WasmDump.cpp
index f92125077aa..be0c08ebb21 100644
--- a/js/src/wasm/WasmDump.cpp
+++ b/js/src/wasm/WasmDump.cpp
@@ -193,7 +193,7 @@ void wasm::Dump(const StructType& structType, IndentedPrinter& out) {
   out.printf("(struct\n");
   {
     IndentedPrinter::AutoIndent innerIndent(out);
-    for (const StructField& field : structType.fields_) {
+    for (const FieldType& field : structType.fields_) {
       out.printf("(field ");
       if (field.isMutable) {
         out.printf("(mut ");
@@ -216,11 +216,11 @@ void wasm::Dump(const ArrayType& arrayType) {
 
 void wasm::Dump(const ArrayType& arrayType, IndentedPrinter& out) {
   out.printf("(array ");
-  if (arrayType.isMutable_) {
+  if (arrayType.isMutable()) {
     out.printf("(mut ");
   }
-  Dump(arrayType.elementType_, out);
-  if (arrayType.isMutable_) {
+  Dump(arrayType.elementType(), out);
+  if (arrayType.isMutable()) {
     out.printf(")");
   }
   out.printf(")\n");
diff --git a/js/src/wasm/WasmGcObject-inl.h b/js/src/wasm/WasmGcObject-inl.h
index c12b30a0588..29f42e617fb 100644
--- a/js/src/wasm/WasmGcObject-inl.h
+++ b/js/src/wasm/WasmGcObject-inl.h
@@ -171,7 +171,7 @@ inline gc::AllocKind WasmArrayObject::allocKind() const {
   if (isDataInline()) {
     // numElements_ was validated to not overflow when constructing this object
     uint32_t storageBytes = calcStorageBytesUnchecked(
-        typeDef().arrayType().elementType_.size(), numElements_);
+        typeDef().arrayType().elementType().size(), numElements_);
     return allocKindForIL(storageBytes);
   }
 
@@ -338,7 +338,7 @@ MOZ_ALWAYS_INLINE WasmArrayObject* WasmArrayObject::createArray(
     JSContext* cx, wasm::TypeDefInstanceData* typeDefData,
     js::gc::Heap initialHeap, uint32_t numElements) {
   MOZ_ASSERT(typeDefData->arrayElemSize ==
-             typeDefData->typeDef->arrayType().elementType_.size());
+             typeDefData->typeDef->arrayType().elementType().size());
   mozilla::CheckedUint32 storageBytes =
       calcStorageBytesChecked(typeDefData->arrayElemSize, numElements);
   if (!storageBytes.isValid() ||
diff --git a/js/src/wasm/WasmGcObject.cpp b/js/src/wasm/WasmGcObject.cpp
index ee4c2f30dae..2faaad4c3b0 100644
--- a/js/src/wasm/WasmGcObject.cpp
+++ b/js/src/wasm/WasmGcObject.cpp
@@ -238,9 +238,8 @@ bool WasmGcObject::lookUpProperty(JSContext* cx, Handle<WasmGcObject*> obj,
                                  JSMSG_WASM_OUT_OF_BOUNDS);
         return false;
       }
-      const StructField& field = structType.fields_[index];
-      offset->set(field.offset);
-      *type = field.type;
+      offset->set(structType.fieldOffset(index));
+      *type = structType.fields_[index].type;
       return true;
     }
     case wasm::TypeDefKind::Array: {
@@ -255,13 +254,13 @@ bool WasmGcObject::lookUpProperty(JSContext* cx, Handle<WasmGcObject*> obj,
         return false;
       }
       uint64_t scaledIndex =
-          uint64_t(index) * uint64_t(arrayType.elementType_.size());
+          uint64_t(index) * uint64_t(arrayType.elementType().size());
       if (scaledIndex >= uint64_t(UINT32_MAX)) {
         // It's unrepresentable as an WasmGcObject::PropOffset.  Give up.
         return false;
       }
       offset->set(uint32_t(scaledIndex));
-      *type = arrayType.elementType_;
+      *type = arrayType.elementType();
       return true;
     }
     default:
@@ -359,12 +358,12 @@ void WasmArrayObject::obj_trace(JSTracer* trc, JSObject* object) {
 
   const auto& typeDef = arrayObj.typeDef();
   const auto& arrayType = typeDef.arrayType();
-  if (!arrayType.elementType_.isRefRepr()) {
+  if (!arrayType.elementType().isRefRepr()) {
     return;
   }
 
   uint32_t numElements = arrayObj.numElements_;
-  uint32_t elemSize = arrayType.elementType_.size();
+  uint32_t elemSize = arrayType.elementType().size();
   for (uint32_t i = 0; i < numElements; i++) {
     AnyRef* elementPtr = reinterpret_cast<AnyRef*>(data + i * elemSize);
     TraceManuallyBarrieredEdge(trc, elementPtr, "wasm-array-element");
@@ -389,7 +388,7 @@ void WasmArrayObject::obj_finalize(JS::GCContext* gcx, JSObject* object) {
     // arrayObj.numElements_ was validated to not overflow when constructing the
     // array
     size_t trailerSize = calcStorageBytesUnchecked(
-        typeDef.arrayType().elementType_.size(), arrayObj.numElements_);
+        typeDef.arrayType().elementType().size(), arrayObj.numElements_);
     // Ensured by WasmArrayObject::createArrayNonEmpty.
     MOZ_RELEASE_ASSERT(trailerSize <= size_t(MaxArrayPayloadBytes));
     gcx->removeCellMemory(&arrayObj, trailerSize + TrailerBlockOverhead,
@@ -420,7 +419,7 @@ size_t WasmArrayObject::obj_moved(JSObject* obj, JSObject* old) {
       // arrayObj.numElements_ was validated not to overflow when constructing
       // the array
       size_t trailerSize = calcStorageBytesUnchecked(
-          typeDef.arrayType().elementType_.size(), arrayObj.numElements_);
+          typeDef.arrayType().elementType().size(), arrayObj.numElements_);
       // Ensured by WasmArrayObject::createArrayOOL.
       MOZ_RELEASE_ASSERT(trailerSize <= size_t(MaxArrayPayloadBytes));
       nursery.trackTrailerOnPromotion(arrayObj.dataHeader(), obj, trailerSize,
@@ -434,20 +433,20 @@ size_t WasmArrayObject::obj_moved(JSObject* obj, JSObject* old) {
 
 void WasmArrayObject::storeVal(const Val& val, uint32_t itemIndex) {
   const ArrayType& arrayType = typeDef().arrayType();
-  size_t elementSize = arrayType.elementType_.size();
+  size_t elementSize = arrayType.elementType().size();
   MOZ_ASSERT(itemIndex < numElements_);
   uint8_t* data = data_ + elementSize * itemIndex;
-  WriteValTo(val, arrayType.elementType_, data);
+  WriteValTo(val, arrayType.elementType(), data);
 }
 
 void WasmArrayObject::fillVal(const Val& val, uint32_t itemIndex,
                               uint32_t len) {
   const ArrayType& arrayType = typeDef().arrayType();
-  size_t elementSize = arrayType.elementType_.size();
+  size_t elementSize = arrayType.elementType().size();
   uint8_t* data = data_ + elementSize * itemIndex;
   MOZ_ASSERT(itemIndex <= numElements_ && len <= numElements_ - itemIndex);
   for (uint32_t i = 0; i < len; i++) {
-    WriteValTo(val, arrayType.elementType_, data);
+    WriteValTo(val, arrayType.elementType(), data);
     data += elementSize;
   }
 }
@@ -513,9 +512,10 @@ bool WasmStructObject::getField(JSContext* cx, uint32_t index,
                                 MutableHandle<Value> val) {
   const StructType& resultType = typeDef().structType();
   MOZ_ASSERT(index <= resultType.fields_.length());
-  const StructField& field = resultType.fields_[index];
+  const FieldType& field = resultType.fields_[index];
+  uint32_t fieldOffset = resultType.fieldOffset(index);
   StorageType ty = field.type.storageType();
-  return ToJSValue(cx, fieldOffsetToAddress(ty, field.offset), ty, val);
+  return ToJSValue(cx, fieldOffsetToAddress(ty, fieldOffset), ty, val);
 }
 
 /* static */
@@ -578,7 +578,7 @@ size_t WasmStructObject::obj_moved(JSObject* obj, JSObject* old) {
 void WasmStructObject::storeVal(const Val& val, uint32_t fieldIndex) {
   const StructType& structType = typeDef().structType();
   StorageType fieldType = structType.fields_[fieldIndex].type;
-  uint32_t fieldOffset = structType.fields_[fieldIndex].offset;
+  uint32_t fieldOffset = structType.fieldOffset(fieldIndex);
 
   MOZ_ASSERT(fieldIndex < structType.fields_.length());
   bool areaIsOutline;
diff --git a/js/src/wasm/WasmGcObject.h b/js/src/wasm/WasmGcObject.h
index b68679c5c72..e09596aefa2 100644
--- a/js/src/wasm/WasmGcObject.h
+++ b/js/src/wasm/WasmGcObject.h
@@ -86,8 +86,8 @@ class WasmGcObject : public JSObject {
   // single contiguous area of memory:
   //
   // * If the object in question is a WasmStructObject, it is the value of
-  //   `wasm::StructField::offset` for the relevant field, without regard to
-  //   the inline/outline split.
+  //   `wasm::StructType::fieldOffset()` for the relevant field, without regard
+  //   to the inline/outline split.
   //
   // * If the object in question is a WasmArrayObject, then
   //   - u32 == UINT32_MAX (0xFFFF'FFFF) means the "length" property
diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp
index fe613b248b3..6c4fc95416a 100644
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -1514,7 +1514,7 @@ static bool ArrayCopyFromData(JSContext* cx, Handle<WasmArrayObject*> arrayObj,
   // Compute the number of bytes to copy, ensuring it's below 2^32.
   CheckedUint32 numBytesToCopy =
       CheckedUint32(numElements) *
-      CheckedUint32(typeDef->arrayType().elementType_.size());
+      CheckedUint32(typeDef->arrayType().elementType().size());
   if (!numBytesToCopy.isValid()) {
     // Because the request implies that 2^32 or more bytes are to be copied.
     ReportTrapError(cx, JSMSG_WASM_OUT_OF_BOUNDS);
@@ -1665,7 +1665,7 @@ static bool ArrayCopyFromElem(JSContext* cx, Handle<WasmArrayObject*> arrayObj,
   // Any data coming from an element segment will be an AnyRef. Writes into
   // array memory are done with raw pointers, so we must ensure here that the
   // destination size is correct.
-  MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType_.size() ==
+  MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType().size() ==
                      sizeof(AnyRef));
 
   Rooted<WasmArrayObject*> arrayObj(
@@ -1771,7 +1771,7 @@ static bool ArrayCopyFromElem(JSContext* cx, Handle<WasmArrayObject*> arrayObj,
   // Any data coming from an element segment will be an AnyRef. Writes into
   // array memory are done with raw pointers, so we must ensure here that the
   // destination size is correct.
-  MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType_.size() ==
+  MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType().size() ==
                      sizeof(AnyRef));
 
   // Get hold of the array.
@@ -1969,8 +1969,8 @@ static WasmArrayObject* UncheckedCastToArrayI16(HandleAnyRef ref) {
   JSObject& object = ref.toJSObject();
   WasmArrayObject& array = object.as<WasmArrayObject>();
   DebugOnly<const ArrayType*> type(&array.typeDef().arrayType());
-  MOZ_ASSERT(type->elementType_ == StorageType::I16);
-  MOZ_ASSERT(type->isMutable_ == isMutable);
+  MOZ_ASSERT(type->elementType() == StorageType::I16);
+  MOZ_ASSERT(type->isMutable() == isMutable);
   return &array;
 }
 
@@ -2388,7 +2388,7 @@ bool Instance::init(JSContext* cx, const JSObjectVector& funcImports,
         // StructLayout::close ensures this is an integral number of words.
         MOZ_ASSERT((typeDefData->structTypeSize % sizeof(uintptr_t)) == 0);
       } else {
-        uint32_t arrayElemSize = typeDef.arrayType().elementType_.size();
+        uint32_t arrayElemSize = typeDef.arrayType().elementType().size();
         typeDefData->arrayElemSize = arrayElemSize;
         MOZ_ASSERT(arrayElemSize == 16 || arrayElemSize == 8 ||
                    arrayElemSize == 4 || arrayElemSize == 2 ||
diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp
index 8310ef57e66..9754a778201 100644
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -4464,11 +4464,11 @@ class FunctionCompiler {
   // WasmStructObject, a MIR pointer to a value, and a field descriptor,
... (file diff truncated)
Loading diff…