diff options
Diffstat (limited to 'Objects/frameobject.c')
-rw-r--r-- | Objects/frameobject.c | 218 |
1 files changed, 137 insertions, 81 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 83dacfd5..4f195ee 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -48,7 +48,7 @@ frame_getlineno(PyFrameObject *f, void *closure) } /* Setter for f_lineno - you can set f_lineno from within a trace function in - * order to jump to a given line of code, subject to some restrictions. Most + * order to jump to a given line of code, subject to some restrictions. Most * lines are OK to jump to because they don't make any assumptions about the * state of the stack (obvious because you could remove the line and the code * would still work without any stack errors), but there are some constructs @@ -68,7 +68,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) int new_lineno = 0; /* The new value of f_lineno */ int new_lasti = 0; /* The new value of f_lasti */ int new_iblock = 0; /* The new value of f_iblock */ - char *code = NULL; /* The bytecode for the frame... */ + unsigned char *code = NULL; /* The bytecode for the frame... */ Py_ssize_t code_len = 0; /* ...and its length */ char *lnotab = NULL; /* Iterating over co_lnotab */ Py_ssize_t lnotab_len = 0; /* (ditto) */ @@ -85,7 +85,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) int blockstack[CO_MAXBLOCKS]; /* Walking the 'finally' blocks */ int in_finally[CO_MAXBLOCKS]; /* (ditto) */ int blockstack_top = 0; /* (ditto) */ - int setup_op = 0; /* (ditto) */ + unsigned char setup_op = 0; /* (ditto) */ /* f_lineno must be an integer. */ if (!PyInt_CheckExact(p_new_lineno)) { @@ -137,7 +137,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) } /* We're now ready to look at the bytecode. */ - PyString_AsStringAndSize(f->f_code->co_code, &code, &code_len); + PyString_AsStringAndSize(f->f_code->co_code, (char **)&code, &code_len); min_addr = MIN(new_lasti, f->f_lasti); max_addr = MAX(new_lasti, f->f_lasti); @@ -159,7 +159,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) /* You can't jump into or out of a 'finally' block because the 'try' * block leaves something on the stack for the END_FINALLY to clean - * up. So we walk the bytecode, maintaining a simulated blockstack. + * up. So we walk the bytecode, maintaining a simulated blockstack. * When we reach the old or new address and it's in a 'finally' block * we note the address of the corresponding SETUP_FINALLY. The jump * is only legal if neither address is in a 'finally' block or @@ -383,7 +383,7 @@ static PyGetSetDef frame_getsetlist[] = { ob_type == &Frametype f_back next item on free list, or NULL f_stacksize size of value stack - ob_size size of localsplus + ob_size size of localsplus Note that the value and block stacks are preserved -- this can save another malloc() call or two (and two free() calls as well!). Also note that, unlike for integers, each frame object is a @@ -408,12 +408,12 @@ frame_dealloc(PyFrameObject *f) PyObject **p, **valuestack; PyCodeObject *co; - PyObject_GC_UnTrack(f); + PyObject_GC_UnTrack(f); Py_TRASHCAN_SAFE_BEGIN(f) /* Kill all local variables */ - valuestack = f->f_valuestack; - for (p = f->f_localsplus; p < valuestack; p++) - Py_CLEAR(*p); + valuestack = f->f_valuestack; + for (p = f->f_localsplus; p < valuestack; p++) + Py_CLEAR(*p); /* Free stack */ if (f->f_stacktop != NULL) { @@ -430,18 +430,18 @@ frame_dealloc(PyFrameObject *f) Py_CLEAR(f->f_exc_value); Py_CLEAR(f->f_exc_traceback); - co = f->f_code; - if (co->co_zombieframe == NULL) - co->co_zombieframe = f; + co = f->f_code; + if (co->co_zombieframe == NULL) + co->co_zombieframe = f; else if (numfree < MAXFREELIST) { ++numfree; f->f_back = free_list; free_list = f; - } + } else PyObject_GC_Del(f); - Py_DECREF(co); + Py_DECREF(co); Py_TRASHCAN_SAFE_END(f) } @@ -482,12 +482,12 @@ frame_clear(PyFrameObject *f) int i, slots; /* Before anything else, make sure that this frame is clearly marked - * as being defunct! Else, e.g., a generator reachable from this - * frame may also point to this frame, believe itself to still be - * active, and try cleaning up this frame again. - */ + * as being defunct! Else, e.g., a generator reachable from this + * frame may also point to this frame, believe itself to still be + * active, and try cleaning up this frame again. + */ oldtop = f->f_stacktop; - f->f_stacktop = NULL; + f->f_stacktop = NULL; Py_CLEAR(f->f_exc_type); Py_CLEAR(f->f_exc_value); @@ -514,10 +514,10 @@ PyTypeObject PyFrame_Type = { "frame", sizeof(PyFrameObject), sizeof(PyObject *), - (destructor)frame_dealloc, /* tp_dealloc */ + (destructor)frame_dealloc, /* tp_dealloc */ 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ @@ -530,8 +530,8 @@ PyTypeObject PyFrame_Type = { PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ - 0, /* tp_doc */ - (traverseproc)frame_traverse, /* tp_traverse */ + 0, /* tp_doc */ + (traverseproc)frame_traverse, /* tp_traverse */ (inquiry)frame_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ @@ -579,7 +579,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, builtins = NULL; } if (builtins == NULL) { - /* No builtins! Make up a minimal one + /* No builtins! Make up a minimal one Give them 'None', at least. */ builtins = PyDict_New(); if (builtins == NULL || @@ -599,39 +599,39 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, Py_INCREF(builtins); } if (code->co_zombieframe != NULL) { - f = code->co_zombieframe; - code->co_zombieframe = NULL; - _Py_NewReference((PyObject *)f); - assert(f->f_code == code); + f = code->co_zombieframe; + code->co_zombieframe = NULL; + _Py_NewReference((PyObject *)f); + assert(f->f_code == code); } - else { - Py_ssize_t extras, ncells, nfrees; - ncells = PyTuple_GET_SIZE(code->co_cellvars); - nfrees = PyTuple_GET_SIZE(code->co_freevars); - extras = code->co_stacksize + code->co_nlocals + ncells + - nfrees; - if (free_list == NULL) { - f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, - extras); - if (f == NULL) { - Py_DECREF(builtins); - return NULL; - } - } - else { - assert(numfree > 0); - --numfree; - f = free_list; - free_list = free_list->f_back; - if (f->ob_size < extras) { - f = PyObject_GC_Resize(PyFrameObject, f, extras); - if (f == NULL) { - Py_DECREF(builtins); - return NULL; - } - } - _Py_NewReference((PyObject *)f); - } + else { + Py_ssize_t extras, ncells, nfrees; + ncells = PyTuple_GET_SIZE(code->co_cellvars); + nfrees = PyTuple_GET_SIZE(code->co_freevars); + extras = code->co_stacksize + code->co_nlocals + ncells + + nfrees; + if (free_list == NULL) { + f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, + extras); + if (f == NULL) { + Py_DECREF(builtins); + return NULL; + } + } + else { + assert(numfree > 0); + --numfree; + f = free_list; + free_list = free_list->f_back; + if (f->ob_size < extras) { + f = PyObject_GC_Resize(PyFrameObject, f, extras); + if (f == NULL) { + Py_DECREF(builtins); + return NULL; + } + } + _Py_NewReference((PyObject *)f); + } f->f_code = code; extras = code->co_nlocals + ncells + nfrees; @@ -640,7 +640,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, f->f_localsplus[i] = NULL; f->f_locals = NULL; f->f_trace = NULL; - f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; + f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; } f->f_stacktop = f->f_valuestack; f->f_builtins = builtins; @@ -659,13 +659,13 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, Py_DECREF(f); return NULL; } - f->f_locals = locals; + f->f_locals = locals; } else { if (locals == NULL) locals = globals; Py_INCREF(locals); - f->f_locals = locals; + f->f_locals = locals; } f->f_tstate = tstate; @@ -701,18 +701,38 @@ PyFrame_BlockPop(PyFrameObject *f) return b; } -/* Convert between "fast" version of locals and dictionary version */ +/* Convert between "fast" version of locals and dictionary version. + + map and values are input arguments. map is a tuple of strings. + values is an array of PyObject*. At index i, map[i] is the name of + the variable with value values[i]. The function copies the first + nmap variable from map/values into dict. If values[i] is NULL, + the variable is deleted from dict. + + 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 map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, - Py_ssize_t deref) + int deref) { Py_ssize_t j; + assert(PyTuple_Check(map)); + assert(PyDict_Check(dict)); + assert(PyTuple_Size(map) >= nmap); for (j = nmap; --j >= 0; ) { PyObject *key = PyTuple_GET_ITEM(map, j); PyObject *value = values[j]; - if (deref) + assert(PyString_Check(key)); + if (deref) { + assert(PyCell_Check(value)); value = PyCell_GET(value); + } if (value == NULL) { if (PyObject_DelItem(dict, key) != 0) PyErr_Clear(); @@ -724,29 +744,55 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, } } +/* Copy values from the "locals" dict into the fast locals. + + dict is an input argument containing string keys representing + variables names and arbitrary PyObject* as values. + + map and values are input arguments. map is a tuple of strings. + values is an array of PyObject*. At index i, map[i] is the name of + the variable with value values[i]. The function copies the first + nmap variable from map/values into dict. If values[i] is NULL, + the variable is deleted from dict. + + 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. If clear is true, then variables in map but not in dict + are set to NULL in map; if clear is false, variables missing in + dict are ignored. + + Exceptions raised while modifying the dict are silently ignored, + because there is no good way to report them. +*/ + static void dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, - Py_ssize_t deref, int clear) + int deref, int clear) { Py_ssize_t j; + assert(PyTuple_Check(map)); + assert(PyDict_Check(dict)); + assert(PyTuple_Size(map) >= nmap); for (j = nmap; --j >= 0; ) { PyObject *key = PyTuple_GET_ITEM(map, j); PyObject *value = PyObject_GetItem(dict, key); - if (value == NULL) + assert(PyString_Check(key)); + /* We only care about NULLs if clear is true. */ + if (value == NULL) { PyErr_Clear(); + if (!clear) + continue; + } if (deref) { - if (value || clear) { - if (PyCell_GET(values[j]) != value) { - if (PyCell_Set(values[j], value) < 0) - PyErr_Clear(); - } - } - } else if (value != NULL || clear) { - if (values[j] != value) { - Py_XINCREF(value); - Py_XDECREF(values[j]); - values[j] = value; + assert(PyCell_Check(values[j])); + if (PyCell_GET(values[j]) != value) { + if (PyCell_Set(values[j], value) < 0) + PyErr_Clear(); } + } else if (values[j] != value) { + Py_XINCREF(value); + Py_XDECREF(values[j]); + values[j] = value; } Py_XDECREF(value); } @@ -761,7 +807,7 @@ PyFrame_FastToLocals(PyFrameObject *f) PyObject *error_type, *error_value, *error_traceback; PyCodeObject *co; Py_ssize_t j; - int ncells, nfreevars; + int ncells, nfreevars; if (f == NULL) return; locals = f->f_locals; @@ -788,8 +834,18 @@ PyFrame_FastToLocals(PyFrameObject *f) if (ncells || nfreevars) { map_to_dict(co->co_cellvars, ncells, locals, fast + co->co_nlocals, 1); - map_to_dict(co->co_freevars, nfreevars, - locals, fast + co->co_nlocals + ncells, 1); + /* If the namespace is unoptimized, then one of the + following cases applies: + 1. It does not contain free variables, because it + uses import * or is a top-level namespace. + 2. It is a class namespace. + We don't want to accidentally copy free variables + 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); + } } PyErr_Restore(error_type, error_value, error_traceback); } @@ -827,7 +883,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) locals, fast + co->co_nlocals, 1, clear); dict_to_map(co->co_freevars, nfreevars, locals, fast + co->co_nlocals + ncells, 1, - clear); + clear); } PyErr_Restore(error_type, error_value, error_traceback); } |