Skip to content

[RuntimeAsync] ilasm/ildasm support for the MethodImpl.Async (Take 2) #115658

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

hez2010
Copy link
Contributor

@hez2010 hez2010 commented May 16, 2025

We still define async as a keyword, but allow it to appear as an identifier.

cc @VSadov

Test code:

.assembly async {}
.module async.dll

.assembly extern System.Runtime { }

.class private auto ansi beforefieldinit async
	extends [System.Runtime]System.Object
{
	.method private hidebysig static 
		valuetype [System.Runtime]System.Threading.Tasks.ValueTask`1<int32> async (
			int32 async
		) cil managed async
	{
		.entrypoint
		ret
	}
}

Code after ilasm-ildasm round-trip:

.assembly extern System.Console
{
  .ver 0:0:0:0
}
.assembly extern System.Runtime
{
  .ver 0:0:0:0
}
.assembly 'async'
{
  .ver 0:0:0:0
}
.module async.dll
// MVID: {33350b0f-ac29-4c00-af71-862deacba9aa}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x000002C7087E0000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit 'async'
       extends [System.Runtime]System.Object
{
  .method private hidebysig static valuetype [System.Runtime]System.Threading.Tasks.ValueTask`1<int32>
          'async'(int32 'async') cil managed async
  {
    .entrypoint
    // Code size       1 (0x1)
    .maxstack  8
    IL_0000:  ret
  } // end of method 'async'::'async'

} // end of class 'async'

I found we have the same problem for some other MethodImpl attributes such as nooptimization, aggressiveinlining, aggressiveoptimization etc. Should I fix them as well? @jkotas

@Copilot Copilot AI review requested due to automatic review settings May 16, 2025 15:46
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label May 16, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR extends the support for MethodImpl attributes to include the async keyword, treating it similarly to other attributes like nooptimization and aggressiveoptimization.

  • Added the async keyword definition in the ilasm header file.
  • Updated the disassembler and parser grammar files to handle async as a valid attribute.
  • Introduced a new token ASYNC_ in the parser definition for method implementation attributes.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

File Description
src/coreclr/inc/il_kywd.h Added async attribute definition to the keyword table
src/coreclr/ildasm/dasm.cpp Added check to output " async" when the method is async
src/coreclr/ilasm/prebuilt/asmparse.grammar Updated grammar to accept async as an identifier
src/coreclr/ilasm/asmparse.y Added async token handling to the parser productions

Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT
See info in area-owners.md if you want to be subscribed.

@jkotas
Copy link
Member

jkotas commented May 17, 2025

I found we have the same problem for all other MethodImpl attributes
Should I fix them as well? @jkotas

Sounds reasonable to me - as long as it is non-breaking.

don't get escaped by Roslyn

Is there an example of where Roslyn does identifier escaping like that? I am not aware of any. It does not sound right for Roslyn to be aware of keywords in textual IL representation.

I see this as a problem specific to textual IL representation, so ilasm/ildasm are the right place to deal with it.

@hez2010
Copy link
Contributor Author

hez2010 commented May 18, 2025

Is there an example of where Roslyn does identifier escaping like that? I am not aware of any

For example, if you write void Foo(int noinlining) in C#, Roslyn will emit 'noinlining' as the parameter name instead of noinlining.
Or maybe I'm wrong, as I observed this behavior from ILSpy. So the behavior may come from ILSpy instead of Roslyn.

@jkotas
Copy link
Member

jkotas commented May 18, 2025

Or maybe I'm wrong, as I observed this behavior from ILSpy. So the behavior may come from ILSpy instead of Roslyn.

Right, ildasm (and ILSpy?) encloses identifiers that happen to match IL keywords in quotes.

These identifiers are not enclosed in quotes in the metadata emitted by Roslyn. For example, the following program prints noinlining without quotes:

public class Program
{
    static void Main()
    {
        Console.WriteLine(typeof(Program).GetMethod("Foo").GetParameters()[0].Name);
    }

    public void Foo(int noinlining) { }
}

@hez2010
Copy link
Contributor Author

hez2010 commented May 18, 2025

It seems that all existing keywords defined in il_kywd.h have the same problem.
For example, this won't compile as well:

.assembly test {}
.module test.dll

.assembly extern System.Console { }
.assembly extern System.Runtime { }

.class private auto ansi beforefieldinit async
	extends [System.Runtime]System.Object
{
	.method private hidebysig static 
		void test (
			int32 lpstr
		) cil managed
	{
		.entrypoint
		ret
	}
}

because we have lpstr defined as a keyword in ilasm. You can also try using any keyword defined in il_kywd.h as an identifier, like to, any, date, arm, value, request etc, and they won't compile as well.

So I believe the correct fix is to take the breaking change here, and audit the existing IL code and correctly escape them. i.e. modifying all async to 'async' for places like dotnet/dotnet#544 (comment).

I would propose a fix that:

  1. Changing all identifiers that called async in existing IL code to 'async'
  2. Revert Revert "[RuntimeAsync] ilasm/ildasm support for the MethodImpl.Async" #115621

@jkotas
Copy link
Member

jkotas commented May 18, 2025

We still define async as a keyword, but allow it to appear as an identifier.
I found we have the same problem for all other MethodImpl attributes
Should I fix them as well? @jkotas

What's the problem with this solution?

It matches what Roslyn does. When C# introduces a new keyword, they do not break all code that happened to use this keyword as an identifier. They only break code where it introduces ambiguity. For example, public void Foo(int await) { } compiles fine even though await is a keyword.

We prefer option with less breaking changes when there are multiple equal options.

This PR does not need to solve it for all keywords. Switching just methodimpl related keywords to a less breaking plan is good enough for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-ILTools-coreclr community-contribution Indicates that the PR has been added by a community member runtime-async
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants