LCOV - code coverage report
Current view: top level - src - iddict.c (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 105 111 94.6 %
Date: 2022-07-16 23:42:53 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 61 72 84.7 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : #define hash_size(h) (jl_array_len(h) / 2)
       4                 :            : 
       5                 :            : // compute empirical max-probe for a given size
       6                 :            : #define max_probe(size) ((size) <= 1024 ? 16 : (size) >> 6)
       7                 :            : 
       8                 :            : #define keyhash(k) jl_object_id_(jl_typeof(k), k)
       9                 :            : #define h2index(hv, sz) (size_t)(((hv) & ((sz)-1)) * 2)
      10                 :            : 
      11                 :            : static inline int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_t *val);
      12                 :            : 
      13                 :    1945280 : JL_DLLEXPORT jl_array_t *jl_idtable_rehash(jl_array_t *a, size_t newsz)
      14                 :            : {
      15                 :    1945280 :     size_t sz = jl_array_len(a);
      16                 :            :     size_t i;
      17                 :    1945280 :     jl_value_t **ol = (jl_value_t **)a->data;
      18                 :    1945280 :     jl_array_t *newa = jl_alloc_vec_any(newsz);
      19                 :            :     // keep the original array in the original slot since we need `ol`
      20                 :            :     // to be valid in the loop below.
      21                 :    1945280 :     JL_GC_PUSH2(&newa, &a);
      22         [ +  + ]:   52888000 :     for (i = 0; i < sz; i += 2) {
      23         [ +  + ]:   50942700 :         if (ol[i + 1] != NULL) {
      24                 :   20374600 :             jl_table_assign_bp(&newa, ol[i], ol[i + 1]);
      25                 :            :             // it is however necessary here because allocation
      26                 :            :             // can (and will) occur in a recursive call inside table_lookup_bp
      27                 :            :         }
      28                 :            :     }
      29                 :    1945280 :     JL_GC_POP();
      30                 :    1945280 :     return newa;
      31                 :            : }
      32                 :            : 
      33                 :   61663500 : static inline int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_t *val)
      34                 :            : {
      35                 :            :     // pa points to a **un**rooted address
      36                 :            :     uint_t hv;
      37                 :   61663500 :     jl_array_t *a = *pa;
      38                 :            :     size_t orig, index, iter, empty_slot;
      39                 :   61663500 :     size_t newsz, sz = hash_size(a);
      40         [ +  + ]:   61663500 :     if (sz == 0) {
      41                 :      40484 :         a = jl_alloc_vec_any(HT_N_INLINE);
      42                 :      40484 :         sz = hash_size(a);
      43                 :      40484 :         *pa = a;
      44                 :            :     }
      45         [ +  + ]:   61663500 :     size_t maxprobe = max_probe(sz);
      46                 :   61663500 :     _Atomic(jl_value_t*) *tab = (_Atomic(jl_value_t*)*)a->data;
      47                 :            : 
      48                 :   61663500 :     hv = keyhash(key);
      49                 :            :     while (1) {
      50                 :   61978000 :         iter = 0;
      51                 :   61978000 :         index = h2index(hv, sz);
      52                 :   61978000 :         sz *= 2;
      53                 :   61978000 :         orig = index;
      54                 :   61978000 :         empty_slot = -1;
      55                 :            : 
      56                 :            :         do {
      57                 :  266671000 :             jl_value_t *k2 = jl_atomic_load_relaxed(&tab[index]);
      58         [ +  + ]:  266671000 :             if (k2 == NULL) {
      59         [ +  + ]:   60704900 :                 if (empty_slot == -1)
      60                 :   60432000 :                     empty_slot = index;
      61                 :   60704900 :                 break;
      62                 :            :             }
      63         [ +  + ]:  205966000 :             if (jl_egal(key, k2)) {
      64         [ +  - ]:     955159 :                 if (jl_atomic_load_relaxed(&tab[index + 1]) != NULL) {
      65                 :     955159 :                     jl_atomic_store_release(&tab[index + 1], val);
      66                 :     955159 :                     jl_gc_wb(a, val);
      67                 :     955159 :                     return 0;
      68                 :            :                 }
      69                 :            :                 // `nothing` is our sentinel value for deletion, so need to keep searching if it's also our search key
      70         [ #  # ]:          0 :                 assert(key == jl_nothing);
      71         [ #  # ]:          0 :                 if (empty_slot == -1)
      72                 :          0 :                     empty_slot = index;
      73                 :            :             }
      74   [ +  +  +  + ]:  205011000 :             if (empty_slot == -1 && jl_atomic_load_relaxed(&tab[index + 1]) == NULL) {
      75         [ -  + ]:     276353 :                 assert(jl_atomic_load_relaxed(&tab[index]) == jl_nothing);
      76                 :     276353 :                 empty_slot = index;
      77                 :            :             }
      78                 :            : 
      79                 :  205011000 :             index = (index + 2) & (sz - 1);
      80                 :  205011000 :             iter++;
      81   [ +  +  +  + ]:  205011000 :         } while (iter <= maxprobe && index != orig);
      82                 :            : 
      83         [ +  + ]:   61022800 :         if (empty_slot != -1) {
      84                 :   60708300 :             jl_atomic_store_release(&tab[empty_slot], key);
      85                 :   60708300 :             jl_gc_wb(a, key);
      86                 :   60708300 :             jl_atomic_store_release(&tab[empty_slot + 1], val);
      87                 :   60708300 :             jl_gc_wb(a, val);
      88                 :   60708300 :             return 1;
      89                 :            :         }
      90                 :            : 
      91                 :            :         /* table full */
      92                 :            :         /* quadruple size, rehash, retry the insert */
      93                 :            :         /* it's important to grow the table really fast; otherwise we waste */
      94                 :            :         /* lots of time rehashing all the keys over and over. */
      95                 :     314506 :         sz = jl_array_len(a);
      96         [ +  + ]:     314506 :         if (sz < HT_N_INLINE)
      97                 :       2070 :             newsz = HT_N_INLINE;
      98   [ +  +  +  + ]:     312436 :         else if (sz >= (1 << 19) || (sz <= (1 << 8)))
      99                 :     305154 :             newsz = sz << 1;
     100                 :            :         else
     101                 :       7282 :             newsz = sz << 2;
     102                 :     314506 :         *pa = jl_idtable_rehash(*pa, newsz);
     103                 :            : 
     104                 :     314506 :         a = *pa;
     105                 :     314506 :         tab = (_Atomic(jl_value_t*)*)a->data;
     106                 :     314506 :         sz = hash_size(a);
     107         [ +  + ]:     314506 :         maxprobe = max_probe(sz);
     108                 :            :     }
     109                 :            : }
     110                 :            : 
     111                 :            : /* returns bp if key is in hash, otherwise NULL */
     112                 :  425855000 : inline _Atomic(jl_value_t*) *jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT
     113                 :            : {
     114                 :  425855000 :     size_t sz = hash_size(a);
     115         [ +  + ]:  425855000 :     if (sz == 0)
     116                 :     556916 :         return NULL;
     117         [ +  + ]:  425298000 :     size_t maxprobe = max_probe(sz);
     118                 :  425298000 :     _Atomic(jl_value_t*) *tab = (_Atomic(jl_value_t*)*)a->data;
     119                 :  425298000 :     uint_t hv = keyhash(key);
     120                 :  425298000 :     size_t index = h2index(hv, sz);
     121                 :  425298000 :     sz *= 2;
     122                 :  425298000 :     size_t orig = index;
     123                 :  425298000 :     size_t iter = 0;
     124                 :            : 
     125                 :            :     do {
     126                 :  748148000 :         jl_value_t *k2 = jl_atomic_load_relaxed(&tab[index]); // just to ensure the load doesn't get duplicated
     127         [ +  + ]:  748148000 :         if (k2 == NULL)
     128                 :   61764400 :             return NULL;
     129         [ +  + ]:  686384000 :         if (jl_egal(key, k2)) {
     130         [ +  - ]:  362185000 :             if (jl_atomic_load_relaxed(&tab[index + 1]) != NULL)
     131                 :  362185000 :                 return &tab[index + 1];
     132                 :            :             // `nothing` is our sentinel value for deletion, so need to keep searching if it's also our search key
     133         [ #  # ]:          0 :             if (key != jl_nothing)
     134                 :          0 :                 return NULL; // concurrent insertion hasn't completed yet
     135                 :            :         }
     136                 :            : 
     137                 :  324199000 :         index = (index + 2) & (sz - 1);
     138                 :  324199000 :         iter++;
     139   [ +  +  +  + ]:  324199000 :     } while (iter <= maxprobe && index != orig);
     140                 :            : 
     141                 :    1348810 :     return NULL;
     142                 :            : }
     143                 :            : 
     144                 :            : JL_DLLEXPORT
     145                 :   41282700 : jl_array_t *jl_eqtable_put(jl_array_t *h, jl_value_t *key, jl_value_t *val, int *p_inserted)
     146                 :            : {
     147                 :   41282700 :     int inserted = jl_table_assign_bp(&h, key, val);
     148         [ +  + ]:   41282700 :     if (p_inserted)
     149                 :   39919100 :         *p_inserted = inserted;
     150                 :   41282700 :     return h;
     151                 :            : }
     152                 :            : 
     153                 :            : // Note: lookup in the IdDict is permitted concurrently, if you avoid deletions,
     154                 :            : // and assuming you do use an external lock around all insertions
     155                 :            : JL_DLLEXPORT
     156                 :  424204000 : jl_value_t *jl_eqtable_get(jl_array_t *h, jl_value_t *key, jl_value_t *deflt) JL_NOTSAFEPOINT
     157                 :            : {
     158                 :  424204000 :     _Atomic(jl_value_t*) *bp = jl_table_peek_bp(h, key);
     159         [ +  + ]:  424204000 :     return (bp == NULL) ? deflt : jl_atomic_load_relaxed(bp);
     160                 :            : }
     161                 :            : 
     162                 :            : JL_DLLEXPORT
     163                 :    1134240 : jl_value_t *jl_eqtable_pop(jl_array_t *h, jl_value_t *key, jl_value_t *deflt, int *found)
     164                 :            : {
     165                 :    1134240 :     _Atomic(jl_value_t*) *bp = jl_table_peek_bp(h, key);
     166         [ +  - ]:    1134240 :     if (found)
     167                 :    1134240 :         *found = (bp != NULL);
     168         [ +  + ]:    1134240 :     if (bp == NULL)
     169                 :     704299 :         return deflt;
     170                 :     429946 :     jl_value_t *val = jl_atomic_load_relaxed(bp);
     171                 :     429946 :     jl_atomic_store_relaxed(bp - 1, jl_nothing); // clear the key
     172                 :     429946 :     jl_atomic_store_relaxed(bp, NULL); // and the value (briefly corrupting the table)
     173                 :     429946 :     return val;
     174                 :            : }
     175                 :            : 
     176                 :            : JL_DLLEXPORT
     177                 :   99252300 : size_t jl_eqtable_nextind(jl_array_t *t, size_t i)
     178                 :            : {
     179         [ -  + ]:   99252300 :     if (i & 1)
     180                 :          0 :         i++;
     181                 :   99252300 :     size_t alen = jl_array_dim0(t);
     182   [ +  +  +  + ]: 1499900000 :     while (i < alen && ((void **)t->data)[i + 1] == NULL)
     183                 : 1400650000 :         i += 2;
     184         [ +  + ]:   99252300 :     if (i >= alen)
     185                 :   87596600 :         return (size_t)-1;
     186                 :   11655700 :     return i;
     187                 :            : }
     188                 :            : 
     189                 :            : #undef hash_size
     190                 :            : #undef max_probe

Generated by: LCOV version 1.14