[Python-checkins] r74132 - in python/branches/py3k: Doc/c-api/code.rst Doc/c-api/concrete.rst Doc/c-api/reflection.rst Doc/library/sys.rst Include/code.h Include/frameobject.h Lib/test/test_code.py Misc/NEWS Modules/_ctypes/callbacks.c Modules/_testcapimodule.c Modules/pyexpat.c Objects/codeobject.c Objects/frameobject.c Objects/lnotab_notes.txt Python/_warnings.c Python/ceval.c Python/compile.c Python/traceback.c

alexandre.vassalotti python-checkins at python.org
Tue Jul 21 06:30:03 CEST 2009


Author: alexandre.vassalotti
Date: Tue Jul 21 06:30:03 2009
New Revision: 74132

Log:
Merged revisions 72487-72488,72879 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r72487 | jeffrey.yasskin | 2009-05-08 17:51:06 -0400 (Fri, 08 May 2009) | 7 lines
  
  PyCode_NewEmpty:
  Most uses of PyCode_New found by http://www.google.com/codesearch?q=PyCode_New
  are trying to build an empty code object, usually to put it in a dummy frame
  object. This patch adds a PyCode_NewEmpty wrapper which lets the user specify
  just the filename, function name, and first line number, instead of also
  requiring lots of code internals.
........
  r72488 | jeffrey.yasskin | 2009-05-08 18:23:21 -0400 (Fri, 08 May 2009) | 13 lines
  
  Issue 5954, PyFrame_GetLineNumber:
  Most uses of PyCode_Addr2Line
  (http://www.google.com/codesearch?q=PyCode_Addr2Line) are just trying to get
  the line number of a specified frame, but there's no way to do that directly.
  Forcing people to go through the code object makes them know more about the
  guts of the interpreter than they should need.
  
  The remaining uses of PyCode_Addr2Line seem to be getting the line from a
  traceback (for example,
  http://www.google.com/codesearch/p?hl=en#u_9_nDrchrw/pygame-1.7.1release/src/base.c&q=PyCode_Addr2Line),
  which is replaced by the tb_lineno field.  So we may be able to deprecate
  PyCode_Addr2Line entirely for external use.
........
  r72879 | jeffrey.yasskin | 2009-05-23 19:23:01 -0400 (Sat, 23 May 2009) | 14 lines
  
  Issue #6042:
  lnotab-based tracing is very complicated and isn't documented very well.  There
  were at least 3 comment blocks purporting to document co_lnotab, and none did a
  very good job. This patch unifies them into Objects/lnotab_notes.txt which
  tries to completely capture the current state of affairs.
  
  I also discovered that we've attached 2 layers of patches to the basic tracing
  scheme. The first layer avoids jumping to instructions that don't start a line,
  to avoid problems in if statements and while loops.  The second layer
  discovered that jumps backward do need to trace at instructions that don't
  start a line, so it added extra lnotab entries for 'while' and 'for' loops, and
  added a special case for backward jumps within the same line. I replaced these
  patches by just treating forward and backward jumps differently.
........


Added:
   python/branches/py3k/Doc/c-api/code.rst
      - copied unchanged from r72488, /python/trunk/Doc/c-api/code.rst
   python/branches/py3k/Objects/lnotab_notes.txt
      - copied unchanged from r72879, /python/trunk/Objects/lnotab_notes.txt
Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/c-api/concrete.rst
   python/branches/py3k/Doc/c-api/reflection.rst
   python/branches/py3k/Doc/library/sys.rst
   python/branches/py3k/Include/code.h
   python/branches/py3k/Include/frameobject.h
   python/branches/py3k/Lib/test/test_code.py
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/_ctypes/callbacks.c
   python/branches/py3k/Modules/_testcapimodule.c
   python/branches/py3k/Modules/pyexpat.c
   python/branches/py3k/Objects/codeobject.c
   python/branches/py3k/Objects/frameobject.c
   python/branches/py3k/Python/_warnings.c
   python/branches/py3k/Python/ceval.c
   python/branches/py3k/Python/compile.c
   python/branches/py3k/Python/traceback.c

Modified: python/branches/py3k/Doc/c-api/concrete.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/concrete.rst	(original)
+++ python/branches/py3k/Doc/c-api/concrete.rst	Tue Jul 21 06:30:03 2009
@@ -105,3 +105,4 @@
    cell.rst
    gen.rst
    datetime.rst
+   code.rst

Modified: python/branches/py3k/Doc/c-api/reflection.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/reflection.rst	(original)
+++ python/branches/py3k/Doc/c-api/reflection.rst	Tue Jul 21 06:30:03 2009
@@ -29,6 +29,11 @@
    currently executing.
 
 
+.. cfunction:: int PyFrame_GetLineNumber(PyFrameObject *frame)
+
+   Return the line number that *frame* is currently executing.
+
+
 .. cfunction:: int PyEval_GetRestricted()
 
    If there is a current frame and it is executing in restricted mode, return true,

Modified: python/branches/py3k/Doc/library/sys.rst
==============================================================================
--- python/branches/py3k/Doc/library/sys.rst	(original)
+++ python/branches/py3k/Doc/library/sys.rst	Tue Jul 21 06:30:03 2009
@@ -720,9 +720,11 @@
       specifies the local trace function.
 
    ``'line'``
-      The interpreter is about to execute a new line of code (sometimes multiple
-      line events on one line exist).  The local trace function is called; *arg*
-      is ``None``; the return value specifies the new local trace function.
+      The interpreter is about to execute a new line of code or re-execute the
+      condition of a loop.  The local trace function is called; *arg* is
+      ``None``; the return value specifies the new local trace function.  See
+      :file:`Objects/lnotab_notes.txt` for a detailed explanation of how this
+      works.
 
    ``'return'``
       A function (or other code block) is about to return.  The local trace

Modified: python/branches/py3k/Include/code.h
==============================================================================
--- python/branches/py3k/Include/code.h	(original)
+++ python/branches/py3k/Include/code.h	Tue Jul 21 06:30:03 2009
@@ -24,7 +24,8 @@
     PyObject *co_filename;	/* unicode (where it was loaded from) */
     PyObject *co_name;		/* unicode (name, for reference) */
     int co_firstlineno;		/* first source line number */
-    PyObject *co_lnotab;	/* string (encoding addr<->lineno mapping) */
+    PyObject *co_lnotab;	/* string (encoding addr<->lineno mapping) See
+				   Objects/lnotab_notes.txt for details. */
     void *co_zombieframe;     /* for optimization only (see frameobject.c) */
 } PyCodeObject;
 
@@ -72,6 +73,14 @@
 	PyObject *, PyObject *, PyObject *, PyObject *,
 	PyObject *, PyObject *, int, PyObject *); 
         /* same as struct above */
+
+/* Creates a new empty code object with the specified source location. */
+PyAPI_FUNC(PyCodeObject *)
+PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno);
+
+/* Return the line number associated with the specified bytecode index
+   in this code object.  If you just need the line number of a frame,
+   use PyFrame_GetLineNumber() instead. */
 PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
 
 /* for internal use only */
@@ -80,15 +89,11 @@
         int ap_upper;
 } PyAddrPair;
 
-/* Check whether lasti (an instruction offset) falls outside bounds
-   and whether it is a line number that should be traced.  Returns
-   a line number if it should be traced or -1 if the line should not.
-
-   If lasti is not within bounds, updates bounds.
+/* Update *bounds to describe the first and one-past-the-last instructions in the
+   same line as lasti.  Return the number of that line.
 */
-
-PyAPI_FUNC(int) PyCode_CheckLineNumber(PyCodeObject* co,
-                                       int lasti, PyAddrPair *bounds);
+PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co,
+                                        int lasti, PyAddrPair *bounds);
 
 PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
                                       PyObject *names, PyObject *lineno_obj);

