tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WasmSerialize.cpp (53714B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "wasm/WasmSerialize.h"
      8 
      9 #include "mozilla/EnumeratedRange.h"
     10 #include "mozilla/Maybe.h"
     11 #include "mozilla/RefPtr.h"
     12 #include "mozilla/Try.h"
     13 #include "mozilla/Vector.h"
     14 
     15 #include <cstdint>
     16 #include <cstring>
     17 #include <type_traits>
     18 #include <utility>
     19 
     20 #include "jit/ProcessExecutableMemory.h"
     21 #include "js/StreamConsumer.h"
     22 #include "wasm/WasmCode.h"
     23 #include "wasm/WasmCodegenTypes.h"
     24 #include "wasm/WasmGC.h"
     25 #include "wasm/WasmInitExpr.h"
     26 #include "wasm/WasmModule.h"
     27 #include "wasm/WasmModuleTypes.h"
     28 #include "wasm/WasmTypeDef.h"
     29 #include "wasm/WasmValType.h"
     30 #include "wasm/WasmValue.h"
     31 
     32 using namespace js;
     33 using namespace js::wasm;
     34 
     35 using mozilla::Err;
     36 using mozilla::Maybe;
     37 using mozilla::Ok;
     38 
     39 namespace js {
     40 namespace wasm {
     41 
     42 // The following assert is used as a tripwire for for new fields being added to
     43 // types. If this assertion is broken by your code, verify the serialization
     44 // code is correct, and then update the assertion.
     45 //
     46 // We only check serialized type sizes on one 'golden' platform. The platform
     47 // is arbitrary, but must remain consistent. The platform should be as specific
     48 // as possible so these assertions don't erroneously fire. Checkout the
     49 // definition of ENABLE_WASM_VERIFY_SERIALIZATION_FOR_SIZE in js/moz.configure
     50 // for the current platform.
     51 //
     52 // If this mechanism becomes a hassle, we can investigate other methods of
     53 // achieving the same goal.
     54 #if defined(ENABLE_WASM_VERIFY_SERIALIZATION_FOR_SIZE)
     55 
     56 template <typename T, size_t Size>
     57 struct Tripwire {
     58  // The following will print a compile error that contains the size of type,
     59  // and can be used for updating the assertion to the correct size.
     60  static char (*_Error)[sizeof(T)] = 1;
     61 
     62  // We must reference the bad declaration to work around SFINAE.
     63  static const bool Value = !_Error;
     64 };
     65 
     66 template <typename T>
     67 struct Tripwire<T, sizeof(T)> {
     68  static const bool Value = true;
     69 };
     70 
     71 #  define WASM_VERIFY_SERIALIZATION_FOR_SIZE(Type, Size) \
     72    static_assert(Tripwire<Type, Size>::Value);
     73 
     74 #else
     75 #  define WASM_VERIFY_SERIALIZATION_FOR_SIZE(Type, Size) static_assert(true);
     76 #endif
     77 
     78 // A pointer is not cacheable POD
     79 static_assert(!is_cacheable_pod<const uint8_t*>);
     80 
     81 // A non-fixed sized array is not cacheable POD
     82 static_assert(!is_cacheable_pod<uint8_t[]>);
     83 
     84 // Cacheable POD is not inherited
     85 struct TestPodBase {};
     86 WASM_DECLARE_CACHEABLE_POD(TestPodBase);
     87 struct InheritTestPodBase : public TestPodBase {};
     88 static_assert(is_cacheable_pod<TestPodBase> &&
     89              !is_cacheable_pod<InheritTestPodBase>);
     90 
     91 // Coding functions for containers and smart pointers need to know which code
     92 // function to apply to the inner value. 'CodeFunc' is the common signature to
     93 // be used for this.
     94 template <CoderMode mode, typename T>
     95 using CodeFunc = CoderResult (*)(Coder<mode>&, CoderArg<mode, T>);
     96 
     97 // Some functions are generic for MODE_SIZE and MODE_ENCODE, but not
     98 // MODE_DECODE. This assert is used to ensure that the right function overload
     99 // is chosen in these cases.
    100 #define STATIC_ASSERT_ENCODING_OR_SIZING \
    101  static_assert(mode == MODE_ENCODE || mode == MODE_SIZE, "wrong overload");
    102 
    103 CoderResult Coder<MODE_SIZE>::writeBytes(const void* unusedSrc, size_t length) {
    104  size_ += length;
    105  if (!size_.isValid()) {
    106    return Err(OutOfMemory());
    107  }
    108  return Ok();
    109 }
    110 
    111 CoderResult Coder<MODE_ENCODE>::writeBytes(const void* src, size_t length) {
    112  MOZ_RELEASE_ASSERT(buffer_ + length <= end_);
    113  memcpy(buffer_, src, length);
    114  buffer_ += length;
    115  return Ok();
    116 }
    117 
    118 CoderResult Coder<MODE_DECODE>::readBytes(void* dest, size_t length) {
    119  MOZ_RELEASE_ASSERT(buffer_ + length <= end_);
    120  memcpy(dest, buffer_, length);
    121  buffer_ += length;
    122  return Ok();
    123 }
    124 
    125 CoderResult Coder<MODE_DECODE>::readBytesRef(size_t length,
    126                                             const uint8_t** bytesBegin) {
    127  MOZ_RELEASE_ASSERT(buffer_ + length <= end_);
    128  *bytesBegin = buffer_;
    129  buffer_ += length;
    130  return Ok();
    131 }
    132 
    133 // Cacheable POD coding functions
    134 
    135 template <CoderMode mode, typename T,
    136          typename = std::enable_if_t<is_cacheable_pod<T>>,
    137          typename = std::enable_if_t<mode == MODE_DECODE>>
    138 CoderResult CodePod(Coder<mode>& coder, T* item) {
    139  return coder.readBytes((void*)item, sizeof(T));
    140 }
    141 
    142 template <CoderMode mode, typename T,
    143          typename = std::enable_if_t<is_cacheable_pod<T>>,
    144          typename = std::enable_if_t<mode != MODE_DECODE>>
    145 CoderResult CodePod(Coder<mode>& coder, const T* item) {
    146  STATIC_ASSERT_ENCODING_OR_SIZING;
    147  return coder.writeBytes((const void*)item, sizeof(T));
    148 }
    149 
    150 // "Magic Marker". Use to sanity check the serialization process.
    151 
    152 enum class Marker : uint32_t {
    153  LinkData = 0x49102278,
    154  Imports,
    155  Exports,
    156  DataSegments,
    157  ElemSegments,
    158  CustomSections,
    159  Code,
    160  Metadata,
    161  ModuleMetadata,
    162  CodeMetadata,
    163  CodeBlock
    164 };
    165 
    166 template <CoderMode mode>
    167 CoderResult Magic(Coder<mode>& coder, Marker item) {
    168  if constexpr (mode == MODE_DECODE) {
    169    // Assert the specified marker is in the binary
    170    Marker decoded;
    171    MOZ_TRY(CodePod(coder, &decoded));
    172    MOZ_RELEASE_ASSERT(decoded == item);
    173    return Ok();
    174  } else {
    175    // Encode the specified marker in the binary
    176    return CodePod(coder, &item);
    177  }
    178 }
    179 
    180 // Coding function for a nullable pointer
    181 //
    182 // These functions will only code the inner value is not null. The
    183 // coding function to use for the inner value is specified by a template
    184 // parameter.
    185 
    186 template <CoderMode _, typename T, CodeFunc<MODE_DECODE, T> CodeT>
    187 CoderResult CodeNullablePtr(Coder<MODE_DECODE>& coder, T* item) {
    188  // Decode 'isNonNull'
    189  uint8_t isNonNull;
    190  MOZ_TRY(CodePod(coder, &isNonNull));
    191 
    192  if (isNonNull == 1) {
    193    // Code the inner type
    194    MOZ_TRY(CodeT(coder, item));
    195  } else {
    196    // Initialize to nullptr
    197    *item = nullptr;
    198  }
    199  return Ok();
    200 }
    201 
    202 template <CoderMode mode, typename T, CodeFunc<mode, T> CodeT>
    203 CoderResult CodeNullablePtr(Coder<mode>& coder, const T* item) {
    204  STATIC_ASSERT_ENCODING_OR_SIZING;
    205 
    206  // Encode or size 'isNonNull'
    207  const uint8_t isNonNull = *item != nullptr;
    208  MOZ_TRY(CodePod(coder, &isNonNull));
    209 
    210  if (isNonNull) {
    211    // Encode or size the inner value
    212    MOZ_TRY(CodeT(coder, item));
    213  }
    214  return Ok();
    215 }
    216 
    217 // mozilla::Maybe coding functions
    218 //
    219 // These functions will only code the inner value if Maybe.isSome(). The
    220 // coding function to use for the inner value is specified by a template
    221 // parameter.
    222 
    223 template <CoderMode _, typename T, CodeFunc<MODE_DECODE, T> CodeT>
    224 CoderResult CodeMaybe(Coder<MODE_DECODE>& coder, Maybe<T>* item) {
    225  // Decode 'isSome()'
    226  uint8_t isSome;
    227  MOZ_TRY(CodePod(coder, &isSome));
    228 
    229  if (isSome == 1) {
    230    // Initialize to Some with default constructor
    231    item->emplace();
    232    // Code the inner type
    233    MOZ_TRY(CodeT(coder, item->ptr()));
    234  } else {
    235    // Initialize to nothing
    236    *item = mozilla::Nothing();
    237  }
    238  return Ok();
    239 }
    240 
    241 template <CoderMode mode, typename T, CodeFunc<mode, T> CodeT>
    242 CoderResult CodeMaybe(Coder<mode>& coder, const Maybe<T>* item) {
    243  STATIC_ASSERT_ENCODING_OR_SIZING;
    244 
    245  // Encode or size 'isSome()'
    246  const uint8_t isSome = item->isSome() ? 1 : 0;
    247  MOZ_TRY(CodePod(coder, &isSome));
    248 
    249  if (item->isSome()) {
    250    // Encode or size the inner value
    251    MOZ_TRY(CodeT(coder, item->ptr()));
    252  }
    253  return Ok();
    254 }
    255 
    256 // Cacheable POD mozilla::Vector coding functions
    257 //
    258 // These functions are only available if the element type is cacheable POD. In
    259 // this case, the whole contents of the vector are copied directly to/from the
    260 // buffer.
    261 
    262 template <CoderMode mode, typename T, size_t N,
    263          typename = std::enable_if_t<is_cacheable_pod<T>>,
    264          typename = std::enable_if_t<mode == MODE_DECODE>>
    265 CoderResult CodePodVector(Coder<mode>& coder,
    266                          Vector<T, N, SystemAllocPolicy>* item) {
    267  // Decode the length
    268  size_t length;
    269  MOZ_TRY(CodePod(coder, &length));
    270 
    271  // Prepare to copy into the vector
    272  if (!item->initLengthUninitialized(length)) {
    273    return Err(OutOfMemory());
    274  }
    275 
    276  // Copy directly from the buffer to the vector
    277  const size_t byteLength = length * sizeof(T);
    278  return coder.readBytes((void*)item->begin(), byteLength);
    279 }
    280 
    281 template <CoderMode mode, typename T, size_t N,
    282          typename = std::enable_if_t<is_cacheable_pod<T>>,
    283          typename = std::enable_if_t<mode != MODE_DECODE>>
    284 CoderResult CodePodVector(Coder<mode>& coder,
    285                          const Vector<T, N, SystemAllocPolicy>* item) {
    286  STATIC_ASSERT_ENCODING_OR_SIZING;
    287 
    288  // Encode the length
    289  const size_t length = item->length();
    290  MOZ_TRY(CodePod(coder, &length));
    291 
    292  // Copy directly from the vector to the buffer
    293  const size_t byteLength = length * sizeof(T);
    294  return coder.writeBytes((const void*)item->begin(), byteLength);
    295 }
    296 
    297 // Non-cacheable-POD mozilla::Vector coding functions
    298 //
    299 // These functions implement the general case of coding a vector of some type.
    300 // The coding function to use on the vector elements is provided through a
    301 // template parameter.
    302 
    303 template <CoderMode _, typename T, CodeFunc<MODE_DECODE, T> CodeT, size_t N,
    304          typename std::enable_if_t<!is_cacheable_pod<T>, bool> = true>
    305 CoderResult CodeVector(Coder<MODE_DECODE>& coder,
    306                       Vector<T, N, SystemAllocPolicy>* item) {
    307  // Decode the length
    308  size_t length;
    309  MOZ_TRY(CodePod(coder, &length));
    310 
    311  // Attempt to grow the buffer to length, this will default initialize each
    312  // element
    313  if (!item->resize(length)) {
    314    return Err(OutOfMemory());
    315  }
    316 
    317  // Decode each child element from the buffer
    318  for (auto iter = item->begin(); iter != item->end(); iter++) {
    319    MOZ_TRY(CodeT(coder, iter));
    320  }
    321  return Ok();
    322 }
    323 
    324 template <CoderMode mode, typename T, CodeFunc<mode, T> CodeT, size_t N,
    325          typename std::enable_if_t<!is_cacheable_pod<T>, bool> = true>
    326 CoderResult CodeVector(Coder<mode>& coder,
    327                       const Vector<T, N, SystemAllocPolicy>* item) {
    328  STATIC_ASSERT_ENCODING_OR_SIZING;
    329 
    330  // Encode the length
    331  const size_t length = item->length();
    332  MOZ_TRY(CodePod(coder, &length));
    333 
    334  // Encode each child element
    335  for (auto iter = item->begin(); iter != item->end(); iter++) {
    336    MOZ_TRY(CodeT(coder, iter));
    337  }
    338  return Ok();
    339 }
    340 
    341 // This function implements encoding and decoding of RefPtr<T>. A coding
    342 // function is provided for the inner value through a template parameter.
    343 //
    344 // The special handling of const qualification allows a RefPtr<const T> to be
    345 // decoded correctly.
    346 template <CoderMode mode, typename T,
    347          CodeFunc<mode, std::remove_const_t<T>> CodeT>
    348 CoderResult CodeRefPtr(Coder<mode>& coder, CoderArg<mode, RefPtr<T>> item) {
    349  if constexpr (mode == MODE_DECODE) {
    350    // The RefPtr should not be initialized yet
    351    MOZ_ASSERT(!item->get());
    352 
    353    // Allocate and default construct the inner type
    354    auto* allocated = js_new<std::remove_const_t<T>>();
    355    if (!allocated) {
    356      return Err(OutOfMemory());
    357    }
    358 
    359    // Initialize the RefPtr
    360    *item = allocated;
    361 
    362    // Decode the inner type
    363    MOZ_TRY(CodeT(coder, allocated));
    364    return Ok();
    365  } else {
    366    // Encode the inner type
    367    return CodeT(coder, item->get());
    368  }
    369 }
    370 
    371 // The same as CodeRefPtr, but allowing for nullable pointers.
    372 template <CoderMode mode, typename T,
    373          CodeFunc<mode, std::remove_const_t<T>> CodeT>
    374 CoderResult CodeNullableRefPtr(Coder<mode>& coder,
    375                               CoderArg<mode, RefPtr<T>> item) {
    376  if constexpr (mode == MODE_DECODE) {
    377    uint32_t isNull;
    378    MOZ_TRY(CodePod(coder, &isNull));
    379    if (isNull == 0) {
    380      MOZ_ASSERT(item->get() == nullptr);
    381      return Ok();
    382    }
    383    return CodeRefPtr<mode, T, CodeT>(coder, item);
    384  } else {
    385    uint32_t isNull = !!item->get() ? 1 : 0;
    386    MOZ_TRY(CodePod(coder, &isNull));
    387    if (isNull == 0) {
    388      return Ok();
    389    }
    390    return CodeRefPtr<mode, T, CodeT>(coder, item);
    391  }
    392 }
    393 
    394 // This function implements encoding and decoding of UniquePtr<T>.
    395 // A coding function is provided for the inner value as a function parameter.
    396 template <CoderMode mode, typename T,
    397          CodeFunc<mode, std::remove_const_t<T>> CodeT>
    398 CoderResult CodeUniquePtr(Coder<mode>& coder,
    399                          CoderArg<mode, UniquePtr<T>> item) {
    400  if constexpr (mode == MODE_DECODE) {
    401    // The UniquePtr should not be initialized yet
    402    MOZ_ASSERT(!item->get());
    403 
    404    // Allocate and default construct the inner type
    405    auto allocated = js::MakeUnique<std::remove_const_t<T>>();
    406    if (!allocated.get()) {
    407      return Err(OutOfMemory());
    408    }
    409 
    410    // Decode the inner type
    411    MOZ_TRY(CodeT(coder, allocated.get()));
    412 
    413    // Initialize the UniquePtr
    414    *item = std::move(allocated);
    415    return Ok();
    416  } else {
    417    // Encode the inner type
    418    return CodeT(coder, item->get());
    419  }
    420 }
    421 
    422 // UniqueChars coding functions
    423 
    424 static size_t StringLengthWithNullChar(const char* chars) {
    425  return chars ? strlen(chars) + 1 : 0;
    426 }
    427 
    428 CoderResult CodeUniqueChars(Coder<MODE_DECODE>& coder, UniqueChars* item) {
    429  uint32_t lengthWithNullChar;
    430  MOZ_TRY(CodePod(coder, &lengthWithNullChar));
    431 
    432  // Decode the bytes, if any
    433  if (lengthWithNullChar) {
    434    item->reset(js_pod_malloc<char>(lengthWithNullChar));
    435    if (!item->get()) {
    436      return Err(OutOfMemory());
    437    }
    438    return coder.readBytes((char*)item->get(), lengthWithNullChar);
    439  }
    440 
    441  // If there were no bytes to write, the string should be null
    442  MOZ_ASSERT(!item->get());
    443  return Ok();
    444 }
    445 
    446 template <CoderMode mode>
    447 CoderResult CodeUniqueChars(Coder<mode>& coder, const UniqueChars* item) {
    448  WASM_VERIFY_SERIALIZATION_FOR_SIZE(UniqueChars, 8);
    449  STATIC_ASSERT_ENCODING_OR_SIZING;
    450 
    451  // Encode the length
    452  const uint32_t lengthWithNullChar = StringLengthWithNullChar(item->get());
    453  MOZ_TRY(CodePod(coder, &lengthWithNullChar));
    454 
    455  // Write the bytes, if any
    456  if (lengthWithNullChar) {
    457    return coder.writeBytes((const void*)item->get(), lengthWithNullChar);
    458  }
    459 
    460  // If there were no bytes to write, the string should be null
    461  MOZ_ASSERT(!item->get());
    462  return Ok();
    463 }
    464 
    465 // Code a CacheableChars. This just forwards to UniqueChars, as that's the
    466 // only data in the class, via inheritance.
    467 template <CoderMode mode>
    468 CoderResult CodeCacheableChars(Coder<mode>& coder,
    469                               CoderArg<mode, CacheableChars> item) {
    470  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CacheableChars, 8);
    471  return CodeUniqueChars(coder, (UniqueChars*)item);
    472 }
    473 
    474 // Code a ShareableChars. This functions only needs to forward to the inner
    475 // unique chars.
    476 template <CoderMode mode>
    477 CoderResult CodeShareableChars(Coder<mode>& coder,
    478                               CoderArg<mode, ShareableChars> item) {
    479  return CodeUniqueChars(coder, &item->chars);
    480 }
    481 
    482 // Code a CacheableName
    483 template <CoderMode mode>
    484 CoderResult CodeCacheableName(Coder<mode>& coder,
    485                              CoderArg<mode, CacheableName> item) {
    486  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CacheableName, 40);
    487  MOZ_TRY(CodePodVector(coder, &item->bytes_));
    488  return Ok();
    489 }
    490 
    491 // Code a ShareableBytes.
    492 template <CoderMode mode>
    493 CoderResult CodeShareableBytes(Coder<mode>& coder,
    494                               CoderArg<mode, ShareableBytes> item) {
    495  return CodePodVector<mode>(coder, &item->vector);
    496 }
    497 
    498 // WasmValType.h
    499 
    500 /* static */
    501 SerializableTypeCode SerializableTypeCode::serialize(PackedTypeCode ptc,
    502                                                     const TypeContext& types) {
    503  SerializableTypeCode stc = {};
    504  stc.typeCode = PackedRepr(ptc.typeCode());
    505  stc.typeIndex = ptc.typeDef() ? types.indexOf(*ptc.typeDef())
    506                                : SerializableTypeCode::NoTypeIndex;
    507  stc.nullable = ptc.isNullable();
    508  return stc;
    509 }
    510 
    511 PackedTypeCode SerializableTypeCode::deserialize(const TypeContext& types) {
    512  if (typeIndex == SerializableTypeCode::NoTypeIndex) {
    513    return PackedTypeCode::pack(TypeCode(typeCode), nullable);
    514  }
    515  const TypeDef* typeDef = &types.type(typeIndex);
    516  return PackedTypeCode::pack(TypeCode(typeCode), typeDef, nullable);
    517 }
    518 
    519 template <CoderMode mode>
    520 CoderResult CodePackedTypeCode(Coder<mode>& coder,
    521                               CoderArg<mode, PackedTypeCode> item) {
    522  if constexpr (mode == MODE_DECODE) {
    523    SerializableTypeCode stc;
    524    MOZ_TRY(CodePod(coder, &stc));
    525    *item = stc.deserialize(*coder.types_);
    526    return Ok();
    527  } else if constexpr (mode == MODE_SIZE) {
    528    return coder.writeBytes(nullptr, sizeof(SerializableTypeCode));
    529  } else {
    530    SerializableTypeCode stc =
    531        SerializableTypeCode::serialize(*item, *coder.types_);
    532    return CodePod(coder, &stc);
    533  }
    534 }
    535 
    536 template <CoderMode mode, typename T>
    537 CoderResult CodeTypeDefRef_Impl(Coder<mode>& coder, CoderArg<mode, T> item) {
    538  static constexpr uint32_t NullTypeIndex = UINT32_MAX;
    539  static_assert(NullTypeIndex > MaxTypes, "invariant");
    540 
    541  if constexpr (mode == MODE_DECODE) {
    542    uint32_t typeIndex;
    543    MOZ_TRY(CodePod(coder, &typeIndex));
    544    if (typeIndex != NullTypeIndex) {
    545      *item = &coder.types_->type(typeIndex);
    546    }
    547    return Ok();
    548  } else if constexpr (mode == MODE_SIZE) {
    549    return coder.writeBytes(nullptr, sizeof(uint32_t));
    550  } else {
    551    uint32_t typeIndex = !*item ? NullTypeIndex : coder.types_->indexOf(**item);
    552    return CodePod(coder, &typeIndex);
    553  }
    554 }
    555 
    556 template <CoderMode mode>
    557 CoderResult CodeTypeDefRef(Coder<mode>& coder,
    558                           CoderArg<mode, const TypeDef*> item) {
    559  return CodeTypeDefRef_Impl<mode, const TypeDef*>(coder, item);
    560 }
    561 
    562 template <CoderMode mode>
    563 CoderResult CodeTypeDefRef(Coder<mode>& coder,
    564                           CoderArg<mode, SharedTypeDef> item) {
    565  return CodeTypeDefRef_Impl<mode, SharedTypeDef>(coder, item);
    566 }
    567 
    568 template <CoderMode mode>
    569 CoderResult CodeValType(Coder<mode>& coder, CoderArg<mode, ValType> item) {
    570  return CodePackedTypeCode(coder, item->addressOfPacked());
    571 }
    572 
    573 template <CoderMode mode>
    574 CoderResult CodeStorageType(Coder<mode>& coder,
    575                            CoderArg<mode, StorageType> item) {
    576  return CodePackedTypeCode(coder, item->addressOfPacked());
    577 }
    578 
    579 template <CoderMode mode>
    580 CoderResult CodeRefType(Coder<mode>& coder, CoderArg<mode, RefType> item) {
    581  return CodePackedTypeCode(coder, item->addressOfPacked());
    582 }
    583 
    584 // WasmValue.h
    585 
    586 template <CoderMode mode>
    587 CoderResult CodeLitVal(Coder<mode>& coder, CoderArg<mode, LitVal> item) {
    588  MOZ_TRY(CodeValType(coder, &item->type_));
    589  MOZ_TRY(CodePod(coder, &item->cell_));
    590  return Ok();
    591 }
    592 
    593 // WasmInitExpr.h
    594 
    595 template <CoderMode mode>
    596 CoderResult CodeInitExpr(Coder<mode>& coder, CoderArg<mode, InitExpr> item) {
    597  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::InitExpr, 80);
    598  MOZ_TRY(CodePod(coder, &item->kind_));
    599  MOZ_TRY(CodeValType(coder, &item->type_));
    600  switch (item->kind_) {
    601    case InitExprKind::Literal:
    602      MOZ_TRY(CodeLitVal(coder, &item->literal_));
    603      break;
    604    case InitExprKind::Variable:
    605      MOZ_TRY(CodePodVector(coder, &item->bytecode_));
    606      break;
    607    default:
    608      MOZ_CRASH();
    609  }
    610  return Ok();
    611 }
    612 
    613 // WasmTypeDef.h
    614 
    615 template <CoderMode mode>
    616 CoderResult CodeFuncType(Coder<mode>& coder, CoderArg<mode, FuncType> item) {
    617  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::FuncType, 344);
    618  MOZ_TRY((CodeVector<mode, ValType, &CodeValType<mode>>(coder, &item->args_)));
    619  MOZ_TRY(
    620      (CodeVector<mode, ValType, &CodeValType<mode>>(coder, &item->results_)));
    621  MOZ_TRY(CodePod(coder, &item->immediateTypeId_));
    622  return Ok();
    623 }
    624 
    625 template <CoderMode mode>
    626 CoderResult CodeFieldType(Coder<mode>& coder, CoderArg<mode, FieldType> item) {
    627  MOZ_TRY(CodeStorageType(coder, &item->type));
    628  MOZ_TRY(CodePod(coder, &item->isMutable));
    629  return Ok();
    630 }
    631 
    632 template <CoderMode mode>
    633 CoderResult CodeStructType(Coder<mode>& coder,
    634                           CoderArg<mode, StructType> item) {
    635  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StructType, 192);
    636  MOZ_TRY((CodeVector<mode, FieldType, &CodeFieldType<mode>>(coder,
    637                                                             &item->fields_)));
    638  if constexpr (mode == MODE_DECODE) {
    639    if (!item->init()) {
    640      return Err(OutOfMemory());
    641    }
    642  }
    643  return Ok();
    644 }
    645 
    646 template <CoderMode mode>
    647 CoderResult CodeArrayType(Coder<mode>& coder, CoderArg<mode, ArrayType> item) {
    648  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::ArrayType, 16);
    649  MOZ_TRY(CodeFieldType(coder, &item->fieldType_));
    650  return Ok();
    651 }
    652 
    653 template <CoderMode mode>
    654 CoderResult CodeTypeDef(Coder<mode>& coder, CoderArg<mode, TypeDef> item) {
    655  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::TypeDef, 376);
    656  MOZ_TRY(CodeTypeDefRef(coder, &item->superTypeDef_));
    657  MOZ_TRY(CodePod(coder, &item->subTypingDepth_));
    658  MOZ_TRY(CodePod(coder, &item->isFinal_));
    659  // TypeDef is a tagged union containing kind = None. This implies that
    660  // we must manually initialize the variant that we decode.
    661  if constexpr (mode == MODE_DECODE) {
    662    MOZ_RELEASE_ASSERT(item->kind_ == TypeDefKind::None);
    663  }
    664  MOZ_TRY(CodePod(coder, &item->kind_));
    665  switch (item->kind_) {
    666    case TypeDefKind::Struct: {
    667      if constexpr (mode == MODE_DECODE) {
    668        new (&item->structType_) StructType();
    669      }
    670      MOZ_TRY(CodeStructType(coder, &item->structType_));
    671      break;
    672    }
    673    case TypeDefKind::Func: {
    674      if constexpr (mode == MODE_DECODE) {
    675        new (&item->funcType_) FuncType();
    676      }
    677      MOZ_TRY(CodeFuncType(coder, &item->funcType_));
    678      break;
    679    }
    680    case TypeDefKind::Array: {
    681      if constexpr (mode == MODE_DECODE) {
    682        new (&item->arrayType_) ArrayType();
    683      }
    684      MOZ_TRY(CodeArrayType(coder, &item->arrayType_));
    685      break;
    686    }
    687    case TypeDefKind::None: {
    688      break;
    689    }
    690    default:
    691      MOZ_ASSERT_UNREACHABLE();
    692  }
    693  return Ok();
    694 }
    695 
    696 using RecGroupIndexMap =
    697    HashMap<const RecGroup*, uint32_t, PointerHasher<const RecGroup*>,
    698            SystemAllocPolicy>;
    699 
    700 template <CoderMode mode>
    701 CoderResult CodeTypeContext(Coder<mode>& coder,
    702                            CoderArg<mode, TypeContext> item) {
    703  if constexpr (mode == MODE_DECODE) {
    704    // Decoding type definitions needs to reference the type context of the
    705    // module
    706    MOZ_ASSERT(!coder.types_);
    707    coder.types_ = item;
    708 
    709    // Decode the number of recursion groups in the module
    710    uint32_t numRecGroups;
    711    MOZ_TRY(CodePod(coder, &numRecGroups));
    712 
    713    // Decode each recursion group
    714    for (uint32_t recGroupIndex = 0; recGroupIndex < numRecGroups;
    715         recGroupIndex++) {
    716      // Decode if this recursion group is equivalent to a previous recursion
    717      // group
    718      uint32_t canonRecGroupIndex;
    719      MOZ_TRY(CodePod(coder, &canonRecGroupIndex));
    720      MOZ_RELEASE_ASSERT(canonRecGroupIndex <= recGroupIndex);
    721 
    722      // If the decoded index is not ours, we must re-use the previous decoded
    723      // recursion group.
    724      if (canonRecGroupIndex != recGroupIndex) {
    725        SharedRecGroup recGroup = item->groups()[canonRecGroupIndex];
    726        if (!item->addRecGroup(recGroup)) {
    727          return Err(OutOfMemory());
    728        }
    729        continue;
    730      }
    731 
    732      // Decode the number of types in the recursion group
    733      uint32_t numTypes;
    734      MOZ_TRY(CodePod(coder, &numTypes));
    735 
    736      MutableRecGroup recGroup = item->startRecGroup(numTypes);
    737      if (!recGroup) {
    738        return Err(OutOfMemory());
    739      }
    740 
    741      // Decode the type definitions
    742      for (uint32_t groupTypeIndex = 0; groupTypeIndex < numTypes;
    743           groupTypeIndex++) {
    744        MOZ_TRY(CodeTypeDef(coder, &recGroup->type(groupTypeIndex)));
    745      }
    746 
    747      // Finish the recursion group
    748      if (!item->endRecGroup()) {
    749        return Err(OutOfMemory());
    750      }
    751    }
    752  } else {
    753    // Encode the number of recursion groups in the module
    754    uint32_t numRecGroups = item->groups().length();
    755    MOZ_TRY(CodePod(coder, &numRecGroups));
    756 
    757    // We must be careful to only encode every unique recursion group only once
    758    // and in module order. The reason for this is that encoding type def
    759    // references uses the module type index map, which only stores the first
    760    // type index a type was canonicalized to.
    761    //
    762    // Using this map to encode both recursion groups would turn the following
    763    // type section from:
    764    //
    765    // 0: (type (struct (field 0)))
    766    // 1: (type (struct (field 1))) ;; identical to 0
    767    //
    768    // into:
    769    //
    770    // 0: (type (struct (field 0)))
    771    // 1: (type (struct (field 0))) ;; not identical to 0!
    772    RecGroupIndexMap canonRecGroups;
    773 
    774    // Encode each recursion group
    775    for (uint32_t groupIndex = 0; groupIndex < numRecGroups; groupIndex++) {
    776      SharedRecGroup group = item->groups()[groupIndex];
    777 
    778      // Find the index of the first time this recursion group was encoded, or
    779      // set it to this index if it hasn't been encoded.
    780      RecGroupIndexMap::AddPtr canonRecGroupIndex =
    781          canonRecGroups.lookupForAdd(group.get());
    782      if (!canonRecGroupIndex) {
    783        if (!canonRecGroups.add(canonRecGroupIndex, group.get(), groupIndex)) {
    784          return Err(OutOfMemory());
    785        }
    786      }
    787 
    788      // Encode the canon index for this recursion group
    789      MOZ_TRY(CodePod(coder, &canonRecGroupIndex->value()));
    790 
    791      // Don't encode this recursion group if we've already encoded it
    792      if (canonRecGroupIndex->value() != groupIndex) {
    793        continue;
    794      }
    795 
    796      // Encode the number of types in the recursion group
    797      uint32_t numTypes = group->numTypes();
    798      MOZ_TRY(CodePod(coder, &numTypes));
    799 
    800      // Encode the type definitions
    801      for (uint32_t i = 0; i < numTypes; i++) {
    802        MOZ_TRY(CodeTypeDef(coder, &group->type(i)));
    803      }
    804    }
    805  }
    806  return Ok();
    807 }
    808 
    809 // WasmModuleTypes.h
    810 
    811 template <CoderMode mode>
    812 CoderResult CodeImport(Coder<mode>& coder, CoderArg<mode, Import> item) {
    813  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::Import, 88);
    814  MOZ_TRY(CodeCacheableName(coder, &item->module));
    815  MOZ_TRY(CodeCacheableName(coder, &item->field));
    816  MOZ_TRY(CodePod(coder, &item->kind));
    817  return Ok();
    818 }
    819 
    820 template <CoderMode mode>
    821 CoderResult CodeExport(Coder<mode>& coder, CoderArg<mode, Export> item) {
    822  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::Export, 48);
    823  MOZ_TRY(CodeCacheableName(coder, &item->fieldName_));
    824  MOZ_TRY(CodePod(coder, &item->pod));
    825  return Ok();
    826 }
    827 
    828 template <CoderMode mode>
    829 CoderResult CodeGlobalDesc(Coder<mode>& coder,
    830                           CoderArg<mode, GlobalDesc> item) {
    831  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::GlobalDesc, 104);
    832  MOZ_TRY(CodePod(coder, &item->kind_));
    833  MOZ_TRY(CodeInitExpr(coder, &item->initial_));
    834  MOZ_TRY(CodePod(coder, &item->offset_));
    835  MOZ_TRY(CodePod(coder, &item->isMutable_));
    836  MOZ_TRY(CodePod(coder, &item->isWasm_));
    837  MOZ_TRY(CodePod(coder, &item->isExport_));
    838  MOZ_TRY(CodePod(coder, &item->importIndex_));
    839  return Ok();
    840 }
    841 
    842 template <CoderMode mode>
    843 CoderResult CodeTagType(Coder<mode>& coder, CoderArg<mode, TagType> item) {
    844  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::TagType, 72);
    845  // We skip serializing/deserializing the size and argOffsets fields because
    846  // those are computed from the argTypes field when we deserialize.
    847  MOZ_TRY(CodeTypeDefRef(coder, &item->type_));
    848  if constexpr (mode == MODE_DECODE) {
    849    if (!item->initialize(item->type_)) {
    850      return Err(OutOfMemory());
    851    }
    852  }
    853 
    854  return Ok();
    855 }
    856 
    857 template <CoderMode mode>
    858 CoderResult CodeTagDesc(Coder<mode>& coder, CoderArg<mode, TagDesc> item) {
    859  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::TagDesc, 24);
    860  MOZ_TRY(CodePod(coder, &item->kind));
    861  MOZ_TRY((
    862      CodeRefPtr<mode, const TagType, &CodeTagType<mode>>(coder, &item->type)));
    863  MOZ_TRY(CodePod(coder, &item->isExport));
    864  return Ok();
    865 }
    866 
    867 template <CoderMode mode>
    868 CoderResult CodeModuleElemSegment(Coder<mode>& coder,
    869                                  CoderArg<mode, ModuleElemSegment> item) {
    870  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::ModuleElemSegment, 232);
    871  MOZ_TRY(CodePod(coder, &item->kind));
    872  MOZ_TRY(CodePod(coder, &item->tableIndex));
    873  MOZ_TRY(CodeRefType(coder, &item->elemType));
    874  MOZ_TRY((CodeMaybe<mode, InitExpr, &CodeInitExpr<mode>>(
    875      coder, &item->offsetIfActive)));
    876  MOZ_TRY(CodePod(coder, &item->encoding));
    877  MOZ_TRY(CodePodVector(coder, &item->elemIndices));
    878  MOZ_TRY(CodePod(coder, &item->elemExpressions.count));
    879  MOZ_TRY(CodePodVector(coder, &item->elemExpressions.exprBytes));
    880  return Ok();
    881 }
    882 
    883 template <CoderMode mode>
    884 CoderResult CodeDataSegment(Coder<mode>& coder,
    885                            CoderArg<mode, DataSegment> item) {
    886  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::DataSegment, 144);
    887  MOZ_TRY(CodePod(coder, &item->memoryIndex));
    888  MOZ_TRY((CodeMaybe<mode, InitExpr, &CodeInitExpr<mode>>(
    889      coder, &item->offsetIfActive)));
    890  MOZ_TRY(CodePodVector(coder, &item->bytes));
    891  return Ok();
    892 }
    893 
    894 template <CoderMode mode>
    895 CoderResult CodeCustomSection(Coder<mode>& coder,
    896                              CoderArg<mode, CustomSection> item) {
    897  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CustomSection, 48);
    898  MOZ_TRY(CodePodVector(coder, &item->name));
    899  MOZ_TRY((CodeRefPtr<mode, const ShareableBytes, &CodeShareableBytes<mode>>(
    900      coder, &item->payload)));
    901  return Ok();
    902 }
    903 
    904 template <CoderMode mode>
    905 CoderResult CodeNameSection(Coder<mode>& coder,
    906                            CoderArg<mode, NameSection> item) {
    907  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::NameSection, 56);
    908  MOZ_TRY(CodePod(coder, &item->customSectionIndex));
    909  MOZ_TRY(CodePod(coder, &item->moduleName));
    910  MOZ_TRY(CodePodVector(coder, &item->funcNames));
    911  // We do not serialize `payload` because the ModuleMetadata will do that for
    912  // us.
    913  return Ok();
    914 }
    915 
    916 template <CoderMode mode>
    917 CoderResult CodeTableDesc(Coder<mode>& coder, CoderArg<mode, TableDesc> item) {
    918  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::TableDesc, 144);
    919  MOZ_TRY(CodeRefType(coder, &item->elemType));
    920  MOZ_TRY(CodePod(coder, &item->isImported));
    921  MOZ_TRY(CodePod(coder, &item->isExported));
    922  MOZ_TRY(CodePod(coder, &item->isAsmJS));
    923  MOZ_TRY(CodePod(coder, &item->limits));
    924  MOZ_TRY(
    925      (CodeMaybe<mode, InitExpr, &CodeInitExpr<mode>>(coder, &item->initExpr)));
    926  return Ok();
    927 }
    928 
    929 // WasmCodegenTypes.h
    930 
    931 template <CoderMode mode>
    932 CoderResult CodeTrapSitesForKind(Coder<mode>& coder,
    933                                 CoderArg<mode, TrapSitesForKind> item) {
    934  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::TrapSitesForKind, 160);
    935 #ifdef DEBUG
    936  MOZ_TRY(CodePodVector(coder, &item->machineInsns_));
    937 #endif
    938  MOZ_TRY(CodePodVector(coder, &item->pcOffsets_));
    939  MOZ_TRY(CodePodVector(coder, &item->bytecodeOffsets_));
    940  // Inlining requires lazy tiering, which does not support serialization yet.
    941  MOZ_RELEASE_ASSERT(item->inlinedCallerOffsetsMap_.empty());
    942  return Ok();
    943 }
    944 
    945 template <CoderMode mode>
    946 CoderResult CodeTrapSites(Coder<mode>& coder, CoderArg<mode, TrapSites> item) {
    947  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::TrapSites, 2080);
    948  for (Trap trap : mozilla::MakeEnumeratedRange(Trap::Limit)) {
    949    MOZ_TRY(CodeTrapSitesForKind(coder, &item->array_[trap]));
    950  }
    951  return Ok();
    952 }
    953 
    954 template <CoderMode mode>
    955 CoderResult CodeCallSites(Coder<mode>& coder, CoderArg<mode, CallSites> item) {
    956  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CallSites, 160);
    957  MOZ_TRY(CodePodVector(coder, &item->kinds_));
    958  MOZ_TRY(CodePodVector(coder, &item->lineOrBytecodes_));
    959  MOZ_TRY(CodePodVector(coder, &item->returnAddressOffsets_));
    960  // Inlining requires lazy tiering, which does not support serialization yet.
    961  MOZ_RELEASE_ASSERT(item->inlinedCallerOffsetsMap_.empty());
    962  return Ok();
    963 }
    964 
    965 // WasmCompileArgs.h
    966 
    967 template <CoderMode mode>
    968 CoderResult CodeScriptedCaller(Coder<mode>& coder,
    969                               CoderArg<mode, ScriptedCaller> item) {
    970  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::ScriptedCaller, 16);
    971  MOZ_TRY((CodeUniqueChars(coder, &item->filename)));
    972  MOZ_TRY((CodePod(coder, &item->filenameIsURL)));
    973  MOZ_TRY((CodePod(coder, &item->line)));
    974  return Ok();
    975 }
    976 
    977 template <CoderMode mode>
    978 CoderResult CodeBuiltinModuleIds(Coder<mode>& coder,
    979                                 CoderArg<mode, BuiltinModuleIds> item) {
    980  WASM_VERIFY_SERIALIZATION_FOR_SIZE(BuiltinModuleIds, 16);
    981  MOZ_TRY(CodePod(coder, &item->selfTest));
    982  MOZ_TRY(CodePod(coder, &item->intGemm));
    983  MOZ_TRY(CodePod(coder, &item->jsString));
    984  MOZ_TRY(CodePod(coder, &item->jsStringConstants));
    985  MOZ_TRY((CodeNullableRefPtr<mode, const ShareableChars, &CodeShareableChars>(
    986      coder, &item->jsStringConstantsNamespace)));
    987  return Ok();
    988 }
    989 
    990 template <CoderMode mode>
    991 CoderResult CodeFeatureArgs(Coder<mode>& coder,
    992                            CoderArg<mode, FeatureArgs> item) {
    993  WASM_VERIFY_SERIALIZATION_FOR_SIZE(FeatureArgs, 32);
    994 #define WASM_FEATURE(NAME, LOWER_NAME, ...) \
    995  MOZ_TRY(CodePod(coder, &item->LOWER_NAME));
    996  JS_FOR_WASM_FEATURES(WASM_FEATURE)
    997 #undef WASM_FEATURE
    998  MOZ_TRY(CodePod(coder, &item->sharedMemory));
    999  MOZ_TRY(CodePod(coder, &item->simd));
   1000  MOZ_TRY(CodePod(coder, &item->isBuiltinModule));
   1001  MOZ_TRY(CodeBuiltinModuleIds(coder, &item->builtinModules));
   1002  return Ok();
   1003 }
   1004 
   1005 template <CoderMode mode>
   1006 CoderResult CodeCompileArgs(Coder<mode>& coder,
   1007                            CoderArg<mode, CompileArgs> item) {
   1008  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CompileArgs, 72);
   1009  MOZ_TRY((CodeScriptedCaller(coder, &item->scriptedCaller)));
   1010  MOZ_TRY((CodeUniqueChars(coder, &item->sourceMapURL)));
   1011  MOZ_TRY((CodePod(coder, &item->baselineEnabled)));
   1012  MOZ_TRY((CodePod(coder, &item->ionEnabled)));
   1013  MOZ_TRY((CodePod(coder, &item->debugEnabled)));
   1014  MOZ_TRY((CodePod(coder, &item->forceTiering)));
   1015  MOZ_TRY((CodeFeatureArgs(coder, &item->features)));
   1016  return Ok();
   1017 }
   1018 
   1019 // WasmGC.h
   1020 
   1021 CoderResult CodeStackMap(Coder<MODE_DECODE>& coder,
   1022                         CoderArg<MODE_DECODE, wasm::StackMap*> item,
   1023                         wasm::StackMaps* stackMaps) {
   1024  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StackMap, 12);
   1025  // Decode the stack map header
   1026  StackMapHeader header;
   1027  MOZ_TRY(CodePod(coder, &header));
   1028 
   1029  // Allocate a stack map for the header
   1030  StackMap* map = stackMaps->create(header);
   1031  if (!map) {
   1032    return Err(OutOfMemory());
   1033  }
   1034 
   1035  // Decode the bitmap into the stackmap
   1036  MOZ_TRY(coder.readBytes(map->rawBitmap(), map->rawBitmapLengthInBytes()));
   1037 
   1038  *item = map;
   1039  return Ok();
   1040 }
   1041 
   1042 template <CoderMode mode>
   1043 CoderResult CodeStackMap(Coder<mode>& coder,
   1044                         CoderArg<mode, wasm::StackMap> item) {
   1045  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StackMap, 12);
   1046  STATIC_ASSERT_ENCODING_OR_SIZING;
   1047 
   1048  // Encode the stackmap header
   1049  MOZ_TRY(CodePod(coder, &item->header));
   1050 
   1051  // Encode the stackmap bitmap
   1052  MOZ_TRY(coder.writeBytes(item->rawBitmap(), item->rawBitmapLengthInBytes()));
   1053 
   1054  return Ok();
   1055 }
   1056 
   1057 CoderResult CodeStackMaps(Coder<MODE_DECODE>& coder,
   1058                          CoderArg<MODE_DECODE, wasm::StackMaps> item) {
   1059  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StackMaps, 200);
   1060  // Decode the amount of stack maps
   1061  size_t length;
   1062  MOZ_TRY(CodePod(coder, &length));
   1063 
   1064  for (size_t i = 0; i < length; i++) {
   1065    // Decode the offset
   1066    uint32_t codeOffset;
   1067    MOZ_TRY(CodePod(coder, &codeOffset));
   1068 
   1069    // Decode the stack map
   1070    StackMap* map;
   1071    MOZ_TRY(CodeStackMap(coder, &map, item));
   1072 
   1073    // Add it to the map
   1074    if (!item->finalize(codeOffset, map)) {
   1075      return Err(OutOfMemory());
   1076    }
   1077  }
   1078 
   1079  return Ok();
   1080 }
   1081 
   1082 template <CoderMode mode>
   1083 CoderResult CodeStackMaps(Coder<mode>& coder,
   1084                          CoderArg<mode, wasm::StackMaps> item) {
   1085  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StackMaps, 200);
   1086  STATIC_ASSERT_ENCODING_OR_SIZING;
   1087 
   1088  // Encode the amount of stack maps
   1089  size_t length = item->length();
   1090  MOZ_TRY(CodePod(coder, &length));
   1091 
   1092  for (auto iter = item->codeOffsetToStackMap_.iter(); !iter.done();
   1093       iter.next()) {
   1094    uint32_t codeOffset = iter.get().key();
   1095 
   1096    // Encode the offset
   1097    MOZ_TRY(CodePod(coder, &codeOffset));
   1098 
   1099    // Encode the stack map
   1100    MOZ_TRY(CodeStackMap(coder, iter.get().value()));
   1101  }
   1102  return Ok();
   1103 }
   1104 
   1105 // WasmCode.h
   1106 
   1107 template <CoderMode mode>
   1108 CoderResult CodeSymbolicLinkArray(
   1109    Coder<mode>& coder,
   1110    CoderArg<mode, wasm::LinkData::SymbolicLinkArray> item) {
   1111  for (SymbolicAddress address :
   1112       mozilla::MakeEnumeratedRange(SymbolicAddress::Limit)) {
   1113    MOZ_TRY(CodePodVector(coder, &(*item)[address]));
   1114  }
   1115  return Ok();
   1116 }
   1117 
   1118 template <CoderMode mode>
   1119 CoderResult CodeLinkData(Coder<mode>& coder,
   1120                         CoderArg<mode, wasm::LinkData> item) {
   1121  // SymbolicLinkArray depends on SymbolicAddress::Limit, which is changed
   1122  // often. Exclude symbolicLinks field from trip wire value calculation.
   1123  WASM_VERIFY_SERIALIZATION_FOR_SIZE(
   1124      wasm::LinkData, 88 + sizeof(wasm::LinkData::SymbolicLinkArray));
   1125  MOZ_TRY(CodePod(coder, &item->pod()));
   1126  MOZ_TRY(CodePodVector(coder, &item->internalLinks));
   1127  MOZ_TRY(CodePodVector(coder, &item->callFarJumps));
   1128  MOZ_TRY(CodeSymbolicLinkArray(coder, &item->symbolicLinks));
   1129  return Ok();
   1130 }
   1131 
   1132 // WasmMetadata.h
   1133 
   1134 template <CoderMode mode>
   1135 CoderResult CodeCodeMetadata(Coder<mode>& coder,
   1136                             CoderArg<mode, wasm::CodeMetadata> item) {
   1137  // NOTE: keep the field sequence here in sync with the sequence in the
   1138  // declaration of CodeMetadata.
   1139 
   1140  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CodeMetadata, 736);
   1141  // Serialization doesn't handle asm.js or debug enabled modules
   1142  MOZ_RELEASE_ASSERT(mode == MODE_SIZE || !item->isAsmJS());
   1143 
   1144  MOZ_TRY(Magic(coder, Marker::CodeMetadata));
   1145 
   1146  MOZ_TRY(CodePod(coder, &item->kind));
   1147  MOZ_TRY((CodeRefPtr<mode, const CompileArgs, &CodeCompileArgs>(
   1148      coder, &item->compileArgs)));
   1149 
   1150  MOZ_TRY(CodePod(coder, &item->numFuncImports));
   1151  MOZ_TRY(CodePod(coder, &item->funcImportsAreJS));
   1152  MOZ_TRY(CodePod(coder, &item->numGlobalImports));
   1153 
   1154  // We must deserialize types first so that they're available for
   1155  // deserializing values that need types.
   1156  MOZ_TRY(
   1157      (CodeRefPtr<mode, TypeContext, &CodeTypeContext>(coder, &item->types)));
   1158  MOZ_TRY(CodePodVector(coder, &item->funcs));
   1159  MOZ_TRY((
   1160      CodeVector<mode, TableDesc, &CodeTableDesc<mode>>(coder, &item->tables)));
   1161  MOZ_TRY(CodePodVector(coder, &item->memories));
   1162  MOZ_TRY((CodeVector<mode, TagDesc, &CodeTagDesc<mode>>(coder, &item->tags)));
   1163  MOZ_TRY((CodeVector<mode, GlobalDesc, &CodeGlobalDesc<mode>>(
   1164      coder, &item->globals)));
   1165 
   1166  MOZ_TRY((CodeMaybe<mode, uint32_t, &CodePod>(coder, &item->startFuncIndex)));
   1167 
   1168  MOZ_TRY((
   1169      CodeVector<mode, RefType, &CodeRefType>(coder, &item->elemSegmentTypes)));
   1170 
   1171  MOZ_TRY((CodeMaybe<mode, uint32_t, &CodePod>(coder, &item->dataCount)));
   1172  MOZ_TRY((CodePodVector(coder, &item->exportedFuncIndices)));
   1173 
   1174  // We do not serialize `asmJSSigToTableIndex` because we don't serialize
   1175  // asm.js.
   1176 
   1177  MOZ_TRY(CodePodVector(coder, &item->customSectionRanges));
   1178 
   1179  MOZ_TRY((CodeMaybe<mode, BytecodeRange, &CodePod>(coder,
   1180                                                    &item->codeSectionRange)));
   1181 
   1182  MOZ_TRY((CodeMaybe<mode, NameSection, &CodeNameSection>(coder,
   1183                                                          &item->nameSection)));
   1184 
   1185  // TODO (bug 1907645): We do not serialize branch hints yet.
   1186 
   1187  MOZ_TRY(CodePod(coder, &item->funcDefsOffsetStart));
   1188  MOZ_TRY(CodePod(coder, &item->funcImportsOffsetStart));
   1189  MOZ_TRY(CodePod(coder, &item->funcExportsOffsetStart));
   1190  MOZ_TRY(CodePod(coder, &item->typeDefsOffsetStart));
   1191  MOZ_TRY(CodePod(coder, &item->memoriesOffsetStart));
   1192  MOZ_TRY(CodePod(coder, &item->tablesOffsetStart));
   1193  MOZ_TRY(CodePod(coder, &item->tagsOffsetStart));
   1194  MOZ_TRY(CodePod(coder, &item->instanceDataLength));
   1195 
   1196  if constexpr (mode == MODE_DECODE) {
   1197    MOZ_ASSERT(!item->isAsmJS());
   1198  }
   1199 
   1200  return Ok();
   1201 }
   1202 
   1203 template <CoderMode mode>
   1204 CoderResult CodeCodeTailMetadata(Coder<mode>& coder,
   1205                                 CoderArg<mode, wasm::CodeTailMetadata> item) {
   1206  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CodeTailMetadata, 384);
   1207 
   1208  if constexpr (mode == MODE_ENCODE) {
   1209    MOZ_ASSERT(!item->debugEnabled);
   1210  }
   1211 
   1212  MOZ_TRY((CodeNullablePtr<
   1213           mode, SharedBytes,
   1214           &CodeRefPtr<mode, const ShareableBytes, CodeShareableBytes>>(
   1215      coder, &item->codeSectionBytecode)));
   1216 
   1217  if constexpr (mode == MODE_DECODE) {
   1218    int64_t inliningBudget;
   1219    MOZ_TRY(CodePod(coder, &inliningBudget));
   1220    item->inliningBudget.lock().get() = inliningBudget;
   1221  } else {
   1222    int64_t inliningBudget = item->inliningBudget.lock().get();
   1223    MOZ_TRY(CodePod(coder, &inliningBudget));
   1224  }
   1225 
   1226  MOZ_TRY(CodePodVector(coder, &item->funcDefRanges));
   1227  MOZ_TRY(CodePodVector(coder, &item->funcDefFeatureUsages));
   1228  MOZ_TRY(CodePodVector(coder, &item->funcDefCallRefs));
   1229  MOZ_TRY(CodePodVector(coder, &item->funcDefAllocSites));
   1230  MOZ_TRY(CodePod(coder, &item->numCallRefMetrics));
   1231  MOZ_TRY(CodePod(coder, &item->numAllocSites));
   1232 
   1233  // Name section payload is handled by ModuleMetadata.
   1234 
   1235  if constexpr (mode == MODE_DECODE) {
   1236    // Initialize debugging state to disabled
   1237    item->debugEnabled = false;
   1238  }
   1239 
   1240  return Ok();
   1241 }
   1242 
   1243 template <CoderMode mode>
   1244 CoderResult CodeModuleMetadata(Coder<mode>& coder,
   1245                               CoderArg<mode, wasm::ModuleMetadata> item) {
   1246  // NOTE: keep the field sequence here in sync with the sequence in the
   1247  // declaration of ModuleMetadata.
   1248 
   1249  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::ModuleMetadata, 272);
   1250  MOZ_TRY(Magic(coder, Marker::ModuleMetadata));
   1251 
   1252  MOZ_TRY((CodeRefPtr<mode, CodeMetadata, &CodeCodeMetadata>(coder,
   1253                                                             &item->codeMeta)));
   1254  MOZ_TRY((CodeRefPtr<mode, CodeTailMetadata, CodeCodeTailMetadata>(
   1255      coder, &item->codeTailMeta)));
   1256  if constexpr (mode == MODE_DECODE) {
   1257    item->codeTailMeta->codeMeta = item->codeMeta;
   1258  }
   1259  MOZ_TRY(Magic(coder, Marker::Imports));
   1260  MOZ_TRY((CodeVector<mode, Import, &CodeImport<mode>>(coder, &item->imports)));
   1261  MOZ_TRY(Magic(coder, Marker::Exports));
   1262  MOZ_TRY((CodeVector<mode, Export, &CodeExport<mode>>(coder, &item->exports)));
   1263  MOZ_TRY(Magic(coder, Marker::ElemSegments));
   1264  MOZ_TRY((CodeVector<mode, ModuleElemSegment, CodeModuleElemSegment<mode>>(
   1265      coder, &item->elemSegments)));
   1266  // not serialized: dataSegmentRanges
   1267  MOZ_TRY(Magic(coder, Marker::DataSegments));
   1268  MOZ_TRY(
   1269      (CodeVector<mode, SharedDataSegment,
   1270                  &CodeRefPtr<mode, const DataSegment, CodeDataSegment<mode>>>(
   1271          coder, &item->dataSegments)));
   1272  MOZ_TRY(Magic(coder, Marker::CustomSections));
   1273  MOZ_TRY((CodeVector<mode, CustomSection, &CodeCustomSection<mode>>(
   1274      coder, &item->customSections)));
   1275  MOZ_TRY(CodePod(coder, &item->featureUsage));
   1276 
   1277  // Give CodeTailMetadata a pointer to our name payload now that we've
   1278  // deserialized it.
   1279  if constexpr (mode == MODE_DECODE) {
   1280    if (item->codeMeta->nameSection) {
   1281      item->codeTailMeta->nameSectionPayload =
   1282          item->customSections[item->codeMeta->nameSection->customSectionIndex]
   1283              .payload;
   1284    }
   1285  }
   1286 
   1287  return Ok();
   1288 }
   1289 
   1290 // WasmCode.h
   1291 
   1292 template <CoderMode mode>
   1293 CoderResult CodeFuncToCodeRangeMap(
   1294    Coder<mode>& coder, CoderArg<mode, wasm::FuncToCodeRangeMap> item) {
   1295  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::FuncToCodeRangeMap, 80);
   1296  MOZ_TRY(CodePod(coder, &item->startFuncIndex_));
   1297  MOZ_TRY(CodePodVector(coder, &item->funcToCodeRange_));
   1298  return Ok();
   1299 }
   1300 
   1301 CoderResult CodeCodeBlock(Coder<MODE_DECODE>& coder,
   1302                          wasm::UniqueCodeBlock* item,
   1303                          const wasm::LinkData& linkData) {
   1304  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CodeBlock, 2784);
   1305  *item = js::MakeUnique<CodeBlock>(CodeBlock::kindFromTier(Tier::Serialized));
   1306  if (!*item) {
   1307    return Err(OutOfMemory());
   1308  }
   1309  MOZ_TRY(Magic(coder, Marker::CodeBlock));
   1310 
   1311  // Decode the code byte range
   1312  size_t codeBytesLength;
   1313  const uint8_t* codeBytes;
   1314  MOZ_TRY(CodePod(coder, &codeBytesLength));
   1315  MOZ_TRY(coder.readBytesRef(codeBytesLength, &codeBytes));
   1316 
   1317  // Allocate a code segment using the code bytes
   1318  uint8_t* codeStart;
   1319  uint32_t allocationLength;
   1320  CodeSource codeSource(codeBytes, codeBytesLength, linkData, nullptr);
   1321  (*item)->segment =
   1322      CodeSegment::allocate(codeSource, nullptr, /* allowLastDitchGC */ true,
   1323                            &codeStart, &allocationLength);
   1324  if (!(*item)->segment) {
   1325    return Err(OutOfMemory());
   1326  }
   1327  (*item)->codeBase = codeStart;
   1328  (*item)->codeLength = codeSource.lengthBytes();
   1329 
   1330  MOZ_TRY(CodeFuncToCodeRangeMap(coder, &(*item)->funcToCodeRange));
   1331  MOZ_TRY(CodePodVector(coder, &(*item)->codeRanges));
   1332  MOZ_TRY(CodeCallSites(coder, &(*item)->callSites));
   1333  MOZ_TRY(CodeTrapSites(coder, &(*item)->trapSites));
   1334  MOZ_TRY(CodePodVector(coder, &(*item)->funcExports));
   1335  MOZ_TRY(CodeStackMaps(coder, &(*item)->stackMaps));
   1336  MOZ_TRY(CodePodVector(coder, &(*item)->tryNotes));
   1337  MOZ_TRY(CodePodVector(coder, &(*item)->codeRangeUnwindInfos));
   1338  return Ok();
   1339 }
   1340 
   1341 template <CoderMode mode>
   1342 CoderResult CodeCodeBlock(Coder<mode>& coder,
   1343                          CoderArg<mode, wasm::CodeBlock> item,
   1344                          const wasm::LinkData& linkData) {
   1345  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::CodeBlock, 2784);
   1346  STATIC_ASSERT_ENCODING_OR_SIZING;
   1347  MOZ_TRY(Magic(coder, Marker::CodeBlock));
   1348 
   1349  // Encode the code bytes
   1350  MOZ_TRY(CodePod(coder, &item->codeLength));
   1351  if constexpr (mode == MODE_SIZE) {
   1352    // Just calculate the length of bytes written
   1353    MOZ_TRY(coder.writeBytes(item->codeBase, item->codeLength));
   1354  } else {
   1355    // Get the start of where the code bytes will be written
   1356    uint8_t* serializedBase = coder.buffer_;
   1357    // Write the code bytes
   1358    MOZ_TRY(coder.writeBytes(item->codeBase, item->codeLength));
   1359    // Unlink the code bytes written to the buffer
   1360    StaticallyUnlink(serializedBase, linkData);
   1361  }
   1362 
   1363  MOZ_TRY(CodeFuncToCodeRangeMap(coder, &item->funcToCodeRange));
   1364  MOZ_TRY(CodePodVector(coder, &item->codeRanges));
   1365  MOZ_TRY(CodeCallSites(coder, &item->callSites));
   1366  MOZ_TRY(CodeTrapSites(coder, &item->trapSites));
   1367  MOZ_TRY(CodePodVector(coder, &item->funcExports));
   1368  MOZ_TRY(CodeStackMaps(coder, &item->stackMaps));
   1369  MOZ_TRY(CodePodVector(coder, &item->tryNotes));
   1370  MOZ_TRY(CodePodVector(coder, &item->codeRangeUnwindInfos));
   1371  return Ok();
   1372 }
   1373 
   1374 CoderResult CodeSharedCode(Coder<MODE_DECODE>& coder, wasm::SharedCode* item,
   1375                           const wasm::ModuleMetadata& moduleMeta) {
   1376  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::Code, 976);
   1377 
   1378  FuncImportVector funcImports;
   1379  MOZ_TRY(CodePodVector(coder, &funcImports));
   1380 
   1381  UniqueCodeBlock sharedStubs;
   1382  UniqueLinkData sharedStubsLinkData;
   1383  MOZ_TRY((CodeUniquePtr<MODE_DECODE, LinkData, CodeLinkData>(
   1384      coder, &sharedStubsLinkData)));
   1385  MOZ_TRY(CodeCodeBlock(coder, &sharedStubs, *sharedStubsLinkData));
   1386  sharedStubs->sendToProfiler(*moduleMeta.codeMeta, *moduleMeta.codeTailMeta,
   1387                              nullptr, FuncIonPerfSpewerSpan(),
   1388                              FuncBaselinePerfSpewerSpan());
   1389 
   1390  UniqueLinkData optimizedCodeLinkData;
   1391  UniqueCodeBlock optimizedCode;
   1392  MOZ_TRY((CodeUniquePtr<MODE_DECODE, LinkData, CodeLinkData>(
   1393      coder, &optimizedCodeLinkData)));
   1394  MOZ_TRY(CodeCodeBlock(coder, &optimizedCode, *optimizedCodeLinkData));
   1395  optimizedCode->sendToProfiler(*moduleMeta.codeMeta, *moduleMeta.codeTailMeta,
   1396                                nullptr, FuncIonPerfSpewerSpan(),
   1397                                FuncBaselinePerfSpewerSpan());
   1398 
   1399  // Create and initialize the code
   1400  MutableCode code = js_new<Code>(CompileMode::Once, *moduleMeta.codeMeta,
   1401                                  *moduleMeta.codeTailMeta,
   1402                                  /*codeMetaForAsmJS=*/nullptr);
   1403  if (!code || !code->initialize(
   1404                   std::move(funcImports), std::move(sharedStubs),
   1405                   std::move(sharedStubsLinkData), std::move(optimizedCode),
   1406                   std::move(optimizedCodeLinkData), CompileAndLinkStats())) {
   1407    return Err(OutOfMemory());
   1408  }
   1409 
   1410  // not serialized: debugStubOffset_
   1411 
   1412  uint32_t offsetOfRequestTierUpStub = 0;
   1413  MOZ_TRY(CodePod(coder, &offsetOfRequestTierUpStub));
   1414  code->setRequestTierUpStubOffset(offsetOfRequestTierUpStub);
   1415 
   1416  uint32_t offsetOfCallRefMetricsStub = 0;
   1417  MOZ_TRY(CodePod(coder, &offsetOfCallRefMetricsStub));
   1418  code->setUpdateCallRefMetricsStubOffset(offsetOfCallRefMetricsStub);
   1419 
   1420  *item = code;
   1421  return Ok();
   1422 }
   1423 
   1424 template <CoderMode mode>
   1425 CoderResult CodeSharedCode(Coder<mode>& coder,
   1426                           CoderArg<mode, wasm::SharedCode> item) {
   1427  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::Code, 976);
   1428  STATIC_ASSERT_ENCODING_OR_SIZING;
   1429  // Don't encode the CodeMetadata or CodeTailMetadata, that is handled by
   1430  // wasm::ModuleMetadata.
   1431  MOZ_TRY(CodePodVector(coder, &(*item)->funcImports()));
   1432  const CodeBlock& sharedStubsCodeBlock = (*item)->sharedStubs();
   1433  const LinkData& sharedStubsLinkData =
   1434      *(*item)->codeBlockLinkData(sharedStubsCodeBlock);
   1435  MOZ_TRY(CodeLinkData(coder, &sharedStubsLinkData));
   1436  MOZ_TRY(CodeCodeBlock(coder, &sharedStubsCodeBlock, sharedStubsLinkData));
   1437  const CodeBlock& optimizedCodeBlock =
   1438      (*item)->completeTierCodeBlock(Tier::Serialized);
   1439  const LinkData& optimizedLinkData =
   1440      *(*item)->codeBlockLinkData(optimizedCodeBlock);
   1441  MOZ_TRY(CodeLinkData(coder, &optimizedLinkData));
   1442  MOZ_TRY(CodeCodeBlock(coder, &optimizedCodeBlock, optimizedLinkData));
   1443 
   1444  // not serialized: debugStubOffset_
   1445 
   1446  uint32_t offsetOfRequestTierUpStub = (*item)->requestTierUpStubOffset();
   1447  MOZ_TRY(CodePod(coder, &offsetOfRequestTierUpStub));
   1448 
   1449  uint32_t offsetOfCallRefMetricsStub =
   1450      (*item)->updateCallRefMetricsStubOffset();
   1451  MOZ_TRY(CodePod(coder, &offsetOfCallRefMetricsStub));
   1452 
   1453  return Ok();
   1454 }
   1455 
   1456 // WasmModule.h
   1457 
   1458 CoderResult CodeModule(Coder<MODE_DECODE>& coder, MutableModule* item) {
   1459  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::Module, 56);
   1460  JS::BuildIdCharVector currentBuildId;
   1461  if (!GetOptimizedEncodingBuildId(&currentBuildId)) {
   1462    return Err(OutOfMemory());
   1463  }
   1464  JS::BuildIdCharVector deserializedBuildId;
   1465  MOZ_TRY(CodePodVector(coder, &deserializedBuildId));
   1466 
   1467  MOZ_RELEASE_ASSERT(EqualContainers(currentBuildId, deserializedBuildId));
   1468 
   1469  MutableModuleMetadata moduleMeta;
   1470  MOZ_TRY((CodeRefPtr<MODE_DECODE, ModuleMetadata, &CodeModuleMetadata>(
   1471      coder, &moduleMeta)));
   1472 
   1473  SharedCode code;
   1474  MOZ_TRY(Magic(coder, Marker::Code));
   1475  MOZ_TRY(CodeSharedCode(coder, &code, *moduleMeta));
   1476 
   1477  *item = js_new<Module>(*moduleMeta, *code,
   1478                         /* loggingDeserialized = */ true);
   1479  return Ok();
   1480 }
   1481 
   1482 template <CoderMode mode>
   1483 CoderResult CodeModule(Coder<mode>& coder, CoderArg<mode, Module> item) {
   1484  WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::Module, 56);
   1485  STATIC_ASSERT_ENCODING_OR_SIZING;
   1486  MOZ_RELEASE_ASSERT(!item->code().debugEnabled());
   1487  MOZ_RELEASE_ASSERT(item->code_->hasCompleteTier(Tier::Serialized));
   1488 
   1489  JS::BuildIdCharVector currentBuildId;
   1490  if (!GetOptimizedEncodingBuildId(&currentBuildId)) {
   1491    return Err(OutOfMemory());
   1492  }
   1493  MOZ_TRY(CodePodVector(coder, &currentBuildId));
   1494  MOZ_TRY((CodeRefPtr<mode, const ModuleMetadata, &CodeModuleMetadata>(
   1495      coder, &item->moduleMeta_)));
   1496  MOZ_TRY(Magic(coder, Marker::Code));
   1497  MOZ_TRY(CodeSharedCode(coder, &item->code_));
   1498  return Ok();
   1499 }
   1500 
   1501 }  // namespace wasm
   1502 }  // namespace js
   1503 
   1504 bool Module::canSerialize() const {
   1505  // TODO(bug 1903131): JS string builtins don't support serialization
   1506  // TODO(bug 1913109): lazy tiering doesn't support serialization
   1507  return code_->mode() != CompileMode::LazyTiering &&
   1508         !codeMeta().isBuiltinModule() &&
   1509         codeMeta().features().builtinModules.hasNone() &&
   1510         !code_->debugEnabled();
   1511 }
   1512 
   1513 static bool GetSerializedSize(const Module& module, size_t* size) {
   1514  Coder<MODE_SIZE> coder(module.codeMeta().types.get());
   1515  auto result = CodeModule(coder, &module);
   1516  if (result.isErr()) {
   1517    return false;
   1518  }
   1519  *size = coder.size_.value();
   1520  return true;
   1521 }
   1522 
   1523 bool Module::serialize(Bytes* bytes) const {
   1524  MOZ_RELEASE_ASSERT(canSerialize());
   1525  MOZ_RELEASE_ASSERT(code_->hasCompleteTier(Tier::Serialized));
   1526 
   1527  size_t serializedSize;
   1528  if (!GetSerializedSize(*this, &serializedSize)) {
   1529    // An error is an overflow, return false
   1530    return false;
   1531  }
   1532 
   1533  // Try to allocate the destination buffer
   1534  if (!bytes->resizeUninitialized(serializedSize)) {
   1535    return false;
   1536  }
   1537 
   1538  Coder<MODE_ENCODE> coder(codeMeta().types.get(), bytes->begin(),
   1539                           serializedSize);
   1540  CoderResult result = CodeModule(coder, this);
   1541  if (result.isErr()) {
   1542    // An error is an OOM, return false
   1543    return false;
   1544  }
   1545  // Every byte is accounted for
   1546  MOZ_RELEASE_ASSERT(coder.buffer_ == coder.end_);
   1547 
   1548  // Clear out link data now, it's no longer needed.
   1549  code().clearLinkData();
   1550 
   1551  return true;
   1552 }
   1553 
   1554 /* static */
   1555 MutableModule Module::deserialize(const uint8_t* begin, size_t size) {
   1556  Coder<MODE_DECODE> coder(begin, size);
   1557  MutableModule module;
   1558  CoderResult result = CodeModule(coder, &module);
   1559  if (result.isErr()) {
   1560    // An error is an OOM, return nullptr
   1561    return nullptr;
   1562  }
   1563  // Every byte is accounted for
   1564  MOZ_RELEASE_ASSERT(coder.buffer_ == coder.end_);
   1565  return module;
   1566 }
   1567 
   1568 void Module::initGCMallocBytesExcludingCode() {
   1569  // The size doesn't have to be exact so use the serialization framework to
   1570  // calculate a value. We consume all errors, as they can only be overflow and
   1571  // can be ignored until the end.
   1572  constexpr CoderMode MODE = MODE_SIZE;
   1573  Coder<MODE> coder(codeMeta().types.get());
   1574 
   1575  // Add the size of the ModuleMetadata
   1576  (void)CodeModuleMetadata<MODE>(coder, moduleMeta_);
   1577 
   1578  // Overflow really shouldn't be possible here, but handle it anyways.
   1579  size_t serializedSize = coder.size_.isValid() ? coder.size_.value() : 0;
   1580  gcMallocBytesExcludingCode_ = sizeof(*this) + serializedSize;
   1581 }