View of /RuleDispatch/src/dispatch/assembler.txt
Parent Directory
| Revision Log
Revision:
2112 -
(
download)
Thu Dec 22 05:26:05 2005 UTC (18 years, 4 months ago) by
pje
File size: 6660 byte(s)
Added jumps, labels, and backpatching forward references, all of which
turned out to be easier to do than I expected, as long as we assume
the total code size is <64K. At this point, the assembler probably has
everything it will need for doing generic function stuff, so I probably
won't bother with any special support for loops or try: blocks, or for
that matter nested scopes. At some point, the <64K limit for jump
handling may need to be fixed, though, if we ever generate big enough
generic functions. (Which assumes I ever manage to generate something
useful with this module in the first place, which is not a given at
this point.)
======================================================
Generating Python Bytecode with ``dispatch.assembler``
======================================================
>>> from dispatch.assembler import *
>>> from dis import dis
Line number tracking:
>>> def simple_code(flno, slno, consts=1, ):
... c = Code()
... c.set_lineno(flno)
... for i in range(consts): c.LOAD_CONST(None)
... c.set_lineno(slno)
... c.RETURN_VALUE()
... return c.code()
>>> dis(simple_code(1,1))
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
>>> simple_code(1,1).co_stacksize
1
>>> dis(simple_code(13,414))
13 0 LOAD_CONST 0 (None)
414 3 RETURN_VALUE
>>> dis(simple_code(13,14,100))
13 0 LOAD_CONST 0 (None)
3 LOAD_CONST 0 (None)
...
14 300 RETURN_VALUE
>>> simple_code(13,14,100).co_stacksize
100
>>> dis(simple_code(13,572,120))
13 0 LOAD_CONST 0 (None)
3 LOAD_CONST 0 (None)
...
572 360 RETURN_VALUE
Stack size tracking:
>>> c = Code()
>>> c.LOAD_CONST(1)
>>> c.POP_TOP()
>>> c.LOAD_CONST(2)
>>> c.LOAD_CONST(3)
>>> c.co_stacksize
2
>>> c.BINARY_ADD()
>>> c.LOAD_CONST(4)
>>> c.co_stacksize
2
>>> c.LOAD_CONST(5)
>>> c.LOAD_CONST(6)
>>> c.co_stacksize
4
>>> c.POP_TOP()
>>> c.stack_size
3
Stack underflow detection/recovery, and global/local variable names:
>>> c = Code()
>>> c.LOAD_GLOBAL('foo')
>>> c.stack_size
1
>>> c.STORE_ATTR('bar') # drops stack by 2
Traceback (most recent call last):
...
AssertionError: Stack underflow
>>> c.co_names # 'bar' isn't added unless success
['foo']
>>> c.LOAD_ATTR('bar')
>>> c.co_names
['foo', 'bar']
>>> c.DELETE_FAST('baz')
>>> c.co_varnames
['baz']
>>> dis(c.code())
0 0 LOAD_GLOBAL 0 (foo)
3 LOAD_ATTR 1 (bar)
6 DELETE_FAST 0 (baz)
Sequence operators and stack tracking:
Function calls and raise:
>>> c = Code()
>>> c.LOAD_GLOBAL('locals')
>>> c.CALL_FUNCTION() # argc/kwargc default to 0
>>> c.POP_TOP()
>>> c.LOAD_GLOBAL('foo')
>>> c.LOAD_CONST(1)
>>> c.LOAD_CONST('x')
>>> c.LOAD_CONST(2)
>>> c.CALL_FUNCTION(1,1) # argc, kwargc
>>> c.POP_TOP()
>>> dis(c.code())
0 0 LOAD_GLOBAL 0 (locals)
3 CALL_FUNCTION 0
6 POP_TOP
7 LOAD_GLOBAL 1 (foo)
10 LOAD_CONST 0 (1)
13 LOAD_CONST 1 ('x')
16 LOAD_CONST 2 (2)
19 CALL_FUNCTION 257
22 POP_TOP
>>> c = Code()
>>> c.LOAD_GLOBAL('foo')
>>> c.LOAD_CONST(1)
>>> c.LOAD_CONST('x')
>>> c.LOAD_CONST(2)
>>> c.BUILD_MAP(0)
>>> c.stack_size
5
>>> c.CALL_FUNCTION_KW(1,1)
>>> c.POP_TOP()
>>> c.stack_size
0
>>> c = Code()
>>> c.LOAD_GLOBAL('foo')
>>> c.LOAD_CONST(1)
>>> c.LOAD_CONST('x')
>>> c.LOAD_CONST(1)
>>> c.BUILD_TUPLE(1)
>>> c.CALL_FUNCTION_VAR(0,1)
>>> c.POP_TOP()
>>> c.stack_size
0
>>> c = Code()
>>> c.LOAD_GLOBAL('foo')
>>> c.LOAD_CONST(1)
>>> c.LOAD_CONST('x')
>>> c.LOAD_CONST(1)
>>> c.BUILD_TUPLE(1)
>>> c.BUILD_MAP(0)
>>> c.CALL_FUNCTION_VAR_KW(0,1)
>>> c.POP_TOP()
>>> c.stack_size
0
>>> c = Code()
>>> c.RAISE_VARARGS(0)
>>> c.RAISE_VARARGS(1)
Traceback (most recent call last):
...
AssertionError: Stack underflow
>>> c.LOAD_CONST(1)
>>> c.RAISE_VARARGS(1)
>>> dis(c.code())
0 0 RAISE_VARARGS 0
3 LOAD_CONST 0 (1)
6 RAISE_VARARGS 1
Sequence building, unpacking, dup'ing:
>>> c = Code()
>>> c.LOAD_CONST(1)
>>> c.LOAD_CONST(2)
>>> c.BUILD_TUPLE(3)
Traceback (most recent call last):
...
AssertionError: Stack underflow
>>> c.BUILD_LIST(3)
Traceback (most recent call last):
...
AssertionError: Stack underflow
>>> c.BUILD_TUPLE(2)
>>> c.stack_size
1
>>> c.UNPACK_SEQUENCE(2)
>>> c.stack_size
2
>>> c.DUP_TOPX(3)
Traceback (most recent call last):
...
AssertionError: Stack underflow
>>> c.DUP_TOPX(2)
>>> c.stack_size
4
>>> c.LOAD_CONST(3)
>>> c.BUILD_LIST(5)
>>> c.stack_size
1
>>> c.UNPACK_SEQUENCE(5)
>>> c.BUILD_SLICE(3)
>>> c.stack_size
3
>>> c.BUILD_SLICE(3)
>>> c.stack_size
1
>>> c.BUILD_SLICE(2)
Traceback (most recent call last):
...
AssertionError: Stack underflow
>>> dis(c.code())
0 0 LOAD_CONST 0 (1)
3 LOAD_CONST 1 (2)
6 BUILD_TUPLE 2
9 UNPACK_SEQUENCE 2
12 DUP_TOPX 2
15 LOAD_CONST 2 (3)
18 BUILD_LIST 5
21 UNPACK_SEQUENCE 5
24 BUILD_SLICE 3
27 BUILD_SLICE 3
XXX Need tests for MAKE_CLOSURE/MAKE_FUNCTION
Labels and backpatching forward references:
>>> c = Code()
>>> ref = c.JUMP_ABSOLUTE()
>>> c.LOAD_CONST(1)
>>> ref()
>>> c.RETURN_VALUE()
>>> dis(c.code())
0 0 JUMP_ABSOLUTE 6
3 LOAD_CONST 0 (1)
>> 6 RETURN_VALUE
>>> c = Code()
>>> ref = c.JUMP_FORWARD()
>>> c.LOAD_CONST(1)
>>> ref()
>>> c.RETURN_VALUE()
>>> dis(c.code())
0 0 JUMP_FORWARD 3 (to 6)
3 LOAD_CONST 0 (1)
>> 6 RETURN_VALUE
>>> c = Code()
>>> lbl = c.label()
>>> c.LOAD_CONST(1)
>>> c.JUMP_IF_TRUE(lbl)
Traceback (most recent call last):
...
AssertionError: Relative jumps can't go backwards
>>> c = Code()
>>> lbl = c.label()
>>> c.LOAD_CONST(1)
>>> ref = c.JUMP_ABSOLUTE(lbl)
>>> dis(c.code())
0 >> 0 LOAD_CONST 0 (1)
3 JUMP_ABSOLUTE 0