-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Support constant values of aggregate types #722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This could be fixed. Would need a new bytecode: LOAD_CONST, and its argument would be a pointer to a uPy object. This pointer would need to be aligned (and we can do that easily). In fact, doing this we could combine all the LOAD_CONST_xxx bytecodes into this one. And then ints, decs, bytes and strings would not need to be allocated using a qstr. Could even combine LOAD_CONST_SMALL_INT. But, all this would increase size of the bytecode by about 4 bytes per LOAD_CONST_xxx opcode on stmhal (2 bytes average for pointer alignment, 2 going from 2 byte qstr to 4 byte pointer). The reason this wasn't done from the start is because I didn't want any pointers in the bytecode, and didn't want to make a constant table (as CPython does). |
But why? That's what I thought about to implement this, would also probably help with bytecode persistence. |
Wanted to keep it simple. But I'd rather just put pointers directly in the bytecode: they would take about the same number of bytes because with a table you need an index to the table (1-2 bytes) and then the pointer in the table (4 bytes on 32 bit). With inline pointers, you need alignment bytes (average 2) plus the pointer, making it about the same. I think this change is a good idea (be it a const table or inline pointers). It will reduce RAM usage overall, since at the moment, eg a float, is made a qstr at parse time, then each time it is used new RAM is allocated for the object and the qstr is parsed. Not optimal at all, in terms of speed or RAM. You would add LOAD_CONST_OBJ, which simply pushed the given ptr (inline or from table) onto the stack. This would replace LOAD_CONST_INT, LOAD_CONST_DEC, LOAD_CONST_BYTES and LOAD_CONST_ELLIPSIS. And could be used for pushing whole tuples. In all these cases the overall RAM usage (bytecode + objects) would decrease or remain about the same. The more frequently used ones, LOAD_CONST_{FALSE, TRUE, NONE, SMALL_INT} would remain, for reasons of keeping the bytecode small in RAM. So would LOAD_CONST_STR, because that simply takes a qstr as argument and turns it into an object by setting some bits. |
Um, note that CPython doesn't make constant dicts. Only true constants (numbers, strings, tuples) are put in the constant table for the bytecode. Any dicts that you specify in a script are generated at runtime using the bytecode (as uPy implements at the moment). Of course, this is because dicts are mutable, so a new one must be created each time that part of the bytecode is run. If you wanted to do something like |
For us, we could us the following idiom to make constant dicts: |
Exactly, inline pointers will waste 2 bytes on average. But table indexes would be varlen, and with great probability fit in 1 byte (well, that would largely depend on whether strings are stored in this table). So, 1 byte saving can be counted on here. And if same constant is accessed few times, it will be even higher. Of course, table means extra dereference (and cache pollution), but well, that's the price to pay. The main reason I keep thinking about a table is because of the need to implement #222. And I always thought of inline pointers within bytecode as a hack. They were introduced to resolve bigger issue of global code object array, so I didn't say much against them, but they're dirty hack ;-). And here's the latest proof they're: #747 ;-). |
This allows to directly load a Python object to the Python stack. See issue #722 for background.
Previous to this patch, a big-int, float or imag constant was interned (made into a qstr) and then parsed at runtime to create an object each time it was needed. This is wasteful in RAM and not efficient. Now, these constants are parsed straight away in the parser and turned into objects. This allows constants with large numbers of digits (so addresses issue #1103) and takes us a step closer to #722.
I've had a patch for some time now for making a const table of pointers per function and having the bytecode index that table. But...
No, surprisingly they don't. They waste 0 bytes in almost all cases due to a very fortuitous layout of the bytecodes that mean that the ptr argument to the bytecode op is always aligned. The main use of pointers in bytecode is the MAKE_FUNCTION opcode, which is almost always followed by a STORE_NAME:
As you can see, combined they make exactly 8 bytes, so a long sequence of these pair of ops will always have the ptr aligned if the first one is aligned (valid for a 32 bit machine). And a long sequence of these ops is generally what you get when defining functions/methods. So, with this patch both code size and RAM usage increase noticeably. I've not been able to think of a way to reduce it. |
Add four missing drivers
This commit adds support to the parser so that tuples which contain only constant elements (bool, int, str, bytes, etc) are immediately converted to a tuple object. This makes it more efficient to use tuples containing constant data because they no longer need to be created at runtime by the bytecode (or native code). Furthermore, with this improvement constant tuples that are part of frozen code are now able to be stored fully in ROM (this will be implemented in later commits). Code size is increased by about 400 bytes on Cortex-M4 platforms. See related issue micropython#722. Signed-off-by: Damien George <damien@micropython.org>
Currently, unlike CPython, uPy doesn't support constant tuples, dicts, etc. Any such object is constructed at runtime, which takes time, (lot of) VM stack, etc.
It also precludes efficient usage of almost-core features, like in-place OrderedDict's.
The text was updated successfully, but these errors were encountered: