Code/Wasm/Interpret/Jit/JitOperatorImpls.cs
// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Reflection;
// using System.Reflection.Emit;
// using WasmBox.Wasm.Instructions;

// namespace WasmBox.Wasm.Interpret.Jit
// {
//     using InstructionImpl = Action<CompilerContext, ILGenerator>;

//     /// <summary>
//     /// A collection of methods that compiler WebAssembly instructions to IL.
//     /// </summary>
//     public static class JitOperatorImpls
//     {
//         private static InstructionImpl ImplementAsOpCode(OpCode op, WasmValueType? resultType = null, params WasmValueType[] parameterTypes)
//         {
//             return (context, gen) =>
//             {
//                 var paramTypesOnStack = context.Pop(parameterTypes.Length);
//                 for (int i = 0; i < parameterTypes.Length; i++)
//                 {
//                     if (parameterTypes[i] != paramTypesOnStack[i])
//                     {
//                         throw new InvalidOperationException($"Expected type '{parameterTypes[i]}' on stack for argument {i} of opcode '{op}', but got type '{paramTypesOnStack[i]}' instead.");
//                     }
//                 }
//                 gen.Emit(op);
//                 if (resultType.HasValue)
//                 {
//                     context.Push(resultType.Value);
//                 }
//             };
//         }

//         private static InstructionImpl ImplementAsCall(MethodInfo callee)
//         {
//             return (context, gen) =>
//             {
//                 var parameterTypes = callee.GetParameters().Select(p => ValueHelpers.ToWasmValueType(p.ParameterType)).ToArray();
//                 var paramTypesOnStack = context.Pop(parameterTypes.Length);
//                 for (int i = 0; i < parameterTypes.Length; i++)
//                 {
//                     if (parameterTypes[i] != paramTypesOnStack[i])
//                     {
//                         throw new InvalidOperationException($"Expected type '{parameterTypes[i]}' on stack for argument {i} of method '{callee}', but got type '{paramTypesOnStack[i]}' instead.");
//                     }
//                 }
//                 gen.Emit(OpCodes.Call, callee);
//                 if (callee.ReturnType != null && callee.ReturnType != typeof(void))
//                 {
//                     context.Push(ValueHelpers.ToWasmValueType(callee.ReturnType));
//                 }
//             };
//         }

//         private static InstructionImpl Chain(params InstructionImpl[] impls)
//         {
//             return (context, gen) =>
//             {
//                 foreach (var impl in impls)
//                 {
//                     impl(context, gen);
//                 }
//             };
//         }

//         private static InstructionImpl ImplementAsBinaryOpCode(OpCode op, WasmValueType type)
//         {
//             return ImplementAsOpCode(op, type, type, type);
//         }

//         private static InstructionImpl ImplementAsComparisonOpCode(OpCode op, WasmValueType type)
//         {
//             return ImplementAsOpCode(op, WasmValueType.Int32, type, type);
//         }

//         private static InstructionImpl ImplementAsUnaryOpCode(OpCode op, WasmValueType type)
//         {
//             return ImplementAsOpCode(op, type, type);
//         }

//         /// <summary>
//         /// Compiles an 'i32.add' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Add(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Add, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.clz' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Clz(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.CountLeadingZeros),
//                     new[] { typeof(int) }));
//         }

//         /// <summary>
//         /// Compiles an 'i32.ctz' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Ctz(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.CountTrailingZeros),
//                     new[] { typeof(int) }));
//         }

//         /// <summary>
//         /// Compiles an 'i32.sub' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Sub(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Sub, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.mul' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Mul(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Mul, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.div_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32DivS(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Div, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.div_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32DivU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Div_Un, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.eq' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Eq(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Ceq, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.eqz' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Eqz(Instruction instruction)
//         {
//             return Chain(Int32Const(Operators.Int32Const.Create(0)), Int32Eq(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i32.ne' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Ne(Instruction instruction)
//         {
//             return Chain(Int32Eq(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i32.ge_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32GeS(Instruction instruction)
//         {
//             return Chain(Int32LtS(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i32.ge_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32GeU(Instruction instruction)
//         {
//             return Chain(Int32LtU(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i32.le_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32LeS(Instruction instruction)
//         {
//             return Chain(Int32GtS(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i32.le_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32LeU(Instruction instruction)
//         {
//             return Chain(Int32GtU(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i32.lt_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32LtS(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Clt, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.lt_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32LtU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Clt_Un, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.gt_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32GtS(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Cgt, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.gt_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32GtU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Cgt_Un, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.rem_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32RemS(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.RemS),
//                     new[] { typeof(int), typeof(int) }));
//         }

//         /// <summary>
//         /// Compiles an 'i32.rem_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32RemU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Rem_Un, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.rotl' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Rotl(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.RotateLeft),
//                     new[] { typeof(int), typeof(int) }));
//         }

//         /// <summary>
//         /// Compiles an 'i32.rotr' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Rotr(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.RotateRight),
//                     new[] { typeof(int), typeof(int) }));
//         }

//         /// <summary>
//         /// Compiles an 'i32.and' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32And(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.And, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.or' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Or(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Or, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.popcnt' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Popcnt(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.PopCount),
//                     new[] { typeof(int) }));
//         }

//         /// <summary>
//         /// Compiles an 'i32.wrap/i64' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32WrapInt64(Instruction instruction)
//         {
//             return ImplementAsOpCode(OpCodes.Conv_I4, WasmValueType.Int32, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i32.xor' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Xor(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Xor, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.shl' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Shl(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Shl, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.shl_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32ShrS(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Shr, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i32.shl_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32ShrU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Shr_Un, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i64.add' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Add(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Add, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.clz' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Clz(Instruction instruction)
//         {
//             return Chain(
//                 ImplementAsCall(
//                     typeof(ValueHelpers).GetMethod(
//                         nameof(ValueHelpers.CountLeadingZeros),
//                         new[] { typeof(long) })),
//                 Int64ExtendUInt32(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.ctz' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Ctz(Instruction instruction)
//         {
//             return Chain(
//                 ImplementAsCall(
//                     typeof(ValueHelpers).GetMethod(
//                         nameof(ValueHelpers.CountTrailingZeros),
//                         new[] { typeof(long) })),
//                 Int64ExtendUInt32(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.sub' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Sub(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Sub, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.mul' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Mul(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Mul, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.div_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64DivS(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Div, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.div_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64DivU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Div_Un, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.eq' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Eq(Instruction instruction)
//         {
//             return ImplementAsComparisonOpCode(OpCodes.Ceq, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.eqz' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Eqz(Instruction instruction)
//         {
//             return Chain(Int64Const(Operators.Int64Const.Create(0)), Int64Eq(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.extend_s/i32' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64ExtendSInt32(Instruction instruction)
//         {
//             return ImplementAsOpCode(OpCodes.Conv_I8, WasmValueType.Int64, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i64.extend_u/i32' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64ExtendUInt32(Instruction instruction)
//         {
//             return ImplementAsOpCode(OpCodes.Conv_U8, WasmValueType.Int64, WasmValueType.Int32);
//         }

//         /// <summary>
//         /// Compiles an 'i64.ne' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Ne(Instruction instruction)
//         {
//             return Chain(Int64Eq(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.ge_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64GeS(Instruction instruction)
//         {
//             return Chain(Int64LtS(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.ge_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64GeU(Instruction instruction)
//         {
//             return Chain(Int64LtU(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.le_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64LeS(Instruction instruction)
//         {
//             return Chain(Int64GtS(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.le_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64LeU(Instruction instruction)
//         {
//             return Chain(Int64GtU(instruction), Int32Eqz(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.lt_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64LtS(Instruction instruction)
//         {
//             return ImplementAsComparisonOpCode(OpCodes.Clt, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.lt_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64LtU(Instruction instruction)
//         {
//             return ImplementAsComparisonOpCode(OpCodes.Clt_Un, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.gt_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64GtS(Instruction instruction)
//         {
//             return ImplementAsComparisonOpCode(OpCodes.Cgt, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.gt_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64GtU(Instruction instruction)
//         {
//             return ImplementAsComparisonOpCode(OpCodes.Cgt_Un, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.rem_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64RemS(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.RemS),
//                     new[] { typeof(long), typeof(long) }));
//         }

//         /// <summary>
//         /// Compiles an 'i64.rem_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64RemU(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Rem_Un, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.rotl' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Rotl(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.RotateLeft),
//                     new[] { typeof(long), typeof(long) }));
//         }

//         /// <summary>
//         /// Compiles an 'i64.rotr' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Rotr(Instruction instruction)
//         {
//             return ImplementAsCall(
//                 typeof(ValueHelpers).GetMethod(
//                     nameof(ValueHelpers.RotateRight),
//                     new[] { typeof(long), typeof(long) }));
//         }

//         /// <summary>
//         /// Compiles an 'i64.and' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64And(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.And, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.or' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Or(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Or, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.popcnt' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Popcnt(Instruction instruction)
//         {
//             return Chain(
//                 ImplementAsCall(
//                     typeof(ValueHelpers).GetMethod(
//                         nameof(ValueHelpers.PopCount),
//                         new[] { typeof(long) })),
//                 Int64ExtendUInt32(instruction));
//         }