Modified: python/branches/py3k/Include/frameobject.h
==============================================================================
--- python/branches/py3k/Include/frameobject.h	(original)
+++ python/branches/py3k/Include/frameobject.h	Tue Jul 21 06:30:03 2009
@@ -38,8 +38,11 @@
 
     PyThreadState *f_tstate;
     int f_lasti;		/* Last instruction if called */
-    /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
-       f_trace is set) -- at other times use PyCode_Addr2Line instead. */
+    /* Call PyFrame_GetLineNumber() instead of reading this field
+       directly.  As of 2.3 f_lineno is only valid when tracing is
+       active (i.e. when f_trace is set).  At other times we use
+       PyCode_Addr2Line to calculate the line from the current
+       bytecode index. */
     int f_lineno;		/* Current line number */
     int f_iblock;		/* index in f_blockstack */
     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
@@ -75,6 +78,9 @@
 
 PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
 
+/* Return the line of code the frame is currently executing. */
+PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
+
 #ifdef __cplusplus
 }
 #endif

Modified: python/branches/py3k/Lib/test/test_code.py
==============================================================================
--- python/branches/py3k/Lib/test/test_code.py	(original)
+++ python/branches/py3k/Lib/test/test_code.py	Tue Jul 21 06:30:03 2009
@@ -102,6 +102,9 @@
 
 """
 
+import unittest
+import _testcapi
+
 def consts(t):
     """Yield a doctest-safe sequence of object reprs."""
     for elt in t:
@@ -118,10 +121,21 @@
         print("%s: %s" % (attr, getattr(co, "co_" + attr)))
     print("consts:", tuple(consts(co.co_consts)))
 
+
+class CodeTest(unittest.TestCase):
+
+    def test_newempty(self):
+        co = _testcapi.code_newempty("filename", "funcname", 15)
+        self.assertEquals(co.co_filename, "filename")
+        self.assertEquals(co.co_name, "funcname")
+        self.assertEquals(co.co_firstlineno, 15)
+
+
 def test_main(verbose=None):
-    from test.support import run_doctest
+    from test.support import run_doctest, run_unittest
     from test import test_code
     run_doctest(test_code, verbose)
+    run_unittest(CodeTest)
 
 
 if __name__ == '__main__':

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Tue Jul 21 06:30:03 2009
@@ -40,6 +40,15 @@
 
 - The code flags for old __future__ features are now available again.
 
+- Issue #5954: Add a PyFrame_GetLineNumber() function to replace most uses of
+  PyCode_Addr2Line().
+
+- Issue #5959: Add a PyCode_NewEmpty() function to create a new empty code
+  object at a specified file, function, and line number.
+
+- Issue #1419652: Change the first argument to PyImport_AppendInittab() to
+  ``const char *`` as the string is stored beyond the call.
+
 Library
 -------
 

Modified: python/branches/py3k/Modules/_ctypes/callbacks.c
==============================================================================
--- python/branches/py3k/Modules/_ctypes/callbacks.c	(original)
+++ python/branches/py3k/Modules/_ctypes/callbacks.c	Tue Jul 21 06:30:03 2009
@@ -94,41 +94,13 @@
 /* after code that pyrex generates */
 void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
 {
-	PyObject *py_srcfile = 0;
-	PyObject *py_funcname = 0;
 	PyObject *py_globals = 0;
-	PyObject *empty_tuple = 0;
-	PyObject *empty_string = 0;
 	PyCodeObject *py_code = 0;
 	PyFrameObject *py_frame = 0;
     
-	py_srcfile = PyUnicode_DecodeFSDefault(filename);
-	if (!py_srcfile) goto bad;
-	py_funcname = PyUnicode_FromString(funcname);
-	if (!py_funcname) goto bad;
 	py_globals = PyDict_New();
 	if (!py_globals) goto bad;
-	empty_tuple = PyTuple_New(0);
-	if (!empty_tuple) goto bad;
-	empty_string = PyBytes_FromString("");
-	if (!empty_string) goto bad;
-	py_code = PyCode_New(
-		0,            /*int argcount,*/
-		0,            /*int kwonlyargcount,*/
-		0,            /*int nlocals,*/
-		0,            /*int stacksize,*/
-		0,            /*int flags,*/
-		empty_string, /*PyObject *code,*/
-		empty_tuple,  /*PyObject *consts,*/
-		empty_tuple,  /*PyObject *names,*/
-		empty_tuple,  /*PyObject *varnames,*/
-		empty_tuple,  /*PyObject *freevars,*/
-		empty_tuple,  /*PyObject *cellvars,*/
-		py_srcfile,   /*PyObject *filename,*/
-		py_funcname,  /*PyObject *name,*/
-		lineno,   /*int firstlineno,*/
-		empty_string  /*PyObject *lnotab*/
-		);
+	py_code = PyCode_NewEmpty(filename, funcname, lineno);
 	if (!py_code) goto bad;
 	py_frame = PyFrame_New(
 		PyThreadState_Get(), /*PyThreadState *tstate,*/
@@ -141,10 +113,6 @@
 	PyTraceBack_Here(py_frame);
   bad:
 	Py_XDECREF(py_globals);
-	Py_XDECREF(py_srcfile);
-	Py_XDECREF(py_funcname);
-	Py_XDECREF(empty_tuple);
-	Py_XDECREF(empty_string);
 	Py_XDECREF(py_code);
 	Py_XDECREF(py_frame);
 }

Modified: python/branches/py3k/Modules/_testcapimodule.c
==============================================================================
--- python/branches/py3k/Modules/_testcapimodule.c	(original)
+++ python/branches/py3k/Modules/_testcapimodule.c	Tue Jul 21 06:30:03 2009
@@ -1446,6 +1446,21 @@
 	Py_RETURN_NONE;
 }
 
+/* To test that the result of PyCode_NewEmpty has the right members. */
+static PyObject *
+code_newempty(PyObject *self, PyObject *args)
+{
+	const char *filename;
+	const char *funcname;
+        int firstlineno;
+
+	if (!PyArg_ParseTuple(args, "ssi:code_newempty",
+			      &filename, &funcname, &firstlineno))
+		return NULL;
+
+	return (PyObject *)PyCode_NewEmpty(filename, funcname, firstlineno);
+}
+
 static PyMethodDef TestMethods[] = {
 	{"raise_exception",	raise_exception,		 METH_VARARGS},
 	{"raise_memoryerror",   (PyCFunction)raise_memoryerror,  METH_NOARGS},
@@ -1498,6 +1513,7 @@
 	{"traceback_print", traceback_print, 	         METH_VARARGS},
 	{"exception_print", exception_print, 	         METH_VARARGS},
 	{"argparsing",     argparsing, METH_VARARGS},
+	{"code_newempty", code_newempty, 	         METH_VARARGS},
 	{NULL, NULL} /* sentinel */
 };
 

Modified: python/branches/py3k/Modules/pyexpat.c
==============================================================================
--- python/branches/py3k/Modules/pyexpat.c	(original)
+++ python/branches/py3k/Modules/pyexpat.c	Tue Jul 21 06:30:03 2009
@@ -209,53 +209,11 @@
 static PyCodeObject*
 getcode(enum HandlerTypes slot, char* func_name, int lineno)
 {
-    PyObject *code = NULL;
-    PyObject *name = NULL;
-    PyObject *nulltuple = NULL;
-    PyObject *filename = NULL;
-
     if (handler_info[slot].tb_code == NULL) {
-        code = PyBytes_FromString("");
-        if (code == NULL)
-            goto failed;
-        name = PyUnicode_FromString(func_name);
-        if (name == NULL)
-            goto failed;
-        nulltuple = PyTuple_New(0);
-        if (nulltuple == NULL)
-            goto failed;
-        filename = PyUnicode_DecodeFSDefault(__FILE__);
         handler_info[slot].tb_code =
-            PyCode_New(0,		/* argcount */
-                       0,       /* kwonlyargcount */
-                       0,		/* nlocals */
-                       0,		/* stacksize */
-                       0,		/* flags */
-                       code,		/* code */
-                       nulltuple,	/* consts */
-                       nulltuple,	/* names */
-                       nulltuple,	/* varnames */
-#if PYTHON_API_VERSION >= 1010
-                       nulltuple,	/* freevars */
-                       nulltuple,	/* cellvars */
-#endif
-                       filename,	/* filename */
-                       name,		/* name */
-                       lineno,		/* firstlineno */
-                       code		/* lnotab */
-                       );
-        if (handler_info[slot].tb_code == NULL)
-            goto failed;
-        Py_DECREF(code);
-        Py_DECREF(nulltuple);
-        Py_DECREF(filename);
-        Py_DECREF(name);
+            PyCode_NewEmpty(__FILE__, func_name, lineno);
     }
     return handler_info[slot].tb_code;
- failed:
-    Py_XDECREF(code);
-    Py_XDECREF(name);
-    return NULL;
 }
 
 #ifdef FIX_TRACE

Modified: python/branches/py3k/Objects/codeobject.c
==============================================================================
--- python/branches/py3k/Objects/codeobject.c	(original)
+++ python/branches/py3k/Objects/codeobject.c	Tue Jul 21 06:30:03 2009
@@ -54,7 +54,7 @@
 	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) ||
@@ -112,6 +112,53 @@
 	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)
 
@@ -431,48 +478,8 @@
 	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
@@ -491,85 +498,10 @@
 	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.
-	*/
-
-
-int 
-PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
+/* 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)
 {
         int size, addr, line;
         unsigned char* p;
@@ -586,11 +518,9 @@
            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 +533,6 @@
                 --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++;

Modified: python/branches/py3k/Objects/frameobject.c
==============================================================================
--- python/branches/py3k/Objects/frameobject.c	(original)
+++ python/branches/py3k/Objects/frameobject.c	Tue Jul 21 06:30:03 2009
@@ -31,17 +31,19 @@
 	return f->f_locals;
 }
 
-static PyObject *
-frame_getlineno(PyFrameObject *f, void *closure)
+int
+PyFrame_GetLineNumber(PyFrameObject *f)
 {
-	int lineno;
-
 	if (f->f_trace)
-		lineno = f->f_lineno;
+		return f->f_lineno;
 	else
-		lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+		return PyCode_Addr2Line(f->f_code, f->f_lasti);
+}
 
-	return PyLong_FromLong(lineno);
+static PyObject *
+frame_getlineno(PyFrameObject *f, void *closure)
+{
+	return PyLong_FromLong(PyFrame_GetLineNumber(f));
 }
 
 /* Setter for f_lineno - you can set f_lineno from within a trace function in
@@ -345,16 +347,14 @@
 static int
 frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
 {
-	/* We rely on f_lineno being accurate when f_trace is set. */
+	PyObject* old_value;
 
-	PyObject* old_value = f->f_trace;
+	/* We rely on f_lineno being accurate when f_trace is set. */
+	f->f_lineno = PyFrame_GetLineNumber(f);
 
+	old_value = f->f_trace;
 	Py_XINCREF(v);
 	f->f_trace = v;
-
-	if (v != NULL)
-		f->f_lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
-
 	Py_XDECREF(old_value);
 
 	return 0;

Modified: python/branches/py3k/Python/_warnings.c
==============================================================================
--- python/branches/py3k/Python/_warnings.c	(original)
+++ python/branches/py3k/Python/_warnings.c	Tue Jul 21 06:30:03 2009
@@ -462,7 +462,7 @@
     }
     else {
         globals = f->f_globals;
-        *lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+        *lineno = PyFrame_GetLineNumber(f);
     }
 
     *module = NULL;

Modified: python/branches/py3k/Python/ceval.c
==============================================================================
--- python/branches/py3k/Python/ceval.c	(original)
+++ python/branches/py3k/Python/ceval.c	Tue Jul 21 06:30:03 2009
@@ -2761,7 +2761,7 @@
 		default:
 			fprintf(stderr,
 				"XXX lineno: %d, opcode: %d\n",
-				PyCode_Addr2Line(f->f_code, f->f_lasti),
+				PyFrame_GetLineNumber(f),
 				opcode);
 			PyErr_SetString(PyExc_SystemError, "unknown opcode");
 			why = WHY_EXCEPTION;
@@ -3522,33 +3522,30 @@
 	return result;
 }
 
+/* See Objects/lnotab_notes.txt for a description of how tracing works. */
 static int
 maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
 		      PyFrameObject *frame, int *instr_lb, int *instr_ub,
 		      int *instr_prev)
 {
 	int result = 0;
+	int line = frame->f_lineno;
 
         /* If the last instruction executed isn't in the current
-           instruction window, reset the window.  If the last
-           instruction happens to fall at the start of a line or if it
-           represents a jump backwards, call the trace function.
+           instruction window, reset the window.
         */
-	if ((frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub)) {
-		int line;
+	if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) {
 		PyAddrPair bounds;
-
-		line = PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
-					      &bounds);
-		if (line >= 0) {
-			frame->f_lineno = line;
-			result = call_trace(func, obj, frame,
-					    PyTrace_LINE, Py_None);
-		}
+		line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
+					       &bounds);
 		*instr_lb = bounds.ap_lower;
 		*instr_ub = bounds.ap_upper;
 	}
-	else if (frame->f_lasti <= *instr_prev) {
+	/* If the last instruction falls at the start of a line or if
+           it represents a jump backwards, update the frame's line
+           number and call the trace function. */
+	if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) {
+		frame->f_lineno = line;
 		result = call_trace(func, obj, frame, PyTrace_LINE, Py_None);
 	}
 	*instr_prev = frame->f_lasti;

Modified: python/branches/py3k/Python/compile.c
==============================================================================
--- python/branches/py3k/Python/compile.c	(original)
+++ python/branches/py3k/Python/compile.c	Tue Jul 21 06:30:03 2009
@@ -1748,9 +1748,6 @@
 	VISIT(c, expr, s->v.For.iter);
 	ADDOP(c, GET_ITER);
 	compiler_use_next_block(c, start);
-	/* for expressions must be traced on each iteration,
-	   so we need to set an extra line number. */
-	c->u->u_lineno_set = 0;
 	ADDOP_JREL(c, FOR_ITER, cleanup);
 	VISIT(c, expr, s->v.For.target);
 	VISIT_SEQ(c, stmt, s->v.For.body);
@@ -1796,9 +1793,6 @@
 	if (!compiler_push_fblock(c, LOOP, loop))
 		return 0;
 	if (constant == -1) {
-		/* while expressions must be traced on each iteration,
-		   so we need to set an extra line number. */
-		c->u->u_lineno_set = 0;
 		VISIT(c, expr, s->v.While.test);
 		ADDOP_JABS(c, POP_JUMP_IF_FALSE, anchor);
 	}
@@ -3654,51 +3648,9 @@
 	return size;
 }
 
-/* All about a_lnotab.
-
-c_lnotab is an array of unsigned bytes disguised as a Python string.
-It is used to map bytecode offsets to source code line #s (when needed
-for tracebacks).
-
-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, assemble_lnotab (it used
-to be called 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.
-*/
+/* Appends a pair to the end of the line number table, a_lnotab, representing
+   the instruction's bytecode offset and line number.  See
+   Objects/lnotab_notes.txt for the description of the line number table. */
 
 static int
 assemble_lnotab(struct assembler *a, struct instr *i)

Modified: python/branches/py3k/Python/traceback.c
==============================================================================
--- python/branches/py3k/Python/traceback.c	(original)
+++ python/branches/py3k/Python/traceback.c	Tue Jul 21 06:30:03 2009
@@ -114,8 +114,7 @@
 		Py_XINCREF(frame);
 		tb->tb_frame = frame;
 		tb->tb_lasti = frame->f_lasti;
-		tb->tb_lineno = PyCode_Addr2Line(frame->f_code, 
-						 frame->f_lasti);
+		tb->tb_lineno = PyFrame_GetLineNumber(frame);
 		PyObject_GC_Track(tb);
 	}
 	return tb;


More information about the Python-checkins mailing list