@@ -80,18 +80,6 @@ static bool is_c_wrapper(PyObject* obj){
8080 } \
8181} while(0)
8282
83- static PyObject * make_global_immutable (PyObject * globals , PyObject * name )
84- {
85- PyObject * value = PyDict_GetItem (globals , name ); // value.rc = x
86-
87- _PyDict_SetKeyImmutable ((PyDictObject * )globals , name );
88-
89- if (!_Py_IsImmutable (value )){
90- return value ;
91- }else {
92- Py_RETURN_NONE ;
93- }
94- }
9583
9684/**
9785 * Special function for walking the reachable graph of a function object.
@@ -106,27 +94,26 @@ static PyObject* make_global_immutable(PyObject* globals, PyObject* name)
10694 */
10795static PyObject * walk_function (PyObject * op , stack * frontier )
10896{
109- PyObject * builtins ;
110- PyObject * globals ;
111- PyObject * module ;
112- PyObject * module_dict ;
113- PyFunctionObject * f ;
114- PyObject * f_ptr ;
115- PyCodeObject * f_code ;
97+ PyObject * builtins = NULL ;
98+ PyObject * frozen_builtins = NULL ;
99+ PyObject * globals = NULL ;
100+ PyObject * frozen_globals = NULL ;
101+ PyObject * module = NULL ;
102+ PyObject * module_dict = NULL ;
103+ PyFunctionObject * f = NULL ;
104+ PyObject * f_ptr = NULL ;
105+ PyCodeObject * f_code = NULL ;
116106 Py_ssize_t size ;
117- stack * f_stack ;
107+ stack * f_stack = NULL ;
118108 bool check_globals = false;
109+
119110 _PyObject_ASSERT (op , PyFunction_Check (op ));
120111
121112 _Py_SetImmutable (op );
122113
123114
124115 f = (PyFunctionObject * )op ;
125116
126- // TODO find a way to use traverse to avoid having to manually walk
127- // the function's members
128- // f->func_code needs special treatment (see below)
129- // func_globals, func_builtins, and func_module can stay mutable, but depending on code we may need to make some keys immutable
130117 globals = f -> func_globals ;
131118 builtins = f -> func_builtins ;
132119
@@ -163,8 +150,17 @@ static PyObject* walk_function(PyObject* op, stack* frontier)
163150
164151 f_ptr = f -> func_code ;
165152 if (stack_push (f_stack , f_ptr )){
166- stack_free (f_stack );
167- return PyErr_NoMemory ();
153+ goto nomemory ;
154+ }
155+
156+ frozen_builtins = PyDict_New ();
157+ if (frozen_builtins == NULL ){
158+ goto nomemory ;
159+ }
160+
161+ frozen_globals = PyDict_New ();
162+ if (frozen_globals == NULL ){
163+ goto nomemory ;
168164 }
169165
170166 while (!stack_empty (f_stack )){
@@ -188,21 +184,20 @@ static PyObject* walk_function(PyObject* op, stack* frontier)
188184 }
189185
190186 if (PyDict_Contains (globals , name )){
191- PyObject * value = make_global_immutable (globals , name );
192- if (!Py_IsNone (value )){
193- if (stack_push (frontier , value )){
194- stack_free (f_stack );
195- // frontier freed by the caller
196- return PyErr_NoMemory ();
197- }
187+ PyObject * value = PyDict_GetItem (globals , name );
188+ if (PyDict_SetItem (frozen_globals , name , value )){
189+ Py_DECREF (frozen_builtins );
190+ Py_DECREF (frozen_globals );
191+ stack_free (f_stack );
192+ return NULL ;
198193 }
199194 }else if (PyDict_Contains (builtins , name )){
200-
201- _PyDict_SetKeyImmutable (( PyDictObject * ) builtins , name );
202-
203- PyObject * value = PyDict_GetItem ( builtins , name ); // value.rc = x
204- if (! _Py_IsImmutable ( value )){
205- _Py_SetImmutable ( value ) ;
195+ PyObject * value = PyDict_GetItem ( builtins , name );
196+ if ( PyDict_SetItem ( frozen_builtins , name , value )){
197+ Py_DECREF ( frozen_builtins );
198+ Py_DECREF ( frozen_globals );
199+ stack_free ( f_stack );
200+ return NULL ;
206201 }
207202 }else if (PyDict_Contains (module_dict , name )){
208203 PyObject * value = PyDict_GetItem (module_dict , name ); // value.rc = x
@@ -211,9 +206,7 @@ static PyObject* walk_function(PyObject* op, stack* frontier)
211206
212207 if (!_Py_IsImmutable (value )){
213208 if (stack_push (frontier , value )){
214- stack_free (f_stack );
215- // frontier freed by the caller
216- return PyErr_NoMemory ();
209+ goto nomemory ;
217210 }
218211 }
219212 }
@@ -227,29 +220,24 @@ static PyObject* walk_function(PyObject* op, stack* frontier)
227220 _Py_SetImmutable (value );
228221
229222 if (stack_push (f_stack , value )){
230- stack_free (f_stack );
231- // frontier freed by the caller
232- return PyErr_NoMemory ();
223+ goto nomemory ;
233224 }
234225 }else {
235226 if (stack_push (frontier , value )){
236- stack_free (f_stack );
237- // frontier freed by the caller
238- return PyErr_NoMemory ();
227+ goto nomemory ;
239228 }
240229 }
241230 }
242231
243232 if (check_globals && PyUnicode_Check (value )){
244233 PyObject * name = value ;
245234 if (PyDict_Contains (globals , name )){
246- value = make_global_immutable (globals , name );
247- if (!Py_IsNone (value )){
248- if (stack_push (frontier , value )){
249- stack_free (f_stack );
250- // frontier freed by the caller
251- return PyErr_NoMemory ();
252- }
235+ value = PyDict_GetItem (globals , name );
236+ if (PyDict_SetItem (frozen_globals , name , value )){
237+ Py_DECREF (frozen_builtins );
238+ Py_DECREF (frozen_globals );
239+ stack_free (f_stack );
240+ return NULL ;
253241 }
254242 }
255243 }
@@ -270,29 +258,39 @@ static PyObject* walk_function(PyObject* op, stack* frontier)
270258 if (PyUnicode_Check (value )){
271259 PyObject * name = value ;
272260 if (PyDict_Contains (globals , name )){
273- value = make_global_immutable (globals , name );
274- if (!Py_IsNone (value )){
275- if (stack_push (frontier , value )){
276- stack_free (f_stack );
277- // frontier freed by the caller
278- return PyErr_NoMemory ();
279- }
261+ value = PyDict_GetItem (globals , name );
262+ if (PyDict_SetItem (frozen_globals , name , value )){
263+ Py_DECREF (frozen_builtins );
264+ Py_DECREF (frozen_globals );
265+ return NULL ;
280266 }
281267 }
282268 }
283269 }
284270 }
285271
272+ if (stack_push (frontier , frozen_globals )){
273+ goto nomemory ;
274+ }
275+
276+ f -> func_globals = frozen_globals ;
277+ Py_DECREF (globals );
278+
279+ if (stack_push (frontier , frozen_builtins )){
280+ goto nomemory ;
281+ }
282+
283+ f -> func_builtins = frozen_builtins ;
284+ Py_DECREF (builtins );
285+
286286 Py_RETURN_NONE ;
287- }
288287
289- #define _Py_FREEZE_CALL (f , item , frontier ) do { \
290- PyObject* err = f((item), (frontier)); \
291- if(!Py_IsNone(err)){ \
292- stack_free((frontier)); \
293- return err; \
294- } \
295- } while(0)
288+ nomemory :
289+ Py_XDECREF (frozen_builtins );
290+ Py_XDECREF (frozen_globals );
291+ stack_free (f_stack );
292+ return PyErr_NoMemory ();
293+ }
296294
297295static int _freeze_visit (PyObject * obj , void * frontier )
298296{
@@ -309,7 +307,6 @@ static int _freeze_visit(PyObject* obj, void* frontier)
309307 }
310308
311309 if (!_Py_IsImmutable (obj )){
312- //printf("Pushing object %p tp=%p rc=0x%lx\n", (void *)obj, obj->ob_type, obj->ob_refcnt);
313310 if (stack_push ((stack * )frontier , obj )){
314311 PyErr_NoMemory ();
315312 return -1 ;
@@ -321,9 +318,6 @@ static int _freeze_visit(PyObject* obj, void* frontier)
321318
322319PyObject * _Py_Freeze (PyObject * obj )
323320{
324- //printf("\nFreezing object: ");
325- //PyObject_Print(obj, stdout, 0);
326- //printf(" rc=0x%lx\n", obj->ob_refcnt);
327321 if (_Py_IsImmutable (obj ) && _Py_IsImmutable (Py_TYPE (obj ))){
328322 Py_RETURN_NONE ;
329323 }
@@ -340,32 +334,29 @@ PyObject* _Py_Freeze(PyObject* obj)
340334
341335 while (!stack_empty (frontier )){
342336 PyObject * item = stack_pop (frontier ); // item.rc = x + 1
343- //printf("Current item %p tp=%p rc=0x%lx: ", (void *)item, item->ob_type, item->ob_refcnt);
344- //fflush(stdout);
345- //PyObject_Print(item, stdout, 0);
346- //printf("\n");
347337
348338 PyTypeObject * type = Py_TYPE (item );
349339 traverseproc traverse ;
350340 PyObject * type_op = NULL ;
351341
352342 if (_Py_IsImmutable (item )){
353- // Direct access like this is not recommended, but will be removed in the future as
354- // this is just for debugging purposes.
355343 goto handle_type ;
356344 }
357345
358346 _Py_SetImmutable (item );
359347
360- //printf("Frozen object %p tp=%p rc=0x%lx\n", (void *)item, item->ob_type, item->ob_refcnt);
361348
362349 if (is_c_wrapper (item )) {
363350 // C functions are not mutable, so we can skip them.
364351 continue ;
365352 }
366353
367354 if (PyFunction_Check (item )){
368- _Py_FREEZE_CALL (walk_function , item , frontier );
355+ PyObject * err = walk_function (item , frontier );
356+ if (!Py_IsNone (err )){
357+ stack_free (frontier );
358+ return err ;
359+ }
369360 goto handle_type ;
370361 }
371362
@@ -380,7 +371,6 @@ PyObject* _Py_Freeze(PyObject* obj)
380371handle_type :
381372 type_op = _PyObject_CAST (item -> ob_type );
382373 if (!_Py_IsImmutable (type_op )){
383- // Previously this included a check for is_leaf_type, but
384374 if (stack_push (frontier , type_op ))
385375 {
386376 stack_free (frontier );
0 commit comments