|
|
|
@ -21,7 +21,8 @@ static PyMemberDef frame_memberlist[] = { |
|
|
|
static PyObject * |
|
|
|
frame_getlocals(PyFrameObject *f, void *closure) |
|
|
|
{ |
|
|
|
PyFrame_FastToLocals(f); |
|
|
|
if (PyFrame_FastToLocalsWithError(f) < 0) |
|
|
|
return NULL; |
|
|
|
Py_INCREF(f->f_locals); |
|
|
|
return f->f_locals; |
|
|
|
} |
|
|
|
@ -772,12 +773,9 @@ PyFrame_BlockPop(PyFrameObject *f) |
|
|
|
If deref is true, then the values being copied are cell variables |
|
|
|
and the value is extracted from the cell variable before being put |
|
|
|
in dict. |
|
|
|
|
|
|
|
Exceptions raised while modifying the dict are silently ignored, |
|
|
|
because there is no good way to report them. |
|
|
|
*/ |
|
|
|
|
|
|
|
static void |
|
|
|
static int |
|
|
|
map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, |
|
|
|
int deref) |
|
|
|
{ |
|
|
|
@ -794,14 +792,19 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, |
|
|
|
value = PyCell_GET(value); |
|
|
|
} |
|
|
|
if (value == NULL) { |
|
|
|
if (PyObject_DelItem(dict, key) != 0) |
|
|
|
PyErr_Clear(); |
|
|
|
if (PyObject_DelItem(dict, key) != 0) { |
|
|
|
if (PyErr_ExceptionMatches(PyExc_KeyError)) |
|
|
|
PyErr_Clear(); |
|
|
|
else |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if (PyObject_SetItem(dict, key, value) != 0) |
|
|
|
PyErr_Clear(); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Copy values from the "locals" dict into the fast locals. |
|
|
|
@ -858,42 +861,49 @@ dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
PyFrame_FastToLocals(PyFrameObject *f) |
|
|
|
int |
|
|
|
PyFrame_FastToLocalsWithError(PyFrameObject *f) |
|
|
|
{ |
|
|
|
/* Merge fast locals into f->f_locals */ |
|
|
|
PyObject *locals, *map; |
|
|
|
PyObject **fast; |
|
|
|
PyObject *error_type, *error_value, *error_traceback; |
|
|
|
PyCodeObject *co; |
|
|
|
Py_ssize_t j; |
|
|
|
Py_ssize_t ncells, nfreevars; |
|
|
|
if (f == NULL) |
|
|
|
return; |
|
|
|
|
|
|
|
if (f == NULL) { |
|
|
|
PyErr_BadInternalCall(); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
locals = f->f_locals; |
|
|
|
if (locals == NULL) { |
|
|
|
locals = f->f_locals = PyDict_New(); |
|
|
|
if (locals == NULL) { |
|
|
|
PyErr_Clear(); /* Can't report it :-( */ |
|
|
|
return; |
|
|
|
} |
|
|
|
if (locals == NULL) |
|
|
|
return -1; |
|
|
|
} |
|
|
|
co = f->f_code; |
|
|
|
map = co->co_varnames; |
|
|
|
if (!PyTuple_Check(map)) |
|
|
|
return; |
|
|
|
PyErr_Fetch(&error_type, &error_value, &error_traceback); |
|
|
|
if (!PyTuple_Check(map)) { |
|
|
|
PyErr_Format(PyExc_SystemError, |
|
|
|
"co_varnames must be a tuple, not %s", |
|
|
|
Py_TYPE(map)->tp_name); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
fast = f->f_localsplus; |
|
|
|
j = PyTuple_GET_SIZE(map); |
|
|
|
if (j > co->co_nlocals) |
|
|
|
j = co->co_nlocals; |
|
|
|
if (co->co_nlocals) |
|
|
|
map_to_dict(map, j, locals, fast, 0); |
|
|
|
if (co->co_nlocals) { |
|
|
|
if (map_to_dict(map, j, locals, fast, 0) < 0) |
|
|
|
return -1; |
|
|
|
} |
|
|
|
ncells = PyTuple_GET_SIZE(co->co_cellvars); |
|
|
|
nfreevars = PyTuple_GET_SIZE(co->co_freevars); |
|
|
|
if (ncells || nfreevars) { |
|
|
|
map_to_dict(co->co_cellvars, ncells, |
|
|
|
locals, fast + co->co_nlocals, 1); |
|
|
|
if (map_to_dict(co->co_cellvars, ncells, |
|
|
|
locals, fast + co->co_nlocals, 1)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/* If the namespace is unoptimized, then one of the |
|
|
|
following cases applies: |
|
|
|
1. It does not contain free variables, because it |
|
|
|
@ -903,11 +913,24 @@ PyFrame_FastToLocals(PyFrameObject *f) |
|
|
|
into the locals dict used by the class. |
|
|
|
*/ |
|
|
|
if (co->co_flags & CO_OPTIMIZED) { |
|
|
|
map_to_dict(co->co_freevars, nfreevars, |
|
|
|
locals, fast + co->co_nlocals + ncells, 1); |
|
|
|
if (map_to_dict(co->co_freevars, nfreevars, |
|
|
|
locals, fast + co->co_nlocals + ncells, 1) < 0) |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
PyErr_Restore(error_type, error_value, error_traceback); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
PyFrame_FastToLocals(PyFrameObject *f) |
|
|
|
{ |
|
|
|
int res; |
|
|
|
|
|
|
|
assert(!PyErr_Occurred()); |
|
|
|
|
|
|
|
res = PyFrame_FastToLocalsWithError(f); |
|
|
|
if (res < 0) |
|
|
|
PyErr_Clear(); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
|