Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

await Async method will create wrong IL #83

Open
jerviscui opened this issue Apr 15, 2021 · 4 comments
Open

await Async method will create wrong IL #83

jerviscui opened this issue Apr 15, 2021 · 4 comments

Comments

@jerviscui
Copy link

TestClass:

[TaskLog]
public class TaskTest
{
    public Task Test()
    {
        Console.WriteLine($"front {Thread.CurrentThread.ManagedThreadId}");

        return Task.Delay(1000);
        //Console.WriteLine("end");
    }
    
    public async Task AwaitTest()
    {
        Console.WriteLine($"front {Thread.CurrentThread.ManagedThreadId}");
        await Task.Delay(10);
        Console.WriteLine($"end {Thread.CurrentThread.ManagedThreadId}");
        //throw new ArgumentException();
    }
}

method boundary Aspect:

public class TaskLogAttribute : OnMethodBoundaryAspect
{
    /// <inheritdoc />
    public override void OnEntry(MethodExecutionArgs arg)
    {
        Console.WriteLine($"OnEntry {Thread.CurrentThread.ManagedThreadId}");
    }

    /// <inheritdoc />
    public override void OnExit(MethodExecutionArgs arg)
    {
        Console.WriteLine($"OnExit {Thread.CurrentThread.ManagedThreadId}");
    }
}

caller:

class Program
{
    static async Task Main(string[] args)
    {
        var t = new TaskTest();
        await t.AwaitTest();
    }
}

The result:

OnEntry 4
OnEntry 4
front 4
OnExit 4
OnExit 4
OnEntry 4
end 4
OnExit 4

@FerdinandBrunauer
Copy link

FerdinandBrunauer commented Mar 18, 2022

I think your OnExit method should look like the following:

    /// <inheritdoc />
    public override void OnExit(MethodExecutionArgs arg)
    {
        if (arg.ReturnValue is Task t)
        {
            t.ContinueWith(_ =>
            {
                Console.WriteLine($"OnExit {Thread.CurrentThread.ManagedThreadId}");
            }, TaskContinuationOptions.ExecuteSynchronously);
        }
        else
        {
            Console.WriteLine($"OnExit {Thread.CurrentThread.ManagedThreadId}");
        }
    }

@jerviscui
Copy link
Author

It's been too long.
But, I think I wan to say, OnEntry and OnExit run many times.
Beacuse there is many times run OnEntry and OnExit in the TaskStateMachine.

@mjvh80
Copy link

mjvh80 commented Dec 2, 2022

I think the issue here is that there's a difference currently whether an aspect is applied to a class or to a method directly. If it is applied directly to an async method there is special handling of the underlying MoveNext (see e.g.

var moveNextMethod = ((TypeDefinition)asyncAttribute.ConstructorArguments[0].Value).Methods.First(m => m.Name == "MoveNext");
) However, if the aspect is applied to the class (or assembly) then it is also applied to the compiler generated state machine class as well, and thus the MoveNext method contained therein.

@Ralf1108
Copy link
Collaborator

Ralf1108 commented Dec 2, 2022

@mjvh80 so the solution would be to identify the compiler generated state machine class and skip weaving anything in it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants