private void EmitSetHandlerForMethod(MethodInfoMapping miMapping, ILGenerator ctIl) { var newMethod = CreateHandlerMethod(miMapping); ctIl.Emit(OpCodes.Ldarg_0); ctIl.Emit(OpCodes.Ldfld, templateType.GetField("handlers", BindingFlags.Instance | BindingFlags.NonPublic)); ctIl.Emit(OpCodes.Ldstr, miMapping.PublicName); ctIl.Emit(OpCodes.Ldarg_0); ctIl.Emit(OpCodes.Ldftn, newMethod); ctIl.Emit(OpCodes.Newobj, typeof(Action <FramedClient, long, MemoryStream>).GetConstructor(new[] { typeof(object), typeof(IntPtr) })); ctIl.EmitCall(OpCodes.Call, typeof(Dictionary <string, Action <FramedClient, long, MemoryStream> >).GetMethod("set_Item"), null); }
private void DefineMessageTypeForActorMethodParams(MethodInfoMapping miMapping) { var messageTypeName = miMapping.PublicName + "Message"; var typeBuilder = this.moduleBuilder.DefineType("Messages." + messageTypeName, TypeAttributes.Public); // Empty ctor typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.HideBySig); // Type attributes var protoContractCtor = typeof(ProtoBuf.ProtoContractAttribute).GetConstructor(Type.EmptyTypes); typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(protoContractCtor, new object[0])); // Properties var miParams = miMapping.Info.GetParameters() .ToArray(); // Index used for proto member attribute. Must start with 1. for (int idx = 0, i = 1; idx < miParams.Length; ++idx) { var p = miParams[idx]; // Ommit parameter in message if it is a IActorSession and is on first place if (p.ParameterType == typeof(IActorSession) && idx == 0) { continue; } var fb = typeBuilder.DefineField(p.Name, p.ParameterType, FieldAttributes.Public); var protoMemberCtor = typeof(ProtoBuf.ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); fb.SetCustomAttribute(new CustomAttributeBuilder(protoMemberCtor, new object[] { i })); ++i; } var createdType = typeBuilder.CreateType(); this.messageParamTypes[miMapping.PublicName] = createdType; }
private void DefineMessageTypeForActorMethodParams(MethodInfoMapping miMapping) { var messageTypeName = miMapping.PublicName + "Message"; var typeBuilder = this.moduleBuilder.DefineType("Messages." + messageTypeName, TypeAttributes.Public); // Empty ctor typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.HideBySig); // Type attributes var protoContractCtor = typeof(ProtoBuf.ProtoContractAttribute).GetConstructor(Type.EmptyTypes); typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(protoContractCtor, new object[0])); // Properties var miParams = miMapping.Info.GetParameters() .ToArray(); // Index used for proto member attribute. Must start with 1. for (int idx = 0, i = 1; idx < miParams.Length; ++idx) { var p = miParams[idx]; // Ommit parameter in message if it is a IActorSession and is on first place if (p.ParameterType == typeof(IActorSession) && idx == 0) continue; var fb = typeBuilder.DefineField(p.Name, p.ParameterType, FieldAttributes.Public); var protoMemberCtor = typeof(ProtoBuf.ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); fb.SetCustomAttribute(new CustomAttributeBuilder(protoMemberCtor, new object[] { i })); ++i; } var createdType = typeBuilder.CreateType(); this.messageParamTypes[miMapping.PublicName] = createdType; }
private void DefineMessageTypeForActorMethodReturn(MethodInfoMapping miMapping) { Type returnType = null; var returnTypeTask = miMapping.Info.ReturnType; bool isEmptyReply = returnTypeTask == typeof(Task); if (returnTypeTask == typeof(Task)) returnType = typeof(System.Reactive.Unit); else { var genArgs = returnTypeTask.GetGenericArguments(); if (genArgs.Length != 1) throw new InvalidOperationException("Return type of a method must be Task<T>"); returnType = genArgs[0]; } var messageTypeName = miMapping.PublicName + "MessageReply"; var replyInterfaceType = typeof(IReplyMessage<>).MakeGenericType(returnType); var typeBuilder = this.moduleBuilder.DefineType("Messages." + messageTypeName, TypeAttributes.Public, null, new[] { replyInterfaceType }); // Empty ctor var cb = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, Type.EmptyTypes); var cbIl = cb.GetILGenerator(); cbIl.Emit(OpCodes.Ret); // Type attributes var protoContractCtor = typeof(ProtoBuf.ProtoContractAttribute).GetConstructor(Type.EmptyTypes); typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(protoContractCtor, new object[0])); var protoMemberCtor = typeof(ProtoBuf.ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); var errfb = typeBuilder.DefineField("$ErrorMessage", typeof(string), FieldAttributes.Public); errfb.SetCustomAttribute(new CustomAttributeBuilder(protoMemberCtor, new object[] { 1 })); FieldBuilder fb = null; if (!isEmptyReply) { fb = typeBuilder.DefineField("@Return", returnType, FieldAttributes.Public); fb.SetCustomAttribute(new CustomAttributeBuilder(protoMemberCtor, new object[] { 2 })); } //GetResult() var getResultMb = typeBuilder.DefineMethod("GetResult", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, returnType, Type.EmptyTypes); var gril = getResultMb.GetILGenerator(); var isOKLabel = gril.DefineLabel(); gril.Emit(OpCodes.Ldarg_0); gril.Emit(OpCodes.Ldfld, errfb); gril.Emit(OpCodes.Ldnull); gril.Emit(OpCodes.Ceq); //if($ErrorMessage != null) { gril.Emit(OpCodes.Brtrue_S, isOKLabel); // throw new Exception($ErrorMessage); gril.Emit(OpCodes.Ldarg_0); gril.Emit(OpCodes.Ldfld, errfb); gril.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new[] { typeof(string) })); gril.Emit(OpCodes.Throw); // } else { // return @Return; } gril.MarkLabel(isOKLabel); if (!isEmptyReply) { gril.Emit(OpCodes.Ldarg_0); gril.Emit(OpCodes.Ldfld, fb); } else { gril.EmitCall(OpCodes.Call, typeof(System.Reactive.Unit).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetGetMethod(), null); } gril.Emit(OpCodes.Ret); //SetResult var setResultMb = typeBuilder.DefineMethod("SetResult", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(void), new[] { returnType }); var sril = setResultMb.GetILGenerator(); if (!isEmptyReply) { sril.Emit(OpCodes.Ldarg_0); sril.Emit(OpCodes.Ldarg_1); sril.Emit(OpCodes.Stfld, fb); } sril.Emit(OpCodes.Ret); //SetError var setErrorMb = typeBuilder.DefineMethod("SetError", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(void), new[] { typeof(string) }); var seil = setErrorMb.GetILGenerator(); seil.Emit(OpCodes.Ldarg_0); seil.Emit(OpCodes.Ldarg_1); seil.Emit(OpCodes.Stfld, errfb); seil.Emit(OpCodes.Ret); var createdType = typeBuilder.CreateType(); this.messageReturnTypes[miMapping.PublicName] = createdType; }
private void EmitSetHandlerForMethod(MethodInfoMapping miMapping, ILGenerator ctIl) { var newMethod = CreateHandlerMethod(miMapping); ctIl.Emit(OpCodes.Ldarg_0); ctIl.Emit(OpCodes.Ldfld, templateType.GetField("handlers", BindingFlags.Instance | BindingFlags.NonPublic)); ctIl.Emit(OpCodes.Ldstr, miMapping.PublicName); ctIl.Emit(OpCodes.Ldarg_0); ctIl.Emit(OpCodes.Ldftn, newMethod); ctIl.Emit(OpCodes.Newobj, typeof (Action<FramedClient, long, MemoryStream>).GetConstructor(new[] {typeof (object), typeof (IntPtr)})); ctIl.EmitCall(OpCodes.Call, typeof (Dictionary<string, Action<FramedClient, long, MemoryStream>>).GetMethod("set_Item"), null); }
private MethodBuilder CreateHandlerMethod(MethodInfoMapping miMapping) { var sendMethodTaskRet = miMapping.Info.ReturnType; bool isNoParamTask = sendMethodTaskRet == typeof(Task); var sendMethodInnerRet = sendMethodTaskRet == typeof(Task) ? typeof(System.Reactive.Unit) : sendMethodTaskRet.GetGenericArguments()[0]; var mb = actorImplBuilder.DefineMethod(miMapping.PublicName + "Handler", MethodAttributes.Private | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(void), new[] { typeof(FramedClient), typeof(long), typeof(MemoryStream) }); Type messageType = moduleBuilder.GetType("Messages." + miMapping.PublicName + "Message"); Type replyMessageType = moduleBuilder.GetType("Messages." + miMapping.PublicName + "MessageReply"); var desMethod = typeof(IStacksSerializer).GetMethod("Deserialize").MakeGenericMethod(messageType); var il = mb.GetILGenerator(); var messageLocal = il.DeclareLocal(messageType); var endLabel = il.DefineLabel(); // try { il.BeginExceptionBlock(); //var msg = base.serializer.Deserialize<P>(ms); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, templateType.GetField("serializer", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Callvirt, desMethod, null); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, templateType.GetField("actorImplementation", BindingFlags.Instance | BindingFlags.NonPublic)); //actorImplementation.[methodName](params); var sendParams = miMapping.Info.GetParameters(); // If first parameter is IActorSession, load session for dictionary and // place it on stack as first parameter. if (sendParams.Length >= 1 && sendParams[0].ParameterType == typeof(IActorSession)) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, templateType.GetField("actorSessions", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Ldarg_1); //FramedClient used as a key for session cache il.EmitCall(OpCodes.Call, typeof(Dictionary<IFramedClient, IActorSession>).GetMethod("get_Item"), null); } for (int idx = 0, i = 1; idx < sendParams.Length; ++idx) { // Ommit first parameter if it is an IActorSession if (idx == 0 && sendParams[0].ParameterType == typeof(IActorSession)) continue; var field = GetFieldInfoFromProtobufMessage(messageType, i); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldfld, field); ++i; } il.EmitCall(OpCodes.Callvirt, miMapping.InterfaceInfo, null); } il.Emit(OpCodes.Newobj, replyMessageType.GetConstructor(Type.EmptyTypes)); if (isNoParamTask) { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponseNoResult", BindingFlags.Instance | BindingFlags.NonPublic), null); } else { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponse", BindingFlags.Instance | BindingFlags.NonPublic) .MakeGenericMethod(sendMethodInnerRet), null); } // } catch (Exception e) { il.BeginCatchBlock(typeof(Exception)); var excMsgLocal = il.DeclareLocal(typeof(string)); var replyMsgLocal = il.DeclareLocal(typeof(IReplyMessage<>).MakeGenericType(sendMethodInnerRet)); //var excMsgLocal = e.Message; il.EmitCall(OpCodes.Call, typeof(Exception).GetProperty("Message").GetGetMethod(), null); il.Emit(OpCodes.Stloc, excMsgLocal); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Newobj, replyMessageType.GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Stloc, replyMsgLocal); il.Emit(OpCodes.Ldloc, replyMsgLocal); il.Emit(OpCodes.Ldloc, excMsgLocal); il.EmitCall(OpCodes.Callvirt, typeof(IReplyMessage<>).MakeGenericType(sendMethodInnerRet).GetMethod("SetError"), null); il.Emit(OpCodes.Ldloc, replyMsgLocal); if (isNoParamTask) { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponseNoResult", BindingFlags.Instance | BindingFlags.NonPublic), null); } else { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponse", BindingFlags.Instance | BindingFlags.NonPublic) .MakeGenericMethod(sendMethodInnerRet), null); } // } il.EndExceptionBlock(); il.MarkLabel(endLabel); il.Emit(OpCodes.Ret); return mb; }
private void DefineMessageTypeForActorMethodReturn(MethodInfoMapping miMapping) { Type returnType = null; var returnTypeTask = miMapping.Info.ReturnType; bool isEmptyReply = returnTypeTask == typeof(Task); if (returnTypeTask == typeof(Task)) { returnType = typeof(System.Reactive.Unit); } else { var genArgs = returnTypeTask.GetGenericArguments(); if (genArgs.Length != 1) { throw new InvalidOperationException("Return type of a method must be Task<T>"); } returnType = genArgs[0]; } var messageTypeName = miMapping.PublicName + "MessageReply"; var replyInterfaceType = typeof(IReplyMessage <>).MakeGenericType(returnType); var typeBuilder = this.moduleBuilder.DefineType("Messages." + messageTypeName, TypeAttributes.Public, null, new[] { replyInterfaceType }); // Empty ctor var cb = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, Type.EmptyTypes); var cbIl = cb.GetILGenerator(); cbIl.Emit(OpCodes.Ret); // Type attributes var protoContractCtor = typeof(ProtoBuf.ProtoContractAttribute).GetConstructor(Type.EmptyTypes); typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(protoContractCtor, new object[0])); var protoMemberCtor = typeof(ProtoBuf.ProtoMemberAttribute).GetConstructor(new[] { typeof(int) }); var errfb = typeBuilder.DefineField("$ErrorMessage", typeof(string), FieldAttributes.Public); errfb.SetCustomAttribute(new CustomAttributeBuilder(protoMemberCtor, new object[] { 1 })); FieldBuilder fb = null; if (!isEmptyReply) { fb = typeBuilder.DefineField("@Return", returnType, FieldAttributes.Public); fb.SetCustomAttribute(new CustomAttributeBuilder(protoMemberCtor, new object[] { 2 })); } //GetResult() var getResultMb = typeBuilder.DefineMethod("GetResult", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, returnType, Type.EmptyTypes); var gril = getResultMb.GetILGenerator(); var isOKLabel = gril.DefineLabel(); gril.Emit(OpCodes.Ldarg_0); gril.Emit(OpCodes.Ldfld, errfb); gril.Emit(OpCodes.Ldnull); gril.Emit(OpCodes.Ceq); //if($ErrorMessage != null) { gril.Emit(OpCodes.Brtrue_S, isOKLabel); // throw new Exception($ErrorMessage); gril.Emit(OpCodes.Ldarg_0); gril.Emit(OpCodes.Ldfld, errfb); gril.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new[] { typeof(string) })); gril.Emit(OpCodes.Throw); // } else { // return @Return; } gril.MarkLabel(isOKLabel); if (!isEmptyReply) { gril.Emit(OpCodes.Ldarg_0); gril.Emit(OpCodes.Ldfld, fb); } else { gril.EmitCall(OpCodes.Call, typeof(System.Reactive.Unit).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetGetMethod(), null); } gril.Emit(OpCodes.Ret); //SetResult var setResultMb = typeBuilder.DefineMethod("SetResult", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(void), new[] { returnType }); var sril = setResultMb.GetILGenerator(); if (!isEmptyReply) { sril.Emit(OpCodes.Ldarg_0); sril.Emit(OpCodes.Ldarg_1); sril.Emit(OpCodes.Stfld, fb); } sril.Emit(OpCodes.Ret); //SetError var setErrorMb = typeBuilder.DefineMethod("SetError", MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(void), new[] { typeof(string) }); var seil = setErrorMb.GetILGenerator(); seil.Emit(OpCodes.Ldarg_0); seil.Emit(OpCodes.Ldarg_1); seil.Emit(OpCodes.Stfld, errfb); seil.Emit(OpCodes.Ret); var createdType = typeBuilder.CreateType(); this.messageReturnTypes[miMapping.PublicName] = createdType; }
private MethodBuilder CreateHandlerMethod(MethodInfoMapping miMapping) { var sendMethodTaskRet = miMapping.Info.ReturnType; bool isNoParamTask = sendMethodTaskRet == typeof(Task); var sendMethodInnerRet = sendMethodTaskRet == typeof(Task) ? typeof(System.Reactive.Unit) : sendMethodTaskRet.GetGenericArguments()[0]; var mb = actorImplBuilder.DefineMethod(miMapping.PublicName + "Handler", MethodAttributes.Private | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(void), new[] { typeof(FramedClient), typeof(long), typeof(MemoryStream) }); Type messageType = moduleBuilder.GetType("Messages." + miMapping.PublicName + "Message"); Type replyMessageType = moduleBuilder.GetType("Messages." + miMapping.PublicName + "MessageReply"); var desMethod = typeof(IStacksSerializer).GetMethod("Deserialize").MakeGenericMethod(messageType); var il = mb.GetILGenerator(); var messageLocal = il.DeclareLocal(messageType); var endLabel = il.DefineLabel(); // try { il.BeginExceptionBlock(); //var msg = base.serializer.Deserialize<P>(ms); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, templateType.GetField("serializer", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Callvirt, desMethod, null); il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, templateType.GetField("actorImplementation", BindingFlags.Instance | BindingFlags.NonPublic)); //actorImplementation.[methodName](params); var sendParams = miMapping.Info.GetParameters(); // If first parameter is IActorSession, load session for dictionary and // place it on stack as first parameter. if (sendParams.Length >= 1 && sendParams[0].ParameterType == typeof(IActorSession)) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, templateType.GetField("actorSessions", BindingFlags.Instance | BindingFlags.NonPublic)); il.Emit(OpCodes.Ldarg_1); //FramedClient used as a key for session cache il.EmitCall(OpCodes.Call, typeof(Dictionary <IFramedClient, IActorSession>).GetMethod("get_Item"), null); } for (int idx = 0, i = 1; idx < sendParams.Length; ++idx) { // Ommit first parameter if it is an IActorSession if (idx == 0 && sendParams[0].ParameterType == typeof(IActorSession)) { continue; } var field = GetFieldInfoFromProtobufMessage(messageType, i); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldfld, field); ++i; } il.EmitCall(OpCodes.Callvirt, miMapping.InterfaceInfo, null); } il.Emit(OpCodes.Newobj, replyMessageType.GetConstructor(Type.EmptyTypes)); if (isNoParamTask) { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponseNoResult", BindingFlags.Instance | BindingFlags.NonPublic), null); } else { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponse", BindingFlags.Instance | BindingFlags.NonPublic) .MakeGenericMethod(sendMethodInnerRet), null); } // } catch (Exception e) { il.BeginCatchBlock(typeof(Exception)); var excMsgLocal = il.DeclareLocal(typeof(string)); var replyMsgLocal = il.DeclareLocal(typeof(IReplyMessage <>).MakeGenericType(sendMethodInnerRet)); //var excMsgLocal = e.Message; il.EmitCall(OpCodes.Call, typeof(Exception).GetProperty("Message").GetGetMethod(), null); il.Emit(OpCodes.Stloc, excMsgLocal); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Newobj, replyMessageType.GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Stloc, replyMsgLocal); il.Emit(OpCodes.Ldloc, replyMsgLocal); il.Emit(OpCodes.Ldloc, excMsgLocal); il.EmitCall(OpCodes.Callvirt, typeof(IReplyMessage <>).MakeGenericType(sendMethodInnerRet).GetMethod("SetError"), null); il.Emit(OpCodes.Ldloc, replyMsgLocal); if (isNoParamTask) { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponseNoResult", BindingFlags.Instance | BindingFlags.NonPublic), null); } else { il.EmitCall(OpCodes.Call, templateType.GetMethod("HandleResponse", BindingFlags.Instance | BindingFlags.NonPublic) .MakeGenericMethod(sendMethodInnerRet), null); } // } il.EndExceptionBlock(); il.MarkLabel(endLabel); il.Emit(OpCodes.Ret); return(mb); }