Code/Wasm/Interpret/Jit/JitCompiler.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 module compiler that compiles WebAssembly instructions to CIL.
//     /// </summary>
//     public class JitCompiler : ModuleCompiler
//     {
//         /// <summary>
//         /// Creates a JIT compiler from the default operator implementations.
//         /// </summary>
//         public JitCompiler()
//             : this(DefaultOperatorImplementations)
//         { }

//         /// <summary>
//         /// Creates a JIT compiler from an operator implementation map.
//         /// </summary>
//         /// <param name="operatorImplementations">A mapping of operators to functions that compile instructions.</param>
//         public JitCompiler(
//             IReadOnlyDictionary<Operator, Func<Instruction, InstructionImpl>> operatorImplementations)
//         {
//             this.OperatorImplementations = operatorImplementations; 
//         }

//         /// <summary>
//         /// Gets a mapping of operators to functions that compile instances of those operators
//         /// to implementations. <c>null</c> implementations indicate that an operator instance
//         /// cannot be compiled.
//         /// </summary>
//         /// <value>A mapping of operators to functions that compile instructions.</value>
//         public IReadOnlyDictionary<Operator, Func<Instruction, InstructionImpl>> OperatorImplementations { get; private set; }

//         internal ModuleInstance module;
//         internal int offset;
//         internal IReadOnlyList<FunctionType> types;
//         private AssemblyBuilder assembly;
//         internal IReadOnlyList<MethodBuilder> builders;
//         private TypeBuilder wasmType;
//         private IReadOnlyList<Func<IReadOnlyList<object>, IReadOnlyList<object>>> wrappers;
//         private List<CompiledFunctionDefinition> functionDefinitions;

//         private int helperFieldIndex;
//         private Dictionary<FieldInfo, object> constFieldValues;

//         /// <inheritdoc/>
//         public override void Initialize(ModuleInstance module, int offset, IReadOnlyList<FunctionType> types)
//         {
//             this.module = module;
//             this.offset = offset;
//             this.types = types;
//             this.helperFieldIndex = 0;
//             this.constFieldValues = new Dictionary<FieldInfo, object>();
//             this.functionDefinitions = new List<CompiledFunctionDefinition>();

//             this.assembly = AssemblyBuilder.DefineDynamicAssembly(
//                 new AssemblyName("wasm"),
//                 AssemblyBuilderAccess.RunAndCollect);
//             var wasmModule = assembly.DefineDynamicModule("main");
//             this.wasmType = wasmModule.DefineType("CompiledWasm", TypeAttributes.Public | TypeAttributes.Sealed);
//             var builderList = new List<MethodBuilder>();
//             var wrapperList = new List<Func<IReadOnlyList<object>, IReadOnlyList<object>>>();
//             foreach (var signature in types)
//             {
//                 var methodDef = wasmType.DefineMethod(
//                     $"func_{builderList.Count}",
//                     MethodAttributes.Public | MethodAttributes.Static);
//                 methodDef.SetParameters(
//                     signature.ParameterTypes.Select(ValueHelpers.ToClrType)
//                     .Concat(new[] { typeof(uint) })
//                     .ToArray());
//                 if (signature.ReturnTypes.Count == 0)
//                 {
//                     methodDef.SetReturnType(typeof(void));
//                 }
//                 else if (signature.ReturnTypes.Count == 1)
//                 {
//                     methodDef.SetReturnType(ValueHelpers.ToClrType(signature.ReturnTypes[0]));
//                 }
//                 else
//                 {
//                     throw new WasmException("Cannot compile functions with more than one return value.");
//                 }
//                 builderList.Add(methodDef);
//             }
//             this.builders = builderList;
//             this.wrappers = wrapperList;
//         }

//         /// <inheritdoc/>
//         public override FunctionDefinition Compile(int index, FunctionBody body)
//         {
//             var signature = types[index];
//             var builder = builders[index];
//             var ilGen = builder.GetILGenerator();
//             if (TryCompile(signature, body, ilGen))
//             {
//                 var result = new CompiledFunctionDefinition(signature, builder, module.Policy.TranslateExceptions);
//                 functionDefinitions.Add(result);
//                 return result;
//             }
//             else
//             {
//                 return MakeInterpreterThunk(index, body, ilGen);
//             }
//         }

