Skip to content

Commit c573499

Browse files
bpo-33720: Refactor marshalling/unmarshalling floats. (GH-8071)
1 parent e22072f commit c573499

File tree

3 files changed

+77
-112
lines changed

3 files changed

+77
-112
lines changed

Include/pyport.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,10 @@ extern "C" {
525525
* Usage:
526526
* int _Py_NO_INLINE x(void) { return 3; }
527527
*/
528-
#if defined(__GNUC__) || defined(__clang__)
529-
# define _Py_NO_INLINE __attribute__((noinline))
528+
#if defined(_MSC_VER)
529+
# define _Py_NO_INLINE __declspec(noinline)
530+
#elif defined(__GNUC__) || defined(__clang__)
531+
# define _Py_NO_INLINE __attribute__ ((noinline))
530532
#else
531533
# define _Py_NO_INLINE
532534
#endif

Objects/call.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,7 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...)
12711271

12721272
/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
12731273
stack consumption, Disable inlining to optimize the stack consumption. */
1274-
PyObject* _Py_NO_INLINE
1274+
_Py_NO_INLINE PyObject *
12751275
_PyStack_AsTuple(PyObject *const *stack, Py_ssize_t nargs)
12761276
{
12771277
PyObject *args;

Python/marshal.c

Lines changed: 72 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,32 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
266266
} while (d != 0);
267267
}
268268

269+
static void
270+
w_float_bin(double v, WFILE *p)
271+
{
272+
unsigned char buf[8];
273+
if (_PyFloat_Pack8(v, buf, 1) < 0) {
274+
p->error = WFERR_UNMARSHALLABLE;
275+
return;
276+
}
277+
w_string((const char *)buf, 8, p);
278+
}
279+
280+
static void
281+
w_float_str(double v, WFILE *p)
282+
{
283+
int n;
284+
char *buf = PyOS_double_to_string(v, 'g', 17, 0, NULL);
285+
if (!buf) {
286+
p->error = WFERR_NOMEMORY;
287+
return;
288+
}
289+
n = (int)strlen(buf);
290+
w_byte(n, p);
291+
w_string(buf, n, p);
292+
PyMem_Free(buf);
293+
}
294+
269295
static int
270296
w_ref(PyObject *v, char *flag, WFILE *p)
271297
{
@@ -375,69 +401,24 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
375401
}
376402
else if (PyFloat_CheckExact(v)) {
377403
if (p->version > 1) {
378-
unsigned char buf[8];
379-
if (_PyFloat_Pack8(PyFloat_AsDouble(v),
380-
buf, 1) < 0) {
381-
p->error = WFERR_UNMARSHALLABLE;
382-
return;
383-
}
384404
W_TYPE(TYPE_BINARY_FLOAT, p);
385-
w_string((char*)buf, 8, p);
405+
w_float_bin(PyFloat_AS_DOUBLE(v), p);
386406
}
387407
else {
388-
char *buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v),
389-
'g', 17, 0, NULL);
390-
if (!buf) {
391-
p->error = WFERR_NOMEMORY;
392-
return;
393-
}
394-
n = strlen(buf);
395408
W_TYPE(TYPE_FLOAT, p);
396-
w_byte((int)n, p);
397-
w_string(buf, n, p);
398-
PyMem_Free(buf);
409+
w_float_str(PyFloat_AS_DOUBLE(v), p);
399410
}
400411
}
401412
else if (PyComplex_CheckExact(v)) {
402413
if (p->version > 1) {
403-
unsigned char buf[8];
404-
if (_PyFloat_Pack8(PyComplex_RealAsDouble(v),
405-
buf, 1) < 0) {
406-
p->error = WFERR_UNMARSHALLABLE;
407-
return;
408-
}
409414
W_TYPE(TYPE_BINARY_COMPLEX, p);
410-
w_string((char*)buf, 8, p);
411-
if (_PyFloat_Pack8(PyComplex_ImagAsDouble(v),
412-
buf, 1) < 0) {
413-
p->error = WFERR_UNMARSHALLABLE;
414-
return;
415-
}
416-
w_string((char*)buf, 8, p);
415+
w_float_bin(PyComplex_RealAsDouble(v), p);
416+
w_float_bin(PyComplex_ImagAsDouble(v), p);
417417
}
418418
else {
419-
char *buf;
420419
W_TYPE(TYPE_COMPLEX, p);
421-
buf = PyOS_double_to_string(PyComplex_RealAsDouble(v),
422-
'g', 17, 0, NULL);
423-
if (!buf) {
424-
p->error = WFERR_NOMEMORY;
425-
return;
426-
}
427-
n = strlen(buf);
428-
w_byte((int)n, p);
429-
w_string(buf, n, p);
430-
PyMem_Free(buf);
431-
buf = PyOS_double_to_string(PyComplex_ImagAsDouble(v),
432-
'g', 17, 0, NULL);
433-
if (!buf) {
434-
p->error = WFERR_NOMEMORY;
435-
return;
436-
}
437-
n = strlen(buf);
438-
w_byte((int)n, p);
439-
w_string(buf, n, p);
440-
PyMem_Free(buf);
420+
w_float_str(PyComplex_RealAsDouble(v), p);
421+
w_float_str(PyComplex_ImagAsDouble(v), p);
441422
}
442423
}
443424
else if (PyBytes_CheckExact(v)) {
@@ -880,6 +861,38 @@ r_PyLong(RFILE *p)
880861
return NULL;
881862
}
882863

