8000 Add _PyCode_GetPureScriptXIData(). · python/cpython@6772ed9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6772ed9

Browse files
Add _PyCode_GetPureScriptXIData().
1 parent 49c4abb commit 6772ed9

File tree

5 files changed

+101
-34
lines changed

5 files changed

+101
-34
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ PyAPI_FUNC(int) _PyCode_GetScriptXIData(
195195
PyThreadState *,
196196
PyObject *,
197197
_PyXIData_t *);
198+
PyAPI_FUNC(int) _PyCode_GetPureScriptXIData(
199+
PyThreadState *,
200+
PyObject *,
201+
_PyXIData_t *);
198202

199203

200204
/* using cross-interpreter data */

Lib/test/_code_definitions.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def ham_C_closure(z):
242242
spam_full,
243243
]
244244

245-
SCRIPT_FUNCTIONS = [
245+
PURE_SCRIPT_FUNCTIONS = [
246246
simple_script,
247247
complex_script,
248248
script_with_explicit_empty_return,
@@ -251,6 +251,11 @@ def ham_C_closure(z):
251251
spam_with_inner_not_closure,
252252
spam_with_inner_closure,
253253
]
254+
SCRIPT_FUNCTIONS = [
255+
*PURE_SCRIPT_FUNCTIONS,
256+
script_with_globals,
257+
spam_with_globals_and_builtins,
258+
]
254259

255260

256261
# generators

Lib/test/test_crossinterp.py

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

760760

761-
class ShareableScriptTests(_GetXIDataTests):
761+
class PureShareableScriptTests(_GetXIDataTests):
762762

763-
MODE = 'script'
763+
MODE = 'script-pure'
764764

765765
VALID_SCRIPTS = [
766766
'',
@@ -809,25 +809,35 @@ def test_invalid_bytes(self):
809809
*(s.encode('utf8') for s in self.INVALID_SCRIPTS),
810810
])
811811

812-
def test_script_code(self):
812+
def test_pure_script_code(self):
813813
self.assert_roundtrip_equal_not_identical([
814-
*(f.__code__ for f in defs.SCRIPT_FUNCTIONS),
815-
defs.script_with_globals.__code__,
814+
*(f.__code__ for f in defs.PURE_SCRIPT_FUNCTIONS),
815+
])
816+
817+
def test_impure_script_code(self):
818+
self.assert_not_shareable([
819+
*(f.__code__ for f in defs.SCRIPT_FUNCTIONS
820+
if f not in defs.PURE_SCRIPT_FUNCTIONS),
816821
])
817822

818823
def test_other_code(self):
819824
self.assert_not_shareable([
820825
*(f.__code__ for f in defs.FUNCTIONS
821-
if f not in defs.SCRIPT_FUNCTIONS and
822-
f is not defs.script_with_globals),
826+
if f not in defs.SCRIPT_FUNCTIONS),
823827
*(f.__code__ for f in defs.FUNCTION_LIKE),
824828
])
825829

826-
def test_script_function(self):
830+
def test_pure_script_function(self):
827831
self.assert_roundtrip_not_equal([
828-
*defs.SCRIPT_FUNCTIONS,
832+
*defs.PURE_SCRIPT_FUNCTIONS,
829833
], expecttype=types.CodeType)
830834

835+
def test_impure_script_function(self):
836+
self.assert_not_shareable([
837+
*(f for f in defs.SCRIPT_FUNCTIONS
838+
if f not in defs.PURE_SCRIPT_FUNCTIONS),
839+
])
840+
831841
def test_other_function(self):
832842
self.assert_not_shareable([
833843
*(f for f in defs.FUNCTIONS
@@ -849,6 +859,23 @@ def test_other_objects(self):
849859
])
850860

851861

862+
class ShareableScriptTests(PureShareableScriptTests):
863+
864+
MODE = 'script'
865+
866+
def test_impure_script_code(self):
867+
self.assert_roundtrip_equal_not_identical([
868+
*(f.__code__ for f in defs.SCRIPT_FUNCTIONS
869+
if f not in defs.PURE_SCRIPT_FUNCTIONS),
870+
])
871+
872+
def test_impure_script_function(self):
873+
self.assert_roundtrip_not_equal([
874+
*(f for f in defs.SCRIPT_FUNCTIONS
875+
if f not in defs.PURE_SCRIPT_FUNCTIONS),
876+
], expecttype=types.CodeType)
877+
878+
852879
class ShareableTypeTests(_GetXIDataTests):
853880

854881
MODE = 'xidata'

Modules/_testinternalcapi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,11 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs)
19941994
goto error;
19951995
}
19961996
}
1997+
else if (strcmp(mode, "script-pure") == 0) {
1998+
if (_PyCode_GetPureScriptXIData(tstate, obj, xidata) != 0) {
1999+
goto error;
2000+
}
2001+
}
19972002
else {
19982003
PyErr_Format(PyExc_ValueError, "unsupported mode %R", modeobj);
19992004
goto error;

Python/crossinterp.c

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,21 @@ _PyMarshal_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata)
789789
/* script wrapper */
790790

791791
static int
792-
verify_script(PyThreadState *tstate, PyCodeObject *co)
792+
verify_script(PyThreadState *tstate, PyCodeObject *co, int checked, int pure)
793793
{
794-
assert(_PyCode_VerifyStateless(
795-
tstate, co, NULL, NULL, _PyEval_GetBuiltins(tstate)) == 0);
794+
// Make sure it isn't a closure and (optionally) doesn't use globals.
795+
PyObject *builtins = NULL;
796+
if (pure) {
797+
builtins = _PyEval_GetBuiltins(tstate);
798+
assert(builtins != NULL);
799+
}
800+
if (checked) {
801+
assert(_PyCode_VerifyStateless(tstate, co, NULL, NULL, builtins) == 0);
802+
}
803+
else if (_PyCode_VerifyStateless(tstate, co, NULL, NULL, builtins) < 0) {
804+
return -1;
805+
}
806+
// Make sure it doesn't have args.
796807
if (co->co_argcount > 0
797808
|| co->co_posonlyargcount > 0
798809
|| co->co_kwonlyargcount > 0
@@ -802,6 +813,7 @@ verify_script(PyThreadState *tstate, PyCodeObject *co)
802813
"code with args not supported");
803814
return -1;
804815
}
816+
// Make sure it doesn't return anything.
805817
if (!_PyCode_ReturnsOnlyNone(co)) {
806818
_PyErr_SetString(tstate, PyExc_ValueError,
807819
"code that returns a value is not a script");
@@ -810,50 +822,41 @@ verify_script(PyThreadState *tstate, PyCodeObject *co)
810822
return 0;
811823
}
812824

813-
int
814-
_PyCode_GetScriptXIData(PyThreadState *tstate,
815-
PyObject *obj, _PyXIData_t *xidata)
825+
static int
826+
get_script_xidata(PyThreadState *tstate, PyObject *obj, int pure,
827+
_PyXIData_t *xidata)
816828
{
817829
// Get the corresponding code object.
818830
PyObject *code = NULL;
831+
int checked = 0;
819832
if (PyCode_Check(obj)) {
820833
code = obj;
821834
Py_INCREF(code);
822-
PyObject *builtins = _PyEval_GetBuiltins(tstate);
823-
assert(builtins != NULL);
824-
if (_PyCode_VerifyStateless(
825-
tstate, (PyCodeObject *)code, NULL, NULL, builtins) < 0)
826-
{
827-
goto error;
828-
}
829-
if (verify_script(tstate, (PyCodeObject *)code) < 0) {
830-
goto error;
831-
}
832835
}
833836
else if (PyFunction_Check(obj)) {
834837
code = PyFunction_GET_CODE(obj);
835838
assert(code != NULL);
836839
Py_INCREF(code);
837-
if (_PyFunction_VerifyStateless(tstate, obj) < 0) {
838-
goto error;
839-
}
840-
if (verify_script(tstate, (PyCodeObject *)code) < 0) {
841-
goto error;
840+
if (pure) {
841+
if (_PyFunction_VerifyStateless(tstate, obj) < 0) {
842+
goto error;
843+
}
844+
checked = 1;
842845
}
843846
}
844847
else {
845848
const char *filename = "<script>";
846849
PyCompilerFlags cf = _PyCompilerFlags_INIT;
847850
cf.cf_flags = PyCF_SOURCE_IS_UTF8;
848851
PyObject *ref = NULL;
849-
const char *script =
850-
_Py_SourceAsString(obj, "???", "???", &cf, &ref);
852+
const char *script = _Py_SourceAsString(obj, "???", "???", &cf, &ref);
851853
if (script == NULL) {
852854
if (!PyBytes_Check(obj) && !PyUnicode_Check(obj)
853855
&& !PyByteArray_Check(obj) && !PyObject_CheckBuffer(obj))
854856
{
855857
// We discard the raised exception.
856-
_PyErr_Format(tstate, PyExc_TypeError, "unsupported script %R", obj);
858+
_PyErr_Format(tstate, PyExc_TypeError,
859+
"unsupported script %R", obj);
857860
}
858861
goto error;
859862
}
@@ -862,6 +865,15 @@ _PyCode_GetScriptXIData(PyThreadState *tstate,
862865
if (code == NULL) {
863866
goto error;
864867
}
868+
if (!pure) {
869+
// It can't be a closure.
870+
checked = 1;
871+
}
872+
}
873+
874+
// Make sure it's actually a script.
875+
if (verify_script(tstate, (PyCodeObject *)code, checked, pure) < 0) {
876+
goto error;
865877
}
866878

867879
// Convert the code object.
@@ -882,6 +894,20 @@ _PyCode_GetScriptXIData(PyThreadState *tstate,
882894
return -1;
883895
}
884896

897+
int
898+
_PyCode_GetScriptXIData(PyThreadState *tstate,
899+
PyObject *obj, _PyXIData_t *xidata)
900+
{
901+
return get_script_xidata(tstate, obj, 0, xidata);
902+
}
903+
904+
int
905+
_PyCode_GetPureScriptXIData(PyThreadState *tstate,
906+
PyObject *obj, _PyXIData_t *xidata)
907+
{
908+
return get_script_xidata(tstate, obj, 1, xidata);
909+
}
910+
885911

886912
/* using cross-interpreter data */
887913

0 commit comments

Comments
 (0)
0