Skip to content

Commit ed9fa0a

Browse files
eendebakptclaude
andcommitted
gh-NNNN: Remove Python/dtoa.c and its init/fini plumbing
Python/dtoa.c (the 2800-line David Gay dtoa + _Py_dg_strtod) is now completely unreachable — format_float_short and _PyOS_ascii_strtod went through _Py_fmt_dtoa and _Py_wuffs_strtod in the previous two commits. Delete the file and strip the plumbing it had acquired across the rest of the tree: * Include/internal/pycore_dtoa.h: drop the _Py_dg_* declarations, _PyDtoa_Init/Fini, and _dtoa_state_INIT. Header now only declares _Py_fmt_dtoa / _Py_fmt_dtoa_free / _Py_wuffs_strtod. * Include/internal/pycore_interp_structs.h: remove `struct Bigint`, `struct _dtoa_state`, and the `dtoa` field on `PyInterpreterState`. Saves ~2.3 KB of static state per interpreter. * Include/internal/pycore_runtime_init.h: drop the `.dtoa = ...` line and the now-unused pycore_dtoa.h include. * Python/pystate.c / Python/pylifecycle.c: drop the dtoa-state fix-up in per-interpreter init and the _PyDtoa_Init / _PyDtoa_Fini calls. * Makefile.pre.in: drop Python/dtoa.o from LIBRARY_OBJS and the dedicated -fno-strict-aliasing rule that existed to work around a clang 4 miscompile of dtoa's ratio() (bpo-30104). * PCbuild/pythoncore.vcxproj{,.filters}: drop the ClCompile entry for Python/dtoa.c on Windows. Full float-formatting + strtod + C-API regression passes (1,501 tests across test_float, test_strtod, test_format, test_capi). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c1502a0 commit ed9fa0a

File tree

9 files changed

+21
-2932
lines changed

9 files changed

+21
-2932
lines changed

Include/internal/pycore_dtoa.h

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,16 @@ extern "C" {
1111
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
1212

1313

14-
#if defined(Py_USING_MEMORY_DEBUGGER) || _PY_SHORT_FLOAT_REPR == 0
15-
16-
#define _dtoa_state_INIT(INTERP) \
17-
{0}
18-
19-
#else
20-
21-
#define _dtoa_state_INIT(INTERP) \
22-
{ \
23-
.preallocated_next = (INTERP)->dtoa.preallocated, \
24-
}
25-
#endif
26-
27-
extern double _Py_dg_strtod(const char *str, char **ptr);
28-
extern char* _Py_dg_dtoa(double d, int mode, int ndigits,
29-
int *decpt, int *sign, char **rve);
30-
extern void _Py_dg_freedtoa(char *s);
31-
32-
33-
extern PyStatus _PyDtoa_Init(PyInterpreterState *interp);
34-
extern void _PyDtoa_Fini(PyInterpreterState *interp);
35-
36-
// Replacements for the two David Gay entry points above. _Py_fmt_dtoa is
37-
// backed by Python/_fmt/ (a vendored trim of fmtlib); _Py_wuffs_strtod is
38-
// backed by Python/_wuffs/ (a vendored trim of Wuffs). Calling conventions
39-
// match _Py_dg_dtoa / _Py_dg_strtod respectively so pystrtod.c can swap them
40-
// in without touching call-site logic.
14+
// Float <-> string conversion entry points for libpython. Both replace
15+
// David Gay's dtoa machinery that previously lived in Python/dtoa.c:
16+
//
17+
// * _Py_fmt_dtoa is backed by a vendored trim of fmtlib ({fmt}) in
18+
// Python/_fmt/. Mirrors _Py_dg_dtoa's calling convention for modes
19+
// 0/2/3. The returned char* is PyMem_Malloc'd — pair each call with
20+
// _Py_fmt_dtoa_free.
21+
//
22+
// * _Py_wuffs_strtod is backed by a vendored trim of Wuffs in
23+
// Python/_wuffs/. Mirrors _Py_dg_strtod's calling convention.
4124
extern char* _Py_fmt_dtoa(double d, int mode, int ndigits,
4225
int *decpt, int *sign, char **rve);
4326
extern void _Py_fmt_dtoa_free(char *s);

Include/internal/pycore_interp_structs.h

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -454,44 +454,11 @@ typedef struct _PyOptimizationConfig {
454454
bool uops_optimize_enabled;
455455
} _PyOptimizationConfig;
456456

457-
struct
458-
Bigint {
459-
struct Bigint *next;
460-
int k, maxwds, sign, wds;
461-
uint32_t x[1];
462-
};
463-
464-
#if defined(Py_USING_MEMORY_DEBUGGER) || _PY_SHORT_FLOAT_REPR == 0
465-
466-
struct _dtoa_state {
467-
int _not_used;
468-
};
469-
470-
#else // !Py_USING_MEMORY_DEBUGGER && _PY_SHORT_FLOAT_REPR != 0
471-
472-
/* The size of the Bigint freelist */
473-
#define Bigint_Kmax 7
474-
475-
/* The size of the cached powers of 5 array */
476-
#define Bigint_Pow5size 8
477-
478-
#ifndef PRIVATE_MEM
479-
#define PRIVATE_MEM 2304
480-
#endif
481-
#define Bigint_PREALLOC_SIZE \
482-
((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
483-
484-
struct _dtoa_state {
485-
// p5s is an array of powers of 5 of the form:
486-
// 5**(2**(i+2)) for 0 <= i < Bigint_Pow5size
487-
struct Bigint *p5s[Bigint_Pow5size];
488-
// XXX This should be freed during runtime fini.
489-
struct Bigint *freelist[Bigint_Kmax+1];
490-
double preallocated[Bigint_PREALLOC_SIZE];
491-
double *preallocated_next;
492-
};
493-
494-
#endif // !Py_USING_MEMORY_DEBUGGER
457+
// `struct Bigint` and `struct _dtoa_state` used to live here to back the
458+
// David Gay dtoa's per-interpreter `Bigint` freelist and 2 KB pre-allocated
459+
// arena. With dtoa replaced by fmt + wuffs, neither is reachable — fmt uses
460+
// stdlib malloc via its own allocator template, and wuffs uses stack-bounded
461+
// state.
495462

496463
struct _py_code_state {
497464
PyMutex mutex;
@@ -988,7 +955,6 @@ struct _is {
988955
struct _py_object_state object_state;
989956
struct _Py_unicode_state unicode;
990957
struct _Py_long_state long_state;
991-
struct _dtoa_state dtoa;
992958
struct _py_func_state func_state;
993959
struct _py_code_state code_state;
994960

Include/internal/pycore_runtime_init.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ extern "C" {
1111
#include "pycore_structs.h"
1212
#include "pycore_ceval_state.h" // _PyEval_RUNTIME_PERF_INIT
1313
#include "pycore_debug_offsets.h" // _Py_DebugOffsets_INIT()
14-
#include "pycore_dtoa.h" // _dtoa_state_INIT()
1514
#include "pycore_faulthandler.h" // _faulthandler_runtime_state_INIT
1615
#include "pycore_floatobject.h" // _py_float_format_*
1716
#include "pycore_function.h"
@@ -142,7 +141,6 @@ extern PyTypeObject _PyExc_MemoryError;
142141
.wr_seq = QSBR_INITIAL, \
143142
.rd_seq = QSBR_INITIAL, \
144143
}, \
145-
.dtoa = _dtoa_state_INIT(&(INTERP)), \
146144
.dict_state = _dict_state_INIT, \
147145
.mem_free_queue = _Py_mem_free_queue_INIT(INTERP.mem_free_queue), \
148146
.func_state = { \

Makefile.pre.in

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,6 @@ PYTHON_OBJS= \
513513
Python/pystrcmp.o \
514514
Python/pystrtod.o \
515515
Python/pystrhex.o \
516-
Python/dtoa.o \
517516
Python/_fmt/fmt_dtoa.o \
518517
Python/_wuffs/wuffs_strtod.o \
519518
Python/fileutils.o \
@@ -3231,13 +3230,6 @@ regen-jit:
32313230
.c.o:
32323231
$(CC) -c $(PY_CORE_CFLAGS) -o $@ $<
32333232

3234-
# bpo-30104: dtoa.c uses union to cast double to unsigned long[2]. clang 4.0
3235-
# with -O2 or higher and strict aliasing miscompiles the ratio() function
3236-
# causing rounding issues. Compile dtoa.c using -fno-strict-aliasing on clang.
3237-
# https://bugs.llvm.org//show_bug.cgi?id=31928
3238-
Python/dtoa.o: Python/dtoa.c
3239-
$(CC) -c $(PY_CORE_CFLAGS) $(CFLAGS_ALIASING) -o $@ $<
3240-
32413233
# Vendored {fmt} float-to-string path — see Python/_fmt/README.vendor.
32423234
# Compiled as C++17 with exceptions and RTTI disabled so libpython doesn't
32433235
# acquire a libstdc++ runtime dependency beyond what operator new pulls in.

PCbuild/pythoncore.vcxproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,6 @@
670670
<ClCompile Include="..\Python\pystrtod.c" />
671671
<ClCompile Include="..\Python\remote_debugging.c" />
672672
<ClCompile Include="..\Python\qsbr.c" />
673-
<ClCompile Include="..\Python\dtoa.c" />
674673
<ClCompile Include="..\Python\Python-ast.c" />
675674
<ClCompile Include="..\Python\Python-tokenize.c" />
676675
<ClCompile Include="..\Python\pythonrun.c" />

PCbuild/pythoncore.vcxproj.filters

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,9 +1553,6 @@
15531553
<ClCompile Include="..\Python\qsbr.c">
15541554
<Filter>Python</Filter>
15551555
</ClCompile>
1556-
<ClCompile Include="..\Python\dtoa.c">
1557-
<Filter>Python</Filter>
1558-
</ClCompile>
15591556
<ClCompile Include="..\Python\Python-ast.c">
15601557
<Filter>Python</Filter>
15611558
</ClCompile>

0 commit comments

Comments
 (0)