@@ -488,15 +488,41 @@ public static IntPtr AllocateTypeAssociatedMemory(Type type, int size)
488488 private static partial IntPtr AllocateTypeAssociatedMemory ( QCallTypeHandle type , uint size ) ;
489489
490490 [ MethodImpl ( MethodImplOptions . InternalCall ) ]
491- private static extern IntPtr AllocTailCallArgBufferWorker ( int size , IntPtr gcDesc ) ;
491+ private static extern unsafe TailCallArgBuffer * GetTailCallArgBuffer ( ) ;
492492
493- private static IntPtr AllocTailCallArgBuffer ( int size , IntPtr gcDesc )
493+ [ LibraryImport ( QCall , EntryPoint = "TailCallHelp_AllocTailCallArgBufferInternal" ) ]
494+ private static unsafe partial TailCallArgBuffer * AllocTailCallArgBufferInternal ( int size ) ;
495+
496+ private const int TAILCALLARGBUFFER_ACTIVE = 0 ;
497+ // private const int TAILCALLARGBUFFER_INSTARG_ONLY = 1;
498+ private const int TAILCALLARGBUFFER_INACTIVE = 2 ;
499+
500+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ] // To allow unrolling of Span.Clear
501+ private static unsafe TailCallArgBuffer * AllocTailCallArgBuffer ( int size , IntPtr gcDesc )
494502 {
495- IntPtr buffer = AllocTailCallArgBufferWorker ( size , gcDesc ) ;
496- if ( buffer == IntPtr . Zero )
503+ TailCallArgBuffer * buffer = GetTailCallArgBuffer ( ) ;
504+ if ( buffer != null && buffer ->Size >= size )
505+ {
506+ buffer ->State = TAILCALLARGBUFFER_INACTIVE ;
507+ }
508+ else
497509 {
498- throw new OutOfMemoryException ( ) ;
510+ buffer = AllocTailCallArgBufferWorker ( size ) ;
511+
512+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
513+ static TailCallArgBuffer * AllocTailCallArgBufferWorker ( int size ) => AllocTailCallArgBufferInternal ( size ) ;
499514 }
515+ Debug . Assert ( buffer != null ) ;
516+ Debug . Assert ( buffer ->Size >= size ) ;
517+ Debug . Assert ( buffer ->State == TAILCALLARGBUFFER_INACTIVE ) ;
518+
519+ buffer ->GCDesc = gcDesc ;
520+
521+ new Span < byte > ( buffer + 1 , size - sizeof ( TailCallArgBuffer ) ) . Clear ( ) ;
522+
523+ // The buffer is now ready to be used.
524+ buffer ->State = TAILCALLARGBUFFER_ACTIVE ;
525+
500526 return buffer ;
501527 }
502528
@@ -506,7 +532,7 @@ private static IntPtr AllocTailCallArgBuffer(int size, IntPtr gcDesc)
506532 [ StackTraceHidden ]
507533 private static unsafe void DispatchTailCalls (
508534 IntPtr callersRetAddrSlot ,
509- delegate * < IntPtr , ref byte , PortableTailCallFrame * , void > callTarget ,
535+ delegate * < TailCallArgBuffer * , ref byte , PortableTailCallFrame * , void > callTarget ,
510536 ref byte retVal )
511537 {
512538 IntPtr callersRetAddr ;
@@ -537,11 +563,8 @@ private static unsafe void DispatchTailCalls(
537563 {
538564 tls ->Frame = prevFrame ;
539565
540- // If the arg buffer is reporting inst argument, it is safe to abandon it now
541- if ( tls ->ArgBuffer != IntPtr . Zero && * ( int * ) tls ->ArgBuffer == 1 /* TAILCALLARGBUFFER_INSTARG_ONLY */ )
542- {
543- * ( int * ) tls ->ArgBuffer = 2 /* TAILCALLARGBUFFER_ABANDONED */ ;
544- }
566+ // If the arg buffer is reporting inst argument (TAILCALLARGBUFFER_INSTARG_ONLY), it is safe to abandon it now.
567+ tls ->ArgBuffer ->State = TAILCALLARGBUFFER_INACTIVE ;
545568 }
546569 }
547570
@@ -1217,13 +1240,22 @@ private static bool CanCastToWorker(TypeHandle srcTH, TypeHandle destTH, bool nu
12171240 internal unsafe struct PortableTailCallFrame
12181241 {
12191242 public IntPtr TailCallAwareReturnAddress ;
1220- public delegate * < IntPtr , ref byte , PortableTailCallFrame * , void > NextCall ;
1243+ public delegate * < TailCallArgBuffer * , ref byte , PortableTailCallFrame * , void > NextCall ;
1244+ }
1245+
1246+ [ StructLayout ( LayoutKind . Sequential ) ]
1247+ internal struct TailCallArgBuffer
1248+ {
1249+ public int State ;
1250+ public int Size ;
1251+ public IntPtr GCDesc ;
1252+ // Args
12211253 }
12221254
12231255 [ StructLayout ( LayoutKind . Sequential ) ]
12241256 internal unsafe struct TailCallTls
12251257 {
12261258 public PortableTailCallFrame * Frame ;
1227- public IntPtr ArgBuffer ;
1259+ public TailCallArgBuffer * ArgBuffer ;
12281260 }
12291261}
0 commit comments