Skip to content

Commit 125262d

Browse files
alexmalyshevmeta-codesync[bot]
authored andcommitted
Move value_cache, value_indices, and type_index_offset into ModuleState
Summary: Move the `value_cache`, `value_indices`, and `type_index_offset` file-scope globals from `StaticPython/classloader.c` into the `ModuleState` class. The Python objects (`value_cache`, `value_indices`) are stored as `Ref<>` members with proper GC traversal. C accessor functions are provided in `module_c_state.h/cpp` for use from the C code in `classloader.c`. Reviewed By: jbower-fb Differential Revision: D96742325 fbshipit-source-id: 7759165fa1959a3ec7c649fa7acc88ebc04cf8c0
1 parent 0f3c830 commit 125262d

5 files changed

Lines changed: 93 additions & 27 deletions

File tree

cinderx/StaticPython/classloader.c

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -913,43 +913,42 @@ void* _PyClassloader_LookupSymbol(PyObject* lib_name, PyObject* symbol_name) {
913913
}
914914
#endif
915915

916-
// Python list used to cache values
917-
static PyObject* value_cache;
918-
// Dictionary of cached object -> index
919-
static PyObject* value_indices;
920-
// Current offset for type cache. When the type cache is cleared this
921-
// gets incremented by the current size so that we don't reuse previous
922-
// slots and any existing caches will fail.
923-
static int32_t type_index_offset;
924-
925916
void _PyClassLoader_ClearValueCache() {
926-
if (value_cache == NULL) {
917+
PyObject* vc = Ci_GetValueCache();
918+
if (vc == NULL) {
927919
return;
928920
}
929-
type_index_offset += PyList_Size(value_cache);
930-
Py_CLEAR(value_cache);
931-
Py_CLEAR(value_indices);
921+
Ci_AddTypeIndexOffset(PyList_Size(vc));
922+
Ci_ClearValueCache();
923+
Ci_ClearValueIndices();
932924
}
933925

934926
int32_t _PyClassLoader_CacheValue(PyObject* value) {
935-
if (value_cache == NULL) {
936-
value_cache = PyList_New(0);
937-
if (value_cache == NULL) {
927+
PyObject* vc = Ci_GetValueCache();
928+
if (vc == NULL) {
929+
vc = PyList_New(0);
930+
if (vc == NULL) {
938931
return -1;
939932
}
933+
Ci_SetValueCache((PyListObject*)vc);
934+
Py_DECREF(vc);
940935
}
941-
if (value_indices == NULL) {
942-
value_indices = PyDict_New();
943-
if (value_indices == NULL) {
936+
PyObject* vi = Ci_GetValueIndices();
937+
if (vi == NULL) {
938+
vi = PyDict_New();
939+
if (vi == NULL) {
944940
return -1;
945941
}
942+
Ci_SetValueIndices((PyDictObject*)vi);
943+
Py_DECREF(vi);
946944
}
947-
PyObject* index = PyDict_GetItem(value_indices, (PyObject*)value);
945+
PyObject* index = PyDict_GetItem(vi, (PyObject*)value);
948946
if (index != NULL) {
949947
return PyLong_AsLong(index);
950948
}
951949

952-
Py_ssize_t iindex = PyList_GET_SIZE(value_cache) + type_index_offset;
950+
int32_t tio = Ci_GetTypeIndexOffset();
951+
Py_ssize_t iindex = PyList_GET_SIZE(vc) + tio;
953952
if (iindex >= INT32_MAX) {
954953
return -1;
955954
}
@@ -959,13 +958,13 @@ int32_t _PyClassLoader_CacheValue(PyObject* value) {
959958
return -1;
960959
}
961960

962-
if (PyList_Append(value_cache, value) < 0) {
961+
if (PyList_Append(vc, value) < 0) {
963962
Py_DECREF(pyindex);
964963
return -1;
965964
}
966965

967-
if (PyDict_SetItem(value_indices, value, pyindex) < 0) {
968-
Py_SET_SIZE((PyVarObject*)value_cache, iindex - type_index_offset);
966+
if (PyDict_SetItem(vi, value, pyindex) < 0) {
967+
Py_SET_SIZE((PyVarObject*)vc, iindex - tio);
969968
Py_DECREF(pyindex);
970969
return -1;
971970
}
@@ -974,9 +973,11 @@ int32_t _PyClassLoader_CacheValue(PyObject* value) {
974973
}
975974

976975
PyObject* _PyClassLoader_GetCachedValue(int32_t type) {
977-
if (value_cache == NULL || type < type_index_offset) {
976+
PyObject* vc = Ci_GetValueCache();
977+
int32_t tio = Ci_GetTypeIndexOffset();
978+
if (vc == NULL || type < tio) {
978979
return NULL;
979980
}
980-
type -= type_index_offset;
981-
return Py_XNewRef(PyList_GetItem(value_cache, type));
981+
type -= tio;
982+
return Py_XNewRef(PyList_GetItem(vc, type));
982983
}

cinderx/module_c_state.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,44 @@ void Ci_ClearClassLoaderCacheModuleToKeys(void) {
6565
}
6666
}
6767

68+
PyObject* Ci_GetValueCache(void) {
69+
auto state = cinderx::getModuleState();
70+
return state != nullptr ? state->value_cache.getObj() : nullptr;
71+
}
72+
73+
void Ci_SetValueCache(PyListObject* cache) {
74+
cinderx::getModuleState()->value_cache = Ref<PyListObject>::create(cache);
75+
}
76+
77+
void Ci_ClearValueCache(void) {
78+
if (auto state = cinderx::getModuleState(); state != nullptr) {
79+
state->value_cache.reset();
80+
}
81+
}
82+
83+
PyObject* Ci_GetValueIndices(void) {
84+
auto state = cinderx::getModuleState();
85+
return state != nullptr ? state->value_indices.getObj() : nullptr;
86+
}
87+
88+
void Ci_SetValueIndices(PyDictObject* indices) {
89+
cinderx::getModuleState()->value_indices = Ref<PyDictObject>::create(indices);
90+
}
91+
92+
void Ci_ClearValueIndices(void) {
93+
if (auto state = cinderx::getModuleState(); state != nullptr) {
94+
state->value_indices.reset();
95+
}
96+
}
97+
98+
int32_t Ci_GetTypeIndexOffset(void) {
99+
return cinderx::getModuleState()->type_index_offset;
100+
}
101+
102+
void Ci_AddTypeIndexOffset(int32_t offset) {
103+
cinderx::getModuleState()->type_index_offset += offset;
104+
}
105+
68106
int Ci_Watchers_WatchDict(PyObject* dict) {
69107
return cinderx::getModuleState()->watcher_state.watchDict(dict);
70108
}

cinderx/module_c_state.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ PyObject* Ci_GetClassLoaderCacheModuleToKeys(void);
3838
void Ci_SetClassLoaderCacheModuleToKeys(PyDictObject* cache);
3939
void Ci_ClearClassLoaderCacheModuleToKeys(void);
4040

41+
// Value cache for adaptive interpreter.
42+
PyObject* Ci_GetValueCache(void);
43+
void Ci_SetValueCache(PyListObject* cache);
44+
void Ci_ClearValueCache(void);
45+
46+
// Value-to-index mapping.
47+
PyObject* Ci_GetValueIndices(void);
48+
void Ci_SetValueIndices(PyDictObject* indices);
49+
void Ci_ClearValueIndices(void);
50+
51+
// Type index offset for value cache.
52+
int32_t Ci_GetTypeIndexOffset(void);
53+
void Ci_AddTypeIndexOffset(int32_t offset);
54+
4155
// WatcherState.
4256

4357
int Ci_Watchers_WatchDict(PyObject* dict);

cinderx/module_state.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ int ModuleState::traverse(visitproc visit, void* arg) {
1717
Py_VISIT(genericinst_cache);
1818
Py_VISIT(classloader_cache);
1919
Py_VISIT(classloader_cache_module_to_keys);
20+
Py_VISIT(value_cache);
21+
Py_VISIT(value_indices);
2022
Py_VISIT(builtin_next);
2123
return 0;
2224
}
@@ -26,6 +28,8 @@ int ModuleState::clear() {
2628
genericinst_cache.reset();
2729
classloader_cache.reset();
2830
classloader_cache_module_to_keys.reset();
31+
value_cache.reset();
32+
value_indices.reset();
2933
sys_clear_caches.reset();
3034
builtin_next.reset();
3135
return 0;

cinderx/module_state.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ struct ModuleState {
6767
// Mapping from module name to classloader cache keys for that module.
6868
Ref<PyDictObject> classloader_cache_module_to_keys;
6969

70+
// Cache for Static Python primitive values (int/float/etc.) by type.
71+
Ref<PyListObject> value_cache;
72+
73+
// Mapping from Static Python value types to their indices.
74+
Ref<PyDictObject> value_indices;
75+
76+
// Running offset for assigning type indices to Static Python types.
77+
int32_t type_index_offset{0};
78+
7079
// Snapshotted member dicts for standard builtin types (int, str, list, etc.)
7180
// so the JIT optimizer can look up methods during multithreaded compilation
7281
// without calling PyType_Lookup (which isn't safe off the main thread).

0 commit comments

Comments
 (0)