# Copyright 2006-2007 Grant T. Olson.
# See LICENSE for terms.
import dis, opcode, sys

from pyasm.x86asm import assembler, PYTHON

from pyasm.pythonConstants import PythonConstants

from pyasm.structs import PyObject, PyTypeObject, PyFunctionObject, \
PyTupleObject


ob_refcnt = PyObject.ob_refcnt
ob_type = PyObject.ob_type
tp_dealloc = PyTypeObject.tp_dealloc
func_globals = PyFunctionObject.func_globals
ob_size = PyTupleObject.ob_size

debugBuild = ob_refcnt != 0

del PyObject
del PyTypeObject
del PyFunctionObject
del PyTupleObject

debug = 0

codeType = type(compile("1","","single"))

def printCodeObject(co):
    print 'co_argcount', co.co_argcount
    print 'co_cellvars', co.co_cellvars
    print 'co_code',repr(co.co_code)
    print 'co_consts', co.co_consts
    print 'co_filename', co.co_filename
    print 'co_firstlineno',co.co_firstlineno
    print 'co_flags', co.co_flags
    print 'co_freevars',co.co_freevars
    print 'co_lnotab',co.co_lnotab
    print 'co_name',co.co_name
    print 'co_names',co.co_names
    print 'co_nlocals',co.co_nlocals
    print 'co_stacksize',co.co_stacksize
    print 'co_varnames',co.co_varnames
    print dis.dis(co)

