Skip to content

Commit 606003f

Browse files
gh-132775: Add _PyBytes_GetXIData() (gh-133101)
This is the base for several other XIData wrappers, like pickle and marshal. It is essentially a refactor of the existing bytes XIData code.
1 parent 31d1342 commit 606003f

File tree

3 files changed

+99
-14
lines changed

3 files changed

+99
-14
lines changed

Include/internal/pycore_crossinterp.h

+23
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ PyAPI_FUNC(void) _PyXIData_Clear(PyInterpreterState *, _PyXIData_t *);
112112
do { \
113113
(DATA)->free = (FUNC); \
114114
} while (0)
115+
#define _PyXIData_CHECK_FREE(DATA, FUNC) \
116+
((DATA)->free == (FUNC))
115117
// Additionally, some shareable types are essentially light wrappers
116118
// around other shareable types. The xidatafunc of the wrapper
117119
// can often be implemented by calling the wrapped object's
@@ -123,6 +125,8 @@ PyAPI_FUNC(void) _PyXIData_Clear(PyInterpreterState *, _PyXIData_t *);
123125
do { \
124126
(DATA)->new_object = (FUNC); \
125127
} while (0)
128+
#define _PyXIData_CHECK_NEW_OBJECT(DATA, FUNC) \
129+
((DATA)->new_object == (FUNC))
126130

127131

128132
/* getting cross-interpreter data */
@@ -148,6 +152,25 @@ PyAPI_FUNC(int) _PyObject_GetXIData(
148152
PyObject *,
149153
_PyXIData_t *);
150154

155+
// _PyObject_GetXIData() for bytes
156+
typedef struct {
157+
const char *bytes;
158+
Py_ssize_t len;
159+
} _PyBytes_data_t;
160+
PyAPI_FUNC(int) _PyBytes_GetData(PyObject *, _PyBytes_data_t *);
161+
PyAPI_FUNC(PyObject *) _PyBytes_FromData(_PyBytes_data_t *);
162+
PyAPI_FUNC(PyObject *) _PyBytes_FromXIData(_PyXIData_t *);
163+
PyAPI_FUNC(int) _PyBytes_GetXIData(
164+
PyThreadState *,
165+
PyObject *,
166+
_PyXIData_t *);
167+
PyAPI_FUNC(_PyBytes_data_t *) _PyBytes_GetXIDataWrapped(
168+
PyThreadState *,
169+
PyObject *,
170+
size_t,
171+
xid_newobjfunc,
172+
_PyXIData_t *);
173+
151174

152175
/* using cross-interpreter data */
153176

