private static void CreateMethodDelegate(HandlerClassBuildingContext classContext) { const int implementationArgIndex = 1; const int dataArgIndex = 2; const int offsetArgIndex = 3; var methodBuilder = classContext.Builder.DefineMethod("Handle", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, typeof(Task<byte[]>), new[] { typeof(object), typeof(byte[]), typeof(int) }); var il = new MyILGenerator(methodBuilder.GetILGenerator()); var emittingContext = new HandlerMethodEmittingContext(il, classContext.Fields); var serviceDescriptionChain = classContext.ServiceDescriptionChain; il.Ldarg(implementationArgIndex); // stack_0 = (TServiceImplementation) arg_1 il.Castclass(serviceDescriptionChain.First().Type); for (int i = 0; i < serviceDescriptionChain.Count - 1; i++) { var current = serviceDescriptionChain[i]; var next = serviceDescriptionChain[i + 1]; il.Callvirt(current.Type.GetProperty(next.Name).GetGetMethod()); // stack_0 = stack_0.Property } var methodDescription = classContext.MethodDescription; var genericArgumentMap = methodDescription.GenericParameters .Zip(classContext.GenericTypeParameterBuilders, (p, a) => new KeyValuePair<string, Type>(p.Name, a)) .ToDictionary(x => x.Key, x => x.Value); var parameterDescriptions = methodDescription.Parameters.Select(x => x.DeepSubstituteGenerics(genericArgumentMap)).ToArray(); var retvalType = methodDescription.ReturnType.DeepSubstituteGenerics(genericArgumentMap); var allParameterCodecs = parameterDescriptions.Select((x, i) => new HandlerParameterCodec(emittingContext, x)).ToArray(); var requestParameterCodecs = allParameterCodecs.Where(x => x.IsRequestParameter).ToArray(); var responseParameterCodecs = allParameterCodecs.Where(x => x.IsResponseParameter).ToArray(); if (requestParameterCodecs.Any()) { il.Ldarg(dataArgIndex); // remainingBytes = dataArray.Length - offset il.Ldlen(); il.Ldarg(offsetArgIndex); il.Sub(); il.Stloc(emittingContext.RemainingBytesVar); var pinnedVar = il.PinArray(typeof(byte), 2); // var pinned dataPointer = pin(dataArray) il.Ldloc(pinnedVar); // data = dataPointer + offset il.Ldarg(offsetArgIndex); il.Add(); il.Stloc(emittingContext.DataPointerVar); } foreach (var codec in allParameterCodecs) codec.EmitDecodeAndPrepare(); // ReSharper disable CoVariantArrayConversion var resolvedMethodInfo = classContext.GenericTypeParameterBuilders.Any() ? methodDescription.MethodInfo.MakeGenericMethod(classContext.GenericTypeParameterBuilders) : methodDescription.MethodInfo; il.Callvirt(resolvedMethodInfo); // stack_0 = stack_0.Method(stack_1, stack_2, ...) // ReSharper restore CoVariantArrayConversion switch (methodDescription.RemotingType) { case MethodRemotingType.Direct: EmitProcessAndEncodeDirect(emittingContext, responseParameterCodecs, retvalType); break; case MethodRemotingType.AsyncVoid: EmitProcessAndEncodeAsyncVoid(emittingContext); break; case MethodRemotingType.AsyncWithRetval: EmitProcessAndEncodeAsyncWithRetval(classContext, emittingContext, retvalType.GetGenericArguments()[0]); break; default: throw new ArgumentOutOfRangeException(); } il.Ret(); }
protected override void EmitLoadCount(MyILGenerator il, Action<MyILGenerator> emitLoad) { emitLoad(il); il.Ldlen(); il.Conv_I4(); }