@@ -3,127 +3,66 @@ title: LLVM-C Handle Wrappers
33---
44
55## LLVM-C Handle wrappers
6-
7- Handles for LLVM are just opaque pointers. They generally come in one of three forms.
6+ ?Handles? for LLVM are just opaque pointers. They generally come in one of three forms.
87
98 1 . Context owned
109 Where there is always a well known owner that ultimately is responsible for
1110 disposing/releasing the resource.
1211 2 . Global resources
13- Where there is no parent child ownership relationship and callers must manually release the resource
12+ Where there is no parent child ownership relationship and callers must manually release
13+ the resource.
1414 3 . An unowned alias to a global resource
1515 This occurs when a child of a global resource contains a reference to the parent. In such
1616 a case the handle should be considered like an alias and not disposed.
1717
18- The Handle implementations in Ubiquity.NET.Llvm follow consistent patterns for implementing each form of handle.
19-
20- ### Contextual handles
21-
22- These handles are never manually released or disposed, though releasing their containers will make them
23- invalid. The general pattern for implementing such handles is as follows:
24-
25- ``` C#
26- using System ;
27- using System .Collections .Generic ;
28-
29- namespace Ubiquity .NET .Llvm .Native
30- {
31- internal struct LLVMxyzRef
32- : IEquatable <LLVMxyzRef >
33- {
34- public override int GetHashCode ( ) => Handle .GetHashCode ( );
35-
36- public override bool Equals ( object obj )
37- => ! ( obj is null )
38- && ( obj is LLVMxyxRef r )
39- && ( r .Handle == Handle );
40-
41- public bool Equals ( LLVMxyxRef other )
42- => Handle == other .Handle ;
43-
44- public static bool operator == ( LLVMxyxRef lhs , LLVMxyxRef rhs )
45- => EqualityComparer <LLVMxyxRef >.Default .Equals ( lhs , rhs );
46-
47- public static bool operator != ( LLVMxyxRef lhs , LLVMxyxRef rhs )
48- => ! ( lhs == rhs );
49-
50- internal LLVMxyxRef ( IntPtr pointer )
51- {
52- Handle = pointer ;
53- }
54-
55- private readonly IntPtr Handle ;
56- }
57- }
58- ```
18+ The Handle implementations in Ubiquity.NET.Llvm follow consistent patterns for implementing
19+ each form of handle. All handle types are generated from the native C++ headers. Thus they are
20+ a source only NuGet package built along with the native extended C API library. The generated
21+ sources are not useful outside of the ` Ubiquity.NET.Llvm.Interop ` as they use classes within
22+ that as a base class. Ultimately, the handles are reduced to two forms:
23+ 1 ) Requires caller to release them
24+ - Lifetime of the thing the handle refers to is controlled by the caller
25+ - Release is implemented by standard .NET pattern with [ IDisposable] ( xref:System.IDisposable )
26+ 2 ) Does NOT require any dispose
27+ - Lifetime of the thing the handle refers to is controlled by the container
28+
29+ > [ !NOTE]
30+ > The use of code generation for the handles in a different repo is a bit fragile as the
31+ > generated handles are derived from and depend on support in a different consuming repository.
32+ > This is a result of the historical split of the native code libraries. The build of that,
33+ > takes a MUCH longer time AND requires distinct runners for each RID supported. While there is
34+ > thinking about how to unify these repositories that isn't done yet as the focus is on getting
35+ > the support for LLVM20.x and especially the JIT support. [ It's been a long run with LLVM10 as
36+ > the only option.]
37+
38+ ### Contextual handles and Aliases
39+ These handles are never manually released or disposed, though releasing their containers will
40+ make them invalid. The general pattern for implementing such handles is to use a generated
41+ struct that is marked as implementing the ` IContextHandle<THandle> ` interface. This interface
42+ is ONLY used during marshalling where the concreted type ` THandle ` is known and therefore does
43+ NOT require any boxing. The struct is essentially a strongly typed alias for an nint value.
44+ Contiguous sequences of these handles are re-interpret castable to a sequence of nint. (The
45+ interop support uses this for efficient marshalling of arrays.)
5946
6047### Global Handles
61- Global handles require the caller to explicitly release the resources. In Ubiquity.NET.Llvm these
62- are managed with the .NET SafeHandles types through an Ubiquity.NET.Llvm specific derived type
63- LlvmObject. Since these types are derived from a SafeHandle they are properly cleaned
64- up by the runtime without the need to make the containing type implement IDisposable,
65- though there may be other reasons to make a type Disposable. Generally, types should
66- avoid IDisposable unless they really need to perform some special cleanup early or in
67- a particular ordered sequence but such cases are rare.
68-
69- All resource handles in Ubiquity.NET.Llvm requiring explicit release are handled consistently
70- using the following basic pattern:
71-
72- ``` C#
73- using System ;
74- using System .Runtime .InteropServices ;
75- using System .Security ;
76-
77- using static Ubiquity .NET .Llvm .Native .NativeMethods ;
78-
79- namespace Ubiquity .NET .Llvm .Native
80- {
81- [SecurityCritical ]
82- internal class LLVMxyzRef
83- : LlvmObjectRef
84- {
85- public LLVMxyzRef ( IntPtr handle , bool owner )
86- : base ( owner )
87- {
88- SetHandle ( handle );
89- }
90-
91- [SecurityCritical ]
92- protected override bool ReleaseHandle ( )
93- {
94- LLVMDisposeXyz ( handle );
95- return true ;
96- }
48+ Global handles require the caller to explicitly release the resources. In
49+ Ubiquity.NET.Llvm.Interop these are managed with the .NET [ SafeHandle] ( xref:System.Runtime.InteropServices.SafeHandle )
50+ types through an LLVM interop specific derived type ` GlobalHandleBase ` . Since these types are
51+ derived from a ` SafeHandle ` they are cleaned up with the standard .NET [ IDisposable] ( xref:System.IDisposable ) .
9752
98- private LLVMxyzRef ( )
99- : base ( true )
100- {
101- }
53+ All resource handles in ` Ubiquity.NET.Llvm,Interop ` requiring explicit release are handled consistently
54+ using the generated handle types as a distinct type derived from ` GlobalHandleBase `
10255
103- [DllImport ( LibraryPath , CallingConvention = CallingConvention .Cdecl )]
104- private static extern void LLVMDisposeXyz ( IntPtr @xyz );
105- }
106- }
107- ```
56+ Global handles that also have an alias include a declaration of the alias type and allow
57+ conversion to the unowned form of the handle.
10858
10959### Global Alias handles
110- Global alias handles are a specialized form of global handles where they do not
111- participate in ownership control/release. These are commonly used when a child
112- of a global container exposes a property that references the parent container.
113- In such cases the reference retrieved from the child shouldn't be used to destroy
114- the parent when no longer used.
60+ Global alias handles are a specialized form of global handles where they do not participate in
61+ ownership control/release. These are commonly used when a child of a global container exposes
62+ a property that references the parent container. In such cases the reference retrieved from the
63+ child shouldn't be used to destroy the parent when no longer used.
11564
116- In Ubiquity.NET.Llvm this is represented as a distinct handle type derived from the global
117- handle as follows:
65+ In Ubiquity.NET.Llvm.Interop this is represented as an unowned context handle, that is alias
66+ handles are the same as a context handle. There is no way to convert from an unowned alias to
67+ an owned global handle (The other way around is allowed and supported)
11868
119- ``` C#
120- // xyz alias
121- internal class LLVMxyzAlias
122- : LLVMxyzRef
123- {
124- private LLVMxyzAlias ()
125- : base ( IntPtr .Zero , false )
126- {
127- }
128- }
129- ```
0 commit comments