private static void EmitForwardingMethod(TypeBuilder proxyTB,
bool isStatic,
FieldBuilder regularFB,
FieldBuilder overloadFB,
MethodSignature sig,
ElseGenDelegate elseGen)
{
MethodAttributes attributes;
CallingConventions conventions;
if (isStatic)
{
attributes = MethodAttributes.Public | MethodAttributes.Static;
conventions = CallingConventions.Standard;
}
else
{
attributes = MethodAttributes.Public | MethodAttributes.Virtual;
conventions = CallingConventions.HasThis;
}
MethodBuilder mb = proxyTB.DefineMethod(sig.Name, attributes, conventions, sig.ReturnType, sig.ParamTypes);
ILGen gen = new ILGen(mb.GetILGenerator());
Label foundLabel = gen.DefineLabel();
Label elseLabel = gen.DefineLabel();
Label endLabel = gen.DefineLabel();
if (sig.ParamTypes.Length > 18)
elseGen(gen);
else
{
if (overloadFB != null)
{
EmitGetVar(gen, overloadFB);
gen.Emit(OpCodes.Dup);
gen.Emit(OpCodes.Brtrue_S, foundLabel);
gen.Emit(OpCodes.Pop);
}
EmitGetVar(gen, regularFB);
gen.Emit(OpCodes.Dup);
gen.Emit(OpCodes.Brfalse_S, elseLabel);
if (overloadFB != null)
gen.MarkLabel(foundLabel);
gen.Emit(OpCodes.Castclass, typeof(IFn));
if (!isStatic)
gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0);
for (int i = 0; i < sig.ParamTypes.Length; i++)
{
gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1);
if (sig.ParamTypes[i].IsValueType)
gen.Emit(OpCodes.Box, sig.ParamTypes[i]);
}
gen.EmitCall(Compiler.Methods_IFn_invoke[sig.ParamTypes.Length + (isStatic ? 0 : 1)]);
//gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[sig.ParamTypes.Length + (isStatic ? 0 : 1)]);
if (sig.ReturnType == typeof(void))
gen.Emit(OpCodes.Pop);
else if (sig.ReturnType.IsValueType)
gen.Emit(OpCodes.Unbox_Any,sig.ReturnType);
gen.Emit(OpCodes.Br_S, endLabel);
gen.MarkLabel(elseLabel);
gen.Emit(OpCodes.Pop);
elseGen(gen);
gen.MarkLabel(endLabel);
gen.Emit(OpCodes.Ret);
}
}