Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8cf4947

Browse files
gh-132775: Add _PyFunction_GetXIData() (gh-133481)
1 parent121ed71 commit8cf4947

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

‎Include/internal/pycore_crossinterp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ PyAPI_FUNC(int) _PyCode_GetPureScriptXIData(
200200
PyObject*,
201201
_PyXIData_t*);
202202

203+
// _PyObject_GetXIData() for functions
204+
PyAPI_FUNC(PyObject*)_PyFunction_FromXIData(_PyXIData_t*);
205+
PyAPI_FUNC(int)_PyFunction_GetXIData(
206+
PyThreadState*,
207+
PyObject*,
208+
_PyXIData_t*);
209+
203210

204211
/* using cross-interpreter data */
205212

‎Lib/test/test_crossinterp.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,40 @@ def test_other_objects(self):
758758
])
759759

760760

761+
classShareableFuncTests(_GetXIDataTests):
762+
763+
MODE='func'
764+
765+
deftest_stateless(self):
766+
self.assert_roundtrip_not_equal([
767+
*defs.STATELESS_FUNCTIONS,
768+
# Generators can be stateless too.
769+
*defs.FUNCTION_LIKE,
770+
])
771+
772+
deftest_not_stateless(self):
773+
self.assert_not_shareable([
774+
*(fforfindefs.FUNCTIONS
775+
iffnotindefs.STATELESS_FUNCTIONS),
776+
])
777+
778+
deftest_other_objects(self):
779+
self.assert_not_shareable([
780+
None,
781+
True,
782+
False,
783+
Ellipsis,
784+
NotImplemented,
785+
9999,
786+
'spam',
787+
b'spam',
788+
(),
789+
[],
790+
{},
791+
object(),
792+
])
793+
794+
761795
classPureShareableScriptTests(_GetXIDataTests):
762796

763797
MODE='script-pure'

‎Modules/_testinternalcapi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,11 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs)
19891989
gotoerror;
19901990
}
19911991
}
1992+
elseif (strcmp(mode,"func")==0) {
1993+
if (_PyFunction_GetXIData(tstate,obj,xidata)!=0) {
1994+
gotoerror;
1995+
}
1996+
}
19921997
elseif (strcmp(mode,"script")==0) {
19931998
if (_PyCode_GetScriptXIData(tstate,obj,xidata)!=0) {
19941999
gotoerror;

‎Python/crossinterp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include"pycore_initconfig.h"// _PyStatus_OK()
1111
#include"pycore_namespace.h"// _PyNamespace_New()
1212
#include"pycore_pythonrun.h"// _Py_SourceAsString()
13+
#include"pycore_setobject.h"// _PySet_NextEntry()
1314
#include"pycore_typeobject.h"// _PyStaticType_InitBuiltin()
1415

1516

‎Python/crossinterp_data_lookup.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,60 @@ _PyCode_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
677677
return0;
678678
}
679679

680+
// function
681+
682+
PyObject*
683+
_PyFunction_FromXIData(_PyXIData_t*xidata)
684+
{
685+
// For now "stateless" functions are the only ones we must accommodate.
686+
687+
PyObject*code=_PyMarshal_ReadObjectFromXIData(xidata);
688+
if (code==NULL) {
689+
returnNULL;
690+
}
691+
// Create a new function.
692+
assert(PyCode_Check(code));
693+
PyObject*globals=PyDict_New();
694+
if (globals==NULL) {
695+
Py_DECREF(code);
696+
returnNULL;
697+
}
698+
PyObject*func=PyFunction_New(code,globals);
699+
Py_DECREF(code);
700+
Py_DECREF(globals);
701+
returnfunc;
702+
}
703+
704+
int
705+
_PyFunction_GetXIData(PyThreadState*tstate,PyObject*func,
706+
_PyXIData_t*xidata)
707+
{
708+
if (!PyFunction_Check(func)) {
709+
constchar*msg="expected a function, got %R";
710+
format_notshareableerror(tstate,NULL,0,msg,func);
711+
return-1;
712+
}
713+
if (_PyFunction_VerifyStateless(tstate,func)<0) {
714+
PyObject*cause=_PyErr_GetRaisedException(tstate);
715+
assert(cause!=NULL);
716+
constchar*msg="only stateless functions are shareable";
717+
set_notshareableerror(tstate,cause,0,msg);
718+
Py_DECREF(cause);
719+
return-1;
720+
}
721+
PyObject*code=PyFunction_GET_CODE(func);
722+
723+
// Ideally code objects would be immortal and directly shareable.
724+
// In the meantime, we use marshal.
725+
if (_PyMarshal_GetXIData(tstate,code,xidata)<0) {
726+
return-1;
727+
}
728+
// Replace _PyMarshal_ReadObjectFromXIData.
729+
// (_PyFunction_FromXIData() will call it.)
730+
_PyXIData_SET_NEW_OBJECT(xidata,_PyFunction_FromXIData);
731+
return0;
732+
}
733+
680734

681735
// registration
682736

@@ -717,4 +771,6 @@ _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry)
717771
if (_xidregistry_add_type(xidregistry,&PyTuple_Type,_tuple_shared)!=0) {
718772
Py_FatalError("could not register tuple for cross-interpreter sharing");
719773
}
774+
775+
// For now, we do not register PyCode_Type or PyFunction_Type.
720776
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp