dotnet / runtimelab

This repo is for experimentation and exploring new ideas that may or may not make it into the main dotnet/runtime repo.
MIT License
1.43k stars 200 forks source link

[NativeAOT-LLVM, Wasm] Cannot marshal struct containing an array #2234

Closed RReverser closed 1 year ago

RReverser commented 1 year ago

Minimal repro:

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
    [MarshalAs(UnmanagedType.LPArray)]
    public byte[] bytes;
}

[DllImport("*")]
public static extern void pass_custom_struct(MyStruct s);

...

pass_custom_struct(new MyStruct {
    bytes = new byte[] { 1, 2, 3 }
});

Results in:

EXEC : warning : Method `[S.P.CompilerGenerated]Internal.CompilerGenerated.<Module>.ManagedToNative__MyStruct(MyS
truct&,__NativeType__MyStruct&)` will always throw because: Failed to load type 'Byte[]' from assembly '?' [C:\Us 
ers\me\Documents\NativeAOTWasm\helloworld\helloworld.csproj]
RReverser commented 1 year ago

Following #2233, I thought this one might be fixed in 8.0.0-* previews as well, so rechecked, but it still fails, albeit with different error messages:

EXEC : error : Code generation failed for method '[minisample]Lib.pass_custom_struct(MyStruct)' [C:\User
s\me\Documents\minisample\minisample.csproj]
  ILCompiler.CodeGenerationFailedException: Code generation failed for method '[minisample]Lib.pass_cust
  om_struct(MyStruct)'
     at Internal.JitInterface.CorInfoImpl.CompileMethodInternal(IMethodNode, MethodIL) in /_/src/coreclr 
  /tools/Common/JitInterface/CorInfoImpl.cs:line 410
     at Internal.JitInterface.CorInfoImpl.CompileMethod(IMethodCodeNode, MethodIL ) in /_/src/coreclr/to 
  ols/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs:line 63
     at ILCompiler.LLVMCodegenCompilation.CompileSingleMethod(CorInfoImpl, LLVMMethodCodeNode) in /_/src 
  /coreclr/tools/aot/ILCompiler.LLVM/Compiler/LLVMCodegenCompilation.cs:line 145
     at ILCompiler.LLVMCodegenCompilation.CompileSingleThreaded(List`1) in /_/src/coreclr/tools/aot/ILCo 
  mpiler.LLVM/Compiler/LLVMCodegenCompilation.cs:line 129
     at ILCompiler.LLVMCodegenCompilation.ComputeDependencyNodeDependencies(List`1) in /_/src/coreclr/to 
  ols/aot/ILCompiler.LLVM/Compiler/LLVMCodegenCompilation.cs:line 106
     at ILCompiler.DependencyAnalysisFramework.DependencyAnalyzer`2.ComputeMarkedNodes() in /_/src/corec 
  lr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs:line 315
     at ILCompiler.LLVMCodegenCompilation.CompileInternal(String, ObjectDumper) in /_/src/coreclr/tools/ 
  aot/ILCompiler.LLVM/Compiler/LLVMCodegenCompilation.cs:line 73
     at ILCompiler.Compilation.ILCompiler.ICompilation.Compile(String, ObjectDumper) in /_/src/coreclr/t 
  ools/aot/ILCompiler.Compiler/Compiler/Compilation.cs:line 529
     at ILCompiler.Program.Run(String[]) in /_/src/coreclr/tools/aot/ILCompiler/Program.cs:line 996      
     at ILCompiler.Program.Main(String[]) in /_/src/coreclr/tools/aot/ILCompiler/Program.cs:line 1188    
C:\Users\me\Documents\minisample\.packages\microsoft.dotnet.ilcompiler.llvm\8.0.0-alpha.1.23170.1\build\
Microsoft.NETCore.Native.targets(307,5): error MSB3073: The command ""C:\Users\me\Documents\minisample\. 
packages\runtime.win-x64.microsoft.dotnet.ilcompiler.llvm\8.0.0-alpha.1.23170.1\tools\\ilc" @"obj\Debug\
net7.0\browser-wasm\native\minisample.ilc.rsp"" exited with code 1. [C:\Users\me\Documents\minisample\mi 
nisample.csproj]

cc @SingleAccretion

SingleAccretion commented 1 year ago

This is supposed to have been fixed with #2220.

RReverser commented 1 year ago

"merged 3 hours ago" love living on the edge 😅 Okay, I'll recheck when that's out.

Btw, just to be sure based on the title of the PR alone - Pass structs by reference in accordance with the WASM C ABI - you mean only for structs with >1 field, right? Because structs with 1 field like in my example still need to be passed as their inner value.

SingleAccretion commented 1 year ago

Btw, just to be sure based on the title of the PR alone - Pass structs by reference in accordance with the WASM C ABI - you mean only for structs with >1 field, right? Because structs with 1 field like in my example still need to be passed as their inner value.

That is correct. I suspect the failure here is because the code used to (explicitly) block any struct arguments for PInvokes.

RReverser commented 1 year ago

"merged 3 hours ago" love living on the edge 😅 Okay, I'll recheck when that's out.

Ah I see 8.0.0-alpha.1.23172.1 is already published; just tried and it doesn't crash.