diff -rcN Python-1.5.1/Include/intobject.h Python-1.5.1.new/Include/intobject.h
*** Python-1.5.1/Include/intobject.h	Fri Aug  1 22:41:13 1997
--- Python-1.5.1.new/Include/intobject.h	Sun Jun 28 07:14:09 1998
***************
*** 85,90 ****
--- 85,106 ----
  /* Macro, trading safety for speed */
  #define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival)
  
+ /* make small int cache visible for ceval.c */
+ #ifndef NSMALLPOSINTS
+ #define NSMALLPOSINTS		100
+ #endif
+ #ifndef NSMALLNEGINTS
+ #define NSMALLNEGINTS		1
+ #endif
+ #if NSMALLNEGINTS + NSMALLPOSINTS > 0
+ /* References to small integers are saved in this array so that they
+    can be shared.
+    The integers that are saved are those in the range
+    -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
+ */
+ extern PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
+ #endif
+ 
  #ifdef __cplusplus
  }
  #endif
diff -rcN Python-1.5.1/Include/opcode.h Python-1.5.1.new/Include/opcode.h
*** Python-1.5.1/Include/opcode.h	Thu May  8 20:39:04 1997
--- Python-1.5.1.new/Include/opcode.h	Thu Jul  2 00:06:02 1998
***************
*** 42,47 ****
--- 42,48 ----
  #define ROT_TWO		2
  #define ROT_THREE	3
  #define DUP_TOP		4
+ #define LOAD_NONE	5
  
  #define UNARY_POSITIVE	10
  #define UNARY_NEGATIVE	11
***************
*** 127,132 ****
--- 128,136 ----
  
  #define SET_FUNC_ARGS	117	/* Argcount */
  
+ #define LOAD_ATTR_FAST	118	/* Load local and deference attribute in one opcode */
+ #define STORE_ATTR_FAST	119	/* Load local and deference attribute in one opcode */
+ 
  #define SETUP_LOOP	120	/* Target address (absolute) */
  #define SETUP_EXCEPT	121	/* "" */
  #define SETUP_FINALLY	122	/* "" */
***************
*** 146,151 ****
--- 150,160 ----
  #define CALL_FUNCTION	131	/* #args + (#kwargs<<8) */
  #define MAKE_FUNCTION	132	/* #defaults */
  #define BUILD_SLICE 	133	/* Number of items */
+ 
+ #define LOAD_TWO_FAST	134	/* == LOAD_FAST + LOAD_FAST */
+ #define STORE_TWO_FAST	135	/* == STORE_FAST + STORE_FAST */
+ 
+ #define LOADI		136	/* load a number from the small int cache */
  
  /* Comparison operator codes (argument to COMPARE_OP) */
  enum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD};
diff -rcN Python-1.5.1/Lib/dis.py Python-1.5.1.new/Lib/dis.py
*** Python-1.5.1/Lib/dis.py	Tue Nov 18 10:47:55 1997
--- Python-1.5.1.new/Lib/dis.py	Thu Jun 25 22:01:18 1998
***************
*** 1,8 ****
  """Disassembler of Python byte code into mnemonics."""
  
! import sys
! import string
! import types
  
  def dis(x=None):
  	"""Disassemble classes, methods, functions, or code.
--- 1,8 ----
  """Disassembler of Python byte code into mnemonics."""
  
! import sys, string, types
! 
! from opcodes import *
  
  def dis(x=None):
  	"""Disassemble classes, methods, functions, or code.
***************
*** 21,27 ****
  		for name, x1 in items:
  			if type(x1) in (types.MethodType,
  					types.FunctionType,
! 					types.CodeType):
  				print "Disassembly of %s:" % name
  				try:
  					dis(x1)
--- 21,28 ----
  		for name, x1 in items:
  			if type(x1) in (types.MethodType,
  					types.FunctionType,
! 					types.CodeType,
! 					types.ClassType):
  				print "Disassembly of %s:" % name
  				try:
  					dis(x1)
***************
*** 35,40 ****
--- 36,43 ----
  			x = x.func_code
  		if hasattr(x, 'co_code'):
  			disassemble(x)
+ 		elif type(x) == type(""):
+ 			disassemble_string(x)
  		else:
  			raise TypeError, \
  			      "don't know how to disassemble %s objects" % \
***************
*** 59,65 ****
  	while i < n:
  		c = code[i]
  		op = ord(c)
! 		if op == SET_LINENO and i > 0: print # Extra blank line
  		if i == lasti: print '-->',
  		else: print '   ',
  		if i in labels: print '>>',
--- 62,69 ----
  	while i < n:
  		c = code[i]
  		op = ord(c)
! 		if op == opmap['SET_LINENO'] and i > 0:
! 		    print # Extra blank line
  		if i == lasti: print '-->',
  		else: print '   ',
  		if i in labels: print '>>',
***************
*** 79,84 ****
--- 83,154 ----
  				print '(to ' + `i + oparg` + ')',
  			elif op in haslocal:
  				print '(' + co.co_varnames[oparg] + ')',
+ 			elif op in haslocal2:
+ 				print '(%s, %s)' % \
+ 				      (co.co_varnames[ord(code[i-2])],
+ 				       co.co_varnames[ord(code[i-1])]),
+ 			elif op in haslocalandname:
+ 				print '(%s, %s)' % \
+ 				      (co.co_varnames[ord(code[i-2])],
+ 				       co.co_names[ord(code[i-1])]),
+ 			elif op in hascompare:
+ 				print '(' + cmp_op[oparg] + ')',
+ 		print
+ 
+ def disassemble_string(code, lasti=-1, varnames=None, names=None,
+ 		       constants=None):
+ 	labels = findlabels(code)
+ 	n = len(code)
+ 	i = 0
+ 	while i < n:
+ 		c = code[i]
+ 		op = ord(c)
+ 		if op == opmap['SET_LINENO'] and i > 0:
+ 		    print # Extra blank line
+ 		if i == lasti: print '-->',
+ 		else: print '   ',
+ 		if i in labels: print '>>',
+ 		else: print '  ',
+ 		print string.rjust(`i`, 4),
+ 		print string.ljust(opname[op], 15),
+ 		i = i+1
+ 		if op >= HAVE_ARGUMENT:
+ 			oparg = ord(code[i]) + ord(code[i+1])*256
+ 			i = i+2
+ 			print string.rjust(`oparg`, 5),
+ 			if op in hasconst:
+ 			    if constants:
+ 				print '(' + `constants[oparg]` + ')',
+ 			    else:
+ 				print '(%d)'%oparg,
+ 			elif op in hasname:
+ 			    if names is not None:
+ 				print '(' + names[oparg] + ')',
+ 			    else:
+ 				print '(%d)'%oparg,
+ 			elif op in hasjrel:
+ 				print '(to ' + `i + oparg` + ')',
+ 			elif op in haslocal:
+ 			    if varnames:
+ 				print '(' + varnames[oparg] + ')',
+ 			    else:
+ 				print '(%d)' % oparg,
+ 			elif op in haslocal2:
+ 			    if varnames:
+ 				print '(%s, %s)' % \
+ 				      (varnames[ord(code[i-2])],
+ 				       varnames[ord(code[i-1])]),
+ 			    else:
+ 				print '(%d,%d)' % \
+ 				      (ord(code[i-2]),ord(code[i-1])),
+ 			elif op in haslocalandname:
+ 			    if varnames and names:
+ 				print '(%s, %s)' % \
+ 				      (varnames[ord(code[i-2])],
+ 				       names[ord(code[i-1])]),
+ 			    else:
+ 				print '(%d,%d)' % \
+ 				      (ord(code[i-2]),ord(code[i-1])),
  			elif op in hascompare:
  				print '(' + cmp_op[oparg] + ')',
  		print
***************
*** 111,258 ****
  					labels.append(label)
  	return labels
  
! cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
!         'is not', 'exception match', 'BAD')
! 
! hasconst = []
! hasname = []
! hasjrel = []
! hasjabs = []
! haslocal = []
! hascompare = []
! 
! opname = [''] * 256
! for op in range(256): opname[op] = '<' + `op` + '>'
! 
! def def_op(name, op):
! 	opname[op] = name
! 
! def name_op(name, op):
! 	opname[op] = name
! 	hasname.append(op)
! 
! def jrel_op(name, op):
! 	opname[op] = name
! 	hasjrel.append(op)
! 
! def jabs_op(name, op):
! 	opname[op] = name
! 	hasjabs.append(op)
! 
! # Instruction opcodes for compiled code
! 
! def_op('STOP_CODE', 0)
! def_op('POP_TOP', 1)
! def_op('ROT_TWO', 2)
! def_op('ROT_THREE', 3)
! def_op('DUP_TOP', 4)
! 
! def_op('UNARY_POSITIVE', 10)
! def_op('UNARY_NEGATIVE', 11)
! def_op('UNARY_NOT', 12)
! def_op('UNARY_CONVERT', 13)
! 
! def_op('UNARY_INVERT', 15)
! 
! def_op('BINARY_POWER', 19)
! 
! def_op('BINARY_MULTIPLY', 20)
! def_op('BINARY_DIVIDE', 21)
! def_op('BINARY_MODULO', 22)
! def_op('BINARY_ADD', 23)
! def_op('BINARY_SUBTRACT', 24)
! def_op('BINARY_SUBSCR', 25)
! 
! def_op('SLICE+0', 30)
! def_op('SLICE+1', 31)
! def_op('SLICE+2', 32)
! def_op('SLICE+3', 33)
! 
! def_op('STORE_SLICE+0', 40)
! def_op('STORE_SLICE+1', 41)
! def_op('STORE_SLICE+2', 42)
! def_op('STORE_SLICE+3', 43)
! 
! def_op('DELETE_SLICE+0', 50)
! def_op('DELETE_SLICE+1', 51)
! def_op('DELETE_SLICE+2', 52)
! def_op('DELETE_SLICE+3', 53)
! 
! def_op('STORE_SUBSCR', 60)
! def_op('DELETE_SUBSCR', 61)
! 
! def_op('BINARY_LSHIFT', 62)
! def_op('BINARY_RSHIFT', 63)
! def_op('BINARY_AND', 64)
! def_op('BINARY_XOR', 65)
! def_op('BINARY_OR', 66)
! 
! def_op('PRINT_EXPR', 70)
! def_op('PRINT_ITEM', 71)
! def_op('PRINT_NEWLINE', 72)
! 
! def_op('BREAK_LOOP', 80)
! 
! def_op('LOAD_LOCALS', 82)
! def_op('RETURN_VALUE', 83)
! 
! def_op('EXEC_STMT', 85)
! 
! def_op('POP_BLOCK', 87)
! def_op('END_FINALLY', 88)
! def_op('BUILD_CLASS', 89)
! 
! HAVE_ARGUMENT = 90		# Opcodes from here have an argument: 
! 
! name_op('STORE_NAME', 90)	# Index in name list 
! name_op('DELETE_NAME', 91)	# "" 
! def_op('UNPACK_TUPLE', 92)	# Number of tuple items 
! def_op('UNPACK_LIST', 93)	# Number of list items 
! def_op('UNPACK_ARG', 94)	# Number of arguments expected
! name_op('STORE_ATTR', 95)	# Index in name list 
! name_op('DELETE_ATTR', 96)	# ""
! name_op('STORE_GLOBAL', 97)	# ""
! name_op('DELETE_GLOBAL', 98)	# ""
! name_op('UNPACK_VARARG', 99)	# Minimal number of arguments
! 
! def_op('LOAD_CONST', 100)	# Index in const list 
! hasconst.append(100)
! name_op('LOAD_NAME', 101)	# Index in name list 
! def_op('BUILD_TUPLE', 102)	# Number of tuple items 
! def_op('BUILD_LIST', 103)	# Number of list items 
! def_op('BUILD_MAP', 104)	# Always zero for now 
! name_op('LOAD_ATTR', 105)	# Index in name list 
! def_op('COMPARE_OP', 106)	# Comparison operator 
! hascompare.append(106)
! name_op('IMPORT_NAME', 107)	# Index in name list 
! name_op('IMPORT_FROM', 108)	# Index in name list 
! 
! jrel_op('JUMP_FORWARD', 110)	# Number of bytes to skip 
! jrel_op('JUMP_IF_FALSE', 111)	# "" 
! jrel_op('JUMP_IF_TRUE', 112)	# "" 
! jabs_op('JUMP_ABSOLUTE', 113)	# Target byte offset from beginning of code 
! jrel_op('FOR_LOOP', 114)	# Number of bytes to skip 
! 
! name_op('LOAD_LOCAL', 115)	# Index in name list
! name_op('LOAD_GLOBAL', 116)	# Index in name list
! 
! def_op('SET_FUNC_ARGS', 117)	# Argcount
! 
! jrel_op('SETUP_LOOP', 120)	# Distance to target address
! jrel_op('SETUP_EXCEPT', 121)	# ""
! jrel_op('SETUP_FINALLY', 122)	# ""
! 
! def_op('LOAD_FAST', 124)	# Local variable number
! haslocal.append(124)
! def_op('STORE_FAST', 125)	# Local variable number
! haslocal.append(125)
! def_op('DELETE_FAST', 126)	# Local variable number
! haslocal.append(126)
! 
! def_op('SET_LINENO', 127)	# Current line number
! SET_LINENO = 127
! 
! def_op('RAISE_VARARGS', 130)
! def_op('CALL_FUNCTION', 131)
! def_op('MAKE_FUNCTION', 132)
! def_op('BUILD_SLICE', 133)
--- 181,232 ----
  					labels.append(label)
  	return labels
  