Python/crossinterp.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ _PyXIData_InitWithSize(_PyXIData_t *xidata,
154154
// where it was allocated, so the interpreter is required.
155155
assert(interp != NULL);
156156
_PyXIData_Init(xidata, interp, NULL, obj, new_object);
157-
xidata->data = PyMem_RawMalloc(size);
157+
xidata->data = PyMem_RawCalloc(1, size);
158158
if (xidata->data == NULL) {
159159
return -1;
160160
}

Python/crossinterp_data_lookup.h

+75-13
Original file line numberDiff line numberDiff line change
@@ -348,36 +348,98 @@ _PyXIData_UnregisterClass(PyThreadState *tstate, PyTypeObject *cls)
348348

349349
// bytes
350350

351-
struct _shared_bytes_data {
351+
int
352+
_PyBytes_GetData(PyObject *obj, _PyBytes_data_t *data)
353+
{
354+
if (!PyBytes_Check(obj)) {
355+
PyErr_Format(PyExc_TypeError, "expected bytes, got %R", obj);
356+
return -1;
357+
}
352358
char *bytes;
353359
Py_ssize_t len;
354-
};
360+
if (PyBytes_AsStringAndSize(obj, &bytes, &len) < 0) {
361+
return -1;
362+
}
363+
*data = (_PyBytes_data_t){
364+
.bytes = bytes,
365+
.len = len,
366+
};
367+
return 0;
368+
}
355369

356-
static PyObject *
357-
_new_bytes_object(_PyXIData_t *xidata)
370+
PyObject *
371+
_PyBytes_FromData(_PyBytes_data_t *data)
358372
{
359-
struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(xidata->data);
360-
return PyBytes_FromStringAndSize(shared->bytes, shared->len);
373+
return PyBytes_FromStringAndSize(data->bytes, data->len);
374+
}
375+
376+
PyObject *
377+
_PyBytes_FromXIData(_PyXIData_t *xidata)
378+
{
379+
_PyBytes_data_t *data = (_PyBytes_data_t *)xidata->data;
380+
assert(_PyXIData_OBJ(xidata) != NULL
381+
&& PyBytes_Check(_PyXIData_OBJ(xidata)));
382+
return _PyBytes_FromData(data);
361383
}
362384

363385
static int
364-
_bytes_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
386+
_bytes_shared(PyThreadState *tstate,
387+
PyObject *obj, size_t size, xid_newobjfunc newfunc,
388+
_PyXIData_t *xidata)
365389
{
390+
assert(size >= sizeof(_PyBytes_data_t));
391+
assert(newfunc != NULL);
366392
if (_PyXIData_InitWithSize(
367-
xidata, tstate->interp, sizeof(struct _shared_bytes_data), obj,
368-
_new_bytes_object
369-
) < 0)
393+
xidata, tstate->interp, size, obj, newfunc) < 0)
370394
{
371395
return -1;
372396
}
373-
struct _shared_bytes_data *shared = (struct _shared_bytes_data *)xidata->data;
374-
if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) {
397+
_PyBytes_data_t *data = (_PyBytes_data_t *)xidata->data;
398+
if (_PyBytes_GetData(obj, data) < 0) {
375399
_PyXIData_Clear(tstate->interp, xidata);
376400
return -1;
377401
}
378402
return 0;
379403
}
380404

405+
int
406+
_PyBytes_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
407+
{
408+
if (!PyBytes_Check(obj)) {
409+
PyErr_Format(PyExc_TypeError, "expected bytes, got %R", obj);
410+
return -1;
411+
}
412+
size_t size = sizeof(_PyBytes_data_t);
413+
return _bytes_shared(tstate, obj, size, _PyBytes_FromXIData, xidata);
414+
}
415+
416+
_PyBytes_data_t *
417+
_PyBytes_GetXIDataWrapped(PyThreadState *tstate,
418+
PyObject *obj, size_t size, xid_newobjfunc newfunc,
419+
_PyXIData_t *xidata)
420+
{
421+
if (!PyBytes_Check(obj)) {
422+
PyErr_Format(PyExc_TypeError, "expected bytes, got %R", obj);
423+
return NULL;
424+
}
425+
if (size < sizeof(_PyBytes_data_t)) {
426+
PyErr_Format(PyExc_ValueError, "expected size >= %d, got %d",
427+
sizeof(_PyBytes_data_t), size);
428+
return NULL;
429+
}
430+
if (newfunc == NULL) {
431+
if (size == sizeof(_PyBytes_data_t)) {
432+
PyErr_SetString(PyExc_ValueError, "missing new_object func");
433+
return NULL;
434+
}
435+
newfunc = _PyBytes_FromXIData;
436+
}
437+
if (_bytes_shared(tstate, obj, size, newfunc, xidata) < 0) {
438+
return NULL;
439+
}
440+
return (_PyBytes_data_t *)xidata->data;
441+
}
442+
381443
// str
382444

383445
struct _shared_str_data {
@@ -608,7 +670,7 @@ _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry)
608670
}
609671

610672
// bytes
611-
if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _bytes_shared) != 0) {
673+
if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _PyBytes_GetXIData) != 0) {
612674
Py_FatalError("could not register bytes for cross-interpreter sharing");
613675
}
614676

0 commit comments

Comments
 (0)