/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 *
 * Copyright 2015 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "wasm/WasmOpIter.h"

#include "jit/AtomicOp.h"

using namespace js;
using namespace js::jit;
using namespace js::wasm;

#ifdef ENABLE_WASM_SIMD
#  define WASM_SIMD_OP(code) return code
#else
#  define WASM_SIMD_OP(code) break
#endif

#ifdef DEBUG
OpKind wasm::Classify(OpBytes op) {
  switch (Op(op.b0)) {
    case Op::Block:
      return OpKind::Block;
    case Op::Loop:
      return OpKind::Loop;
    case Op::Unreachable:
      return OpKind::Unreachable;
    case Op::Drop:
      return OpKind::Drop;
    case Op::I32Const:
      return OpKind::I32Const;
    case Op::I64Const:
      return OpKind::I64Const;
    case Op::F32Const:
      return OpKind::F32Const;
    case Op::F64Const:
      return OpKind::F64Const;
    case Op::Br:
      return OpKind::Br;
    case Op::BrIf:
      return OpKind::BrIf;
    case Op::BrTable:
      return OpKind::BrTable;
    case Op::Nop:
      return OpKind::Nop;
    case Op::I32Clz:
    case Op::I32Ctz:
    case Op::I32Popcnt:
    case Op::I64Clz:
    case Op::I64Ctz:
    case Op::I64Popcnt:
    case Op::F32Abs:
    case Op::F32Neg:
    case Op::F32Ceil:
    case Op::F32Floor:
    case Op::F32Trunc:
    case Op::F32Nearest:
    case Op::F32Sqrt:
    case Op::F64Abs:
    case Op::F64Neg:
    case Op::F64Ceil:
    case Op::F64Floor:
    case Op::F64Trunc:
    case Op::F64Nearest:
    case Op::F64Sqrt:
      return OpKind::Unary;
    case Op::I32Add:
    case Op::I32Sub:
    case Op::I32Mul:
    case Op::I32DivS:
    case Op::I32DivU:
    case Op::I32RemS:
    case Op::I32RemU:
    case Op::I32And:
    case Op::I32Or:
    case Op::I32Xor:
    case Op::I32Shl:
    case Op::I32ShrS:
    case Op::I32ShrU:
    case Op::I32Rotl:
    case Op::I32Rotr:
    case Op::I64Add:
    case Op::I64Sub:
    case Op::I64Mul:
    case Op::I64DivS:
    case Op::I64DivU:
    case Op::I64RemS:
    case Op::I64RemU:
    case Op::I64And:
    case Op::I64Or:
    case Op::I64Xor:
    case Op::I64Shl:
    case Op::I64ShrS:
    case Op::I64ShrU:
    case Op::I64Rotl:
    case Op::I64Rotr:
    case Op::F32Add:
    case Op::F32Sub:
    case Op::F32Mul:
    case Op::F32Div:
    case Op::F32Min:
    case Op::F32Max:
    case Op::F32CopySign:
    case Op::F64Add:
    case Op::F64Sub:
    case Op::F64Mul:
    case Op::F64Div:
    case Op::F64Min:
    case Op::F64Max:
    case Op::F64CopySign:
      return OpKind::Binary;
    case Op::I32Eq:
    case Op::I32Ne:
    case Op::I32LtS:
    case Op::I32LtU:
    case Op::I32LeS:
    case Op::I32LeU:
    case Op::I32GtS:
    case Op::I32GtU:
    case Op::I32GeS:
    case Op::I32GeU:
    case Op::I64Eq:
    case Op::I64Ne:
    case Op::I64LtS:
    case Op::I64LtU:
    case Op::I64LeS:
    case Op::I64LeU:
    case Op::I64GtS:
    case Op::I64GtU:
    case Op::I64GeS:
    case Op::I64GeU:
    case Op::F32Eq:
    case Op::F32Ne:
    case Op::F32Lt:
    case Op::F32Le:
    case Op::F32Gt:
    case Op::F32Ge:
    case Op::F64Eq:
    case Op::F64Ne:
    case Op::F64Lt:
    case Op::F64Le:
    case Op::F64Gt:
    case Op::F64Ge:
      return OpKind::Comparison;
    case Op::I32Eqz:
    case Op::I32WrapI64:
    case Op::I32TruncF32S:
    case Op::I32TruncF32U:
    case Op::I32ReinterpretF32:
    case Op::I32TruncF64S:
    case Op::I32TruncF64U:
    case Op::I64ExtendI32S:
    case Op::I64ExtendI32U:
    case Op::I64TruncF32S:
    case Op::I64TruncF32U:
    case Op::I64TruncF64S:
    case Op::I64TruncF64U:
    case Op::I64ReinterpretF64:
    case Op::I64Eqz:
    case Op::F32ConvertI32S:
    case Op::F32ConvertI32U:
    case Op::F32ReinterpretI32:
    case Op::F32ConvertI64S:
    case Op::F32ConvertI64U:
    case Op::F32DemoteF64:
    case Op::F64ConvertI32S:
    case Op::F64ConvertI32U:
    case Op::F64ConvertI64S:
    case Op::F64ConvertI64U:
    case Op::F64ReinterpretI64:
    case Op::F64PromoteF32:
    case Op::I32Extend8S:
    case Op::I32Extend16S:
    case Op::I64Extend8S:
    case Op::I64Extend16S:
    case Op::I64Extend32S:
      return OpKind::Conversion;
    case Op::I32Load8S:
    case Op::I32Load8U:
    case Op::I32Load16S:
    case Op::I32Load16U:
    case Op::I64Load8S:
    case Op::I64Load8U:
    case Op::I64Load16S:
    case Op::I64Load16U:
    case Op::I64Load32S:
    case Op::I64Load32U:
    case Op::I32Load:
    case Op::I64Load:
    case Op::F32Load:
    case Op::F64Load:
      return OpKind::Load;
    case Op::I32Store8:
    case Op::I32Store16:
    case Op::I64Store8:
    case Op::I64Store16:
    case Op::I64Store32:
    case Op::I32Store:
    case Op::I64Store:
    case Op::F32Store:
    case Op::F64Store:
      return OpKind::Store;
    case Op::SelectNumeric:
    case Op::SelectTyped:
      return OpKind::Select;
    case Op::LocalGet:
      return OpKind::GetLocal;
    case Op::LocalSet:
      return OpKind::SetLocal;
    case Op::LocalTee:
      return OpKind::TeeLocal;
    case Op::GlobalGet:
      return OpKind::GetGlobal;
    case Op::GlobalSet:
      return OpKind::SetGlobal;
    case Op::TableGet:
      return OpKind::TableGet;
    case Op::TableSet:
      return OpKind::TableSet;
    case Op::Call:
      return OpKind::Call;
    case Op::ReturnCall:
      return OpKind::ReturnCall;
    case Op::CallIndirect:
      return OpKind::CallIndirect;
    case Op::ReturnCallIndirect:
      return OpKind::ReturnCallIndirect;
    case Op::CallRef:
      return OpKind::CallRef;
    case Op::ReturnCallRef:
      return OpKind::ReturnCallRef;
    case Op::Return:
    case Op::Limit:
      // Accept Limit, for use in decoding the end of a function after the body.
      return OpKind::Return;
    case Op::If:
      return OpKind::If;
    case Op::Else:
      return OpKind::Else;
    case Op::End:
      return OpKind::End;
    case Op::Catch:
      return OpKind::Catch;
    case Op::CatchAll:
      return OpKind::CatchAll;
    case Op::Delegate:
      return OpKind::Delegate;
    case Op::Throw:
      return OpKind::Throw;
    case Op::Rethrow:
      return OpKind::Rethrow;
    case Op::Try:
      return OpKind::Try;
    case Op::ThrowRef:
      return OpKind::ThrowRef;
    case Op::TryTable:
      return OpKind::TryTable;
    case Op::MemorySize:
      return OpKind::MemorySize;
    case Op::MemoryGrow:
      return OpKind::MemoryGrow;
    case Op::RefNull:
      return OpKind::RefNull;
    case Op::RefFunc:
      return OpKind::RefFunc;
    case Op::RefIsNull:
      return OpKind::RefIsNull;
    case Op::RefAsNonNull:
      return OpKind::RefAsNonNull;
    case Op::BrOnNull:
      return OpKind::BrOnNull;
    case Op::BrOnNonNull:
      return OpKind::BrOnNonNull;
    case Op::RefEq:
      return OpKind::Comparison;
    case Op::GcPrefix: {
      switch (GcOp(op.b1)) {
        case GcOp::Limit:
          // Reject Limit for GcPrefix encoding
          break;
        case GcOp::StructNew:
          return OpKind::StructNew;
        case GcOp::StructNewDefault:
          return OpKind::StructNewDefault;
        case GcOp::StructGet:
        case GcOp::StructGetS:
        case GcOp::StructGetU:
          return OpKind::StructGet;
        case GcOp::StructSet:
          return OpKind::StructSet;
        case GcOp::ArrayNew:
          return OpKind::ArrayNew;
        case GcOp::ArrayNewFixed:
          return OpKind::ArrayNewFixed;
        case GcOp::ArrayNewDefault:
          return OpKind::ArrayNewDefault;
        case GcOp::ArrayNewData:
          return OpKind::ArrayNewData;
        case GcOp::ArrayNewElem:
          return OpKind::ArrayNewElem;
        case GcOp::ArrayInitData:
          return OpKind::ArrayInitData;
        case GcOp::ArrayInitElem:
          return OpKind::ArrayInitElem;
        case GcOp::ArrayGet:
        case GcOp::ArrayGetS:
        case GcOp::ArrayGetU:
          return OpKind::ArrayGet;
        case GcOp::ArraySet:
          return OpKind::ArraySet;
        case GcOp::ArrayLen:
          return OpKind::ArrayLen;
        case GcOp::ArrayCopy:
          return OpKind::ArrayCopy;
        case GcOp::ArrayFill:
          return OpKind::ArrayFill;
        case GcOp::RefI31:
        case GcOp::I31GetS:
        case GcOp::I31GetU:
          return OpKind::Conversion;
        case GcOp::RefTest:
        case GcOp::RefTestNull:
          return OpKind::RefTest;
        case GcOp::RefCast:
        case GcOp::RefCastNull:
          return OpKind::RefCast;
        case GcOp::BrOnCast:
        case GcOp::BrOnCastFail:
          return OpKind::BrOnCast;
        case GcOp::AnyConvertExtern:
          return OpKind::RefConversion;
        case GcOp::ExternConvertAny:
          return OpKind::RefConversion;
      }
      break;
    }
    case Op::SimdPrefix: {
      switch (SimdOp(op.b1)) {
        case SimdOp::MozPMADDUBSW:
        case SimdOp::Limit:
          // Reject Limit and reserved codes for SimdPrefix encoding
          break;
        case SimdOp::I8x16ExtractLaneS:
        case SimdOp::I8x16ExtractLaneU:
        case SimdOp::I16x8ExtractLaneS:
        case SimdOp::I16x8ExtractLaneU:
        case SimdOp::I32x4ExtractLane:
        case SimdOp::I64x2ExtractLane:
        case SimdOp::F32x4ExtractLane:
        case SimdOp::F64x2ExtractLane:
          WASM_SIMD_OP(OpKind::ExtractLane);
        case SimdOp::I8x16Splat:
        case SimdOp::I16x8Splat:
        case SimdOp::I32x4Splat:
        case SimdOp::I64x2Splat:
        case SimdOp::F32x4Splat:
        case SimdOp::F64x2Splat:
        case SimdOp::V128AnyTrue:
        case SimdOp::I8x16AllTrue:
        case SimdOp::I16x8AllTrue:
        case SimdOp::I32x4AllTrue:
        case SimdOp::I64x2AllTrue:
        case SimdOp::I8x16Bitmask:
        case SimdOp::I16x8Bitmask:
        case SimdOp::I32x4Bitmask:
        case SimdOp::I64x2Bitmask:
          WASM_SIMD_OP(OpKind::Conversion);
        case SimdOp::I8x16ReplaceLane:
        case SimdOp::I16x8ReplaceLane:
        case SimdOp::I32x4ReplaceLane:
        case SimdOp::I64x2ReplaceLane:
        case SimdOp::F32x4ReplaceLane:
        case SimdOp::F64x2ReplaceLane:
          WASM_SIMD_OP(OpKind::ReplaceLane);
        case SimdOp::I8x16Eq:
        case SimdOp::I8x16Ne:
        case SimdOp::I8x16LtS:
        case SimdOp::I8x16LtU:
        case SimdOp::I8x16GtS:
        case SimdOp::I8x16GtU:
        case SimdOp::I8x16LeS:
        case SimdOp::I8x16LeU:
        case SimdOp::I8x16GeS:
        case SimdOp::I8x16GeU:
        case SimdOp::I16x8Eq:
        case SimdOp::I16x8Ne:
        case SimdOp::I16x8LtS:
        case SimdOp::I16x8LtU:
        case SimdOp::I16x8GtS:
        case SimdOp::I16x8GtU:
        case SimdOp::I16x8LeS:
        case SimdOp::I16x8LeU:
        case SimdOp::I16x8GeS:
        case SimdOp::I16x8GeU:
        case SimdOp::I32x4Eq:
        case SimdOp::I32x4Ne:
        case SimdOp::I32x4LtS:
        case SimdOp::I32x4LtU:
        case SimdOp::I32x4GtS:
        case SimdOp::I32x4GtU:
        case SimdOp::I32x4LeS:
        case SimdOp::I32x4LeU:
        case SimdOp::I32x4GeS:
        case SimdOp::I32x4GeU:
        case SimdOp::I64x2Eq:
        case SimdOp::I64x2Ne:
        case SimdOp::I64x2LtS:
        case SimdOp::I64x2GtS:
        case SimdOp::I64x2LeS:
        case SimdOp::I64x2GeS:
        case SimdOp::F32x4Eq:
        case SimdOp::F32x4Ne:
        case SimdOp::F32x4Lt:
        case SimdOp::F32x4Gt:
        case SimdOp::F32x4Le:
        case SimdOp::F32x4Ge:
        case SimdOp::F64x2Eq:
        case SimdOp::F64x2Ne:
        case SimdOp::F64x2Lt:
        case SimdOp::F64x2Gt:
        case SimdOp::F64x2Le:
        case SimdOp::F64x2Ge:
        case SimdOp::V128And:
        case SimdOp::V128Or:
        case SimdOp::V128Xor:
        case SimdOp::V128AndNot:
        case SimdOp::I8x16AvgrU:
        case SimdOp::I16x8AvgrU:
        case SimdOp::I8x16Add:
        case SimdOp::I8x16AddSatS:
        case SimdOp::I8x16AddSatU:
        case SimdOp::I8x16Sub:
        case SimdOp::I8x16SubSatS:
        case SimdOp::I8x16SubSatU:
        case SimdOp::I8x16MinS:
        case SimdOp::I8x16MaxS:
        case SimdOp::I8x16MinU:
        case SimdOp::I8x16MaxU:
        case SimdOp::I16x8Add:
        case SimdOp::I16x8AddSatS:
        case SimdOp::I16x8AddSatU:
        case SimdOp::I16x8Sub:
        case SimdOp::I16x8SubSatS:
        case SimdOp::I16x8SubSatU:
        case SimdOp::I16x8Mul:
        case SimdOp::I16x8MinS:
        case SimdOp::I16x8MaxS:
        case SimdOp::I16x8MinU:
        case SimdOp::I16x8MaxU:
        case SimdOp::I32x4Add:
        case SimdOp::I32x4Sub:
        case SimdOp::I32x4Mul:
        case SimdOp::I32x4MinS:
        case SimdOp::I32x4MaxS:
        case SimdOp::I32x4MinU:
        case SimdOp::I32x4MaxU:
        case SimdOp::I64x2Add:
        case SimdOp::I64x2Sub:
        case SimdOp::I64x2Mul:
        case SimdOp::F32x4Add:
        case SimdOp::F32x4Sub:
        case SimdOp::F32x4Mul:
        case SimdOp::F32x4Div:
        case SimdOp::F32x4Min:
        case SimdOp::F32x4Max:
        case SimdOp::F64x2Add:
        case SimdOp::F64x2Sub:
        case SimdOp::F64x2Mul:
        case SimdOp::F64x2Div:
        case SimdOp::F64x2Min:
        case SimdOp::F64x2Max:
        case SimdOp::I8x16NarrowI16x8S:
        case SimdOp::I8x16NarrowI16x8U:
        case SimdOp::I16x8NarrowI32x4S:
        case SimdOp::I16x8NarrowI32x4U:
        case SimdOp::I8x16Swizzle:
        case SimdOp::F32x4PMin:
        case SimdOp::F32x4PMax:
        case SimdOp::F64x2PMin:
        case SimdOp::F64x2PMax:
        case SimdOp::I32x4DotI16x8S:
        case SimdOp::I16x8ExtmulLowI8x16S:
        case SimdOp::I16x8ExtmulHighI8x16S:
        case SimdOp::I16x8ExtmulLowI8x16U:
        case SimdOp::I16x8ExtmulHighI8x16U:
        case SimdOp::I32x4ExtmulLowI16x8S:
        case SimdOp::I32x4ExtmulHighI16x8S:
        case SimdOp::I32x4ExtmulLowI16x8U:
        case SimdOp::I32x4ExtmulHighI16x8U:
        case SimdOp::I64x2ExtmulLowI32x4S:
        case SimdOp::I64x2ExtmulHighI32x4S:
        case SimdOp::I64x2ExtmulLowI32x4U:
        case SimdOp::I64x2ExtmulHighI32x4U:
        case SimdOp::I16x8Q15MulrSatS:
        case SimdOp::F32x4RelaxedMin:
        case SimdOp::F32x4RelaxedMax:
        case SimdOp::F64x2RelaxedMin:
        case SimdOp::F64x2RelaxedMax:
        case SimdOp::I8x16RelaxedSwizzle:
        case SimdOp::I16x8RelaxedQ15MulrS:
        case SimdOp::I16x8RelaxedDotI8x16I7x16S:
          WASM_SIMD_OP(OpKind::Binary);
        case SimdOp::I8x16Neg:
        case SimdOp::I16x8Neg:
        case SimdOp::I16x8ExtendLowI8x16S:
        case SimdOp::I16x8ExtendHighI8x16S:
        case SimdOp::I16x8ExtendLowI8x16U:
        case SimdOp::I16x8ExtendHighI8x16U:
        case SimdOp::I32x4Neg:
        case SimdOp::I32x4ExtendLowI16x8S:
        case SimdOp::I32x4ExtendHighI16x8S:
        case SimdOp::I32x4ExtendLowI16x8U:
        case SimdOp::I32x4ExtendHighI16x8U:
        case SimdOp::I32x4TruncSatF32x4S:
        case SimdOp::I32x4TruncSatF32x4U:
        case SimdOp::I64x2Neg:
        case SimdOp::I64x2ExtendLowI32x4S:
        case SimdOp::I64x2ExtendHighI32x4S:
        case SimdOp::I64x2ExtendLowI32x4U:
        case SimdOp::I64x2ExtendHighI32x4U:
        case SimdOp::F32x4Abs:
        case SimdOp::F32x4Neg:
        case SimdOp::F32x4Sqrt:
        case SimdOp::F32x4ConvertI32x4S:
        case SimdOp::F32x4ConvertI32x4U:
        case SimdOp::F64x2Abs:
        case SimdOp::F64x2Neg:
        case SimdOp::F64x2Sqrt:
        case SimdOp::V128Not:
        case SimdOp::I8x16Popcnt:
        case SimdOp::I8x16Abs:
        case SimdOp::I16x8Abs:
        case SimdOp::I32x4Abs:
        case SimdOp::I64x2Abs:
        case SimdOp::F32x4Ceil:
        case SimdOp::F32x4Floor:
        case SimdOp::F32x4Trunc:
        case SimdOp::F32x4Nearest:
        case SimdOp::F64x2Ceil:
        case SimdOp::F64x2Floor:
        case SimdOp::F64x2Trunc:
        case SimdOp::F64x2Nearest:
        case SimdOp::F32x4DemoteF64x2Zero:
        case SimdOp::F64x2PromoteLowF32x4:
        case SimdOp::F64x2ConvertLowI32x4S:
        case SimdOp::F64x2ConvertLowI32x4U:
        case SimdOp::I32x4TruncSatF64x2SZero:
        case SimdOp::I32x4TruncSatF64x2UZero:
        case SimdOp::I16x8ExtaddPairwiseI8x16S:
        case SimdOp::I16x8ExtaddPairwiseI8x16U:
        case SimdOp::I32x4ExtaddPairwiseI16x8S:
        case SimdOp::I32x4ExtaddPairwiseI16x8U:
        case SimdOp::I32x4RelaxedTruncF32x4S:
        case SimdOp::I32x4RelaxedTruncF32x4U:
        case SimdOp::I32x4RelaxedTruncF64x2SZero:
        case SimdOp::I32x4RelaxedTruncF64x2UZero:
          WASM_SIMD_OP(OpKind::Unary);
        case SimdOp::I8x16Shl:
        case SimdOp::I8x16ShrS:
        case SimdOp::I8x16ShrU:
        case SimdOp::I16x8Shl:
        case SimdOp::I16x8ShrS:
        case SimdOp::I16x8ShrU:
        case SimdOp::I32x4Shl:
        case SimdOp::I32x4ShrS:
        case SimdOp::I32x4ShrU:
        case SimdOp::I64x2Shl:
        case SimdOp::I64x2ShrS:
        case SimdOp::I64x2ShrU:
          WASM_SIMD_OP(OpKind::VectorShift);
        case SimdOp::V128Bitselect:
          WASM_SIMD_OP(OpKind::Ternary);
        case SimdOp::I8x16Shuffle:
          WASM_SIMD_OP(OpKind::VectorShuffle);
        case SimdOp::V128Const:
          WASM_SIMD_OP(OpKind::V128Const);
        case SimdOp::V128Load:
        case SimdOp::V128Load8Splat:
        case SimdOp::V128Load16Splat:
        case SimdOp::V128Load32Splat:
        case SimdOp::V128Load64Splat:
        case SimdOp::V128Load8x8S:
        case SimdOp::V128Load8x8U:
        case SimdOp::V128Load16x4S:
        case SimdOp::V128Load16x4U:
        case SimdOp::V128Load32x2S:
        case SimdOp::V128Load32x2U:
        case SimdOp::V128Load32Zero:
        case SimdOp::V128Load64Zero:
          WASM_SIMD_OP(OpKind::Load);
        case SimdOp::V128Store:
          WASM_SIMD_OP(OpKind::Store);
        case SimdOp::V128Load8Lane:
        case SimdOp::V128Load16Lane:
        case SimdOp::V128Load32Lane:
        case SimdOp::V128Load64Lane:
          WASM_SIMD_OP(OpKind::LoadLane);
        case SimdOp::V128Store8Lane:
        case SimdOp::V128Store16Lane:
        case SimdOp::V128Store32Lane:
        case SimdOp::V128Store64Lane:
          WASM_SIMD_OP(OpKind::StoreLane);
        case SimdOp::F32x4RelaxedMadd:
        case SimdOp::F32x4RelaxedNmadd:
        case SimdOp::F64x2RelaxedMadd:
        case SimdOp::F64x2RelaxedNmadd:
        case SimdOp::I8x16RelaxedLaneSelect:
        case SimdOp::I16x8RelaxedLaneSelect:
        case SimdOp::I32x4RelaxedLaneSelect:
        case SimdOp::I64x2RelaxedLaneSelect:
        case SimdOp::I32x4RelaxedDotI8x16I7x16AddS:
          WASM_SIMD_OP(OpKind::Ternary);
      }
      break;
    }
    case Op::MiscPrefix: {
      switch (MiscOp(op.b1)) {
        case MiscOp::Limit:
          // Reject Limit for MiscPrefix encoding
          break;
        case MiscOp::I32TruncSatF32S:
        case MiscOp::I32TruncSatF32U:
        case MiscOp::I32TruncSatF64S:
        case MiscOp::I32TruncSatF64U:
        case MiscOp::I64TruncSatF32S:
        case MiscOp::I64TruncSatF32U:
        case MiscOp::I64TruncSatF64S:
        case MiscOp::I64TruncSatF64U:
          return OpKind::Conversion;
        case MiscOp::MemoryCopy:
        case MiscOp::TableCopy:
          return OpKind::MemOrTableCopy;
        case MiscOp::DataDrop:
        case MiscOp::ElemDrop:
          return OpKind::DataOrElemDrop;
        case MiscOp::MemoryFill:
          return OpKind::MemFill;
        case MiscOp::MemoryInit:
        case MiscOp::TableInit:
          return OpKind::MemOrTableInit;
        case MiscOp::TableFill:
          return OpKind::TableFill;
        case MiscOp::MemoryDiscard:
          return OpKind::MemDiscard;
        case MiscOp::TableGrow:
          return OpKind::TableGrow;
        case MiscOp::TableSize:
          return OpKind::TableSize;
      }
      break;
    }
    case Op::ThreadPrefix: {
      switch (ThreadOp(op.b1)) {
        case ThreadOp::Limit:
          // Reject Limit for ThreadPrefix encoding
          break;
        case ThreadOp::Notify:
          return OpKind::Notify;
        case ThreadOp::I32Wait:
        case ThreadOp::I64Wait:
          return OpKind::Wait;
        case ThreadOp::Fence:
          return OpKind::Fence;
        case ThreadOp::I32AtomicLoad:
        case ThreadOp::I64AtomicLoad:
        case ThreadOp::I32AtomicLoad8U:
        case ThreadOp::I32AtomicLoad16U:
        case ThreadOp::I64AtomicLoad8U:
        case ThreadOp::I64AtomicLoad16U:
        case ThreadOp::I64AtomicLoad32U:
          return OpKind::AtomicLoad;
        case ThreadOp::I32AtomicStore:
        case ThreadOp::I64AtomicStore:
        case ThreadOp::I32AtomicStore8U:
        case ThreadOp::I32AtomicStore16U:
        case ThreadOp::I64AtomicStore8U:
        case ThreadOp::I64AtomicStore16U:
        case ThreadOp::I64AtomicStore32U:
          return OpKind::AtomicStore;
        case ThreadOp::I32AtomicAdd:
        case ThreadOp::I64AtomicAdd:
        case ThreadOp::I32AtomicAdd8U:
        case ThreadOp::I32AtomicAdd16U:
        case ThreadOp::I64AtomicAdd8U:
        case ThreadOp::I64AtomicAdd16U:
        case ThreadOp::I64AtomicAdd32U:
        case ThreadOp::I32AtomicSub:
        case ThreadOp::I64AtomicSub:
        case ThreadOp::I32AtomicSub8U:
        case ThreadOp::I32AtomicSub16U:
        case ThreadOp::I64AtomicSub8U:
        case ThreadOp::I64AtomicSub16U:
        case ThreadOp::I64AtomicSub32U:
        case ThreadOp::I32AtomicAnd:
        case ThreadOp::I64AtomicAnd:
        case ThreadOp::I32AtomicAnd8U:
        case ThreadOp::I32AtomicAnd16U:
        case ThreadOp::I64AtomicAnd8U:
        case ThreadOp::I64AtomicAnd16U:
        case ThreadOp::I64AtomicAnd32U:
        case ThreadOp::I32AtomicOr:
        case ThreadOp::I64AtomicOr:
        case ThreadOp::I32AtomicOr8U:
        case ThreadOp::I32AtomicOr16U:
        case ThreadOp::I64AtomicOr8U:
        case ThreadOp::I64AtomicOr16U:
        case ThreadOp::I64AtomicOr32U:
        case ThreadOp::I32AtomicXor:
        case ThreadOp::I64AtomicXor:
        case ThreadOp::I32AtomicXor8U:
        case ThreadOp::I32AtomicXor16U:
        case ThreadOp::I64AtomicXor8U:
        case ThreadOp::I64AtomicXor16U:
        case ThreadOp::I64AtomicXor32U:
        case ThreadOp::I32AtomicXchg:
        case ThreadOp::I64AtomicXchg:
        case ThreadOp::I32AtomicXchg8U:
        case ThreadOp::I32AtomicXchg16U:
        case ThreadOp::I64AtomicXchg8U:
        case ThreadOp::I64AtomicXchg16U:
        case ThreadOp::I64AtomicXchg32U:
          return OpKind::AtomicRMW;
        case ThreadOp::I32AtomicCmpXchg:
        case ThreadOp::I64AtomicCmpXchg:
        case ThreadOp::I32AtomicCmpXchg8U:
        case ThreadOp::I32AtomicCmpXchg16U:
        case ThreadOp::I64AtomicCmpXchg8U:
        case ThreadOp::I64AtomicCmpXchg16U:
        case ThreadOp::I64AtomicCmpXchg32U:
          return OpKind::AtomicCmpXchg;
        default:
          break;
      }
      break;
    }
    case Op::MozPrefix: {
      switch (MozOp(op.b1)) {
        case MozOp::Limit:
          // Reject Limit for the MozPrefix encoding
          break;
        case MozOp::TeeGlobal:
          return OpKind::TeeGlobal;
        case MozOp::I32BitNot:
        case MozOp::I32Abs:
        case MozOp::I32Neg:
          return OpKind::Unary;
        case MozOp::I32Min:
        case MozOp::I32Max:
        case MozOp::F64Mod:
        case MozOp::F64Pow:
        case MozOp::F64Atan2:
          return OpKind::Binary;
        case MozOp::F64SinNative:
        case MozOp::F64SinFdlibm:
        case MozOp::F64CosNative:
        case MozOp::F64CosFdlibm:
        case MozOp::F64TanNative:
        case MozOp::F64TanFdlibm:
        case MozOp::F64Asin:
        case MozOp::F64Acos:
        case MozOp::F64Atan:
        case MozOp::F64Exp:
        case MozOp::F64Log:
          return OpKind::Unary;
        case MozOp::I32TeeStore8:
        case MozOp::I32TeeStore16:
        case MozOp::I64TeeStore8:
        case MozOp::I64TeeStore16:
        case MozOp::I64TeeStore32:
        case MozOp::I32TeeStore:
        case MozOp::I64TeeStore:
        case MozOp::F32TeeStore:
        case MozOp::F64TeeStore:
        case MozOp::F32TeeStoreF64:
        case MozOp::F64TeeStoreF32:
          return OpKind::TeeStore;
        case MozOp::OldCallDirect:
          return OpKind::OldCallDirect;
        case MozOp::OldCallIndirect:
          return OpKind::OldCallIndirect;
        case MozOp::CallBuiltinModuleFunc:
          return OpKind::CallBuiltinModuleFunc;
        case MozOp::StackSwitch:
          return OpKind::StackSwitch;
      }
      break;
    }
    case Op::FirstPrefix:
      break;
  }
  MOZ_CRASH("unimplemented opcode");
}
#endif  // DEBUG

