static bool DecodeBranch(FunctionDecoder& f, Expr expr, ExprType* type) { MOZ_ASSERT(expr == Expr::Br || expr == Expr::BrIf); uint32_t relativeDepth; if (!f.d().readVarU32(&relativeDepth)) return f.fail("expected relative depth"); if (!f.branchWithType(relativeDepth, ExprType::Void)) return f.fail("branch depth exceeds current nesting level"); Expr value; if (!f.d().readExpr(&value)) return f.fail("expected branch value"); if (value != Expr::Nop) return f.fail("NYI: branch values"); if (expr == Expr::BrIf) { ExprType actual; if (!DecodeExpr(f, &actual)) return false; if (!CheckType(f, actual, ValType::I32)) return false; *type = ExprType::Void; } else { *type = AnyType; } return true; }
static bool DecodeBlock(FunctionDecoder& f, bool isLoop, ExprType* type) { if (!f.pushBlock()) return f.fail("nesting overflow"); if (isLoop) { if (!f.pushBlock()) return f.fail("nesting overflow"); } uint32_t numExprs; if (!f.d().readVarU32(&numExprs)) return f.fail("unable to read block's number of expressions"); ExprType exprType = ExprType::Void; for (uint32_t i = 0; i < numExprs; i++) { if (!DecodeExpr(f, &exprType)) return false; } if (isLoop) f.popBlock(); ExprType branchType = f.popBlock(); *type = Unify(branchType, exprType); return true; }
static bool DecodeExpr(FunctionDecoder& f, ExprType expected) { Expr expr; if (!f.d().readExpr(&expr)) return f.fail("unable to read expression"); switch (expr) { case Expr::Nop: return CheckType(f, ExprType::Void, expected); case Expr::Call: return DecodeCall(f, expected); case Expr::CallImport: return DecodeCallImport(f, expected); case Expr::I32Const: return DecodeConst(f, expected); case Expr::GetLocal: return DecodeGetLocal(f, expected); case Expr::SetLocal: return DecodeSetLocal(f, expected); case Expr::Block: return DecodeBlock(f, expected); case Expr::I32Add: case Expr::I32Sub: case Expr::I32Mul: case Expr::I32DivS: case Expr::I32DivU: case Expr::I32RemS: case Expr::I32RemU: case Expr::I32And: case Expr::I32Or: case Expr::I32Xor: case Expr::I32Shl: case Expr::I32ShrS: case Expr::I32ShrU: case Expr::F32Add: case Expr::F32Sub: case Expr::F32Mul: case Expr::F32Div: case Expr::F32Min: case Expr::F32Max: case Expr::F32CopySign: case Expr::F64Add: case Expr::F64Sub: case Expr::F64Mul: case Expr::F64Div: case Expr::F64Min: case Expr::F64Max: case Expr::F64CopySign: return DecodeBinaryOperator(f, expected); default: break; } return f.fail("bad expression code"); }
static bool DecodeLoadStoreAddress(FunctionDecoder &f) { uint32_t offset, align; return DecodeExpr(f, ExprType::I32) && f.d().readVarU32(&offset) && f.d().readVarU32(&align) && mozilla::IsPowerOfTwo(align) && (offset == 0 || f.fail("NYI: address offsets")) && f.fail("NYI: wasm loads and stores"); }
static bool DecodeCallImport(FunctionDecoder& f, ExprType* type) { uint32_t importIndex; if (!f.d().readVarU32(&importIndex)) return f.fail("unable to read import index"); if (importIndex >= f.mg().numImports()) return f.fail("import index out of range"); return DecodeCallWithSig(f, *f.mg().import(importIndex).sig, type); }
static bool DecodeCall(FunctionDecoder& f, ExprType* type) { uint32_t funcIndex; if (!f.d().readVarU32(&funcIndex)) return f.fail("unable to read import index"); if (funcIndex >= f.mg().numFuncSigs()) return f.fail("callee index out of range"); return DecodeCallWithSig(f, f.mg().funcSig(funcIndex), type); }
static bool DecodeGetLocal(FunctionDecoder& f, ExprType expected) { uint32_t localIndex; if (!f.d().readVarU32(&localIndex)) return f.fail("unable to read get_local index"); if (localIndex >= f.fg().locals().length()) return f.fail("get_local index out of range"); return CheckType(f, ToExprType(f.fg().locals()[localIndex]), expected); }
static bool DecodeGetLocal(FunctionDecoder& f, ExprType* type) { uint32_t localIndex; if (!f.d().readVarU32(&localIndex)) return f.fail("unable to read get_local index"); if (localIndex >= f.locals().length()) return f.fail("get_local index out of range"); *type = ToExprType(f.locals()[localIndex]); return true; }
static bool DecodeConstF64(FunctionDecoder& f, ExprType expected) { double value; if (!f.d().readFixedF64(&value)) return f.fail("unable to read f64.const immediate"); if (IsNaN(value)) { const double jsNaN = JS::GenericNaN(); if (memcmp(&value, &jsNaN, sizeof(value)) != 0) return f.fail("NYI: NaN literals with custom payloads"); } return CheckType(f, ExprType::F64, expected); }
static bool DecodeCallIndirect(FunctionDecoder& f, ExprType expected) { uint32_t sigIndex; if (!f.d().readVarU32(&sigIndex)) return f.fail("unable to read indirect call signature index"); if (sigIndex >= f.mg().numSigs()) return f.fail("signature index out of range"); if (!DecodeExpr(f, ExprType::I32)) return false; return DecodeCallWithSig(f, f.mg().sig(sigIndex), expected); }
static bool DecodeConstF32(FunctionDecoder& f, ExprType* type) { float value; if (!f.d().readFixedF32(&value)) return f.fail("unable to read f32.const immediate"); if (IsNaN(value)) { const float jsNaN = (float)JS::GenericNaN(); if (memcmp(&value, &jsNaN, sizeof(value)) != 0) return f.fail("NYI: NaN literals with custom payloads"); } *type = ExprType::F32; return true; }
static bool DecodeSetLocal(FunctionDecoder& f, ExprType expected) { uint32_t localIndex; if (!f.d().readVarU32(&localIndex)) return f.fail("unable to read set_local index"); if (localIndex >= f.fg().locals().length()) return f.fail("set_local index out of range"); ExprType localType = ToExprType(f.fg().locals()[localIndex]); if (!DecodeExpr(f, localType)) return false; return CheckType(f, localType, expected); }
static bool DecodeConst(FunctionDecoder& f, ExprType expected) { if (!f.d().readVarU32()) return f.fail("unable to read i32.const immediate"); return CheckType(f, ExprType::I32, expected); }
static bool DecodeCallImport(FunctionDecoder& f, ExprType expected) { uint32_t importIndex; if (!f.d().readU32(&importIndex)) return f.fail("unable to read import index"); if (importIndex >= f.mg().numImports()) return f.fail("import index out of range"); const DeclaredSig& sig = *f.mg().import(importIndex).sig; for (ValType argType : sig.args()) { if (!DecodeExpr(f, ToExprType(argType))) return false; } return CheckType(f, sig.ret(), expected); }
static bool DecodeCall(FunctionDecoder& f, ExprType expected) { uint32_t funcIndex; if (!f.d().readU32(&funcIndex)) return f.fail("unable to read import index"); if (funcIndex >= f.mg().numFuncSigs()) return f.fail("callee index out of range"); const DeclaredSig& sig = f.mg().funcSig(funcIndex); for (ValType argType : sig.args()) { if (!DecodeExpr(f, ToExprType(argType))) return false; } return CheckType(f, sig.ret(), expected); }
static bool DecodeConstI32(FunctionDecoder& f, ExprType* type) { int32_t _; if (!f.d().readVarS32(&_)) return f.fail("unable to read i32.const immediate"); *type = ExprType::I32; return true; }
static bool DecodeConstI64(FunctionDecoder& f, ExprType* type) { int64_t _; if (!f.d().readVarS64(&_)) return f.fail("unable to read i64.const immediate"); *type = ExprType::I64; return true; }
static bool DecodeLoadStoreAddress(FunctionDecoder &f, unsigned width) { uint32_t flags; if (!f.d().readVarU32(&flags)) return f.fail("expected memory access flags"); uint32_t alignLog2 = flags; if (alignLog2 >= 32 || (1u << alignLog2) > width) return f.fail("greater than natural alignment"); uint32_t offset; if (!f.d().readVarU32(&offset)) return f.fail("expected memory access offset"); ExprType baseType; if (!DecodeExpr(f, &baseType)) return false; return CheckType(f, baseType, ExprType::I32); }
static bool CheckType(FunctionDecoder& f, ExprType actual, ExprType expected) { if (actual == expected || expected == ExprType::Void) return true; UniqueChars error(JS_smprintf("type mismatch: expression has type %s but expected %s", ToCString(actual), ToCString(expected))); if (!error) return false; return f.fail(error.get()); }
static bool DecodeBrTable(FunctionDecoder& f, ExprType* type) { uint32_t tableLength; if (!f.d().readVarU32(&tableLength)) return false; if (tableLength > MaxBrTableElems) return f.fail("too many br_table entries"); for (uint32_t i = 0; i < tableLength; i++) { uint32_t depth; if (!f.d().readFixedU32(&depth)) return f.fail("missing br_table entry"); if (!f.branchWithType(depth, ExprType::Void)) return f.fail("branch depth exceeds current nesting level"); } uint32_t defaultDepth; if (!f.d().readFixedU32(&defaultDepth)) return f.fail("expected default relative depth"); if (!f.branchWithType(defaultDepth, ExprType::Void)) return f.fail("branch depth exceeds current nesting level"); ExprType actual; if (!DecodeExpr(f, &actual)) return false; if (!CheckType(f, actual, ExprType::I32)) return false; *type = AnyType; return true; }
static bool DecodeBlock(FunctionDecoder& f, ExprType expected) { uint32_t numExprs; if (!f.d().readVarU32(&numExprs)) return f.fail("unable to read block's number of expressions"); if (numExprs) { for (uint32_t i = 0; i < numExprs - 1; i++) { if (!DecodeExpr(f, ExprType::Void)) return false; } if (!DecodeExpr(f, expected)) return false; } else { if (!CheckType(f, ExprType::Void, expected)) return false; } return true; }
static bool DecodeExpr(FunctionDecoder& f, ExprType expected) { Expr expr; if (!f.d().readExpr(&expr)) return f.fail("unable to read expression"); switch (expr) { case Expr::Nop: return CheckType(f, ExprType::Void, expected); case Expr::Call: return DecodeCall(f, expected); case Expr::CallImport: return DecodeCallImport(f, expected); case Expr::CallIndirect: return DecodeCallIndirect(f, expected); case Expr::I32Const: return DecodeConstI32(f, expected); case Expr::I64Const: return f.fail("NYI: i64") && DecodeConstI64(f, expected); case Expr::F32Const: return DecodeConstF32(f, expected); case Expr::F64Const: return DecodeConstF64(f, expected); case Expr::GetLocal: return DecodeGetLocal(f, expected); case Expr::SetLocal: return DecodeSetLocal(f, expected); case Expr::Block: return DecodeBlock(f, expected); case Expr::If: return DecodeIfElse(f, /* hasElse */ false, expected); case Expr::IfElse: return DecodeIfElse(f, /* hasElse */ true, expected); case Expr::I32Clz: return DecodeUnaryOperator(f, expected, ExprType::I32); case Expr::I32Ctz: return f.fail("NYI: ctz"); case Expr::I32Popcnt: return f.fail("NYI: popcnt"); case Expr::I64Clz: case Expr::I64Ctz: case Expr::I64Popcnt: return f.fail("NYI: i64") && DecodeUnaryOperator(f, expected, ExprType::I64); case Expr::F32Abs: case Expr::F32Neg: case Expr::F32Ceil: case Expr::F32Floor: case Expr::F32Sqrt: return DecodeUnaryOperator(f, expected, ExprType::F32); case Expr::F32Trunc: return f.fail("NYI: trunc"); case Expr::F32Nearest: return f.fail("NYI: nearest"); case Expr::F64Abs: case Expr::F64Neg: case Expr::F64Ceil: case Expr::F64Floor: case Expr::F64Sqrt: return DecodeUnaryOperator(f, expected, ExprType::F64); case Expr::F64Trunc: return f.fail("NYI: trunc"); case Expr::F64Nearest: return f.fail("NYI: nearest"); case Expr::I32Add: case Expr::I32Sub: case Expr::I32Mul: case Expr::I32DivS: case Expr::I32DivU: case Expr::I32RemS: case Expr::I32RemU: case Expr::I32And: case Expr::I32Or: case Expr::I32Xor: case Expr::I32Shl: case Expr::I32ShrS: case Expr::I32ShrU: return DecodeBinaryOperator(f, expected, ExprType::I32); case Expr::I64Add: case Expr::I64Sub: case Expr::I64Mul: case Expr::I64DivS: case Expr::I64DivU: case Expr::I64RemS: case Expr::I64RemU: case Expr::I64And: case Expr::I64Or: case Expr::I64Xor: case Expr::I64Shl: case Expr::I64ShrS: case Expr::I64ShrU: return f.fail("NYI: i64") && DecodeBinaryOperator(f, expected, ExprType::I64); case Expr::F32Add: case Expr::F32Sub: case Expr::F32Mul: case Expr::F32Div: case Expr::F32Min: case Expr::F32Max: return DecodeBinaryOperator(f, expected, ExprType::F32); case Expr::F32CopySign: return f.fail("NYI: copysign"); case Expr::F64Add: case Expr::F64Sub: case Expr::F64Mul: case Expr::F64Div: case Expr::F64Min: case Expr::F64Max: return DecodeBinaryOperator(f, expected, ExprType::F64); case Expr::F64CopySign: return f.fail("NYI: copysign"); case Expr::I32Eq: case Expr::I32Ne: case Expr::I32LtS: case Expr::I32LtU: case Expr::I32LeS: case Expr::I32LeU: case Expr::I32GtS: case Expr::I32GtU: case Expr::I32GeS: case Expr::I32GeU: return DecodeComparisonOperator(f, expected, ExprType::I32); case Expr::I64Eq: case Expr::I64Ne: case Expr::I64LtS: case Expr::I64LtU: case Expr::I64LeS: case Expr::I64LeU: case Expr::I64GtS: case Expr::I64GtU: case Expr::I64GeS: case Expr::I64GeU: return f.fail("NYI: i64") && DecodeComparisonOperator(f, expected, ExprType::I64); case Expr::F32Eq: case Expr::F32Ne: case Expr::F32Lt: case Expr::F32Le: case Expr::F32Gt: case Expr::F32Ge: return DecodeComparisonOperator(f, expected, ExprType::F32); case Expr::F64Eq: case Expr::F64Ne: case Expr::F64Lt: case Expr::F64Le: case Expr::F64Gt: case Expr::F64Ge: return DecodeComparisonOperator(f, expected, ExprType::F64); case Expr::I32WrapI64: return f.fail("NYI: i64") && DecodeConversionOperator(f, expected, ExprType::I32, ExprType::I64); case Expr::I32TruncSF32: case Expr::I32TruncUF32: return DecodeConversionOperator(f, expected, ExprType::I32, ExprType::F32); case Expr::I32ReinterpretF32: return f.fail("NYI: reinterpret"); case Expr::I32TruncSF64: case Expr::I32TruncUF64: return DecodeConversionOperator(f, expected, ExprType::I32, ExprType::F64); case Expr::I64ExtendSI32: case Expr::I64ExtendUI32: return f.fail("NYI: i64") && DecodeConversionOperator(f, expected, ExprType::I64, ExprType::I32); case Expr::I64TruncSF32: case Expr::I64TruncUF32: return f.fail("NYI: i64") && DecodeConversionOperator(f, expected, ExprType::I64, ExprType::F32); case Expr::I64TruncSF64: case Expr::I64TruncUF64: case Expr::I64ReinterpretF64: return f.fail("NYI: i64") && DecodeConversionOperator(f, expected, ExprType::I64, ExprType::F64); case Expr::F32ConvertSI32: case Expr::F32ConvertUI32: return DecodeConversionOperator(f, expected, ExprType::F32, ExprType::I32); case Expr::F32ReinterpretI32: return f.fail("NYI: reinterpret"); case Expr::F32ConvertSI64: case Expr::F32ConvertUI64: return f.fail("NYI: i64") && DecodeConversionOperator(f, expected, ExprType::F32, ExprType::I64); case Expr::F32DemoteF64: return DecodeConversionOperator(f, expected, ExprType::F32, ExprType::F64); case Expr::F64ConvertSI32: case Expr::F64ConvertUI32: return DecodeConversionOperator(f, expected, ExprType::F64, ExprType::I32); case Expr::F64ConvertSI64: case Expr::F64ConvertUI64: case Expr::F64ReinterpretI64: return f.fail("NYI: i64") && DecodeConversionOperator(f, expected, ExprType::F64, ExprType::I64); case Expr::F64PromoteF32: return DecodeConversionOperator(f, expected, ExprType::F64, ExprType::F32); case Expr::I32LoadMem: case Expr::I32LoadMem8S: case Expr::I32LoadMem8U: case Expr::I32LoadMem16S: case Expr::I32LoadMem16U: return DecodeLoad(f, expected, ExprType::I32); case Expr::I64LoadMem: case Expr::I64LoadMem8S: case Expr::I64LoadMem8U: case Expr::I64LoadMem16S: case Expr::I64LoadMem16U: case Expr::I64LoadMem32S: case Expr::I64LoadMem32U: return DecodeLoad(f, expected, ExprType::I64); case Expr::F32LoadMem: return DecodeLoad(f, expected, ExprType::F32); case Expr::F64LoadMem: return DecodeLoad(f, expected, ExprType::F64); case Expr::I32StoreMem: case Expr::I32StoreMem8: case Expr::I32StoreMem16: return DecodeStore(f, expected, ExprType::I32); case Expr::I64StoreMem: case Expr::I64StoreMem8: case Expr::I64StoreMem16: case Expr::I64StoreMem32: return f.fail("NYI: i64") && DecodeStore(f, expected, ExprType::I64); case Expr::F32StoreMem: return DecodeStore(f, expected, ExprType::F32); case Expr::F64StoreMem: return DecodeStore(f, expected, ExprType::F64); default: break; } return f.fail("bad expression code"); }
static bool DecodeExpr(FunctionDecoder& f, ExprType* type) { Expr expr; if (!f.d().readExpr(&expr)) return f.fail("unable to read expression"); switch (expr) { case Expr::Nop: return DecodeNop(f, type); case Expr::Call: return DecodeCall(f, type); case Expr::CallImport: return DecodeCallImport(f, type); case Expr::CallIndirect: return DecodeCallIndirect(f, type); case Expr::I32Const: return DecodeConstI32(f, type); case Expr::I64Const: return DecodeConstI64(f, type); case Expr::F32Const: return DecodeConstF32(f, type); case Expr::F64Const: return DecodeConstF64(f, type); case Expr::GetLocal: return DecodeGetLocal(f, type); case Expr::SetLocal: return DecodeSetLocal(f, type); case Expr::Block: return DecodeBlock(f, /* isLoop */ false, type); case Expr::Loop: return DecodeBlock(f, /* isLoop */ true, type); case Expr::If: return DecodeIfElse(f, /* hasElse */ false, type); case Expr::IfElse: return DecodeIfElse(f, /* hasElse */ true, type); case Expr::I32Clz: case Expr::I32Ctz: case Expr::I32Popcnt: return DecodeUnaryOperator(f, ValType::I32, type); case Expr::I64Clz: case Expr::I64Ctz: case Expr::I64Popcnt: return f.fail("NYI: i64") && DecodeUnaryOperator(f, ValType::I64, type); case Expr::F32Abs: case Expr::F32Neg: case Expr::F32Ceil: case Expr::F32Floor: case Expr::F32Sqrt: return DecodeUnaryOperator(f, ValType::F32, type); case Expr::F32Trunc: return f.fail("NYI: trunc"); case Expr::F32Nearest: return f.fail("NYI: nearest"); case Expr::F64Abs: case Expr::F64Neg: case Expr::F64Ceil: case Expr::F64Floor: case Expr::F64Sqrt: return DecodeUnaryOperator(f, ValType::F64, type); case Expr::F64Trunc: return f.fail("NYI: trunc"); case Expr::F64Nearest: return f.fail("NYI: nearest"); case Expr::I32Add: case Expr::I32Sub: case Expr::I32Mul: case Expr::I32DivS: case Expr::I32DivU: case Expr::I32RemS: case Expr::I32RemU: case Expr::I32And: case Expr::I32Or: case Expr::I32Xor: case Expr::I32Shl: case Expr::I32ShrS: case Expr::I32ShrU: return DecodeBinaryOperator(f, ValType::I32, type); case Expr::I64Add: case Expr::I64Sub: case Expr::I64Mul: case Expr::I64DivS: case Expr::I64DivU: case Expr::I64RemS: case Expr::I64RemU: case Expr::I64And: case Expr::I64Or: case Expr::I64Xor: case Expr::I64Shl: case Expr::I64ShrS: case Expr::I64ShrU: return DecodeBinaryOperator(f, ValType::I64, type); case Expr::F32Add: case Expr::F32Sub: case Expr::F32Mul: case Expr::F32Div: case Expr::F32Min: case Expr::F32Max: return DecodeBinaryOperator(f, ValType::F32, type); case Expr::F32CopySign: return f.fail("NYI: copysign"); case Expr::F64Add: case Expr::F64Sub: case Expr::F64Mul: case Expr::F64Div: case Expr::F64Min: case Expr::F64Max: return DecodeBinaryOperator(f, ValType::F64, type); case Expr::F64CopySign: return f.fail("NYI: copysign"); case Expr::I32Eq: case Expr::I32Ne: case Expr::I32LtS: case Expr::I32LtU: case Expr::I32LeS: case Expr::I32LeU: case Expr::I32GtS: case Expr::I32GtU: case Expr::I32GeS: case Expr::I32GeU: return DecodeComparisonOperator(f, ValType::I32, type); case Expr::I64Eq: case Expr::I64Ne: case Expr::I64LtS: case Expr::I64LtU: case Expr::I64LeS: case Expr::I64LeU: case Expr::I64GtS: case Expr::I64GtU: case Expr::I64GeS: case Expr::I64GeU: return DecodeComparisonOperator(f, ValType::I64, type); case Expr::F32Eq: case Expr::F32Ne: case Expr::F32Lt: case Expr::F32Le: case Expr::F32Gt: case Expr::F32Ge: return DecodeComparisonOperator(f, ValType::F32, type); case Expr::F64Eq: case Expr::F64Ne: case Expr::F64Lt: case Expr::F64Le: case Expr::F64Gt: case Expr::F64Ge: return DecodeComparisonOperator(f, ValType::F64, type); case Expr::I32WrapI64: return DecodeConversionOperator(f, ValType::I32, ValType::I64, type); case Expr::I32TruncSF32: case Expr::I32TruncUF32: return DecodeConversionOperator(f, ValType::I32, ValType::F32, type); case Expr::I32ReinterpretF32: return f.fail("NYI: reinterpret"); case Expr::I32TruncSF64: case Expr::I32TruncUF64: return DecodeConversionOperator(f, ValType::I32, ValType::F64, type); case Expr::I64ExtendSI32: case Expr::I64ExtendUI32: return DecodeConversionOperator(f, ValType::I64, ValType::I32, type); case Expr::I64TruncSF32: case Expr::I64TruncUF32: return DecodeConversionOperator(f, ValType::I64, ValType::F32, type); case Expr::I64TruncSF64: case Expr::I64TruncUF64: return DecodeConversionOperator(f, ValType::I64, ValType::F64, type); case Expr::I64ReinterpretF64: return f.fail("NYI: i64"); case Expr::F32ConvertSI32: case Expr::F32ConvertUI32: return DecodeConversionOperator(f, ValType::F32, ValType::I32, type); case Expr::F32ReinterpretI32: return f.fail("NYI: reinterpret"); case Expr::F32ConvertSI64: case Expr::F32ConvertUI64: return f.fail("NYI: i64") && DecodeConversionOperator(f, ValType::F32, ValType::I64, type); case Expr::F32DemoteF64: return DecodeConversionOperator(f, ValType::F32, ValType::F64, type); case Expr::F64ConvertSI32: case Expr::F64ConvertUI32: return DecodeConversionOperator(f, ValType::F64, ValType::I32, type); case Expr::F64ConvertSI64: case Expr::F64ConvertUI64: case Expr::F64ReinterpretI64: return f.fail("NYI: i64") && DecodeConversionOperator(f, ValType::F64, ValType::I64, type); case Expr::F64PromoteF32: return DecodeConversionOperator(f, ValType::F64, ValType::F32, type); case Expr::I32Load8S: case Expr::I32Load8U: return DecodeLoad(f, 1, ValType::I32, type); case Expr::I32Load16S: case Expr::I32Load16U: return DecodeLoad(f, 2, ValType::I32, type); case Expr::I32Load: return DecodeLoad(f, 4, ValType::I32, type); case Expr::I64Load: case Expr::I64Load8S: case Expr::I64Load8U: case Expr::I64Load16S: case Expr::I64Load16U: case Expr::I64Load32S: case Expr::I64Load32U: return f.fail("NYI: i64") && DecodeLoad(f, 0, ValType::I64, type); case Expr::F32Load: return DecodeLoad(f, 4, ValType::F32, type); case Expr::F64Load: return DecodeLoad(f, 8, ValType::F64, type); case Expr::I32Store8: return DecodeStore(f, 1, ValType::I32, type); case Expr::I32Store16: return DecodeStore(f, 2, ValType::I32, type); case Expr::I32Store: return DecodeStore(f, 4, ValType::I32, type); case Expr::I64Store: case Expr::I64Store8: case Expr::I64Store16: case Expr::I64Store32: return f.fail("NYI: i64") && DecodeStore(f, 0, ValType::I64, type); case Expr::F32Store: return DecodeStore(f, 4, ValType::F32, type); case Expr::F64Store: return DecodeStore(f, 8, ValType::F64, type); case Expr::Br: return DecodeBranch(f, expr, type); case Expr::BrIf: return DecodeBranch(f, expr, type); case Expr::BrTable: return DecodeBrTable(f, type); case Expr::Return: return DecodeReturn(f, type); default: // Note: it's important not to remove this default since readExpr() // can return Expr values for which there is no enumerator. break; } return f.fail("bad expression code"); }