1717#nullable enable
1818#pragma warning disable CS8500
1919
20- namespace Castle . DynamicProxy . Internal
20+ namespace Castle . DynamicProxy
2121{
2222 using System ;
2323 using System . ComponentModel ;
24+ using System . Diagnostics . CodeAnalysis ;
2425 using System . Threading ;
2526
27+ using Castle . DynamicProxy . Internal ;
28+
2629 // This file contains a set of `unsafe` types used at runtime by DynamicProxy proxies to represent by-ref-like values
2730 // in an `IInvocation`. Such values live exclusively on the evaluation stack and therefore cannot be boxed. Thus they are
2831 // in principle incompatible with `IInvocation` and we need to replace them with something else... namely these types here.
@@ -38,42 +41,46 @@ namespace Castle.DynamicProxy.Internal
3841 //
3942 // *) Unmanaged pointers can be safe when used to reference stack-allocated objects. However, that is only true
4043 // when they point into "live" stack frames. That is, they MUST NOT reference parameters or local variables
41- // of methods that have already finished executing. This is why we have the `ByRefLikeProxy .Invalidate` method:
42- // DynamicProxy (or whatever else instantiated a `ByRefLikeProxy ` object to point at a method parameter or local
44+ // of methods that have already finished executing. This is why we have the `ByRefLikeReference .Invalidate` method:
45+ // DynamicProxy (or whatever else instantiated a `ByRefLikeReference ` object to point at a method parameter or local
4346 // variable) must invoke this method before said method returns (or tail-calls).
4447 //
4548 // *) The `checkType` / `checkPtr` arguments of `GetPtr` or `Invalidate`, respectively, have two purposes:
4649 //
47- // 1. DynamicProxy, or whatever else instantiated a `ByRefLikeProxy `, is expected to know at all times what
50+ // 1. DynamicProxy, or whatever else instantiated a `ByRefLikeReference `, is expected to know at all times what
4851 // exactly each instance references. These parameters make it harder for anyone to use the type directly
4952 // if they didn't also instantiate it themselves.
5053 //
5154 // 2. `checkPtr` of `Invalidate` attempts to prevent re-use of a referenced storage location for another
52- // similarly-typed local variable by the JIT. DynamicProxy typically instantiates `ByRefLikeProxy ` instances
55+ // similarly-typed local variable by the JIT. DynamicProxy typically instantiates `ByRefLikeReference ` instances
5356 // at the start of intercepted method bodies, and it invokes `Invalidate` at the very end, meaning that
5457 // the address of the local/parameter is taken at each method boundary, meaning that static analysis should
5558 // never during the whole method see the local/parameter as "no longer in use". (This may be a little
5659 // paranoid, since the CoreCLR JIT probably exempts so-called "address-exposed" locals from reuse anyway.)
5760 //
5861 // *) Finally, we only ever access the unmanaged pointer field through `Volatile` or `Interlocked` to better guard
59- // against cases where someone foolishly copied a `ByRefLikeProxy ` instance out of the `IInvocation.Arguments`
62+ // against cases where someone foolishly copied a `ByRefLikeReference ` instance out of the `IInvocation.Arguments`
6063 // and uses it from another thread.
6164 //
62- // As far as I can reason, `ByRefLikeProxy ` et al. should be safe to use IFF they are never copied out from an
65+ // As far as I can reason, `ByRefLikeReference ` et al. should be safe to use IFF they are never copied out from an
6366 // `IInvocation`, and IFF DynamicProxy succeeds in destructing them and erasing them from the `IInvocation` right
6467 // before the intercepted method finishes executing.
6568
6669 /// <summary>
67- /// Do not use! Only DynamicProxy internals may interact with this class type directly .
70+ /// Do not use! This type should only be used by DynamicProxy internals .
6871 /// </summary>
69- [ CLSCompliant ( false ) ]
7072 [ EditorBrowsable ( EditorBrowsableState . Never ) ]
71- public unsafe class ByRefLikeProxy
73+ public unsafe class ByRefLikeReference
7274 {
7375 private readonly Type type ;
7476 private nint ptr ;
7577
76- public ByRefLikeProxy ( Type type , void * ptr )
78+ /// <summary>
79+ /// Do not use! This constructor should only be called by DynamicProxy internals.
80+ /// </summary>
81+ [ CLSCompliant ( false ) ]
82+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
83+ public ByRefLikeReference ( Type type , void * ptr )
7784 {
7885 if ( type . IsByRefLikeSafe ( ) == false )
7986 {
@@ -89,6 +96,11 @@ public ByRefLikeProxy(Type type, void* ptr)
8996 this . ptr = ( nint ) ptr ;
9097 }
9198
99+ /// <summary>
100+ /// Do not use! This method should only be called by DynamicProxy internals.
101+ /// </summary>
102+ [ CLSCompliant ( false ) ]
103+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
92104 public void * GetPtr ( Type checkType )
93105 {
94106 if ( checkType != type )
@@ -111,6 +123,11 @@ public ByRefLikeProxy(Type type, void* ptr)
111123 return ptr ;
112124 }
113125
126+ /// <summary>
127+ /// Do not use! This method should only be called by DynamicProxy internals.
128+ /// </summary>
129+ [ CLSCompliant ( false ) ]
130+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
114131 public void Invalidate ( void * checkPtr )
115132 {
116133 var ptr = ( void * ) Interlocked . CompareExchange ( ref this . ptr , ( nint ) null , ( nint ) checkPtr ) ;
@@ -124,15 +141,29 @@ public void Invalidate(void* checkPtr)
124141
125142#if NET9_0_OR_GREATER
126143 /// <summary>
127- /// Access instances of this type through the public-facing <see cref="IByRefLikeProxy{TByRefLike}"/> interface.
128- /// Only DynamicProxy internals may interact with this class type directly.
144+ /// Permits indirect access to by-ref-like argument values during method interception.
129145 /// </summary>
130- [ CLSCompliant ( false ) ]
131- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
132- public unsafe class ByRefLikeProxy < TByRefLike > : ByRefLikeProxy , IByRefLikeProxy < TByRefLike >
146+ /// <remarks>
147+ /// Instances of by-ref-like (<c>ref struct</c>) types live exclusively on the evaluation stack.
148+ /// Therefore, they cannot be boxed and put into the <see langword="object"/>-typed <see cref="IInvocation.Arguments"/> array.
149+ /// DynamicProxy replaces these unboxable values with <see cref="ByRefLikeReference{TByRefLike}"/> references
150+ /// (or, in the case of spans, with <see cref="SpanReference{T}"/> or <see cref="ReadOnlySpanReference{T}"/>),
151+ /// which grant you indirect read/write access to the actual values.
152+ /// <para>
153+ /// These references are only valid for the duration of the intercepted method call.
154+ /// Any attempt to use it beyond that will result in a <see cref="AccessViolationException"/>.
155+ /// </para>
156+ /// </remarks>
157+ /// <typeparam name="TByRefLike">A by-ref-like (<c>ref struct</c>) type.</typeparam>
158+ public unsafe class ByRefLikeReference < TByRefLike > : ByRefLikeReference
133159 where TByRefLike : struct , allows ref struct
134160 {
135- public ByRefLikeProxy ( Type type , void * ptr )
161+ /// <summary>
162+ /// Do not use! This constructor should only be called by DynamicProxy internals.
163+ /// </summary>
164+ [ CLSCompliant ( false ) ]
165+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
166+ public ByRefLikeReference ( Type type , void * ptr )
136167 : base ( type , ptr )
137168 {
138169 if ( type != typeof ( TByRefLike ) )
@@ -151,26 +182,33 @@ public ref TByRefLike Value
151182 }
152183#endif
153184
154- #if ! NET9_0_OR_GREATER
155- /// <summary>
156- /// Access instances of this type through the public-facing <see cref="IReadOnlySpanProxy{T}"/> interface.
157- /// Only DynamicProxy internals may interact with this class type directly.
158- /// </summary>
159- #else
160185 /// <summary>
161- /// Access instances of this type through either of the public-facing
162- /// <see cref="IReadOnlySpanProxy{T}"/> or <see cref="IByRefLikeProxy{TByRefLike}"/> interfaces.
163- /// Only DynamicProxy internals may interact with this class type directly.
186+ /// Permits indirect access to <see cref="ReadOnlySpan{T}"/>-typed argument values during method interception.
164187 /// </summary>
165- #endif
166- [ CLSCompliant ( false ) ]
167- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
168- public unsafe class ReadOnlySpanProxy < T > : ByRefLikeProxy , IReadOnlySpanProxy < T >
188+ /// <remarks>
189+ /// <see cref="ReadOnlySpan{T}"/> is a by-ref-like (<c>ref struct</c>) type, which means that
190+ /// instances of it live exclusively on the evaluation stack. Therefore, they cannot be boxed
191+ /// and put into the <see langword="object"/>-typed <see cref="IInvocation.Arguments"/> array.
192+ /// DynamicProxy replaces these unboxable values with instances of <see cref="ReadOnlySpanReference{T}"/>,
193+ /// which grant you indirect read/write access to the actual value.
194+ /// <para>
195+ /// These references are only valid for the duration of the intercepted method call.
196+ /// Any attempt to use it beyond that will result in a <see cref="AccessViolationException"/>.
197+ /// </para>
198+ /// </remarks>
199+ public unsafe class ReadOnlySpanReference < T >
169200#if NET9_0_OR_GREATER
170- , IByRefLikeProxy < ReadOnlySpan < T > >
201+ : ByRefLikeReference < ReadOnlySpan < T > >
202+ #else
203+ : ByRefLikeReference
171204#endif
172205 {
173- public ReadOnlySpanProxy ( Type type , void * ptr )
206+ /// <summary>
207+ /// Do not use! This constructor should only be called by DynamicProxy internals.
208+ /// </summary>
209+ [ CLSCompliant ( false ) ]
210+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
211+ public ReadOnlySpanReference ( Type type , void * ptr )
174212 : base ( type , ptr )
175213 {
176214 if ( type != typeof ( ReadOnlySpan < T > ) )
@@ -179,35 +217,44 @@ public ReadOnlySpanProxy(Type type, void* ptr)
179217 }
180218 }
181219
220+ #if ! NET9_0_OR_GREATER
182221 public ref ReadOnlySpan < T > Value
183222 {
184223 get
185224 {
186225 return ref * ( ReadOnlySpan < T > * ) GetPtrNocheck ( ) ;
187226 }
188227 }
228+ #endif
189229 }
190230
191- #if ! NET9_0_OR_GREATER
192- /// <summary>
193- /// Access instances of this type through the public-facing <see cref="ISpanProxy{T}"/> interface.
194- /// Only DynamicProxy internals may interact with this class type directly.
195- /// </summary>
196- #else
197231 /// <summary>
198- /// Access instances of this type through either of the public-facing
199- /// <see cref="ISpanProxy{T}"/> or <see cref="IByRefLikeProxy{TByRefLike}"/> interfaces.
200- /// Only DynamicProxy internals may interact with this class type directly.
232+ /// Permits indirect access to <see cref="Span{T}"/>-typed argument values during method interception.
201233 /// </summary>
202- #endif
203- [ CLSCompliant ( false ) ]
204- [ EditorBrowsable ( EditorBrowsableState . Never ) ]
205- public unsafe class SpanProxy < T > : ByRefLikeProxy , ISpanProxy < T >
234+ /// <remarks>
235+ /// <see cref="Span{T}"/> is a by-ref-like (<c>ref struct</c>) type, which means that
236+ /// instances of it live exclusively on the evaluation stack. Therefore, they cannot be boxed
237+ /// and put into the <see langword="object"/>-typed <see cref="IInvocation.Arguments"/> array.
238+ /// DynamicProxy replaces these unboxable values with instances of <see cref="SpanReference{T}"/>,
239+ /// which grant you indirect read/write access to the actual value.
240+ /// <para>
241+ /// These references are only valid for the duration of the intercepted method call.
242+ /// Any attempt to use it beyond that will result in a <see cref="AccessViolationException"/>.
243+ /// </para>
244+ /// </remarks>
245+ public unsafe class SpanReference < T >
206246#if NET9_0_OR_GREATER
207- , IByRefLikeProxy < Span < T > >
247+ : ByRefLikeReference < Span < T > >
248+ #else
249+ : ByRefLikeReference
208250#endif
209251 {
210- public SpanProxy ( Type type , void * ptr )
252+ /// <summary>
253+ /// Do not use! This constructor should only be called by DynamicProxy internals.
254+ /// </summary>
255+ [ CLSCompliant ( false ) ]
256+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
257+ public SpanReference ( Type type , void * ptr )
211258 : base ( type , ptr )
212259 {
213260 if ( type != typeof ( Span < T > ) )
@@ -216,13 +263,15 @@ public SpanProxy(Type type, void* ptr)
216263 }
217264 }
218265
266+ #if ! NET9_0_OR_GREATER
219267 public ref Span < T > Value
220268 {
221269 get
222270 {
223271 return ref * ( Span < T > * ) GetPtrNocheck ( ) ;
224272 }
225273 }
274+ #endif
226275 }
227276}
228277
0 commit comments