[Patches] nice speedup for compile.c

Charles G Waldman cgw@fnal.gov
Thu, 27 Apr 2000 18:29:28 -0500 (CDT)


This implements an idea suggested in one of the /*XXX*/ comments in
compile.c

With this patch in place, the time required to import a 5000-line file
(with lots of constants in it) is reduced from 15 seconds to under 3
seconds on my system.


                   I confirm that, to the best of my knowledge and belief, this
                   contribution is free of any claims of third parties under
                   copyright, patent or other rights or interests ("claims").  To
                   the extent that I have any such claims, I hereby grant to CNRI a
                   nonexclusive, irrevocable, royalty-free, worldwide license to
                   reproduce, distribute, perform and/or display publicly, prepare
                   derivative versions, and otherwise use this contribution as part
                   of the Python software and its related documentation, or any
                   derivative versions thereof, at no cost to CNRI or its licensed
                   users, and to authorize others to do so.

                   I acknowledge that CNRI may, at its sole discretion, decide
                   whether or not to incorporate this contribution in the Python
                   software and its related documentation.  I further grant CNRI
                   permission to use my name and other identifying information
                   provided to CNRI by me for use in connection with the Python
                   software and its related documentation.

Index: Python/compile.c
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Python/compile.c,v
retrieving revision 2.105
diff -c -r2.105 compile.c
*** compile.c	2000/04/13 14:10:44	2.105
--- compile.c	2000/04/27 23:26:20
***************
*** 300,307 ****
  
  struct compiling {
  	PyObject *c_code;		/* string */
! 	PyObject *c_consts;	/* list of objects */
! 	PyObject *c_names;	/* list of strings (names) */
  	PyObject *c_globals;	/* dictionary (value=None) */
  	PyObject *c_locals;	/* dictionary (value=localID) */
  	PyObject *c_varnames;	/* list (inverse of c_locals) */
--- 300,309 ----
  
  struct compiling {
  	PyObject *c_code;		/* string */
! 	PyObject *c_consts;	/* dictionary of objects */
! 	PyObject *c_const_list; /* inverse of c_consts */
! 	PyObject *c_names;	/* dictionary of strings (names) */
! 	PyObject *c_name_list;  /* inverse of c_names */
  	PyObject *c_globals;	/* dictionary (value=None) */
  	PyObject *c_locals;	/* dictionary (value=localID) */
  	PyObject *c_varnames;	/* list (inverse of c_locals) */
***************
*** 403,409 ****
  static void com_addoparg Py_PROTO((struct compiling *, int, int));
  static void com_addfwref Py_PROTO((struct compiling *, int, int *));
  static void com_backpatch Py_PROTO((struct compiling *, int));
! static int com_add Py_PROTO((struct compiling *, PyObject *, PyObject *));
  static int com_addconst Py_PROTO((struct compiling *, PyObject *));
  static int com_addname Py_PROTO((struct compiling *, PyObject *));
  static void com_addopname Py_PROTO((struct compiling *, int, node *));
--- 405,411 ----
  static void com_addoparg Py_PROTO((struct compiling *, int, int));
  static void com_addfwref Py_PROTO((struct compiling *, int, int *));
  static void com_backpatch Py_PROTO((struct compiling *, int));
! static int com_add Py_PROTO((struct compiling *, PyObject *, PyObject *, PyObject *));
  static int com_addconst Py_PROTO((struct compiling *, PyObject *));
  static int com_addname Py_PROTO((struct compiling *, PyObject *));
  static void com_addopname Py_PROTO((struct compiling *, int, node *));
***************
*** 421,442 ****
  	struct compiling *c;
  	char *filename;
  {
  	if ((c->c_code = PyString_FromStringAndSize((char *)NULL,
  						    1000)) == NULL)
! 		goto fail_3;
! 	if ((c->c_consts = PyList_New(0)) == NULL)
! 		goto fail_2;
! 	if ((c->c_names = PyList_New(0)) == NULL)
! 		goto fail_1;
  	if ((c->c_globals = PyDict_New()) == NULL)
! 		goto fail_0;
  	if ((c->c_locals = PyDict_New()) == NULL)
! 		goto fail_00;
  	if ((c->c_varnames = PyList_New(0)) == NULL)
! 		goto fail_000;
  	if ((c->c_lnotab = PyString_FromStringAndSize((char *)NULL,
  						      1000)) == NULL)
! 		goto fail_0000;
  	c->c_nlocals = 0;
  	c->c_argcount = 0;
  	c->c_flags = 0;
--- 423,449 ----
  	struct compiling *c;
  	char *filename;
  {
+ 	memset((void *)c, '\0', sizeof(struct compiling));
  	if ((c->c_code = PyString_FromStringAndSize((char *)NULL,
  						    1000)) == NULL)
! 		goto fail;
! 	if ((c->c_consts = PyDict_New()) == NULL)
! 		goto fail;
! 	if ((c->c_const_list = PyList_New(0)) == NULL)
! 		goto fail;
! 	if ((c->c_names = PyDict_New()) == NULL)
! 		goto fail;
! 	if ((c->c_name_list = PyList_New(0)) == NULL)
! 		goto fail;
  	if ((c->c_globals = PyDict_New()) == NULL)
! 		goto fail;
  	if ((c->c_locals = PyDict_New()) == NULL)
! 		goto fail;
  	if ((c->c_varnames = PyList_New(0)) == NULL)
! 		goto fail;
  	if ((c->c_lnotab = PyString_FromStringAndSize((char *)NULL,
  						      1000)) == NULL)
! 		goto fail;
  	c->c_nlocals = 0;
  	c->c_argcount = 0;
  	c->c_flags = 0;
***************
*** 458,476 ****
  	c-> c_lnotab_next = 0;
  	return 1;
  	
!   fail_0000:
!   	Py_DECREF(c->c_varnames);
!   fail_000:
!   	Py_DECREF(c->c_locals);
!   fail_00:
!   	Py_DECREF(c->c_globals);
!   fail_0:
!   	Py_DECREF(c->c_names);
!   fail_1:
! 	Py_DECREF(c->c_consts);
!   fail_2:
! 	Py_DECREF(c->c_code);
!   fail_3:
   	return 0;
  }
  
--- 465,472 ----
  	c-> c_lnotab_next = 0;
  	return 1;
  	
!   fail:
! 	com_free(c);
   	return 0;
  }
  
***************
*** 480,486 ****
--- 476,484 ----
  {
  	Py_XDECREF(c->c_code);
  	Py_XDECREF(c->c_consts);
+ 	Py_XDECREF(c->c_const_list);
  	Py_XDECREF(c->c_names);
+ 	Py_XDECREF(c->c_name_list);
  	Py_XDECREF(c->c_globals);
  	Py_XDECREF(c->c_locals);
  	Py_XDECREF(c->c_varnames);
***************
*** 665,688 ****
  /* Handle literals and names uniformly */
  
  static int
! com_add(c, list, v)
  	struct compiling *c;
  	PyObject *list;
  	PyObject *v;
  {
! 	int n = PyList_Size(list);
! 	int i;
! 	/* XXX This is quadratic in the number of names per compilation unit.
! 	   XXX Should use a dictionary. */
! 	for (i = n; --i >= 0; ) {
! 		PyObject *w = PyList_GetItem(list, i);
! 		if (v->ob_type == w->ob_type && PyObject_Compare(v, w) == 0)
! 			return i;
  	}
! 	/* Check for error from PyObject_Compare */
! 	if (PyErr_Occurred() || PyList_Append(list, v) != 0)
! 		c->c_errors++;
  	return n;
  }
  
  static int
--- 663,706 ----
  /* Handle literals and names uniformly */
  
  static int
! com_add(c, dict, list, v)
  	struct compiling *c;
+ 	PyObject *dict;
  	PyObject *list;
  	PyObject *v;
  {
! 	PyObject *w, *t=NULL, *np=NULL;
! 	int n;
! 	
! 	t = PyTuple_New(2);
! 	if (t == NULL)
! 	    goto fail;
! 	PyTuple_SetItem(t, 0, v);
! 	Py_INCREF(v);
! 	PyTuple_SetItem(t, 1, (PyObject *)v->ob_type);
! 	Py_INCREF(v->ob_type);
! 	w = PyDict_GetItem(dict, t);
! 	if (PyErr_Occurred()) /* check for error from Py_ObjectCompare */
! 	    goto fail;
! 	if (w){
! 		n = PyInt_AsLong(w);
! 	} else {
! 		n = PyList_Size(list);
! 		if ((np = PyInt_FromLong((long)n)) == NULL)
! 		    goto fail;
! 		if (PyList_Append(list, v) != 0)
! 		    goto fail;
! 		if (PyDict_SetItem(dict, t, np) != 0)
! 		    goto fail;
! 		Py_DECREF(np);
  	}
! 	Py_DECREF(t);
  	return n;
+   fail:
+ 	Py_XDECREF(np);
+ 	Py_XDECREF(t);
+ 	c->c_errors++;
+ 	return 0;
  }
  
  static int
***************
*** 690,696 ****
  	struct compiling *c;
  	PyObject *v;
  {
! 	return com_add(c, c->c_consts, v);
  }
  
  static int
--- 708,714 ----
  	struct compiling *c;
  	PyObject *v;
  {
! 	return com_add(c, c->c_consts, c->c_const_list, v);
  }
  
  static int
***************
*** 698,704 ****
  	struct compiling *c;
  	PyObject *v;
  {
! 	return com_add(c, c->c_names, v);
  }
  
  #ifdef PRIVATE_NAME_MANGLING
--- 716,722 ----
  	struct compiling *c;
  	PyObject *v;
  {
! 	return com_add(c, c->c_names, c->c_name_list, v);
  }
  
  #ifdef PRIVATE_NAME_MANGLING
***************
*** 3373,3379 ****
  #define NEXTOP()	(*next_instr++)
  #define NEXTARG()	(next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
  #define GETITEM(v, i)	(PyList_GetItem((v), (i)))
! #define GETNAMEOBJ(i)	(GETITEM(c->c_names, (i)))
  	
  	PyErr_Fetch(&error_type, &error_value, &error_traceback);
  
--- 3391,3397 ----
  #define NEXTOP()	(*next_instr++)
  #define NEXTARG()	(next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
  #define GETITEM(v, i)	(PyList_GetItem((v), (i)))
! #define GETNAMEOBJ(i)	(GETITEM(c->c_name_list, (i)))
  	
  	PyErr_Fetch(&error_type, &error_value, &error_traceback);
  
***************
*** 3480,3487 ****
  	co = NULL;
  	if (sc.c_errors == 0) {
  		PyObject *consts, *names, *varnames, *filename, *name;
! 		consts = PyList_AsTuple(sc.c_consts);
! 		names = PyList_AsTuple(sc.c_names);
  		varnames = PyList_AsTuple(sc.c_varnames);
  		filename = PyString_InternFromString(sc.c_filename);
  		name = PyString_InternFromString(sc.c_name);
--- 3498,3505 ----
  	co = NULL;
  	if (sc.c_errors == 0) {
  		PyObject *consts, *names, *varnames, *filename, *name;
! 		consts = PyList_AsTuple(sc.c_const_list);
! 		names = PyList_AsTuple(sc.c_name_list);
  		varnames = PyList_AsTuple(sc.c_varnames);
  		filename = PyString_InternFromString(sc.c_filename);
  		name = PyString_InternFromString(sc.c_name);