class codeObjectAssembler:
    def __init__(self):
        self.tempLabels = {}
        self.a = assembler()
        PythonConstants(self.a)
        self.loadStringConstants()
        self.code_objects = []
        self.currentExitFunc = ""
        self.primary_co_type = "exec"
        self.currentBytecodeOffset = None
        self.bytecodeOffsetLabel = None
        self.blocks = []
        
    stringConstants = {
        "newline":"\n",
        "misaligned":"****************** Stack misaligned ***************",
        "module_init_array": "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
        "foo": "foo",
        "build_class_OOO": "OOO",
        "imports": "__import__",
        "all":"__all__",
        "dict":"__dict__",
        "keys":"keys",
        }

    def loadStringConstants(self):
        for key,val in codeObjectAssembler.stringConstants.iteritems():
            if val[-1] != "\0":
                val += "\0"
            self.a.ADStr(key,val)

    def assembleCodeObject(self, co, name="exec:main"):
        self.code_objects.append( (co,name) )
        self.assembleCodeObjects()
        return self.a.Compile()

    def assembleCodeObjects(self):
        while self.code_objects:
            code_object = self.code_objects.pop(0)
            self.assembleSingleCodeObject(*code_object)
            
    def assembleSingleCodeObject(self, co, name="exec:main"):
        self.debugPrintCt("\n\n!!!!!!!!!!!!!!!! START COMPILATION !!!!!!!!!!!!!!!!!",1)
        self.co_type = 'normal'
        if name.startswith("module:"):
            self.co_type = 'module'
            self.primary_co_type = 'module'
            name = "init" + name[len("module:"):]
        elif name.startswith("exe:"):
            self.co_type = 'exe'
            self.primary_co_type = 'exe'
            name = name[len("exe:"):]
        elif name.startswith("exec:"):
            self.primary_co_type = "exec"
            self.co_type = "exec"
            name = name[len("exec:"):]
            name = name + " PYTHON"
        else:
            name = name

        self.co_firstlineno = co.co_firstlineno
        self.co_lnotab = co.co_lnotab

        self.co_lineNumbers = {}
        numbers = [ord(x) for x in co.co_lnotab]
        lineno = co.co_firstlineno
        addr = 0
        for i in range(0,len(numbers),2):
            addr_inc, line_inc = numbers[i], numbers[i+1]
            if line_inc == 0: continue # lines > 255 bytecodes
            lineno += line_inc
            addr += addr_inc
            self.co_lineNumbers[addr] = lineno

        self.a("!PROC %s" % name)

        if self.co_type == 'exec':
            self.a("!ARG globalsIn")
            self.a("!ARG localsIn")
        else:
            self.a("!ARG self")
            self.a("!ARG args")
        
        self.a("!LOCAL x")
        self.a("!LOCAL v")
        self.a("!LOCAL w")
        self.a("!LOCAL u")
        self.a("!LOCAL t")

        self.a("!LOCAL names")
        
        self.a("!LOCAL locals")
        self.a("!LOCAL globals")
        self.a("!LOCAL builtins")
        self.a("!LOCAL tstate")
        
        self.currentExitFunc = self.getTempLabel("exit_func")
        
        self.emit_const_defs(co.co_consts)
        self.emit_var_defs(co.co_varnames)
        self.emit_cellvar_defs(len(co.co_cellvars)+len(co.co_freevars))

        # No more variables after this point, begin code emission
        self.debugTestStackBegin()
        self.debugPrintRt("BEGIN RUNNING %s" % name)
        if self.co_type == "module":
            self.a("MOV EAX,1012")
            self.a("PUSH EAX")
            self.a("PUSH 0")
            self.a("PUSH 0")
            self.a("PUSH module_init_array")
            self.a.ADStr("module_name",name[4:] + "\0")
            self.a("PUSH module_name")
            self.a("CALL Py_InitModule4")
            self.a("ADD ESP,20")
            self.a("PUSH EAX")
            self.a("CALL PyModule_GetDict")
            self.emit_py_error_check(4)
            self.emit_incref_reg()
            self.emit_incref_reg()
            self.a("MOV locals,EAX")
            self.a("MOV globals,EAX")
            
        elif self.co_type == "exe":
            self.a("CALL PyEval_InitThreads")
            self.a("CALL Py_Initialize")
            self.a('!CALL PyImport_AddModule "__main__\\0"')
            self.emit_py_error_check(4)
            self.a("PUSH EAX")
            self.a("CALL PyModule_GetDict")
            self.emit_py_error_check(4)
            self.emit_incref_reg()
            self.emit_incref_reg()
            self.a("MOV locals,EAX")
            self.a("MOV globals,EAX")
            self.a("CALL PyThreadState_Get")
            self.emit_py_error_check()
            self.a("MOV w, EAX")

            #init frame
            # do we need to do this for each object
            self.a("CALL PyThreadState_Get")
            self.emit_py_error_check(0)
            self.a("MOV tstate, EAX")
            self.a("PUSH locals")
            self.a("PUSH globals")
            self.emit_none()
            self.a("PUSH EAX")
            self.a("PUSH tstate")
            self.a("CALL PyFrame_New")
            self.emit_py_error_check(16)
                        
            

                        
            #TODO: bind builtins

        #builtins            
        self.a('!CALL PyImport_ImportModule "__builtin__\\0"')
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
        self.a("CALL PyModule_GetDict")
        self.emit_py_error_check(4)
        self.emit_incref_reg()
        self.a("MOV builtins, EAX")

        #end builtins

       
        self.emit_const_values(co.co_consts)
        self.emit_var_values(co.co_argcount, len(co.co_varnames))
        self.emit_names(co.co_names)
        self.emit_cellvar_values(len(co.co_cellvars), len(co.co_freevars))

        self.bindLocals()
        
        self.walkCode(co)
        self.a.AIL(self.currentExitFunc)

        if self.co_type == "exe":
            self.a("CALL Py_Finalize")

        self.debugPrintRt("FINISH RUNNING %s" % name)        
        self.debugTestStackEnd()
        self.a.EP()
        self.debugPrintCt("!!!!!!!!!!!!!!!! END COMPILATION !!!!!!!!!!!!!!!!!")
        

    def getTempLabel(self,labelPrefix):
        if self.tempLabels.has_key(labelPrefix):
            self.tempLabels[labelPrefix] += 1
        else:
            self.tempLabels[labelPrefix] = 1000
        return "%s_%s" % (labelPrefix, self.tempLabels[labelPrefix])

    def bindLocals(self):
        if self.co_type in('module','exe'): return
        #self.a("CALL PyEval_GetGlobals")
        if self.co_type == 'exec':
            self.debugPrintRt("!!!!!!!!!!!use globals as locals",1)
            self.a("CALL PyEval_GetGlobals")
            self.emit_py_error_check()
            #self.a("MOV globals, EAX")
            self.a("MOV EAX, globalsIn")
            self.a("MOV globals, EAX")
            self.a("MOV EAX, localsIn")
            self.a("MOV locals, EAX")
        else:
            self.debugPrintRt("!!!!!!!!!!!!!!!!!Made new locals dict",1)
            self.a("CALL PyDict_New")
            self.emit_py_error_check(0)
            self.a("MOV locals, EAX")
            #self.a("CALL PyEval_GetGlobals")
            #self.emit_py_error_check()
            self.a("MOV EAX, self")
            self.a("MOV EAX, [EAX + %s]" % func_globals)
            self.emit_incref_reg()
            self.a("MOV globals, EAX")

    def debugPrintCt(self,string,level=1):
        """
        Print debugging info at compile time
        """
        if debug>=level: print >> sys.stderr, "%s%s" % ("  " * (level -1), string)

    def debugPrintConstantRt(self,const,level=1):
        """
        Print debugging info directly to stdout when code is executed
        """
        if debug>=level:
            self.a("PUSH EAX")
            self.a("PUSH %s" % const)
            self.a("CALL PySys_WriteStderr")
            self.a("ADD ESP,0x4")
            self.a("POP EAX")
    
    def debugPrintRt(self,string,level=1):
        """
        Print debugging info directly to stdout when code is executed
        """
        if debug>=level:
            self.a("PUSH EAX")
            self.a("PUSH EBX")
            self.a("PUSH ECX")
            self.a("PUSH EDX")
            self.a('!CALL PySys_WriteStderr "%s%s\\n\\0"' % ("  " * (level -1), string))
            self.a("ADD ESP,0x4")
            self.a("POP EDX")
            self.a("POP ECX")
            self.a("POP EBX")
            self.a("POP EAX")

    def debugTestStackBegin(self):
        """
        These two functions throw a sentinel onto the stack in debug mode
        And check for it at the end of the function
        """
        if debug:
            self.a("PUSH 0x12345678")

    def debugTestStackEnd(self):
        if debug:
            tempLabel = self.getTempLabel("test_stack_end")
            self.a("POP EDX")
            self.a("CMP EDX,0x12345678")
            self.a("JE %s" % tempLabel)
            self.debugPrintConstantRt("misaligned",1)
            self.a.AIL(tempLabel)
    
    def walkCode(self,co):
        self.currentBytecodeOffset = 0
        self.bytecodeOffsetLabel = self.getTempLabel("bytecode_offset")
        
        code = co.co_code
        head,tail = code[0],code[1:]
        while head:
            labelName = "%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset)
            self.a.AIL(labelName)
            self.debugPrintCt("ADDED LABEL %s" % labelName, 10)

            if self.co_lineNumbers.has_key(self.currentBytecodeOffset):
                self.debugPrintRt("!!LINE %s" % self.co_lineNumbers[self.currentBytecodeOffset],1)
            
            opnum = ord(head)
            oparg = None
            opname = opcode.opname[ord(head)].replace("+","_") # workaround SLICE+ ops
            if opnum >= 90: # has arg
                oparg = ord(tail[0]) + ord(tail[1])*256
                tail = tail[2:]

            dispatch = codeObjectAssembler.__dict__.get(opname,None)
            if dispatch:
                if opnum >= 90:
                    self.currentBytecodeOffset += 3
                    dispatch(self,oparg)
                else:
                    self.currentBytecodeOffset += 1
                    dispatch(self)
                    
            else:
                raise Exception("NO HANDLER FOR %s %s " % (opname , oparg))
            head,tail = tail[:1],tail[1:]

    #
    # These emit most of the ASM

    def emit_names(self,names):
        #self.a("MOV names,%s" % id(names))
        self.emit_tuple(names)
        self.a("MOV names,EAX")
                
    def emit_const_defs(self, consts):
        for const in range(len(consts)):
            self.a("!LOCAL const%s" % const)
            self.debugPrintCt("ADDING LOCAL const%s" % const,1)

    def emit_cellvar_defs(self, cellvars):
        for cellvar in range(cellvars):
            self.a("!LOCAL cellvar%s" % cellvar)
            self.debugPrintCt("ADDING LOCAL cellvar%s" % cellvar,1)

    def emit_var_defs(self, vars):
        if len(vars) == 0: return
        self.varZeroOffset = self.a.CurrentProcedure.LocalOffset
        for variable in range(len(vars)):
            self.a("!LOCAL var%s" % variable)
            self.debugPrintCt("ADDING LOCAL var%s" % variable,1)

    def emit_const_defs(self, consts):
        for const in range(len(consts)):
            self.a("!LOCAL const%s" % const)
            self.debugPrintCt("ADDING LOCAL const%s" % const,1)


    def emit_const_values(self, consts):
        for i in range(len(consts)):
            self.emit_py_object(consts[i])
            self.a('MOV const%s,EAX' % i)

    def emit_cellvar_values(self, cellvars, freevars):
        if cellvars + freevars == 0: return

        for i in range(cellvars):
            self.debugPrintRt("Setting cellvar%s to None" % i,2)
            self.emit_int(23)
            self.a("PUSH EAX")
            self.a("CALL PyCell_New")
            self.emit_py_error_check(4)
            self.a("MOV cellvar%s, EAX" % i)
            
        if freevars == 0:return
        
        self.a("PUSH self")
        self.a("CALL PyXFunction_GetClosure")
        self.emit_py_error_check(4)
        self.a("MOV v, EAX")
        
        for i in range(freevars):
            self.debugPrintRt("Setting cellvar%s to None" % (i + cellvars),2)
            self.a("PUSH %s" % i)
            self.a("PUSH v")
            self.a("CALL PyTuple_GetItem")
            self.emit_py_error_check(8)
            self.emit_incref_reg()
            self.a("MOV cellvar%s, EAX" % (i + cellvars))

    def emit_var_values(self,argcount,varcount):
        """
        Load all arguments and put PyNone as a placeholder in uninitialized vars
        """
        if self.co_type != 'normal': return
        if argcount == 0 and varcount == 0: return

        loop = self.getTempLabel("loopStart")
        defaults = self.getTempLabel("defaults")
        defaultsLoop = self.getTempLabel("defaultsLoop")
        varsLoop = self.getTempLabel("varsLoop")
        exit = self.getTempLabel("exit")

        self.a("PUSH EDX")
        self.a("PUSH EBX")

        self.a("MOV EDX,0")
        self.a("MOV EBX, EBP")
        self.a("SUB EBX, %s" % (self.varZeroOffset+4))
        self.varZeroOffset = None
        
        self.a.AIL(loop)
        self.a("PUSH EDX")

        self.a("PUSH EDX")
        self.a("PUSH args")
        self.a("CALL PyTuple_GetItem")

        # if there's an error, ignore it and try defaults
        # TODO: properly check for index out of range error
        self.a("ADD ESP, 8")
        self.a("POP EDX")

        self.a("TEST EAX,EAX")
        self.a("JZ %s" % defaults) # ran out of args passed in

        self.emit_incref_reg()
        self.a("MOV [EBX], EAX")
        self.a("ADD EDX,0x1")
        self.a("SUB EBX,0x4")

        self.a("CMP EDX, %s" % argcount)
        self.a("JL %s" % loop)
        self.a("JMP %s" % varsLoop)

        self.a.AIL(defaults)
        # plug in defaults if we need to.

        self.a("PUSH EDX")
        self.a("PUSH EBX")
        self.a("CALL PyErr_Clear")
        self.a("POP EBX")
        self.a("POP EDX")

        # get defaults list
        self.a("!CALL PyXFunction_GetDefaults self")
        #self.emit_py_error_check(4)
        self.a("ADD ESP,4") #can't use emit_py_error_check: NULL == no defaults
        self.a("TEST EAX,EAX")
        self.a("JZ %s" % varsLoop)
        self.a("MOV v,EAX")

        #calculate how many defaults we need to get
        self.a("ADD EAX, %s" % ob_size)
        self.a("MOV EAX,[EAX]")
        self.a("MOV w, EAX")

        #adjust defaults indexes accordingly
        self.a("SUB EDX, %s" % argcount)
        self.a("ADD EDX, w")

        self.a.AIL(defaultsLoop)

        self.a("PUSH EDX")
        self.a("PUSH v")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)

        self.emit_incref_reg()
        self.a("MOV [EBX], EAX")

        self.a("ADD EDX,0x1")
        self.a("SUB EBX,0x4")
        self.a("CMP EDX, w")
        self.a("JL %s" % defaultsLoop)

        self.a("CMP EDX, %s" % varcount)
        self.a("JL %s" % varsLoop)

        self.emit_decref_var("v")
        self.a("JMP %s" % exit)

        self.a.AIL(varsLoop)

        self.a("PUSH EDX")

        self.emit_none()

        self.a("POP EDX")

        self.a("MOV [EBX], EAX")
        self.a("ADD EDX,0x1")
        self.a("SUB EBX,0x4")

        self.a("CMP EDX, %s" % varcount)
        self.a("JL %s" % varsLoop)

        self.a.AIL(exit)

        self.a("POP EBX")
        self.a("POP EDX")


    def emit_c_error_check(self,stackSize=0,autoCleanup=True,errorCallback=None):
        """
        If something returning a c-style int error code, 0 is good
        """
        tempLabel = self.getTempLabel("c_error_check")
        
        self.a("TEST EAX,EAX")
        self.a("JZ %s" % tempLabel)
        self.debugPrintRt("C ERROR!",1)
        if errorCallback:
            errorCallback(self.a)
        if stackSize:
            self.a("ADD ESP,%s" % stackSize)
        self.a("MOV EAX,0") # or else the interpreter thinks this is a pointer.
        self.a('JMP %s' % self.currentExitFunc)
        self.a.AIL("%s" % tempLabel)
        if autoCleanup:
            self.a("ADD ESP, %s" % stackSize)
            
    def emit_py_error_check(self,stackSize=0,autoCleanup=True,errorCallback=None):
        """
        If something returning a PyObject* returns null there is an error
        """
        tempLabel = self.getTempLabel("py_error_check")
        
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % tempLabel)
        if errorCallback:
            errorCallback(self.a)
        if stackSize:
            self.a("ADD ESP,%s" % stackSize)
        self.debugPrintRt("PY_ERROR!",1)

        exitPoint = self.currentExitFunc

        #look for exception handler
        for i in range(len(self.blocks)-1,-1,-1):
            typ,offset = self.blocks[i]
            if typ in (opcode.opmap['SETUP_EXCEPT'], opcode.opmap['SETUP_FINALLY']):
                self.debugPrintCt("FOUND BLOCK",2)
                exitPoint = offset
                break

        if exitPoint != self.currentExitFunc: # add info to the stack
            goodTB = self.getTempLabel("goodTB")
            self.a("CALL PyThreadState_Get")
            self.a("PUSH [EAX+48]") # curexc_traceback

            self.a("POP ECX")
            self.a("TEST ECX,ECX")
            self.a("JNZ %s" % goodTB)
            self.a("PUSH EAX")
            
            self.emit_none()
            self.a("MOV ECX,EAX")
            self.a("POP EAX")
            
            self.a.AIL(goodTB)
            self.a("PUSH ECX")            
            self.a("PUSH [EAX+44]") # curexc_value
            self.emit_incref_var("[EAX+44]")
            self.a("PUSH [EAX+40]") # curexc_type
            self.emit_incref_var("[EAX+40]")
            
            self.a("MOV [EAX+48],0") # set to null
            self.a("MOV [EAX+44],0") # set to null
            self.a("MOV [EAX+40],0") #  set to null
            self.a("MOV EAX,0")
            self.a("CALL PyErr_Clear")
        
        self.a('JMP %s' % exitPoint)
        self.a.AIL("%s" % tempLabel)

        if autoCleanup:
            self.a("ADD ESP, %s" % stackSize)


    #
    # create py_objects, mostly for consts
    # since we may do static compilation, we cant just reuse
    # the co.co_consts
    #
    def emit_float(self,val):
        """ Emit float from string, leave results on EAX"""
        if type(val) != str:
            val = repr(val)
        tempLabel = self.getTempLabel("float")
        self.a.ADStr(tempLabel,"%s\0" % val)
        self.a("PUSH 0")
        self.a("PUSH %s" % tempLabel)
        self.a("CALL PyString_FromString")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
        self.a('CALL PyFloat_FromString')
        self.emit_py_error_check(8)

    def emit_long(self,val):
        """Result saved in EAX"""
        if type(val) != str:
            val = repr(val)
        tempLabel = self.getTempLabel("string")
        self.a.ADStr(tempLabel,"%s\0" % val)
        self.a("PUSH 0")
        self.a("PUSH 0")
        self.a("PUSH %s" % tempLabel)
        self.a('CALL PyLong_FromString')
        self.emit_py_error_check(12)

    def emit_int(self,val):
        """Result saved in EAX"""
        if type(val) != int:
            raise Exception("Can't coerce %s into int" % val)
        self.a("MOV EAX,%s" %  val)
        self.a("PUSH EAX")
        self.a('CALL PyInt_FromLong')
        self.emit_py_error_check(4)

    def emit_string(self,val):
        """Result saved in EAX"""
        tempLabel = self.getTempLabel("string")
        if type(val) != str:
            val = repr(val)
        if val[-1] != "\0":
            val += "\0"
        self.debugPrintRt("VAL IS %s"% repr(val),10)
        self.a.ADStr(tempLabel,val)
        self.a("PUSH %s" % tempLabel)
        self.a('CALL PyString_FromString')
        # need to do this better for strings with Quotes, etc
        self.emit_py_error_check(4)

    def emit_none(self):
        """Result saved in EAX"""
        if self.primary_co_type in ("module", "exe"):
            self.a("MOV EAX, PyNone")
        else:
            self.a("MOV EAX, _Py_NoneStruct")
        self.emit_incref_reg()

    def emit_tuple(self,tup):
        if type(tup) != tuple:
            raise Exception("Can't coerce type %s to tuple" % type(tup))
        tup = list(tup)
        tup.reverse() # pack from right to left
        for item in tup:
            self.emit_py_object(item)
            self.a('PUSH EAX')
        self.a("MOV EAX,%s" % len(tup))
        self.a("PUSH EAX")
        self.a('CALL PyTuple_Pack')
        self.emit_py_error_check((len(tup) * 4) + 4)

    def emit_code_object(self, val):
        tempLabel = self.getTempLabel("code_object")
        tup = (val, tempLabel)
        self.code_objects.append(tup)

        self.a("PUSH %s" % len(val.co_freevars))

        self.a("PUSH %s" % tempLabel)
        self.a("CALL PyXCode_New")
        self.emit_py_error_check(8)

    def emit_py_object(self,val):
        typ = type(val)
        if typ == int:
            self.emit_int(val)
        elif typ == float:
            self.emit_float(val)
        elif typ == long:
            self.emit_long(val)
        elif typ == str:
            self.emit_string(val)
        elif typ == type(None):
            self.emit_none()
        elif typ == tuple:
            self.emit_tuple(val)
        elif typ == codeType:
            self.emit_code_object(val)
        else:
            raise Exception("COULDN'T RESOVLE TYPE %s" % typ)

    #
    # end create pyobjects
    #


    #
    # Reference count helpers, incref, decref
    #

    def emit_incref_reg(self,regname='EAX'):
        self.debugPrintRt("INCREF_REG",2)
        self.a("ADD [%s + %s], 0x1" % (regname,ob_refcnt))

    def emit_incref_var(self,varname):
        self.debugPrintRt("INCREF_VAR",2)
        self.a("PUSH EAX")
        self.a("MOV EAX,%s" % varname)
        self.emit_incref_reg()
        self.a("POP EAX")

    def emit_decref_reg(self,regname='EAX'):
        self.debugPrintRt("DECREF_REG",2)
        self.debugPrintRt("DECREF_REG Trying to subtract SUB [%s + %s], 0x1" % (regname, ob_refcnt),1)

        exit_decref_reg = self.getTempLabel("edr")
        test_for_negative = self.getTempLabel('tfn')

        self.a("SUB [%s + %s], 0x1" % (regname, ob_refcnt))
        self.a("JS %s" % test_for_negative)
        self.a("CMP [%s + %s], 0"% (regname, ob_refcnt))
        self.a("JNZ %s" % test_for_negative)

        #dealloc
        self.debugPrintRt("deallocating object",1)
        self.a("PUSH EAX")
        self.a("PUSH %s" % regname)

        if debugBuild:
            self.a("CALL _Py_Dealloc")
            self.a("ADD ESP,4")
            self.a("POP EAX")
        else:
            self.a("MOV EAX, [%s + %s]" % (regname, ob_type))
            self.a("ADD EAX, %s" % tp_dealloc)
            self.a("CALL [EAX]")
            self.a("ADD ESP,4")
            self.a("POP EAX")


        self.a("JMP %s" % exit_decref_reg)

        #TODO: Make debug flag
        self.a.AIL(test_for_negative)
        self.a("CMP [%s + %s], 0"% (regname, ob_refcnt))
        self.a("JNS %s" % exit_decref_reg)
        self.debugPrintRt("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NEGATIVE REF COUNT!!!!!!!!!!!!!!!!!!!!!")
        

        
        #exit        
        self.a.AIL(exit_decref_reg)

    def emit_decref_var(self,varname):
        self.debugPrintRt("DECREF_VAR",2)
        self.a("PUSH EAX")
        self.a("MOV EAX,%s" % varname)
        self.emit_decref_reg()
        self.a("POP EAX")
        
    #
    # end reference count helpers
    #

    ###
    ### OPCODE IMPLEMENTATION
    ###

    """

    STOP_CODE 
    Indicates end-of-code to the compiler, not used by the interpreter. 

    """

    def NOP(self):
        """Do nothing code. Used as a placeholder by the bytecode optimizer. """
        self.debugPrintRt("NOP",1)


    def POP_TOP(self):
        """ Removes the top-of-stack (TOS) item. """
        self.debugPrintRt("POP_TOP")
        self.a("POP EAX")
        self.emit_decref_reg()

    def ROT_TWO(self):
        """ Swaps the two top-most stack items. """
        self.debugPrintRt("ROT_TWO",1)
        self.a("POP v")
        self.a("POP w")
        self.a("PUSH v")
        self.a("PUSH w")

    def ROT_THREE(self):
        """
        Lifts second and third stack item one position up, moves top down to position
        three.
        """
        self.debugPrintRt("ROT_THREE",1)
        self.a("POP v")
        self.a("POP w")
        self.a("POP x")
        self.a("PUSH v")
        self.a("PUSH x")
        self.a("PUSH w")

    """
    ROT_FOUR 
    Lifts second, third and forth stack item one position up, moves top down to
    position four. 

    """
    def DUP_TOP(self):
        """Duplicates the reference on top of the stack."""
        self.debugPrintRt("DUP_TOP",1)
        self.a("POP EAX")
        self.emit_incref_reg()
        self.a("PUSH EAX")
        self.a("PUSH EAX")

    """
    Unary Operations take the top of
    the stack, apply the operation, and push the result back on the stack. 
    """
    
    
    def UNARY_POSITIVE(self):
        """Implements TOS = +TOS. """
        self.debugPrintRt("UNARY_POSITIVE",1)
        self.a("CALL PyNumber_Positive")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")

    def UNARY_NEGATIVE(self):
        """ Implements TOS = -TOS. """
        self.debugPrintRt("UNARY_NEGATIVE",1)
        self.a("CALL PyNumber_Negative")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")

    def UNARY_NOT(self):
        """Implements TOS = not TOS. """
        self.debugPrintRt("UNARY_NOT",1)
        tempLabel = self.getTempLabel("unary_not_false")
        tempLabel2 = self.getTempLabel("unary_not_done")
        self.a("CALL PyObject_IsTrue")
        self.a("ADD ESP,0x4")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % tempLabel)
        
        self.a("MOV EAX, _Py_TrueStruct")
        self.a("JMP %s" % tempLabel2)

        self.a.AIL(tempLabel)        
        self.a("MOV EAX, _Py_ZeroStruct")

        self.a.AIL(tempLabel2)
        self.emit_incref_reg()
        self.a("PUSH EAX")

    def UNARY_CONVERT(self):
        """Implements TOS = `TOS`. """
        self.debugPrintRt("UNARY_CONVERT",1)
        self.a("CALL PyObject_Repr")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
        
    def UNARY_INVERT(self):
        """Implements TOS = ~TOS. """
        self.debugPrintRt("UNARY_INVERT",1)
        self.a("CALL PyNumber_Invert")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
        
    def GET_ITER(self):
        """Implements TOS = iter(TOS). """
        self.debugPrintRt("GET_ITER",1)
        self.a("POP w")
        self.a("PUSH w") #TOP() duplicate
        self.a("PUSH w")
        self.a("CALL PyObject_GetIter")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
    
    """
    Binary operations remove the top of the stack (TOS) and the second top-most
    stack item (TOS1) from the stack. They perform the operation, and put the
    result back on the stack. 
    """

    def emit_binary_op(self, opFunction):
        """
        We have to swap TOS and TOS1 before calling the function
        """
        self.a("POP v")
        self.a("POP w")
        self.a("PUSH v")
        self.a("PUSH w")
        self.a("CALL %s" % opFunction)
        self.emit_py_error_check(8)
        self.emit_decref_var("w")
        self.emit_decref_var("v")
        self.a("PUSH EAX")

    def BINARY_POWER(self):
        """Implements TOS = TOS1 ** TOS. """
        self.debugPrintRt("BINARY_POWER",1)
        self.emit_binary_op("PyNumber_Power")

    def BINARY_MULTIPLY(self):
        """Implements TOS = TOS1 * TOS. """
        self.debugPrintRt("BINARY_MULTIPLY",1)
        self.emit_binary_op("PyNumber_Multiply")

    def BINARY_DIVIDE(self):
        """Implements TOS = TOS1 / TOS when from __future__ import division is not in effect. """
        self.debugPrintRt("BINARY_DIVIDE",1)
        self.emit_binary_op("PyNumber_Divide")

    
    def BINARY_FLOOR_DIVIDE(self):
        """Implements TOS = TOS1 // TOS."""
        self.debugPrintRt("BINARY_FLOOR_DIVIDE",1)
        self.emit_binary_op("PyNumber_FloorDivide")
        
        
    def BINARY_TRUE_DIVIDE(self): 
        """Implements TOS = TOS1 / TOS when from __future__ import division is in effect. """
        self.debugPrintRt("BINARY_TRUE_DIVIDE",1)
        self.emit_binary_op("PyNumber_TrueDivide")

    def BINARY_MODULO(self):
        """ Implements TOS = TOS1 % TOS. """
        self.debugPrintRt("BINARY_MODULO",1)
        self.emit_binary_op("PyNumber_Remainder")

    def BINARY_ADD(self):
        """Implements TOS = TOS1 + TOS. """
        self.debugPrintRt("BINARY_ADD",1)
        self.emit_binary_op("PyNumber_Add")
   
    def BINARY_SUBTRACT(self):
        """Implements TOS = TOS1 - TOS. """
        self.debugPrintRt("BINARY_SUBTRACT",1)
        self.emit_binary_op("PyNumber_Subtract")
        

    def BINARY_SUBSCR(self): 
        """Implements TOS = TOS1[TOS]. """
        self.debugPrintRt("BINARY_SUBSCR",1)
        self.emit_binary_op("PyObject_GetItem")

    def BINARY_LSHIFT(self):
        """Implements TOS = TOS1 << TOS."""
        self.debugPrintRt("BINARY_LSHIFT",1)
        self.emit_binary_op("PyNumber_Lshift")

    def BINARY_RSHIFT (self):
        """Implements TOS = TOS1 >> TOS. """
        self.debugPrintRt("BINARY_RSHIFT",1)
        self.emit_binary_op("PyNumber_Rshift")

    def BINARY_AND(self): 
        """Implements TOS = TOS1 & TOS. """
        self.debugPrintRt("BINARY_AND",1)
        self.emit_binary_op("PyNumber_And")
        
    def BINARY_XOR(self): 
        """Implements TOS = TOS1 ^ TOS. """
        self.debugPrintRt("BINARY_XOR",1)
        self.emit_binary_op("PyNumber_Xor")
        
    def BINARY_OR (self):
        """Implements TOS = TOS1 | TOS. """
        self.debugPrintRt("BINARY_OR",1)
        self.emit_binary_op("PyNumber_Or")
        
    """
    In-place operations are like binary operations, in that they remove TOS and
    TOS1, and push the result back on the stack, but the operation is done in-place
    when TOS1 supports it, and the resulting TOS may be (but does not have to be)
    the original TOS1. 
    """

    def emit_inplace_op(self, opFunction):
        """ """
        self.emit_binary_op(opFunction)

    
    def INPLACE_POWER(self): 
        """Implements in-place TOS = TOS1 ** TOS."""
        self.debugPrintRt("INPLACE_POWER",1)
        self.a("POP v")
        self.a("POP w")
        self.emit_none()
        self.a("MOV x, EAX")
        self.a("PUSH x")
        self.a("PUSH v")
        self.a("PUSH w")
        self.a("CALL PyNumber_InPlacePower")
        self.emit_py_error_check(12)
        self.emit_decref_var("x")
        self.emit_decref_var("v")
        self.emit_decref_var("w")
        self.a("PUSH EAX")
    
    def INPLACE_MULTIPLY(self): 
        """Implements in-place TOS = TOS1 * TOS. """
        self.emit_inplace_op("PyNumber_InPlaceMultiply")

    def INPLACE_DIVIDE (self):
        """
        Implements in-place TOS = TOS1 / TOS when from __future__ import division is
        not in effect.
        """
        self.emit_inplace_op("PyNumber_InPlaceDivide")

    def INPLACE_FLOOR_DIVIDE(self):
        """Implements in-place TOS = TOS1 // TOS. """
        self.emit_inplace_op("PyNumber_InPlaceFloorDivide")

    def INPLACE_TRUE_DIVIDE(self):
        """Implements in-place TOS = TOS1 / TOS when from __future__ import division is in effect. """
        self.emit_inplace_op("PyNumber_InPlaceTrueDivide")

    def INPLACE_MODULO(self): 
        """Implements in-place TOS = TOS1 % TOS. """
        self.emit_inplace_op("PyNumber_InPlaceRemainder")

    def INPLACE_ADD(self):
        """Implements in-place TOS = TOS1 + TOS. """
        self.emit_inplace_op("PyNumber_InPlaceAdd")

    def INPLACE_SUBTRACT(self):
        """Implements in-place TOS = TOS1 - TOS. """
        self.emit_inplace_op("PyNumber_InPlaceSubtract")

    def INPLACE_LSHIFT(self):
        """Implements in-place TOS = TOS1 << TOS. """
        self.emit_inplace_op("PyNumber_InPlaceLshift")

    def INPLACE_RSHIFT(self):
        """Implements in-place TOS = TOS1 >> TOS. """
        self.emit_inplace_op("PyNumber_InPlaceRshift")

    def INPLACE_AND(self):
        """Implements in-place TOS = TOS1 & TOS. """
        self.emit_inplace_op("PyNumber_InPlaceAnd")

    def INPLACE_XOR(self):
        """Implements in-place TOS = TOS1 ^ TOS. """
        self.emit_inplace_op("PyNumber_InPlaceXor")

    def INPLACE_OR(self):
        """Implements in-place TOS = TOS1 | TOS. """
        self.emit_inplace_op("PyNumber_InPlaceOr")

    """
    The slice opcodes take up to three parameters. 
    """

    def SLICE_0(self):
        """Implements TOS = TOS[:].""" 
        self.debugPrintRt("SLICE+0", 1)
        self.a("POP w")
        self.a("PUSH 0x7fffffff")
        self.a("PUSH 0")
        self.a("PUSH w")
        self.a("CALL PySequence_GetSlice")
        self.emit_py_error_check(12)
        self.emit_decref_var("w")
        self.a("PUSH EAX")
        
    
    def SLICE_1(self):
        """Implements TOS = TOS1[TOS:]. """
        self.debugPrintRt("SLICE+1", 1)
        #self.a("POP w")
        self.a("POP x")
        self.a("PUSH x")
        self.a("CALL PyInt_AsLong")
        self.emit_py_error_check(4)
        self.a("MOV w, EAX")
        self.emit_decref_var("x")
        
        self.a("POP v")
        self.a("PUSH 0x7fffffff")
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PySequence_GetSlice")
        self.emit_py_error_check(12)
        self.emit_decref_var("v")
        self.a("PUSH EAX")

    def SLICE_2(self):
        """ Implements TOS = TOS1[:TOS].  """
        self.debugPrintRt("SLICE+2", 1)
        #self.a("POP w")
        self.a("POP x")
        self.a("PUSH x")
        self.a("CALL PyInt_AsLong")
        self.emit_py_error_check(4)
        self.a("MOV w, EAX")
        self.emit_decref_var("x")
        
        self.a("POP v")
        self.a("PUSH w")
        self.a("PUSH 0")
        self.a("PUSH v")
        self.a("CALL PySequence_GetSlice")
        self.emit_py_error_check(12)
        self.emit_decref_var("v")
        self.a("PUSH EAX")
        

    def SLICE_3(self): 
        """Implements TOS = TOS2[TOS1:TOS]. """
        self.debugPrintRt("SLICE+3", 1)
        #self.a("POP w")
        self.a("POP x")
        self.a("PUSH x")
        self.a("CALL PyInt_AsLong")
        self.emit_py_error_check(4)
        self.a("MOV w, EAX")
        self.emit_decref_var("x")

        self.a("POP t")
        self.a("PUSH t")        
        self.a("CALL PyInt_AsLong")
        self.emit_py_error_check(4)
        self.a("MOV x, EAX")
        self.emit_decref_var("t")
        
        self.a("POP v")
        self.a("PUSH w")
        self.a("PUSH x")
        self.a("PUSH v")
        self.a("CALL PySequence_GetSlice")
        self.emit_py_error_check(12)
        self.emit_decref_var("v")
        self.a("PUSH EAX")
    """
    Slice assignment needs even an additional parameter. As any statement, they put nothing on the stack. 
    """

    def STORE_SLICE_0(self):
        """Implements TOS[:] = TOS1. """
        self.debugPrintRt("STORE_SLICE+0", 1)
        self.a("POP w")
        self.a("POP x")
        #null
        self.a("PUSH 0")
        #index high
        self.a("PUSH 0")
        #index low
        self.a("PUSH 0")
    
        self.a("CALL PySlice_New")
        self.emit_py_error_check(12)

        self.debugPrintRt("Got New Slice",1)

        self.a("PUSH x")
        self.a("PUSH EAX")
        self.a("PUSH w")
        
        self.a("CALL PyObject_SetItem")
        self.emit_c_error_check(12)

        self.emit_decref_var("x")
        self.emit_decref_var("w")
 
        self.debugPrintRt("Set item",1)        
        

    def STORE_SLICE_1(self):
        """Implements TOS1[TOS:] = TOS2. """
        self.debugPrintRt("STORE_SLICE+1", 1)
        self.a("POP w")
        self.a("POP x")
        self.a("POP v")
        #null
        self.a("PUSH 0")
        #index high
        self.a("PUSH 0")
        #index low
        self.a("PUSH w")
    
        self.a("CALL PySlice_New")
        self.emit_py_error_check(12)

        self.debugPrintRt("Got New Slice",1)

        self.a("PUSH v")
        self.a("PUSH EAX")
        self.a("PUSH x")
        
        self.a("CALL PyObject_SetItem")
        self.emit_c_error_check(12)

        self.emit_decref_var("v")
        self.emit_decref_var("x")
        self.emit_decref_var("w")
 
        self.debugPrintRt("Set item",1)
        
    
    def STORE_SLICE_2(self):
        """ Implements TOS1[:TOS] = TOS2. """
        self.debugPrintRt("STORE_SLICE+2", 1)
        self.a("POP w")
        self.a("POP x")
        self.a("POP v")
        #null
        self.a("PUSH 0")
        #index high
        self.a("PUSH w")
        #index low
        self.a("PUSH 0")
    
        self.a("CALL PySlice_New")
        self.emit_py_error_check(12)

        self.debugPrintRt("Got New Slice",1)

        self.a("PUSH v")
        self.a("PUSH EAX")
        self.a("PUSH x")
        
        self.a("CALL PyObject_SetItem")
        self.emit_c_error_check(12)

        self.emit_decref_var("w")
        self.emit_decref_var("v")
        self.emit_decref_var("x")
 
        self.debugPrintRt("Set item",1)

    def STORE_SLICE_3(self):
        """ Implements TOS2[TOS1:TOS] = TOS3. """
        self.debugPrintRt("STORE_SLICE+3", 1)
        self.a("POP w")
        self.a("POP x")
        self.a("POP v")
        self.a("POP t")
        #null
        self.a("PUSH 0")
        #index high
        self.a("PUSH w")
        #index low
        self.a("PUSH x")
    
        self.a("CALL PySlice_New")
        self.emit_py_error_check(12)

        self.debugPrintRt("Got New Slice",1)

        self.a("PUSH t")
        self.a("PUSH EAX")
        self.a("PUSH v")
        
        self.a("CALL PyObject_SetItem")
        self.emit_c_error_check(12)

        self.emit_decref_var("w")
        self.emit_decref_var("x")
        self.emit_decref_var("v")
        self.emit_decref_var("t")

        self.debugPrintRt("Set item",1)


    def DELETE_SLICE_0(self):
        """ Implements del TOS[:]. """
        self.debugPrintRt("DELETE_SLICE+0", 1)
        self.a("POP w")

        #index high
        self.a("PUSH %s" % sys.maxint)
        
        #index low
        self.a("PUSH 0")

        self.a("PUSH w")
        
        self.a("CALL PySequence_DelSlice")
        self.emit_c_error_check(12)

        self.emit_decref_var("w")
 
        self.debugPrintRt("Set item",1)        

    
    def DELETE_SLICE_1(self): 
        """Implements del TOS1[TOS:]. """
        self.debugPrintRt("DELETE_SLICE+1", 1)
        self.a("POP w")
        self.a("POP v")

        #index high
        self.a("PUSH %s"% sys.maxint)
        
        #index low
        self.a("PUSH w")
        self.a("CALL PyInt_AsLong")
        self.a("ADD ESP,0x4")  # returns int, not error code
        self.a("PUSH EAX")

        self.a("PUSH v")
        
        self.a("CALL PySequence_DelSlice")
        self.emit_c_error_check(12)

        self.emit_decref_var("w")
        self.emit_decref_var("v")
 
        self.debugPrintRt("Set item",1)       

    def DELETE_SLICE_2(self):
        """Implements del TOS1[:TOS]. """
        self.debugPrintRt("DELETE_SLICE+2", 1)
        self.a("POP w")
        self.a("POP v")

        #index high
        self.a("PUSH w")
        self.a("CALL PyInt_AsLong")
        self.a("ADD ESP,0x4") # returns int, not error code
        self.a("PUSH EAX")

        #index low
        self.a("PUSH 0")

        self.a("PUSH v")
        
        self.a("CALL PySequence_DelSlice")
        self.emit_c_error_check(12)

        self.emit_decref_var("w")
        self.emit_decref_var("v")
 
        self.debugPrintRt("Set item",1)     


    def DELETE_SLICE_3(self):
        """Implements del TOS2[TOS1:TOS]. """
        self.debugPrintRt("DELETE_SLICE+3", 1)
        self.a("POP w")
        self.a("POP v")
        self.a("POP u")
        #null
        #index high
        self.a("PUSH w")
        self.a("CALL PyInt_AsLong")
        self.a("ADD ESP,0x4") # returns int, not error code
        self.a("PUSH EAX")

        #index low
        self.a("PUSH v")
        self.a("CALL PyInt_AsLong")
        self.a("ADD ESP,0x4") # returns int, not error code
        self.a("PUSH EAX")

        self.a("PUSH u")
        
        self.a("CALL PySequence_DelSlice")
        self.emit_c_error_check(12)

        self.emit_decref_var("w")
        self.emit_decref_var("v")
        self.emit_decref_var("u")
 
        self.debugPrintRt("Set item",1)     

    def STORE_SUBSCR(self):
        """Implements TOS1[TOS] = TOS2. """
        self.debugPrintRt("STORE_SUBSCR",1)
        
        self.a("POP w")
        self.a("POP v")
        self.a("POP u")

        self.a("PUSH u")
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PyObject_SetItem")
        self.emit_c_error_check(12)
        self.emit_decref_var("u")
        self.emit_decref_var("w")
        self.emit_decref_var("v")

    def DELETE_SUBSCR (self):
        """Implements del TOS1[TOS]. """
        self.debugPrintRt("DELETE_SUBSCR")
        self.a("POP w")
        self.a("POP v")
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PyObject_DelItem")
        self.emit_c_error_check(8)
        self.emit_decref_var("w")
        self.emit_decref_var("v")

    """
    Miscellaneous opcodes. 
    """

    def PRINT_EXPR(self):
        """
        Implements the expression statement for the interactive mode. TOS is removed
        from the stack and printed. In non-interactive mode, an expression statement is
        terminated with POP_STACK.
        """
        self.debugPrintRt("PRINT_EXPR",1)
        
        #self.a("CALL PySys_WriteStdout")
        #self.a("ADD ESP, 0x4")
        self.a("POP v")
        #self.a('MOV v, ESP')
        self.a('!CALL PySys_GetObject "displayhook\\0"')
        self.emit_py_error_check(4)
        self.a('MOV w, EAX')

        self.debugPrintRt("    Got Display Hook",2)
        
        self.a("PUSH v")
        self.a("PUSH 1")

        self.debugPrintRt("    pre Packed tuple",2)
        self.a('CALL PyTuple_Pack')
        self.emit_py_error_check(8)
        self.a('MOV x, EAX')
        self.debugPrintRt("    Return from PyTuplePack",2)
        
        
        self.a('!CALL PyEval_CallObject w x')
        self.emit_py_error_check(8)
        self.debugPrintRt("    Called display hook with tuple",2)
        

    def PRINT_ITEM(self,to=False):
        """
        Prints TOS to the file-like object bound to sys.stdout. There is one such
        instruction for each item in the print statement.
        """
        softspaceName = self.getTempLabel("softspace")
        
        self.debugPrintRt("PRINT_ITEM",1)
        if to:
            self.a("POP w")
        else:
            self.a('!CALL PySys_GetObject "stdout\\0"')
            self.emit_py_error_check(4)
            self.emit_incref_reg()
            self.a("MOV w,EAX")
            
        self.a("POP v")
        
        self.debugPrintRt("    Calling softspace",2)
        self.a("PUSH 0")
        self.a("PUSH w")
        self.a("CALL PyFile_SoftSpace")
        self.a("ADD ESP,8") # returns a valie, not an error code

        self.a("CMP EAX,0")
        self.a("JE %s" % softspaceName)
        
        self.a("PUSH w")
        self.a('PUSH " \\0"')
        self.a("CALL PyFile_WriteString")
        self.debugPrintRt("    Got back from PyFile_WriteString",2)
        self.emit_c_error_check(8)

        self.a.AIL(softspaceName)
        
        self.a("PUSH 1")
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PyFile_WriteObject")
        self.debugPrintRt("    got back from write object",2)
        self.emit_c_error_check(12)

        self.a("PUSH 1")
        self.a("PUSH w")
        self.a("CALL PyFile_SoftSpace")
        self.a("ADD ESP,8") #returns a value, not an error code

        self.debugPrintRt("    wrote object",2)


    def PRINT_ITEM_TO(self):
        """
        Like PRINT_ITEM, but prints the item second from TOS to the file-like object at
        TOS. This is used by the extended print statement. 
        """
        self.PRINT_ITEM(to=True)
        
    def PRINT_NEWLINE(self,to=False):
        """
        Prints a new line on sys.stdout. This is generated as the last operation of a
        print statement, unless the statement ends with a comma.
        """
        
        self.debugPrintRt("PRINT_NEWLINE",1)

        if to:
            self.a("POP w")
        else:
            self.a('!CALL PySys_GetObject "stdout\\0"')
            self.emit_py_error_check(4)
            self.debugPrintRt("Got stdout",2)
            self.a("MOV w, EAX")
        self.a("PUSH w")
        self.a('PUSH newline')
        self.a("CALL PyFile_WriteString")
        self.debugPrintRt("Got back from PyFile_WriteString",2)
        self.emit_c_error_check(8)
        self.debugPrintRt("    No Error",2)

        self.debugPrintRt("    CAlling softspace",2)
        self.a("PUSH 0")
        self.a("PUSH w")
        self.a("CALL PyFile_SoftSpace")
        self.a("ADD ESP,8") # this returns a value, not an error code
        #self.emit_error_check()
        self.debugPrintRt("Wrote newline",2)
        

    def PRINT_NEWLINE_TO(self):
        """
        Like PRINT_NEWLINE, but prints the new line on the file-like object on the TOS.
        This is used by the extended print statement. 
        """
        self.PRINT_NEWLINE(to=True)
        
    def BREAK_LOOP(self):
        """
        Terminates a loop due to a break statement.
        """
        self.debugPrintRt("BREAK_LOOP",1)
        for i in range(len(self.blocks)-1,-1,-1):
            block = self.blocks[i]
            self.debugPrintRt("TRYING %s %s" % block,3)
            if block[0] == opcode.opmap['SETUP_LOOP']:
                self.debugPrintRt("FOUND MATCH",3)
                self.a("JMP %s" % block[1])
                break

                
            
    """
    CONTINUE_LOOP    target 
    Continues a loop due to a continue statement. target is the address to jump to
    (which should be a FOR_ITER instruction). 

    LIST_APPEND 
    Calls list.append(TOS1, TOS). Used to implement list comprehensions. 

    """

    def LOAD_LOCALS(self):
        """
        Pushes a reference to the locals of the current scope on the stack. This is
        used in the code for a class definition: After the class body is evaluated, the
        locals are passed to the class definition.
        """
        #self.a("ADD locals,1") # incref
        self.emit_incref_var("locals")
        self.a("PUSH locals")


    def RETURN_VALUE(self):
        """Returns with TOS to the caller of the function. """
        self.debugPrintRt("RETURN_VALUE",1)
        self.a("POP EAX")
        self.a("JMP %s" % self.currentExitFunc)

    """
    YIELD_VALUE 
    Pops TOS and yields it from a generator. 

    """
    
    def IMPORT_STAR(self):
        """
        Loads all symbols not starting with "_" directly from the module TOS to the
        local namespace. The module is popped after loading all names. This opcode
        implements from module import *.
        """
        self.debugPrintRt("IMPORT_STAR",1)
        addItems = self.getTempLabel("import_star_loop")
        exit = self.getTempLabel("import_star_exit")
        gotValue = self.getTempLabel("import_star_got_value")
        loopStart = self.getTempLabel("import_star_loop_start")
        loopEnd = self.getTempLabel("import_star_loop_end")
        addItem = self.getTempLabel("import_start_add_item")
        
        self.a("POP v") # module
        self.a("PUSH all")
        self.a("PUSH v")
        self.a("CALL PyObject_GetAttrString")
        self.a("ADD ESP,8")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % addItems) # had __all__

        self.a("CALL PyErr_Clear")
        self.a("PUSH dict")
        self.a("PUSH v")
        self.a("CALL PyObject_GetAttrString")
        self.a("ADD ESP,8")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % addItems) # had __dict__
        self.a('!CALL PyErr_SetString PyExc_ImportError "from-import-* object has no __dict__ or __all__\\0"')
        self.emit_c_error_check(0)

        self.a.AIL(addItems)
        self.a("MOV w,EAX") # w is dict-like item
        self.a("PUSH 0")
        self.a("PUSH keys")
        self.a("PUSH w")
        self.a("CALL PyObject_CallMethod")
        self.emit_py_error_check(12)
        self.a("MOV x, EAX") # keys

        self.a("MOV ECX,0")

        self.a.AIL(loopStart)
        self.a("PUSH ECX")
        self.a("PUSH x")
        self.a("CALL PySequence_GetItem")
        self.a("ADD ESP,8")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % addItem)
        self.a("CALL PyErr_Clear") #else we got a IndexOutOfRangeError
        self.a("JMP %s" % loopEnd)
        
        self.a.AIL(addItem)
        self.a("MOV u, EAX") # name
        self.a("PUSH u")
        self.a("PUSH v")
        self.a("CALL PyObject_GetAttr")
        self.debugPrintRt("Getting value",2)
        self.emit_py_error_check(8)
        self.debugPrintRt("GotValue",2)

        #TODO: UNDERSCORE CHECK
        
        self.a("MOV t,EAX") # value
        self.a("PUSH t") # value
        self.a("PUSH u") # name
        self.a("PUSH locals") #dest dict
        self.a("CALL PyDict_SetItem")
        self.debugPrintRt("PyDict_SetItem",2)
        self.emit_c_error_check(12)
        self.debugPrintRt("PyDict_SetItem SUcceeded",2)
        self.a("ADD ECX, 1")
        self.a("JMP %s" % loopStart)

        self.a.AIL(loopEnd)
        self.a.AIL(exit)
        
        
        
        
        
        

    """
    EXEC_STMT 
    Implements exec TOS2,TOS1,TOS. The compiler fills missing optional parameters
    with None. 

    """
    
    def POP_BLOCK(self):
        """
        Removes one block from the block stack. Per frame, there is a stack of blocks,
        denoting nested loops, try statements, and such.
        """
        self.debugPrintRt("POP_BLOCK")
        self.blocks.pop()

    def END_FINALLY(self):
        """
        Terminates a finally clause. The interpreter recalls whether the exception has
        to be re-raised, or whether the function returns, and continues with the
        outer-next block.
        """
        self.debugPrintRt("END_FINALLY",1)

        dontReraise = self.getTempLabel("end_finally_dont_reraise")
        classOrString = self.getTempLabel("end_finally_class_or_string")
        #TODO: Check for int why_code (when is this used)
        self.a("POP v")

        self.debugPrintRt("Checking for exception",2)
        self.emit_none()
        self.a("CMP v,EAX")
        self.a("JE %s" % dontReraise)

        self.a("MOV EAX,v")
        self.a("CMP [EAX+%s],%s" % (ob_type,id(type(1))))
        self.a("JNE %s" % classOrString)

        self.debugPrintRt("INT CODE",1)
        self.a("JMP %s" % dontReraise)

        self.a.AIL(classOrString)
        self.debugPrintRt("reraising finally",2)        
        self.a("POP w")
        self.a("POP u")
        #TODO: Get PyErr_Restore working right with traceback
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PyErr_SetObject")
        self.a("ADD ESP, 8")
        self.a("MOV EAX,0")

        self.emit_py_error_check(0)
        self.a.AIL(dontReraise)
        

    def BUILD_CLASS(self):
        """
        Creates a new class object. TOS is the methods dictionary, TOS1 the tuple of
        the names of the base classes, and TOS2 the class name.  All of the following
        opcodes expect arguments. An argument is two bytes, with the more significant
        byte last. 
        """
        self.debugPrintRt("BUILD_CLASS",1)
        self.a("POP w") # methods
        self.a("POP v") # bases
        self.a("POP u") # class name
        self.a("MOV EAX, %s" % id(type(self.__class__)))#"PyClass_Type")
        self.a("ADD [EAX],1") # refcount
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("PUSH u")
        self.a("PUSH build_class_OOO")
        self.a("PUSH EAX")
        self.debugPrintRt("Before call",1)
        self.a("CALL PyObject_CallFunction")
        self.debugPrintRt("Call function",1)
        self.emit_py_error_check(20)
        self.debugPrintRt("Dwored",1)

        self.emit_decref_var("w")
        self.emit_decref_var("v")
        self.emit_decref_var("u")
        
        self.a("PUSH EAX")
    
    def STORE_NAME(self,namei):
        """
        Implements name = TOS. namei is the index of name in the attribute co_names of
        the code object. The compiler tries to use STORE_LOCAL or STORE_GLOBAL if
        possible.
        """
        self.debugPrintRt("STORE_NAME %s" % namei,1)

        self.debugPrintRt("    Getting Name",2)
        
        self.a("PUSH %s" % namei)
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)
        self.debugPrintRt("    Got Name",2)

        self.debugPrintRt("    Setting value",2)        
        self.a("PUSH EAX")
        self.a("PUSH locals")
        self.a("CALL PyObject_SetItem")
        self.emit_c_error_check(12)
        self.debugPrintRt("    Set Value",2)
        
        
        
    """
    DELETE_NAME    namei 
    Implements del name, where namei is the index into co_names attribute of the
    code object. 

    """
    
    def UNPACK_SEQUENCE(self,count):
        """
        Unpacks TOS into count individual values, which are put onto the stack
        right-to-left.
        """

        self.debugPrintRt("UNPACK_SEQUENCE",1)

        try_list = self.getTempLabel("try_list")
        try_iterator = self.getTempLabel('try_iterator')
        exit = self.getTempLabel("exit")
        
        self.a("POP w")
        self.a("MOV EAX,w")
        self.a("CMP [EAX+%s],%s" % (ob_type,id(type((1,2)))))
        self.a("JNE %s" % try_list)
        for i in range(count-1,-1,-1):
            self.debugPrintRt("    Adding item %s" % i,2)
            self.a("PUSH %s" % i)
            self.a("PUSH w")
            self.a("CALL PyTuple_GetItem")
            self.emit_py_error_check(8)
            self.emit_incref_reg()
            self.a("PUSH EAX")
        self.a("JMP %s" % exit)

        self.a.AIL(try_list)
        self.a("CMP [EAX+%s],%s" % (ob_type,id(type([]))))
        self.a("JNE %s" % try_iterator)
        for i in range(count-1,-1,-1):
            self.debugPrintRt("    Adding item %s" % i,1)
            self.a("PUSH %s" % i)
            self.a("PUSH w")
            self.a("CALL PyList_GetItem")
            self.emit_py_error_check(8)
            self.emit_incref_reg()
            self.a("PUSH EAX")
        self.a("JMP %s" % exit)
        
        self.a.AIL(try_iterator)
        self.a("PUSH w")
        self.a("CALL PyObject_GetIter")
        self.emit_py_error_check(4)
        self.a("MOV x,EAX")
        for i in range(count):
            self.debugPrintRt("ITER %s" % i, 1)
            self.a("PUSH x")
            self.a("CALL PyIter_Next")
            self.emit_py_error_check(4)
            self.a("PUSH EAX")
            
        self.a.AIL(exit)
        self.emit_decref_var("w")
    
    """
    DUP_TOPX    count 
    Duplicate count items, keeping them in the same order. Due to implementation
    limits, count should be between 1 and 5 inclusive. 

    """
    def STORE_ATTR(self,namei):
        """Implements TOS.name = TOS1, where namei is the index of name in co_names. """
        self.debugPrintRt("STORE_ATTR")
        self.a("PUSH %s" % namei)
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)
        self.emit_incref_reg()
        self.a("MOV w,EAX")
        self.a("POP v")
        self.a("POP u")

        self.a("PUSH u")
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PyObject_SetAttr")
        self.emit_c_error_check(12)
        self.emit_decref_var("u")
        self.emit_decref_var("v")
        self.emit_decref_var("w")
        
    """
    DELETE_ATTR    namei 
    Implements del TOS.name, using namei as index into co_names. 

    """
    
    def STORE_GLOBAL(self,namei):
        """Works as STORE_NAME, but stores the name as a global. """
        self.debugPrintRt("STORE_GLOBAL",1)

        setValue = self.getTempLabel("store_global_set_value")
        clearError = self.getTempLabel("store_global_clear_value")
        
        self.debugPrintRt("    Getting Name",2)
        
        self.a("PUSH %s" % namei)
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)
        self.emit_incref_reg()
        self.a("MOV w, EAX")
        self.debugPrintRt("    Got Name",2)

        self.a("POP v")

        #store new one
        self.debugPrintRt("    Setting value",2)
        self.a("PUSH v")
        self.a("PUSH w")
        self.a("PUSH globals")
        self.a("CALL PyDict_SetItem")
        self.emit_c_error_check(12)
        self.debugPrintRt("    Set Value",2)
        self.emit_decref_var("w")
        self.emit_decref_var("v")

    """
    DELETE_GLOBAL    namei 
    Works as DELETE_NAME, but deletes a global name. 

    """
    def LOAD_CONST(self,consti):
        """Pushes "co_consts[consti]" onto the stack. """
        self.debugPrintRt("LOADING_CONST %s" % consti,1)
        self.a("MOV EAX, const%s" % consti)
        self.emit_incref_reg()
        self.a("PUSH EAX")
        self.debugPrintRt("Successfully loaded const",2)

    def emit_load_name_or_global(self,namei,typ):
        self.debugPrintRt("    Getting Name",2)

        skip_incref = self.getTempLabel("skip_incref")
        
        self.a("MOV EAX,%s" % namei)
        self.a("PUSH EAX")
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)
        self.debugPrintRt("    Got Name",2)

        self.emit_incref_reg()
        self.a("MOV w, EAX")

        self.debugPrintRt("    getting value",2)        
        self.a("PUSH EAX")
        self.a("PUSH %s" % typ)
        self.a("CALL PyObject_GetItem")
        self.debugPrintRt("    haven't checked for error yet",2)
        self.a("ADD ESP,8") #self.emit_py_error_check(8)
        self.a("CMP EAX,EAX") # should we do something like XINCREF?
        self.a("JZ %s" % skip_incref)
        self.emit_incref_reg()
        self.a.AIL(skip_incref)
        self.a("PUSH EAX")
        self.emit_decref_var("w")
        self.debugPrintRt("    Got Value",2)
        
    def LOAD_NAME(self,namei):
        """Pushes the value associated with "co_names[namei]" onto the stack. """
        self.debugPrintRt("LOAD_NAME %s" % namei,1)
        exit = globals = self.getTempLabel("load_name_exit")
        
        self.emit_load_name_or_global(namei,"locals")
        self.a("POP EAX")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % exit)
        self.debugPrintRt("didn't find local",1)
        self.a("CALL PyErr_Clear");

        self.emit_load_name_or_global(namei,"globals")
        self.a("POP EAX")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % exit)
        self.debugPrintRt("didn't find global",2)
        self.a("CALL PyErr_Clear");

        self.emit_load_name_or_global(namei,"builtins")
        self.a("POP EAX")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % exit)
        self.debugPrintRt("didn't find builtin",2)


        self.a.AIL(exit)
        self.debugPrintRt("exiting",2)
        self.emit_py_error_check(0)
        self.a("PUSH EAX")

    def emit_build_tuple_or_list(self, items, objName):
        self.a("PUSH %s" % items)
        self.a("CALL Py%s_New" % objName)
        self.emit_py_error_check(4)
        self.a("MOV w, EAX")
        for i in range(items-1,-1,-1):
            # the item to set is already on the top of the stack
            self.debugPrintRt("Adding item %s" % i,1)
            self.a("PUSH %s" % i)
            self.a("PUSH w")# list or tuple
            self.a("CALL Py%s_SetItem" % objName)
            self.emit_c_error_check(12)
        self.a("PUSH w")

    def emit_build_dynamic_tuple_or_list(self, objName):

        listLoop = self.getTempLabel("listLoop")
        exit = self.getTempLabel("exit")
        
        self.a("POP v") # number of items
        self.a("PUSH v")
        self.a("CALL Py%s_New" % objName)
        self.emit_py_error_check(4)
        self.a("MOV w, EAX")

        self.a.AIL(listLoop)
        self.a("SUB v,1")
        self.a("CMP v,-1")
        self.a("JZ %s" % exit)

        # the item to set is already on the top of the stack
        self.a("PUSH v")
        self.a("PUSH w")# list or tuple
        self.a("CALL Py%s_SetItem" % objName)
        self.emit_c_error_check(12)

        self.a("JMP %s" % listLoop)

        self.a.AIL(exit)
        self.a("PUSH w")

    def BUILD_TUPLE(self, count):
        """
        Creates a tuple consuming count items from the stack, and pushes the resulting
        tuple onto the stack.
        """
        self.debugPrintRt("BUILD_TUPLE",1)
        self.emit_build_tuple_or_list(count,"Tuple")

    def BUILD_LIST(self,count):
        """Works as BUILD_TUPLE, but creates a list. """
        self.debugPrintRt("BUILD_LIST",1)
        self.emit_build_tuple_or_list(count,"List")

    def BUILD_MAP(self,zero):
        """
        Pushes a new empty dictionary object onto the stack. The argument is ignored
        and set to zero by the compiler.
        """
        self.debugPrintRt("BUILD_MAP",1)
        self.a("CALL PyDict_New")
        self.emit_py_error_check(0)
        self.a("PUSH EAX")
   
    def LOAD_ATTR(self, namei):
        """ Replaces TOS with getattr(TOS, co_names[namei]). """
        self.debugPrintRt("LOAD_ATTR")
        self.a("PUSH %s" % namei)
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)
        self.emit_incref_reg()
        self.a("MOV v, EAX")
        
        self.a("POP w")
        self.a("PUSH v")
        self.a("PUSH w")
        self.a("CALL PyObject_GetAttr")
        self.emit_py_error_check(8)
        self.a("PUSH EAX")
        self.emit_decref_var("w")
        self.emit_decref_var("v")

    def COMPARE_OP(self, opname):
        """Performs a Boolean operation. The operation name can be found in cmp_op[opname]. """
        self.debugPrintRt("COMPARE_OP",1)
        optype = opcode.cmp_op[opname]

        if optype in ('<', '<=', '==', '!=', '>', '>='):
            self.a("POP w")
            self.a("POP v")
            self.a("PUSH %s" % opname)
            self.a("PUSH w")
            self.a("PUSH v")
            self.a("CALL PyObject_RichCompare")
            self.emit_py_error_check(12)
            self.a("PUSH EAX")
            self.emit_decref_var("v")
            self.emit_decref_var("w")
        elif optype == 'exception match':
            isFalse = self.getTempLabel("cmp_op_isfalse")
            done = self.getTempLabel("cmp_op_done")
            self.a("POP w")
            self.a("POP v")
            self.a("PUSH w")
            self.a("PUSH v")
            self.a("CALL PyErr_GivenExceptionMatches")
            self.a("ADD ESP,0x8")
            self.a("CMP EAX,0")
            self.a("JZ %s" % isFalse)
            #true
            self.debugPrintRt("was true",2)
            self.a("MOV EAX,_Py_TrueStruct")
            self.emit_incref_reg()
            self.a("JMP %s" % done)

            #false
            self.a.AIL(isFalse)
            self.debugPrintRt("was false")
            self.a("MOV EAX,_Py_ZeroStruct")
            self.emit_incref_reg()

            self.a.AIL(done)
            self.debugPrintRt("done",2)
            self.a("PUSH EAX")
            self.emit_decref_var("v")
            self.emit_decref_var("w")
        elif optype in ('is', 'is not'):
            is_not = self.getTempLabel("compare_op_is_not")
            done_is_not = self.getTempLabel("compare_op_is_not_exit")
            self.debugPrintRt("is type",1)
            self.a("POP EAX")
            self.a("POP v")
            self.a("CMP EAX,v")
            if optype == 'is':
                self.a("JNZ %s" % is_not)
            else:
                self.a("JZ %s" % is_not)
            self.debugPrintRt("is type",1)
            self.a("MOV EAX,_Py_TrueStruct")
            self.emit_incref_reg()
            self.a("JMP %s" % done_is_not)

            #false
            self.a.AIL(is_not)
            self.debugPrintRt("was false")
            self.a("MOV EAX,_Py_ZeroStruct")
            self.emit_incref_reg()

            self.a.AIL(done_is_not)
            self.a("PUSH EAX")
        else:
            raise Exception(" haven't implemented compare for %s yet" % optype)
            #, 'in', 'not in', 'is', 'is not', , 'BAD')

    def IMPORT_NAME(self, namei):
        """
        Imports the module co_names[namei]. The module object is pushed onto the stack.
        The current namespace is not affected: for a proper import statement, a
        subsequent STORE_FAST instruction modifies the namespace.
        """
        self.debugPrintRt("IMPORT_NAME",1)
        self.a("PUSH %s" % namei)
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8)
        self.a("MOV w, EAX") # name of module

        self.a("PUSH imports")        
        self.a("CALL PyString_FromString")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
        self.a("PUSH builtins")
        self.a("CALL PyObject_GetItem")
        self.debugPrintRt("After PyObject_GetItem",2)
        self.emit_py_error_check(8)
        self.debugPrintRt("GOT __import__",2)
        self.a("MOV x, EAX")
        
        self.a("POP v")
        #self.a("POP u") don't need?

        self.a("PUSH w")
        self.a("PUSH globals")
        self.a("PUSH locals")
        self.a("PUSH v")
        #self.a("PUSH u")
        #TODO U check from source.  What does this do?

        self.emit_build_tuple_or_list(4,"Tuple")
        self.a("POP w")

        #self.a("MOV EAX,0") #null
        #self.a("PUSH EAX")
        self.a("PUSH w")
        
        self.a("PUSH x")
        self.debugPrintRt("Going to call object",2)
        self.a("CALL PyEval_CallObject")
        self.debugPrintRt("PyEval_CallObject -> Before error check",2)
        self.emit_py_error_check(8)
        self.debugPrintRt("PyEval_CallObject -> After error check",2)
        self.a("PUSH EAX")
        
    
    def IMPORT_FROM(self, namei):
        """
        Loads the attribute co_names[namei] from the module found in TOS. The resulting
        object is pushed onto the stack, to be subsequently stored by a STORE_FAST
        instruction.
        """
        self.debugPrintRt("IMPORT_FROM",1)
        self.a("PUSH %s" % namei)
        self.a("PUSH names")
        self.a("CALL PyTuple_GetItem")
        self.emit_py_error_check(8) # TODO: Recast error fi we can't find the item
        self.debugPrintRt("Got Name", 2)
        self.a("MOV w, EAX")
        self.a("POP v")
        self.a("PUSH v") # keep it on the stack
        self.a("PUSH w")
        self.a("PUSH v")
        self.a("CALL PyObject_GetAttr")
        self.emit_py_error_check(8)
        self.a("PUSH EAX")

    def JUMP_FORWARD(self,delta): 
        """Increments byte code counter by delta. """
        self.debugPrintRt("JUMP_FORWARD",1)
        self.a("JMP %s" % ("%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta)))

    def JUMP_IF_TRUE(self, delta):
        """If TOS is true, increment the byte code counter by delta. TOS is left on the stack. """
        self.debugPrintRt("JUMP_IF_TRUE",1)
        self.a("POP w")
        self.a("PUSH w")
        self.a("MOV EAX, _Py_TrueStruct")
        self.a("CMP w, EAX")
        self.a("JE %s" % ("%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta)))
  
    def JUMP_IF_FALSE(self,delta): 
        """If TOS is false, increment the byte code counter by delta. TOS is not changed. """
        self.debugPrintRt("JUMP_IF_FALSE",1)
        self.a("POP w")
        self.a("PUSH w")
        self.a("MOV EAX, _Py_TrueStruct")
        self.a("CMP w, EAX")
        self.a("JNE %s" % ("%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta)))
        
    def JUMP_ABSOLUTE(self, target):
        """ Set byte code counter to target. """
        self.debugPrintRt("JUMP_ABSOLUTE",1)
        self.a("JMP %s" % ("%s_%s" % (self.bytecodeOffsetLabel, target)))

    def FOR_ITER(self, delta):
        """
        TOS is an iterator. Call its next() method. If this yields a new value, push it
        on the stack (leaving the iterator below it). If the iterator indicates it is
        exhausted TOS is popped, and the byte code counter is incremented by delta.
        """
        self.debugPrintRt("FOR_ITER")

        checkEx = self.getTempLabel("for_iter_check_ex")
        exitIter = self.getTempLabel("for_iter_exit")

        self.a("POP w")
        self.emit_incref_var("w")
        self.a("PUSH w") # leave on stack
        self.a("PUSH w")
        self.a("CALL PyIter_Next")
        self.a("ADD ESP,4")
        self.a("MOV u, EAX")
        
        self.a("TEST EAX,EAX")
        self.a("JZ %s" % checkEx)
        #passed, got item
        self.a("PUSH u")
        self.a("JMP %s" % exitIter)


        self.a.AIL(checkEx)        
        self.a("PUSH PyExc_StopIteration")
        self.a("CALL PyErr_ExceptionMatches")
        self.emit_c_error_check(4)
        self.a("CALL PyErr_Clear")
        self.emit_decref_var("w")
        #self.a("POP w")
        self.a("JMP %s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta))
        self.a.AIL(exitIter)

    def LOAD_GLOBAL(self,namei):
        """Loads the global named co_names[namei] onto the stack. """
        self.debugPrintRt("LOAD_GLOBAL",1)
        exit = globals = self.getTempLabel("load_name_exit")
        
        self.emit_load_name_or_global(namei,"globals")
        self.a("POP EAX")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % exit)
        self.debugPrintRt("didn't find global",2)
        self.a("CALL PyErr_Clear");

        self.emit_load_name_or_global(namei,"builtins")
        self.a("POP EAX")
        self.a("TEST EAX,EAX")
        self.a("JNZ %s" % exit)
        self.debugPrintRt("didn't find builtin",2)


        self.a.AIL(exit)
        self.debugPrintRt("exiting",2)
        self.emit_py_error_check(0)
        self.debugPrintRt("passed error check",2)
        self.a("PUSH EAX")
        
    def SETUP_LOOP(self, delta):
        """
        Pushes a block for a loop onto the block stack. The block spans from the
        current instruction with a size of delta bytes.
        """
        self.debugPrintRt("SETUP_LOOP",1)
        loop_label = "%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta)
        self.blocks.append( (opcode.opmap['SETUP_LOOP'], loop_label) )
        # really a no-op so far

    def SETUP_EXCEPT(self, delta):
        """
        Pushes a try block from a try-except clause onto the block stack. delta points
        to the first except block.
        """
        self.debugPrintRt("SETUP_EXCEPT",1)
        except_label = "%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta)
        self.blocks.append( (opcode.opmap['SETUP_EXCEPT'], except_label) )
        # really a no-op so far
        
    def SETUP_FINALLY(self, delta):
        """
        Pushes a try block from a try-except clause onto the block stack. delta points
        to the finally block.
        """
        self.debugPrintRt("SETUP_FINALLY",1)
        finally_label = "%s_%s" % (self.bytecodeOffsetLabel, self.currentBytecodeOffset + delta)
        self.blocks.append( (opcode.opmap['SETUP_FINALLY'], finally_label))
        # really a no-op so far
    
    def LOAD_FAST(self, var_num):
        """Pushes a reference to the local co_varnames[var_num] onto the stack. """
        self.debugPrintRt("LOAD_FAST")
        self.emit_incref_var("var%s" % var_num)
        self.a("PUSH var%s" % var_num)

    def STORE_FAST(self, var_num):
        """ Stores TOS into the local co_varnames[var_num]. """
        self.debugPrintRt("STORE_FAST")
        self.debugPrintRt("STORING var%s" % var_num)
        self.emit_decref_var("var%s" % var_num)
        self.a("POP var%s" % var_num)
        #already incref'ed when pushed onto stack
        #self.emit_incref_var("var%s" % var_num)

    """    

    DELETE_FAST    var_num 
    Deletes local co_varnames[var_num]. 

    """
    def LOAD_CLOSURE(self, i):
        """
        Pushes a reference to the cell contained in slot i of the cell and free
        variable storage. The name of the variable is co_cellvars[i] if i is less than
        the length of co_cellvars. Otherwise it is co_freevars[i - len(co_cellvars)]. 
        """
        self.a("MOV EAX, cellvar%s" % i)
        self.emit_incref_reg()
        self.a("PUSH EAX")
    
    def LOAD_DEREF(self,i): 
        """
        Loads the cell contained in slot i of the cell and free variable storage.
        Pushes a reference to the object the cell contains on the stack.
        """
        self.debugPrintRt("LOAD_DEREF")
        self.emit_incref_var("cellvar%s" % i)
        self.a("PUSH cellvar%s" % i)

        self.a("CALL PyCell_Get")
        self.emit_py_error_check(4)
        self.a("PUSH EAX")
   
    def STORE_DEREF(self,i): 
        """Stores TOS into the cell contained in slot i of the cell and free variable storage. """
        self.debugPrintRt("STORE_DEREF")
        self.a("POP w") # save for decref
        self.a("PUSH w")
        self.a("PUSH cellvar%s" % i)
        self.a("CALL PyCell_Set")
        self.emit_c_error_check(8)


    
    def SET_LINENO(self, lineno):
        """This opcode is obsolete. """
        raise Exception("SET_LINENO is obsolete")

    """
    RAISE_VARARGS    argc 
    Raises an exception. argc indicates the number of parameters to the raise
    statement, ranging from 0 to 3. The handler will find the traceback as TOS2,
    the parameter as TOS1, and the exception as TOS. 

    """

    def emit_pos_and_kw_args(self,argc,kw=False, var=False):
        """ emit positiona and kw args code, and store the PyObjects in u an w"""
        argCount = argc & 0xff
        kwCount = (argc >> 8) & 0xff

        self.debugPrintRt("%s normal args %s kw args %s" % (argc, argCount, kwCount))

        def get_var_args():
            if var:
                self.a("POP x")

        #kw args
        if not kwCount and not kw:
            self.a("MOV EAX,0")
            self.a("MOV u, EAX")
            get_var_args()
        else:
            if kw:
                self.a("POP u")
            else:
                self.a("CALL PyDict_New")
                self.emit_py_error_check(0)
                self.a("MOV u,EAX")
            get_var_args()
            
            for i in range(kwCount):
                self.debugPrintRt("Adding element %s" % i)
                self.a("POP w") # value
                self.a("POP v") #key
                self.a("PUSH w")
                self.a("PUSH v")
                self.a("PUSH u")
                self.a("CALL PyDict_SetItem")
                self.emit_c_error_check(12)
        
        
        self.emit_build_tuple_or_list(argCount,"Tuple")
        self.debugPrintRt("BUILT TUPLE %s" % argCount)
        self.a("POP w")

        if var:
            self.a("PUSH x")
            self.a("PUSH w")
            self.a("CALL PySequence_Concat")
            self.emit_py_error_check(8)
            self.a("MOV w, EAX")
        
        self.a("POP v")
        self.a("PUSH u")
        self.a("PUSH w")
        self.a("PUSH v")
        self.debugPrintRt("Preparing to call function")
        self.a("CALL PyObject_Call")
        self.debugPrintRt("Called function")
        self.emit_py_error_check(12)
        self.debugPrintRt("No Error")
        self.a("PUSH EAX")
        
    def CALL_FUNCTION(self, argc):
        """
        Calls a function. The low byte of argc indicates the number of positional
        parameters, the high byte the number of keyword parameters. On the stack, the
        opcode finds the keyword parameters first. For each keyword argument, the value
        is on top of the key. Below the keyword parameters, the positional parameters
        are on the stack, with the right-most parameter on top. Below the parameters,
        the function object to call is on the stack.
        """

        self.debugPrintRt("CALL_FUNCTION",1)
        self.emit_pos_and_kw_args(argc)

    def MAKE_FUNCTION(self, argc, closure=False):
        """
        Pushes a new function object on the stack. TOS is the code associated with the
        function. The function object is defined to have argc default parameters, which
        are found below TOS.
        """
        self.debugPrintRt("MAKE_FUNCTION",1)
        
        self.a("POP w")
        self.a("PUSH globals")
        self.a("PUSH w")
        self.a("CALL PyXFunction_New")
        self.emit_py_error_check(8)
        self.emit_incref_reg()
        self.a("MOV t, EAX")

        if closure:
            self.debugPrintRt("DOING CLOSURE STUFF",1)

            self.a("PUSH t")
            self.a("CALL PyXFunction_GetFreevarNum")
            self.a("ADD ESP,4") # zero is valid length
            self.a("PUSH EAX")
            
            self.emit_build_dynamic_tuple_or_list('Tuple')
            self.a("PUSH t")
            self.a("CALL PyXFunction_SetClosure")
            self.emit_c_error_check(8)

        if argc > 0:
            self.emit_build_tuple_or_list(argc,"Tuple")
            #tuple already on top of stack
            self.a("PUSH t")
            self.a("CALL PyXFunction_SetDefaults")
            self.emit_c_error_check(8)
        self.a("PUSH t")
            

    def MAKE_CLOSURE(self,argc):
        """
        Creates a new function object, sets its func_closure slot, and pushes it on the
        stack. TOS is the code associated with the function. If the code object has N
        free variables, the next N items on the stack are the cells for these
        variables. The function also has argc default parameters, where are found
        before the cells.
        """
        self.debugPrintCt("MAKE_CLOSURE %s" % argc,1)
        self.debugPrintRt("MAKE_CLOSURE %s" % argc,1)
        self.MAKE_FUNCTION(argc,closure=True)

    def BUILD_SLICE (self,argc):
        """
        Pushes a slice object on the stack. argc must be 2 or 3. If it is 2,
        slice(TOS1, TOS) is pushed; if it is 3, slice(TOS2, TOS1, TOS) is pushed. See
        the slice() built-in function for more information.
        """
        self.debugPrintRt("BUILD_SLICE")
        if argc != 3:
            self.a("PUSH 0")

        self.a("CALL PySlice_New")
        self.emit_py_error_check(12)
        self.a("PUSH EAX")
        self.emit_incref_reg()
    
    """
    EXTENDED_ARG    ext 
    Prefixes any opcode which has an argument too big to fit into the default two
    bytes. ext holds two additional bytes which, taken together with the subsequent
    opcode's argument, comprise a four-byte argument, ext being the two
    most-significant bytes. 

    """
    def CALL_FUNCTION_VAR(self, argc):
        """
        Calls a function. argc is interpreted as in CALL_FUNCTION. The top element on
        the stack contains the variable argument list, followed by keyword and
        positional arguments. 
        """
        self.debugPrintRt("CALL_FUNCTION_VAR",1)
        self.emit_pos_and_kw_args(argc,var=True)
        
    def CALL_FUNCTION_KW(self,argc):
        """
        Calls a function. argc is interpreted as in CALL_FUNCTION. The top element on
        the stack contains the keyword arguments dictionary, followed by explicit
        keyword and positional arguments.
        """
        self.debugPrintRt("CALL_FUNCTION_KW",1)
        self.emit_pos_and_kw_args(argc,kw=True)

    def CALL_FUNCTION_VAR_KW(self, argc):
        """
        Calls a function. argc is interpreted as in CALL_FUNCTION. The top element on
        the stack contains the keyword arguments dictionary, followed by the
        variable-arguments tuple, followed by explicit keyword and positional
        arguments. 
        """
        self.debugPrintRt("CALL_FUNCTION_VAR_KW",1)
        self.emit_pos_and_kw_args(argc,var=True,kw=True)