! def dxppcode(opcode):
!     import sys
!     try:
! 	profile = sys.getdxp()
!     except AttributeError:
! 	print "Python not enabled for profiling..."
! 	return
! 
!     if type(profile[0]) == type(0):
! 	print "%s: %d" % (opname[opcode], profile[opcode])
!     else:
! 	print "%s: %d" % (opname[opcode], profile[256][opcode])
! 	dxpprint_simple(profile[opcode], "  ", n=256)
! 
! def dxpprint(n=10):
!     import sys
!     try:
! 	profile = sys.getdxp()
!     except AttributeError:
! 	print "Python not enabled for profiling..."
! 	return
! 
!     if type(profile[0]) == type(0):
! 	dxpprint_simple(profile, n=n)
!     else:
! 	dxpprint_matrix(profile, n=n)
! 
! def dxpprint_simple(profile, indent="", n=10):
!     items = map(None, profile[1:], range(len(profile)-1))
!     items.sort()
!     items.reverse()
!     for item in items[0:n]:
! 	if item[0] != 0:
! 	    print "%s%s: %d" % (indent, opname[item[1]], item[0])
! 
! def sum(l):
!     return reduce(lambda x,y:x+y, l, 0)
! 
! def dxpprint_matrix(profile, n=10):
!     items = profile[1:-1]
!     for i in range(len(items)):
! 	items[i] = (sum(items[i]), items[i], i)
!     items.sort()
!     items.reverse()
!     for item in items[0:n]:
! 	if item[0] != 0:
! 	    print ""
! 	    print "%s (%d):" % (opname[item[2]], item[0])
! 	    dxpprint_simple(item[1], "  ", n)
diff -rcN Python-1.5.1/Lib/opcodes.py Python-1.5.1.new/Lib/opcodes.py
*** Python-1.5.1/Lib/opcodes.py	Wed Dec 31 19:00:00 1969
--- Python-1.5.1.new/Lib/opcodes.py	Wed Jul  1 16:05:51 1998
***************
*** 0 ****
--- 1,171 ----
+ 
+ """opcodes module - shared between dis and optimize"""
+ 
+ # range of small_int cache - values must match with those used by intobject.c
+ NSMALLPOSINTS = 100
+ NSMALLNEGINTS = 1
+ 
+ opname = [''] * 256
+ for op in range(256): opname[op] = '<' + `op` + '>'
+ opmap = {}
+ 
+ cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
+         'is not', 'exception match', 'BAD')
+ 
+ hasconst = []
+ hasname = []
+ hasjrel = []
+ hasjabs = []
+ haslocal = []
+ haslocal2 = []
+ haslocalandname = []
+ hascompare = []
+ 
+ def def_op(name, op):
+     global opname, opmap
+     opname[op] = name
+     opmap[name] = op
+ 
+ def name_op(name, op):
+     global hasname
+     def_op(name, op)
+     hasname.append(op)
+ 
+ def jrel_op(name, op):
+     global hasjrel
+     def_op(name, op)
+     hasjrel.append(op)
+ 
+ def jabs_op(name, op):
+     global  hasjabs
+     def_op(name, op)
+     hasjabs.append(op)
+ 
+ def_op('STOP_CODE', 0)
+ def_op('POP_TOP', 1)
+ def_op('ROT_TWO', 2)
+ def_op('ROT_THREE', 3)
+ def_op('DUP_TOP', 4)
+ def_op('LOAD_NONE', 5)
+ 
+ def_op('UNARY_POSITIVE', 10)
+ def_op('UNARY_NEGATIVE', 11)
+ def_op('UNARY_NOT', 12)
+ def_op('UNARY_CONVERT', 13)
+ 
+ def_op('UNARY_INVERT', 15)
+ 
+ def_op('BINARY_POWER', 19)
+ 
+ def_op('BINARY_MULTIPLY', 20)
+ def_op('BINARY_DIVIDE', 21)
+ def_op('BINARY_MODULO', 22)
+ def_op('BINARY_ADD', 23)
+ def_op('BINARY_SUBTRACT', 24)
+ def_op('BINARY_SUBSCR', 25)
+ 
+ def_op('SLICE+0', 30)
+ def_op('SLICE+1', 31)
+ def_op('SLICE+2', 32)
+ def_op('SLICE+3', 33)
+ 
+ def_op('STORE_SLICE+0', 40)
+ def_op('STORE_SLICE+1', 41)
+ def_op('STORE_SLICE+2', 42)
+ def_op('STORE_SLICE+3', 43)
+ 
+ def_op('DELETE_SLICE+0', 50)
+ def_op('DELETE_SLICE+1', 51)
+ def_op('DELETE_SLICE+2', 52)
+ def_op('DELETE_SLICE+3', 53)
+ 
+ def_op('STORE_SUBSCR', 60)
+ def_op('DELETE_SUBSCR', 61)
+ 
+ def_op('BINARY_LSHIFT', 62)
+ def_op('BINARY_RSHIFT', 63)
+ def_op('BINARY_AND', 64)
+ def_op('BINARY_XOR', 65)
+ def_op('BINARY_OR', 66)
+ 
+ def_op('PRINT_EXPR', 70)
+ def_op('PRINT_ITEM', 71)
+ def_op('PRINT_NEWLINE', 72)
+ 
+ def_op('BREAK_LOOP', 80)
+ 
+ def_op('LOAD_LOCALS', 82)
+ def_op('RETURN_VALUE', 83)
+ 
+ def_op('EXEC_STMT', 85)
+ 
+ def_op('POP_BLOCK', 87)
+ def_op('END_FINALLY', 88)
+ def_op('BUILD_CLASS', 89)
+ 
+ HAVE_ARGUMENT = 90		# Opcodes from here have an argument: 
+ 
+ name_op('STORE_NAME', 90)	# Index in name list 
+ name_op('DELETE_NAME', 91)	# "" 
+ def_op('UNPACK_TUPLE', 92)	# Number of tuple items 
+ def_op('UNPACK_LIST', 93)	# Number of list items 
+ def_op('UNPACK_ARG', 94)	# Number of arguments expected
+ name_op('STORE_ATTR', 95)	# Index in name list 
+ name_op('DELETE_ATTR', 96)	# ""
+ name_op('STORE_GLOBAL', 97)	# ""
+ name_op('DELETE_GLOBAL', 98)	# ""
+ name_op('UNPACK_VARARG', 99)	# Minimal number of arguments
+ 
+ def_op('LOAD_CONST', 100)	# Index in const list 
+ hasconst.append(100)
+ name_op('LOAD_NAME', 101)	# Index in name list 
+ def_op('BUILD_TUPLE', 102)	# Number of tuple items 
+ def_op('BUILD_LIST', 103)	# Number of list items 
+ def_op('BUILD_MAP', 104)	# Always zero for now 
+ name_op('LOAD_ATTR', 105)	# Index in name list 
+ def_op('COMPARE_OP', 106)	# Comparison operator 
+ hascompare.append(106)
+ name_op('IMPORT_NAME', 107)	# Index in name list 
+ name_op('IMPORT_FROM', 108)	# Index in name list 
+ 
+ jrel_op('JUMP_FORWARD', 110)	# Number of bytes to skip 
+ jrel_op('JUMP_IF_FALSE', 111)	# "" 
+ jrel_op('JUMP_IF_TRUE', 112)	# "" 
+ jabs_op('JUMP_ABSOLUTE', 113)	# Target byte offset from beginning of code 
+ jrel_op('FOR_LOOP', 114)	# Number of bytes to skip 
+ 
+ name_op('LOAD_LOCAL', 115)	# Index in name list
+ name_op('LOAD_GLOBAL', 116)	# Index in name list
+ 
+ def_op('SET_FUNC_ARGS', 117)	# Argcount
+ def_op('LOAD_ATTR_FAST', 118)
+ haslocalandname.append(118)
+ def_op('STORE_ATTR_FAST', 119)
+ haslocalandname.append(119)
+ 
+ jrel_op('SETUP_LOOP', 120)	# Distance to target address
+ jrel_op('SETUP_EXCEPT', 121)	# ""
+ jrel_op('SETUP_FINALLY', 122)	# ""
+ 
+ def_op('LOAD_FAST', 124)	# Local variable number
+ haslocal.append(124)
+ def_op('STORE_FAST', 125)	# Local variable number
+ haslocal.append(125)
+ def_op('DELETE_FAST', 126)	# Local variable number
+ haslocal.append(126)
+ 
+ def_op('SET_LINENO', 127)	# Current line number
+ SET_LINENO = 127
+ 
+ def_op('RAISE_VARARGS', 130)
+ def_op('CALL_FUNCTION', 131)
+ def_op('MAKE_FUNCTION', 132)
+ def_op('BUILD_SLICE', 133)
+ 
+ def_op('LOAD_TWO_FAST', 134)	# two local arg indexes
+ haslocal2.append(134)
+ def_op('STORE_TWO_FAST', 135)	# two local arg indexes
+ haslocal2.append(135)
+ def_op('LOADI', 136)
+ 
+ del def_op, name_op, jrel_op, jabs_op
diff -rcN Python-1.5.1/Lib/optimize.py Python-1.5.1.new/Lib/optimize.py
*** Python-1.5.1/Lib/optimize.py	Wed Dec 31 19:00:00 1969
--- Python-1.5.1.new/Lib/optimize.py	Wed Jul  1 16:55:22 1998
***************
*** 0 ****
--- 1,673 ----
+ 
+ 
+ from opcodes import *
+ 
+ # try not to import other Python modules because while this module is
+ # being imported its optimizations are not applied
+ # the opcode module imported above is not a big deal since it's only
+ # used here and by the dis module
+ import posix, strop
+ 
+ # varying stages of optimization - which is called is determined
+ # later by the value of the OPTLEVEL environment variable
+ def optimize0(code, vars=None, names=None, consts=None):
+     return code
+ 
+ def optimize1(code, vars=None, names=None, consts=None):
+     lsc = LoadStoreCompressor(code, vars, names, consts)
+     return lsc.code()
+     
+ def optimize2(code, vars=None, names=None, consts=None):
+     lsc = LoadStoreCompressor(code, vars, names, consts)
+     sle = StoreLoadEliminator(lsc)
+     return sle.code()
+ 
+ def optimize3(code, vars=None, names=None, consts=None):
+     lsc = LoadStoreCompressor(code, vars, names, consts)
+     sle = StoreLoadEliminator(lsc)
+     lnr = LineNumberRemover(sle)
+     cpe = ConstPopEliminator(lnr)
+     return cpe.code()
+ 
+ def optimize4(code, vars=None, names=None, consts=None):
+     lsc = LoadStoreCompressor(code, vars, names, consts)
+     sle = StoreLoadEliminator(lsc)
+     lnr = LineNumberRemover(sle)
+     cpe = ConstPopEliminator(lnr)
+     jne1 = JumpNextEliminator(cpe)
+     jpo = JumpOptimizer(jne1)
+     return jpo.code()
+ 
+ def optimize5(code, vars=None, names=None, consts=None):
+     tra = TupleRearranger(code, vars, names, consts)
+     lsc = LoadStoreCompressor(tra, vars, names, consts)
+     sle = StoreLoadEliminator(lsc, vars, names, consts)
+     lnr = LineNumberRemover(sle, vars, names, consts)
+     cee = ConstantExpressionEvaluator(lnr, vars, names, consts)
+     cpe = ConstPopEliminator(cee, vars, names, consts)
+     jne1 = JumpNextEliminator(cpe, vars, names, consts)
+     jpo = JumpOptimizer(jne1, vars, names, consts)
+     csc = ConstantShortcut(jpo, vars, names, consts)
+     mle = MultiLoadEliminator(csc, vars, names, consts)
+     dcr1 = DeadCodeRemover(mle, vars, names, consts)
+     # convert back to string form to force the code to be re-blocked
+     dcr2 = DeadCodeRemover(dcr1.code(), vars, names, consts)
+     jne2 = JumpNextEliminator(dcr2, vars, names, consts)
+     return jne2.code()
+ 
+ class OptimizeFilter:
+     """Base peephole optimizer class for Python byte code.
+ 
+ Instances of OptimizeFilter subclasses are chained together in a
+ pipeline, each one responsible for a single optimization."""
+ 
+     def __init__(self, code, varnames=None, names=None, constants=None):
+ 	"""input can be a list as emitted by code_to_blocks or another
+ OptimizeFilter instance. varnames and constants args are just placeholders
+ for the future."""
+ 	self.varnames = varnames
+ 	self.names = names
+ 	self.constants = constants
+ 	if type(code) == type(""):
+ 	    self.input = self.blocks(code)
+ 	else:
+ 	    self.input = code
+ 
+ 	# if varnames or constants were not passed in,
+ 	# try and get them from the input
+ 	if varnames is None:
+ 	    try:
+ 		self.varnames = self.input.varnames
+ 	    except AttributeError:
+ 		pass
+ 	if names is None:
+ 	    try:
+ 		self.names = self.input.names
+ 	    except AttributeError:
+ 		pass
+ 	if constants is None:
+ 	    try:
+ 		self.constants = self.input.constants
+ 	    except AttributeError:
+ 		pass
+ 
+ 	self.output = None
+ 
+     def optimize(self):
+ 	"""Optimize each block in the input blocks."""
+ 	blocks = self.input
+ 	self.output = [None]*len(blocks)
+ 	for i in range(len(blocks)):
+ 	    self.output[i] = self.optimize_block(blocks[i])
+ 
+     def optimize_block(self, block):
+ 	# noop - subclasses will override this
+ 	return block
+ 
+     def reset(self):
+ 	self.output = None
+ 	try:
+ 	    self.input.reset()
+ 	except AttributeError:
+ 	    # will happen if the input is a list
+ 	    pass
+ 
+     def blocks(self,code):
+ 	"""Convert code string to block form."""
+ 	blocks = []
+ 	labels = findlabels(code)
+ 	n = len(code)
+ 	i = 0
+ 	while i < n:
+ 	    if i in labels: blocks.append([])
+ 	    c = code[i]
+ 	    op = ord(c)
+ 	    i = i + 1
+ 	    if op >= HAVE_ARGUMENT:
+ 		oparg = (ord(code[i]), ord(code[i+1]))
+ 		argval = oparg[0]+(oparg[1]<<8)
+ 		i = i + 2
+ 		if is_abs_jump(op):
+ 		    blocks[-1].append((op, (labels.index(argval), 0)))
+ 		elif is_jump(op):
+ 		    blocks[-1].append((op, (labels.index(i+argval), 0)))
+ 		else:
+ 		    blocks[-1].append((op, oparg))
+ 	    else:
+ 		blocks[-1].append((op,))
+ 	return blocks
+ 
+     def code(self):
+ 	"""Convert the block form of the code back to a string."""
+ 	if self.output is None: self.optimize()
+ 	blocklengths = []
+ 	for block in self.output:
+ 	    blocklengths.append(blocklength(block))
+ 
+ 	codelist = []
+ 	i = 0
+ 	for block in self.output:
+ 	    for inst in block:
+ 		op = chr(inst[0])
+ 		if is_abs_jump(inst[0]):
+ 		    i = i + 3
+ 		    oparg = inst[1]
+ 		    blockaddr = oparg[0]+(oparg[1]<<8)
+ 		    val = sum(blocklengths[:blockaddr])
+ 		    codelist.append("%s%s%s" %
+ 				    (op,chr(val&0xff),chr(val>>8)))
+ 		elif is_jump(inst[0]):
+ 		    i = i + 3
+ 		    oparg = inst[1]
+ 		    blockaddr = oparg[0]+(oparg[1]<<8)
+ 		    val = sum(blocklengths[:blockaddr])-i
+ 		    codelist.append("%s%s%s" %
+ 				    (op,chr(val&0xff),chr(val>>8)))
+ 		elif len(inst) == 2:
+ 		    i = i + 3
+ 		    oparg = inst[1]
+ 		    codelist.append("%s%s%s" %
+ 				    (op,chr(oparg[0]),chr(oparg[1])))
+ 		else:
+ 		    i = i + 1
+ 		    codelist.append(op)
+ 
+ 	return strop.join(codelist, "")
+ 
+     ## bunch of list-like methods ...
+ 
+     def __getattr__(self, name):
+ 	if self.output is None: self.optimize()
+ 	return getattr(self.output, name)
+ 
+     def __repr__(self):
+ 	if self.output is None: self.optimize()
+ 	return repr(self.output)
+ 
+     def __cmp__(self, list):
+ 	if self.output is None: self.optimize()
+ 	if type(list) == type(self.output):
+ 	    return cmp(self.output, list)
+ 	else:
+ 	    return cmp(self.output, list.output)
+ 
+     def __len__(self):
+ 	if self.output is None: self.optimize()
+ 	return len(self.output)
+ 
+     def __getitem__(self, i):
+ 	if self.output is None: self.optimize()
+ 	return self.output[i]
+ 
+     def __setitem__(self, i, item):
+ 	if self.output is None: self.optimize()
+ 	self.output[i] = item
+ 
+     def __delitem__(self, i):
+ 	if self.output is None: self.optimize()
+ 	del self.output[i]
+ 
+     def __getslice__(self, i, j):
+ 	if self.output is None: self.optimize()
+ 	return self.__class__(self.output[i:j])
+ 
+     def __setslice__(self, i, j, list):
+ 	if self.output is None: self.optimize()
+ 	if type(list) == type(self.output):
+ 	    self.output[i:j] = list
+ 	else:
+ 	    self.output[i:j] = list.output
+ 
+     def __delslice__(self, i, j):
+ 	if self.output is None: self.optimize()
+ 	del self.output[i:j]
+ 
+     def append(self, item):
+ 	if self.output is None: self.optimize()
+ 	self.output.append(item)
+ 
+     def insert(self, i, item):
+ 	if self.output is None: self.optimize()
+ 	self.output.insert(i, item)
+ 
+     def remove(self, item):
+ 	if self.output is None: self.optimize()
+ 	self.output.remove(item)
+ 
+ class DeadCodeRemover(OptimizeFilter):
+     """Removes all code in a block that follows an unconditional transfer"""
+     counter = 0
+     def optimize_block(self, block):
+ 	block = block[:]		# copy
+ 	for i in range(len(block)-1):
+ 	    if is_unconditional_transfer(block[i][0]):
+ 		block = block[:i+1]
+ 		self.__class__.counter = self.__class__.counter+1
+ 		break
+ 	return block
+ 	
+ class LineNumberRemover(OptimizeFilter):
+     """Removes all SET_LINENO instructions"""
+     counter = 0
+     def optimize_block(self, block):
+ 	block = block[:]
+ 	i = 0
+ 	while i < len(block):
+ 	    if block[i][0] == opmap['SET_LINENO']:
+ 		self.__class__.counter = self.__class__.counter+1
+ 		del block[i]
+ 	    else:
+ 		i = i + 1
+ 	return block
+ 	
+ class LoadStoreCompressor(OptimizeFilter):
+     """Combines pairs of LOAD_FAST/STORE_FAST into LOAD_TWO_FAST/STORE_TWO_FAST"""
+     counter = 0
+     def optimize_block(self, block):
+ 	newblock = block[:]
+ 	i = 0
+ 	while i < len(newblock)-1:
+ 	    if (newblock[i][0] == opmap['LOAD_FAST'] and
+ 		newblock[i+1][0] == opmap['LOAD_FAST'] and
+ 		(newblock[i][1][1] == 0 == newblock[i+1][1][1])):
+ 		pass
+ 		newblock[i] = (opmap['LOAD_TWO_FAST'],
+ 			       (newblock[i][1][0],newblock[i+1][1][0]))
+ 		self.__class__.counter = self.__class__.counter+1
+ 		del newblock[i+1]
+ 	    elif (newblock[i][0] == opmap['STORE_FAST'] and
+ 		  newblock[i+1][0] == opmap['STORE_FAST'] and
+ 		  (newblock[i][1][1] == 0 == newblock[i+1][1][1])):
+ 		pass
+ 		newblock[i] = (opmap['STORE_TWO_FAST'],
+ 			       (newblock[i][1][0],newblock[i+1][1][0]))
+ 		self.__class__.counter = self.__class__.counter+1
+ 		del newblock[i+1]
+ 	    elif (newblock[i][0] == opmap['LOAD_FAST'] and
+ 		  newblock[i+1][0] == opmap['LOAD_ATTR'] and
+ 		(newblock[i][1][1] == 0 == newblock[i+1][1][1])):
+ 		newblock[i] = (opmap['LOAD_ATTR_FAST'],
+ 			       (newblock[i][1][0],newblock[i+1][1][0]))
+ 		self.__class__.counter = self.__class__.counter+1
+ 		del newblock[i+1]
+ 	    elif (newblock[i][0] == opmap['LOAD_FAST'] and
+ 		  newblock[i+1][0] == opmap['STORE_ATTR'] and
+ 		(newblock[i][1][1] == 0 == newblock[i+1][1][1])):
+ 		newblock[i] = (opmap['STORE_ATTR_FAST'],
+ 			       (newblock[i][1][0],newblock[i+1][1][0]))
+ 		self.__class__.counter = self.__class__.counter+1
+ 		del newblock[i+1]
+ 	    i = i + 1
+ 	return newblock
+ 
+ class MultiLoadEliminator(OptimizeFilter):
+     """Converts n LOADs of the same item to one load and n-1 DUP_TOPs"""
+     counter = 0
+     def optimize_block(self,block):
+ 	block = block[:]
+ 	i = 0
+ 	# "slow" compared to LOADI and LOAD_NONE
+ 	slow_loadops = (opmap['LOAD_FAST'], opmap['LOAD_CONST'],
+ 			opmap['LOAD_GLOBAL'], opmap['LOAD_NAME'])
+ 	while i < len(block)-1:
+ 	    op = block[i][0]
+ 	    if op in slow_loadops:
+ 		j = i + 1
+ 		while j < len(block):
+ 		    if block[j] == block[i]:
+ 			self.__class__.counter = self.__class__.counter + 1
+ 			j = j + 1
+ 		    else:
+ 			break
+ 		if j > i+1:
+ 		    block[i+1:j] = [(opmap['DUP_TOP'],)]*(j-(i+1))
+ 	    i = i + 1
+ 	return block
+ 
+ class StoreLoadEliminator(OptimizeFilter):
+     """Converts a STORE followed by a LOAD of the same item to a DUP_TOP/STORE"""
+     counter = 0
+     def optimize_block(self,block):
+ 	block = block[:]
+ 	i = 0
+ 	for i in range(len(block)-1):
+ 	    op1 = block[i][0]
+ 	    op2 = block[i+1][0]
+ 	    if (op1 == opmap['STORE_FAST'] and op2 == opmap['LOAD_FAST'] or
+ 		op1 == opmap['STORE_GLOBAL'] and op2 == opmap['LOAD_GLOBAL'] or
+ 		op1 == opmap['STORE_TWO_FAST'] and op2 == opmap['LOAD_TWO_FAST'] or
+ 		op1 == opmap['STORE_ATTR_FAST'] and
+ 		op2 == opmap['LOAD_ATTR_FAST']):
+ 		if block[i][1] == block[i+1][1]:
+ 		    block[i+1] = block[i]
+ 		    block[i] = (opmap['DUP_TOP'],)
+ 		    self.__class__.counter = self.__class__.counter+1
+ 	    i = i + 1
+ 	return block
+ 
+ # should eliminate all single load/pop pairs
+ class ConstPopEliminator(OptimizeFilter):
+     """Deletes LOAD_CONST/POP_TOP instruction pairs"""
+     counter = 0
+     def optimize_block(self,block):
+ 	block = block[:]
+ 	i = 0
+ 	while i < len(block)-1:
+ 	    op1 = block[i][0]
+ 	    op2 = block[i+1][0]
+ 	    if op1 == opmap['LOAD_CONST'] and op2 == opmap['POP_TOP']:
+ 		del block[i+1]
+ 		del block[i]
+ 		self.__class__.counter = self.__class__.counter+1
+ 	    else:
+ 		i = i + 1
+ 	return block
+ 
+ class JumpNextEliminator(OptimizeFilter):
+     """deletes JUMPs to the next block that are the last instruction in a block"""
+     counter = 0
+     def optimize(self):
+ 	blocks = self.input
+ 	self.output = [None]*len(blocks)
+ 	for i in range(len(blocks)):
+ 	    block = blocks[i][:]
+ 	    inst = block[-1]
+ 	    if inst[0] == opmap['JUMP_FORWARD']:
+ 		oparg = inst[1]
+ 		blockaddr = oparg[0]+(oparg[1]<<8)
+ 		if blockaddr == i+1:
+ 		    block = block[:-1]
+ 		    self.__class__.counter = self.__class__.counter+1
+ 	    self.output[i] = block
+ 
+ class JumpOptimizer(OptimizeFilter):
+     """Optimizes JUMPs to JUMPs"""
+     counter = 0
+     def optimize_block(self,block):
+ 	block = block[:]
+ 	i = 0
+ 	for i in range(len(block)):
+ 	    op = block[i]		# save this opcode
+ 	    if not is_jump(op): continue # no use if it's not a jump
+ 	    # calculate target opcode
+ 	    oparg = op[1]
+ 	    blockaddr = oparg[0]+(oparg[1]<<8)
+ 	    otherblock = self.blocks[blockaddr]
+ 	    otherop = otherblock[0]
+ 	    # as long as it's an unconditional jump, keep jumping
+ 	    while is_unconditional_jump(otherop[0]):
+ 		self.__class__.counter = self.__class__.counter+1
+ 		block[i] = (op[0], otherop[1])
+ 		oparg = otherop[1]
+ 		blockaddr = oparg[0]+(oparg[1]<<8)
+ 		otherblock = self[blockaddr]
+ 		otherop = otherblock[0]
+ 	return block
+ 
+ class TupleRearranger(OptimizeFilter):
+     """Reorganizes BUILD_TUPLE/UNPACK_TUPLE sequences to eliminate tuple ops"""
+     counter = 0
+     def optimize_block(self, block):
+ 	block = block[:]
+ 	i = 0
+ 	while i < len(block):
+ 	    if block[i][0] == opmap['BUILD_TUPLE']:
+ 		if i < len(block)-1:
+ 		    if (block[i+1][0] == opmap['UNPACK_TUPLE'] and
+ 			block[i][1][0] == block[i+1][1][0]):
+ 			arg = block[i][1][0]
+ 			if i+2+arg < len(block):
+ 			    stores = block[i+2:i+2+arg]
+ 			    allstores = 1
+ 			    for b in stores:
+ 				if not is_simple_store(b[0]):
+ 				    allstores = 0
+ 				    break
+ 			    if allstores:
+ 				self.__class__.counter = self.__class__.counter+1
+ 				stores.reverse()
+ 				block[i:i+2+arg] = stores
+ 				i = i + 1 + arg
+ 	    i = i + 1
+ 	return block
+ 
+ class ConstantShortcut(OptimizeFilter):
+     """map common constant loads into special instructions"""
+     counter = 0
+     def optimize_block(self, block):
+ 	# need a constants tuple to perform the lookups...
+ 	if self.constants is None:
+ 	    return block
+ 
+ 	newblock = block[:]
+ 	for i in range(len(newblock)):
+ 	    if newblock[i][0] == opmap['LOAD_CONST']:
+ 		a1 = newblock[i][1][0]
+ 		a2 = newblock[i][1][1]
+ 		arg = self.constants[a1+(a2<<8)]
+ 		# this code is a bit fragile.  at compile time we are
+ 		# assuming the values of NSMALLNEGINTS and NSMALLPOSINTS
+ 		# are the same as those compiled into the Python interpreter...
+ 		if (type(arg) == type(1) and
+ 		    0 <= arg < NSMALLPOSINTS):
+ 		    self.__class__.counter = self.__class__.counter+1
+ 		    newblock[i] = (opmap['LOADI'],(arg&0xff,arg>>8))
+ 		elif arg is None:
+ 		    self.__class__.counter = self.__class__.counter+1
+ 		    newblock[i] = (opmap['LOAD_NONE'],)
+ 
+ 	return newblock
+ 
+ class ConstantExpressionEvaluator(OptimizeFilter):
+     """evaluation constant expressions and store the result in constants"""
+     counter = 0
+     def optimize_block(self, block):
+ 	if self.constants is None:
+ 	    return block
+ 
+ 	block = block[:]
+ 	i = 0
+ 	while i < len(block)-1:
+ 	    op1 = block[i]
+ 	    op2 = block[i+1]
+ 
+ 	    try:
+ 		if (op1[0] == opmap['LOAD_CONST'] and is_unary_op(op2[0])):
+ 		    arg1 = self.constants[op1[1][0]+(op1[1][1]<<8)]
+ 		    if op2[0] == opmap['UNARY_NOT']: result = not arg1
+ 		    elif op2[0] == opmap['UNARY_INVERT']: result = ~arg1
+ 		    elif op2[0] == opmap['UNARY_POSITIVE']: result = +arg1
+ 		    elif op2[0] == opmap['UNARY_NEGATIVE']: result = -arg1
+ 		    elif op2[0] == opmap['UNARY_CONVERT']: result = `arg1`
+ 		    else:
+ 			raise ValueError, \
+ 			      "Unrecognized unary opcode: %d"%op2[0]
+ 		    try:
+ 			index = self.constants.index(result)
+ 		    except ValueError:
+ 			self.constants.append(result)
+ 			index = self.constants.index(result)
+ 		    block[i:i+2] = [(opmap['LOAD_CONST'],
+ 				     (index&0xff, (index>>8)))]
+ 		    self.__class__.counter = self.__class__.counter + 1
+ 		    # do not advance i - we want to consider the new
+ 		    # instruction again
+ 
+ 		elif (i < len(block)-2 and
+ 		      op1[0] == op2[0] == opmap['LOAD_CONST']):
+ 		    op3 = block[i+2]
+ 		    if is_bin_op(op3[0]):
+ 			arg1 = self.constants[op1[1][0]+(op1[1][1]<<8)]
+ 			arg2 = self.constants[op2[1][0]+(op2[1][1]<<8)]
+ 			if op3[0] == opmap['BINARY_ADD']:
+ 			    result = arg1 + arg2
+ 			elif op3[0] == opmap['BINARY_MULTIPLY']:
+ 			    result = arg1 * arg2
+ 			elif op3[0] == opmap['BINARY_SUBTRACT']:
+ 			    result = arg1 - arg2
+ 			elif op3[0] == opmap['BINARY_DIVIDE']:
+ 			    result = arg1 / arg2
+ 			elif op3[0] == opmap['BINARY_MODULO']:
+ 			    result = arg1 % arg2
+ 			elif op3[0] == opmap['BINARY_POWER']:
+ 			    result = arg1 ** arg2
+ 			elif op3[0] == opmap['BINARY_LSHIFT']:
+ 			    result = (arg1 << arg2)
+ 			elif op3[0] == opmap['BINARY_RSHIFT']:
+ 			    result = (arg1 >> arg2)
+ 			elif op3[0] == opmap['BINARY_AND']:
+ 			    result = (arg1 & arg2)
+ 			elif op3[0] == opmap['BINARY_OR']:
+ 			    result = (arg1 | arg2)
+ 			elif op3[0] == opmap['BINARY_XOR']:
+ 			    result = (arg1 ^ arg2)
+ 			else:
+ 			    raise ValueError, \
+ 				  "Unrecognized binary opcode: %d"%op3[0]
+ 			try:
+ 			    index = self.constants.index(result)
+ 			except ValueError:
+ 			    self.constants.append(result)
+ 			    index = self.constants.index(result)
+ 			block[i:i+3] = [(opmap['LOAD_CONST'], (index&0xff, (index>>8)))]
+ 			self.__class__.counter = self.__class__.counter + 1
+ 			# do not advance i - we want to consider the new
+ 			# instruction again
+ 		    else:
+ 			i = i + 1
+ 		else:
+ 		    i = i + 1
+ 	    except:
+ 		# getting an exception may be valid, so we can't quit
+ 		# check out Lib/bdb.py where it executes:
+ 		#	1 + ''		# generate an exception
+ 		# or Lib/code.py where it executes:
+ 		#	try: 1/0
+ 		#	except: ...
+ 		i = i + 1
+ 	return block
+ 
+ def findlabels(code):
+     labels = [0]
+     n = len(code)
+     i = 0
+     while i < n:
+ 	c = code[i]
+ 	op = ord(c)
+ 	i = i+1
+ 	if op >= HAVE_ARGUMENT:
+ 	    try:
+ 		oparg = ord(code[i]) + ord(code[i+1])*256
+ 	    except IndexError:
+ 		print "<%02d> %d" % (op, i)
+ 		raise IndexError
+ 	    except TypeError:
+ 		print "<%02d> %d" % (op, i)
+ 		raise IndexError
+ 	    i = i+2
+ 	    label = -1
+ 	    if is_abs_jump(op):
+ 		label = oparg
+ 	    elif is_jump(op):
+ 		label = i+oparg
+ 	    if label >= 0:
+ 		if label not in labels:
+ 		    labels.append(label)
+     labels.sort()
+     return labels
+ 
+ def is_unary_op(op):
+     return ((opmap['UNARY_POSITIVE'] <= op <= opmap['UNARY_CONVERT']) or
+ 	    op == opmap['UNARY_INVERT'])
+ 
+ def is_bin_op(op):
+     return ((opmap['BINARY_POWER'] <= op <= opmap['BINARY_SUBTRACT']) or
+ 	    (opmap['BINARY_LSHIFT'] <= op <= opmap['BINARY_OR']))
+ 	    
+ JUMP_OP_MIN = opmap['JUMP_FORWARD']
+ JUMP_OP_MAX = opmap['FOR_LOOP']
+ SETUP_OP_MIN = opmap['SETUP_LOOP']
+ SETUP_OP_MAX = opmap['SETUP_FINALLY']
+ 
+ def is_jump(op):
+     return ((JUMP_OP_MIN <= op <= JUMP_OP_MAX) or
+ 	    (SETUP_OP_MIN <= op <= SETUP_OP_MAX))
+ 
+ def is_abs_jump(op):
+     return opmap['JUMP_ABSOLUTE'] == op
+ 
+ def is_unconditional_transfer(op):
+     return ((op == opmap['RETURN_VALUE']) or is_unconditional_jump(op))
+ 
+ def is_unconditional_jump(op):
+     return op in [opmap['JUMP_FORWARD'], opmap['JUMP_ABSOLUTE']]
+ 
+ def is_simple_store(op):
+     return op in [opmap['STORE_FAST'], opmap['STORE_GLOBAL'], opmap['STORE_NAME']]
+ 
+ def sum(list):
+     return reduce(lambda x,y: x+y, list, 0)
+ 
+ def blocklength(block):
+     bl = 0
+     for insn in block:
+ 	bl = bl + 1
+ 	try:
+ 	    bl = bl + len(insn[1])
+ 	except IndexError:
+ 	    pass
+     return bl
+ 
+ def test():
+     import dis, sys
+     stdout = sys.stdout
+ 
+     import pystone
+     orig = open('pystone.out', 'w')
+     opt = open('pystone.opt', 'w')
+     for n in dir(pystone):
+ 	f = getattr(pystone, n)
+ 	if type(f) == type(pystone.Proc0):
+ 	    code = f.func_code.co_code
+ 	    varnames = f.func_code.co_varnames
+ 	    names = f.func_code.co_names
+ 	    constants = f.func_code.co_consts
+ 	    sys.stdout = orig
+ 	    print "\n===Function %s:\n" % n
+ 	    dis.dis(f)
+ 	    sys.stdout = opt
+ 	    print "\n===Function %s:\n" % n
+ 	    code = optimize(code, varnames, names, constants)
+ 	    dis.disassemble_string(code,
+ 				   varnames=varnames,
+ 				   names=names,
+ 				   constants=constants)
+ 
+     sys.stdout = stdout
+ 
+ def print_counts():
+     print "DeadCodeRemover:", DeadCodeRemover.counter
+     print "LineNumberRemover:", LineNumberRemover.counter
+     print "LoadStoreCompressor:", LoadStoreCompressor.counter
+     print "StoreLoadEliminator:", StoreLoadEliminator.counter
+     print "ConstPopEliminator:", ConstPopEliminator.counter
+     print "ConstantExpressionEvaluator:", ConstantExpressionEvaluator.counter
+     print "JumpNextEliminator:", JumpNextEliminator.counter
+     print "JumpOptimizer:", JumpOptimizer.counter
+     print "TupleRearranger:", TupleRearranger.counter
+     print "ConstantShortcut:", ConstantShortcut.counter
+     print "MultiLoadEliminator:", MultiLoadEliminator.counter
+ 
+ try:
+     optimize = eval('optimize%d'%strop.atoi(posix.environ['OPTLEVEL']))
+ except KeyError:
+     optimize = optimize5
+ 
+ try:
+     x = posix.environ['OPTSTATS']
+     import sys
+     sys.exitfunc = print_counts
+ except KeyError:
+     pass
+ 
+ if __name__ == "__main__": test()
diff -rcN Python-1.5.1/Objects/intobject.c Python-1.5.1.new/Objects/intobject.c
*** Python-1.5.1/Objects/intobject.c	Mon Aug  4 22:16:05 1997
--- Python-1.5.1.new/Objects/intobject.c	Mon Jun 29 08:17:10 1998
***************
*** 32,37 ****
--- 32,38 ----
  /* Integer object implementation */
  
  #include "Python.h"
