Example #1
0
        private void ImplementCallback(ChordInfo chord)
        {
            MethodBuilder callback = target.DefineMethod(string.Format("{0}Callback", chord.Name),
                                             MethodAttributes.Private, typeof (void),
                                             new Type[] {typeof (object), typeof (bool)});

            callback.DefineParameter(1, ParameterAttributes.In, "bus");
            callback.DefineParameter(2, ParameterAttributes.In, "unused");

            int joinParameterCount = chord.JoinParameters.Length;
            int inChannelParameterCount = chord.InChannelParameters.Length;
            int outChannelParameterCount = chord.OutChannelParameters.Length;

            Type returnType = chord.ChordMethod.ReturnType;

            ILGenerator generator = callback.GetILGenerator();

            // IL: Get join channel
            if (returnType != typeof(void))
            {
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, channelImplementer
                               .GetJoinChannelField(chord.ChordMethod.Name,
                                                    returnType));
            }

            // IL: Receive from Bus and store array
            generator.DeclareLocal(typeof(object[]));
            generator.Emit(OpCodes.Ldarg_1);
            generator.EmitCall(OpCodes.Call, typeof (Bus).GetMethod("Receive", new Type[] {}), null);
            generator.Emit(OpCodes.Stloc_0);

            generator.Emit(OpCodes.Ldarg_0);

            // IL: Reregister bus
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldftn, callback);
            generator.Emit(OpCodes.Newobj, typeof(WaitOrTimerCallback).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
            generator.EmitCall(OpCodes.Call, typeof(ChordManager).GetMethod("RegisterBus", new Type[] { typeof(Bus), typeof(WaitOrTimerCallback) }), null);

            // IL: Unwrap value array
            for (int parameterIndex = 0; parameterIndex < joinParameterCount; parameterIndex++)
            {
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ldc_I4, parameterIndex);
                generator.Emit(OpCodes.Ldelem_Ref);
                if (chord.JoinParameters[parameterIndex].ParameterType.IsValueType)
                    generator.Emit(OpCodes.Unbox_Any, chord.JoinParameters[parameterIndex].ParameterType);
            }
            for (int parameterIndex = 0; parameterIndex < inChannelParameterCount; parameterIndex++)
            {
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ldc_I4, parameterIndex + joinParameterCount);
                generator.Emit(OpCodes.Ldelem_Ref);
                if (chord.InChannelParameters[parameterIndex].ParameterType.IsValueType)
                    generator.Emit(OpCodes.Unbox_Any, chord.InChannelParameters[parameterIndex].ParameterType);
            }

            // IL: Prepare out channels
            for (int channelParameterIndex = 0; channelParameterIndex < outChannelParameterCount; channelParameterIndex++)
            {
                generator.DeclareLocal(chord.OutChannelParameters[channelParameterIndex].ParameterType.GetElementType());
                generator.Emit(OpCodes.Ldloca, channelParameterIndex + 1);
            }

            // IL: Call chord method
            generator.EmitCall(OpCodes.Call, chord.ChordMethod, null);

            // IL: Send result to join channel
            if (returnType != typeof(void))
            {
                generator.EmitCall(OpCodes.Call, typeof(Channel<>)
                                   .MakeGenericType(new Type[] { returnType })
                                   .GetMethod("Send"), null);
            }

            // IL: Handle out channel results
            for (int channelParameterIndex = 0; channelParameterIndex < outChannelParameterCount; channelParameterIndex++)
            {
                Type channelType = chord.OutChannelParameters[channelParameterIndex]
                                                .ParameterType.GetElementType();
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, channelImplementer
                               .GetChannelField(chord.OutChannelNames[channelParameterIndex],
                                                channelType));

                generator.Emit(OpCodes.Ldloc, channelParameterIndex + 1);
                generator.EmitCall(OpCodes.Call, typeof(Channel<>)
                                   .MakeGenericType(new Type[] { channelType })
                                   .GetMethod("Send"), null);
            }

            generator.Emit(OpCodes.Ret);

            callbacks.Add(chord, callback);
        }
Example #2
0
 public void Implement(ChordInfo chord)
 {
     ImplementCallback(chord);
 }