Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-33720: Refactor marshalling/unmarshalling floats. #8071

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Include/pyport.h
Original file line number Diff line number Diff line change
@@ -525,8 +525,10 @@ extern "C" {
* Usage:
* int _Py_NO_INLINE x(void) { return 3; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define _Py_NO_INLINE __attribute__((noinline))
#if defined(_MSC_VER)
# define _Py_NO_INLINE __declspec(noinline)
#elif defined(__GNUC__) || defined(__clang__)
# define _Py_NO_INLINE __attribute__ ((noinline))
#else
# define _Py_NO_INLINE
#endif
2 changes: 1 addition & 1 deletion Objects/call.c
Original file line number Diff line number Diff line change
@@ -1271,7 +1271,7 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...)

/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their
stack consumption, Disable inlining to optimize the stack consumption. */
PyObject* _Py_NO_INLINE
_Py_NO_INLINE PyObject *
_PyStack_AsTuple(PyObject *const *stack, Py_ssize_t nargs)
{
PyObject *args;
181 changes: 72 additions & 109 deletions Python/marshal.c
Original file line number Diff line number Diff line change
@@ -266,6 +266,32 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
} while (d != 0);
}

static void
w_float_bin(double v, WFILE *p)
{
unsigned char buf[8];
if (_PyFloat_Pack8(v, buf, 1) < 0) {
p->error = WFERR_UNMARSHALLABLE;
return;
}
w_string((const char *)buf, 8, p);
}

static void
w_float_str(double v, WFILE *p)
{
int n;
char *buf = PyOS_double_to_string(v, 'g', 17, 0, NULL);
if (!buf) {
p->error = WFERR_NOMEMORY;
return;
}
n = (int)strlen(buf);
w_byte(n, p);
w_string(buf, n, p);
PyMem_Free(buf);
}

static int
w_ref(PyObject *v, char *flag, WFILE *p)
{
@@ -375,69 +401,24 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
}
else if (PyFloat_CheckExact(v)) {
if (p->version > 1) {
unsigned char buf[8];
if (_PyFloat_Pack8(PyFloat_AsDouble(v),
buf, 1) < 0) {
p->error = WFERR_UNMARSHALLABLE;
return;
}
W_TYPE(TYPE_BINARY_FLOAT, p);
w_string((char*)buf, 8, p);
w_float_bin(PyFloat_AS_DOUBLE(v), p);
}
else {
char *buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v),
'g', 17, 0, NULL);
if (!buf) {
p->error = WFERR_NOMEMORY;
return;
}
n = strlen(buf);
W_TYPE(TYPE_FLOAT, p);
w_byte((int)n, p);
w_string(buf, n, p);
PyMem_Free(buf);
w_float_str(PyFloat_AS_DOUBLE(v), p);
}
}
else if (PyComplex_CheckExact(v)) {
if (p->version > 1) {
unsigned char buf[8];
if (_PyFloat_Pack8(PyComplex_RealAsDouble(v),
buf, 1) < 0) {
p->error = WFERR_UNMARSHALLABLE;
return;
}
W_TYPE(TYPE_BINARY_COMPLEX, p);
w_string((char*)buf, 8, p);
if (_PyFloat_Pack8(PyComplex_ImagAsDouble(v),
buf, 1) < 0) {
p->error = WFERR_UNMARSHALLABLE;
return;
}
w_string((char*)buf, 8, p);
w_float_bin(PyComplex_RealAsDouble(v), p);
w_float_bin(PyComplex_ImagAsDouble(v), p);
}
else {
char *buf;
W_TYPE(TYPE_COMPLEX, p);
buf = PyOS_double_to_string(PyComplex_RealAsDouble(v),
'g', 17, 0, NULL);
if (!buf) {
p->error = WFERR_NOMEMORY;
return;
}
n = strlen(buf);
w_byte((int)n, p);
w_string(buf, n, p);
PyMem_Free(buf);
buf = PyOS_double_to_string(PyComplex_ImagAsDouble(v),
'g', 17, 0, NULL);
if (!buf) {
p->error = WFERR_NOMEMORY;
return;
}
n = strlen(buf);
w_byte((int)n, p);
w_string(buf, n, p);
PyMem_Free(buf);
w_float_str(PyComplex_RealAsDouble(v), p);
w_float_str(PyComplex_ImagAsDouble(v), p);
}
}
else if (PyBytes_CheckExact(v)) {
@@ -880,6 +861,38 @@ r_PyLong(RFILE *p)
return NULL;
}