//         private WasmFunctionDefinition MakeInterpreterThunk(int index, FunctionBody body, ILGenerator generator)
//         {
//             var signature = types[index];

//             // Create an interpreted function definition.
//             var func = new WasmFunctionDefinition(signature, body, module);

//             // Call it.
//             EmitExternalCall(
//                 generator,
//                 signature.ParameterTypes.Count,
//                 func,
//                 signature.ParameterTypes
//                     .Select<WasmValueType, Func<ILGenerator, Type>>(
//                         (p, i) => gen =>
//                         {
//                             gen.Emit(OpCodes.Ldarg, i);
//                             return ValueHelpers.ToClrType(p);
//                         })
//                     .ToArray());

//             // Return.
//             generator.Emit(OpCodes.Ret);

//             return func;
//         }

//         internal void EmitExternalCall(ILGenerator generator, int callerParameterCount, FunctionDefinition callee, IReadOnlyList<Func<ILGenerator, Type>> arguments)
//         {
//             var signature = new FunctionType(callee.ParameterTypes, callee.ReturnTypes);

//             // Create a function definition field, fill it and push its value onto the stack.
//             var field = DefineConstHelperField(callee);
//             generator.Emit(OpCodes.Ldsfld, field);

//             // Call it.
//             EmitExternalCall(generator, callerParameterCount, signature, callee.GetType(), arguments);
//         }

//         internal static void EmitExternalCall(ILGenerator generator, int callerParameterCount, FunctionType signature, Type calleeType, IReadOnlyList<Func<ILGenerator, Type>> arguments)
//         {
//             // To bridge the divide between JIT-compiled code and the interpreter,
//             // we generate code that packs the parameter list of a JIT-compiled
//             // function as an array of objects and feed that to the interpreter.
//             // We then unpack the list of objects produced by the interpreter.

//             // Create the arguments array.
//             EmitNewArray<object>(
//                 generator,
//                 arguments
//                     .Select<Func<ILGenerator, Type>, Action<ILGenerator>>(
//                         arg => gen =>
//                         {
//                             gen.Emit(OpCodes.Box, arg(gen));
//                         })
//                     .ToArray());

//             // Load the call stack depth.
//             generator.Emit(OpCodes.Ldarg, callerParameterCount);

//             // Call the interpreter.
//             var callee = calleeType
//                 .GetMethod("Invoke", new[] { typeof(IReadOnlyList<object>), typeof(uint) });

//             if (callee.IsPublic && calleeType.IsPublic)
//             {
//                 generator.Emit(OpCodes.Call, callee);
//             }
//             else
//             {
//                 generator.Emit(
//                     OpCodes.Callvirt,
//                     typeof(FunctionDefinition)
//                         .GetMethod("Invoke", new[] { typeof(IReadOnlyList<object>), typeof(uint) }));
//             }

//             // Unpack the interpreter's return values.
//             EmitUnpackList(
//                 generator,
//                 signature.ReturnTypes.Select(ValueHelpers.ToClrType).ToArray(),
//                 typeof(IReadOnlyList<object>));
//         }

//         private static bool IsGloballyAccessible(MethodInfo method)
//         {
//             return method.IsPublic && IsGloballyAccessible(method.DeclaringType);
//         }

//         private static bool IsGloballyAccessible(Type type)
//         {
//             return type.IsPublic || (type.IsNestedPublic && IsGloballyAccessible(type.DeclaringType));
//         }

//         private static void EmitUnpackList(ILGenerator generator, IReadOnlyList<Type> elementTypes, Type type)
//         {
//             var itemGetter = type.GetProperties().First(x => x.GetIndexParameters().Length > 0).GetMethod;
//             var local = generator.DeclareLocal(type);
//             generator.Emit(OpCodes.Stloc, local);
//             for (int i = 0; i < elementTypes.Count; i++)
//             {
//                 generator.Emit(OpCodes.Ldloc, local);
//                 generator.Emit(OpCodes.Ldc_I4, i);
//                 generator.Emit(OpCodes.Callvirt, itemGetter);
//                 generator.Emit(OpCodes.Unbox_Any, elementTypes[i]);
//             }
//         }

//         private FieldBuilder DefineConstHelperField(object value)
//         {
//             var field = DefineHelperField(value.GetType());
//             constFieldValues[field] = value;
//             return field;
//         }

//         private FieldBuilder DefineHelperField(Type type)
//         {
//             return wasmType.DefineField($"helper_{helperFieldIndex++}", type, FieldAttributes.Public | FieldAttributes.Static);
//         }

//         private static void EmitNewArray<T>(ILGenerator generator, IReadOnlyList<Action<ILGenerator>> valueGenerators)
//         {
//             generator.Emit(OpCodes.Ldc_I4, valueGenerators.Count);
//             generator.Emit(OpCodes.Newarr, typeof(T));
//             for (int i = 0; i < valueGenerators.Count; i++)
//             {
//                 generator.Emit(OpCodes.Dup);
//                 generator.Emit(OpCodes.Ldc_I4, i);
//                 valueGenerators[i](generator);
//                 generator.Emit(OpCodes.Stelem, typeof(T));
//             }
//         }

//         private bool TryCompile(FunctionType signature, FunctionBody body, ILGenerator generator)
//         {
//             var impl = GetImplementationOrNull(body.BodyInstructions);
//             if (impl == null)
//             {
//                 return false;
//             }
//             else
//             {
//                 var locals = new Dictionary<uint, LocalBuilder>();
//                 var localTypes = new List<WasmValueType>(signature.ParameterTypes);
//                 uint localIndex = (uint)signature.ParameterTypes.Count;
//                 foreach (var item in body.Locals)
//                 {
//                     for (uint i = 0; i < item.LocalCount; i++)
//                     {
//                         locals[localIndex++] = generator.DeclareLocal(ValueHelpers.ToClrType(item.LocalType));
//                         localTypes.Add(item.LocalType);
//                     }
//                 }
//                 var context = new CompilerContext(this, localTypes, signature.ParameterTypes.Count, locals);

//                 // Increment the call stack depth.
//                 generator.Emit(OpCodes.Ldarg, signature.ParameterTypes.Count);
//                 generator.Emit(OpCodes.Ldc_I4_1);
//                 generator.Emit(OpCodes.Add);
//                 generator.Emit(OpCodes.Starg, signature.ParameterTypes.Count);

//                 // Emit the method body.
//                 impl(context, generator);

//                 // Return.
//                 generator.Emit(OpCodes.Ret);
//                 return true;
//             }
//         }

//         private InstructionImpl GetImplementationOrNull(Instruction instruction)
//         {
//             Func<Instruction, InstructionImpl> impl;
//             if (OperatorImplementations.TryGetValue(instruction.Op, out impl))
//             {
//                 return impl(instruction);
//             }
//             else
//             {
//                 return null;
//             }
//         }

//         private InstructionImpl GetImplementationOrNull(IReadOnlyList<Instruction> instructions)
//         {
//             var impls = new List<InstructionImpl>();
//             foreach (var instruction in instructions)
//             {
//                 var instructionImpl = GetImplementationOrNull(instruction);
//                 if (instructionImpl == null)
//                 {
//                     return null;
//                 }
//                 impls.Add(instructionImpl);
//             }
//             return (context, gen) =>
//             {
//                 foreach (var impl in impls)
//                 {
//                     impl(context, gen);
//                 }
//             };
//         }

//         /// <inheritdoc/>
//         public override void Finish()
//         {
//             // Create the type.
//             var realType = wasmType.CreateType();

//             // Populate its fields.
//             foreach (var pair in constFieldValues)
//             {
//                 realType.GetField(pair.Key.Name).SetValue(null, pair.Value);
//             }
//             constFieldValues = null;

//             // Rewrite function definitions.
//             foreach (var functionDef in functionDefinitions)
//             {
//                 functionDef.method = realType.GetMethod(functionDef.method.Name);
//             }
//             functionDefinitions = null;
//         }