864+
static double
865+
r_float_bin(RFILE *p)
866+
{
867+
const unsigned char *buf = (const unsigned char *) r_string(8, p);
868+
if (buf == NULL)
869+
return -1;
870+
return _PyFloat_Unpack8(buf, 1);
871+
}
872+
873+
/* Issue #33720: Disable inlining for reducing the C stack consumption
874+
on PGO builds. */
875+
_Py_NO_INLINE static double
876+
r_float_str(RFILE *p)
877+
{
878+
int n;
879+
char buf[256];
880+
const char *ptr;
881+
n = r_byte(p);
882+
if (n == EOF) {
883+
PyErr_SetString(PyExc_EOFError,
884+
"EOF read where object expected");
885+
return -1;
886+
}
887+
ptr = r_string(n, p);
888+
if (ptr == NULL) {
889+
return -1;
890+
}
891+
memcpy(buf, ptr, n);
892+
buf[n] = '\0';
893+
return PyOS_string_to_double(buf, NULL, NULL);
894+
}
895+
883896
/* allocate the reflist index for a new object. Return -1 on failure */
884897
static Py_ssize_t
885898
r_ref_reserve(int flag, RFILE *p)
@@ -1016,36 +1029,17 @@ r_object(RFILE *p)
10161029

10171030
case TYPE_FLOAT:
10181031
{
1019-
char buf[256];
1020-
const char *ptr;
1021-
double dx;
1022-
n = r_byte(p);
1023-
if (n == EOF) {
1024-
PyErr_SetString(PyExc_EOFError,
1025-
"EOF read where object expected");
1026-
break;
1027-
}
1028-
ptr = r_string(n, p);
1029-
if (ptr == NULL)
1030-
break;
1031-
memcpy(buf, ptr, n);
1032-
buf[n] = '\0';
1033-
dx = PyOS_string_to_double(buf, NULL, NULL);
1034-
if (dx == -1.0 && PyErr_Occurred())
1032+
double x = r_float_str(p);
1033+
if (x == -1.0 && PyErr_Occurred())
10351034
break;
1036-
retval = PyFloat_FromDouble(dx);
1035+
retval = PyFloat_FromDouble(x);
10371036
R_REF(retval);
10381037
break;
10391038
}
10401039

10411040
case TYPE_BINARY_FLOAT:
10421041
{
1043-
const unsigned char *buf;
1044-
double x;
1045-
buf = (const unsigned char *) r_string(8, p);
1046-
if (buf == NULL)
1047-
break;
1048-
x = _PyFloat_Unpack8(buf, 1);
1042+
double x = r_float_bin(p);
10491043
if (x == -1.0 && PyErr_Occurred())
10501044
break;
10511045
retval = PyFloat_FromDouble(x);
@@ -1055,35 +1049,11 @@ r_object(RFILE *p)
10551049

10561050
case TYPE_COMPLEX:
10571051
{
1058-
char buf[256];
1059-
const char *ptr;
10601052
Py_complex c;
1061-
n = r_byte(p);
1062-
if (n == EOF) {
1063-
PyErr_SetString(PyExc_EOFError,
1064-
"EOF read where object expected");
1065-
break;
1066-
}
1067-
ptr = r_string(n, p);
1068-
if (ptr == NULL)
1069-
break;
1070-
memcpy(buf, ptr, n);
1071-
buf[n] = '\0';
1072-
c.real = PyOS_string_to_double(buf, NULL, NULL);
1053+
c.real = r_float_str(p);
10731054
if (c.real == -1.0 && PyErr_Occurred())
10741055
break;
1075-
n = r_byte(p);
1076-
if (n == EOF) {
1077-
PyErr_SetString(PyExc_EOFError,
1078-
"EOF read where object expected");
1079-
break;
1080-
}
1081-
ptr = r_string(n, p);
1082-
if (ptr == NULL)
1083-
break;
1084-
memcpy(buf, ptr, n);
1085-
buf[n] = '\0';
1086-
c.imag = PyOS_string_to_double(buf, NULL, NULL);
1056+
c.imag = r_float_str(p);
10871057
if (c.imag == -1.0 && PyErr_Occurred())
10881058
break;
10891059
retval = PyComplex_FromCComplex(c);
@@ -1093,18 +1063,11 @@ r_object(RFILE *p)
10931063

10941064
case TYPE_BINARY_COMPLEX:
10951065
{
1096-
const unsigned char *buf;
10971066
Py_complex c;
1098-
buf = (const unsigned char *) r_string(8, p);
1099-
if (buf == NULL)
1100-
break;
1101-
c.real = _PyFloat_Unpack8(buf, 1);
1067+
c.real = r_float_bin(p);
11021068
if (c.real == -1.0 && PyErr_Occurred())
11031069
break;
1104-
buf = (const unsigned char *) r_string(8, p);
1105-
if (buf == NULL)
1106-
break;
1107-
c.imag = _PyFloat_Unpack8(buf, 1);
1070+
c.imag = r_float_bin(p);
11081071
if (c.imag == -1.0 && PyErr_Occurred())
11091072
break;
11101073
retval = PyComplex_FromCComplex(c);

0 commit comments

Comments
 (0)