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 *************** *** 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 *************** *** 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