private MethodInfo CreateDecodeDeferredMethod(ProxyClassBuildingContext classContext, string parentMethodName, IReadOnlyList <Type> genericTypeArguments, Type pureRetvalType) { var methodBuilder = classContext.Builder.DefineMethod("__rpc_decode_deferred_" + parentMethodName, MethodAttributes.Private | MethodAttributes.HideBySig); var genericTypeParameterBuilders = genericTypeArguments.Any() ? methodBuilder.DefineGenericParameters(genericTypeArguments.Select(x => x.Name).ToArray()) : new GenericTypeParameterBuilder[0]; var genericArgumentMap = genericTypeParameterBuilders.ToDictionary(x => x.Name, x => (Type)x); var retvalType = pureRetvalType.DeepSubstituteGenerics(genericArgumentMap); methodBuilder.SetParameters(DecodeDeferredParameterTypes); methodBuilder.SetReturnType(retvalType); methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed); var il = new MyILGenerator(methodBuilder.GetILGenerator()); var emittingContext = new ProxyMethodEmittingContext(il, classContext.Fields); il.Ldarg(1); il.Call(TaskMethods.GetResult(typeof(byte[]))); EmitPrepareToDecode(emittingContext); var retvalCodec = new ProxyMethodRetvalCodec(retvalType); retvalCodec.EmitDecode(emittingContext); il.Ret(); return(methodBuilder); }
private void CreateMethod(ProxyClassBuildingContext classContext, string path, MethodDescription methodDesc) { var methodBuilder = classContext.Builder.DefineMethod(methodDesc.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual); var genericTypeParameterBuilders = methodDesc.GenericParameters.Any() ? methodBuilder.DefineGenericParameters(methodDesc.GenericParameters.Select(x => x.Name).ToArray()) : new GenericTypeParameterBuilder[0]; var genericTypeParameterCodecs = genericTypeParameterBuilders.Select(x => new ProxyMethodGenericArgumentCodec(x)).ToArray(); var genericArgumentMap = genericTypeParameterBuilders.ToDictionary(x => x.Name, x => (Type)x); var parameterDescriptions = methodDesc.Parameters.Select(x => x.DeepSubstituteGenerics(genericArgumentMap)).ToArray(); var parameterTypesAdjustedForRefs = parameterDescriptions.Select(x => x.Way == MethodParameterWay.Val ? x.Type : x.Type.MakeByRefType()).ToArray(); var allParameterCodecs = parameterDescriptions.Select(x => new ProxyMethodParameterCodec(x)).ToArray(); var retvalType = methodDesc.ReturnType.DeepSubstituteGenerics(genericArgumentMap); methodBuilder.SetParameters(parameterTypesAdjustedForRefs); methodBuilder.SetReturnType(retvalType); methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed); var il = new MyILGenerator(methodBuilder.GetILGenerator()); var emittingContext = new ProxyMethodEmittingContext(il, classContext.Fields); var requestDataArrayVar = il.DeclareLocal(typeof(byte[])); // byte[] dataArray var requestParametersCodecs = allParameterCodecs.Where(x => x.IsRequestParameter).ToArray(); if (requestParametersCodecs.Any() || genericTypeParameterBuilders.Any()) { bool haveSizeOnStack = false; foreach (var codec in genericTypeParameterCodecs) { codec.EmitCalculateSize(emittingContext); // stack_0 += CalculateSize(T_i) EmitAddIf(il, ref haveSizeOnStack); } foreach (var parameter in requestParametersCodecs) { parameter.EmitCalculateSize(emittingContext); // stack_0 += CalculateSize(arg_i) EmitAddIf(il, ref haveSizeOnStack); } il.Newarr(typeof(byte)); // dataArray = new byte[stack_0] il.Stloc(requestDataArrayVar); var pinnedVar = il.PinArray(typeof(byte), requestDataArrayVar); // var pinned dataPointer = pin(dataArray) il.Ldloc(pinnedVar); // data = dataPointer il.Stloc(emittingContext.DataPointerVar); foreach (var codec in genericTypeParameterCodecs) { codec.EmitEncode(emittingContext); // Encode(T_i, data) } foreach (var codec in requestParametersCodecs) { codec.EmitEncode(emittingContext); // Encode(arg_i, data) } } else { il.Ldnull(); // dataArray = null il.Stloc(requestDataArrayVar); } il.Ldarg(0); // stack_0 = methodCallProcessor il.Ldfld(classContext.Fields.Processor); il.Ldtoken(classContext.InterfaceType); // stack_1 = typeof(T) il.Call(TypeMethods.GetTypeFromHandle); il.Ldstr(string.Format("{0}/{1}", path, methodDesc.Name)); // stack_2 = SuperServicePath/ServiceName/MethodName il.Ldarg(0); // stack_3 = scope il.Ldfld(classContext.Fields.Scope); il.Ldloc(requestDataArrayVar); // stack_4 = dataArray il.Ldarg(0); // stack_5 = timeoutSettings il.Ldfld(classContext.Fields.TimeoutSettings); var responseParameterCodecs = allParameterCodecs.Where(x => x.IsResponseParameter).ToArray(); if (responseParameterCodecs.Any() && methodDesc.RemotingType != MethodRemotingType.Direct) { throw new ArgumentException(string.Format("Error processing {0} method: only direct methods can have Ref or Out parameters", path)); } switch (methodDesc.RemotingType) { case MethodRemotingType.Direct: EmitProcessDirect(emittingContext, responseParameterCodecs, retvalType); break; case MethodRemotingType.AsyncVoid: EmitProcessAsyncVoid(il); break; case MethodRemotingType.AsyncWithRetval: EmitProcessAsyncWithRetval(classContext, emittingContext, methodDesc.Name, genericTypeParameterBuilders, retvalType); break; default: throw new ArgumentOutOfRangeException(); } il.Ret(); }