const char* OpBytes::toString() const {
  switch (Op(b0)) {
    case Op::Unreachable:
      return "unreachable";
    case Op::Nop:
      return "nop";
    case Op::Block:
      return "block";
    case Op::Loop:
      return "loop";
    case Op::If:
      return "if";
    case Op::Else:
      return "else";
    case Op::Try:
      return "try";
    case Op::Catch:
      return "catch";
    case Op::Throw:
      return "throw";
    case Op::Rethrow:
      return "rethrow";
    case Op::ThrowRef:
      return "throw_ref";
    case Op::End:
      return "end";
    case Op::Br:
      return "br";
    case Op::BrIf:
      return "br_if";
    case Op::BrTable:
      return "br_table";
    case Op::Return:
      return "return";
    case Op::Call:
      return "call";
    case Op::CallIndirect:
      return "call_indirect";
    case Op::ReturnCall:
      return "return_call";
    case Op::ReturnCallIndirect:
      return "return_call_indirect";
    case Op::CallRef:
      return "call_ref";
    case Op::ReturnCallRef:
      return "return_call_ref";
    case Op::Delegate:
      return "delegate";
    case Op::CatchAll:
      return "catch_all";
    case Op::Drop:
      return "drop";
    case Op::SelectNumeric:
      return "select";
    case Op::SelectTyped:
      return "select";
    case Op::TryTable:
      return "try_table";
    case Op::LocalGet:
      return "local.get";
    case Op::LocalSet:
      return "local.set";
    case Op::LocalTee:
      return "local.tee";
    case Op::GlobalGet:
      return "global.get";
    case Op::GlobalSet:
      return "global.set";
    case Op::TableGet:
      return "table.get";
    case Op::TableSet:
      return "table.set";
    case Op::I32Load:
      return "i32.load";
    case Op::I64Load:
      return "i64.load";
    case Op::F32Load:
      return "f32.load";
    case Op::F64Load:
      return "f64.load";
    case Op::I32Load8S:
      return "i32.load8_s";
    case Op::I32Load8U:
      return "i32.load8_u";
    case Op::I32Load16S:
      return "i32.load16_s";
    case Op::I32Load16U:
      return "i32.load16_u";
    case Op::I64Load8S:
      return "i64.load8_s";
    case Op::I64Load8U:
      return "i64.load8_u";
    case Op::I64Load16S:
      return "i64.load16_s";
    case Op::I64Load16U:
      return "i64.load16_u";
    case Op::I64Load32S:
      return "i64.load32_s";
    case Op::I64Load32U:
      return "i64.load32_u";
    case Op::I32Store:
      return "i32.store";
    case Op::I64Store:
      return "i64.store";
    case Op::F32Store:
      return "f32.store";
    case Op::F64Store:
      return "f64.store";
    case Op::I32Store8:
      return "i32.store8";
    case Op::I32Store16:
      return "i32.store16";
    case Op::I64Store8:
      return "i64.store8";
    case Op::I64Store16:
      return "i64.store16";
    case Op::I64Store32:
      return "i64.store32";
    case Op::MemorySize:
      return "memory.size";
    case Op::MemoryGrow:
      return "memory.grow";
    case Op::I32Const:
      return "i32.const";
    case Op::I64Const:
      return "i64.const";
    case Op::F32Const:
      return "f32.const";
    case Op::F64Const:
      return "f64.const";
    case Op::I32Eqz:
      return "i32.eqz";
    case Op::I32Eq:
      return "i32.eq";
    case Op::I32Ne:
      return "i32.ne";
    case Op::I32LtS:
      return "i32.lt_s";
    case Op::I32LtU:
      return "i32.lt_u";
    case Op::I32GtS:
      return "i32.gt_s";
    case Op::I32GtU:
      return "i32.gt_u";
    case Op::I32LeS:
      return "i32.le_s";
    case Op::I32LeU:
      return "i32.le_u";
    case Op::I32GeS:
      return "i32.ge_s";
    case Op::I32GeU:
      return "i32.ge_u";
    case Op::I64Eqz:
      return "i64.eqz";
    case Op::I64Eq:
      return "i64.eq";
    case Op::I64Ne:
      return "i64.ne";
    case Op::I64LtS:
      return "i64.lt_s";
    case Op::I64LtU:
      return "i64.lt_u";
    case Op::I64GtS:
      return "i64.gt_s";
    case Op::I64GtU:
      return "i64.gt_u";
    case Op::I64LeS:
      return "i64.le_s";
    case Op::I64LeU:
      return "i64.le_u";
    case Op::I64GeS:
      return "i64.ge_s";
    case Op::I64GeU:
      return "i64.ge_u";
    case Op::F32Eq:
      return "f32.eq";
    case Op::F32Ne:
      return "f32.ne";
    case Op::F32Lt:
      return "f32.lt";
    case Op::F32Gt:
      return "f32.gt";
    case Op::F32Le:
      return "f32.le";
    case Op::F32Ge:
      return "f32.ge";
    case Op::F64Eq:
      return "f64.eq";
    case Op::F64Ne:
      return "f64.ne";
    case Op::F64Lt:
      return "f64.lt";
    case Op::F64Gt:
      return "f64.gt";
    case Op::F64Le:
      return "f64.le";
    case Op::F64Ge:
      return "f64.ge";
    case Op::I32Clz:
      return "i32.clz";
    case Op::I32Ctz:
      return "i32.ctz";
    case Op::I32Popcnt:
      return "i32.popcnt";
    case Op::I32Add:
      return "i32.add";
    case Op::I32Sub:
      return "i32.sub";
    case Op::I32Mul:
      return "i32.mul";
    case Op::I32DivS:
      return "i32.div_s";
    case Op::I32DivU:
      return "i32.div_u";
    case Op::I32RemS:
      return "i32.rem_s";
    case Op::I32RemU:
      return "i32.rem_u";
    case Op::I32And:
      return "i32.and";
    case Op::I32Or:
      return "i32.or";
    case Op::I32Xor:
      return "i32.xor";
    case Op::I32Shl:
      return "i32.shl";
    case Op::I32ShrS:
      return "i32.shr_s";
    case Op::I32ShrU:
      return "i32.shr_u";
    case Op::I32Rotl:
      return "i32.rotl";
    case Op::I32Rotr:
      return "i32.rotr";
    case Op::I64Clz:
      return "i64.clz";
    case Op::I64Ctz:
      return "i64.ctz";
    case Op::I64Popcnt:
      return "i64.popcnt";
    case Op::I64Add:
      return "i64.add";
    case Op::I64Sub:
      return "i64.sub";
    case Op::I64Mul:
      return "i64.mul";
    case Op::I64DivS:
      return "i64.div_s";
    case Op::I64DivU:
      return "i64.div_u";
    case Op::I64RemS:
      return "i64.rem_s";
    case Op::I64RemU:
      return "i64.rem_u";
    case Op::I64And:
      return "i64.and";
    case Op::I64Or:
      return "i64.or";
    case Op::I64Xor:
      return "i64.xor";
    case Op::I64Shl:
      return "i64.shl";
    case Op::I64ShrS:
      return "i64.shr_s";
    case Op::I64ShrU:
      return "i64.shr_u";
    case Op::I64Rotl:
      return "i64.rotl";
    case Op::I64Rotr:
      return "i64.rotr";
    case Op::F32Abs:
      return "f32.abs";
    case Op::F32Neg:
      return "f32.neg";
    case Op::F32Ceil:
      return "f32.ceil";
    case Op::F32Floor:
      return "f32.floor";
    case Op::F32Trunc:
      return "f32.trunc";
    case Op::F32Nearest:
      return "f32.nearest";
    case Op::F32Sqrt:
      return "f32.sqrt";
    case Op::F32Add:
      return "f32.add";
    case Op::F32Sub:
      return "f32.sub";
    case Op::F32Mul:
      return "f32.mul";
    case Op::F32Div:
      return "f32.div";
    case Op::F32Min:
      return "f32.min";
    case Op::F32Max:
      return "f32.max";
    case Op::F32CopySign:
      return "f32.copysign";
    case Op::F64Abs:
      return "f64.abs";
    case Op::F64Neg:
      return "f64.neg";
    case Op::F64Ceil:
      return "f64.ceil";
    case Op::F64Floor:
      return "f64.floor";
    case Op::F64Trunc:
      return "f64.trunc";
    case Op::F64Nearest:
      return "f64.nearest";
    case Op::F64Sqrt:
      return "f64.sqrt";
    case Op::F64Add:
      return "f64.add";
    case Op::F64Sub:
      return "f64.sub";
    case Op::F64Mul:
      return "f64.mul";
    case Op::F64Div:
      return "f64.div";
    case Op::F64Min:
      return "f64.min";
    case Op::F64Max:
      return "f64.max";
    case Op::F64CopySign:
      return "f64.copysign";
    case Op::I32WrapI64:
      return "i32.wrap_i64";
    case Op::I32TruncF32S:
      return "i32.trunc_f32_s";
    case Op::I32TruncF32U:
      return "i32.trunc_f32_u";
    case Op::I32TruncF64S:
      return "i32.trunc_f64_s";
    case Op::I32TruncF64U:
      return "i32.trunc_f64_u";
    case Op::I64ExtendI32S:
      return "i64.extend_i32_s";
    case Op::I64ExtendI32U:
      return "i64.extend_i32_u";
    case Op::I64TruncF32S:
      return "i64.trunc_f32_s";
    case Op::I64TruncF32U:
      return "i64.trunc_f32_u";
    case Op::I64TruncF64S:
      return "i64.trunc_f64_s";
    case Op::I64TruncF64U:
      return "i64.trunc_f64_u";
    case Op::F32ConvertI32S:
      return "f32.convert_i32_s";
    case Op::F32ConvertI32U:
      return "f32.convert_i32_u";
    case Op::F32ConvertI64S:
      return "f32.convert_i64_s";
    case Op::F32ConvertI64U:
      return "f32.convert_i64_u";
    case Op::F32DemoteF64:
      return "f32.demote_f64";
    case Op::F64ConvertI32S:
      return "f64.convert_i32_s";
    case Op::F64ConvertI32U:
      return "f64.convert_i32_u";
    case Op::F64ConvertI64S:
      return "f64.convert_i64_s";
    case Op::F64ConvertI64U:
      return "f64.convert_i64_u";
    case Op::F64PromoteF32:
      return "f64.promote_f32";
    case Op::I32ReinterpretF32:
      return "i32.reinterpret_f32";
    case Op::I64ReinterpretF64:
      return "i64.reinterpret_f64";
    case Op::F32ReinterpretI32:
      return "f32.reinterpret_i32";
    case Op::F64ReinterpretI64:
      return "f64.reinterpret_i64";
    case Op::I32Extend8S:
      return "i32.extend8_s";
    case Op::I32Extend16S:
      return "i32.extend16_s";
    case Op::I64Extend8S:
      return "i64.extend8_s";
    case Op::I64Extend16S:
      return "i64.extend16_s";
    case Op::I64Extend32S:
      return "i64.extend32_s";
    case Op::RefNull:
      return "ref.null";
    case Op::RefIsNull:
      return "ref.is_null";
    case Op::RefFunc:
      return "ref.func";
    case Op::RefAsNonNull:
      return "ref.as_non_null";
    case Op::BrOnNull:
      return "br_on_null";
    case Op::RefEq:
      return "ref.eq";
    case Op::BrOnNonNull:
      return "br_on_non_null";
    case Op::GcPrefix: {
      switch (GcOp(b1)) {
        case GcOp::StructNew:
          return "struct.new";
        case GcOp::StructNewDefault:
          return "struct.new_default";
        case GcOp::StructGet:
          return "struct.get";
        case GcOp::StructGetS:
          return "struct.get_s";
        case GcOp::StructGetU:
          return "struct.get_u";
        case GcOp::StructSet:
          return "struct.set";
        case GcOp::ArrayNew:
          return "array.new";
        case GcOp::ArrayNewDefault:
          return "array.new_default";
        case GcOp::ArrayNewFixed:
          return "array.new_fixed";
        case GcOp::ArrayNewData:
          return "array.new_data";
        case GcOp::ArrayNewElem:
          return "array.new_elem";
        case GcOp::ArrayGet:
          return "array.get";
        case GcOp::ArrayGetS:
          return "array.get_s";
        case GcOp::ArrayGetU:
          return "array.get_u";
        case GcOp::ArraySet:
          return "array.set";
        case GcOp::ArrayLen:
          return "array.len";
        case GcOp::ArrayFill:
          return "array.fill";
        case GcOp::ArrayCopy:
          return "array.copy";
        case GcOp::ArrayInitData:
          return "array.init_data";
        case GcOp::ArrayInitElem:
          return "array.init_elem";
        case GcOp::RefTest:
          return "ref.test";
        case GcOp::RefTestNull:
          return "ref.test";
        case GcOp::RefCast:
          return "ref.cast";
        case GcOp::RefCastNull:
          return "ref.cast";
        case GcOp::BrOnCast:
          return "br_on_cast";
        case GcOp::BrOnCastFail:
          return "br_on_cast_fail";
        case GcOp::AnyConvertExtern:
          return "any.convert_extern";
        case GcOp::ExternConvertAny:
          return "extern.convert_any";
        case GcOp::RefI31:
          return "ref.i31";
        case GcOp::I31GetS:
          return "i31.get_s";
        case GcOp::I31GetU:
          return "i31.get_u";
        default:
          return "unknown";
      }
    }
    case Op::MiscPrefix: {
      switch (MiscOp(b1)) {
        case MiscOp::I32TruncSatF32S:
          return "i32.trunc_sat_f32_s";
        case MiscOp::I32TruncSatF32U:
          return "i32.trunc_sat_f32_u";
        case MiscOp::I32TruncSatF64S:
          return "i32.trunc_sat_f64_s";
        case MiscOp::I32TruncSatF64U:
          return "i32.trunc_sat_f64_u";
        case MiscOp::I64TruncSatF32S:
          return "i64.trunc_sat_f32_s";
        case MiscOp::I64TruncSatF32U:
          return "i64.trunc_sat_f32_u";
        case MiscOp::I64TruncSatF64S:
          return "i64.trunc_sat_f64_s";
        case MiscOp::I64TruncSatF64U:
          return "i64.trunc_sat_f64_u";
        case MiscOp::MemoryInit:
          return "memory.init";
        case MiscOp::DataDrop:
          return "data.drop";
        case MiscOp::MemoryCopy:
          return "memory.copy";
        case MiscOp::MemoryFill:
          return "memory.fill";
        case MiscOp::TableInit:
          return "table.init";
        case MiscOp::ElemDrop:
          return "elem.drop";
        case MiscOp::TableCopy:
          return "table.copy";
        case MiscOp::TableGrow:
          return "table.grow";
        case MiscOp::TableSize:
          return "table.size";
        case MiscOp::TableFill:
          return "table.fill";
        case MiscOp::MemoryDiscard:
          return "memory.discard";
        default:
          return "unknown";
      }
    }
    case Op::SimdPrefix: {
      switch (SimdOp(b1)) {
        case SimdOp::V128Load:
          return "v128.load";
        case SimdOp::V128Load8x8S:
          return "v128.load8x8_s";
        case SimdOp::V128Load8x8U:
          return "v128.load8x8_u";
        case SimdOp::V128Load16x4S:
          return "v128.load16x4_s";
        case SimdOp::V128Load16x4U:
          return "v128.load16x4_u";
        case SimdOp::V128Load32x2S:
          return "v128.load32x2_s";
        case SimdOp::V128Load32x2U:
          return "v128.load32x2_u";
        case SimdOp::V128Load8Splat:
          return "v128.load8_splat";
        case SimdOp::V128Load16Splat:
          return "v128.load16_splat";
        case SimdOp::V128Load32Splat:
          return "v128.load32_splat";
        case SimdOp::V128Load64Splat:
          return "v128.load64_splat";
        case SimdOp::V128Store:
          return "v128.store";
        case SimdOp::V128Const:
          return "v128.const";
        case SimdOp::I8x16Shuffle:
          return "i8x16.shuffle";
        case SimdOp::I8x16Swizzle:
          return "i8x16.swizzle";
        case SimdOp::I8x16Splat:
          return "i8x16.splat";
        case SimdOp::I16x8Splat:
          return "i16x8.splat";
        case SimdOp::I32x4Splat:
          return "i32x4.splat";
        case SimdOp::I64x2Splat:
          return "i64x2.splat";
        case SimdOp::F32x4Splat:
          return "f32x4.splat";
        case SimdOp::F64x2Splat:
          return "f64x2.splat";
        case SimdOp::I8x16ExtractLaneS:
          return "i8x16.extract_lane_s";
        case SimdOp::I8x16ExtractLaneU:
          return "i8x16.extract_lane_u";
        case SimdOp::I8x16ReplaceLane:
          return "i8x16.replace_lane";
        case SimdOp::I16x8ExtractLaneS:
          return "i16x8.extract_lane_s";
        case SimdOp::I16x8ExtractLaneU:
          return "i16x8.extract_lane_u";
        case SimdOp::I16x8ReplaceLane:
          return "i16x8.replace_lane";
        case SimdOp::I32x4ExtractLane:
          return "i32x4.extract_lane";
        case SimdOp::I32x4ReplaceLane:
          return "i32x4.replace_lane";
        case SimdOp::I64x2ExtractLane:
          return "i64x2.extract_lane";
        case SimdOp::I64x2ReplaceLane:
          return "i64x2.replace_lane";
        case SimdOp::F32x4ExtractLane:
          return "f32x4.extract_lane";
        case SimdOp::F32x4ReplaceLane:
          return "f32x4.replace_lane";
        case SimdOp::F64x2ExtractLane:
          return "f64x2.extract_lane";
        case SimdOp::F64x2ReplaceLane:
          return "f64x2.replace_lane";
        case SimdOp::I8x16Eq:
          return "i8x16.eq";
        case SimdOp::I8x16Ne:
          return "i8x16.ne";
        case SimdOp::I8x16LtS:
          return "i8x16.lt_s";
        case SimdOp::I8x16LtU:
          return "i8x16.lt_u";
        case SimdOp::I8x16GtS:
          return "i8x16.gt_s";
        case SimdOp::I8x16GtU:
          return "i8x16.gt_u";
        case SimdOp::I8x16LeS:
          return "i8x16.le_s";
        case SimdOp::I8x16LeU:
          return "i8x16.le_u";
        case SimdOp::I8x16GeS:
          return "i8x16.ge_s";
        case SimdOp::I8x16GeU:
          return "i8x16.ge_u";
        case SimdOp::I16x8Eq:
          return "i16x8.eq";
        case SimdOp::I16x8Ne:
          return "i16x8.ne";
        case SimdOp::I16x8LtS:
          return "i16x8.lt_s";
        case SimdOp::I16x8LtU:
          return "i16x8.lt_u";
        case SimdOp::I16x8GtS:
          return "i16x8.gt_s";
        case SimdOp::I16x8GtU:
          return "i16x8.gt_u";
        case SimdOp::I16x8LeS:
          return "i16x8.le_s";
        case SimdOp::I16x8LeU:
          return "i16x8.le_u";
        case SimdOp::I16x8GeS:
          return "i16x8.ge_s";
        case SimdOp::I16x8GeU:
          return "i16x8.ge_u";
        case SimdOp::I32x4Eq:
          return "i32x4.eq";
        case SimdOp::I32x4Ne:
          return "i32x4.ne";
        case SimdOp::I32x4LtS:
          return "i32x4.lt_s";
        case SimdOp::I32x4LtU:
          return "i32x4.lt_u";
        case SimdOp::I32x4GtS:
          return "i32x4.gt_s";
        case SimdOp::I32x4GtU:
          return "i32x4.gt_u";
        case SimdOp::I32x4LeS:
          return "i32x4.le_s";
        case SimdOp::I32x4LeU:
          return "i32x4.le_u";
        case SimdOp::I32x4GeS:
          return "i32x4.ge_s";
        case SimdOp::I32x4GeU:
          return "i32x4.ge_u";
        case SimdOp::F32x4Eq:
          return "f32x4.eq";
        case SimdOp::F32x4Ne:
          return "f32x4.ne";
        case SimdOp::F32x4Lt:
          return "f32x4.lt";
        case SimdOp::F32x4Gt:
          return "f32x4.gt";
        case SimdOp::F32x4Le:
          return "f32x4.le";
        case SimdOp::F32x4Ge:
          return "f32x4.ge";
        case SimdOp::F64x2Eq:
          return "f64x2.eq";
        case SimdOp::F64x2Ne:
          return "f64x2.ne";
        case SimdOp::F64x2Lt:
          return "f64x2.lt";
        case SimdOp::F64x2Gt:
          return "f64x2.gt";
        case SimdOp::F64x2Le:
          return "f64x2.le";
        case SimdOp::F64x2Ge:
          return "f64x2.ge";
        case SimdOp::V128Not:
          return "v128.not";
        case SimdOp::V128And:
          return "v128.and";
        case SimdOp::V128AndNot:
          return "v128.andnot";
        case SimdOp::V128Or:
          return "v128.or";
        case SimdOp::V128Xor:
          return "v128.xor";
        case SimdOp::V128Bitselect:
          return "v128.bit_select";
        case SimdOp::V128AnyTrue:
          return "v128.any_true";
        case SimdOp::V128Load8Lane:
          return "v128.load8_lane";
        case SimdOp::V128Load16Lane:
          return "v128.load16_lane";
        case SimdOp::V128Load32Lane:
          return "v128.load32_lane";
        case SimdOp::V128Load64Lane:
          return "v128.load64_lane";
        case SimdOp::V128Store8Lane:
          return "v128.store8_lane";
        case SimdOp::V128Store16Lane:
          return "v128.store16_lane";
        case SimdOp::V128Store32Lane:
          return "v128.store32_lane";
        case SimdOp::V128Store64Lane:
          return "v128.store64_lane";
        case SimdOp::V128Load32Zero:
          return "v128.load32_zero";
        case SimdOp::V128Load64Zero:
          return "v128.load64_zero";
        case SimdOp::F32x4DemoteF64x2Zero:
          return "f32x4.demote_f64x2_zero";
        case SimdOp::F64x2PromoteLowF32x4:
          return "f64x2.promote_low_f32x4";
        case SimdOp::I8x16Abs:
          return "i8x16.abs";
        case SimdOp::I8x16Neg:
          return "i8x16.neg";
        case SimdOp::I8x16Popcnt:
          return "i8x16.popcnt";
        case SimdOp::I8x16AllTrue:
          return "i8x16.all_true";
        case SimdOp::I8x16Bitmask:
          return "i8x16.bitmask";
        case SimdOp::I8x16NarrowI16x8S:
          return "i8x16.narrow_i16x8_s";
        case SimdOp::I8x16NarrowI16x8U:
          return "i8x16.narrow_i16x8_u";
        case SimdOp::F32x4Ceil:
          return "f32x4.ceil";
        case SimdOp::F32x4Floor:
          return "f32x4.floor";
        case SimdOp::F32x4Trunc:
          return "f32x4.trunc";
        case SimdOp::F32x4Nearest:
          return "f32x4.nearest";
        case SimdOp::I8x16Shl:
          return "i8x16.shl";
        case SimdOp::I8x16ShrS:
          return "i8x16.shr_s";
        case SimdOp::I8x16ShrU:
          return "i8x16.shr_u";
        case SimdOp::I8x16Add:
          return "i8x16.add";
        case SimdOp::I8x16AddSatS:
          return "i8x16.add_sat_s";
        case SimdOp::I8x16AddSatU:
          return "i8x16.add_sat_u";
        case SimdOp::I8x16Sub:
          return "i8x16.sub";
        case SimdOp::I8x16SubSatS:
          return "i8x16.sub_sat_s";
        case SimdOp::I8x16SubSatU:
          return "i8x16.sub_sat_u";
        case SimdOp::F64x2Ceil:
          return "f64x2.ceil";
        case SimdOp::F64x2Floor:
          return "f64x2.floor";
        case SimdOp::I8x16MinS:
          return "i8x16.min_s";
        case SimdOp::I8x16MinU:
          return "i8x16.min_u";
        case SimdOp::I8x16MaxS:
          return "i8x16.max_s";
        case SimdOp::I8x16MaxU:
          return "i8x16.max_u";
        case SimdOp::F64x2Trunc:
          return "f64x2.trunc";
        case SimdOp::I8x16AvgrU:
          return "i8x16.avgr_u";
        case SimdOp::I16x8ExtaddPairwiseI8x16S:
          return "i16x8.extadd_pairwise_i8x16_s";
        case SimdOp::I16x8ExtaddPairwiseI8x16U:
          return "i16x8.extadd_pairwise_i8x16_u";
        case SimdOp::I32x4ExtaddPairwiseI16x8S:
          return "i32x4.extadd_pairwise_i16x8_s";
        case SimdOp::I32x4ExtaddPairwiseI16x8U:
          return "i32x4.extadd_pairwise_i16x8_u";
        case SimdOp::I16x8Abs:
          return "i16x8.abs";
        case SimdOp::I16x8Neg:
          return "i16x8.neg";
        case SimdOp::I16x8Q15MulrSatS:
          return "i16x8.q15mulr_sat_s";
        case SimdOp::I16x8AllTrue:
          return "i16x8.all_true";
        case SimdOp::I16x8Bitmask:
          return "i16x8.bitmask";
        case SimdOp::I16x8NarrowI32x4S:
          return "i16x8.narrow_i32x4_s";
        case SimdOp::I16x8NarrowI32x4U:
          return "i16x8.narrow_i32x4_u";
        case SimdOp::I16x8ExtendLowI8x16S:
          return "i16x8.extend_low_i8x16_s";
        case SimdOp::I16x8ExtendHighI8x16S:
          return "i16x8.extend_high_i8x16_s";
        case SimdOp::I16x8ExtendLowI8x16U:
          return "i16x8.extend_low_i8x16_u";
        case SimdOp::I16x8ExtendHighI8x16U:
          return "i16x8.extend_high_i8x16_u";
        case SimdOp::I16x8Shl:
          return "i16x8.shl";
        case SimdOp::I16x8ShrS:
          return "i16x8.shr_s";
        case SimdOp::I16x8ShrU:
          return "i16x8.shr_u";
        case SimdOp::I16x8Add:
          return "i16x8.add";
        case SimdOp::I16x8AddSatS:
          return "i16x8.add_sat_s";
        case SimdOp::I16x8AddSatU:
          return "i16x8.add_sat_u";
        case SimdOp::I16x8Sub:
          return "i16x8.sub";
        case SimdOp::I16x8SubSatS:
          return "i16x8.sub_sat_s";
        case SimdOp::I16x8SubSatU:
          return "i16x8.sub_sat_u";
        case SimdOp::F64x2Nearest:
          return "f64x2.nearest";
        case SimdOp::I16x8Mul:
          return "i16x8.mul";
        case SimdOp::I16x8MinS:
          return "i16x8.min_s";
        case SimdOp::I16x8MinU:
          return "i16x8.min_u";
        case SimdOp::I16x8MaxS:
          return "i16x8.max_s";
        case SimdOp::I16x8MaxU:
          return "i16x8.max_u";
        case SimdOp::I16x8AvgrU:
          return "i16x8.avgr_u";
        case SimdOp::I16x8ExtmulLowI8x16S:
          return "i16x8.extmul_low_i8x16_s";
        case SimdOp::I16x8ExtmulHighI8x16S:
          return "i16x8.extmul_high_i8x16_s";
        case SimdOp::I16x8ExtmulLowI8x16U:
          return "i16x8.extmul_low_i8x16_u";
        case SimdOp::I16x8ExtmulHighI8x16U:
          return "i16x8.extmul_high_i8x16_u";
        case SimdOp::I32x4Abs:
          return "i32x4.abs";
        case SimdOp::I32x4Neg:
          return "i32x4.neg";
        case SimdOp::I32x4AllTrue:
          return "i32x4.all_true";
        case SimdOp::I32x4Bitmask:
          return "i32x4.bitmask";
        case SimdOp::I32x4ExtendLowI16x8S:
          return "i32x4.extend_low_i16x8_s";
        case SimdOp::I32x4ExtendHighI16x8S:
          return "i32x4.extend_high_i16x8_s";
        case SimdOp::I32x4ExtendLowI16x8U:
          return "i32x4.extend_low_i16x8_u";
        case SimdOp::I32x4ExtendHighI16x8U:
          return "i32x4.extend_high_i16x8_u";
        case SimdOp::I32x4Shl:
          return "i32x4.shl";
        case SimdOp::I32x4ShrS:
          return "i32x4.shr_s";
        case SimdOp::I32x4ShrU:
          return "i32x4.shr_u";
        case SimdOp::I32x4Add:
          return "i32x4.add";
        case SimdOp::I32x4Sub:
          return "i32x4.sub";
        case SimdOp::I32x4Mul:
          return "i32x4.mul";
        case SimdOp::I32x4MinS:
          return "i32x4.min_s";
        case SimdOp::I32x4MinU:
          return "i32x4.min_u";
        case SimdOp::I32x4MaxS:
          return "i32x4.max_s";
        case SimdOp::I32x4MaxU:
          return "i32x4.max_u";
        case SimdOp::I32x4DotI16x8S:
          return "i32x4.dot_i16x8_s";
        case SimdOp::I32x4ExtmulLowI16x8S:
          return "i32x4.extmul_low_i16x8_s";
        case SimdOp::I32x4ExtmulHighI16x8S:
          return "i32x4.extmul_high_i16x8_s";
        case SimdOp::I32x4ExtmulLowI16x8U:
          return "i32x4.extmul_low_i16x8_u";
        case SimdOp::I32x4ExtmulHighI16x8U:
          return "i32x4.extmul_high_i16x8_u";
        case SimdOp::I64x2Abs:
          return "i64x2.abs";
        case SimdOp::I64x2Neg:
          return "i64x2.neg";
        case SimdOp::I64x2AllTrue:
          return "i64x2.all_true";
        case SimdOp::I64x2Bitmask:
          return "i64x2.bitmask";
        case SimdOp::I64x2ExtendLowI32x4S:
          return "i64x2.extend_low_i32x4_s";
        case SimdOp::I64x2ExtendHighI32x4S:
          return "i64x2.extend_high_i32x4_s";
        case SimdOp::I64x2ExtendLowI32x4U:
          return "i64x2.extend_low_i32x4_u";
        case SimdOp::I64x2ExtendHighI32x4U:
          return "i64x2.extend_high_i32x4_u";
        case SimdOp::I64x2Shl:
          return "i64x2.shl";
        case SimdOp::I64x2ShrS:
          return "i64x2.shr_s";
        case SimdOp::I64x2ShrU:
          return "i64x2.shr_u";
        case SimdOp::I64x2Add:
          return "i64x2.add";
        case SimdOp::I64x2Sub:
          return "i64x2.sub";
        case SimdOp::I64x2Mul:
          return "i64x2.mul";
        case SimdOp::I64x2Eq:
          return "i64x2.eq";
        case SimdOp::I64x2Ne:
          return "i64x2.ne";
        case SimdOp::I64x2LtS:
          return "i64x2.lt_s";
        case SimdOp::I64x2GtS:
          return "i64x2.gt_s";
        case SimdOp::I64x2LeS:
          return "i64x2.le_s";
        case SimdOp::I64x2GeS:
          return "i64x2.ge_s";
        case SimdOp::I64x2ExtmulLowI32x4S:
          return "i64x2.extmul_low_i32x4_s";
        case SimdOp::I64x2ExtmulHighI32x4S:
          return "i64x2.extmul_high_i32x4_s";
        case SimdOp::I64x2ExtmulLowI32x4U:
          return "i64x2.extmul_low_i32x4_u";
        case SimdOp::I64x2ExtmulHighI32x4U:
          return "i64x2.extmul_high_i32x4_u";
        case SimdOp::F32x4Abs:
          return "f32x4.abs";
        case SimdOp::F32x4Neg:
          return "f32x4.neg";
        case SimdOp::F32x4Sqrt:
          return "f32x4.sqrt";
        case SimdOp::F32x4Add:
          return "f32x4.add";
        case SimdOp::F32x4Sub:
          return "f32x4.sub";
        case SimdOp::F32x4Mul:
          return "f32x4.mul";
        case SimdOp::F32x4Div:
          return "f32x4.div";
        case SimdOp::F32x4Min:
          return "f32x4.min";
        case SimdOp::F32x4Max:
          return "f32x4.max";
        case SimdOp::F32x4PMin:
          return "f32x4.pmin";
        case SimdOp::F32x4PMax:
          return "f32x4.pmax";
        case SimdOp::F64x2Abs:
          return "f64x2.abs";
        case SimdOp::F64x2Neg:
          return "f64x2.neg";
        case SimdOp::F64x2Sqrt:
          return "f64x2.sqrt";
        case SimdOp::F64x2Add:
          return "f64x2.add";
        case SimdOp::F64x2Sub:
          return "f64x2.sub";
        case SimdOp::F64x2Mul:
          return "f64x2.mul";
        case SimdOp::F64x2Div:
          return "f64x2.div";
        case SimdOp::F64x2Min:
          return "f64x2.min";
        case SimdOp::F64x2Max:
          return "f64x2.max";
        case SimdOp::F64x2PMin:
          return "f64x2.pmin";
        case SimdOp::F64x2PMax:
          return "f64x2.pmax";
        case SimdOp::I32x4TruncSatF32x4S:
          return "i32x4.trunc_sat_f32x4_s";
        case SimdOp::I32x4TruncSatF32x4U:
          return "i32x4.trunc_sat_f32x4_u";
        case SimdOp::F32x4ConvertI32x4S:
          return "f32x4.convert_i32x4_s";
        case SimdOp::F32x4ConvertI32x4U:
          return "f32x4.convert_i32x4_u";
        case SimdOp::I32x4TruncSatF64x2SZero:
          return "i32x4.trunc_sat_f64x2_s_zero";
        case SimdOp::I32x4TruncSatF64x2UZero:
          return "i32x4.trunc_sat_f64x2_u_zero";
        case SimdOp::F64x2ConvertLowI32x4S:
          return "f64x2.convert_low_i32x4_s";
        case SimdOp::F64x2ConvertLowI32x4U:
          return "f64x2.convert_low_i32x4_u";
        case SimdOp::I8x16RelaxedSwizzle:
          return "i8x16.relaxed_swizzle";
        case SimdOp::I32x4RelaxedTruncF32x4S:
          return "i32x4.relaxed_trunc_f32x4_s";
        case SimdOp::I32x4RelaxedTruncF32x4U:
          return "i32x4.relaxed_trunc_f32x4_u";
        case SimdOp::I32x4RelaxedTruncF64x2SZero:
          return "i32x4.relaxed_trunc_f64x2_s_zero";
        case SimdOp::I32x4RelaxedTruncF64x2UZero:
          return "i32x4.relaxed_trunc_f64x2_u_zero";
        case SimdOp::F32x4RelaxedMadd:
          return "f32x4.relaxed_madd";
        case SimdOp::F32x4RelaxedNmadd:
          return "f32x4.relaxed_nmadd";
        case SimdOp::F64x2RelaxedMadd:
          return "f64x2.relaxed_madd";
        case SimdOp::F64x2RelaxedNmadd:
          return "f64x2.relaxed_nmadd";
        case SimdOp::I8x16RelaxedLaneSelect:
          return "i8x16.relaxed_laneselect";
        case SimdOp::I16x8RelaxedLaneSelect:
          return "i16x8.relaxed_laneselect";
        case SimdOp::I32x4RelaxedLaneSelect:
          return "i32x4.relaxed_laneselect";
        case SimdOp::I64x2RelaxedLaneSelect:
          return "i64x2.relaxed_laneselect";
        case SimdOp::F32x4RelaxedMin:
          return "f32x4.relaxed_min";
        case SimdOp::F32x4RelaxedMax:
          return "f32x4.relaxed_max";
        case SimdOp::F64x2RelaxedMin:
          return "f64x2.relaxed_min";
        case SimdOp::F64x2RelaxedMax:
          return "f64x2.relaxed_max";
        case SimdOp::I16x8RelaxedQ15MulrS:
          return "i16x8.relaxed_q15mulr_s";
        case SimdOp::I16x8RelaxedDotI8x16I7x16S:
          return "i16x8.relaxed_dot_i8x16_i7x16_s";
        case SimdOp::I32x4RelaxedDotI8x16I7x16AddS:
          return "i32x4.relaxed_dot_i8x16_i7x16_add_s";
        default:
          return "unknown";
      }
    }
    case Op::ThreadPrefix: {
      switch (ThreadOp(b1)) {
        case ThreadOp::Notify:
          return "memory.atomic.notify";
        case ThreadOp::I32Wait:
          return "memory.atomic.wait32";
        case ThreadOp::I64Wait:
          return "memory.atomic.wait64";
        case ThreadOp::Fence:
          return "atomic.fence";
        case ThreadOp::I32AtomicLoad:
          return "i32.atomic.load";
        case ThreadOp::I64AtomicLoad:
          return "i64.atomic.load";
        case ThreadOp::I32AtomicLoad8U:
          return "i32.atomic.load8u";
        case ThreadOp::I32AtomicLoad16U:
          return "i32.atomic.load16_u";
        case ThreadOp::I64AtomicLoad8U:
          return "i64.atomic.load8u";
        case ThreadOp::I64AtomicLoad16U:
          return "i64.atomic.load16_u";
        case ThreadOp::I64AtomicLoad32U:
          return "i64.atomic.load32_u";
        case ThreadOp::I32AtomicStore:
          return "i32.atomic.store";
        case ThreadOp::I64AtomicStore:
          return "i64.atomic.store";
        case ThreadOp::I32AtomicStore8U:
          return "i32.atomic.store8_u";
        case ThreadOp::I32AtomicStore16U:
          return "i32.atomic.store16_u";
        case ThreadOp::I64AtomicStore8U:
          return "i64.atomic.store8_u";
        case ThreadOp::I64AtomicStore16U:
          return "i64.atomic.store16_u";
        case ThreadOp::I64AtomicStore32U:
          return "i64.atomic.store32_u";
        case ThreadOp::I32AtomicAdd:
          return "i32.atomic.rmw.add";
        case ThreadOp::I64AtomicAdd:
          return "i64.atomic.rmw.add";
        case ThreadOp::I32AtomicAdd8U:
          return "i32.atomic.rmw8.add_u";
        case ThreadOp::I32AtomicAdd16U:
          return "i32.atomic.rmw16.add_u";
        case ThreadOp::I64AtomicAdd8U:
          return "i64.atomic.rmw8.add_u";
        case ThreadOp::I64AtomicAdd16U:
          return "i64.atomic.rmw16.add_u";
        case ThreadOp::I64AtomicAdd32U:
          return "i64.atomic.rmw32.add_u";
        case ThreadOp::I32AtomicSub:
          return "i32.atomic.rmw.sub";
        case ThreadOp::I64AtomicSub:
          return "i64.atomic.rmw.sub";
        case ThreadOp::I32AtomicSub8U:
          return "i32.atomic.rmw8.sub_u";
        case ThreadOp::I32AtomicSub16U:
          return "i32.atomic.rmw16.sub_u";
        case ThreadOp::I64AtomicSub8U:
          return "i64.atomic.rmw8.sub_u";
        case ThreadOp::I64AtomicSub16U:
          return "i64.atomic.rmw16.sub_u";
        case ThreadOp::I64AtomicSub32U:
          return "i64.atomic.rmw32.sub_u";
        case ThreadOp::I32AtomicAnd:
          return "i32.atomic.rmw.and";
        case ThreadOp::I64AtomicAnd:
          return "i64.atomic.rmw.and";
        case ThreadOp::I32AtomicAnd8U:
          return "i32.atomic.rmw.and8_u";
        case ThreadOp::I32AtomicAnd16U:
          return "i32.atomic.rmw16.and_u";
        case ThreadOp::I64AtomicAnd8U:
          return "i64.atomic.rmw8.and_u";
        case ThreadOp::I64AtomicAnd16U:
          return "i64.atomic.rmw16.and_u";
        case ThreadOp::I64AtomicAnd32U:
          return "i64.atomic.rmw32.and_u";
        case ThreadOp::I32AtomicOr:
          return "i32.atomic.rmw.or";
        case ThreadOp::I64AtomicOr:
          return "i64.atomic.rmw.or";
        case ThreadOp::I32AtomicOr8U:
          return "i32.atomic.rmw8.or_u";
        case ThreadOp::I32AtomicOr16U:
          return "i32.atomic.rmw16.or_u";
        case ThreadOp::I64AtomicOr8U:
          return "i64.atomic.rmw8.or_u";
        case ThreadOp::I64AtomicOr16U:
          return "i64.atomic.rmw16.or_u";
        case ThreadOp::I64AtomicOr32U:
          return "i64.atomic.rmw32.or_u";
        case ThreadOp::I32AtomicXor:
          return "i32.atomic.rmw.xor";
        case ThreadOp::I64AtomicXor:
          return "i64.atomic.rmw.xor";
        case ThreadOp::I32AtomicXor8U:
          return "i32.atomic.rmw8.xor_u";
        case ThreadOp::I32AtomicXor16U:
          return "i32.atomic.rmw16.xor_u";
        case ThreadOp::I64AtomicXor8U:
          return "i64.atomic.rmw8.xor_u";
        case ThreadOp::I64AtomicXor16U:
          return "i64.atomic.rmw16.xor_u";
        case ThreadOp::I64AtomicXor32U:
          return "i64.atomic.rmw32.xor_u";
        case ThreadOp::I32AtomicXchg:
          return "i32.atomic.rmw.xchg";
        case ThreadOp::I64AtomicXchg:
          return "i64.atomic.rmw.xchg";
        case ThreadOp::I32AtomicXchg8U:
          return "i32.atomic.rmw8.xchg_u";
        case ThreadOp::I32AtomicXchg16U:
          return "i32.atomic.rmw16.xchg_u";
        case ThreadOp::I64AtomicXchg8U:
          return "i64.atomic.rmw8.xchg_u";
        case ThreadOp::I64AtomicXchg16U:
          return "i64.atomic.rmw16.xchg_u";
        case ThreadOp::I64AtomicXchg32U:
          return "i64.atomic.rmw32.xchg_u";
        case ThreadOp::I32AtomicCmpXchg:
          return "i32.atomic.rmw.cmpxchg";
        case ThreadOp::I64AtomicCmpXchg:
          return "i64.atomic.rmw.cmpxchg";
        case ThreadOp::I32AtomicCmpXchg8U:
          return "i32.atomic.rmw8.cmpxchg_u";
        case ThreadOp::I32AtomicCmpXchg16U:
          return "i32.atomic.rmw16.cmpxchg_u";
        case ThreadOp::I64AtomicCmpXchg8U:
          return "i64.atomic.rmw8.cmpxchg_u";
        case ThreadOp::I64AtomicCmpXchg16U:
          return "i64.atomic.rmw16.cmpxchg_u";
        case ThreadOp::I64AtomicCmpXchg32U:
          return "i64.atomic.rmw32.cmpxchg_u";
        default:
          return "unknown";
      }
    }
    default:
      return "unknown";
  }
}

bool UnsetLocalsState::init(const ValTypeVector& locals, size_t numParams) {
  MOZ_ASSERT(setLocalsStack_.empty());

  // Find the first and total count of non-defaultable locals.
  size_t firstNonDefaultable = UINT32_MAX;
  size_t countNonDefaultable = 0;
  for (size_t i = numParams; i < locals.length(); i++) {
    if (!locals[i].isDefaultable()) {
      firstNonDefaultable = std::min(i, firstNonDefaultable);
      countNonDefaultable++;
    }
  }
  firstNonDefaultLocal_ = firstNonDefaultable;
  if (countNonDefaultable == 0) {
    // No locals to track, saving CPU cycles.
    MOZ_ASSERT(firstNonDefaultable == UINT32_MAX);
    return true;
  }

  // setLocalsStack_ cannot be deeper than amount of non-defaultable locals.
  if (!setLocalsStack_.reserve(countNonDefaultable)) {
    return false;
  }

  // Allocate a bitmap for locals starting at the first non-defaultable local.
  size_t bitmapSize =
      ((locals.length() - firstNonDefaultable) + (WordBits - 1)) / WordBits;
  if (!unsetLocals_.resize(bitmapSize)) {
    return false;
  }
  memset(unsetLocals_.begin(), 0, bitmapSize * WordSize);
  for (size_t i = firstNonDefaultable; i < locals.length(); i++) {
    if (!locals[i].isDefaultable()) {
      size_t localUnsetIndex = i - firstNonDefaultable;
      unsetLocals_[localUnsetIndex / WordBits] |=
          1 << (localUnsetIndex % WordBits);
    }
  }
  return true;
}
