mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	[3.14] gh-132775: Add _PyFunction_GetXIData() (gh-133955)
(cherry picked from commit 8cf4947b0f, AKA gh-133481)
Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									c1aa5f82d9
								
							
						
					
					
						commit
						3467656b18
					
				
					 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 @@ def test_other_objects(self): | |||
|         ]) | ||||
| 
 | ||||
| 
 | ||||
| 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
	
	 Miss Islington (bot)
						Miss Islington (bot)