//         /// <summary>
//         /// Compiles an 'i64.xor' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Xor(Instruction instruction)
//         {
//             return ImplementAsBinaryOpCode(OpCodes.Xor, WasmValueType.Int64);
//         }

//         /// <summary>
//         /// Compiles an 'i64.shl' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Shl(Instruction instruction)
//         {
//             return Chain(
//                 Int32WrapInt64(instruction),
//                 ImplementAsOpCode(OpCodes.Shl, WasmValueType.Int64, WasmValueType.Int64, WasmValueType.Int32));
//         }

//         /// <summary>
//         /// Compiles an 'i64.shl_s' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64ShrS(Instruction instruction)
//         {
//             return Chain(
//                 Int32WrapInt64(instruction),
//                 ImplementAsOpCode(OpCodes.Shr, WasmValueType.Int64, WasmValueType.Int64, WasmValueType.Int32));
//         }

//         /// <summary>
//         /// Compiles an 'i64.shl_u' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64ShrU(Instruction instruction)
//         {
//             return Chain(
//                 Int32WrapInt64(instruction),
//                 ImplementAsOpCode(OpCodes.Shr_Un, WasmValueType.Int64, WasmValueType.Int64, WasmValueType.Int32));
//         }

//         /// <summary>
//         /// Compiles an 'i32.const' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int32Const(Instruction instruction)
//         {
//             var immediate = Operators.Int32Const.CastInstruction(instruction).Immediate;
//             return (context, gen) =>
//             {
//                 gen.Emit(OpCodes.Ldc_I4, immediate);
//                 context.Push(WasmValueType.Int32);
//             };
//         }

//         /// <summary>
//         /// Compiles an 'i64.const' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Int64Const(Instruction instruction)
//         {
//             var immediate = Operators.Int64Const.CastInstruction(instruction).Immediate;
//             return (context, gen) =>
//             {
//                 gen.Emit(OpCodes.Ldc_I8, immediate);
//                 context.Push(WasmValueType.Int64);
//             };
//         }

//         /// <summary>
//         /// Compiles an 'f32.const' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Float32Const(Instruction instruction)
//         {
//             var immediate = Operators.Float32Const.CastInstruction(instruction).Immediate;
//             return (context, gen) =>
//             {
//                 gen.Emit(OpCodes.Ldc_R4, immediate);
//                 context.Push(WasmValueType.Float32);
//             };
//         }

//         /// <summary>
//         /// Compiles an 'f64.const' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Float64Const(Instruction instruction)
//         {
//             var immediate = Operators.Float64Const.CastInstruction(instruction).Immediate;
//             return (context, gen) =>
//             {
//                 gen.Emit(OpCodes.Ldc_R8, immediate);
//                 context.Push(WasmValueType.Float64);
//             };
//         }

//         /// <summary>
//         /// Compiles a 'nop' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Nop(Instruction instruction)
//         {
//             return (context, gen) => { };
//         }

//         /// <summary>
//         /// Compiles a 'drop' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Drop(Instruction instruction)
//         {
//             return (context, gen) =>
//             {
//                 context.Pop();
//                 gen.Emit(OpCodes.Pop);
//             };
//         }

//         /// <summary>
//         /// Compiles a 'select' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Select(Instruction instruction)
//         {
//             return (context, gen) =>
//             {
//                 context.Pop();
//                 var rhsType = context.Pop();
//                 var lhsType = context.Pop();
//                 var ifLabel = gen.DefineLabel();
//                 var endLabel = gen.DefineLabel();
//                 gen.Emit(OpCodes.Brtrue, ifLabel);

//                 var rhsLocal = gen.DeclareLocal(ValueHelpers.ToClrType(rhsType));
//                 gen.Emit(OpCodes.Stloc, rhsLocal);
//                 gen.Emit(OpCodes.Pop);
//                 gen.Emit(OpCodes.Ldloc, rhsLocal);
//                 gen.Emit(OpCodes.Br, endLabel);

//                 gen.MarkLabel(ifLabel);
//                 gen.Emit(OpCodes.Pop);

//                 gen.MarkLabel(endLabel);
//                 context.Push(lhsType);
//             };
//         }

