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 static void EmitProcessAndEncodeAsyncWithRetval(HandlerClassBuildingContext classContext, IEmittingContext emittingContext, Type pureRetvalType) { var encodeDeferredMethod = CreateEncodeDeferredMethod(classContext, pureRetvalType); var continueWithMethod = TaskMethods.ContinueWith(pureRetvalType, typeof(byte[])); var il = emittingContext.IL; il.Ldarg(0); il.Ldftn(encodeDeferredMethod); il.Newobj(FuncMethods.Constructor(typeof(Task <>).MakeGenericType(pureRetvalType), typeof(byte[]))); il.Callvirt(continueWithMethod); }
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 Type CreateType(IReadOnlyList <ServiceDescription> serviceDescriptionChain, MethodDescription methodDescription, ServicePath path) { int disambiguator = Interlocked.Increment(ref classNameDisambiguator); var typeBuilder = moduleBuilder.DefineType("__rpc_handler_" + string.Join(".", path) + "_" + disambiguator, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class, typeof(object), new[] { typeof(IHandler) }); var genericTypeParameterBuilders = methodDescription.GenericParameters.Any() ? typeBuilder.DefineGenericParameters(methodDescription.GenericParameters.Select(x => x.Name).ToArray()) : new GenericTypeParameterBuilder[0]; var fieldCache = new HandlerClassFieldCache(typeBuilder); var classContext = new HandlerClassBuildingContext(serviceDescriptionChain, methodDescription, typeBuilder, genericTypeParameterBuilders, fieldCache); CreateMethodDelegate(classContext); CreateConstructor(classContext); return(typeBuilder.CreateType()); }
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 Type CreateType(IReadOnlyList<ServiceDescription> serviceDescriptionChain, MethodDescription methodDescription, ServicePath path) { int disambiguator = Interlocked.Increment(ref classNameDisambiguator); var typeBuilder = moduleBuilder.DefineType("__rpc_handler_" + string.Join(".", path) + "_" + disambiguator, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class, typeof(object), new[] { typeof(IHandler) }); var genericTypeParameterBuilders = methodDescription.GenericParameters.Any() ? typeBuilder.DefineGenericParameters(methodDescription.GenericParameters.Select(x => x.Name).ToArray()) : new GenericTypeParameterBuilder[0]; var fieldCache = new HandlerClassFieldCache(typeBuilder); var classContext = new HandlerClassBuildingContext(serviceDescriptionChain, methodDescription, typeBuilder, genericTypeParameterBuilders, fieldCache); CreateMethodDelegate(classContext); CreateConstructor(classContext); return typeBuilder.CreateType(); }
private static void EmitProcessAndEncodeAsyncWithRetval(HandlerClassBuildingContext classContext, IEmittingContext emittingContext, Type pureRetvalType) { var encodeDeferredMethod = CreateEncodeDeferredMethod(classContext, pureRetvalType); var continueWithMethod = TaskMethods.ContinueWith(pureRetvalType, typeof(byte[])); var il = emittingContext.IL; il.Ldarg(0); il.Ldftn(encodeDeferredMethod); il.Newobj(FuncMethods.Constructor(typeof(Task<>).MakeGenericType(pureRetvalType), typeof(byte[]))); il.Callvirt(continueWithMethod); }
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 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; }