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

EnC: nint and nuint should be treated as equivalent to IntPtr and UIntPtr #48637

Open
tmat opened this issue Oct 15, 2020 · 1 comment
Open

Comments

@tmat
Copy link
Member

tmat commented Oct 15, 2020

Version Used:
Version 16.9.0 Preview 1.0 [30614.203.main]

Steps to Reproduce:

While debugging update:

class C
{
    public void F(nint x, nuint y) { }
}

to

class C
{
    public void F(IntPtr x, UIntPtr y) { }
}

Expected Behavior:

The edit should be allowed since the underlying representation of the types is the same.

Actual Behavior:

Rude edit is reported.

Also validate that symbol matcher considers these types the same (it should as they are the same symbols, but having tests would be good).

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added Area-Interactive untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 15, 2020
@jinujoseph jinujoseph added Bug and removed untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 15, 2020
@jinujoseph jinujoseph added this to the Backlog milestone Oct 15, 2020
@MulleDK19
Copy link

MulleDK19 commented Nov 8, 2020

I just ran into this exact thing while playing with C# 9.

Whether you use nint or IntPtr, the compiler correctly compiles both to the VES supported native int.
But when using nint the C# compiler uses the operations supported directly by the VES like the add and sub instructions.
But when using IntPtr, it calls op_Addition and op_Implicit on IntPtr.

This causes less efficient instructions by the JIT compiler.

private class Test
{
    public int X;

    [MethodImpl(MethodImplOptions.NoInlining)]
    public virtual void InitX()
    {
        this.X = 1337;
    }
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe static void FooBar(Test test)
{
    nint address = GetAddressFast(test); // &test
    nint testAddress = address;
    address = *(nint*)address;
    address = *(nint*)(address + 0x40); // Virtual function table.
    address = *(nint*)(address + 0x20); // Virtual function address.
    delegate*<nint, void> func = (delegate*<nint, void>)address;
    func(testAddress); // Call test.InitX()
}

This results in

sub         rsp,28h
call        Method stub for: Program.GetAddressFast(System.Object)
mov         rcx,qword ptr [rax]
mov         rcx,qword ptr [rcx+40h]
mov         rdx,qword ptr [rcx+20h]
mov         rcx,rax
call        rdx
nop
add         rsp,28h
ret

But when using IntPtr

private unsafe static void FooBar(Test test)
{
    IntPtr address = GetAddressFast(test); // &test
    IntPtr testAddress = address;
    address = *(IntPtr*)address;
    address = *(IntPtr*)(address + 0x40); // Virtual function table.
    address = *(IntPtr*)(address + 0x20); // Virtual function address.
    delegate*<nint, void> func = (delegate*<nint, void>)address;
    func(testAddress); // Call test.InitX();
}

It instead results in

sub         rsp,28h
call        Method stub for: Program.GetAddressFast(System.Object)
mov         rcx,qword ptr [rax]
add         rcx,40h
mov         rcx,qword ptr [rcx]
add         rcx,20h
mov         rdx,qword ptr [rcx]
mov         rcx,rax
call        rdx
nop
add         rsp,28h
ret

The JIT compiler is able to inline the op_Addition operator call, but call void* [System.Runtime]System.IntPtr::op_Explicit(native int) ruins the optimization.

IntPtr x = 0; also fails, while nint x = 0; doesn't, as well as the other operations.
Keywords also cannot be aliased, so there's no way to alias IntPtr, and use the native instructions.
Like int and System.Int32 both are aliases of the VES supported type int32 and behave the exact same way, so should nint and IntPtr (and nuint/UIntPtr).

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

No branches or pull requests

4 participants