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

InvalidOperationException getting type member offset on Unix platforms using .Net Core 2.1.X or higher #116

Closed
adamreeve opened this issue May 20, 2020 · 3 comments
Assignees
Labels
workaround required Incompatibility with a particular platform that is not a bug in principle
Milestone

Comments

@adamreeve
Copy link
Contributor

adamreeve commented May 20, 2020

When running ILGPU.Tests.CPU on Linux (Ubuntu 20.04 in WSL with dotnet SDK 3.1.202 and runtime 2.1.18) I get the following error:

The active test run was aborted. Reason: Test host process crashed : Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. ---> System.ArgumentException: Type 'ILGPU.ArrayView`2[System.Int32,ILGPU.Index1]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
   at System.Runtime.InteropServices.Marshal.OffsetOfHelper(IRuntimeFieldInfo f)
       at ILGPU.IR.Types.TypeInformationManager.<>c__DisplayClass9_0.<CreateCompoundTypeInfo>b__0(FieldInfo left, FieldInfo right) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/TypeInformationManager.cs:line 325
          at System.Collections.Generic.ArraySortHelper`1.SwapIfGreater(T[] keys, Comparison`1 comparer, Int32 a, Int32 b)
       at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, Comparison`1 comparer)
       --- End of inner exception stack trace ---
          at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, Comparison`1 comparer)
       at ILGPU.IR.Types.TypeInformationManager.CreateCompoundTypeInfo(Type type) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/TypeInformationManager.cs:line 323
          at ILGPU.IR.Types.TypeInformationManager.CreateTypeInfo(Type type) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/TypeInformationManager.cs:line 307
             at ILGPU.IR.Types.TypeInformationManager.GetTypeInfo(Type type) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/TypeInformationManager.cs:line 229
                at ILGPU.IR.Types.IRTypeContext.CreateTypeInternal(Type type, MemoryAddressSpace addressSpace) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/IRTypeContext.cs:line 386
                   at ILGPU.IR.Types.IRTypeContext.CreateType(Type type, MemoryAddressSpace addressSpace) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/IRTypeContext.cs:line 279
                      at ILGPU.IR.IRContext.CreateType(Type type, MemoryAddressSpace addressSpace) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Types/IRContext.Types.cs:line 105
                         at ILGPU.IR.Construction.IRBuilder.CreateType(Type type, MemoryAddressSpace addressSpace) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Construction/Types.cs:line 89
                            at ILGPU.IR.Construction.IRBuilder.CreateType(Type type) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/IR/Construction/Types.cs:line 80
                               at ILGPU.Frontend.CodeGenerator.SetupVariables() in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs:line 140
                                  at ILGPU.Frontend.CodeGenerator..ctor(ILFrontend frontend, Builder methodBuilder, DisassembledMethod disassembledMethod, HashSet`1 detectedMethods) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/Frontend/CodeGenerator/CodeGenerator.cs:line 67
                                     at ILGPU.Frontend.CodeGenerationPhase.GenerateCodeInternal(MethodBase method, Boolean isExternalRequest, HashSet`1 detectedMethods, Method& generatedMethod) in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/Frontend/ILFrontend.cs:line 414
                                        at ILGPU.Frontend.ILFrontend.DoWork() in /mnt/c/Users/adree/gr/ILGPU/Src/ILGPU/Frontend/ILFrontend.cs:line 163
                                           at System.Threading.Thread.ThreadMain_ThreadStart()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

This is failing because TypeInformationManager.CreateCompoundTypeInfo is trying to get the offsets of fields for ArrayView, but this contains an abstract ArrayViewSource member which cannot be marshaled. There's a related GitHub issue at dotnet/runtime#7961.

All the CPU tests pass if I change CreateCompoundTypeInfo so it orders by the member MetadataToken:

private TypeInformation CreateCompoundTypeInfo(Type type)
{
    var fieldArray = type.GetFields(
        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    Array.Sort(fieldArray, (left, right) => left.MetadataToken.CompareTo(right.MetadataToken));
    ...
}

But I'm not sure what the implications for this are and whether it's required that the field ordering matches the unmanaged offsets.

@m4rs-mt
Copy link
Owner

m4rs-mt commented May 20, 2020

@adamreeve Thank you for submitting this issue. Unfortunately I am aware of this limitation at the moment. This problem also occurs on Windows and MacOs when you use ValueTuple<T> instances that are not annotated with the StructLayout attribute. This has been requested by many different users in the past. I have been thinking about several ways to work around this limitation (including the ones you just mentioned). However, it is a hard limitation that the order of the fields matches the order in the structure, since the internal code generation magic is based on the order of these fields.

However, it can be argued that this is to be expected as an exception in general, as this type cannot be properly marshalled. If we can make sure that the order of the fields matches the order the programmer originally defined, everything should be fine. I have also found other posts that suggest this as a valid workaround.

@m4rs-mt m4rs-mt added this to the v0.8.1 milestone May 20, 2020
@m4rs-mt m4rs-mt added the workaround required Incompatibility with a particular platform that is not a bug in principle label May 20, 2020
@m4rs-mt
Copy link
Owner

m4rs-mt commented May 27, 2020

I have just received additional feedback that the same problem occurs on MacOS with .Net Core 2.1.X and higher.

@m4rs-mt m4rs-mt changed the title InvalidOperationException getting type member offset on Linux InvalidOperationException getting type member offset on Unix platforms using .Net Core 2.1.X or higher May 27, 2020
@m4rs-mt
Copy link
Owner

m4rs-mt commented Jun 2, 2020

I have tested several possible layout/OS configurations and can currently confirm that the approach to sort fields by their MetadataToken seems to work (more information about this approach can be found here).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
workaround required Incompatibility with a particular platform that is not a bug in principle
Projects
None yet
Development

No branches or pull requests

2 participants