+ #include "intobject.h"
  
  #ifdef HAVE_LIMITS_H
  #include <limits.h>
***************
*** 107,125 ****
  }
  
  static PyIntObject *free_list = NULL;
- #ifndef NSMALLPOSINTS
- #define NSMALLPOSINTS		100
- #endif
- #ifndef NSMALLNEGINTS
- #define NSMALLNEGINTS		1
- #endif
  #if NSMALLNEGINTS + NSMALLPOSINTS > 0
  /* References to small integers are saved in this array so that they
     can be shared.
     The integers that are saved are those in the range
     -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
  */
! static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
  #endif
  #ifdef COUNT_ALLOCS
  int quick_int_allocs, quick_neg_int_allocs;
--- 108,120 ----
  }
  
  static PyIntObject *free_list = NULL;
  #if NSMALLNEGINTS + NSMALLPOSINTS > 0
  /* References to small integers are saved in this array so that they
     can be shared.
     The integers that are saved are those in the range
     -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
  */
! PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS] = {0};
  #endif
  #ifdef COUNT_ALLOCS
  int quick_int_allocs, quick_neg_int_allocs;
***************
*** 132,138 ****
  	register PyIntObject *v;
  #if NSMALLNEGINTS + NSMALLPOSINTS > 0
  	if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS &&
! 	    (v = small_ints[ival + NSMALLNEGINTS]) != NULL) {
  		Py_INCREF(v);
  #ifdef COUNT_ALLOCS
  		if (ival >= 0)
--- 127,134 ----
  	register PyIntObject *v;
  #if NSMALLNEGINTS + NSMALLPOSINTS > 0
  	if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS &&
! 	    *small_ints != NULL) {
! 		v = small_ints[ival+NSMALLNEGINTS];
  		Py_INCREF(v);
  #ifdef COUNT_ALLOCS
  		if (ival >= 0)
***************
*** 147,163 ****
  		if ((free_list = fill_free_list()) == NULL)
  			return NULL;
  	}
  	v = free_list;
  	free_list = *(PyIntObject **)free_list;
  	v->ob_type = &PyInt_Type;
  	v->ob_ival = ival;
  	_Py_NewReference(v);
- #if NSMALLNEGINTS + NSMALLPOSINTS > 0
- 	if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
- 		/* save this one for a following allocation */
- 		Py_INCREF(v);
- 		small_ints[ival + NSMALLNEGINTS] = v;
- 	}
  #endif
  	return (PyObject *) v;
  }
--- 143,185 ----
  		if ((free_list = fill_free_list()) == NULL)
  			return NULL;
  	}
