private DynamicMethod EmitDecode(bool doNoCheckBounds) { const int codecContainerArgIndex = 0; const int dataArgIndex = 1; const int remainingBytesArgIndex = 2; var dynamicMethod = new DynamicMethod("_decode_manual_" + type.FullName + (doNoCheckBounds ? "_dncb_" : ""), type, new[] { typeof(ICodecContainer), typeof(byte *).MakeByRefType(), typeof(int).MakeByRefType() }, Assembly.GetExecutingAssembly().ManifestModule, true); var il = new MyILGenerator(dynamicMethod.GetILGenerator()); var context = new ManualCodecEmittingContext(il, codecContainerArgIndex); il.Ldarg(dataArgIndex); il.Ldind_I(); il.Stloc(context.DataPointerVar); il.Ldarg(remainingBytesArgIndex); il.Ldind_I4(); il.Stloc(context.RemainingBytesVar); emittingCodec.EmitDecode(context, doNoCheckBounds); il.Ldarg(dataArgIndex); il.Ldloc(context.DataPointerVar); il.Stind_I(); il.Ldarg(remainingBytesArgIndex); il.Ldloc(context.RemainingBytesVar); il.Stind_I4(); il.Ret(); return(dynamicMethod); }
private DynamicMethod EmitEncode() { const int codecContainerArgIndex = 0; const int dataArgIndex = 1; const int valueArgIndex = 2; var dynamicMethod = new DynamicMethod("_encode_manual_" + type.FullName, typeof(void), new[] { typeof(ICodecContainer), typeof(byte *).MakeByRefType(), type }, Assembly.GetExecutingAssembly().ManifestModule, true); var il = new MyILGenerator(dynamicMethod.GetILGenerator()); var context = new ManualCodecEmittingContext(il, codecContainerArgIndex); il.Ldarg(dataArgIndex); il.Ldind_I(); il.Stloc(context.DataPointerVar); emittingCodec.EmitEncode(context, valueArgIndex); il.Ldarg(dataArgIndex); il.Ldloc(context.DataPointerVar); il.Stind_I(); il.Ret(); return(dynamicMethod); }
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 EmitCreateCollection(MyILGenerator il, LocalBuilder lengthVar) { il.Ldloc(lengthVar); il.Newarr(ElementType); }
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(); }