@@ -357,13 +357,14 @@ namespace snmalloc
357
357
/* *
358
358
* Handles the messages in the queue if there are any,
359
359
* and then calls the action.
360
- *
360
+ *
361
361
* This is designed to provide a fast path common case that simply
362
362
* checks the queue and calls the action if it is empty. If there
363
363
* are messages, then it goes to the slow path, handle_message_queue_slow.
364
- *
364
+ *
365
365
* This is heavily templated to cause inlining, and passing of arguments on
366
- * the stack as often closing over the arguments would cause less good codegen.
366
+ * the stack as often closing over the arguments would cause less good
367
+ * codegen.
367
368
*/
368
369
template <typename Action, typename ... Args>
369
370
SNMALLOC_FAST_PATH decltype (auto )
@@ -485,6 +486,46 @@ namespace snmalloc
485
486
entry.get_remote ()->trunc_id (), msg);
486
487
}
487
488
489
+ template <typename Domesticator>
490
+ SNMALLOC_FAST_PATH static auto dealloc_local_objects_fast (
491
+ capptr::Alloc<RemoteMessage> msg,
492
+ const PagemapEntry& entry,
493
+ BackendSlabMetadata* meta,
494
+ LocalEntropy& entropy,
495
+ Domesticator domesticate,
496
+ size_t & bytes_freed)
497
+ {
498
+ SNMALLOC_ASSERT (!meta->is_unused ());
499
+
500
+ snmalloc_check_client (
501
+ mitigations (sanity_checks),
502
+ is_start_of_object (entry.get_sizeclass (), address_cast (msg)),
503
+ " Not deallocating start of an object" );
504
+
505
+ size_t objsize = sizeclass_full_to_size (entry.get_sizeclass ());
506
+
507
+ auto [curr, length] = RemoteMessage::template open_free_ring<Config>(
508
+ msg,
509
+ objsize,
510
+ freelist::Object::key_root,
511
+ meta->as_key_tweak (),
512
+ domesticate);
513
+
514
+ // TODO this should be fixed in a separate PR.
515
+ bytes_freed += objsize * length;
516
+
517
+ // Update the head and the next pointer in the free list.
518
+ meta->free_queue .append_segment (
519
+ curr,
520
+ msg.template as_reinterpret <freelist::Object::T<>>(),
521
+ length,
522
+ freelist::Object::key_root,
523
+ meta->as_key_tweak (),
524
+ entropy);
525
+
526
+ return meta->return_objects (length);
527
+ }
528
+
488
529
/* ************************************************************************
489
530
* Allocation Code Overview
490
531
*
@@ -879,7 +920,16 @@ namespace snmalloc
879
920
/* **************************************************************************
880
921
* Deallocation code
881
922
*
923
+ * The main deallocation code is in dealloc. This, like alloc, takes a
924
+ * template to initialise the state of the allocator. It is possible for
925
+ *the first operation on a thread to be a deallocation.
882
926
*
927
+ * The algorithm is
928
+ * - dealloc(void*)
929
+ * - If object, originated from this allocator, then
930
+ * - dealloc_local_object(void*)
931
+ * - Otherwise
932
+ * - dealloc_remote(void*)
883
933
***************************************************************************/
884
934
template <typename CheckInit = CheckInitNoOp>
885
935
SNMALLOC_FAST_PATH void dealloc (void * p_raw)
@@ -935,27 +985,6 @@ namespace snmalloc
935
985
{
936
986
auto meta = entry.get_slab_metadata ();
937
987
938
- if (SNMALLOC_LIKELY (dealloc_local_object_fast (p, entry, meta, entropy)))
939
- return ;
940
-
941
- dealloc_local_object_slow (p, entry, meta);
942
- }
943
-
944
- SNMALLOC_FAST_PATH void
945
- dealloc_local_object (CapPtr<void , capptr::bounds::Alloc> p)
946
- {
947
- // PagemapEntry-s seen here are expected to have meaningful Remote
948
- // pointers
949
- dealloc_local_object (
950
- p, Config::Backend::get_metaentry (snmalloc::address_cast (p)));
951
- }
952
-
953
- SNMALLOC_FAST_PATH static bool dealloc_local_object_fast (
954
- CapPtr<void , capptr::bounds::Alloc> p,
955
- const PagemapEntry& entry,
956
- BackendSlabMetadata* meta,
957
- LocalEntropy& entropy)
958
- {
959
988
SNMALLOC_ASSERT (!meta->is_unused ());
960
989
961
990
snmalloc_check_client (
@@ -969,47 +998,10 @@ namespace snmalloc
969
998
meta->free_queue .add (
970
999
cp, freelist::Object::key_root, meta->as_key_tweak (), entropy);
971
1000
972
- return SNMALLOC_LIKELY (!meta->return_object ());
973
- }
974
-
975
- template <typename Domesticator>
976
- SNMALLOC_FAST_PATH static auto dealloc_local_objects_fast (
977
- capptr::Alloc<RemoteMessage> msg,
978
- const PagemapEntry& entry,
979
- BackendSlabMetadata* meta,
980
- LocalEntropy& entropy,
981
- Domesticator domesticate,
982
- size_t & bytes_freed)
983
- {
984
- SNMALLOC_ASSERT (!meta->is_unused ());
985
-
986
- snmalloc_check_client (
987
- mitigations (sanity_checks),
988
- is_start_of_object (entry.get_sizeclass (), address_cast (msg)),
989
- " Not deallocating start of an object" );
990
-
991
- size_t objsize = sizeclass_full_to_size (entry.get_sizeclass ());
992
-
993
- auto [curr, length] = RemoteMessage::template open_free_ring<Config>(
994
- msg,
995
- objsize,
996
- freelist::Object::key_root,
997
- meta->as_key_tweak (),
998
- domesticate);
999
-
1000
- // TODO this should be fixed in a separate PR.
1001
- bytes_freed += objsize * length;
1002
-
1003
- // Update the head and the next pointer in the free list.
1004
- meta->free_queue .append_segment (
1005
- curr,
1006
- msg.template as_reinterpret <freelist::Object::T<>>(),
1007
- length,
1008
- freelist::Object::key_root,
1009
- meta->as_key_tweak (),
1010
- entropy);
1001
+ if (SNMALLOC_LIKELY (!meta->return_object ()))
1002
+ return ;
1011
1003
1012
- return meta-> return_objects (length );
1004
+ dealloc_local_object_slow (p, entry, meta);
1013
1005
}
1014
1006
1015
1007
/* *
@@ -1339,15 +1331,20 @@ namespace snmalloc
1339
1331
1340
1332
for (size_t i = 0 ; i < NUM_SMALL_SIZECLASSES; i++)
1341
1333
{
1342
- // TODO could optimise this, to return the whole list in one append
1343
- // call.
1344
- while (!small_fast_free_lists[i].empty ())
1334
+ if (small_fast_free_lists[i].empty ())
1335
+ continue ;
1336
+
1337
+ // All elements should have the same entry.
1338
+ const auto & entry =
1339
+ Config::Backend::get_metaentry (small_fast_free_lists[i].peek ());
1340
+ do
1345
1341
{
1342
+ // return each element
1346
1343
auto p = small_fast_free_lists[i].take (key, domesticate);
1347
1344
SNMALLOC_ASSERT (is_start_of_object (
1348
1345
sizeclass_t::from_small_class (i), address_cast (p)));
1349
- dealloc_local_object (p.as_void ());
1350
- }
1346
+ dealloc_local_object (p.as_void (), entry );
1347
+ } while (!small_fast_free_lists[i]. empty ());
1351
1348
}
1352
1349
1353
1350
auto posted = remote_dealloc_cache.template post <sizeof (Allocator)>(
0 commit comments