+ #if NSMALLNEGINTS + NSMALLPOSINTS > 0
+ 	if (! *small_ints) {
+ 		/* initialize the entire small_ints array so it's
+ 		   available for the interpreter */
+ 		int i;
+ 		for (i = -NSMALLNEGINTS; i < NSMALLPOSINTS; i++) {
+ 			if (free_list == NULL) {
+ 				if ((free_list = fill_free_list())
+ 				    == NULL)
+ 					return NULL;
+ 			}
+ 			v = free_list;
+ 			free_list = *(PyIntObject **)free_list;
+ 			v->ob_type = &PyInt_Type;
+ 			v->ob_ival = i;
+ 			_Py_NewReference(v);
+ 			small_ints[i + NSMALLNEGINTS] = v;
+ 		}
+ 	}
+ 
+ 	if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
+ 		v = small_ints[ival + NSMALLNEGINTS];
+ 		Py_INCREF(v);
+ 	}
+ 	else {
+ 		v = free_list;
+ 		free_list = *(PyIntObject **)free_list;
+ 		v->ob_type = &PyInt_Type;
+ 		v->ob_ival = ival;
+ 		_Py_NewReference(v);
+ 	}
+ #else
  	v = free_list;
  	free_list = *(PyIntObject **)free_list;
  	v->ob_type = &PyInt_Type;
  	v->ob_ival = ival;
  	_Py_NewReference(v);
  #endif
  	return (PyObject *) v;
  }
