示例#1
0
        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);
        }
示例#2
0
        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();
        }
示例#3
0
        private Type CreateProxyClass(Type rootInterfaceType, Type interfaceType, string path)
        {
            var serviceDescription = serviceDescriptionBuilder.Build(interfaceType);

            path = path ?? serviceDescription.Name;

            var typeBuilder  = DeclareType(interfaceType);
            var fieldCache   = new ProxyClassFieldCache(typeBuilder);
            var classContext = new ProxyClassBuildingContext(rootInterfaceType, path, typeBuilder, fieldCache);

            foreach (var methodDesc in serviceDescription.Methods)
            {
                CreateMethod(classContext, path, methodDesc);
            }
            CreateConstructor(classContext, path, serviceDescription);
            return(typeBuilder.CreateType());
        }
示例#4
0
        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);
        }
示例#5
0
        private void EmitProcessAsyncWithRetval(ProxyClassBuildingContext classContext, IEmittingContext emittingContext, string parameterMethodName, IReadOnlyList <Type> genericTypeArguments, Type retvalType)
        {
            var pureRetvalType       = retvalType.GetGenericArguments().Single();
            var decodeDeferredMethod = CreateDecodeDeferredMethod(classContext, parameterMethodName, genericTypeArguments, pureRetvalType);

            if (decodeDeferredMethod.IsGenericMethodDefinition)
            {
                decodeDeferredMethod = decodeDeferredMethod.MakeGenericMethod(genericTypeArguments.ToArray());
            }
            var funcConstructor    = FuncMethods.Constructor(typeof(Task <byte[]>), pureRetvalType);
            var continueWithMethod = TaskMethods.ContinueWith(typeof(byte[]), pureRetvalType);

            var il = emittingContext.IL;

            il.Callvirt(OutgoingRequestProcessorMethods.ProcessAsync);
            il.Ldarg(0);
            il.Ldftn(decodeDeferredMethod);
            il.Newobj(funcConstructor);
            il.Callvirt(continueWithMethod);
        }
示例#6
0
        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();
        }
示例#7
0
 private static FieldBuilder CreateSubserviceField(ProxyClassBuildingContext classContext, ServiceDescription subserviceDescription, Type proxyClass)
 {
     return(classContext.Builder.DefineField("_" + subserviceDescription.Name, proxyClass,
                                             FieldAttributes.Private | FieldAttributes.InitOnly));
 }