示例#1
0
        private static AsyncMethodState DeserializeInner(object currentInstance, JToken json)
        {
            if (json == null || !json.Any())
            {
                return(null);
            }
            var state = new AsyncMethodState();

            state.AsyncMethodName          = json["asyncMethodName"].Value <string>();
            state.StateMachineAssemblyName = json["stateMachineAssemblyName"].Value <string>();
            state.StateMachineTypeName     = json["stateMachineTypeName"].Value <string>();
            state.StateNumber    = CreateMember(json["stateNumber"]["memberName"].Value <string>(), json["stateNumber"]["value"].Value <int>());
            state.CurrentAwaiter = CreateMember(json["currentAwaiter"]["memberName"].Value <string>(), DeserializeInner(currentInstance, json["currentAwaiter"]["value"]));
            state.Locals         = new List <Member <object> >();
            foreach (var local in json["locals"])
            {
                var value = local["value"] == null //|| Type.GetType(local["type"].ToString()).IsSubclassOf(typeof(Task))
                    ? null
                    : (local["type"].Value <string>() == currentInstance.GetType().FullName
                        ? currentInstance
                        : local["value"].ToObject(Assembly.Load(local["assembly"].Value <string>()).GetType(local["type"].Value <string>())));
                state.Locals.Add(CreateMember(local["memberName"].Value <string>(), value));
            }
            return(state);
        }
示例#2
0
        private static string Serialize(AsyncMethodState state, int resumeCount)
        {
            var json = new JObject();

            json["resumeCount"] = resumeCount;
            json["state"]       = SerializeInner(state);
            return(json.ToString());
        }
示例#3
0
            public void OnCompleted(Action continuation)
            {
                if (_result > 0)
                {
                    continuation();
                    return;
                }

                var asyncMethod = TryGetStateMachineForDebugger(continuation).Target as IAsyncStateMachine;

                AsyncMethodState state = null;

                while (true)
                {
                    var state1 = new AsyncMethodState();
                    state1.AsyncMethodName          = asyncMethod.Name();
                    state1.AsyncMethodTaskId        = asyncMethod.Task().Id;
                    state1.StateMachineAssemblyName = asyncMethod.GetType().Assembly.FullName;
                    state1.StateMachineTypeName     = asyncMethod.GetType().FullName;
                    state1.StateNumber    = asyncMethod.GetCurrentStateNumber();
                    state1.CurrentAwaiter = CreateMember(asyncMethod.GetCurrentAwaiter().MemberName, state);
                    state1.Locals         = asyncMethod.GetLocalsAndParameters().ToList();
                    state = state1;

                    var parent = asyncMethod.GetAsyncMethodThatsAwaitingThisOne();
                    if (parent == null)
                    {
                        Serialize(state, 0);
                        continuation();
                        return;
                        //throw new NoAwaitingParentException($"Can't figure out which async method is awaiting {asyncMethod.Name()}");
                    }
                    var parentAwaiter = parent.GetCurrentAwaiter();
                    if (parentAwaiter == null)
                    {
                        throw new NotSupportedException($"Async method {parent.Name()} has awaiter types that we don't know how to checkpoint");
                    }
                    var name = parentAwaiter.Value.GetType().ToString();
                    if (parentAwaiter.Value is RunWithCheckpointingAwaiter)
                    {
                        var saver = parentAwaiter.Value as RunWithCheckpointingAwaiter;
                        saver.fn.Clear();
                        saver.fn.Append(Serialize(state, 0));
                        break;
                    }
                    else if (parentAwaiter.Value.GetType().ToString().StartsWith("System.Runtime.CompilerServices.TaskAwaiter"))
                    {
                        asyncMethod = parent;
                    }
                    else
                    {
                        throw new NotSupportedException($"Async method {parent.Name()} is awaiting a {parentAwaiter.Value.GetType().ToString()}, but we only know how to checkpoint awaits on normal Tasks");
                    }
                }

                continuation();
            }
