summaryrefslogtreecommitdiff
path: root/Objects/codeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/codeobject.c')
-rw-r--r--Objects/codeobject.c221
1 files changed, 76 insertions, 145 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index e3eccf7768..bb938ea0aa 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -54,7 +54,7 @@ PyCode_New(int argcount, int kwonlyargcount,
Py_ssize_t i;
/* Check argument types */
- if (argcount < 0 || nlocals < 0 ||
+ if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
code == NULL ||
consts == NULL || !PyTuple_Check(consts) ||
names == NULL || !PyTuple_Check(names) ||
@@ -108,10 +108,58 @@ PyCode_New(int argcount, int kwonlyargcount,
Py_INCREF(lnotab);
co->co_lnotab = lnotab;
co->co_zombieframe = NULL;
+ co->co_weakreflist = NULL;
}
return co;
}
+PyCodeObject *
+PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
+{
+ static PyObject *emptystring = NULL;
+ static PyObject *nulltuple = NULL;
+ PyObject *filename_ob = NULL;
+ PyObject *funcname_ob = NULL;
+ PyCodeObject *result = NULL;
+ if (emptystring == NULL) {
+ emptystring = PyBytes_FromString("");
+ if (emptystring == NULL)
+ goto failed;
+ }
+ if (nulltuple == NULL) {
+ nulltuple = PyTuple_New(0);
+ if (nulltuple == NULL)
+ goto failed;
+ }
+ funcname_ob = PyUnicode_FromString(funcname);
+ if (funcname_ob == NULL)
+ goto failed;
+ filename_ob = PyUnicode_DecodeFSDefault(filename);
+ if (filename_ob == NULL)
+ goto failed;
+
+ result = PyCode_New(0, /* argcount */
+ 0, /* kwonlyargcount */
+ 0, /* nlocals */
+ 0, /* stacksize */
+ 0, /* flags */
+ emptystring, /* code */
+ nulltuple, /* consts */
+ nulltuple, /* names */
+ nulltuple, /* varnames */
+ nulltuple, /* freevars */
+ nulltuple, /* cellvars */
+ filename_ob, /* filename */
+ funcname_ob, /* name */
+ firstlineno, /* firstlineno */
+ emptystring /* lnotab */
+ );
+
+failed:
+ Py_XDECREF(funcname_ob);
+ Py_XDECREF(filename_ob);
+ return result;
+}
#define OFF(x) offsetof(PyCodeObject, x)
@@ -284,22 +332,28 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_lnotab);
if (co->co_zombieframe != NULL)
PyObject_GC_Del(co->co_zombieframe);
+ if (co->co_weakreflist != NULL)
+ PyObject_ClearWeakRefs((PyObject*)co);
PyObject_DEL(co);
}
static PyObject *
code_repr(PyCodeObject *co)
{
- int lineno = -1;
- char *filename = "???";
-
+ int lineno;
if (co->co_firstlineno != 0)
lineno = co->co_firstlineno;
- if (co->co_filename && PyUnicode_Check(co->co_filename))
- filename = _PyUnicode_AsString(co->co_filename);
- return PyUnicode_FromFormat(
- "<code object %.100U at %p, file \"%.300s\", line %d>",
- co->co_name, co, filename, lineno);
+ else
+ lineno = -1;
+ if (co->co_filename && PyUnicode_Check(co->co_filename)) {
+ return PyUnicode_FromFormat(
+ "<code object %U at %p, file \"%U\", line %d>",
+ co->co_name, co, co->co_filename, lineno);
+ } else {
+ return PyUnicode_FromFormat(
+ "<code object %U at %p, file ???, line %d>",
+ co->co_name, co, lineno);
+ }
}
static PyObject *
@@ -363,10 +417,10 @@ code_richcompare(PyObject *self, PyObject *other, int op)
return res;
}
-static long
+static Py_hash_t
code_hash(PyCodeObject *co)
{
- long h, h0, h1, h2, h3, h4, h5, h6;
+ Py_hash_t h, h0, h1, h2, h3, h4, h5, h6;
h0 = PyObject_Hash(co->co_name);
if (h0 == -1) return -1;
h1 = PyObject_Hash(co->co_code);
@@ -415,7 +469,7 @@ PyTypeObject PyCode_Type = {
0, /* tp_traverse */
0, /* tp_clear */
code_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
+ offsetof(PyCodeObject, co_weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
@@ -431,54 +485,14 @@ PyTypeObject PyCode_Type = {
code_new, /* tp_new */
};
-/* All about c_lnotab.
-
-c_lnotab is an array of unsigned bytes disguised as a Python string. In -O
-mode, SET_LINENO opcodes aren't generated, and bytecode offsets are mapped
-to source code line #s (when needed for tracebacks) via c_lnotab instead.
-The array is conceptually a list of
- (bytecode offset increment, line number increment)
-pairs. The details are important and delicate, best illustrated by example:
-
- byte code offset source code line number
- 0 1
- 6 2
- 50 7
- 350 307
- 361 308
-
-The first trick is that these numbers aren't stored, only the increments
-from one row to the next (this doesn't really work, but it's a start):
-
- 0, 1, 6, 1, 44, 5, 300, 300, 11, 1
-
-The second trick is that an unsigned byte can't hold negative values, or
-values larger than 255, so (a) there's a deep assumption that byte code
-offsets and their corresponding line #s both increase monotonically, and (b)
-if at least one column jumps by more than 255 from one row to the next, more
-than one pair is written to the table. In case #b, there's no way to know
-from looking at the table later how many were written. That's the delicate
-part. A user of c_lnotab desiring to find the source line number
-corresponding to a bytecode address A should do something like this
-
- lineno = addr = 0
- for addr_incr, line_incr in c_lnotab:
- addr += addr_incr
- if addr > A:
- return lineno
- lineno += line_incr
-
-In order for this to work, when the addr field increments by more than 255,
-the line # increment in each pair generated must be 0 until the remaining addr
-increment is < 256. So, in the example above, com_set_lineno should not (as
-was actually done until 2.2) expand 300, 300 to 255, 255, 45, 45, but to
-255, 0, 45, 255, 0, 45.
+/* Use co_lnotab to compute the line number from a bytecode index, addrq. See
+ lnotab_notes.txt for the details of the lnotab representation.
*/
int
PyCode_Addr2Line(PyCodeObject *co, int addrq)
{
- int size = PyBytes_Size(co->co_lnotab) / 2;
+ Py_ssize_t size = PyBytes_Size(co->co_lnotab) / 2;
unsigned char *p = (unsigned char*)PyBytes_AsString(co->co_lnotab);
int line = co->co_firstlineno;
int addr = 0;
@@ -491,87 +505,13 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
return line;
}
-/*
- Check whether the current instruction is at the start of a line.
-
- */
-
- /* The theory of SET_LINENO-less tracing.
-
- In a nutshell, we use the co_lnotab field of the code object
- to tell when execution has moved onto a different line.
-
- As mentioned above, the basic idea is so set things up so
- that
-
- *instr_lb <= frame->f_lasti < *instr_ub
-
- is true so long as execution does not change lines.
-
- This is all fairly simple. Digging the information out of
- co_lnotab takes some work, but is conceptually clear.
-
- Somewhat harder to explain is why we don't *always* call the
- line trace function when the above test fails.
-
- Consider this code:
-
- 1: def f(a):
- 2: if a:
- 3: print 1
- 4: else:
- 5: print 2
-
- which compiles to this:
-
- 2 0 LOAD_FAST 0 (a)
- 3 JUMP_IF_FALSE 9 (to 15)
- 6 POP_TOP
-
- 3 7 LOAD_CONST 1 (1)
- 10 PRINT_ITEM
- 11 PRINT_NEWLINE
- 12 JUMP_FORWARD 6 (to 21)
- >> 15 POP_TOP
-
- 5 16 LOAD_CONST 2 (2)
- 19 PRINT_ITEM
- 20 PRINT_NEWLINE
- >> 21 LOAD_CONST 0 (None)
- 24 RETURN_VALUE
-
- If 'a' is false, execution will jump to instruction at offset
- 15 and the co_lnotab will claim that execution has moved to
- line 3. This is at best misleading. In this case we could
- associate the POP_TOP with line 4, but that doesn't make
- sense in all cases (I think).
-
- What we do is only call the line trace function if the co_lnotab
- indicates we have jumped to the *start* of a line, i.e. if the
- current instruction offset matches the offset given for the
- start of a line by the co_lnotab.
-
- This also takes care of the situation where 'a' is true.
- Execution will jump from instruction offset 12 to offset 21.
- Then the co_lnotab would imply that execution has moved to line
- 5, which is again misleading.
-
- Why do we set f_lineno when tracing? Well, consider the code
- above when 'a' is true. If stepping through this with 'n' in
- pdb, you would stop at line 1 with a "call" type event, then
- line events on lines 2 and 3, then a "return" type event -- but
- you would be shown line 5 during this event. This is a change
- from the behaviour in 2.2 and before, and I've found it
- confusing in practice. By setting and using f_lineno when
- tracing, one can report a line number different from that
- suggested by f_lasti on this one occasion where it's desirable.
- */
-
-
+/* Update *bounds to describe the first and one-past-the-last instructions in
+ the same line as lasti. Return the number of that line. */
int
-PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
+_PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
{
- int size, addr, line;
+ Py_ssize_t size;
+ int addr, line;
unsigned char* p;
p = (unsigned char*)PyBytes_AS_STRING(co->co_lnotab);
@@ -586,11 +526,9 @@ PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
instr_lb -- if we stored the matching value of p
somwhere we could skip the first while loop. */
- /* see comments in compile.c for the description of
+ /* See lnotab_notes.txt for the description of
co_lnotab. A point to remember: increments to p
- should come in pairs -- although we don't care about
- the line increments here, treating them as byte
- increments gets confusing, to say the least. */
+ come in (addr, line) pairs. */
bounds->ap_lower = 0;
while (size > 0) {
@@ -603,13 +541,6 @@ PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
--size;
}
- /* If lasti and addr don't match exactly, we don't want to
- change the lineno slot on the frame or execute a trace
- function. Return -1 instead.
- */
- if (addr != lasti)
- line = -1;
-
if (size > 0) {
while (--size >= 0) {
addr += *p++;