Skip to content

Commit 7b82b40

Browse files
committed
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. ........
1 parent 6f82818 commit 7b82b40

18 files changed

+335
-306
lines changed

Doc/c-api/code.rst

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
.. highlightlang:: c
2+
3+
.. _codeobjects:
4+
5+
Code Objects
6+
------------
7+
8+
.. sectionauthor:: Jeffrey Yasskin <jyasskin@gmail.com>
9+
10+
11+
.. index::
12+
object: code
13+
14+
Code objects are a low-level detail of the CPython implementation.
15+
Each one represents a chunk of executable code that hasn't yet been
16+
bound into a function.
17+
18+
.. ctype:: PyCodeObject
19+
20+
The C structure of the objects used to describe code objects. The
21+
fields of this type are subject to change at any time.
22+
23+
24+
.. cvar:: PyTypeObject PyCode_Type
25+
26+
This is an instance of :ctype:`PyTypeObject` representing the Python
27+
:class:`code` type.
28+
29+
30+
.. cfunction:: int PyCode_Check(PyObject *co)
31+
32+
Return true if *co* is a :class:`code` object
33+
34+
.. cfunction:: int PyCode_GetNumFree(PyObject *co)
35+
36+
Return the number of free variables in *co*.
37+
38+
.. cfunction:: PyCodeObject *PyCode_New(int argcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab)
39+
40+
Return a new code object. If you need a dummy code object to
41+
create a frame, use :cfunc:`PyCode_NewEmpty` instead. Calling
42+
:cfunc:`PyCode_New` directly can bind you to a precise Python
43+
version since the definition of the bytecode changes often.
44+
45+
46+
.. cfunction:: int PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
47+
48+
Return a new empty code object with the specified filename,
49+
function name, and first line number. It is illegal to
50+
:keyword:`exec` or :func:`eval` the resulting code object.

Doc/c-api/concrete.rst

+1
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,4 @@ Other Objects
105105
cell.rst
106106
gen.rst
107107
datetime.rst
108+
code.rst

Doc/c-api/reflection.rst

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ Reflection
2929
currently executing.
3030

3131

32+
.. cfunction:: int PyFrame_GetLineNumber(PyFrameObject *frame)
33+
34+
Return the line number that *frame* is currently executing.
35+
36+
3237
.. cfunction:: int PyEval_GetRestricted()
3338

3439
If there is a current frame and it is executing in restricted mode, return true,

Doc/library/sys.rst

+5-3
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,11 @@ always available.
720720
specifies the local trace function.
721721

722722
``'line'``
723-
The interpreter is about to execute a new line of code (sometimes multiple
724-
line events on one line exist). The local trace function is called; *arg*
725-
is ``None``; the return value specifies the new local trace function.
723+
The interpreter is about to execute a new line of code or re-execute the
724+
condition of a loop. The local trace function is called; *arg* is
725+
``None``; the return value specifies the new local trace function. See
726+
:file:`Objects/lnotab_notes.txt` for a detailed explanation of how this
727+
works.
726728

727729
``'return'``
728730
A function (or other code block) is about to return. The local trace

Include/code.h

+14-9
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ typedef struct {
2424
PyObject *co_filename; /* unicode (where it was loaded from) */
2525
PyObject *co_name; /* unicode (name, for reference) */
2626
int co_firstlineno; /* first source line number */
27-
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */
27+
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
28+
Objects/lnotab_notes.txt for details. */
2829
void *co_zombieframe; /* for optimization only (see frameobject.c) */
2930
} PyCodeObject;
3031

@@ -72,6 +73,14 @@ PyAPI_FUNC(PyCodeObject *) PyCode_New(
7273
PyObject *, PyObject *, PyObject *, PyObject *,
7374
PyObject *, PyObject *, int, PyObject *);
7475
/* same as struct above */
76+
77+
/* Creates a new empty code object with the specified source location. */
78+
PyAPI_FUNC(PyCodeObject *)
79+
PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno);
80+
81+
/* Return the line number associated with the specified bytecode index
82+
in this code object. If you just need the line number of a frame,
83+
use PyFrame_GetLineNumber() instead. */
7584
PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
7685

7786
/* for internal use only */
@@ -80,15 +89,11 @@ typedef struct _addr_pair {
8089
int ap_upper;
8190
} PyAddrPair;
8291

83-
/* Check whether lasti (an instruction offset) falls outside bounds
84-
and whether it is a line number that should be traced. Returns
85-
a line number if it should be traced or -1 if the line should not.
86-
87-
If lasti is not within bounds, updates bounds.
92+
/* Update *bounds to describe the first and one-past-the-last instructions in the
93+
same line as lasti. Return the number of that line.
8894
*/
89-
90-
PyAPI_FUNC(int) PyCode_CheckLineNumber(PyCodeObject* co,
91-
int lasti, PyAddrPair *bounds);
95+
PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co,
96+
int lasti, PyAddrPair *bounds);
9297

9398
PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
9499
PyObject *names, PyObject *lineno_obj);

Include/frameobject.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ typedef struct _frame {
3838

3939
PyThreadState *f_tstate;
4040
int f_lasti; /* Last instruction if called */
41-
/* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
42-
f_trace is set) -- at other times use PyCode_Addr2Line instead. */
41+
/* Call PyFrame_GetLineNumber() instead of reading this field
42+
directly. As of 2.3 f_lineno is only valid when tracing is
43+
active (i.e. when f_trace is set). At other times we use
44+
PyCode_Addr2Line to calculate the line from the current
45+
bytecode index. */
4346
int f_lineno; /* Current line number */
4447
int f_iblock; /* index in f_blockstack */
4548
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
@@ -75,6 +78,9 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
7578

7679
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
7780

81+
/* Return the line of code the frame is currently executing. */
82+
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *);
83+
7884
#ifdef __cplusplus
7985
}
8086
#endif

Lib/test/test_code.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@
102102
103103
"""
104104

105+
import unittest
106+
import _testcapi
107+
105108
def consts(t):
106109
"""Yield a doctest-safe sequence of object reprs."""
107110
for elt in t:
@@ -118,10 +121,21 @@ def dump(co):
118121
print("%s: %s" % (attr, getattr(co, "co_" + attr)))
119122
print("consts:", tuple(consts(co.co_consts)))
120123

124+
125+
class CodeTest(unittest.TestCase):
126+
127+
def test_newempty(self):
128+
co = _testcapi.code_newempty("filename", "funcname", 15)
129+
self.assertEquals(co.co_filename, "filename")
130+
self.assertEquals(co.co_name, "funcname")
131+
self.assertEquals(co.co_firstlineno, 15)
132+
133+
121134
def test_main(verbose=None):
122-
from test.support import run_doctest
135+
from test.support import run_doctest, run_unittest
123136
from test import test_code
124137
run_doctest(test_code, verbose)
138+
run_unittest(CodeTest)
125139

126140

127141
if __name__ == '__main__':

Misc/NEWS

+9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ C-API
4040

4141
- The code flags for old __future__ features are now available again.
4242

43+
- Issue #5954: Add a PyFrame_GetLineNumber() function to replace most uses of
44+
PyCode_Addr2Line().
45+
46+
- Issue #5959: Add a PyCode_NewEmpty() function to create a new empty code
47+
object at a specified file, function, and line number.
48+
49+
- Issue #1419652: Change the first argument to PyImport_AppendInittab() to
50+
``const char *`` as the string is stored beyond the call.
51+
4352
Library
4453
-------
4554

Modules/_ctypes/callbacks.c

+1-33
Original file line numberDiff line numberDiff line change
@@ -94,41 +94,13 @@ PrintError(char *msg, ...)
9494
/* after code that pyrex generates */
9595
void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
9696
{
97-
PyObject *py_srcfile = 0;
98-
PyObject *py_funcname = 0;
9997
PyObject *py_globals = 0;
100-
PyObject *empty_tuple = 0;
101-
PyObject *empty_string = 0;
10298
PyCodeObject *py_code = 0;
10399
PyFrameObject *py_frame = 0;
104100

105-
py_srcfile = PyUnicode_DecodeFSDefault(filename);
106-
if (!py_srcfile) goto bad;
107-
py_funcname = PyUnicode_FromString(funcname);
108-
if (!py_funcname) goto bad;
109101
py_globals = PyDict_New();
110102
if (!py_globals) goto bad;
111-
empty_tuple = PyTuple_New(0);
112-
if (!empty_tuple) goto bad;
113-
empty_string = PyBytes_FromString("");
114-
if (!empty_string) goto bad;
115-
py_code = PyCode_New(
116-
0, /*int argcount,*/
117-
0, /*int kwonlyargcount,*/
118-
0, /*int nlocals,*/
119-
0, /*int stacksize,*/
120-
0, /*int flags,*/
121-
empty_string, /*PyObject *code,*/
122-
empty_tuple, /*PyObject *consts,*/
123-
empty_tuple, /*PyObject *names,*/
124-
empty_tuple, /*PyObject *varnames,*/
125-
empty_tuple, /*PyObject *freevars,*/
126-
empty_tuple, /*PyObject *cellvars,*/
127-
py_srcfile, /*PyObject *filename,*/
128-
py_funcname, /*PyObject *name,*/
129-
lineno, /*int firstlineno,*/
130-
empty_string /*PyObject *lnotab*/
131-
);
103+
py_code = PyCode_NewEmpty(filename, funcname, lineno);
132104
if (!py_code) goto bad;
133105
py_frame = PyFrame_New(
134106
PyThreadState_Get(), /*PyThreadState *tstate,*/
@@ -141,10 +113,6 @@ void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
141113
PyTraceBack_Here(py_frame);
142114
bad:
143115
Py_XDECREF(py_globals);
144-
Py_XDECREF(py_srcfile);
145-
Py_XDECREF(py_funcname);
146-
Py_XDECREF(empty_tuple);
147-
Py_XDECREF(empty_string);
148116
Py_XDECREF(py_code);
149117
Py_XDECREF(py_frame);
150118
}

Modules/_testcapimodule.c

+16
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,21 @@ argparsing(PyObject *o, PyObject *args)
14461446
Py_RETURN_NONE;
14471447
}
14481448

1449+
/* To test that the result of PyCode_NewEmpty has the right members. */
1450+
static PyObject *
1451+
code_newempty(PyObject *self, PyObject *args)
1452+
{
1453+
const char *filename;
1454+
const char *funcname;
1455+
int firstlineno;
1456+
1457+
if (!PyArg_ParseTuple(args, "ssi:code_newempty",
1458+
&filename, &funcname, &firstlineno))
1459+
return NULL;
1460+
1461+
return (PyObject *)PyCode_NewEmpty(filename, funcname, firstlineno);
1462+
}
1463+
14491464
static PyMethodDef TestMethods[] = {
14501465
{"raise_exception", raise_exception, METH_VARARGS},
14511466
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
@@ -1498,6 +1513,7 @@ static PyMethodDef TestMethods[] = {
14981513
{"traceback_print", traceback_print, METH_VARARGS},
14991514
{"exception_print", exception_print, METH_VARARGS},
15001515
{"argparsing", argparsing, METH_VARARGS},
1516+
{"code_newempty", code_newempty, METH_VARARGS},
15011517
{NULL, NULL} /* sentinel */
15021518
};
15031519

Modules/pyexpat.c

+1-43
Original file line numberDiff line numberDiff line change
@@ -209,53 +209,11 @@ flag_error(xmlparseobject *self)
209209
static PyCodeObject*
210210
getcode(enum HandlerTypes slot, char* func_name, int lineno)
211211
{
212-
PyObject *code = NULL;
213-
PyObject *name = NULL;
214-
PyObject *nulltuple = NULL;
215-
PyObject *filename = NULL;
216-
217212
if (handler_info[slot].tb_code == NULL) {
218-
code = PyBytes_FromString("");
219-
if (code == NULL)
220-
goto failed;
221-
name = PyUnicode_FromString(func_name);
222-
if (name == NULL)
223-
goto failed;
224-
nulltuple = PyTuple_New(0);
225-
if (nulltuple == NULL)
226-
goto failed;
227-
filename = PyUnicode_DecodeFSDefault(__FILE__);
228213
handler_info[slot].tb_code =
229-
PyCode_New(0, /* argcount */
230-
0, /* kwonlyargcount */
231-
0, /* nlocals */
232-
0, /* stacksize */
233-
0, /* flags */
234-
code, /* code */
235-
nulltuple, /* consts */
236-
nulltuple, /* names */
237-
nulltuple, /* varnames */
238-
#if PYTHON_API_VERSION >= 1010
239-
nulltuple, /* freevars */
240-
nulltuple, /* cellvars */
241-
#endif
242-
filename, /* filename */
243-
name, /* name */
244-
lineno, /* firstlineno */
245-
code /* lnotab */
246-
);
247-
if (handler_info[slot].tb_code == NULL)
248-
goto failed;
249-
Py_DECREF(code);
250-
Py_DECREF(nulltuple);
251-
Py_DECREF(filename);
252-
Py_DECREF(name);
214+
PyCode_NewEmpty(__FILE__, func_name, lineno);
253215
}
254216
return handler_info[slot].tb_code;
255-
failed:
256-
Py_XDECREF(code);
257-
Py_XDECREF(name);
258-
return NULL;
259217
}
260218

261219
#ifdef FIX_TRACE

0 commit comments

Comments
 (0)