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

Unmanaged calli not supported with generic arguments #9136

Closed
ThadHouse opened this issue Oct 16, 2017 · 12 comments · Fixed by #97079
Closed

Unmanaged calli not supported with generic arguments #9136

ThadHouse opened this issue Oct 16, 2017 · 12 comments · Fixed by #97079

Comments

@ThadHouse
Copy link
Contributor

I am trying to write a cross platform library that interops with native code, and was planning on using raw IL and the calli instruction to call into my native functions, to allow me to at runtime select the native library to load. I have used this in the past, where I would create individual shim functions for every call, and this worked. However, I was thinking, and reading through the IL spec it seems like it should be allowed, to just build some generic template to handle this code for me. However, when attempting to use calli with generic I receive a BadImageFormatException: Bad element type in SizeOf exception when the JIT attempts to compile the code. It seems like this should work, which makes it seem like a bug in the JIT. Below is both the generic code that seems like it should work, and also the same code without generics that does work.

	.method public static !!T Invoke<T, T2>(native int func, !!T2 val) cil managed
	{
		ldarg.1
		ldarg.0
		calli unmanaged cdecl !!0(!!1)
		ret
	}

I am calling the above with T as long, and T2 as int.

	.method public static int64 Invoke(native int func, int32 val) cil managed
	{
		ldarg.1
		ldarg.0
		calli unmanaged cdecl int64(int32)
		ret
	}
@jkotas
Copy link
Member

jkotas commented Oct 16, 2017

Unmanaged calli is not supported with generic arguments. It is the same underlying reasons why DllImport is not supported with generics.

@jkotas jkotas changed the title Bad element type in SizeOf with generic calli instruction Unmanaged calli not supported with generic arguments Nov 9, 2017
@sakno
Copy link
Contributor

sakno commented Nov 26, 2019

I see that this pull request allows to use blittable types. Is it applicable to calli instruction as well?

@jkotas
Copy link
Member

jkotas commented Nov 26, 2019

Yes, the same rules should apply to calli.

@sakno
Copy link
Contributor

sakno commented Nov 26, 2019

So it is expected in .NET Core 3.1, right?

@jkotas
Copy link
Member

jkotas commented Nov 26, 2019

No, .NET Core 3.1 is "done" for a while. All features we have been working on for last several months are for .NET 5.

@hez2010
Copy link
Contributor

hez2010 commented Apr 25, 2022

Any plan to make it in .NET 7?

@KirillAldashkin
Copy link

I think this problem should be revisited, since function pointers can now be used in pure C# (unsafe delegate*<> from C# 9.0).

unsafe TRet Invoke<TArg, TRet>(nint function, TArg arg)
{
    var ptr = (delegate* unmanaged<TArg, TRet>)function;
    return ptr(arg);
}

@jkotas
Copy link
Member

jkotas commented Sep 13, 2023

Should we enable the unmanaged calli when the assembly has DisableRuntimeMarshallingAttribute? It should be much easier to implement and explain the behavior when the runtime marshalling is out of the picture.

@jkotas
Copy link
Member

jkotas commented Sep 13, 2023

https://github.com/microsoft/CsWinRT can use this.

cc @manodasanW

@jkotas jkotas modified the milestones: Future, 9.0.0 Sep 13, 2023
@jkoritzinsky
Copy link
Member

Should we enable the unmanaged calli when the assembly has DisableRuntimeMarshallingAttribute? It should be much easier to implement and explain the behavior when the runtime marshalling is out of the picture.

That would definitely be an interesting proposition. I think CsWinRT might also need/want #55144 with the same restrictions if we can do that. This is definitely the easier side to implement though and would be useful on its own.

@hez2010
Copy link
Contributor

hez2010 commented Dec 26, 2023

I hit this while trying to use the below helper method to implement ComWrappers in AvaloniaUI/Avalonia#13924

public static T InvokeAndGet<T>(void* @this, int vtblSlot) where T : unmanaged
{
    T ret;
    int hr = ((delegate* unmanaged<void*, T*, int>)(*(*(void***)@this + vtblSlot)))(@this, &ret);

    if (hr != 0)
        Marshal.ThrowExceptionForHR(hr);

    return ret;
}

@MichalPetryka
Copy link
Contributor

I hit this while trying to use the below helper method to implement ComWrappers in AvaloniaUI/Avalonia#13924

public static T InvokeAndGet<T>(void* @this, int vtblSlot) where T : unmanaged
{
    T ret;
    int hr = ((delegate* unmanaged<void*, T*, int>)(*(*(void***)@this + vtblSlot)))(@this, &ret);

    if (hr != 0)
        Marshal.ThrowExceptionForHR(hr);

    return ret;
}

With pointer args like this, you can just cast to void* on call.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jan 17, 2024
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Feb 22, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Mar 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

9 participants