You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A lib fun can take a @[CallConvention] annotation, which tells it to use a non-default calling convention, such as X86_StdCall. A lib itself can also take it, in which case all its funs will use that convention unless otherwise annotated. But this only concerns calling the funs themselves, and there is no such thing for fun parameters and return values. This means it is undefined behavior to deal with those functions across lib boundaries:
# compile with `crystal build --target=i386-windows-msvc --prelude=empty --static`classStringdefto_unsafepointerof(@c)
endend
@[Link("legacy_stdio_definitions")]
libLibCfunprintf(fmt : UInt8*, ...) : Int32funexit(status : Int32) : NoReturnenddefraise(msg)
LibC.printf("Unhandled exception: %s\n", msg)
LibC.exit(1)
end
@[Link(ldflags:"#{__DIR__}/ext.obj")]
libLibFooaliasCallback=Int32, Int32, Int32, Int32, Int32->Int32funfoo(cb : Callback) : Int32
fun bar : Callbackend# prints garbage
f =LibFoo.bar
LibC.printf("%d", f.call(1, 2, 3, 4, 5))
# Exception 0xc0000005 encountered at address 0x000002:# User-mode data execution prevention (DEP) violation at location 0x00000002
f2 =->(a : Int32, b : Int32, c : Int32, d : Int32, e : Int32) : Int32 { a &+ b &+ c &+ d &+ e }
LibC.printf("%d", LibFoo.foo(f2))
This directly blocks x86 Windows support, as the Win32 API uses X86_StdCall for everything, including callbacks: (for x86-64 this call convention is accepted and ignored, which is why stdlib doesn't need it currently)
/* consoleapi.h etc. */#defineWINAPI __stdcall
typedefBOOL (WINAPI*PHANDLER_ROUTINE)(DWORDCtrlType);
__declspec(dllimport) BOOLWINAPISetConsoleCtrlHandler(PHANDLER_ROUTINEHandlerRoutine, BOOLAdd);
There are no relevant non-default calling conventions for x86-64. (It seems MSVC has __vectorcall for both x86 and x86-64, but LLVM doesn't appear to implement the latter.) For other platforms there are AArch64_VectorCall and WASM_EmscriptenInvoke; @[CallConvention] doesn't support them yet.
To avoid attaching calling conventions to types themselves, we could extend the lib syntax to allow annotations for parameter and return types, similar to defs:
libLibFoofunfoo(@[CallConvention("X86_StdCall")] cb : Callback) : Int32
fun bar : @[CallConvention("X86_StdCall")] Callbackend
Though I don't really know how all of this could work at the codegen level without storing each Proc's calling convention dynamically.
The text was updated successfully, but these errors were encountered:
To avoid attaching calling conventions to types themselves
Why would you want to avoid that? In the C headers, its also attached to the function type, right? So I figure it would make sense to do the same in Crystal lib definition.
That means if you want to call the same function signature with different calling conventions, you'll need to define separate proc types for that. I don't see how this could be a problem, though.
Maybe we could allow the alias to "carry" a @[CallConvention] annotation that is only meaningful in those lib fun contexts. What I mean is that IMO we should strive to avoid making Callback an entirely different Crystal type from Proc because that would be quite a significant breaking change.
But if alias means more than just a different name, it would also be quite a change.
I think this needs to go on the Proc type itself. This could work based on just an annotation, meaning @[CallingConventionA] Proc(Int) is a different type from Proc(Int).
However, maybe an optional generic type argument would be better suited for that? Proc(Int, calling_convention: CallingConventionA)
A lib fun can take a
@[CallConvention]
annotation, which tells it to use a non-default calling convention, such asX86_StdCall
. A lib itself can also take it, in which case all its funs will use that convention unless otherwise annotated. But this only concerns calling the funs themselves, and there is no such thing for fun parameters and return values. This means it is undefined behavior to deal with those functions across lib boundaries:This directly blocks x86 Windows support, as the Win32 API uses
X86_StdCall
for everything, including callbacks: (for x86-64 this call convention is accepted and ignored, which is why stdlib doesn't need it currently)There are no relevant non-default calling conventions for x86-64. (It seems MSVC has
__vectorcall
for both x86 and x86-64, but LLVM doesn't appear to implement the latter.) For other platforms there areAArch64_VectorCall
andWASM_EmscriptenInvoke
;@[CallConvention]
doesn't support them yet.To avoid attaching calling conventions to types themselves, we could extend the lib syntax to allow annotations for parameter and return types, similar to defs:
Though I don't really know how all of this could work at the codegen level without storing each
Proc
's calling convention dynamically.The text was updated successfully, but these errors were encountered: