Can asynchronous functions be inline?

Embedding functions is a compiler optimization that replaces the function call site with the body of the called party. This optimization is supported for common C # functions .

Async functions that support async-await in C # 5.0 have a special declaration that includes the async modifier and wrapping return values ​​using Task<> .

Could there also be asynchronous functions?

Example:

Suppose I have the following functions:

 private async Task<int> CalleeAsync() { return await SomeOperationAsync(); } private async Task<int> CallerAsync() { return await CalleeAsync(); } 

Can they be optimized for:

 private async Task<int> CallerAsync() { return await SomeOperationAsync(); } 

Additional loan:

If it is supported, who can decide what exactly? Compiler? Jit? to me?

If it is not supported, should I worry about this and avoid the excessive shells that I sometimes add for readability?

+6
source share
2 answers

Given the complexity of the conversions caused by async/await , I don't think the code is inlineable: async/await forces your method to convert to a hidden class, and your code becomes a state machine with different parts, the code becomes different.

To give an example, a simple method like CalleeAsync() converted to a monster like:

 [CompilerGenerated] private sealed class <CalleeAsync>d__2 { private int <>1__state; private bool $__disposing; public System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> $builder; public Action <>t__MoveNextDelegate; public Program <>4__this; private TaskAwaiter<int> <a1>t__$await4; public void MoveNext() { int result2; System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> asyncTaskMethodBuilder; try { int num = this.<>1__state; if (num != 1) { if (this.<>1__state == -1) { return; } this.<a1>t__$await4 = this.<>4__this.SomeOperationAsync().GetAwaiter<int>(); if (!this.<a1>t__$await4.IsCompleted) { this.<>1__state = 1; this.<a1>t__$await4.OnCompleted(this.<>t__MoveNextDelegate); return; } } else { this.<>1__state = 0; } int result = this.<a1>t__$await4.GetResult(); this.<a1>t__$await4 = default(TaskAwaiter<int>); result2 = result; } catch (Exception exception) { this.<>1__state = -1; asyncTaskMethodBuilder = this.$builder; asyncTaskMethodBuilder.SetException(exception); return; } this.<>1__state = -1; asyncTaskMethodBuilder = this.$builder; asyncTaskMethodBuilder.SetResult(result2); } [DebuggerHidden] public void Dispose() { this.$__disposing = true; this.MoveNext(); this.<>1__state = -1; } [DebuggerHidden] public <CalleeAsync>d__2(int <>1__state) { this.<>1__state = <>1__state; } } 

(note that on this computer I still have Visual Studio 2010 with Async CTP, with .NET 4.5 the generated code may be different).

Do you think something like that is strict?

+4
source

The C # compiler will generate quite a lot of IL-code for a "simple" await , xanatos has already shown what this IL-code looks like when translating to C #. Since the JIT compiler (the one who does inlining) has strict rules on inlining, I doubt that it will embed all this code.

Here are some rules for embedding JIT (this may not be true for the current JIT, but this is a good start). Here I already see two violations of the rules: we have more than 32 bytes of IL code and an exception handling unit.

+1
source

Source: https://habr.com/ru/post/952967/


All Articles