//         /// <summary>
//         /// The default mapping of operators to their implementations.
//         /// </summary>
//         public static readonly IReadOnlyDictionary<Operator, Func<Instruction, InstructionImpl>> DefaultOperatorImplementations =
//             new Dictionary<Operator, Func<Instruction, InstructionImpl>>()
//         {
//             { Operators.Nop, JitOperatorImpls.Nop },
//             { Operators.Drop, JitOperatorImpls.Drop },
//             { Operators.Select, JitOperatorImpls.Select },
//             { Operators.Call, JitOperatorImpls.Call },

//             { Operators.GetLocal, JitOperatorImpls.GetLocal },
//             { Operators.SetLocal, JitOperatorImpls.SetLocal },
//             { Operators.TeeLocal, JitOperatorImpls.TeeLocal },

//             { Operators.Int32Const, JitOperatorImpls.Int32Const },
//             { Operators.Int64Const, JitOperatorImpls.Int64Const },
//             { Operators.Float32Const, JitOperatorImpls.Float32Const },
//             { Operators.Float64Const, JitOperatorImpls.Float64Const },

//             { Operators.Int32Add, JitOperatorImpls.Int32Add },
//             { Operators.Int32And, JitOperatorImpls.Int32And },
//             { Operators.Int32Clz, JitOperatorImpls.Int32Clz },
//             { Operators.Int32Ctz, JitOperatorImpls.Int32Ctz },
//             { Operators.Int32DivS, JitOperatorImpls.Int32DivS },
//             { Operators.Int32DivU, JitOperatorImpls.Int32DivU },
//             { Operators.Int32Eq, JitOperatorImpls.Int32Eq },
//             { Operators.Int32Eqz, JitOperatorImpls.Int32Eqz },
//             { Operators.Int32GeS, JitOperatorImpls.Int32GeS },
//             { Operators.Int32GeU, JitOperatorImpls.Int32GeU },
//             { Operators.Int32GtS, JitOperatorImpls.Int32GtS },
//             { Operators.Int32GtU, JitOperatorImpls.Int32GtU },
//             { Operators.Int32LeS, JitOperatorImpls.Int32LeS },
//             { Operators.Int32LeU, JitOperatorImpls.Int32LeU },
//             { Operators.Int32LtS, JitOperatorImpls.Int32LtS },
//             { Operators.Int32LtU, JitOperatorImpls.Int32LtU },
//             { Operators.Int32Mul, JitOperatorImpls.Int32Mul },
//             { Operators.Int32Ne, JitOperatorImpls.Int32Ne },
//             { Operators.Int32Or, JitOperatorImpls.Int32Or },
//             { Operators.Int32Popcnt, JitOperatorImpls.Int32Popcnt },
//             { Operators.Int32RemS, JitOperatorImpls.Int32RemS },
//             { Operators.Int32RemU, JitOperatorImpls.Int32RemU },
//             { Operators.Int32Rotl, JitOperatorImpls.Int32Rotl },
//             { Operators.Int32Rotr, JitOperatorImpls.Int32Rotr },
//             { Operators.Int32Shl, JitOperatorImpls.Int32Shl },
//             { Operators.Int32ShrS, JitOperatorImpls.Int32ShrS },
//             { Operators.Int32ShrU, JitOperatorImpls.Int32ShrU },
//             { Operators.Int32Sub, JitOperatorImpls.Int32Sub },
//             { Operators.Int32WrapInt64, JitOperatorImpls.Int32WrapInt64 },
//             { Operators.Int32Xor, JitOperatorImpls.Int32Xor },

