[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;
+ }