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 static void CreateConstructor(HandlerClassBuildingContext classContext) { const int thisArgIndex = 0; const int codecContainerArgIndex = 1; var constructorBuilder = classContext.Builder.DefineConstructor( MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] { typeof(ICodecContainer) }); var baseConstructor = typeof(object).GetConstructor(Type.EmptyTypes); var il = new MyILGenerator(constructorBuilder.GetILGenerator()); il.Ldarg(thisArgIndex); il.Call(baseConstructor); il.Ldarg(thisArgIndex); il.Ldarg(codecContainerArgIndex); il.Stfld(classContext.Fields.CodecContainer); foreach (var manualCodecField in classContext.Fields.GetAllManualCodecFields()) { il.Ldarg(thisArgIndex); il.Ldarg(codecContainerArgIndex); il.Call(CodecContainerMethods.GetManualCodecFor(manualCodecField.FieldType.GenericTypeArguments[0])); il.Stfld(manualCodecField); } il.Ret(); }
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 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 Func <Type, string, string, Exception> CreateExceptionCreator() { var dynamicMethod = new DynamicMethod( "__srpc__CreateException", typeof(Exception), new[] { typeof(Type), typeof(string), typeof(string) }, Assembly.GetExecutingAssembly().ManifestModule, true); var il = new MyILGenerator(dynamicMethod.GetILGenerator()); il.Ldarg(0); // stack_0 = (Exception)FormatterServices.GetUninitializedObject(typeof(T)) il.Call(GetUninitializedObject); il.Castclass(typeof(Exception)); il.Dup(); // stack_0.Init() il.Call(InitMethod); il.Dup(); // stack_0._message = message il.Ldarg(1); il.Stfld(MessageField); il.Dup(); // stack_0._message = message il.Ldarg(2); il.Stfld(RemoteStackTraceStringField); il.Ret(); return((Func <Type, string, string, Exception>)dynamicMethod.CreateDelegate(typeof(Func <Type, string, string, Exception>))); }
private static MethodBuilder CreateEncodeDeferredMethod(HandlerClassBuildingContext classContext, Type pureRetvalType) { const int taskArgIndex = 1; var methodBuilder = classContext.Builder.DefineMethod("EncodeDeferred", MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot, typeof(byte[]), new[] { typeof(Task <>).MakeGenericType(pureRetvalType) }); var il = new MyILGenerator(methodBuilder.GetILGenerator()); var emittingContext = new HandlerMethodEmittingContext(il, classContext.Fields); il.Ldarg(taskArgIndex); il.Call(TaskMethods.GetResult(pureRetvalType)); EmitEncodeDirect(emittingContext, new HandlerParameterCodec[0], pureRetvalType); il.Ret(); return(methodBuilder); }
private static void CreateSubserviceProperty(ProxyClassBuildingContext classContext, ServiceDescription subserviceDescription, FieldBuilder fieldBuilder) { var methodBuilder = classContext.Builder.DefineMethod("get_" + subserviceDescription.Name, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.NewSlot | MethodAttributes.Virtual, subserviceDescription.Type, Type.EmptyTypes); methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed); var il = new MyILGenerator(methodBuilder.GetILGenerator()); il.Ldarg(0); il.Ldfld(fieldBuilder); il.Ret(); var propertyBuilder = classContext.Builder.DefineProperty(subserviceDescription.Name, PropertyAttributes.None, subserviceDescription.Type, Type.EmptyTypes); propertyBuilder.SetGetMethod(methodBuilder); }
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(); }
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(); }
private void CreateConstructor(ProxyClassBuildingContext classContext, string path, ServiceDescription serviceDescription) { const int thisArgIndex = 0; const int processorArgIndex = 1; const int scopeArgIndex = 2; const int timeoutSettingsArgIndex = 3; const int codecContainerArgIndex = 4; var constructorBuilder = classContext.Builder.DefineConstructor( MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, ConstructorParameterTypes); var baseConstructor = typeof(object).GetConstructor(Type.EmptyTypes); var il = new MyILGenerator(constructorBuilder.GetILGenerator()); il.Ldarg(thisArgIndex); il.Call(baseConstructor); il.Ldarg(thisArgIndex); il.Ldarg(processorArgIndex); il.Stfld(classContext.Fields.Processor); il.Ldarg(thisArgIndex); il.Ldarg(scopeArgIndex); il.Stfld(classContext.Fields.Scope); il.Ldarg(thisArgIndex); il.Ldarg(timeoutSettingsArgIndex); il.Stfld(classContext.Fields.TimeoutSettings); il.Ldarg(thisArgIndex); il.Ldarg(codecContainerArgIndex); il.Stfld(classContext.Fields.CodecContainer); foreach (var manualCodecField in classContext.Fields.GetAllManualCodecFields()) { var type = manualCodecField.FieldType.GenericTypeArguments[0]; ValidateManualCodecType(type); il.Ldarg(thisArgIndex); il.Ldarg(codecContainerArgIndex); il.Call(CodecContainerMethods.GetManualCodecFor(type)); il.Stfld(manualCodecField); } foreach (var subserviceDesc in serviceDescription.Subservices) { var proxyClass = CreateProxyClass(classContext.InterfaceType, subserviceDesc.Type, path + "/" + subserviceDesc.Name); var fieldBuilder = CreateSubserviceField(classContext, subserviceDesc, proxyClass); CreateSubserviceProperty(classContext, subserviceDesc, fieldBuilder); il.Ldarg(thisArgIndex); il.Ldarg(processorArgIndex); il.Ldarg(scopeArgIndex); il.Ldarg(timeoutSettingsArgIndex); il.Ldarg(codecContainerArgIndex); il.Newobj(proxyClass.GetConstructor(ConstructorParameterTypes)); il.Stfld(fieldBuilder); } il.Ret(); }