1.2 bytecodehacks.ops

This (auto-generated!) file contains a class for each bytecode known by the Python virtual machine (at least in 1.5.2).

This module is safe to "import *" from; the only names that are imported when this is done are the names of the opcodes themselves. Unless you are in the habit of using names like "SETUP_BLOCK" for variable names, you should be fine.

To see a description of each bytecode go look at the documentation for dis. This can be found at http://www.python.org/doc/current/lib/bytecodes.html, or (if you're sensible) in the copy of the Python libaray reference you've downloaded for easy access.

If you look at the code in ops.py you might notice that the construction interface is a bit weird. This is because the opcodes are constructed both by code_editor.CodeString and directly.

Creating opcodes for insertion into a codestring is, I hope, fairly straightforward. There are various categories of opcode: simple (one byte), argumented (three byte) and named opcodes and jumps.

Simple opcodes have no argument. POP_TOP, BINARY_ADD and UNARY_POSITIVE are simple opcodes. They are created in an appropriately simple manner:

op = POP_TOP()

Argumented opcodes take a sixteen byte int as an argument. The meaning of this argument varies from opcode to opcode; for details see the documentation of the dis module. Jumps and named opcodes are in fact argumented opcodes, but they have additional features. Argumented opcodes are created like so:

op = BUILD_TUPLE(4)

Named opcodes can be created like argumented opcodes, but can also take the name they operate on as a parameter. Named opcodes are opcodes that refer to a name or local variable, such as LOAD_GLOBAL, STORE_FAST or LOAD_ATTR. An example:

op = LOAD_GLOBAL("var")

Jumps are a bit different. They can be created with no argument, or with the opcode they should target. They have a label attribute which in turn has an op attribute that points to the target of the jump. There are eight jumps: JUMP_FORWARD, JUMP_IF_FALSE, JUMP_IF_TRUE, FOR_LOOP, SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY and JUMP_ABSOLUTE. The distinction between absolute and relative jumps can safely be ignored.

Opcodes generally sprout the following methods which could be useful to user code:

is_jump ()
Returns 1 if the opcode represents a jump of some kind.
has_name ()
Returns 1 if the opcode uses an element of code.co_names.
has_local ()
Returns 1 if the opcode manipulates a local.
has_name_or_local ()
Returns 1 if the opcode refers to a local variable or name. If this returns 1, there's a strong chance that the opcode will have a name attribute.

execute (stack)
Tricky one to explain this.

This method was added to enable writing of the find_function_call module. Basically a code sequence can be simulated by calling in sequence "opcode.execute(stack)". stack is a list. After simulated execution, the stack contains the opcodes that last touched the respective stack position. An example may help:

>>> from bytecodehacks import ops
>>> op=ops.LOAD_CONST(2)
>>> stack=[]
>>> op.execute(stack)
>>> stack
[LOAD_CONST 2]

Not every function has a meaningful execute method at this time; only bytecodes that may turn up in expressions that aren't jumps in fact. This may change.

manipulate_stack ()
Used to calculate the stack usage of a function. Not designed to be called from user code; its interface is rather odd.

As you can see from above opcodes are also fitted with a basic __repr__ method.

Send comments to mwh@python.net