@@ -164,6 +164,71 @@ void default_exception_translator(const std::exception_ptr &p, void *) {
164164nb_internals *internals = nullptr ;
165165PyTypeObject *nb_meta_cache = nullptr ;
166166
167+
168+ static const char * interned_c_strs[pyobj_name::string_count] {
169+ " value" ,
170+ " copy" ,
171+ " from_dlpack" ,
172+ " __dlpack__" ,
173+ " max_version" ,
174+ " dl_device" ,
175+ };
176+
177+ PyObject **static_pyobjects = nullptr ;
178+
179+ static bool init_pyobjects (PyObject* m) {
180+ PyObject** pyobjects = (PyObject**) PyModule_GetState (m);
181+ if (!pyobjects)
182+ return false ;
183+
184+ NB_NOUNROLL
185+ for (int i = 0 ; i < pyobj_name::string_count; ++i)
186+ pyobjects[i] = PyUnicode_InternFromString (interned_c_strs[i]);
187+
188+ pyobjects[pyobj_name::copy_tpl] =
189+ PyTuple_Pack (1 , pyobjects[pyobj_name::copy_str]);
190+ pyobjects[pyobj_name::max_version_tpl] =
191+ PyTuple_Pack (1 , pyobjects[pyobj_name::max_version_str]);
192+
193+ PyObject* one = PyLong_FromLong (1 );
194+ PyObject* zero = PyLong_FromLong (0 );
195+ pyobjects[pyobj_name::dl_cpu_tpl] = PyTuple_Pack (2 , one, zero);
196+ Py_DECREF (zero);
197+ Py_DECREF (one);
198+
199+ PyObject* major = PyLong_FromLong (dlpack::major_version);
200+ PyObject* minor = PyLong_FromLong (dlpack::minor_version);
201+ pyobjects[pyobj_name::dl_version_tpl] = PyTuple_Pack (2 , major, minor);
202+ Py_DECREF (minor);
203+ Py_DECREF (major);
204+
205+ static_pyobjects = pyobjects;
206+
207+ return true ;
208+ }
209+
210+ NB_NOINLINE int nb_module_traverse (PyObject *m, visitproc visit, void *arg) {
211+ PyObject** pyobjects = (PyObject**) PyModule_GetState (m);
212+ NB_NOUNROLL
213+ for (int i = 0 ; i < pyobj_name::total_count; ++i)
214+ Py_VISIT (pyobjects[i]);
215+ return 0 ;
216+ }
217+
218+ NB_NOINLINE int nb_module_clear (PyObject *m) {
219+ PyObject** pyobjects = (PyObject**) PyModule_GetState (m);
220+ NB_NOUNROLL
221+ for (int i = 0 ; i < pyobj_name::total_count; ++i)
222+ Py_CLEAR (pyobjects[i]);
223+ return 0 ;
224+ }
225+
226+ void nb_module_free (void *m) {
227+ // Allow nanobind_##name##_exec to omit calling nb_module_clear on error.
228+ (void ) nb_module_clear ((PyObject *) m);
229+ }
230+
231+
167232static bool is_alive_value = false ;
168233static bool *is_alive_ptr = &is_alive_value;
169234bool is_alive () noexcept { return *is_alive_ptr; }
@@ -317,29 +382,34 @@ static void internals_cleanup() {
317382#endif
318383}
319384
320- NB_NOINLINE void init (const char *name) {
385+ NB_NOINLINE void nb_module_exec (const char *name, PyObject *m ) {
321386 if (internals)
322387 return ;
323388
389+ check (init_pyobjects (m), " nanobind::detail::nb_module_exec(): "
390+ " could not initialize module state!" );
391+
324392#if defined(PYPY_VERSION)
325393 PyObject *dict = PyEval_GetBuiltins ();
326394#elif PY_VERSION_HEX < 0x03090000
327395 PyObject *dict = PyInterpreterState_GetDict (_PyInterpreterState_Get ());
328396#else
329397 PyObject *dict = PyInterpreterState_GetDict (PyInterpreterState_Get ());
330398#endif
331- check (dict, " nanobind::detail::init(): could not access internals dictionary!" );
399+ check (dict, " nanobind::detail::nb_module_exec(): "
400+ " could not access internals dictionary!" );
332401
333402 PyObject *key = PyUnicode_FromFormat (" __nb_internals_%s_%s__" ,
334403 abi_tag (), name ? name : " " );
335- check (key, " nanobind::detail::init(): could not create dictionary key!" );
404+ check (key, " nanobind::detail::nb_module_exec(): "
405+ " could not create dictionary key!" );
336406
337407 PyObject *capsule = dict_get_item_ref_or_fail (dict, key);
338408 if (capsule) {
339409 Py_DECREF (key);
340410 internals = (nb_internals *) PyCapsule_GetPointer (capsule, " nb_internals" );
341- check (internals,
342- " nanobind::detail::internals_fetch(): capsule pointer is NULL!" );
411+ check (internals, " nanobind::detail::nb_module_exec(): "
412+ " capsule pointer is NULL!" );
343413 nb_meta_cache = internals->nb_meta ;
344414 is_alive_ptr = internals->is_alive_ptr ;
345415 Py_DECREF (capsule);
@@ -381,7 +451,7 @@ NB_NOINLINE void init(const char *name) {
381451
382452 check (p->nb_module && p->nb_meta && p->nb_type_dict && p->nb_func &&
383453 p->nb_method && p->nb_bound_method ,
384- " nanobind::detail::init (): initialization failed!" );
454+ " nanobind::detail::nb_module_exec (): initialization failed!" );
385455
386456#if PY_VERSION_HEX < 0x03090000
387457 p->nb_func ->tp_flags |= NB_HAVE_VECTORCALL;
@@ -476,7 +546,7 @@ NB_NOINLINE void init(const char *name) {
476546 capsule = PyCapsule_New (p, " nb_internals" , nullptr );
477547 int rv = PyDict_SetItem (dict, key, capsule);
478548 check (!rv && capsule,
479- " nanobind::detail::init (): capsule creation failed!" );
549+ " nanobind::detail::nb_module_exec (): capsule creation failed!" );
480550 Py_DECREF (capsule);
481551 Py_DECREF (key);
482552 internals = p;
0 commit comments