static double
r_float_bin(RFILE *p)
{
const unsigned char *buf = (const unsigned char *) r_string(8, p);
if (buf == NULL)
return -1;
return _PyFloat_Unpack8(buf, 1);
}

/* Issue #33720: Disable inlining for reducing the C stack consumption
on PGO builds. */
_Py_NO_INLINE static double
r_float_str(RFILE *p)
{
int n;
char buf[256];
const char *ptr;
n = r_byte(p);
if (n == EOF) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
return -1;
}
ptr = r_string(n, p);
if (ptr == NULL) {
return -1;
}
memcpy(buf, ptr, n);
buf[n] = '\0';
return PyOS_string_to_double(buf, NULL, NULL);
}

/* allocate the reflist index for a new object. Return -1 on failure */
static Py_ssize_t
r_ref_reserve(int flag, RFILE *p)
@@ -1016,36 +1029,17 @@ r_object(RFILE *p)

case TYPE_FLOAT:
{
char buf[256];
const char *ptr;
double dx;
n = r_byte(p);
if (n == EOF) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
break;
}
ptr = r_string(n, p);
if (ptr == NULL)
break;
memcpy(buf, ptr, n);
buf[n] = '\0';
dx = PyOS_string_to_double(buf, NULL, NULL);
if (dx == -1.0 && PyErr_Occurred())
double x = r_float_str(p);
if (x == -1.0 && PyErr_Occurred())
break;
retval = PyFloat_FromDouble(dx);
retval = PyFloat_FromDouble(x);
R_REF(retval);
break;
}

case TYPE_BINARY_FLOAT:
{
const unsigned char *buf;
double x;
buf = (const unsigned char *) r_string(8, p);
if (buf == NULL)
break;
x = _PyFloat_Unpack8(buf, 1);
double x = r_float_bin(p);
if (x == -1.0 && PyErr_Occurred())
break;
retval = PyFloat_FromDouble(x);
@@ -1055,35 +1049,11 @@ r_object(RFILE *p)

case TYPE_COMPLEX:
{
char buf[256];
const char *ptr;
Py_complex c;
n = r_byte(p);
if (n == EOF) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
break;
}
ptr = r_string(n, p);
if (ptr == NULL)
break;
memcpy(buf, ptr, n);
buf[n] = '\0';
c.real = PyOS_string_to_double(buf, NULL, NULL);
c.real = r_float_str(p);
if (c.real == -1.0 && PyErr_Occurred())
break;
n = r_byte(p);
if (n == EOF) {
PyErr_SetString(PyExc_EOFError,
"EOF read where object expected");
break;
}
ptr = r_string(n, p);
if (ptr == NULL)
break;
memcpy(buf, ptr, n);
buf[n] = '\0';
c.imag = PyOS_string_to_double(buf, NULL, NULL);
c.imag = r_float_str(p);
if (c.imag == -1.0 && PyErr_Occurred())
break;
retval = PyComplex_FromCComplex(c);
@@ -1093,18 +1063,11 @@ r_object(RFILE *p)

case TYPE_BINARY_COMPLEX:
{
const unsigned char *buf;
Py_complex c;
buf = (const unsigned char *) r_string(8, p);
if (buf == NULL)
break;
c.real = _PyFloat_Unpack8(buf, 1);
c.real = r_float_bin(p);
if (c.real == -1.0 && PyErr_Occurred())
break;
buf = (const unsigned char *) r_string(8, p);
if (buf == NULL)
break;
c.imag = _PyFloat_Unpack8(buf, 1);
c.imag = r_float_bin(p);
if (c.imag == -1.0 && PyErr_Occurred())
break;
retval = PyComplex_FromCComplex(c);