//         /// <summary>
//         /// Compiles a 'call' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl Call(Instruction instruction)
//         {
//             var callInsn = Operators.Call.CastInstruction(instruction);
//             var index = (int)callInsn.Immediate;
//             return (context, gen) =>
//             {
//                 // Check for stack overflow.
//                 var successLabel = gen.DefineLabel();
//                 gen.Emit(OpCodes.Ldarg, context.ParameterCount);
//                 gen.Emit(OpCodes.Ldc_I4, (int)context.Compiler.module.Policy.MaxCallStackDepth);
//                 gen.Emit(OpCodes.Blt_Un, successLabel);
//                 gen.Emit(OpCodes.Ldstr, "A stack overflow occurred: the max call stack depth was exceeded");
//                 gen.Emit(OpCodes.Ldstr, TrapException.SpecMessages.CallStackExhausted);
//                 gen.Emit(OpCodes.Newobj, typeof(TrapException).GetConstructor(new[] { typeof(string), typeof(string) }));
//                 gen.Emit(OpCodes.Throw);
//                 gen.MarkLabel(successLabel);

//                 FunctionType signature;
//                 if (index < context.Compiler.offset)
//                 {
//                     // If we're calling an import, then things get interesting. Basically, we have to emit
//                     // a call to the import's Invoke method instead of calling the import directly as
//                     // we can do with compiled methods.
//                     var callee = context.Compiler.module.Functions[index];
//                     signature = new FunctionType(callee.ParameterTypes, callee.ReturnTypes);
//                     var args = new List<Func<ILGenerator, Type>>();
//                     foreach (var item in callee.ParameterTypes.Reverse())
//                     {
//                         var loc = gen.DeclareLocal(ValueHelpers.ToClrType(item));
//                         gen.Emit(OpCodes.Stloc, loc);
//                         args.Add(generator =>
//                         {
//                             generator.Emit(OpCodes.Ldloc, loc);
//                             return loc.LocalType;
//                         });
//                     }
//                     args.Reverse();
//                     context.Compiler.EmitExternalCall(gen, context.ParameterCount, callee, args);
//                 }
//                 else
//                 {
//                     // Push the call stack depth onto the evaluation stack.
//                     gen.Emit(OpCodes.Ldarg, context.ParameterCount);

//                     // Emit the call.
//                     signature = context.Compiler.types[index - context.Compiler.offset];
//                     var callee = context.Compiler.builders[index - context.Compiler.offset];
//                     gen.Emit(OpCodes.Call, callee);
//                 }

//                 // Pop and check argument types.
//                 var parameterTypes = signature.ParameterTypes;
//                 var paramTypesOnStack = context.Pop(parameterTypes.Count);
//                 for (int i = 0; i < parameterTypes.Count; i++)
//                 {
//                     if (parameterTypes[i] != paramTypesOnStack[i])
//                     {
//                         throw new InvalidOperationException($"Expected type '{parameterTypes[i]}' on stack for function call, but got type '{paramTypesOnStack[i]}' instead.");
//                     }
//                 }

//                 // Update the type stack.
//                 foreach (var item in signature.ReturnTypes)
//                 {
//                     context.Push(item);
//                 }
//             };
//         }

//         /// <summary>
//         /// Compiles a 'get_local' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl GetLocal(Instruction instruction)
//         {
//             var index = Operators.GetLocal.CastInstruction(instruction).Immediate;
//             return (context, gen) =>
//             {
//                 if (index < context.ParameterCount)
//                 {
//                     gen.Emit(OpCodes.Ldarg, (int)index);
//                 }
//                 else
//                 {
//                     gen.Emit(OpCodes.Ldloc, context.Locals[index]);
//                 }
//                 context.Push(context.LocalTypes[(int)index]);
//             };
//         }

//         /// <summary>
//         /// Compiles a 'set_local' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl SetLocal(Instruction instruction)
//         {
//             var index = Operators.SetLocal.CastInstruction(instruction).Immediate;
//             return (context, gen) =>
//             {
//                 if (index < context.ParameterCount)
//                 {
//                     gen.Emit(OpCodes.Starg, (int)index);
//                 }
//                 else
//                 {
//                     gen.Emit(OpCodes.Stloc, context.Locals[index]);
//                 }
//             };
//         }

//         /// <summary>
//         /// Compiles a 'tee_local' instruction.
//         /// </summary>
//         /// <param name="instruction">The instruction to compile to an implementation.</param>
//         public static InstructionImpl TeeLocal(Instruction instruction)
//         {
//             return (context, gen) =>
//             {
//                 gen.Emit(OpCodes.Dup);
//                 var type = context.Pop();
//                 context.Push(type);
//                 context.Push(type);
//                 SetLocal(instruction)(context, gen);
//             };
//         }
//     }
// }