[Python-checkins] python/dist/src/Objects codeobject.c,1.1.2.1,1.1.2.2
jhylton@users.sourceforge.net
jhylton@users.sourceforge.net
Fri, 23 Aug 2002 11:20:27 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv22074/Objects
Modified Files:
Tag: ast-branch
codeobject.c
Log Message:
Add PyCode_New() and PyCode_Addr2Line().
These used to live in compile.c.
Index: codeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/Attic/codeobject.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -C2 -d -r1.1.2.1 -r1.1.2.2
*** codeobject.c 9 Jul 2002 13:22:00 -0000 1.1.2.1
--- codeobject.c 23 Aug 2002 18:20:24 -0000 1.1.2.2
***************
*** 3,6 ****
--- 3,113 ----
#include "structmember.h"
+ #define NAME_CHARS \
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
+
+ /* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */
+
+ static int
+ all_name_chars(unsigned char *s)
+ {
+ static char ok_name_char[256];
+ static unsigned char *name_chars = (unsigned char *)NAME_CHARS;
+
+ if (ok_name_char[*name_chars] == 0) {
+ unsigned char *p;
+ for (p = name_chars; *p; p++)
+ ok_name_char[*p] = 1;
+ }
+ while (*s) {
+ if (ok_name_char[*s++] == 0)
+ return 0;
+ }
+ return 1;
+ }
+
+ static int
+ intern_strings(PyObject *tuple)
+ {
+ int i;
+
+ for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
+ PyObject *v = PyTuple_GET_ITEM(tuple, i);
+ if (v == NULL || !PyString_Check(v)) {
+ Py_FatalError("non-string found in code slot");
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
+ }
+ return 0;
+ }
+
+ 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)
+ {
+ PyCodeObject *co;
+ int i;
+ /* Check argument types */
+ if (argcount < 0 || nlocals < 0 ||
+ code == NULL ||
+ consts == NULL || !PyTuple_Check(consts) ||
+ names == NULL || !PyTuple_Check(names) ||
+ varnames == NULL || !PyTuple_Check(varnames) ||
+ freevars == NULL || !PyTuple_Check(freevars) ||
+ cellvars == NULL || !PyTuple_Check(cellvars) ||
+ name == NULL || !PyString_Check(name) ||
+ filename == NULL || !PyString_Check(filename) ||
+ lnotab == NULL || !PyString_Check(lnotab) ||
+ !PyObject_CheckReadBuffer(code)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ intern_strings(names);
+ intern_strings(varnames);
+ intern_strings(freevars);
+ intern_strings(cellvars);
+ /* Intern selected string constants */
+ for (i = PyTuple_Size(consts); --i >= 0; ) {
+ PyObject *v = PyTuple_GetItem(consts, i);
+ if (!PyString_Check(v))
+ continue;
+ if (!all_name_chars((unsigned char *)PyString_AS_STRING(v)))
+ continue;
+ PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i));
+ }
+ co = PyObject_NEW(PyCodeObject, &PyCode_Type);
+ if (co != NULL) {
+ co->co_argcount = argcount;
+ co->co_nlocals = nlocals;
+ co->co_stacksize = stacksize;
+ co->co_flags = flags;
+ Py_INCREF(code);
+ co->co_code = code;
+ Py_INCREF(consts);
+ co->co_consts = consts;
+ Py_INCREF(names);
+ co->co_names = names;
+ Py_INCREF(varnames);
+ co->co_varnames = varnames;
+ Py_INCREF(freevars);
+ co->co_freevars = freevars;
+ Py_INCREF(cellvars);
+ co->co_cellvars = cellvars;
+ Py_INCREF(filename);
+ co->co_filename = filename;
+ Py_INCREF(name);
+ co->co_name = name;
+ co->co_firstlineno = firstlineno;
+ Py_INCREF(lnotab);
+ co->co_lnotab = lnotab;
+ }
+ return co;
+ }
+
+
#define OFF(x) offsetof(PyCodeObject, x)
***************
*** 214,215 ****
--- 321,382 ----
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.
+ */
+
+ int
+ PyCode_Addr2Line(PyCodeObject *co, int addrq)
+ {
+ int size = PyString_Size(co->co_lnotab) / 2;
+ unsigned char *p = (unsigned char*)PyString_AsString(co->co_lnotab);
+ int line = co->co_firstlineno;
+ int addr = 0;
+ while (--size >= 0) {
+ addr += *p++;
+ if (addr > addrq)
+ break;
+ line += *p++;
+ }
+ return line;
+ }