[Tutor] bytecode primer, and avoiding a monster download

eryksun eryksun at gmail.com
Tue May 28 03:15:59 CEST 2013


On Mon, May 27, 2013 at 4:01 PM, Jim Mooney <cybervigilante at gmail.com> wrote:
> I was looking at the bytecode doc page as a break from the Lutz book,
> since I like Assembler-type code due to its total non-ambiguity, but
> the page doesn't say much. Is there a doc somewhere that corresponds
> some of the bytecode to Python source? I thought rot_1, 2, 3, and 4
> looked useful, but it would take awhile to disassemble random programs
> to see what source they come from.

Are you referring to the documentation of the dis module?

http://docs.python.org/2/library/dis

AFAIK, that's all the documentation there is. Heed the warning in bold
that bytecode is an implementation detail of the target virtual
machine. For example, Jython creates a .class file containing JVM
bytecode, and its code objects don't even have a co_code attribute...

I once manually instantiated a CPython 2.x code object to create a
very simple function with a default argument. Here was my first and
only attempt, FWIW:

    from opcode import opmap
    from types import FunctionType, CodeType
    from inspect import CO_OPTIMIZED, CO_NEWLOCALS, CO_NOFREE

    OP = type('OP', (), opmap)

    def foo1(x='spam'):
        print x

    foo2 = FunctionType(
      CodeType(            # func_code
        1,                     # co_argcount
        1,                     # co_nlocals
        1,                     # co_stacksize
        CO_OPTIMIZED |         # co_flags
        CO_NEWLOCALS |
        CO_NOFREE,
        str(bytearray([        # co_code
          OP.LOAD_FAST, 0, 0,      # stack.push(fastlocals[0])
                                   #     x is fastlocals[0]
          OP.PRINT_ITEM,           # print stack.pop()
          OP.PRINT_NEWLINE,
          OP.LOAD_CONST, 0, 0,     # stack.push(co_consts[0])
                                   #     co_consts[0] is None
          OP.RETURN_VALUE,         # return stack.pop()
        ])),
        (None,),               # co_consts
        (),                    # co_names
        ('x',),                # co_varnames
        __file__,              # co_filename
        'foo2',                # co_name
        10,                    # co_firstlineno
        '\x00\x01',            # co_lnotab,
                               #   see: Objects/lnotab_notes.txt
        (),                    # co_freevars
        (),                    # co_cellvars
      ),
      globals(),           # func_globals
      'foo2',              # func_name
      ('spam',),           # func_defaults
      None,                # func_closure
    )


For example:

    >>> foo2()
    spam
    >>> foo2('eggs')
    eggs

There's an assembler package on PyPI that does this for real, if this
sort of thing interests you:

https://pypi.python.org/pypi/BytecodeAssembler

As to the VM's ROT operations, I'm not sure what you mean by seeing
"what source they come from". They simply manipulate the top 2, 3, or
4 items on the frame's stack:

    ROT_TWO()
    Swaps the two top-most stack items.

    ROT_THREE()
    Lifts second and third stack item one position up,
    moves top down to position three.

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


More information about the Tutor mailing list