private static void EmitParameters(ILGenerator ilGen, Type[] parameterTypes) { //Take the parameters passed as arguments and convert them to an array of RpcMessage.Parameters. if (parameterTypes.Length > 0) { ilGen.Emit(OpCodes.Ldc_I4, parameterTypes.Length); ilGen.Emit(OpCodes.Newarr, typeof(RpcMessage.Parameter)); for (int i = 0; i < parameterTypes.Length; ++i) { ilGen.Emit(OpCodes.Dup); //for array store ilGen.Emit(OpCodes.Ldc_I4, i); //index for array store ilGen.Emit(OpCodes.Ldarg, (short)i + 1); //argument for ParameterConverter function ThunkHelpers.EmitParameterToMessage(ilGen, parameterTypes[i]); ilGen.Emit(OpCodes.Stelem_Ref); //array store result from ParameterConverter } } else { ilGen.Emit(OpCodes.Ldnull); } }
public static Delegate BuildThunk(RpcMethodDescriptor method) { var dynMethod = new DynamicMethod("ServiceThunk", typeof(void), new[] { typeof(object), typeof(IList <RpcMessage.Parameter>), typeof(RpcMessage.Result) }, typeof(ServiceThunkBuilder).Module); ILGenerator ilGen = dynMethod.GetILGenerator(); //verify number of parameters ilGen.Emit(OpCodes.Ldarg_1); //push IList<RpcMessage.Parameter> ilGen.Emit(OpCodes.Ldc_I4, method.ParameterTypes.Length); //push number of expected parameters ilGen.Emit(OpCodes.Ldarg_2); //push RpcMessage.Result ilGen.Emit(OpCodes.Call, typeof(ServiceThunkHelpers).GetMethod("VerifyParameterCount")); Label paramVerifyLabel = ilGen.DefineLabel(); ilGen.Emit(OpCodes.Brtrue, paramVerifyLabel); ilGen.Emit(OpCodes.Ret); ilGen.MarkLabel(paramVerifyLabel); //load the RpcMessage.Result to the stack, for the call to set the result if (method.ReturnType != typeof(void)) { ilGen.Emit(OpCodes.Ldarg_2); } //load the service instance to the stack, for the call to the service instance ilGen.Emit(OpCodes.Ldarg_0); //load the service call parameters to the stack, if they are the wrong type then an error is stored //in the result message and we return early MethodInfo paramIndexer = typeof(IList <RpcMessage.Parameter>).GetProperty("Item").GetGetMethod(); for (int i = 0; i < method.ParameterTypes.Length; ++i) { Type paramType = method.ParameterTypes[i]; //get RpcMessage.Parameter by calling IList indexer ilGen.Emit(OpCodes.Ldarg_1); ilGen.Emit(OpCodes.Ldc_I4, i); ilGen.Emit(OpCodes.Callvirt, paramIndexer); ilGen.Emit(OpCodes.Ldarg_2); //push RpcMessage.Result LocalBuilder paramLocal = ilGen.DeclareLocal(paramType); ilGen.Emit(OpCodes.Ldloca, (short)paramLocal.LocalIndex); //push ref to result local EmitParameter(ilGen, paramType); Label continueLabel = ilGen.DefineLabel(); ilGen.Emit(OpCodes.Brtrue, continueLabel); //success, continue with next parameter //failed, stack cleanup for (int j = 0; j < i; ++j) { ilGen.Emit(OpCodes.Pop); //pop previous parameters } ilGen.Emit(OpCodes.Pop); //pop service instance if (method.ReturnType != typeof(void)) { ilGen.Emit(OpCodes.Pop); //pop RpcMessage.Result } ilGen.Emit(OpCodes.Ret); ilGen.MarkLabel(continueLabel); //now push the actual parameter ready for the actual call ilGen.Emit(OpCodes.Ldloc, paramLocal.LocalIndex); } //now call the actual service instance method ilGen.Emit(OpCodes.Callvirt, method.SyncCallMethod); //get the return value, storing it in the result message. We know the type, no need for any error //checking if (method.ReturnType != typeof(void)) { //check if result is null ilGen.Emit(OpCodes.Ldarg_2); ilGen.Emit(OpCodes.Ldnull); Label nullReturnLabel = ilGen.DefineLabel(); ilGen.Emit(OpCodes.Beq, nullReturnLabel); //convert return value to a message and store it in the result message ThunkHelpers.EmitParameterToMessage(ilGen, method.ReturnType); ilGen.Emit(OpCodes.Call, typeof(RpcMessage.Result).GetProperty("CallResult").GetSetMethod()); ilGen.Emit(OpCodes.Ret); ilGen.MarkLabel(nullReturnLabel); ilGen.Emit(OpCodes.Pop); //pop return value ilGen.Emit(OpCodes.Pop); //pop result message } ilGen.Emit(OpCodes.Ret); return(dynMethod.CreateDelegate(typeof(RpcServer.MethodDelegate))); }