|
| 1 | +#ifndef Py_INTERNAL_TYPECACHE_H |
| 2 | +#define Py_INTERNAL_TYPECACHE_H |
| 3 | +#ifdef __cplusplus |
| 4 | +extern "C" { |
| 5 | +#endif |
| 6 | + |
| 7 | +#ifndef Py_BUILD_CORE |
| 8 | +# error "this header requires Py_BUILD_CORE define" |
| 9 | +#endif |
| 10 | + |
| 11 | +// TODO(sgross): MRO cache or type cache? |
| 12 | + |
| 13 | +typedef struct _Py_mro_cache_entry { |
| 14 | + PyObject *name; /* name (interned unicode; immortal) */ |
| 15 | + uintptr_t value; /* resolved function (owned ref), or 0=not cached 1=not present */ |
| 16 | +} _Py_mro_cache_entry; |
| 17 | + |
| 18 | +typedef struct _Py_mro_cache_buckets { |
| 19 | + struct _Py_queue_node node; |
| 20 | + union { |
| 21 | + Py_ssize_t refcount; |
| 22 | + Py_ssize_t capacity; |
| 23 | + } u; |
| 24 | + uint32_t available; /* number of unused buckets */ |
| 25 | + uint32_t used; /* number of used buckets */ |
| 26 | + _Py_mro_cache_entry array[]; |
| 27 | +} _Py_mro_cache_buckets; |
| 28 | + |
| 29 | +/* Per-interpreter state */ |
| 30 | +struct _mro_cache_state { |
| 31 | + _Py_mro_cache_buckets *empty_buckets; |
| 32 | + Py_ssize_t empty_buckets_capacity; |
| 33 | +}; |
| 34 | + |
| 35 | +typedef struct _Py_mro_cache_result { |
| 36 | + int hit; |
| 37 | + PyObject *value; |
| 38 | +} _Py_mro_cache_result; |
| 39 | + |
| 40 | +extern PyStatus _Py_mro_cache_init(PyInterpreterState *interp); |
| 41 | +extern void _Py_mro_cache_fini(PyInterpreterState *interp); |
| 42 | +extern void _Py_mro_cache_init_type(PyTypeObject *type); |
| 43 | +extern void _Py_mro_cache_fini_type(PyTypeObject *type); |
| 44 | +extern int _Py_mro_cache_visit(_Py_mro_cache *cache, visitproc visit, void *arg); |
| 45 | + |
| 46 | +extern void _Py_mro_cache_erase(_Py_mro_cache *cache); |
| 47 | +extern void _Py_mro_cache_insert(_Py_mro_cache *cache, PyObject *name, PyObject *value); |
| 48 | +extern void _Py_mro_process_freed_buckets(PyInterpreterState *interp); |
| 49 | + |
| 50 | +extern PyObject *_Py_mro_cache_as_dict(_Py_mro_cache *cache); |
| 51 | + |
| 52 | +static inline _Py_mro_cache_result |
| 53 | +_Py_mro_cache_make_result(uintptr_t *ptr) |
| 54 | +{ |
| 55 | + uintptr_t value = _Py_atomic_load_uintptr_relaxed(ptr); |
| 56 | + return (_Py_mro_cache_result) { |
| 57 | + .hit = value != 0, |
| 58 | + .value = (PyObject *)(value & ~1), |
| 59 | + }; |
| 60 | +} |
| 61 | + |
| 62 | +static inline struct _Py_mro_cache_result |
| 63 | +_Py_mro_cache_lookup(_Py_mro_cache *cache, PyObject *name) |
| 64 | +{ |
| 65 | + Py_hash_t hash = ((PyASCIIObject *)name)->hash; |
| 66 | + uint32_t mask = _Py_atomic_load_uint32(&cache->mask); |
| 67 | + _Py_mro_cache_entry *first = _Py_atomic_load_ptr_relaxed(&cache->buckets); |
| 68 | + |
| 69 | + Py_ssize_t offset = hash & mask; |
| 70 | + _Py_mro_cache_entry *bucket = (_Py_mro_cache_entry *)((char *)first + offset); |
| 71 | + |
| 72 | + PyObject *entry_name = _Py_atomic_load_ptr_relaxed(&bucket->name); |
| 73 | + if (_PY_LIKELY(entry_name == name)) { |
| 74 | + return _Py_mro_cache_make_result(&bucket->value); |
| 75 | + } |
| 76 | + |
| 77 | + /* First loop */ |
| 78 | + while (1) { |
| 79 | + if (entry_name == NULL) { |
| 80 | + return (_Py_mro_cache_result){0, NULL}; |
| 81 | + } |
| 82 | + if (bucket == first) { |
| 83 | + break; |
| 84 | + } |
| 85 | + bucket--; |
| 86 | + entry_name = _Py_atomic_load_ptr_relaxed(&bucket->name); |
| 87 | + if (entry_name == name) { |
| 88 | + return _Py_mro_cache_make_result(&bucket->value); |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + /* Second loop. Start at the last bucket. */ |
| 93 | + bucket = (_Py_mro_cache_entry *)((char *)first + mask); |
| 94 | + while (1) { |
| 95 | + entry_name = _Py_atomic_load_ptr_relaxed(&bucket->name); |
| 96 | + if (entry_name == name) { |
| 97 | + return _Py_mro_cache_make_result(&bucket->value); |
| 98 | + } |
| 99 | + if (entry_name == NULL || bucket == first) { |
| 100 | + return (_Py_mro_cache_result){0, NULL}; |
| 101 | + } |
| 102 | + bucket--; |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | + |
| 107 | +#ifdef __cplusplus |
| 108 | +} |
| 109 | +#endif |
| 110 | +#endif /* !Py_INTERNAL_TYPECACHE_H */ |
0 commit comments