MNT: move static data structs into their own file
diff --git a/numpy/_core/meson.build b/numpy/_core/meson.build
index dbe76e0..aba0b82 100644
--- a/numpy/_core/meson.build
+++ b/numpy/_core/meson.build
@@ -1101,6 +1101,7 @@
'src/multiarray/nditer_constr.c',
'src/multiarray/nditer_pywrap.c',
src_file.process('src/multiarray/nditer_templ.c.src'),
+ 'src/multiarray/npy_static_data.c',
'src/multiarray/number.c',
'src/multiarray/refcount.c',
src_file.process('src/multiarray/scalartypes.c.src'),
diff --git a/numpy/_core/src/common/binop_override.h b/numpy/_core/src/common/binop_override.h
index ec3d046..def9b89 100644
--- a/numpy/_core/src/common/binop_override.h
+++ b/numpy/_core/src/common/binop_override.h
@@ -6,6 +6,7 @@
#include "numpy/arrayobject.h"
#include "get_attr_string.h"
+#include "npy_static_data.h"
/*
* Logic for deciding when binops should return NotImplemented versus when
@@ -128,7 +129,7 @@
* Classes with __array_ufunc__ are living in the future, and only need to
* check whether __array_ufunc__ equals None.
*/
- attr = PyArray_LookupSpecial(other, npy_um_str_array_ufunc);
+ attr = PyArray_LookupSpecial(other, npy_interned_str.array_ufunc);
if (attr != NULL) {
defer = !inplace && (attr == Py_None);
Py_DECREF(attr);
diff --git a/numpy/_core/src/common/npy_cpu_dispatch.c b/numpy/_core/src/common/npy_cpu_dispatch.c
index 388ad25..ff22f23 100644
--- a/numpy/_core/src/common/npy_cpu_dispatch.c
+++ b/numpy/_core/src/common/npy_cpu_dispatch.c
@@ -3,7 +3,7 @@
#include "npy_cpu_dispatch.h"
#include "numpy/ndarraytypes.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
NPY_VISIBILITY_HIDDEN int
npy_cpu_dispatch_tracer_init(PyObject *mod)
diff --git a/numpy/_core/src/common/ufunc_override.c b/numpy/_core/src/common/ufunc_override.c
index fe9ada5..17b678e 100644
--- a/numpy/_core/src/common/ufunc_override.c
+++ b/numpy/_core/src/common/ufunc_override.c
@@ -7,7 +7,7 @@
#include "npy_import.h"
#include "ufunc_override.h"
#include "scalartypes.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
/*
* Check whether an object has __array_ufunc__ defined on its class and it
@@ -35,7 +35,7 @@
* Does the class define __array_ufunc__? (Note that LookupSpecial has fast
* return for basic python types, so no need to worry about those here)
*/
- cls_array_ufunc = PyArray_LookupSpecial(obj, npy_um_str_array_ufunc);
+ cls_array_ufunc = PyArray_LookupSpecial(obj, npy_interned_str.array_ufunc);
if (cls_array_ufunc == NULL) {
if (PyErr_Occurred()) {
PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */
diff --git a/numpy/_core/src/multiarray/alloc.c b/numpy/_core/src/multiarray/alloc.c
index 8f443c6..b7e7c99 100644
--- a/numpy/_core/src/multiarray/alloc.c
+++ b/numpy/_core/src/multiarray/alloc.c
@@ -11,6 +11,7 @@
#include "numpy/npy_common.h"
#include "npy_config.h"
#include "alloc.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
#include <assert.h>
diff --git a/numpy/_core/src/multiarray/array_converter.c b/numpy/_core/src/multiarray/array_converter.c
index 4ed959c..4961730 100644
--- a/numpy/_core/src/multiarray/array_converter.c
+++ b/numpy/_core/src/multiarray/array_converter.c
@@ -21,7 +21,7 @@
#include "abstractdtypes.h"
#include "convert_datatype.h"
#include "descriptor.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "ctors.h"
#include "npy_config.h"
diff --git a/numpy/_core/src/multiarray/arrayfunction_override.c b/numpy/_core/src/multiarray/arrayfunction_override.c
index 250b02b..aa3ab42 100644
--- a/numpy/_core/src/multiarray/arrayfunction_override.c
+++ b/numpy/_core/src/multiarray/arrayfunction_override.c
@@ -7,6 +7,7 @@
#include "numpy/ndarraytypes.h"
#include "get_attr_string.h"
#include "npy_import.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
#include "arrayfunction_override.h"
diff --git a/numpy/_core/src/multiarray/arraytypes.c.src b/numpy/_core/src/multiarray/arraytypes.c.src
index b99598b..9524be8 100644
--- a/numpy/_core/src/multiarray/arraytypes.c.src
+++ b/numpy/_core/src/multiarray/arraytypes.c.src
@@ -42,6 +42,7 @@
#include "arraytypes.h"
#include "umathmodule.h"
+#include "npy_static_data.h"
/*
* Define a stack allocated dummy array with only the minimum information set:
diff --git a/numpy/_core/src/multiarray/arraywrap.c b/numpy/_core/src/multiarray/arraywrap.c
index 7b2bcd9..ae7b6e9 100644
--- a/numpy/_core/src/multiarray/arraywrap.c
+++ b/numpy/_core/src/multiarray/arraywrap.c
@@ -12,7 +12,7 @@
#include "get_attr_string.h"
#include "arraywrap.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
/*
diff --git a/numpy/_core/src/multiarray/common.h b/numpy/_core/src/multiarray/common.h
index c5bb694..19fba9e 100644
--- a/numpy/_core/src/multiarray/common.h
+++ b/numpy/_core/src/multiarray/common.h
@@ -8,7 +8,7 @@
#include "npy_cpu_dispatch.h"
#include "numpy/npy_cpu.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "npy_import.h"
#include <limits.h>
diff --git a/numpy/_core/src/multiarray/common_dtype.c b/numpy/_core/src/multiarray/common_dtype.c
index 6635f13..beba6ac 100644
--- a/numpy/_core/src/multiarray/common_dtype.c
+++ b/numpy/_core/src/multiarray/common_dtype.c
@@ -10,7 +10,7 @@
#include "convert_datatype.h"
#include "dtypemeta.h"
#include "abstractdtypes.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
/*
diff --git a/numpy/_core/src/multiarray/conversion_utils.c b/numpy/_core/src/multiarray/conversion_utils.c
index 9f86842..e7b1936 100644
--- a/numpy/_core/src/multiarray/conversion_utils.c
+++ b/numpy/_core/src/multiarray/conversion_utils.c
@@ -18,6 +18,7 @@
#include "conversion_utils.h"
#include "alloc.h"
#include "npy_buffer.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
static int
diff --git a/numpy/_core/src/multiarray/convert_datatype.c b/numpy/_core/src/multiarray/convert_datatype.c
index 012b2cf..f029ad8 100644
--- a/numpy/_core/src/multiarray/convert_datatype.c
+++ b/numpy/_core/src/multiarray/convert_datatype.c
@@ -35,7 +35,8 @@
#include "dtype_transfer.h"
#include "dtype_traversal.h"
#include "arrayobject.h"
-
+#include "npy_static_data.h"
+#include "multiarraymodule.h"
/*
* Required length of string when converting from unsigned integer type.
diff --git a/numpy/_core/src/multiarray/ctors.c b/numpy/_core/src/multiarray/ctors.c
index 97fb3a4..8ee9d28 100644
--- a/numpy/_core/src/multiarray/ctors.c
+++ b/numpy/_core/src/multiarray/ctors.c
@@ -16,7 +16,7 @@
#include "npy_pycompat.h"
#include "npy_ctypes.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "common.h"
#include "ctors.h"
diff --git a/numpy/_core/src/multiarray/descriptor.c b/numpy/_core/src/multiarray/descriptor.c
index 0d1debd..c1288cd 100644
--- a/numpy/_core/src/multiarray/descriptor.c
+++ b/numpy/_core/src/multiarray/descriptor.c
@@ -22,6 +22,7 @@
#include "conversion_utils.h" /* for PyArray_TypestrConvert */
#include "templ_common.h" /* for npy_mul_sizes_with_overflow */
#include "descriptor.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
#include "alloc.h"
#include "assert.h"
diff --git a/numpy/_core/src/multiarray/dlpack.c b/numpy/_core/src/multiarray/dlpack.c
index 8f1ab72..51cb454 100644
--- a/numpy/_core/src/multiarray/dlpack.c
+++ b/numpy/_core/src/multiarray/dlpack.c
@@ -8,7 +8,7 @@
#include "numpy/arrayobject.h"
#include "npy_argparse.h"
#include "npy_dlpack.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "conversion_utils.h"
diff --git a/numpy/_core/src/multiarray/dtypemeta.c b/numpy/_core/src/multiarray/dtypemeta.c
index a21a441..87a69d8 100644
--- a/numpy/_core/src/multiarray/dtypemeta.c
+++ b/numpy/_core/src/multiarray/dtypemeta.c
@@ -26,6 +26,8 @@
#include "templ_common.h"
#include "refcount.h"
#include "dtype_traversal.h"
+#include "npy_static_data.h"
+#include "multiarraymodule.h"
#include <assert.h>
diff --git a/numpy/_core/src/multiarray/getset.c b/numpy/_core/src/multiarray/getset.c
index df2e101..092ac65 100644
--- a/numpy/_core/src/multiarray/getset.c
+++ b/numpy/_core/src/multiarray/getset.c
@@ -25,6 +25,7 @@
#include "alloc.h"
#include "npy_buffer.h"
#include "shape.h"
+#include "multiarraymodule.h"
/******************* array attribute get and set routines ******************/
diff --git a/numpy/_core/src/multiarray/item_selection.c b/numpy/_core/src/multiarray/item_selection.c
index b954f7a..4d98ce0 100644
--- a/numpy/_core/src/multiarray/item_selection.c
+++ b/numpy/_core/src/multiarray/item_selection.c
@@ -15,7 +15,7 @@
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "common.h"
#include "dtype_transfer.h"
#include "dtypemeta.h"
diff --git a/numpy/_core/src/multiarray/methods.c b/numpy/_core/src/multiarray/methods.c
index 225e13e..dd40fc4 100644
--- a/numpy/_core/src/multiarray/methods.c
+++ b/numpy/_core/src/multiarray/methods.c
@@ -29,6 +29,7 @@
#include "strfuncs.h"
#include "array_assign.h"
#include "npy_dlpack.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
#include "methods.h"
diff --git a/numpy/_core/src/multiarray/methods.h b/numpy/_core/src/multiarray/methods.h
index f70af8e..f49e020 100644
--- a/numpy/_core/src/multiarray/methods.h
+++ b/numpy/_core/src/multiarray/methods.h
@@ -1,7 +1,7 @@
#ifndef NUMPY_CORE_SRC_MULTIARRAY_METHODS_H_
#define NUMPY_CORE_SRC_MULTIARRAY_METHODS_H_
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "npy_import.h"
extern NPY_NO_EXPORT PyMethodDef array_methods[];
diff --git a/numpy/_core/src/multiarray/multiarraymodule.c b/numpy/_core/src/multiarray/multiarraymodule.c
index ebd165a..c6938ad 100644
--- a/numpy/_core/src/multiarray/multiarraymodule.c
+++ b/numpy/_core/src/multiarray/multiarraymodule.c
@@ -23,6 +23,7 @@
#include "numpy/arrayobject.h"
#include "numpy/arrayscalars.h"
+#include "multiarraymodule.h"
#include "numpy/npy_math.h"
#include "npy_argparse.h"
#include "npy_config.h"
@@ -63,7 +64,7 @@
#include "ctors.h"
#include "array_assign.h"
#include "common.h"
-#include "multiarraymodule.h"
+#include "npy_static_data.h"
#include "cblasfuncs.h"
#include "vdot.h"
#include "templ_common.h" /* for npy_mul_sizes_with_overflow */
@@ -4766,193 +4767,11 @@
return;
}
-// static variables are zero-filled by default, no need to explicitly do so
-NPY_VISIBILITY_HIDDEN npy_interned_str_struct npy_interned_str;
-NPY_VISIBILITY_HIDDEN npy_static_pydata_struct npy_static_pydata;
-NPY_VISIBILITY_HIDDEN npy_static_cdata_struct npy_static_cdata;
+// static variables are automatically zero-initialized
NPY_VISIBILITY_HIDDEN npy_thread_unsafe_state_struct npy_thread_unsafe_state;
static int
-intern_strings(void)
-{
- // this is module-level global heap allocation, it is currently
- // never freed
- npy_interned_str.current_allocator = PyUnicode_InternFromString("current_allocator");
- if (npy_interned_str.current_allocator == NULL) {
- return -1;
- }
- npy_interned_str.array = PyUnicode_InternFromString("__array__");
- if (npy_interned_str.array == NULL) {
- return -1;
- }
- npy_interned_str.array_function = PyUnicode_InternFromString("__array_function__");
- if (npy_interned_str.array_function == NULL) {
- return -1;
- }
- npy_interned_str.array_struct = PyUnicode_InternFromString("__array_struct__");
- if (npy_interned_str.array_struct == NULL) {
- return -1;
- }
- npy_interned_str.array_priority = PyUnicode_InternFromString("__array_priority__");
- if (npy_interned_str.array_priority == NULL) {
- return -1;
- }
- npy_interned_str.array_interface = PyUnicode_InternFromString("__array_interface__");
- if (npy_interned_str.array_interface == NULL) {
- return -1;
- }
- npy_interned_str.array_wrap = PyUnicode_InternFromString("__array_wrap__");
- if (npy_interned_str.array_wrap == NULL) {
- return -1;
- }
- npy_interned_str.array_finalize = PyUnicode_InternFromString("__array_finalize__");
- if (npy_interned_str.array_finalize == NULL) {
- return -1;
- }
- npy_interned_str.implementation = PyUnicode_InternFromString("_implementation");
- if (npy_interned_str.implementation == NULL) {
- return -1;
- }
- npy_interned_str.axis1 = PyUnicode_InternFromString("axis1");
- if (npy_interned_str.axis1 == NULL) {
- return -1;
- }
- npy_interned_str.axis2 = PyUnicode_InternFromString("axis2");
- if (npy_interned_str.axis2 == NULL) {
- return -1;
- }
- npy_interned_str.like = PyUnicode_InternFromString("like");
- if (npy_interned_str.like == NULL) {
- return -1;
- }
- npy_interned_str.numpy = PyUnicode_InternFromString("numpy");
- if (npy_interned_str.numpy == NULL) {
- return -1;
- }
- npy_interned_str.where = PyUnicode_InternFromString("where");
- if (npy_interned_str.where == NULL) {
- return -1;
- }
- /* scalar policies */
- npy_interned_str.convert = PyUnicode_InternFromString("convert");
- if (npy_interned_str.convert == NULL) {
- return -1;
- }
- npy_interned_str.preserve = PyUnicode_InternFromString("preserve");
- if (npy_interned_str.preserve == NULL) {
- return -1;
- }
- npy_interned_str.convert_if_no_array = PyUnicode_InternFromString("convert_if_no_array");
- if (npy_interned_str.convert_if_no_array == NULL) {
- return -1;
- }
- npy_interned_str.cpu = PyUnicode_InternFromString("cpu");
- if (npy_interned_str.cpu == NULL) {
- return -1;
- }
- npy_interned_str.dtype = PyUnicode_InternFromString("dtype");
- if (npy_interned_str.dtype == NULL) {
- return -1;
- }
- npy_interned_str.array_err_msg_substr = PyUnicode_InternFromString(
- "__array__() got an unexpected keyword argument 'copy'");
- if (npy_interned_str.array_err_msg_substr == NULL) {
- return -1;
- }
- npy_interned_str.out = PyUnicode_InternFromString("out");
- if (npy_interned_str.out == NULL) {
- return -1;
- }
- npy_interned_str.__dlpack__ = PyUnicode_InternFromString("__dlpack__");
- if (npy_interned_str.__dlpack__ == NULL) {
- return -1;
- }
- return 0;
-}
-
-#define IMPORT_GLOBAL(base_path, name, object) \
- assert(object == NULL); \
- npy_cache_import(base_path, name, &object); \
- if (object == NULL) { \
- return -1; \
- }
-
-/*
- * Initializes global constants.
- *
- * All global constants should live inside the npy_static_pydata
- * struct.
- *
- * Not all entries in the struct are initialized here, some are
- * initialized later but care must be taken in those cases to initialize
- * the constant in a thread-safe manner, ensuring it is initialized
- * exactly once.
- *
- * Anything initialized here is initialized during module import which
- * the python interpreter ensures is done in a single thread.
- *
- * Anything imported here should not need the C-layer at all and will be
- * imported before anything on the C-side is initialized.
- */
-static int
-initialize_static_globals(void)
-{
- // cached reference to objects defined in python
-
- IMPORT_GLOBAL("math", "floor",
- npy_static_pydata.math_floor_func);
-
- IMPORT_GLOBAL("math", "ceil",
- npy_static_pydata.math_ceil_func);
-
- IMPORT_GLOBAL("math", "trunc",
- npy_static_pydata.math_trunc_func);
-
- IMPORT_GLOBAL("math", "gcd",
- npy_static_pydata.math_gcd_func);
-
- IMPORT_GLOBAL("numpy.exceptions", "AxisError",
- npy_static_pydata.AxisError);
-
- IMPORT_GLOBAL("numpy.exceptions", "ComplexWarning",
- npy_static_pydata.ComplexWarning);
-
- IMPORT_GLOBAL("numpy.exceptions", "DTypePromotionError",
- npy_static_pydata.DTypePromotionError);
-
- IMPORT_GLOBAL("numpy.exceptions", "TooHardError",
- npy_static_pydata.TooHardError);
-
- IMPORT_GLOBAL("numpy.exceptions", "VisibleDeprecationWarning",
- npy_static_pydata.VisibleDeprecationWarning);
-
- IMPORT_GLOBAL("numpy._globals", "_CopyMode",
- npy_static_pydata._CopyMode);
-
- IMPORT_GLOBAL("numpy._globals", "_NoValue",
- npy_static_pydata._NoValue);
-
- IMPORT_GLOBAL("numpy._core._exceptions", "_ArrayMemoryError",
- npy_static_pydata._ArrayMemoryError);
-
- IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncBinaryResolutionError",
- npy_static_pydata._UFuncBinaryResolutionError);
-
- IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncInputCastingError",
- npy_static_pydata._UFuncInputCastingError);
-
- IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncNoLoopError",
- npy_static_pydata._UFuncNoLoopError);
-
- IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncOutputCastingError",
- npy_static_pydata._UFuncOutputCastingError);
-
- IMPORT_GLOBAL("os", "fspath",
- npy_static_pydata.os_fspath);
-
- IMPORT_GLOBAL("os", "PathLike",
- npy_static_pydata.os_PathLike);
-
+initialize_thread_unsafe_state(void) {
char *env = getenv("NUMPY_WARN_IF_NO_MEM_POLICY");
if ((env != NULL) && (strncmp(env, "1", 1) == 0)) {
numpy_warn_if_no_mem_policy = 1;
diff --git a/numpy/_core/src/multiarray/multiarraymodule.h b/numpy/_core/src/multiarray/multiarraymodule.h
index 9da928c..f03c264 100644
--- a/numpy/_core/src/multiarray/multiarraymodule.h
+++ b/numpy/_core/src/multiarray/multiarraymodule.h
@@ -1,147 +1,6 @@
#ifndef NUMPY_CORE_SRC_MULTIARRAY_MULTIARRAYMODULE_H_
#define NUMPY_CORE_SRC_MULTIARRAY_MULTIARRAYMODULE_H_
-typedef struct npy_interned_str_struct {
- PyObject *current_allocator;
- PyObject *array;
- PyObject *array_function;
- PyObject *array_struct;
- PyObject *array_priority;
- PyObject *array_interface;
- PyObject *array_wrap;
- PyObject *array_finalize;
- PyObject *implementation;
- PyObject *axis1;
- PyObject *axis2;
- PyObject *like;
- PyObject *numpy;
- PyObject *where;
- PyObject *convert;
- PyObject *preserve;
- PyObject *convert_if_no_array;
- PyObject *cpu;
- PyObject *dtype;
- PyObject *array_err_msg_substr;
- PyObject *out;
- PyObject *errmode_strings[6];
- PyObject *__dlpack__;
-} npy_interned_str_struct;
-
-/*
- * A struct that stores static global data used throughout
- * _multiarray_umath, mostly to cache results that would be
- * prohibitively expensive to compute at runtime in a tight loop.
- *
- * All items in this struct should be initialized during module
- * initialization and thereafter should be immutable. Mutating items in
- * this struct after module initialization is likely not thread-safe.
- */
-
-typedef struct npy_static_pydata_struct {
- /*
- * Used in ufunc_type_resolution.c to avoid reconstructing a tuple
- * storing the default true division return types.
- */
- PyObject *default_truediv_type_tup;
-
- /*
- * Used to set up the default extobj context variable
- */
- PyObject *default_extobj_capsule;
-
- /*
- * The global ContextVar to store the extobject. It is exposed to Python
- * as `_extobj_contextvar`.
- */
- PyObject *npy_extobj_contextvar;
-
- /*
- * A reference to ndarray's implementations for __array_*__ special methods
- */
- PyObject *ndarray_array_ufunc;
- PyObject *ndarray_array_finalize;
- PyObject *ndarray_array_function;
-
- /*
- * References to the '1' and '0' PyLong objects
- */
- PyObject *one_obj;
- PyObject *zero_obj;
-
- /*
- * References to items obtained via an import at module initialization
- */
- PyObject *AxisError;
- PyObject *ComplexWarning;
- PyObject *DTypePromotionError;
- PyObject *TooHardError;
- PyObject *VisibleDeprecationWarning;
- PyObject *_CopyMode;
- PyObject *_NoValue;
- PyObject *_ArrayMemoryError;
- PyObject *_UFuncBinaryResolutionError;
- PyObject *_UFuncInputCastingError;
- PyObject *_UFuncNoLoopError;
- PyObject *_UFuncOutputCastingError;
- PyObject *math_floor_func;
- PyObject *math_ceil_func;
- PyObject *math_trunc_func;
- PyObject *math_gcd_func;
- PyObject *os_PathLike;
- PyObject *os_fspath;
-
- /*
- * Used in the __array__ internals to avoid building a tuple inline
- */
- PyObject *kwnames_is_copy;
-
- /*
- * Used in __imatmul__ to avoid building tuples inline
- */
- PyObject *axes_1d_obj_kwargs;
- PyObject *axes_2d_obj_kwargs;
-
- /*
- * Used for CPU feature detection and dispatch
- */
- PyObject *cpu_dispatch_registry;
-
- /*
- * references to ArrayMethod implementations that are cached
- * to avoid repeatedly creating them
- */
- PyObject *VoidToGenericMethod;
- PyObject *GenericToVoidMethod;
- PyObject *ObjectToGenericMethod;
- PyObject *GenericToObjectMethod;
-} npy_static_pydata_struct;
-
-
-typedef struct npy_static_cdata_struct {
- /*
- * stores sys.flags.optimize as a long, which is used in the add_docstring
- * implementation
- */
- long optimize;
-
- /*
- * LUT used by unpack_bits
- */
- union {
- npy_uint8 bytes[8];
- npy_uint64 uint64;
- } unpack_lookup_big[256];
-
- /*
- * A look-up table to recover integer type numbers from type characters.
- *
- * See the _MAX_LETTER and LETTER_TO_NUM macros in arraytypes.c.src.
- *
- * The smallest type number is ?, the largest is bounded by 'z'.
- */
- npy_int16 _letter_to_num['z' + 1 - '?'];
-} npy_static_cdata_struct;
-
/*
* A struct storing thread-unsafe global state for the _multiarray_umath
* module. We should refactor so the global state is thread-safe,
@@ -214,9 +73,6 @@
} npy_thread_unsafe_state_struct;
-NPY_VISIBILITY_HIDDEN extern npy_interned_str_struct npy_interned_str;
-NPY_VISIBILITY_HIDDEN extern npy_static_pydata_struct npy_static_pydata;
-NPY_VISIBILITY_HIDDEN extern npy_static_cdata_struct npy_static_cdata;
NPY_VISIBILITY_HIDDEN extern npy_thread_unsafe_state_struct npy_thread_unsafe_state;
diff --git a/numpy/_core/src/multiarray/npy_static_data.c b/numpy/_core/src/multiarray/npy_static_data.c
new file mode 100644
index 0000000..be25c05
--- /dev/null
+++ b/numpy/_core/src/multiarray/npy_static_data.c
@@ -0,0 +1,269 @@
+/* numpy static data structs and initialization */
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _UMATHMODULE
+#define _MULTIARRAYMODULE
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <structmember.h>
+
+#include "numpy/ndarraytypes.h"
+#include "numpy/npy_common.h"
+#include "numpy/arrayobject.h"
+#include "npy_import.h"
+#include "npy_static_data.h"
+
+// static variables are zero-filled by default, no need to explicitly do so
+NPY_VISIBILITY_HIDDEN npy_interned_str_struct npy_interned_str;
+NPY_VISIBILITY_HIDDEN npy_static_pydata_struct npy_static_pydata;
+NPY_VISIBILITY_HIDDEN npy_static_cdata_struct npy_static_cdata;
+
+NPY_NO_EXPORT int
+intern_strings(void)
+{
+ npy_interned_str.current_allocator = PyUnicode_InternFromString("current_allocator");
+ if (npy_interned_str.current_allocator == NULL) {
+ return -1;
+ }
+ npy_interned_str.array = PyUnicode_InternFromString("__array__");
+ if (npy_interned_str.array == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_function = PyUnicode_InternFromString("__array_function__");
+ if (npy_interned_str.array_function == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_struct = PyUnicode_InternFromString("__array_struct__");
+ if (npy_interned_str.array_struct == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_priority = PyUnicode_InternFromString("__array_priority__");
+ if (npy_interned_str.array_priority == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_interface = PyUnicode_InternFromString("__array_interface__");
+ if (npy_interned_str.array_interface == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_ufunc = PyUnicode_InternFromString("__array_ufunc__");
+ if (npy_interned_str.array_ufunc == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_wrap = PyUnicode_InternFromString("__array_wrap__");
+ if (npy_interned_str.array_wrap == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_finalize = PyUnicode_InternFromString("__array_finalize__");
+ if (npy_interned_str.array_finalize == NULL) {
+ return -1;
+ }
+ npy_interned_str.implementation = PyUnicode_InternFromString("_implementation");
+ if (npy_interned_str.implementation == NULL) {
+ return -1;
+ }
+ npy_interned_str.axis1 = PyUnicode_InternFromString("axis1");
+ if (npy_interned_str.axis1 == NULL) {
+ return -1;
+ }
+ npy_interned_str.axis2 = PyUnicode_InternFromString("axis2");
+ if (npy_interned_str.axis2 == NULL) {
+ return -1;
+ }
+ npy_interned_str.like = PyUnicode_InternFromString("like");
+ if (npy_interned_str.like == NULL) {
+ return -1;
+ }
+ npy_interned_str.numpy = PyUnicode_InternFromString("numpy");
+ if (npy_interned_str.numpy == NULL) {
+ return -1;
+ }
+ npy_interned_str.where = PyUnicode_InternFromString("where");
+ if (npy_interned_str.where == NULL) {
+ return -1;
+ }
+ npy_interned_str.convert = PyUnicode_InternFromString("convert");
+ if (npy_interned_str.convert == NULL) {
+ return -1;
+ }
+ npy_interned_str.preserve = PyUnicode_InternFromString("preserve");
+ if (npy_interned_str.preserve == NULL) {
+ return -1;
+ }
+ npy_interned_str.convert_if_no_array = PyUnicode_InternFromString("convert_if_no_array");
+ if (npy_interned_str.convert_if_no_array == NULL) {
+ return -1;
+ }
+ npy_interned_str.cpu = PyUnicode_InternFromString("cpu");
+ if (npy_interned_str.cpu == NULL) {
+ return -1;
+ }
+ npy_interned_str.dtype = PyUnicode_InternFromString("dtype");
+ if (npy_interned_str.dtype == NULL) {
+ return -1;
+ }
+ npy_interned_str.array_err_msg_substr = PyUnicode_InternFromString(
+ "__array__() got an unexpected keyword argument 'copy'");
+ if (npy_interned_str.array_err_msg_substr == NULL) {
+ return -1;
+ }
+ npy_interned_str.out = PyUnicode_InternFromString("out");
+ if (npy_interned_str.out == NULL) {
+ return -1;
+ }
+ npy_interned_str.__dlpack__ = PyUnicode_InternFromString("__dlpack__");
+ if (npy_interned_str.__dlpack__ == NULL) {
+ return -1;
+ }
+ npy_interned_str.pyvals_name = PyUnicode_InternFromString("UFUNC_PYVALS_NAME");
+ if (npy_interned_str.pyvals_name == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+#define IMPORT_GLOBAL(base_path, name, object) \
+ assert(object == NULL); \
+ npy_cache_import(base_path, name, &object); \
+ if (object == NULL) { \
+ return -1; \
+ }
+
+
+/*
+ * Initializes global constants.
+ *
+ * All global constants should live inside the npy_static_pydata
+ * struct.
+ *
+ * Not all entries in the struct are initialized here, some are
+ * initialized later but care must be taken in those cases to initialize
+ * the constant in a thread-safe manner, ensuring it is initialized
+ * exactly once.
+ *
+ * Anything initialized here is initialized during module import which
+ * the python interpreter ensures is done in a single thread.
+ *
+ * Anything imported here should not need the C-layer at all and will be
+ * imported before anything on the C-side is initialized.
+ */
+NPY_NO_EXPORT int
+initialize_static_globals(void)
+{
+ // cached reference to objects defined in python
+
+ IMPORT_GLOBAL("math", "floor",
+ npy_static_pydata.math_floor_func);
+
+ IMPORT_GLOBAL("math", "ceil",
+ npy_static_pydata.math_ceil_func);
+
+ IMPORT_GLOBAL("math", "trunc",
+ npy_static_pydata.math_trunc_func);
+
+ IMPORT_GLOBAL("math", "gcd",
+ npy_static_pydata.math_gcd_func);
+
+ IMPORT_GLOBAL("numpy.exceptions", "AxisError",
+ npy_static_pydata.AxisError);
+
+ IMPORT_GLOBAL("numpy.exceptions", "ComplexWarning",
+ npy_static_pydata.ComplexWarning);
+
+ IMPORT_GLOBAL("numpy.exceptions", "DTypePromotionError",
+ npy_static_pydata.DTypePromotionError);
+
+ IMPORT_GLOBAL("numpy.exceptions", "TooHardError",
+ npy_static_pydata.TooHardError);
+
+ IMPORT_GLOBAL("numpy.exceptions", "VisibleDeprecationWarning",
+ npy_static_pydata.VisibleDeprecationWarning);
+
+ IMPORT_GLOBAL("numpy._globals", "_CopyMode",
+ npy_static_pydata._CopyMode);
+
+ IMPORT_GLOBAL("numpy._globals", "_NoValue",
+ npy_static_pydata._NoValue);
+
+ IMPORT_GLOBAL("numpy._core._exceptions", "_ArrayMemoryError",
+ npy_static_pydata._ArrayMemoryError);
+
+ IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncBinaryResolutionError",
+ npy_static_pydata._UFuncBinaryResolutionError);
+
+ IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncInputCastingError",
+ npy_static_pydata._UFuncInputCastingError);
+
+ IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncNoLoopError",
+ npy_static_pydata._UFuncNoLoopError);
+
+ IMPORT_GLOBAL("numpy._core._exceptions", "_UFuncOutputCastingError",
+ npy_static_pydata._UFuncOutputCastingError);
+
+ IMPORT_GLOBAL("os", "fspath",
+ npy_static_pydata.os_fspath);
+
+ IMPORT_GLOBAL("os", "PathLike",
+ npy_static_pydata.os_PathLike);
+
+ // default_truediv_type_tupS
+ PyArray_Descr *tmp = PyArray_DescrFromType(NPY_DOUBLE);
+ if (tmp == NULL) {
+ return -1;
+ }
+
+ npy_static_pydata.default_truediv_type_tup =
+ PyTuple_Pack(3, tmp, tmp, tmp);
+ if (npy_static_pydata.default_truediv_type_tup == NULL) {
+ Py_DECREF(tmp);
+ return -1;
+ }
+ Py_DECREF(tmp);
+
+ PyObject *flags = PySys_GetObject("flags"); /* borrowed object */
+ if (flags == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "cannot get sys.flags");
+ return -1;
+ }
+ PyObject *level = PyObject_GetAttrString(flags, "optimize");
+ if (level == NULL) {
+ return -1;
+ }
+ npy_static_cdata.optimize = PyLong_AsLong(level);
+ Py_DECREF(level);
+
+ /*
+ * see unpack_bits for how this table is used.
+ *
+ * LUT for bigendian bitorder, littleendian is handled via
+ * byteswapping in the loop.
+ *
+ * 256 8 byte blocks representing 8 bits expanded to 1 or 0 bytes
+ */
+ npy_intp j;
+ for (j=0; j < 256; j++) {
+ npy_intp k;
+ for (k=0; k < 8; k++) {
+ npy_uint8 v = (j & (1 << k)) == (1 << k);
+ npy_static_cdata.unpack_lookup_big[j].bytes[7 - k] = v;
+ }
+ }
+
+ npy_static_pydata.kwnames_is_copy = Py_BuildValue("(s)", "copy");
+ if (npy_static_pydata.kwnames_is_copy == NULL) {
+ return -1;
+ }
+
+ npy_static_pydata.one_obj = PyLong_FromLong((long) 1);
+ if (npy_static_pydata.one_obj == NULL) {
+ return -1;
+ }
+
+ npy_static_pydata.zero_obj = PyLong_FromLong((long) 0);
+ if (npy_static_pydata.zero_obj == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
diff --git a/numpy/_core/src/multiarray/npy_static_data.h b/numpy/_core/src/multiarray/npy_static_data.h
new file mode 100644
index 0000000..311f6bc
--- /dev/null
+++ b/numpy/_core/src/multiarray/npy_static_data.h
@@ -0,0 +1,157 @@
+#ifndef NUMPY_CORE_SRC_MULTIARRAY_STATIC_DATA_H_
+#define NUMPY_CORE_SRC_MULTIARRAY_STATIC_DATA_H_
+
+NPY_NO_EXPORT int
+initialize_static_globals(void);
+
+NPY_NO_EXPORT int
+intern_strings(void);
+
+typedef struct npy_interned_str_struct {
+ PyObject *current_allocator;
+ PyObject *array;
+ PyObject *array_function;
+ PyObject *array_struct;
+ PyObject *array_priority;
+ PyObject *array_interface;
+ PyObject *array_wrap;
+ PyObject *array_finalize;
+ PyObject *array_ufunc;
+ PyObject *implementation;
+ PyObject *axis1;
+ PyObject *axis2;
+ PyObject *like;
+ PyObject *numpy;
+ PyObject *where;
+ PyObject *convert;
+ PyObject *preserve;
+ PyObject *convert_if_no_array;
+ PyObject *cpu;
+ PyObject *dtype;
+ PyObject *array_err_msg_substr;
+ PyObject *out;
+ PyObject *errmode_strings[6];
+ PyObject *__dlpack__;
+ PyObject *pyvals_name;
+} npy_interned_str_struct;
+
+/*
+ * A struct that stores static global data used throughout
+ * _multiarray_umath, mostly to cache results that would be
+ * prohibitively expensive to compute at runtime in a tight loop.
+ *
+ * All items in this struct should be initialized during module
+ * initialization and thereafter should be immutable. Mutating items in
+ * this struct after module initialization is likely not thread-safe.
+ */
+
+typedef struct npy_static_pydata_struct {
+ /*
+ * Used in ufunc_type_resolution.c to avoid reconstructing a tuple
+ * storing the default true division return types.
+ */
+ PyObject *default_truediv_type_tup;
+
+ /*
+ * Used to set up the default extobj context variable
+ */
+ PyObject *default_extobj_capsule;
+
+ /*
+ * The global ContextVar to store the extobject. It is exposed to Python
+ * as `_extobj_contextvar`.
+ */
+ PyObject *npy_extobj_contextvar;
+
+ /*
+ * A reference to ndarray's implementations for __array_*__ special methods
+ */
+ PyObject *ndarray_array_ufunc;
+ PyObject *ndarray_array_finalize;
+ PyObject *ndarray_array_function;
+
+ /*
+ * References to the '1' and '0' PyLong objects
+ */
+ PyObject *one_obj;
+ PyObject *zero_obj;
+
+ /*
+ * References to items obtained via an import at module initialization
+ */
+ PyObject *AxisError;
+ PyObject *ComplexWarning;
+ PyObject *DTypePromotionError;
+ PyObject *TooHardError;
+ PyObject *VisibleDeprecationWarning;
+ PyObject *_CopyMode;
+ PyObject *_NoValue;
+ PyObject *_ArrayMemoryError;
+ PyObject *_UFuncBinaryResolutionError;
+ PyObject *_UFuncInputCastingError;
+ PyObject *_UFuncNoLoopError;
+ PyObject *_UFuncOutputCastingError;
+ PyObject *math_floor_func;
+ PyObject *math_ceil_func;
+ PyObject *math_trunc_func;
+ PyObject *math_gcd_func;
+ PyObject *os_PathLike;
+ PyObject *os_fspath;
+
+ /*
+ * Used in the __array__ internals to avoid building a tuple inline
+ */
+ PyObject *kwnames_is_copy;
+
+ /*
+ * Used in __imatmul__ to avoid building tuples inline
+ */
+ PyObject *axes_1d_obj_kwargs;
+ PyObject *axes_2d_obj_kwargs;
+
+ /*
+ * Used for CPU feature detection and dispatch
+ */
+ PyObject *cpu_dispatch_registry;
+
+ /*
+ * references to ArrayMethod implementations that are cached
+ * to avoid repeatedly creating them
+ */
+ PyObject *VoidToGenericMethod;
+ PyObject *GenericToVoidMethod;
+ PyObject *ObjectToGenericMethod;
+ PyObject *GenericToObjectMethod;
+} npy_static_pydata_struct;
+
+
+typedef struct npy_static_cdata_struct {
+ /*
+ * stores sys.flags.optimize as a long, which is used in the add_docstring
+ * implementation
+ */
+ long optimize;
+
+ /*
+ * LUT used by unpack_bits
+ */
+ union {
+ npy_uint8 bytes[8];
+ npy_uint64 uint64;
+ } unpack_lookup_big[256];
+
+ /*
+ * A look-up table to recover integer type numbers from type characters.
+ *
+ * See the _MAX_LETTER and LETTER_TO_NUM macros in arraytypes.c.src.
+ *
+ * The smallest type number is ?, the largest is bounded by 'z'.
+ */
+ npy_int16 _letter_to_num['z' + 1 - '?'];
+} npy_static_cdata_struct;
+
+NPY_VISIBILITY_HIDDEN extern npy_interned_str_struct npy_interned_str;
+NPY_VISIBILITY_HIDDEN extern npy_static_pydata_struct npy_static_pydata;
+NPY_VISIBILITY_HIDDEN extern npy_static_cdata_struct npy_static_cdata;
+
+#endif // NUMPY_CORE_SRC_MULTIARRAY_STATIC_DATA_H_
diff --git a/numpy/_core/src/multiarray/shape.c b/numpy/_core/src/multiarray/shape.c
index 72bea87..c33272d 100644
--- a/numpy/_core/src/multiarray/shape.c
+++ b/numpy/_core/src/multiarray/shape.c
@@ -19,7 +19,7 @@
#include "shape.h"
-#include "multiarraymodule.h" /* for interned strings */
+#include "npy_static_data.h" /* for interned strings */
#include "templ_common.h" /* for npy_mul_sizes_with_overflow */
#include "common.h" /* for convert_shape_to_string */
#include "alloc.h"
diff --git a/numpy/_core/src/umath/_scaled_float_dtype.c b/numpy/_core/src/umath/_scaled_float_dtype.c
index 99d0c64..fbdbbb8 100644
--- a/numpy/_core/src/umath/_scaled_float_dtype.c
+++ b/numpy/_core/src/umath/_scaled_float_dtype.c
@@ -25,6 +25,7 @@
#include "dtypemeta.h"
#include "dispatching.h"
#include "gil_utils.h"
+#include "multiarraymodule.h"
typedef struct {
PyArray_Descr base;
diff --git a/numpy/_core/src/umath/extobj.c b/numpy/_core/src/umath/extobj.c
index 0405b14..f9194ac 100644
--- a/numpy/_core/src/umath/extobj.c
+++ b/numpy/_core/src/umath/extobj.c
@@ -14,7 +14,6 @@
#include "extobj.h"
#include "numpy/ufuncobject.h"
-#include "ufunc_object.h" /* for npy_um_str_pyvals_name */
#include "common.h"
diff --git a/numpy/_core/src/umath/funcs.inc.src b/numpy/_core/src/umath/funcs.inc.src
index 131a678..3825bd8 100644
--- a/numpy/_core/src/umath/funcs.inc.src
+++ b/numpy/_core/src/umath/funcs.inc.src
@@ -9,6 +9,7 @@
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#include "npy_import.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
/*
diff --git a/numpy/_core/src/umath/override.c b/numpy/_core/src/umath/override.c
index ad9c9a4..b7147a2 100644
--- a/numpy/_core/src/umath/override.c
+++ b/numpy/_core/src/umath/override.c
@@ -4,6 +4,7 @@
#include "numpy/ndarraytypes.h"
#include "numpy/ufuncobject.h"
#include "npy_import.h"
+#include "npy_static_data.h"
#include "multiarraymodule.h"
#include "npy_pycompat.h"
#include "override.h"
diff --git a/numpy/_core/src/umath/ufunc_object.c b/numpy/_core/src/umath/ufunc_object.c
index aedb548..48b4f59 100644
--- a/numpy/_core/src/umath/ufunc_object.c
+++ b/numpy/_core/src/umath/ufunc_object.c
@@ -62,6 +62,8 @@
#include "legacy_array_method.h"
#include "abstractdtypes.h"
#include "mapping.h"
+#include "npy_static_data.h"
+#include "multiarraymodule.h"
/* TODO: Only for `NpyIter_GetTransferFlags` until it is public */
#define NPY_ITERATOR_IMPLEMENTATION_CODE
diff --git a/numpy/_core/src/umath/ufunc_object.h b/numpy/_core/src/umath/ufunc_object.h
index 645023f..f8e5223 100644
--- a/numpy/_core/src/umath/ufunc_object.h
+++ b/numpy/_core/src/umath/ufunc_object.h
@@ -10,9 +10,4 @@
NPY_NO_EXPORT PyObject *
PyUFunc_GetDefaultIdentity(PyUFuncObject *ufunc, npy_bool *reorderable);
-/* strings from umathmodule.c that are interned on umath import */
-NPY_VISIBILITY_HIDDEN extern PyObject *npy_um_str_array_ufunc;
-NPY_VISIBILITY_HIDDEN extern PyObject *npy_um_str_array_wrap;
-NPY_VISIBILITY_HIDDEN extern PyObject *npy_um_str_pyvals_name;
-
#endif
diff --git a/numpy/_core/src/umath/umathmodule.c b/numpy/_core/src/umath/umathmodule.c
index f83e33e..5402b17 100644
--- a/numpy/_core/src/umath/umathmodule.c
+++ b/numpy/_core/src/umath/umathmodule.c
@@ -209,29 +209,6 @@
*****************************************************************************
*/
-NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_array_ufunc = NULL;
-NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_array_wrap = NULL;
-NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_pyvals_name = NULL;
-
-/* intern some strings used in ufuncs, returns 0 on success */
-static int
-intern_strings(void)
-{
- npy_um_str_array_ufunc = PyUnicode_InternFromString("__array_ufunc__");
- if (npy_um_str_array_ufunc == NULL) {
- return -1;
- }
- npy_um_str_array_wrap = PyUnicode_InternFromString("__array_wrap__");
- if (npy_um_str_array_wrap == NULL) {
- return -1;
- }
- npy_um_str_pyvals_name = PyUnicode_InternFromString(UFUNC_PYVALS_NAME);
- if (npy_um_str_pyvals_name == NULL) {
- return -1;
- }
- return 0;
-}
-
/* Setup the umath part of the module */
int initumath(PyObject *m)
@@ -297,12 +274,6 @@
PyDict_SetItemString(d, "conj", s);
PyDict_SetItemString(d, "mod", s2);
- if (intern_strings() < 0) {
- PyErr_SetString(PyExc_RuntimeError,
- "cannot intern strings while initializing _multiarray_umath.");
- return -1;
- }
-
/*
* Set up promoters for logical functions
* TODO: This should probably be done at a better place, or even in the