Permalink
Please sign in to comment.
Browse files
Isolated and fixed a buggy interaction between compiler2 and byterun.
The bug was because: - byterun doesn't implement the "optimized namespace access" -- e.g. LOAD_FAST instead of LOAD_NAME. So it had a workaround to look for the co_name "<genexpr>" in the code object. There a Python stdlib bug where inspect.getcallargs doesn't detect the pattern. http://bugs.python.org/issue19611 - compile.c uses the "<genexpr>" name for a generator expression, while compiler2 uses "lambda.1". The fix was to look for ".0" in co_varnames. That is the anonymous argument for a generator expression, which is implemented as its own code object. Result: Got OSH unit tests compiled by compiler2 running under byterun! Also: - Useful function to print co_flags in inspect_pyc.py - Start documenting opcodes - Notes about iterator implementation
- Loading branch information...
Showing
with
205 additions
and 29 deletions.
- +1 −1 opy/compiler2/pyassem.py
- +5 −0 opy/compiler2/pycodegen.py
- +26 −2 opy/misc/inspect_pyc.py
- +91 −0 opy/opcodes.md
- +41 −25 opy/run.sh
- +28 −0 opy/tests/genexpr.py
- +12 −0 opy/tests/genexpr_simple.py
- +1 −1 opy/tools/dumppyc.py
| @@ -0,0 +1,91 @@ | ||
| Notes on VM Opcodes | ||
| =================== | ||
| This is an elaboration on: | ||
| https://docs.python.org/2/library/dis.html | ||
| I copy the descriptions and add my notes, based on what I'm working on. | ||
| `SETUP_LOOP(delta)` | ||
| Pushes a block for a loop onto the block stack. The block spans from the | ||
| current instruction with a size of delta bytes. | ||
| NOTES: compiler2 generates an extra SETUP_LOOP, for generator expressions, | ||
| along with POP_BLOCK. | ||
| `POP_BLOCK()` | ||
| Removes one block from the block stack. Per frame, there is a stack of blocks, | ||
| denoting nested loops, try statements, and such. | ||
| `LOAD_CLOSURE(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)]`. | ||
| NOTES: compiler2 generates an extra one of these | ||
| `MAKE_CLOSURE(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, `TOS1` the tuple | ||
| containing cells for the closure’s free variables. The function also has `argc` | ||
| default parameters, which are found below the cells. | ||
| `LOAD_DEREF(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. | ||
| `GET_ITER()` | ||
| Implements TOS = iter(TOS). | ||
| NOTES: Hm how do I implement this? It turns it from a collection into an | ||
| iterator. Gah. | ||
| PyObject *iter = PyObject_GetIter(iterable); | ||
| objects/abstract.c - | ||
| objects/iterobject.c - PySeqIter_New | ||
| PySeqIter_Type has a it_seq field. The PyObject being iterated over. It | ||
| maintains an index too. | ||
| How does items() work as an iterable then? | ||
| Then iter_iternext() calls: | ||
| PySequence_GetItem(seq, it->it_index) | ||
| `LOAD_FAST(var_num)` | ||
| Pushes a reference to the local `co_varnames[var_num]` onto the stack. | ||
| NOTES: | ||
| This still does a named lookup? Generator expressions do `LOAD_FAST 0 (.0)` | ||
| since there is no formal parameter name. | ||
| Oh I see, there is a `PyObject** fastlocals` in EvalFrame | ||
| It's initialized to `f->f_localsplus` -- frame holds them. Oh I see, that's | ||
| where the frame setup is different! Don't need inspect.callargs. | ||
| FastCall populates fastlocals from `PyObject** args` and `nargs`. | ||
| @@ -0,0 +1,28 @@ | ||
| #!/usr/bin/python | ||
| """ | ||
| Test for generator expressions. | ||
| """ | ||
| def MakeLookup(p): | ||
| #return dict([(pat, tok) for _, pat, tok in p]) | ||
| # Something is broken about how we compile this... | ||
| # Difference in compilation is SETUP_LOOP. So CPython handle this fine, | ||
| # but bytern doesn't. | ||
| return dict((pat, tok) for _, pat, tok in p) | ||
| # This should be an error but isn't. Looks like it's not compiled | ||
| # correctly. | ||
| #return list(i for (i, j) in p) | ||
| fake_pairs = [ | ||
| (False, '-a', 0), | ||
| (False, '-b', 1), | ||
| (False, '-c', 2), | ||
| #(False, '-d', 3), | ||
| #(False, '-e', 4), | ||
| #(False, '-f', 5), | ||
| ] | ||
| #lookup = MakeLookup(id_kind.ID_SPEC.LexerPairs(Kind.BoolUnary)) | ||
| lookup = MakeLookup(fake_pairs) | ||
| print('LOOKUP ***************', len(lookup)) | ||
| print(lookup) |
| @@ -0,0 +1,12 @@ | ||
| #!/usr/bin/python | ||
| """ | ||
| Simpler test for generator expressions. | ||
| """ | ||
| def MakeLookup(p): | ||
| return list(i for i in p) | ||
| #return list([i for i in p]) | ||
| print(MakeLookup([66])) | ||
| # This runs but prints [] | ||
| #print(MakeLookup([1,2])) |
0 comments on commit
aa082c2