@@ -144,7 +144,7 @@ void ets_destroy(struct Ets *ets, GlobalContext *global)
144
144
synclist_destroy (& ets -> ets_tables );
145
145
}
146
146
147
- EtsErrorCode ets_create_table (term name , bool is_named , EtsTableType table_type , EtsAccessType access_type , size_t keypos , term * ret , Context * ctx )
147
+ EtsErrorCode ets_create_table_maybe_gc (term name , bool is_named , EtsTableType table_type , EtsAccessType access_type , size_t keypos , term * ret , Context * ctx )
148
148
{
149
149
if (is_named ) {
150
150
struct EtsTable * ets_table = ets_get_table_by_name (& ctx -> global -> ets , name , TableAccessNone );
@@ -348,7 +348,7 @@ EtsErrorCode ets_insert(term name_or_ref, term entry, Context *ctx)
348
348
return result ;
349
349
}
350
350
351
- static EtsErrorCode ets_table_lookup (struct EtsTable * ets_table , term key , term * ret , Context * ctx )
351
+ static EtsErrorCode ets_table_lookup_maybe_gc (struct EtsTable * ets_table , term key , term * ret , Context * ctx , int num_roots , term * roots )
352
352
{
353
353
if (ets_table -> access_type == EtsAccessPrivate && ets_table -> owner_process_id != ctx -> process_id ) {
354
354
return EtsPermissionDenied ;
@@ -362,7 +362,7 @@ static EtsErrorCode ets_table_lookup(struct EtsTable *ets_table, term key, term
362
362
363
363
size_t size = (size_t ) memory_estimate_usage (res );
364
364
// allocate [object]
365
- if (UNLIKELY (memory_ensure_free_opt (ctx , size + CONS_SIZE , MEMORY_CAN_SHRINK ) != MEMORY_GC_OK )) {
365
+ if (UNLIKELY (memory_ensure_free_with_roots (ctx , size + CONS_SIZE , num_roots , roots , MEMORY_CAN_SHRINK ) != MEMORY_GC_OK )) {
366
366
return EtsAllocationFailure ;
367
367
}
368
368
term new_res = memory_copy_term_tree (& ctx -> heap , res );
@@ -372,20 +372,20 @@ static EtsErrorCode ets_table_lookup(struct EtsTable *ets_table, term key, term
372
372
return EtsOk ;
373
373
}
374
374
375
- EtsErrorCode ets_lookup (term name_or_ref , term key , term * ret , Context * ctx )
375
+ EtsErrorCode ets_lookup_maybe_gc (term name_or_ref , term key , term * ret , Context * ctx )
376
376
{
377
377
struct EtsTable * ets_table = term_is_atom (name_or_ref ) ? ets_get_table_by_name (& ctx -> global -> ets , name_or_ref , TableAccessRead ) : ets_get_table_by_ref (& ctx -> global -> ets , term_to_ref_ticks (name_or_ref ), TableAccessRead );
378
378
if (ets_table == NULL ) {
379
379
return EtsTableNotFound ;
380
380
}
381
381
382
- EtsErrorCode result = ets_table_lookup (ets_table , key , ret , ctx );
382
+ EtsErrorCode result = ets_table_lookup_maybe_gc (ets_table , key , ret , ctx , 0 , NULL );
383
383
SMP_UNLOCK (ets_table );
384
384
385
385
return result ;
386
386
}
387
387
388
- EtsErrorCode ets_lookup_element (term name_or_ref , term key , size_t pos , term * ret , Context * ctx )
388
+ EtsErrorCode ets_lookup_element_maybe_gc (term name_or_ref , term key , size_t pos , term * ret , Context * ctx )
389
389
{
390
390
if (UNLIKELY (pos == 0 )) {
391
391
return EtsBadPosition ;
@@ -492,7 +492,7 @@ static bool operation_to_tuple4(term operation, size_t default_pos, term *positi
492
492
return true;
493
493
}
494
494
495
- EtsErrorCode ets_update_counter (term ref , term key , term operation , term default_value , term * ret , Context * ctx )
495
+ EtsErrorCode ets_update_counter_maybe_gc (term ref , term key , term operation , term default_value , term * ret , Context * ctx )
496
496
{
497
497
struct EtsTable * ets_table = term_is_atom (ref )
498
498
? ets_get_table_by_name (& ctx -> global -> ets , ref , TableAccessWrite )
@@ -501,13 +501,21 @@ EtsErrorCode ets_update_counter(term ref, term key, term operation, term default
501
501
return EtsTableNotFound ;
502
502
}
503
503
504
+ // do not use an invalid term as a root
505
+ term safe_default_value = term_is_invalid_term (default_value ) ? term_nil () : default_value ;
506
+ term roots [] = { key , operation , safe_default_value };
507
+
504
508
term list ;
505
- EtsErrorCode result = ets_table_lookup (ets_table , key , & list , ctx );
509
+ EtsErrorCode result = ets_table_lookup_maybe_gc (ets_table , key , & list , ctx , 3 , roots );
506
510
if (UNLIKELY (result != EtsOk )) {
507
511
SMP_UNLOCK (ets_table );
508
512
return result ;
509
513
}
510
514
515
+ key = roots [0 ];
516
+ operation = roots [1 ];
517
+ default_value = term_is_invalid_term (default_value ) ? term_invalid_term () : roots [2 ];
518
+
511
519
term to_insert ;
512
520
if (term_is_nil (list )) {
513
521
if (term_is_invalid_term (default_value )) {
0 commit comments