diff -rcN Python-1.5.1/Python/ceval.c Python-1.5.1.new/Python/ceval.c
*** Python-1.5.1/Python/ceval.c	Fri Apr 10 18:25:29 1998
--- Python-1.5.1.new/Python/ceval.c	Mon Jun 29 07:49:00 1998
***************
*** 43,48 ****
--- 43,49 ----
  #include "frameobject.h"
  #include "eval.h"
  #include "opcode.h"
+ #include "intobject.h"
  
  #include <ctype.h>
  
***************
*** 374,380 ****
  	/* Make it easier to find out where we are with a debugger */
  	char *filename = PyString_AsString(co->co_filename);
  #endif
! 
  /* Code access macros */
  
  #define GETCONST(i)	Getconst(f, i)
--- 375,381 ----
  	/* Make it easier to find out where we are with a debugger */
  	char *filename = PyString_AsString(co->co_filename);
  #endif
! 	
  /* Code access macros */
  
  #define GETCONST(i)	Getconst(f, i)
***************
*** 409,414 ****
--- 410,420 ----
  #define SETLOCAL(i, value)	do { Py_XDECREF(GETLOCAL(i)); \
  				     GETLOCAL(i) = value; } while (0)
  
+ /* macros to extract indexes when two are smashed into one oparg */
+ #define ARGLO(i) ((i)&0xff)
+ #define ARGHI(i) ((i)>>8)
+ 
+ 
  /* Start of code */
  
  #ifdef USE_STACKCHECK
***************
*** 1272,1282 ****
  				PyErr_SetObject(PyExc_NameError, w);
  			break;
  		
  		case LOAD_CONST:
  			x = GETCONST(oparg);
  			Py_INCREF(x);
  			PUSH(x);
! 			break;
  		
  		case LOAD_NAME:
  			w = GETNAMEV(oparg);
--- 1278,1303 ----
  				PyErr_SetObject(PyExc_NameError, w);
  			break;
  		
+ 		case LOADI:
+ #if NSMALLNEGINTS + NSMALLPOSINTS > 0
+ 			x = (PyObject *)small_ints[NSMALLNEGINTS+oparg];
+ 			Py_INCREF(x);
+ #else
+ 			x = PyInt_FromLong(oparg);
+ #endif
+ 			PUSH(x);
+ 			continue;
+ 
  		case LOAD_CONST:
  			x = GETCONST(oparg);
  			Py_INCREF(x);
  			PUSH(x);
! 			continue;
! 
! 		case LOAD_NONE:
! 			Py_INCREF(Py_None);
! 			PUSH(Py_None);
! 			continue;
  		
  		case LOAD_NAME:
  			w = GETNAMEV(oparg);
***************
*** 1328,1341 ****
  			}
  			Py_INCREF(x);
  			PUSH(x);
! 			if (x != NULL) continue;
! 			break;
  
  		case STORE_FAST:
  			v = POP();
  			SETLOCAL(oparg, v);
  			continue;
  
  		case DELETE_FAST:
  			SETLOCAL(oparg, NULL);
  			continue;
--- 1349,1392 ----
  			}
  			Py_INCREF(x);
  			PUSH(x);
! 			continue;
! 
! 		case LOAD_TWO_FAST:
! 			x = GETLOCAL(ARGLO(oparg));
! 			if (x == NULL) {
! 				PyErr_SetObject(PyExc_NameError,
! 					   PyTuple_GetItem(co->co_varnames,
! 							ARGLO(oparg)));
! 				break;
! 			}
! 
! 			Py_INCREF(x);
! 			PUSH(x);
! 
! 			x = GETLOCAL(ARGHI(oparg));
! 			if (x == NULL) {
! 				PyErr_SetObject(PyExc_NameError,
! 					   PyTuple_GetItem(co->co_varnames,
! 							ARGHI(oparg)));
! 				break;
! 			}
! 
! 			Py_INCREF(x);
! 			PUSH(x);
! 			continue;
  
  		case STORE_FAST:
  			v = POP();
  			SETLOCAL(oparg, v);
  			continue;
  
+ 		case STORE_TWO_FAST:
+ 			v = POP();
+ 			SETLOCAL(ARGLO(oparg), v);
+ 			v = POP();
+ 			SETLOCAL(ARGHI(oparg), v);
+ 			continue;
+ 
  		case DELETE_FAST:
  			SETLOCAL(oparg, NULL);
  			continue;
***************
*** 1381,1386 ****
--- 1432,1466 ----
  			if (x != NULL) continue;
  			break;
  		
+ 		case LOAD_ATTR_FAST:
+ 			x = GETLOCAL(ARGLO(oparg));
+ 			if (x == NULL) {
+ 				PyErr_SetObject(PyExc_NameError,
+ 					   PyTuple_GetItem(co->co_varnames,
+ 							ARGHI(oparg)));
+ 				break;
+ 			}
+ 			w = GETNAMEV(ARGHI(oparg));
+ 			v = x;
+ 			x = PyObject_GetAttr(v, w);
+ 			PUSH(x);
+ 			break;
+ 
+ 		case STORE_ATTR_FAST:
+ 			x = GETLOCAL(ARGLO(oparg));
+ 			if (x == NULL) {
+ 				PyErr_SetObject(PyExc_NameError,
+ 					   PyTuple_GetItem(co->co_varnames,
+ 							ARGHI(oparg)));
+ 				break;
+ 			}
+ 			w = GETNAMEV(ARGHI(oparg));
+ 			v = x;
+ 			u = POP();
+ 			err = PyObject_SetAttr(v, w, u); /* v.w = u */
+ 			Py_DECREF(u);
+ 			break;
+ 			
  		case COMPARE_OP:
  			w = POP();
  			v = POP();
diff -rcN Python-1.5.1/Python/compile.c Python-1.5.1.new/Python/compile.c
*** Python-1.5.1/Python/compile.c	Thu Apr  9 17:39:07 1998
--- Python-1.5.1.new/Python/compile.c	Thu Jul  2 00:07:29 1998
***************
*** 44,49 ****
--- 44,51 ----
  #define PRIVATE_NAME_MANGLING
  #endif
  
+ /* #define DISASSEMBLE */
+ 
  #include "Python.h"
  
  #include "node.h"
***************
*** 316,321 ****
--- 318,326 ----
  #endif
  };
  
+ #ifdef DISASSEMBLE
+ static void disassemble (PyObject *, struct compiling *);
+ #endif
  
  /* Error message including line number */
  
***************
*** 3361,3366 ****
--- 3366,3419 ----
  		PyErr_Restore(error_type, error_value, error_traceback);
  }
  
+ static void
+ optimize_in_python(c) 
+      struct compiling *c;
+ {
+   PyObject *optmodule;
+   PyObject *optfunc;
+   PyObject *new_code;
+ 
+   optmodule = PyImport_ImportModule("optimize");
+   optfunc = PyObject_GetAttrString(optmodule, "optimize");
+   if (!optfunc) return;
+   if (! PyCallable_Check(optfunc)) return;
+ 
+   new_code = PyObject_CallFunction(optfunc, "OOOO",
+ 				   c->c_code, c->c_varnames, c->c_names,
+ 				   c->c_consts);
+   if (new_code && c->c_code != new_code) {
+ #ifdef DISASSEMBLE
+     disassemble(new_code, c);
+ #endif
+     Py_INCREF(new_code);
+     Py_DECREF(c->c_code);
+     c->c_code = new_code;
+     return;
+   }
+ }
+ 
+ static void
+ Optimize(c)
+      struct compiling *c;
+ {
+   static int importing_optimize = 0;
+ 
+   optimize(c);
+ 
+   if (!importing_optimize && Py_OptimizeFlag) {
+     PyObject *optmodule;
+     importing_optimize = 1;
+     optmodule = PyImport_ImportModule("optimize");
+     importing_optimize = 0;
+     if (optmodule)
+       optimize_in_python(c);
+     else
+       PyErr_Clear();
+     Py_XDECREF(optmodule);
+   }
+ }
+ 
  PyCodeObject *
  PyNode_Compile(n, filename)
  	node *n;
***************
*** 3396,3402 ****
  	compile_node(&sc, n);
  	com_done(&sc);
  	if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0) {
! 		optimize(&sc);
  		sc.c_flags |= CO_NEWLOCALS;
  	}
  	else if (TYPE(n) == classdef)
--- 3449,3455 ----
  	compile_node(&sc, n);
  	com_done(&sc);
  	if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0) {
! 		Optimize(&sc);
  		sc.c_flags |= CO_NEWLOCALS;
  	}
  	else if (TYPE(n) == classdef)
***************
*** 3449,3451 ****
--- 3502,3650 ----
  	}
  	return line;
  }