//             { Operators.Int64Add, JitOperatorImpls.Int64Add },
//             { Operators.Int64And, JitOperatorImpls.Int64And },
//             { Operators.Int64Clz, JitOperatorImpls.Int64Clz },
//             { Operators.Int64Ctz, JitOperatorImpls.Int64Ctz },
//             { Operators.Int64DivS, JitOperatorImpls.Int64DivS },
//             { Operators.Int64DivU, JitOperatorImpls.Int64DivU },
//             { Operators.Int64Eq, JitOperatorImpls.Int64Eq },
//             { Operators.Int64Eqz, JitOperatorImpls.Int64Eqz },
//             { Operators.Int64ExtendSInt32, JitOperatorImpls.Int64ExtendSInt32 },
//             { Operators.Int64ExtendUInt32, JitOperatorImpls.Int64ExtendUInt32 },
//             { Operators.Int64GeS, JitOperatorImpls.Int64GeS },
//             { Operators.Int64GeU, JitOperatorImpls.Int64GeU },
//             { Operators.Int64GtS, JitOperatorImpls.Int64GtS },
//             { Operators.Int64GtU, JitOperatorImpls.Int64GtU },
//             { Operators.Int64LeS, JitOperatorImpls.Int64LeS },
//             { Operators.Int64LeU, JitOperatorImpls.Int64LeU },
//             { Operators.Int64LtS, JitOperatorImpls.Int64LtS },
//             { Operators.Int64LtU, JitOperatorImpls.Int64LtU },
//             { Operators.Int64Mul, JitOperatorImpls.Int64Mul },
//             { Operators.Int64Ne, JitOperatorImpls.Int64Ne },
//             { Operators.Int64Or, JitOperatorImpls.Int64Or },
//             { Operators.Int64Popcnt, JitOperatorImpls.Int64Popcnt },
//             { Operators.Int64RemS, JitOperatorImpls.Int64RemS },
//             { Operators.Int64RemU, JitOperatorImpls.Int64RemU },
//             { Operators.Int64Rotl, JitOperatorImpls.Int64Rotl },
//             { Operators.Int64Rotr, JitOperatorImpls.Int64Rotr },
//             { Operators.Int64Shl, JitOperatorImpls.Int64Shl },
//             { Operators.Int64ShrS, JitOperatorImpls.Int64ShrS },
//             { Operators.Int64ShrU, JitOperatorImpls.Int64ShrU },
//             { Operators.Int64Sub, JitOperatorImpls.Int64Sub },
//             { Operators.Int64Xor, JitOperatorImpls.Int64Xor }
//         };
//     }

//     internal sealed class CompiledFunctionDefinition : FunctionDefinition
//     {
//         internal CompiledFunctionDefinition(FunctionType signature, MethodInfo method, bool translateExceptions)
//         {
//             this.signature = signature;
//             this.method = method;
//             this.translateExceptions = translateExceptions;
//         }

//         private FunctionType signature;
//         internal MethodInfo method;
//         private bool translateExceptions;

//         /// <inheritdoc/>
//         public override IReadOnlyList<WasmValueType> ParameterTypes => signature.ParameterTypes;

//         /// <inheritdoc/>
//         public override IReadOnlyList<WasmValueType> ReturnTypes => signature.ReturnTypes;

//         /// <inheritdoc/>
//         public override IReadOnlyList<object> Invoke(IReadOnlyList<object> arguments, uint callStackDepth = 0)
//         {
//             object result;
//             try
//             {
//                 result = method.Invoke(null, arguments.Concat(new object[] { callStackDepth }).ToArray());
//             }
//             catch (TargetInvocationException ex)
//             {
//                 var inner = ex.InnerException;
//                 if (translateExceptions && TryTranslateException(inner, out Exception translate))
//                 {
//                     throw translate;
//                 }
//                 else
//                 {
//                     throw inner;
//                 }
//             }
//             catch (Exception ex)
//             {
//                 if (translateExceptions && TryTranslateException(ex, out Exception translate))
//                 {
//                     throw translate;
//                 }
//                 else
//                 {
//                     throw;
//                 }
//             }

//             if (ReturnTypes.Count == 0)
//             {
//                 return Array.Empty<object>();
//             }
//             else if (ReturnTypes.Count == 1)
//             {
//                 return new[] { result };
//             }
//             else
//             {
//                 throw new WasmException("Cannot compile functions with more than one return value.");
//             }
//         }

//         private static bool TryTranslateException(Exception original, out Exception translated)
//         {
//             if (original.GetType() == typeof(DivideByZeroException))
//             {
//                 translated = new TrapException(original.Message, TrapException.SpecMessages.IntegerDivideByZero);
//                 return true;
//             }
//             else if (original.GetType() == typeof(OverflowException))
//             {
//                 translated = new TrapException(original.Message, TrapException.SpecMessages.IntegerOverflow);
//                 return true;
//             }
//             else
//             {
//                 translated = null;
//                 return false;
//             }
//         }
//     }
// }