[Subversion] / PEAK / src / peak / util / _Code.pyx  

View of /PEAK/src/peak/util/_Code.pyx

Parent Directory | Revision Log
Revision: 763 - (download)
Thu Nov 28 23:44:26 2002 UTC (21 years, 5 months ago) by pje
File size: 4767 byte(s)
Major speedup for module inheritance, thanks to Pyrex!  The 'codeIndex()'
object and associated iterators are now in C, and the speedup is quite
visible.  It's still not as fast as I'd like, but the next step would be
to rewrite 'prepForSimulation()' in Pyrex, and it's a lot more complex
than the 'codeIndex' class.  Unfortunately, you can't just copy your code
into a .pyx file and expect a speedup; you have to think in C even if
the syntax is Pythonic.  Nonetheless, module inheritance spent so much
time in the old 'codeIndex.__init__' method that it was worth the hour or
two it took to convert.

Added support for Pyrex.Distutils to automatically build from .pyx; if
you're using 'mingw32' and Greg hasn't released my fixes yet, you may want
to edit setup.py to force it to compile from .c files instead and run
'pyrexc' manually against the '.pyx' files.  If you want to tinker with
the 'pyx' source files, you'll want to install Pyrex 0.4.6 or better.
cdef extern from "Python.h":
    void* PyMem_Malloc(int n) except NULL
    void* PyMem_Realloc(void *p, int n) except NULL
    void  PyMem_Free(void *p)
    int PyObject_AsReadBuffer(object obj, void **buffer, int *buffer_len) except -1

cdef extern from "opcode.h":

    unsigned char HAS_ARG(unsigned char op)

    enum:
        EXTENDED_ARG

cdef class codeIndex

cdef class opIter:

    cdef codeIndex cidx
    cdef int pos

    def __init__(self, codeIndex cidx, int pos):
        self.cidx = cidx
        self.pos  = pos
        
    def __iter__(self):
        return self

    def __next__(self):
        cdef int pos
        cdef codeIndex c
        
        pos = self.pos
        
        if self.pos == -1:
            raise StopIteration

        c = self.cidx   # XXX Pyrex croaks on self.cidx.opcodeChain[] 
        self.pos = c.opcodeChain[pos]
        return pos


cdef class codeIndex:
    
    """Useful indexes over a code object

        opcodeLocations[op] -- list of instruction numbers with 'op' as opcode

        opcode[i] -- the i'th instruction's opcode

        operand[i] -- the i'th instruction's operand (or None)

        offset[i]  -- location of the i'th instruction

        byteLine[b] -- source line number that generated byte 'b'
    """


    cdef object code
    cdef int *opcodeHeads, *operands, *offsets, *byteLines, *opcodeChain
    cdef unsigned char *opcodes
    cdef int length, codelen


    def __new__(self, codeObject):
        self.opcodeHeads=NULL
        self.opcodeChain=NULL
        self.operands=NULL
        self.offsets=NULL
        self.byteLines=NULL
        self.opcodes=NULL

    def __dealloc__(self):
        if self.opcodeHeads: PyMem_Free(self.opcodeHeads)
        if self.opcodeChain: PyMem_Free(self.opcodeChain)
        if self.operands:    PyMem_Free(self.operands)
        if self.offsets:     PyMem_Free(self.offsets)
        if self.byteLines:   PyMem_Free(self.byteLines)
        if self.opcodes:     PyMem_Free(self.opcodes)
    



    def __init__(self, codeObject):

        self.code = codeObject
        cdef int l, s, arg, end, start, p
        cdef unsigned char *ca
        cdef unsigned char op
        PyObject_AsReadBuffer(codeObject.co_code, <void **>(&ca), &l)

        s = l * sizeof(int)
        self.opcodeHeads     = <int *>PyMem_Malloc(256 * sizeof(int))
        self.opcodeChain     = <int *>PyMem_Malloc(s)
        self.operands        = <int *>PyMem_Malloc(s)
        self.offsets         = <int *>PyMem_Malloc(s)
        self.byteLines       = <int *>PyMem_Malloc(s)
        self.opcodes         = <unsigned char *>PyMem_Malloc(l)

        p = 0
        end = 0
        start = end

        while end < l:            
            op = ca[start]
            if HAS_ARG(op):
                arg = ca[start+1] | ca[start+2]<<8
                if op==EXTENDED_ARG:
                    op = ca[start+3]
                    end = start+6
                    arg = arg << 16
                    arg = arg + (ca[start+4] | ca[start+5]<<8)
                else:
                    end = start+3
            else:
                arg = 0
                end = start+1

            self.opcodes[p] = op
            self.operands[p] = arg
            self.offsets[p] = start
            p = p+1
            start = end
            
        self.length = p
        self.codelen = l

        PyObject_AsReadBuffer(codeObject.co_lnotab, <void **>(&ca), &end)

        p = 0
        arg = codeObject.co_firstlineno
        start = 0

        while p<end:

            for s from 0 <= s < ca[p]:
                self.byteLines[start+s] = arg
                
            start = start + ca[p]
            arg = arg + ca[p+1]
            p = p + 2

        while start<l:
           self.byteLines[start]=arg
           start = start + 1

        for s from 0 <= s < 256:
            self.opcodeHeads[s] = -1

        p = self.length

        while p:
            p = p - 1
            op = self.opcodes[p]
            self.opcodeChain[p] = self.opcodeHeads[op]
            self.opcodeHeads[op] = p









    def opcodeLocations(self, int op):

        if op<0 or op>255:
            raise IndexError, op

        return opIter(self, self.opcodeHeads[op])


    def operand(self, int p):

        if p<0 or p>=self.length:
            raise IndexError, p

        return self.operands[p]


    def opcode(self, int p):

        if p<0 or p>=self.length:
            raise IndexError, p

        return self.opcodes[p]


    def offset(self, int p):

        if p<0 or p>=self.length:
            raise IndexError, p

        return self.offsets[p]


    def byteLine(self, int p):

        if p<0 or p>=self.codelen:
            raise IndexError, p

        return self.byteLines[p]

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help