Prior to this fix, async for assumed the iterator expression was a simple
identifier, and used that identifier as a local to store the intermediate
iterator object. This is incorrect behaviour.
This commit fixes the issue by keeping the iterator object on the stack as
an anonymous local variable.
Fixes issue #11511.
Signed-off-by: Damien George <damien@micropython.org>
On my i5-1235U laptop this speeds LTO "partition=balanced" builds
substantially, because each "partition" can be run on a separate
CPU thread. I used "pygamer" as my test build with a parallelism of
`-j4`, and took the best elapsed time reported over 4 builds.
The improvement was from 34.6s to 24.0s (-30%).
A link-only build (rm build-pygamer/firmware.elf; make -j...) improved
from1 17.4s to 5.1s (-70%)
The size of the resulting firmware is unchanged.
Boards that are nearly full use "-flto-partition=one" to improve code
size optimization. When LTO partition is "one", this feature doesn't help
but it doesn't seem to negatively affect anything either (tested
building trinket_m0)
The asyncio module now has much better CPython compatibility and
deserves to be just called "asyncio".
This will avoid people having to write `from uasyncio import asyncio`.
Renames all files, and updates port manifests to use the new path. Also
renames the built-in _uasyncio to _asyncio.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
PEP-498 allows for conversion specifiers like !r and !s to convert the
expression declared in braces to be passed through repr() and str()
respectively.
This updates the logic that detects the end of the expression to also stop
when it sees "![rs]" that is either at the end of the f-string or before
the ":" indicating the start of the format specifier. The "![rs]" is now
retained in the format string, whereas previously it stayed on the end
of the expression leading to a syntax error.
Previously: `f"{x!y:z}"` --> `"{:z}".format(x!y)`
Now: `f"{x!y:z}"` --> `"{!y:z}".format(x)`
Note that "!a" is not supported by `str.format` as MicroPython has no
`ascii()`, but now this will raise the correct error.
Updated cpydiff and added tests.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
So that the delegation functions don't need to be put somewhere global,
like in mpconfigport.h. That would otherwise make it hard for extension
modules to use delegation.
Signed-off-by: Damien George <damien@micropython.org>
Starting with 2757acf6, the `top` variable in `nlr_jump()` in
`nlraarch64.c` was assigned to register `x19` by the compiler. However,
the assembly code writes over that register with
ldp x19, x20, [%0, #32]
since `%0` is now `x19`. This causes the next line
ldp lr, x9, [%0, #16]
to load the wrong values.
To fix the issue, we move the value of the `top` variable from an unknown
register to a known register at the beginning of the asm code then only use
known/hard-coded registers after that.
Fixes issue #11754.
Signed-off-by: David Lechner <david@pybricks.com>
and re-organize so that esp32 s2/s3 don't do as much at reset
.. it's not necessary (because most data is in esp-idf managed memory)
and doing this saves me from having to debug why reconstruct isn't working
properly on that platform.
This needs to be tested on other platforms again before being merged!
Following how mkrules.cmake works. This makes it easy for a port to enable
frozen code, by defining FROZEN_MANIFEST in its Makefile.
Signed-off-by: Damien George <damien@micropython.org>
This is a MicroPython-specific module that existed to support the old
version of uasyncio. It's undocumented and not enabled on all ports and
takes up code size unnecessarily.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
Previously sys.path could be modified by append/pop or slice assignment.
This allows `sys.path = [...]`, which can be simpler in many cases, but
also improves CPython compatibility.
It also allows sys.path to be set to a tuple which means that you can
clear sys.path (e.g. temporarily) with no allocations.
This also makes sys.path (and sys.argv for consistency) able to be disabled
via mpconfig. The unix port (and upytesthelper) require them, so they
explicitly verify that they're enabled.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
Otherwise you can get into the confusing state where e.g. sys.ps1 is
enabled in config (via `MICROPY_PY_SYS_PS1_PS2`) but still doesn't actually
get enabled.
Also verify that the required delegation options are enabled in modsys.c.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
When compiling mpy-cross, there is no `sys` module, and so there will
be no entries in the `mp_builtin_module_delegation_table`.
MSVC doesn't like this, so instead pretend as if the feature isn't
enabled at all.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This replaces the previous QSTR_null entry in the globals dict which could
leak out to Python (e.g. via iteration of mod.__dict__) and could lead to
crashes.
It results in smaller code size at the expense of turning a lookup into a
loop, but the list it is looping over likely only contains one or two
elements.
To allow a module to register its custom attr function it can use the new
`MP_REGISTER_MODULE_DELEGATION` macro.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
Updates any includes, and references from Makefiles/CMake.
This essentially reverts what was done long ago in commit
136b5cbd7669e8318f8455fc2706da97a5b7994c
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
In order to keep "import umodule" working, the existing mechanism is
replaced with a simple fallback to drop the "u".
This makes importing of built-ins no longer touch the filesystem, which
makes a typical built-in import take ~0.15ms rather than 3-5ms.
(Weak links were added in c14a81662c1df812c0c6b4299f97966302f16477)
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This renames the builtin-modules, such that help('modules') and printing
the module object will show "module" rather than "umodule".
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This reduces the stack frame size of mp_builtin___import__ by
limiting the support path length of files from 256 to 96. This
function can be called recursively for nested imports so it adds up.
Also reduce mp_execute_bytecode (vm.c) from 206 a bc call to 124.
This too is recursive and adds up. It is reduced by preventing
some inlining. It may decrease performance slightly when importing
and unpacking.
Adds two new scripts for debugging. One is used from gdb to print
frame sizes in a backtrace. The other prints what pcs use a
particular stack offset. This helps find infrequently used stack
space.
Fixes#8053.
Prior to this commit, importing a module that exists but has a syntax error
or some other problem that happens at import time would result in a
potentially-incomplete module object getting added to sys.modules.
Subsequent imports would use that object, resulting in confusing error
messages that hide the root cause of the problem.
This commit fixes that issue by removing the failed module from sys.modules
using the new NLR callback mechanism.
Note that it is still important to add the module to sys.modules while the
import is happening so that we can support circular imports just like
CPython does.
Fixes issue #967.
Signed-off-by: David Grayson <davidegrayson@gmail.com>
The changed functions now use less stack, and don't have any issues with
local variables needing to be declared volatile.
Testing on a PYBv1.0, imports (of .py, .mpy and frozen code) now use 64
less bytes of C stack per import depth.
Signed-off-by: Damien George <damien@micropython.org>
NLR buffers are usually quite large (use lots of C stack) and expensive to
push and pop. Some of the time they are only needed to perform clean up if
an exception happens, and then they re-raise the exception.
This commit allows optimizing that scenario by introducing a linked-list of
NLR callbacks that are called automatically when an exception is raised.
They are essentially a light-weight NLR handler that can implement a
"finally" block, i.e. clean-up when an exception is raised, or (by passing
`true` to nlr_pop_jump_callback) when execution leaves the scope.
Signed-off-by: Damien George <damien@micropython.org>
This can lead to duplicate initialisations if a module can be imported
via multiple names, so the module must track this itself anyway.
This reduces code size (diff is -40 bytes), and avoids special treatment of
builtin-modules-with-init with respect to sys.modules. No other builtin
modules get put into sys.modules.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
To use this:
- Create a built-in module, and add the module object as a member of the
parent module's globals dict.
- The submodule can set its `__name__` to either `QSTR_foo_dot_bar` or
`QSTR_bar`. The former requires using qstrdefs(port).h to make the qstr.
Because `bar` is a member of `foo`'s globals, it is possible to write
`import foo` and then immediately use `foo.bar` without importing it
explicitly. This means that if `bar` has an `__init__`, it will not be
called in this situation, and for that reason, sub-modules should not have
`__init__` methods. If this is required, then all initalisation for
sub-modules should be done by the top-level module's (i.e. `foo`'s)
`__init__` method.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This makes it so that sub-packages are resolved relative to their parent's
`__path__`, rather than re-resolving each parent's filesystem path.
The previous behavior was that `import foo.bar` would first re-search
`sys.path` for `foo`, then use the resulting path to find `bar`.
For already-loaded and u-prefixed modules, because we no longer need to
build the path from level to level, we no longer unnecessarily search
the filesystem. This should improve startup time.
Explicitly makes the resolving process clear:
- Loaded modules are returned immediately without touching the filesystem.
- Exact-match of builtins are also returned immediately.
- Then the filesystem search happens.
- If that fails, then the weak-link handling is applied.
This maintains the existing behavior: if a user writes `import time` they
will get time.py if it exits, otherwise the built-in utime. Whereas `import
utime` will always return the built-in.
This also fixes a regression from a7fa18c203a241f670f12ab507aa8b349fcd45a1
where we search the filesystem for built-ins. It is now only possible to
override u-prefixed builtins. This will remove a lot of filesystem stats
at startup, as micropython-specific modules (e.g. `pyb`) will no longer
attempt to look at the filesystem.
Added several improvements to the comments and some minor renaming and
refactoring to make it clearer how the import mechanism works. Overall
code size diff is +56 bytes on STM32.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
If sys.path is enabled, but empty, this will now no longer search the
filesystem. Previously an empty sys.path was equivalent to having
`sys.path=[""]`. This is a breaking change, but this behavior now matches
CPython.
This also provides an alternative mechanism to the u-prefix to force an
import of a builtin module:
```
import sys
_path = sys.path[:]
sys.path.clear()
import foo # Forces the built-in foo.
sys.path.extend(_path)
del _path
```
Code size diff is -32 bytes on PYBV11.
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This generalises and simplifies the code and follows CPython behaviour.
See similar change for floats in a07fc5b6403b9a8bf7e7cb64f857272e5346d7e2.
Signed-off-by: Damien George <damien@micropython.org>
This is possible now that MP_UNARY_OP_INT_MAYBE exists.
As a consequence mp_obj_get_int now also supports user types, which was
previously possible with MP_UNARY_OP_INT but no tests existed for it.
Signed-off-by: Damien George <damien@micropython.org>
To be consistent with MP_UNARY_OP_INT_FLOAT and MP_UNARY_OP_INT_COMPLEX,
and allow int() to first check if a type supports __int__ before trying
other things (as per CPython).
Signed-off-by: Damien George <damien@micropython.org>