示例#4
0
    private static JObject SerializeInner(AsyncMethodState state)
    {
        if (state == null)
        {
            return(null);
        }

        var json = new JObject();

        json["asyncMethodName"]          = state.AsyncMethodName;
        json["stateMachineAssemblyName"] = state.StateMachineAssemblyName;
        json["stateMachineTypeName"]     = state.StateMachineTypeName;
        json["stateNumber"] = new JObject {
            { "memberName", state.StateNumber.MemberName },
            { "value", state.StateNumber.Value }
        };
        json["currentAwaiter"] = new JObject {
            { "memberName", state.CurrentAwaiter.MemberName },
            { "value", SerializeInner(state.CurrentAwaiter.Value) }
        };

        var locals = new JArray();

        json["locals"] = locals;
        foreach (var local in state.Locals)
        {
            if (local.Value == null)
            {
                locals.Add(new JObject {
                    { "memberName", local.MemberName }
                });
            }
            else
            {
                locals.Add(new JObject {
                    { "memberName", local.MemberName },
                    { "assembly", local.Value.GetType().Assembly.FullName },
                    { "type", local.Value.GetType().FullName },
                    { "value", JToken.FromObject(local.Value) }
                });
            }
        }

        return(json);
    }
示例#5
0
        private static void SaveContextInner(AsyncMethodState state)
        {
            if (state == null)
            {
                return;
            }

            SaveContextInner(state.CurrentAwaiter.Value);

            foreach (var local in state.Locals.Where(l => l.Value != null))
            {
                if (local.Value.GetType() == typeof(AsyncContext))
                {
                    Immortal.InstanceProxy.Immortal.TaskIdToSequenceNumber.Data.AddOrUpdate(state.AsyncMethodTaskId,
                                                                                            ((AsyncContext)local.Value).SequenceNumber, (k, v) => v);
                }
            }
        }
