[Python-checkins] gh-100227: Move the dtoa State to PyInterpreterState (gh-102331)

ericsnowcurrently webhook-mailer at python.org
Tue Feb 28 15:14:48 EST 2023


https://github.com/python/cpython/commit/f300a1fa4c121f7807cbda4fc8bb26240c69ea74
commit: f300a1fa4c121f7807cbda4fc8bb26240c69ea74
branch: main
author: Eric Snow <ericsnowcurrently at gmail.com>
committer: ericsnowcurrently <ericsnowcurrently at gmail.com>
date: 2023-02-28T13:14:40-07:00
summary:

gh-100227: Move the dtoa State to PyInterpreterState (gh-102331)

https://github.com/python/cpython/issues/100227

files:
M Include/internal/pycore_dtoa.h
M Include/internal/pycore_interp.h
M Include/internal/pycore_runtime.h
M Include/internal/pycore_runtime_init.h
M Python/dtoa.c
M Python/pystate.c

diff --git a/Include/internal/pycore_dtoa.h b/Include/internal/pycore_dtoa.h
index 67189cf0ade6..fb524770efed 100644
--- a/Include/internal/pycore_dtoa.h
+++ b/Include/internal/pycore_dtoa.h
@@ -24,10 +24,11 @@ Bigint {
 
 #ifdef Py_USING_MEMORY_DEBUGGER
 
-struct _dtoa_runtime_state {
+struct _dtoa_state {
     int _not_used;
 };
-#define _dtoa_runtime_state_INIT {0}
+#define _dtoa_interp_state_INIT(INTERP) \
+    {0}
 
 #else  // !Py_USING_MEMORY_DEBUGGER
 
@@ -40,7 +41,7 @@ struct _dtoa_runtime_state {
 #define Bigint_PREALLOC_SIZE \
     ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
 
-struct _dtoa_runtime_state {
+struct _dtoa_state {
     /* p5s is a linked list of powers of 5 of the form 5**(2**i), i >= 2 */
     // XXX This should be freed during runtime fini.
     struct Bigint *p5s;
@@ -48,9 +49,9 @@ struct _dtoa_runtime_state {
     double preallocated[Bigint_PREALLOC_SIZE];
     double *preallocated_next;
 };
-#define _dtoa_runtime_state_INIT(runtime) \
+#define _dtoa_state_INIT(INTERP) \
     { \
-        .preallocated_next = runtime.dtoa.preallocated, \
+        .preallocated_next = (INTERP)->dtoa.preallocated, \
     }
 
 #endif  // !Py_USING_MEMORY_DEBUGGER
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 60de31b336f6..7ef9c40153e4 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -16,6 +16,7 @@ extern "C" {
 #include "pycore_code.h"          // struct callable_cache
 #include "pycore_context.h"       // struct _Py_context_state
 #include "pycore_dict_state.h"    // struct _Py_dict_state
+#include "pycore_dtoa.h"          // struct _dtoa_state
 #include "pycore_exceptions.h"    // struct _Py_exc_state
 #include "pycore_floatobject.h"   // struct _Py_float_state
 #include "pycore_function.h"      // FUNC_MAX_WATCHERS
@@ -139,6 +140,7 @@ struct _is {
     struct _Py_unicode_state unicode;
     struct _Py_float_state float_state;
     struct _Py_long_state long_state;
+    struct _dtoa_state dtoa;
     /* Using a cache is very effective since typically only a single slice is
        created and then deleted again. */
     PySliceObject *slice_cache;
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index 9ef270791576..2350eaab5976 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -11,7 +11,6 @@ extern "C" {
 #include "pycore_atomic.h"          /* _Py_atomic_address */
 #include "pycore_ceval_state.h"     // struct _ceval_runtime_state
 #include "pycore_dict_state.h"      // struct _Py_dict_runtime_state
-#include "pycore_dtoa.h"            // struct _dtoa_runtime_state
 #include "pycore_floatobject.h"     // struct _Py_float_runtime_state
 #include "pycore_faulthandler.h"    // struct _faulthandler_runtime_state
 #include "pycore_function.h"        // struct _func_runtime_state
@@ -141,7 +140,6 @@ typedef struct pyruntimestate {
     struct _ceval_runtime_state ceval;
     struct _gilstate_runtime_state gilstate;
     struct _getargs_runtime_state getargs;
-    struct _dtoa_runtime_state dtoa;
     struct _fileutils_state fileutils;
     struct _faulthandler_runtime_state faulthandler;
     struct _tracemalloc_runtime_state tracemalloc;
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index a8d5953ff98b..b54adf04761d 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -53,7 +53,6 @@ extern "C" {
         .gilstate = { \
             .check_enabled = 1, \
         }, \
-        .dtoa = _dtoa_runtime_state_INIT(runtime), \
         .fileutils = { \
             .force_ascii = -1, \
         }, \
@@ -94,10 +93,10 @@ extern "C" {
                 }, \
             }, \
         }, \
-        ._main_interpreter = _PyInterpreterState_INIT, \
+        ._main_interpreter = _PyInterpreterState_INIT(runtime._main_interpreter), \
     }
 
-#define _PyInterpreterState_INIT \
+#define _PyInterpreterState_INIT(INTERP) \
     { \
         .id_refcount = -1, \
         .imports = IMPORTS_INIT, \
@@ -113,6 +112,7 @@ extern "C" {
                 { .threshold = 10, }, \
             }, \
         }, \
+        .dtoa = _dtoa_state_INIT(&(INTERP)), \
         .static_objects = { \
             .singletons = { \
                 ._not_used = 1, \
diff --git a/Python/dtoa.c b/Python/dtoa.c
index cff5f1b0658e..6ea60ac9946e 100644
--- a/Python/dtoa.c
+++ b/Python/dtoa.c
@@ -119,7 +119,7 @@
 
 #include "Python.h"
 #include "pycore_dtoa.h"          // _PY_SHORT_FLOAT_REPR
-#include "pycore_runtime.h"       // _PyRuntime
+#include "pycore_pystate.h"       // _PyInterpreterState_GET()
 #include <stdlib.h>               // exit()
 
 /* if _PY_SHORT_FLOAT_REPR == 0, then don't even try to compile
@@ -339,9 +339,9 @@ typedef struct Bigint Bigint;
    Bfree to PyMem_Free.  Investigate whether this has any significant
    performance on impact. */
 
-#define freelist _PyRuntime.dtoa.freelist
-#define private_mem _PyRuntime.dtoa.preallocated
-#define pmem_next _PyRuntime.dtoa.preallocated_next
+#define freelist interp->dtoa.freelist
+#define private_mem interp->dtoa.preallocated
+#define pmem_next interp->dtoa.preallocated_next
 
 /* Allocate space for a Bigint with up to 1<<k digits */
 
@@ -351,6 +351,7 @@ Balloc(int k)
     int x;
     Bigint *rv;
     unsigned int len;
+    PyInterpreterState *interp = _PyInterpreterState_GET();
 
     if (k <= Bigint_Kmax && (rv = freelist[k]))
         freelist[k] = rv->next;
@@ -385,6 +386,7 @@ Bfree(Bigint *v)
         if (v->k > Bigint_Kmax)
             FREE((void*)v);
         else {
+            PyInterpreterState *interp = _PyInterpreterState_GET();
             v->next = freelist[v->k];
             freelist[v->k] = v;
         }
@@ -692,7 +694,8 @@ pow5mult(Bigint *b, int k)
 
     if (!(k >>= 2))
         return b;
-    p5 = _PyRuntime.dtoa.p5s;
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    p5 = interp->dtoa.p5s;
     if (!p5) {
         /* first time */
         p5 = i2b(625);
@@ -700,7 +703,7 @@ pow5mult(Bigint *b, int k)
             Bfree(b);
             return NULL;
         }
-        _PyRuntime.dtoa.p5s = p5;
+        interp->dtoa.p5s = p5;
         p5->next = 0;
     }
     for(;;) {
diff --git a/Python/pystate.c b/Python/pystate.c
index 3c655bf38958..28606e4f32f7 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -3,7 +3,8 @@
 
 #include "Python.h"
 #include "pycore_ceval.h"
-#include "pycore_code.h"           // stats
+#include "pycore_code.h"          // stats
+#include "pycore_dtoa.h"          // _dtoa_state_INIT()
 #include "pycore_frame.h"
 #include "pycore_initconfig.h"
 #include "pycore_object.h"        // _PyType_InitCache()
@@ -618,6 +619,18 @@ free_interpreter(PyInterpreterState *interp)
    e.g. by PyMem_RawCalloc() or memset(), or otherwise pre-initialized.
    The runtime state is not manipulated.  Instead it is assumed that
    the interpreter is getting added to the runtime.
+
+   Note that the main interpreter was statically initialized as part
+   of the runtime and most state is already set properly.  That leaves
+   a small number of fields to initialize dynamically, as well as some
+   that are initialized lazily.
+
+   For subinterpreters we memcpy() the main interpreter in
+   PyInterpreterState_New(), leaving it in the same mostly-initialized
+   state.  The only difference is that the interpreter has some
+   self-referential state that is statically initializexd to the
+   main interpreter.  We fix those fields here, in addition
+   to the other dynamically initialized fields.
   */
 
 static void
@@ -645,6 +658,11 @@ init_interpreter(PyInterpreterState *interp,
     PyConfig_InitPythonConfig(&interp->config);
     _PyType_InitCache(interp);
 
+    if (interp != &runtime->_main_interpreter) {
+        /* Fix the self-referential, statically initialized fields. */
+        interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
+    }
+
     interp->_initialized = 1;
 }
 



More information about the Python-checkins mailing list