+ 
+ #ifdef DISASSEMBLE
+ /* quick-n-dirty byte code disassembler for debugging optimizer output */
+ static void
+ disassemble(code, c)
+     PyObject *code;
+     struct compiling *c;
+ {
+ 
+     int i, len;
+     unsigned char *s;
+ 
+     s = PyString_AsString(code);
+     len = PyString_Size(code);
+     
+     fprintf(stderr, "\n\n********** %s\n", c->c_name);
+ 
+     for (i = 0; i < len; i++) {
+ 	switch (s[i]) {
+ 	case STOP_CODE: fprintf(stderr, "STOP_CODE"); break;
+ 	case POP_TOP: fprintf(stderr, "POP_TOP"); break;
+ 	case ROT_TWO: fprintf(stderr, "ROT_TWO"); break;
+ 	case ROT_THREE: fprintf(stderr, "ROT_THREE"); break;
+ 	case DUP_TOP: fprintf(stderr, "DUP_TOP"); break;
+ 
+ 	case UNARY_POSITIVE: fprintf(stderr, "UNARY_POSITIVE"); break;
+ 	case UNARY_NEGATIVE: fprintf(stderr, "UNARY_NEGATIVE"); break;
+ 	case UNARY_NOT: fprintf(stderr, "UNARY_NOT"); break;
+ 	case UNARY_CONVERT: fprintf(stderr, "UNARY_CONVERT"); break;
+ 
+ 	case UNARY_INVERT: fprintf(stderr, "UNARY_INVERT"); break;
+ 
+ 	case BINARY_POWER: fprintf(stderr, "BINARY_POWER"); break;
+ 
+ 	case BINARY_MULTIPLY: fprintf(stderr, "BINARY_MULTIPLY"); break;
+ 	case BINARY_DIVIDE: fprintf(stderr, "BINARY_DIVIDE"); break;
+ 	case BINARY_MODULO: fprintf(stderr, "BINARY_MODULO"); break;
+ 	case BINARY_ADD: fprintf(stderr, "BINARY_ADD"); break;
+ 	case BINARY_SUBTRACT: fprintf(stderr, "BINARY_SUBTRACT"); break;
+ 	case BINARY_SUBSCR: fprintf(stderr, "BINARY_SUBSCR"); break;
+ 
+ 	case SLICE:
+ 	case SLICE+1:
+ 	case SLICE+2:
+ 	case SLICE+3: fprintf(stderr, "SLICE"); break;
+ 
+ 	case STORE_SLICE:
+ 	case STORE_SLICE+1:
+ 	case STORE_SLICE+2:
+ 	case STORE_SLICE+3: fprintf(stderr, "STORE_SLICE"); break;
+ 
+ 	case DELETE_SLICE:
+ 	case DELETE_SLICE+1:
+ 	case DELETE_SLICE+2:
+ 	case DELETE_SLICE+3: fprintf(stderr, "DELETE_SLICE"); break;
+ 
+ 
+ 	case STORE_SUBSCR: fprintf(stderr, "STORE_SUBSCR"); break;
+ 	case DELETE_SUBSCR: fprintf(stderr, "DELETE_SUBSCR"); break;
+ 
+ 	case BINARY_LSHIFT: fprintf(stderr, "BINARY_LSHIFT"); break;
+ 	case BINARY_RSHIFT: fprintf(stderr, "BINARY_RSHIFT"); break;
+ 	case BINARY_AND: fprintf(stderr, "BINARY_AND"); break;
+ 	case BINARY_XOR: fprintf(stderr, "BINARY_XOR"); break;
+ 	case BINARY_OR: fprintf(stderr, "BINARY_OR"); break;
+ 
+ 
+ 	case PRINT_EXPR: fprintf(stderr, "PRINT_EXPR"); break;
+ 	case PRINT_ITEM: fprintf(stderr, "PRINT_ITEM"); break;
+ 	case PRINT_NEWLINE: fprintf(stderr, "PRINT_NEWLINE"); break;
+ 
+ 	case BREAK_LOOP: fprintf(stderr, "BREAK_LOOP"); break;
+ 
+ 	case LOAD_LOCALS: fprintf(stderr, "LOAD_LOCALS"); break;
+ 	case RETURN_VALUE: fprintf(stderr, "RETURN_VALUE"); break;
+ 
+ 	case EXEC_STMT: fprintf(stderr, "EXEC_STMT"); break;
+ 
+ 	case POP_BLOCK: fprintf(stderr, "POP_BLOCK"); break;
+ 	case END_FINALLY: fprintf(stderr, "END_FINALLY"); break;
+ 	case BUILD_CLASS: fprintf(stderr, "BUILD_CLASS"); break;
+ 
+ 	case STORE_NAME: fprintf(stderr, "STORE_NAME"); break;	
+ 	case DELETE_NAME: fprintf(stderr, "DELETE_NAME"); break;	
+ 	case UNPACK_TUPLE: fprintf(stderr, "UNPACK_TUPLE"); break;	
+ 	case UNPACK_LIST: fprintf(stderr, "UNPACK_LIST"); break;	
+ 	case UNPACK_ARG: fprintf(stderr, "UNPACK_ARG"); break;	
+ 	case STORE_ATTR: fprintf(stderr, "STORE_ATTR"); break;	
+ 	case DELETE_ATTR: fprintf(stderr, "DELETE_ATTR"); break;	
+ 	case STORE_GLOBAL: fprintf(stderr, "STORE_GLOBAL"); break;	
+ 	case DELETE_GLOBAL: fprintf(stderr, "DELETE_GLOBAL"); break;	
+ 	case UNPACK_VARARG: fprintf(stderr, "UNPACK_VARARG"); break;	
+ 
+ 	case LOAD_CONST: fprintf(stderr, "LOAD_CONST"); break;	
+ 	case LOAD_NAME: fprintf(stderr, "LOAD_NAME"); break;	
+ 	case BUILD_TUPLE: fprintf(stderr, "BUILD_TUPLE"); break;	
+ 	case BUILD_LIST: fprintf(stderr, "BUILD_LIST"); break;	
+ 	case BUILD_MAP: fprintf(stderr, "BUILD_MAP"); break;	
+ 	case LOAD_ATTR: fprintf(stderr, "LOAD_ATTR"); break;	
+ 	case COMPARE_OP: fprintf(stderr, "COMPARE_OP"); break;	
+ 	case IMPORT_NAME: fprintf(stderr, "IMPORT_NAME"); break;	
+ 	case IMPORT_FROM: fprintf(stderr, "IMPORT_FROM"); break;	
+ 
+ 	case JUMP_FORWARD: fprintf(stderr, "JUMP_FORWARD"); break;	
+ 	case JUMP_IF_FALSE: fprintf(stderr, "JUMP_IF_FALSE"); break;	
+ 	case JUMP_IF_TRUE: fprintf(stderr, "JUMP_IF_TRUE"); break;	
+ 	case JUMP_ABSOLUTE: fprintf(stderr, "JUMP_ABSOLUTE"); break;	
+ 	case FOR_LOOP: fprintf(stderr, "FOR_LOOP"); break;	
+ 
+ 	case LOAD_LOCAL: fprintf(stderr, "LOAD_LOCAL"); break;	
+ 	case LOAD_GLOBAL: fprintf(stderr, "LOAD_GLOBAL"); break;	
+ 
+ 	case SET_FUNC_ARGS: fprintf(stderr, "SET_FUNC_ARGS"); break;	
+ 
+ 	case SETUP_LOOP: fprintf(stderr, "SETUP_LOOP"); break;	
+ 	case SETUP_EXCEPT: fprintf(stderr, "SETUP_EXCEPT"); break;	
+ 	case SETUP_FINALLY: fprintf(stderr, "SETUP_FINALLY"); break;	
+ 
+ 	case LOAD_FAST: fprintf(stderr, "LOAD_FAST"); break;	
+ 	case STORE_FAST: fprintf(stderr, "STORE_FAST"); break;	
+ 	case DELETE_FAST: fprintf(stderr, "DELETE_FAST"); break;	
+ 
+ 	case SET_LINENO: fprintf(stderr, "SET_LINENO"); break;	
+ 
+ 	case LOAD_TWO_FAST: fprintf(stderr, "LOAD_TWO_FAST"); break;	
+ 	case STORE_TWO_FAST: fprintf(stderr, "STORE_TWO_FAST"); break;	
+ 	case LOAD_ATTR_FAST: fprintf(stderr, "LOAD_ATTR_FAST"); break;	
+ 	case STORE_ATTR_FAST: fprintf(stderr, "STORE_ATTR_FAST"); break;	
+ 
+ 	case RAISE_VARARGS: fprintf(stderr, "RAISE_VARARGS"); break;	
+ 	case CALL_FUNCTION: fprintf(stderr, "CALL_FUNCTION"); break;	
+ 	case MAKE_FUNCTION: fprintf(stderr, "MAKE_FUNCTION"); break;	
+ 	case BUILD_SLICE : fprintf(stderr, "BUILD_SLICE"); break;	
+ 	case LOADI : fprintf(stderr, "LOADI"); break;	
+ 
+ 	default: fprintf(stderr, "<%02d>", s[i]); break;
+ 	}
+ 
+ 	if (HAS_ARG(s[i])) {
+ 	  fprintf(stderr, "\t%d,%d", s[i+1], s[i+2]);
+ 	  i += 2;
+ 	}
+ 	fprintf(stderr, "\n");
+     }
+ }
+ #endif