示例#6
0
        private static ReadStateMachineResult ReconstructStateMachine(AsyncMethodState state)
        {
            var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

            // sm = new StateMachineType();
            var assembly = Assembly.Load(state.StateMachineAssemblyName);
            var sm       = Activator.CreateInstance(assembly.GetType(state.StateMachineTypeName)) as IAsyncStateMachine;

            // sm.builder = BuilderType.Create()
            var builderField = sm.BuilderField();

            builderField.SetValue(sm, builderField.FieldType.GetMethod("Create").Invoke(null, new object[] { }));

            try
            {
                Expression.Lambda <Action>(Expression.Call(Expression.Field(Expression.Constant(sm), builderField), builderField.FieldType.GetMethod("SetStateMachine"), Expression.Constant(sm))).Compile().Invoke();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            // sm.builder.SetStateMachine(sm)

            // sm.state = i
            sm.GetType().GetField(state.StateNumber.MemberName).SetValue(sm, state.StateNumber.Value);

            // sm.<local> = <local_value>
            foreach (var local in state.Locals)
            {
                if (local.Value != null && local.Value.GetType() == typeof(SerializableTaskCompletionSource) && sm.GetType().GetField(local.MemberName, bf).FieldType.IsSubclassOf(typeof(Task)))
                {
                    SerializableTaskCompletionSource stcs;
                    if (((SerializableTaskCompletionSource)local.Value).IsCompleted)
                    {
                        stcs = (SerializableTaskCompletionSource)local.Value;
                    }
                    else
                    {
                        Immortal.InstanceProxy.Immortal.CallCache.Data.TryGetValue(((SerializableTaskCompletionSource)local.Value).SequenceNumber, out stcs);
                    }

                    var getAwaitableTaskMethod = typeof(SerializableTaskCompletionSource).GetMethods().FirstOrDefault(m =>
                                                                                                                      m.GetCustomAttributes(typeof(SerializableTaskCompletionSource.GetAwaitableTaskAttribute)).Any());
                    if (getAwaitableTaskMethod != null)
                    {
                        var genericGetAwaitabeTaskMethod = getAwaitableTaskMethod.MakeGenericMethod(stcs.ResultType.Type);
                        var value = genericGetAwaitabeTaskMethod.Invoke(stcs, new object[] { });
                        sm.GetType().GetField(local.MemberName, bf).SetValue(sm, value);
                    }
                }
                else
                {
                    sm.GetType().GetField(local.MemberName, bf).SetValue(sm, local.Value);
                }
            }

            ReadStateMachineResult awaited;

            if (state.CurrentAwaiter.Value == null)
            {
                // sm.awaiter = new CheckpointSaveAwaiter()
                var awaiter = new CheckpointSaveAwaiter()
                {
                    _result = 0
                };
                awaited = new ReadStateMachineResult()
                {
                    AwaiterForAwaitingThisStateMachine = awaiter, LeafCheckpointSaveAwaiter = awaiter
                };
                sm.GetType().GetField(state.CurrentAwaiter.MemberName, bf).SetValue(sm, awaiter);
            }
            else
            {
                // sm.awaiter = <nested state machine's awaiter>
                awaited = ReconstructStateMachine(state.CurrentAwaiter.Value);
                var awaiter = awaited.AwaiterForAwaitingThisStateMachine;
                sm.GetType().GetField(state.CurrentAwaiter.MemberName, bf).SetValue(sm, awaiter);
            }

            // sm.builder.AwaitOnCompleted(ref child_awaiter, ref sm);
            var varSm      = Expression.Variable(sm.GetType(), "sm");
            var varAwaiter = Expression.Variable(awaited.AwaiterForAwaitingThisStateMachine.GetType(), "awaiter");
            var expression = Expression.Lambda <Action>(Expression.Block(
                                                            new[] { varSm, varAwaiter },
                                                            Expression.Assign(varSm, Expression.Constant(sm)),
                                                            Expression.Assign(varAwaiter, Expression.Constant(awaited.AwaiterForAwaitingThisStateMachine)),
                                                            Expression.Call(
                                                                Expression.Field(varSm, builderField),
                                                                builderField.FieldType.GetMethod("AwaitOnCompleted").MakeGenericMethod(awaited.AwaiterForAwaitingThisStateMachine.GetType(), sm.GetType()),
                                                                new Expression[] { varAwaiter, varSm })));
            var lambda = expression.Compile();

            if (state.CurrentAwaiter.Value == null)
            {
                awaited.LeafActionToStartWork = lambda;
            }
            else
            {
                lambda();
            }

            // task = sm.Builder.Task
            var task = Expression.Lambda <Func <object> >(Expression.Property(Expression.Field(Expression.Constant(sm), builderField), builderField.FieldType.GetProperty("Task"))).Compile().Invoke();

            // task.GetAwaiter();
            var taskAwaiter = task.GetType().GetMethod("GetAwaiter").Invoke(task, new object[] { });


            return(new ReadStateMachineResult
            {
                StateMachine = sm,
                Task = task as Task,
                AwaiterForAwaitingThisStateMachine = taskAwaiter,
                LeafActionToStartWork = awaited.LeafActionToStartWork,
                LeafCheckpointSaveAwaiter = awaited.LeafCheckpointSaveAwaiter
            });
        }
示例#7
0
        private static JObject SerializeInner(AsyncMethodState state)
        {
            if (state == null)
            {
                return(null);
            }

            var json = new JObject();

            json["asyncMethodName"]          = state.AsyncMethodName;
            json["stateMachineAssemblyName"] = state.StateMachineAssemblyName;
            json["stateMachineTypeName"]     = state.StateMachineTypeName;
            json["stateNumber"] = new JObject {
                { "memberName", state.StateNumber.MemberName },
                { "value", state.StateNumber.Value }
            };
            json["currentAwaiter"] = new JObject {
                { "memberName", state.CurrentAwaiter.MemberName },
                { "value", SerializeInner(state.CurrentAwaiter.Value) }
            };

            var locals = new JArray();

            json["locals"] = locals;
            foreach (var local in state.Locals)
            {
                if (local.Value == null)
                {
                    locals.Add(new JObject {
                        { "memberName", local.MemberName }
                    });
                }
                else if (local.Value.GetType().IsSubclassOf(typeof(Task)))
                {
                    SerializableTaskCompletionSource stcs;

                    if (((Task)local.Value).IsCompleted)
                    {
                        var task     = (Task)local.Value;
                        var property = task.GetType().GetProperty("Result", BindingFlags.Public | BindingFlags.Instance);
                        var result   = property.GetValue(task);
                        stcs = new SerializableTaskCompletionSource(result.GetType());
                        stcs.SetResult(result);
                    }
                    else if (!Immortal.InstanceProxy.Immortal.TaskIdToSequenceNumber.Data.TryRemove(((Task)local.Value).Id, out var sequenceNumber) ||
                             !Immortal.InstanceProxy.Immortal.CallCache.Data.TryGetValue(sequenceNumber, out stcs))
                    {
                        stcs = new SerializableTaskCompletionSource();
                    }

                    locals.Add(new JObject
                    {
                        { "memberName", local.MemberName },
                        { "assembly", stcs.GetType().Assembly.FullName },
                        { "type", stcs.GetType().FullName },
                        { "value", JToken.FromObject(stcs) }
                    });
                }
                else
                {
                    if (local.Value.GetType() == typeof(AsyncContext))
                    {
                        Immortal.InstanceProxy.Immortal.TaskIdToSequenceNumber.Data.AddOrUpdate(state.AsyncMethodTaskId, ((AsyncContext)local.Value).SequenceNumber, (k, v) => v);
                    }
                    locals.Add(new JObject
                    {
                        { "memberName", local.MemberName },
                        { "assembly", local.Value.GetType().Assembly.FullName },
                        { "type", local.Value.GetType().FullName },
                        { "value", JToken.FromObject(local.Value) }
                    });
                }
            }

            return(json);
        }
示例#8
0
    private static ReadStateMachineResult ReconstructStateMachine(AsyncMethodState state)
    {
        var bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

        // sm = new StateMachineType();
        var sm = Activator.CreateInstance(state.StateMachineAssemblyName, state.StateMachineTypeName).Unwrap() as IAsyncStateMachine;

        // sm.builder = BuilderType.Create()
        var builderField = sm.BuilderField();

        builderField.SetValue(sm, builderField.FieldType.GetMethod("Create").Invoke(null, new object[] { }));

        // sm.builder.SetStateMachine(sm)
        Expression.Lambda <Action>(Expression.Call(Expression.Field(Expression.Constant(sm), builderField), builderField.FieldType.GetMethod("SetStateMachine"), Expression.Constant(sm))).Compile().Invoke();

        // sm.state = i
        sm.GetType().GetField(state.StateNumber.MemberName).SetValue(sm, state.StateNumber.Value);

        // sm.<local> = <local_value>
        foreach (var local in state.Locals)
        {
            sm.GetType().GetField(local.MemberName, bf).SetValue(sm, local.Value);
        }

        ReadStateMachineResult awaited;

        if (state.CurrentAwaiter.Value == null)
        {
            // sm.awaiter = new CheckpointSaveAwaiter()
            var awaiter = new CheckpointSaveAwaiter()
            {
                _result = 0
            };
            awaited = new ReadStateMachineResult()
            {
                AwaiterForAwaitingThisStateMachine = awaiter, LeafCheckpointSaveAwaiter = awaiter
            };
            sm.GetType().GetField(state.CurrentAwaiter.MemberName, bf).SetValue(sm, awaiter);
        }
        else
        {
            // sm.awaiter = <nested state machine's awaiter>
            awaited = ReconstructStateMachine(state.CurrentAwaiter.Value);
            var awaiter = awaited.AwaiterForAwaitingThisStateMachine;
            sm.GetType().GetField(state.CurrentAwaiter.MemberName, bf).SetValue(sm, awaiter);
        }

        // sm.builder.AwaitOnCompleted(ref child_awaiter, ref sm);
        var varSm      = Expression.Variable(sm.GetType(), "sm");
        var varAwaiter = Expression.Variable(awaited.AwaiterForAwaitingThisStateMachine.GetType(), "awaiter");
        var expression = Expression.Lambda <Action>(Expression.Block(
                                                        new[] { varSm, varAwaiter },
                                                        Expression.Assign(varSm, Expression.Constant(sm)),
                                                        Expression.Assign(varAwaiter, Expression.Constant(awaited.AwaiterForAwaitingThisStateMachine)),
                                                        Expression.Call(
                                                            Expression.Field(varSm, builderField),
                                                            builderField.FieldType.GetMethod("AwaitOnCompleted").MakeGenericMethod(awaited.AwaiterForAwaitingThisStateMachine.GetType(), sm.GetType()),
                                                            new Expression[] { varAwaiter, varSm })));
        var lambda = expression.Compile();

        if (state.CurrentAwaiter.Value == null)
        {
            awaited.LeafActionToStartWork = lambda;
        }
        else
        {
            lambda();
        }

        // task = sm.Builder.Task
        var task = Expression.Lambda <Func <object> >(Expression.Property(Expression.Field(Expression.Constant(sm), builderField), builderField.FieldType.GetProperty("Task"))).Compile().Invoke();

        // task.GetAwaiter();
        var taskAwaiter = task.GetType().GetMethod("GetAwaiter").Invoke(task, new object[] { });


        return(new ReadStateMachineResult
        {
            StateMachine = sm,
            Task = task as Task,
            AwaiterForAwaitingThisStateMachine = taskAwaiter,
            LeafActionToStartWork = awaited.LeafActionToStartWork,
            LeafCheckpointSaveAwaiter = awaited.LeafCheckpointSaveAwaiter
        });
    }