@@ -177,24 +177,26 @@ public unsafe MemoryHandle Allocate(
177177 {
178178 if ( _entries == null ) throw new InvalidOperationException ( "FastLane: Memory not reserved" ) ;
179179
180- var offset = MemoryLaneUtils . FindFreeSpot ( size , ref _freeBlocks , ref _freeBlockCount ) ;
180+ // Calculate total layout footprint including canary guards
181+ int physicalSizeNeeded = MemoryCanary . GetPhysicalSize ( size ) ;
182+ var physicalOffset = MemoryLaneUtils . FindFreeSpot ( physicalSizeNeeded , ref _freeBlocks , ref _freeBlockCount ) ;
181183
182- if ( offset == - 1 )
184+ if ( physicalOffset == - 1 )
183185 throw new OutOfMemoryException ( "FastLane: Cannot allocate - No contiguous block large enough." ) ;
184186
187+ // Position the tracked user data offset cleanly past the pre-canary boundary
188+ var userOffset = MemoryCanary . GetUserOffset ( physicalOffset ) ;
189+ MemoryCanary . WriteGuardBands ( Buffer , userOffset , size ) ;
190+
185191 EnsureEntryCapacity ( EntryCount ) ;
186192
187- //So we reuse freed handles here
188- // So we reuse freed handles here
189193 var id = MemoryLaneUtils . GetNextId ( _freeIds , ref _nextHandleId ) ;
190194
191- // Ensure our flat array is large enough for this ID
192195 if ( id >= _versionsCapacity )
193196 {
194197 GrowVersions ( id + 1 ) ;
195198 }
196199
197- // True O(1) Version Bump
198200 uint version = ++ _versions [ id ] ;
199201
200202#if DEBUG
@@ -206,7 +208,7 @@ public unsafe MemoryHandle Allocate(
206208
207209 _entries [ EntryCount ] = new AllocationEntry
208210 {
209- Offset = offset ,
211+ Offset = userOffset , // Target user data directly for O(1) pointer resolution
210212 Size = size ,
211213 HandleId = id ,
212214 Priority = priority ,
@@ -275,39 +277,37 @@ public nint Resolve(MemoryHandle handle)
275277 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
276278 public void Free ( MemoryHandle handle )
277279 {
278- // 1. Remove from index first
279280 if ( ! _handleIndex . TryRemove ( handle . Id , out var index ) )
280281 throw new InvalidOperationException ( $ "FastLane: Invalid handle { handle . Id } ") ;
281282
282283#if DEBUG
283284 _debugNames . Remove ( handle . Id ) ;
284285#endif
285286
286- // 2. Handle SlowLane/Redirects (This is your cold path)
287287 var entry = _entries [ index ] ;
288- MemoryLaneUtils . ReturnFreeSpace ( entry . Offset , entry . Size , ref _freeBlocks , ref _freeBlockCount ) ;
288+
289+ // Assert safety markers are intact before deallocation operations
290+ MemoryCanary . Validate ( Buffer , entry . Offset , entry . Size , handle . Id ) ;
291+
292+ // Map user boundaries back to complete layout blocks for the free-list
293+ int physicalOffset = MemoryCanary . GetPhysicalOffset ( entry . Offset ) ;
294+ int physicalSize = MemoryCanary . GetPhysicalSize ( entry . Size ) ;
295+ MemoryLaneUtils . ReturnFreeSpace ( physicalOffset , physicalSize , ref _freeBlocks , ref _freeBlockCount ) ;
289296
290297 if ( entry . IsStub && entry . RedirectToId != 0 )
291298 {
292299 var slowHandle = new MemoryHandle ( entry . RedirectToId , entry . RedirectVersion , _slowLane ) ;
293300 _slowLane . Free ( slowHandle ) ;
294301 }
295302
296- // 3. Swap-with-tail removal
297- var lastIdx = -- EntryCount ; // Decrement first to get the last valid index
303+ var lastIdx = -- EntryCount ;
298304 if ( index != lastIdx )
299305 {
300- // Move the last entry into the hole
301306 var movedEntry = _entries [ lastIdx ] ;
302307 _entries [ index ] = movedEntry ;
303-
304- // Update the map to point to the new location
305- // OPTIMIZATION: Use a direct 'Set' or 'Update' if your map allows
306- // to avoid tombstone buildup during updates.
307308 _handleIndex [ movedEntry . HandleId ] = index ;
308309 }
309310
310- // 4. Return ID to pool
311311 _freeIds . Push ( handle . Id ) ;
312312 }
313313
@@ -346,24 +346,27 @@ public unsafe void Compact(int currentFrame, MemoryManagerConfig config)
346346 var newBuffer = Marshal . AllocHGlobal ( Capacity ) ;
347347 var currentOffset = 0 ;
348348
349- // Now take your snapshot for sorting, but ONLY for survivors (non-stubs)
350349 var survivors = _entries . Take ( EntryCount )
351350 . Where ( e => ! e . IsStub )
352351 . OrderBy ( e => e . Offset )
353352 . ToList ( ) ;
354353
355354 foreach ( var survivor in survivors )
356355 {
357- // 1. Move the bytes
358- void * source = ( byte * ) Buffer + survivor . Offset ;
356+ // Extract base tracking coordinates for the entire block footprint
357+ int srcPhysicalOffset = MemoryCanary . GetPhysicalOffset ( survivor . Offset ) ;
358+ int physicalSize = MemoryCanary . GetPhysicalSize ( survivor . Size ) ;
359+
360+ // 1. Move the complete physical block (Canary + User Data + Canary)
361+ void * source = ( byte * ) Buffer + srcPhysicalOffset ;
359362 void * target = ( byte * ) newBuffer + currentOffset ;
360- System . Buffer . MemoryCopy ( source , target , Capacity - currentOffset , survivor . Size ) ;
363+ System . Buffer . MemoryCopy ( source , target , Capacity - currentOffset , physicalSize ) ;
361364
362- // 2. Update the OFFSET ONLY in the real metadata
365+ // 2. Map user offset coordinates relative to the new layout alignment
363366 var index = _handleIndex [ survivor . HandleId ] ;
364- _entries [ index ] . Offset = currentOffset ;
367+ _entries [ index ] . Offset = MemoryCanary . GetUserOffset ( currentOffset ) ;
365368
366- currentOffset += survivor . Size ;
369+ currentOffset += physicalSize ;
367370 }
368371
369372 // --- PASS 3: CLEANUP ---
@@ -463,15 +466,17 @@ public void ReplaceWithStub(MemoryHandle fastHandle, MemoryHandle slowHandle)
463466 if ( ! _handleIndex . TryGetValue ( fastHandle . Id , out var index ) )
464467 throw new InvalidOperationException ( "FastLane: Invalid handle" ) ;
465468
466- // Grab the existing entry
467469 var entry = _entries [ index ] ;
468470
469471 entry . IsStub = true ;
470472 entry . RedirectToId = slowHandle . Id ;
471473 entry . RedirectVersion = slowHandle . Version ;
472474
473- // Cleanup FastLane stats
474- MemoryLaneUtils . ReturnFreeSpace ( entry . Offset , entry . Size , ref _freeBlocks , ref _freeBlockCount ) ;
475+ // Map boundaries to clean up the underlying block pool space cleanly
476+ int physicalOffset = MemoryCanary . GetPhysicalOffset ( entry . Offset ) ;
477+ int physicalSize = MemoryCanary . GetPhysicalSize ( entry . Size ) ;
478+ MemoryLaneUtils . ReturnFreeSpace ( physicalOffset , physicalSize , ref _freeBlocks , ref _freeBlockCount ) ;
479+
475480 entry . Offset = 0 ;
476481 entry . Size = 0 ;
477482
0 commit comments