mirror of
https://github.com/python/cpython.git
synced 2025-07-15 15:25:29 +00:00
gh-132775: Add _PyFunction_GetXIData() (gh-133481)
This commit is contained in:
parent
121ed71f4e
commit
8cf4947b0f
5 changed files with 103 additions and 0 deletions
|
@ -200,6 +200,13 @@ PyAPI_FUNC(int) _PyCode_GetPureScriptXIData(
|
|||
PyObject *,
|
||||
_PyXIData_t *);
|
||||
|
||||
// _PyObject_GetXIData() for functions
|
||||
PyAPI_FUNC(PyObject *) _PyFunction_FromXIData(_PyXIData_t *);
|
||||
PyAPI_FUNC(int) _PyFunction_GetXIData(
|
||||
PyThreadState *,
|
||||
PyObject *,
|
||||
_PyXIData_t *);
|
||||
|
||||
|
||||
/* using cross-interpreter data */
|
||||
|
||||
|
|
|
@ -758,6 +758,40 @@ class CodeTests(_GetXIDataTests):
|
|||
])
|
||||
|
||||
|
||||
class ShareableFuncTests(_GetXIDataTests):
|
||||
|
||||
MODE = 'func'
|
||||
|
||||
def test_stateless(self):
|
||||
self.assert_roundtrip_not_equal([
|
||||
*defs.STATELESS_FUNCTIONS,
|
||||
# Generators can be stateless too.
|
||||
*defs.FUNCTION_LIKE,
|
||||
])
|
||||
|
||||
def test_not_stateless(self):
|
||||
self.assert_not_shareable([
|
||||
*(f for f in defs.FUNCTIONS
|
||||
if f not in defs.STATELESS_FUNCTIONS),
|
||||
])
|
||||
|
||||
def test_other_objects(self):
|
||||
self.assert_not_shareable([
|
||||
None,
|
||||
True,
|
||||
False,
|
||||
Ellipsis,
|
||||
NotImplemented,
|
||||
9999,
|
||||
'spam',
|
||||
b'spam',
|
||||
(),
|
||||
[],
|
||||
{},
|
||||
object(),
|
||||
])
|
||||
|
||||
|
||||
class PureShareableScriptTests(_GetXIDataTests):
|
||||
|
||||
MODE = 'script-pure'
|
||||
|
|
|
@ -1989,6 +1989,11 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp(mode, "func") == 0) {
|
||||
if (_PyFunction_GetXIData(tstate, obj, xidata) != 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp(mode, "script") == 0) {
|
||||
if (_PyCode_GetScriptXIData(tstate, obj, xidata) != 0) {
|
||||
goto error;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "pycore_initconfig.h" // _PyStatus_OK()
|
||||
#include "pycore_namespace.h" // _PyNamespace_New()
|
||||
#include "pycore_pythonrun.h" // _Py_SourceAsString()
|
||||
#include "pycore_setobject.h" // _PySet_NextEntry()
|
||||
#include "pycore_typeobject.h" // _PyStaticType_InitBuiltin()
|
||||
|
||||
|
||||
|
|
|
@ -677,6 +677,60 @@ _PyCode_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// function
|
||||
|
||||
PyObject *
|
||||
_PyFunction_FromXIData(_PyXIData_t *xidata)
|
||||
{
|
||||
// For now "stateless" functions are the only ones we must accommodate.
|
||||
|
||||
PyObject *code = _PyMarshal_ReadObjectFromXIData(xidata);
|
||||
if (code == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Create a new function.
|
||||
assert(PyCode_Check(code));
|
||||
PyObject *globals = PyDict_New();
|
||||
if (globals == NULL) {
|
||||
Py_DECREF(code);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *func = PyFunction_New(code, globals);
|
||||
Py_DECREF(code);
|
||||
Py_DECREF(globals);
|
||||
return func;
|
||||
}
|
||||
|
||||
int
|
||||
_PyFunction_GetXIData(PyThreadState *tstate, PyObject *func,
|
||||
_PyXIData_t *xidata)
|
||||
{
|
||||
if (!PyFunction_Check(func)) {
|
||||
const char *msg = "expected a function, got %R";
|
||||
format_notshareableerror(tstate, NULL, 0, msg, func);
|
||||
return -1;
|
||||
}
|
||||
if (_PyFunction_VerifyStateless(tstate, func) < 0) {
|
||||
PyObject *cause = _PyErr_GetRaisedException(tstate);
|
||||
assert(cause != NULL);
|
||||
const char *msg = "only stateless functions are shareable";
|
||||
set_notshareableerror(tstate, cause, 0, msg);
|
||||
Py_DECREF(cause);
|
||||
return -1;
|
||||
}
|
||||
PyObject *code = PyFunction_GET_CODE(func);
|
||||
|
||||
// Ideally code objects would be immortal and directly shareable.
|
||||
// In the meantime, we use marshal.
|
||||
if (_PyMarshal_GetXIData(tstate, code, xidata) < 0) {
|
||||
return -1;
|
||||
}
|
||||
// Replace _PyMarshal_ReadObjectFromXIData.
|
||||
// (_PyFunction_FromXIData() will call it.)
|
||||
_PyXIData_SET_NEW_OBJECT(xidata, _PyFunction_FromXIData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// registration
|
||||
|
||||
|
@ -717,4 +771,6 @@ _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry)
|
|||
if (_xidregistry_add_type(xidregistry, &PyTuple_Type, _tuple_shared) != 0) {
|
||||
Py_FatalError("could not register tuple for cross-interpreter sharing");
|
||||
}
|
||||
|
||||
// For now, we do not register PyCode_Type or PyFunction_Type.
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue