public override void Generate(ItemData data) { var field = AddMethodArg(data, Method); // define a non-conflict named method that will back the given method. string name = Name; if (data.Names.Contains(name)) { name = name + "_" + (data.FID++); } data.Names.Add(name); // Define the new method. var param = BoundTo.GetParameters(); var meth = NetHelpers.CloneMethod(data.TB, name, BoundTo); ILGenerator gen = meth.GetILGenerator(); // ILuaValue[] loc = new ILuaValue[{param.length}]; LocalBuilder loc = gen.CreateArray(typeof(ILuaValue), param.Length); for (int ind = 0; ind < param.Length; ind++) { // loc[{ind}] = E.Runtime.CreateValue(arg_{ind}); gen.Emit(OpCodes.Ldloc, loc); gen.Emit(OpCodes.Ldc_I4, ind); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, data.EnvField); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod()); gen.Emit(OpCodes.Ldarg, ind + 1); if (!param[ind].ParameterType.IsClass) { gen.Emit(OpCodes.Box, param[ind].ParameterType); } gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateValue))); gen.Emit(OpCodes.Stelem, typeof(ILuaValue)); } // ILuaMultiValue args = E.Runtime.CreateMultiValue(loc); var args = gen.DeclareLocal(typeof(ILuaMultiValue)); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, data.EnvField); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod()); gen.Emit(OpCodes.Ldloc, loc); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateMultiValue))); gen.Emit(OpCodes.Stloc, args); CallFieldAndReturn(gen, BoundTo.ReturnType, field, args, data.EnvField); // link our new method to the method it's bound to. data.TB.DefineMethodOverride(meth, BoundTo); data.Methods.Add(BoundTo); }
/// <summary> /// Creates a new method that implements the given method that throws a /// NotImplementedException. /// </summary> /// <param name="data">The current data.</param> /// <param name="method">The method to implement.</param> static void StubImplement(ItemData data, MethodInfo method, string name) { // we already created this method if (data.Methods.Contains(method)) { return; } // define a no-conflict name for this method if (data.Names.Contains(name)) { name = name + "_" + (data.FID++); } data.Names.Add(name); // define the new method with the same signature as the interface. var meth = NetHelpers.CloneMethod(data.TB, name, method); ILGenerator gen = meth.GetILGenerator(); gen.ThrowException(typeof(NotImplementedException)); // link our new method to be the definition of the interface method. data.TB.DefineMethodOverride(meth, method); }
Type CreateDelegateType(MethodInfo delegateMethod) { var args = delegateMethod.GetParameters(); TypeBuilder tb = NetHelpers.DefineGlobalType("$DelegateHelper"); FieldBuilder meth = tb.DefineField("meth", typeof(ILuaValue), FieldAttributes.Private); FieldBuilder E = tb.DefineField("E", typeof(ILuaEnvironment), FieldAttributes.Private); MethodBuilder mb = NetHelpers.CloneMethod(tb, "Do", delegateMethod); ILGenerator gen = mb.GetILGenerator(); // loc = new object[{args.Length}]; LocalBuilder loc = gen.CreateArray(typeof(object), args.Length); for (int i = 0; i < args.Length; i++) { // loc[i] = arg_{i+1}; gen.Emit(OpCodes.Ldloc, loc); gen.Emit(OpCodes.Ldc_I4, i); gen.Emit(OpCodes.Ldarg, i + 1); if (args[i].ParameterType.IsValueType) { gen.Emit(OpCodes.Box, args[i].ParameterType); } gen.Emit(OpCodes.Stelem, typeof(object)); } // ILuaMultiValue methodArgs = E.Runtime.CreateMultiValueFromObj(loc); LocalBuilder methodArgs = gen.DeclareLocal(typeof(ILuaMultiValue)); gen.Emit(OpCodes.Ldfld, E); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod()); gen.Emit(OpCodes.Ldloc, loc); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateMultiValueFromObj))); gen.Emit(OpCodes.Stloc, methodArgs); // ret = this.meth.Invoke(LuaNil.Nil, false, -1, methodArgs) LocalBuilder ret = gen.DeclareLocal(typeof(ILuaMultiValue)); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, meth); gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Ldfld, typeof(LuaNil).GetField(nameof(LuaNil.Nil), BindingFlags.Static | BindingFlags.Public)); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Ldc_I4_M1); gen.Emit(OpCodes.Ldloc, methodArgs); gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.Invoke))); gen.Emit(OpCodes.Stloc, ret); // Store any by-ref parameters in the arguments for (int i = 0; i < args.Length; i++) { if (args[i].IsOut) { // arg_{i+1} = methodArgs[{i}].As<T>(); gen.Emit(OpCodes.Ldloc, methodArgs); gen.Emit(OpCodes.Ldc_I4, i); gen.Emit(OpCodes.Callvirt, typeof(ILuaMultiValue).GetMethod("get_Item")); gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.As)) .MakeGenericMethod(args[i].ParameterType)); gen.Emit(OpCodes.Starg, i + 1); } } // return ret.As<{info.Return}>(); if (delegateMethod.ReturnType != null && delegateMethod.ReturnType != typeof(void)) { gen.Emit(OpCodes.Ldloc, ret); gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.As)) .MakeGenericMethod(delegateMethod.ReturnType)); } gen.Emit(OpCodes.Ret); //// public <>_type_(ILuaEnvironment E, ILuaValue method) ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(ILuaEnvironment), typeof(ILuaValue) }); gen = cb.GetILGenerator(); // base(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0])); // this.E = E; gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Stfld, E); // this.meth = method; gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_2); gen.Emit(OpCodes.Stfld, meth); gen.Emit(OpCodes.Ret); return(tb.CreateType()); }