Merge pull request #6038 from jepler/merge-1.18

Merge 1.18
This commit is contained in:
Scott Shawcroft 2022-02-18 17:57:18 -08:00 committed by GitHub
commit 918145f768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 1760 additions and 1368 deletions

View File

@ -72,10 +72,10 @@ jobs:
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --emit native
working-directory: tests
- name: mpy Tests
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy -d basics float micropython
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --via-mpy -d basics float micropython
working-directory: tests
- name: Native mpy Tests
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy --emit native -d basics float micropython
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests.py -j1 --via-mpy --emit native -d basics float micropython
working-directory: tests
- name: Build native modules
run: |

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2021 Damien P. George
Copyright (c) 2013-2022 Damien P. George
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -21,11 +21,11 @@ For example::
import framebuf
# FrameBuffer needs 2 bytes for every RGB565 pixel
fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565)
fbuf.fill(0)
fbuf.text('MicroPython!', 0, 0, 0xffff)
fbuf.hline(0, 10, 96, 0xffff)
fbuf.hline(0, 9, 96, 0xffff)
Constructors
------------

View File

@ -80,6 +80,14 @@ Constants
A mutable list of directories to search for imported modules.
.. admonition:: Difference to CPython
:class: attention
On MicroPython, an entry with the value ``".frozen"`` will indicate that import
should search :term:`frozen modules <frozen module>` at that point in the search.
If no frozen module is found then search will *not* look for a directory called
``.frozen``, instead it will continue with the next entry in ``sys.path``.
.. data:: platform
The platform that CircuitPython is running on. For OS/RTOS ports, this is

View File

@ -10,11 +10,13 @@ set(MICROPY_SOURCE_EXTMOD
${MICROPY_EXTMOD_DIR}/machine_i2c.c
${MICROPY_EXTMOD_DIR}/machine_mem.c
${MICROPY_EXTMOD_DIR}/machine_pulse.c
${MICROPY_EXTMOD_DIR}/machine_pwm.c
${MICROPY_EXTMOD_DIR}/machine_signal.c
${MICROPY_EXTMOD_DIR}/machine_spi.c
${MICROPY_EXTMOD_DIR}/modbluetooth.c
${MICROPY_EXTMOD_DIR}/modbtree.c
${MICROPY_EXTMOD_DIR}/modframebuf.c
${MICROPY_EXTMOD_DIR}/modnetwork.c
${MICROPY_EXTMOD_DIR}/modonewire.c
${MICROPY_EXTMOD_DIR}/moduasyncio.c
${MICROPY_EXTMOD_DIR}/modubinascii.c
@ -23,9 +25,11 @@ set(MICROPY_SOURCE_EXTMOD
${MICROPY_EXTMOD_DIR}/moduhashlib.c
${MICROPY_EXTMOD_DIR}/moduheapq.c
${MICROPY_EXTMOD_DIR}/modujson.c
${MICROPY_EXTMOD_DIR}/moduplatform.c
${MICROPY_EXTMOD_DIR}/modurandom.c
${MICROPY_EXTMOD_DIR}/modure.c
${MICROPY_EXTMOD_DIR}/moduselect.c
${MICROPY_EXTMOD_DIR}/modusocket.c
${MICROPY_EXTMOD_DIR}/modussl_axtls.c
${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
${MICROPY_EXTMOD_DIR}/modutimeq.c

View File

@ -9,6 +9,8 @@
#include "py/obj.h"
#include "py/mphal.h"
#if MICROPY_PY_ONEWIRE
/******************************************************************************/
// Low-level 1-Wire routines
@ -139,3 +141,5 @@ const mp_obj_module_t mp_module_onewire = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&onewire_module_globals,
};
#endif // MICROPY_PY_ONEWIRE

146
extmod/moduplatform.c Normal file
View File

@ -0,0 +1,146 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "py/runtime.h"
#include "py/objtuple.h"
#include "py/objstr.h"
#include "py/mphal.h"
#include "genhdr/mpversion.h"
#if MICROPY_PY_UPLATFORM
// platform - Access to underlying platform's identifying data
// TODO: Add more architectures, compilers and libraries.
// See: https://sourceforge.net/p/predef/wiki/Home/
#if defined(__ARM_ARCH)
#define PLATFORM_ARCH "arm"
#elif defined(__x86_64__) || defined(_WIN64)
#define PLATFORM_ARCH "x86_64"
#elif defined(__i386__) || defined(_M_IX86)
#define PLATFORM_ARCH "x86"
#elif defined(__xtensa__) || defined(_M_IX86)
#define PLATFORM_ARCH "xtensa"
#else
#define PLATFORM_ARCH ""
#endif
#if defined(__GNUC__)
#define PLATFORM_COMPILER \
"GCC " \
MP_STRINGIFY(__GNUC__) "." \
MP_STRINGIFY(__GNUC_MINOR__) "." \
MP_STRINGIFY(__GNUC_PATCHLEVEL__)
#elif defined(__ARMCC_VERSION)
#define PLATFORM_COMPILER \
"ARMCC " \
MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
MP_STRINGIFY((__ARMCC_VERSION % 10000))
#elif defined(_MSC_VER)
#if defined(_WIN64)
#define COMPILER_BITS "64 bit"
#elif defined(_M_IX86)
#define COMPILER_BITS "32 bit"
#else
#define COMPILER_BITS ""
#endif
#define PLATFORM_COMPILER \
"MSC v." MP_STRINGIFY(_MSC_VER) " " COMPILER_BITS
#else
#define PLATFORM_COMPILER ""
#endif
#if defined(__GLIBC__)
#define PLATFORM_LIBC_LIB "glibc"
#define PLATFORM_LIBC_VER \
MP_STRINGIFY(__GLIBC__) "." \
MP_STRINGIFY(__GLIBC_MINOR__)
#elif defined(__NEWLIB__)
#define PLATFORM_LIBC_LIB "newlib"
#define PLATFORM_LIBC_VER _NEWLIB_VERSION
#else
#define PLATFORM_LIBC_LIB ""
#define PLATFORM_LIBC_VER ""
#endif
#if defined(__linux)
#define PLATFORM_SYSTEM "Linux"
#elif defined(__unix__)
#define PLATFORM_SYSTEM "Unix"
#elif defined(__CYGWIN__)
#define PLATFORM_SYSTEM "Cygwin"
#elif defined(_WIN32)
#define PLATFORM_SYSTEM "Windows"
#else
#define PLATFORM_SYSTEM "MicroPython"
#endif
#ifndef MICROPY_PLATFORM_VERSION
#define MICROPY_PLATFORM_VERSION ""
#endif
STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-" \
PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER);
STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, PLATFORM_LIBC_LIB);
STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, PLATFORM_LIBC_VER);
STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = {
{&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)}
};
STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return MP_OBJ_FROM_PTR(&info_platform_obj);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform);
STATIC mp_obj_t platform_python_compiler(void) {
return MP_OBJ_FROM_PTR(&info_python_compiler_obj);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler);
STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return MP_OBJ_FROM_PTR(&info_libc_tuple_obj);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver);
STATIC const mp_rom_map_elem_t modplatform_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uplatform) },
{ MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) },
{ MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) },
{ MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) },
};
STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table);
const mp_obj_module_t mp_module_uplatform = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&modplatform_globals,
};
#endif // MICROPY_PY_UPLATFORM

View File

@ -477,11 +477,16 @@ MP_REGISTER_MODULE(MP_QSTR_re, mp_module_ure, MICROPY_PY_URE);
// only if module is enabled by config setting.
#define re1_5_fatal(x) assert(!x)
#include "lib/re1.5/compilecode.c"
#if MICROPY_PY_URE_DEBUG
#include "lib/re1.5/dumpcode.c"
#endif
#include "lib/re1.5/recursiveloop.c"
#include "lib/re1.5/charclass.c"
#if MICROPY_PY_URE_DEBUG
// Make sure the output print statements go to the same output as other Python output.
#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
#include "lib/re1.5/dumpcode.c"
#undef printf
#endif
#endif // MICROPY_PY_URE

View File

@ -36,7 +36,7 @@ class SingletonGenerator:
self.state = None
self.exc = StopIteration()
def __iter__(self):
def __await__(self):
return self
def __next__(self):

View File

@ -66,7 +66,7 @@ async def gather(*aws, return_exceptions=False):
# # cancel all waiting tasks
# raise er
ts[i] = await ts[i]
except Exception as er:
except (core.CancelledError, Exception) as er:
if return_exceptions:
ts[i] = er
else:

View File

@ -130,7 +130,7 @@ class Task:
self.ph_next = None # Paring heap
self.ph_rightmost_parent = None # Paring heap
def __iter__(self):
def __await__(self):
if not self.state:
# Task finished, signal that is has been await'ed on.
self.state = False

View File

@ -17,6 +17,8 @@
#ifdef _WIN32
#define fsync _commit
#else
#include <poll.h>
#endif
typedef struct _mp_obj_vfs_posix_file_t {
@ -180,6 +182,32 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
return 0;
case MP_STREAM_GET_FILENO:
return o->fd;
#if MICROPY_PY_USELECT
case MP_STREAM_POLL: {
#ifdef _WIN32
mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
#else
mp_uint_t ret = 0;
uint8_t pollevents = 0;
if (arg & MP_STREAM_POLL_RD) {
pollevents |= POLLIN;
}
if (arg & MP_STREAM_POLL_WR) {
pollevents |= POLLOUT;
}
struct pollfd pfd = { .fd = o->fd, .events = pollevents };
if (poll(&pfd, 1, 0) > 0) {
if (pfd.revents & POLLIN) {
ret |= MP_STREAM_POLL_RD;
}
if (pfd.revents & POLLOUT) {
ret |= MP_STREAM_POLL_WR;
}
}
return ret;
#endif
}
#endif
default:
*errcode = EINVAL;
return MP_STREAM_ERROR;

View File

@ -2886,6 +2886,10 @@ msgstr ""
msgid "can't load with '%q' index"
msgstr ""
#: py/builtinimport.c
msgid "can't perform relative import"
msgstr ""
#: py/objgenerator.c
msgid "can't send non-None value to a just-started generator"
msgstr ""
@ -2948,10 +2952,6 @@ msgstr ""
msgid "cannot import name %q"
msgstr ""
#: py/builtinimport.c
msgid "cannot perform relative import"
msgstr ""
#: extmod/moductypes.c
msgid "cannot unambiguously get sizeof scalar"
msgstr ""
@ -3642,7 +3642,7 @@ msgstr ""
msgid "matrix is not positive definite"
msgstr ""
#: shared-bindings/wifi/Radio.c
#: ports/espressif/common-hal/wifi/Radio.c
msgid "max_connections must be between 0 and 10"
msgstr ""
@ -4023,6 +4023,10 @@ msgstr ""
msgid "pixel_shader must be displayio.Palette or displayio.ColorConverter"
msgstr ""
#: extmod/vfs_posix_file.c
msgid "poll on file not available on win32"
msgstr ""
#: shared-module/vectorio/Polygon.c
msgid "polygon can only be registered in one parent"
msgstr ""
@ -4068,6 +4072,7 @@ msgstr ""
#: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
#: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h

6
main.c
View File

@ -162,9 +162,9 @@ STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
mp_obj_list_init((mp_obj_list_t *)mp_sys_path, 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
// Frozen modules are in their own pseudo-dir, e.g., ".frozen".
// Prioritize .frozen over /lib.
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_FROZEN_FAKE_DIR_QSTR));
#if MICROPY_MODULE_FROZEN
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
#endif
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
mp_obj_list_init((mp_obj_list_t *)mp_sys_argv, 0);

View File

@ -23,10 +23,7 @@ by the target MicroPython runtime (eg onto a pyboard's filesystem), and then
imported like any other Python module using `import foo`.
Different target runtimes may require a different format of the compiled
bytecode, and such options can be passed to the cross compiler. For example,
the unix port of MicroPython requires the following:
$ ./mpy-cross -mcache-lookup-bc foo.py
bytecode, and such options can be passed to the cross compiler.
If the Python code contains `@native` or `@viper` annotations, then you must
specify `-march` to match the target architecture.

View File

@ -87,7 +87,6 @@ STATIC int usage(char **argv) {
"Target specific options:\n"
"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
"-mno-unicode : don't support unicode in compiled strings\n"
"-mcache-lookup-bc : cache map lookups in the bytecode\n"
"-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n"
"\n"
"Implementation specific options:\n", argv[0]
@ -172,8 +171,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
#ifdef _WIN32
set_fmode_binary();
#endif
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_init(mp_sys_argv, 0);
#if MICROPY_EMIT_NATIVE
// Set default emitter options
@ -184,7 +181,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
// set default compiler configuration
mp_dynamic_compiler.small_int_bits = 31;
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
mp_dynamic_compiler.py_builtins_str_unicode = 1;
#if defined(__i386__)
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
@ -243,10 +239,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
return usage(argv);
}
// TODO check that small_int_bits is within range of host's capabilities
} else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) {
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
} else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) {
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1;
} else if (strcmp(argv[a], "-mno-unicode") == 0) {
mp_dynamic_compiler.py_builtins_str_unicode = 0;
} else if (strcmp(argv[a], "-municode") == 0) {

View File

@ -36,8 +36,6 @@
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
#define MICROPY_COMP_RETURN_IF_EXPR (1)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_READER_POSIX (1)
#define MICROPY_ENABLE_RUNTIME (0)
#define MICROPY_ENABLE_GC (1)

View File

@ -13,6 +13,9 @@ include ../../py/mkenv.mk
-include mpconfigport.mk
include $(VARIANT_DIR)/mpconfigvariant.mk
# Use the default frozen manifest, variants may override this.
FROZEN_MANIFEST ?= variants/manifest.py
# This should be configured by the mpconfigvariant.mk
PROG ?= micropython
@ -39,7 +42,7 @@ CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DI
# Debugging/Optimization
ifdef DEBUG
COPT ?= -O0
COPT ?= -Og
else
COPT ?= -Os
COPT += -DNDEBUG
@ -256,12 +259,14 @@ SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
# SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
ifneq ($(FROZEN_MPY_DIR),)
ifneq ($(FROZEN_MANIFEST),)
# To use frozen code create a manifest.py file with a description of files to
# freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch).
CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
CFLAGS += -DMICROPY_MODULE_FROZEN_STR
CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
MPY_CROSS_FLAGS += -mcache-lookup-bc
CFLAGS += -DMICROPY_MODULE_FROZEN_STR
endif
HASCPP17 = $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 7)
@ -273,9 +278,7 @@ endif
CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99 -std=gnu11,$(CFLAGS) $(CXXFLAGS_MOD))
ifeq ($(MICROPY_FORCE_32BIT),1)
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86'
else
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc'
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86'
endif
ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-)

View File

@ -161,7 +161,7 @@ STATIC void pairheap_test(size_t nops, int *ops) {
mp_pairheap_init_node(pairheap_lt, &node[i]);
}
mp_pairheap_t *heap = mp_pairheap_new(pairheap_lt);
printf("create:");
mp_printf(&mp_plat_print, "create:");
for (size_t i = 0; i < nops; ++i) {
if (ops[i] >= 0) {
heap = mp_pairheap_push(pairheap_lt, heap, &node[ops[i]]);
@ -175,13 +175,13 @@ STATIC void pairheap_test(size_t nops, int *ops) {
;
}
}
printf("\npop all:");
mp_printf(&mp_plat_print, "\npop all:");
while (!mp_pairheap_is_empty(pairheap_lt, heap)) {
mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]);
;
heap = mp_pairheap_pop(pairheap_lt, heap);
}
printf("\n");
mp_printf(&mp_plat_print, "\n");
}
// function to run extra tests for things that can't be checked by scripts

View File

@ -494,16 +494,10 @@ MP_NOINLINE int main_(int argc, char **argv) {
char *home = getenv("HOME");
char *path = getenv("MICROPYPATH");
if (path == NULL) {
#ifdef MICROPY_PY_SYS_PATH_DEFAULT
path = MICROPY_PY_SYS_PATH_DEFAULT;
#else
path = "~/.micropython/lib:/usr/lib/micropython";
#endif
}
size_t path_num = 2; // [0] is for current dir (or base dir of the script)
// [1] is for frozen files.
size_t builtin_path_count = path_num;
if (*path == ':') {
size_t path_num = 1; // [0] is for current dir (or base dir of the script)
if (*path == PATHLIST_SEP_CHAR) {
path_num++;
}
for (char *p = path; p != NULL; p = strchr(p, PATHLIST_SEP_CHAR)) {
@ -516,11 +510,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
mp_obj_t *path_items;
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);
// Frozen modules are in their own pseudo-dir, e.g., ".frozen".
path_items[1] = MP_OBJ_NEW_QSTR(MP_FROZEN_FAKE_DIR_QSTR);
{
char *p = path;
for (mp_uint_t i = builtin_path_count; i < path_num; i++) {
for (mp_uint_t i = 1; i < path_num; i++) {
char *p1 = strchr(p, PATHLIST_SEP_CHAR);
if (p1 == NULL) {
p1 = p + strlen(p);
@ -661,7 +653,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
break;
}
// Set base dir of the script as first entry in sys.path
// Set base dir of the script as first entry in sys.path.
char *p = strrchr(basedir, '/');
path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
free(pathbuf);

View File

@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
@ -48,6 +49,29 @@
#define USE_STATFS 1
#endif
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2, 25)
#include <sys/random.h>
#define _HAVE_GETRANDOM
#endif
#endif
STATIC mp_obj_t mod_os_urandom(mp_obj_t num) {
mp_int_t n = mp_obj_get_int(num);
vstr_t vstr;
vstr_init_len(&vstr, n);
#ifdef _HAVE_GETRANDOM
RAISE_ERRNO(getrandom(vstr.buf, n, 0), errno);
#else
int fd = open("/dev/urandom", O_RDONLY);
RAISE_ERRNO(fd, errno);
RAISE_ERRNO(read(fd, vstr.buf, n), errno);
close(fd);
#endif
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_urandom_obj, mod_os_urandom);
STATIC mp_obj_t mod_os_stat(mp_obj_t path_in) {
struct stat sb;
const char *path = mp_obj_str_get_str(path_in);
@ -308,6 +332,7 @@ STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
{ MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) },
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_os_stat_obj) },
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mod_os_urandom_obj) },
#if MICROPY_PY_OS_STATVFS
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mod_os_statvfs_obj) },
#endif

View File

@ -80,10 +80,14 @@
#endif
#define MICROPY_STREAMS_POSIX_API (1)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1)
#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
#endif
#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
#define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
#endif
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_VFS_POSIX_FILE (1)
#define MICROPY_PY_FUNCTION_ATTRS (1)
@ -107,6 +111,8 @@
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
#define MICROPY_PY_BUILTINS_SLICE_INDICES (1)
#define MICROPY_PY_SYS_ATEXIT (1)
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)
#define MICROPY_PY_SYS_EXIT (1)
#if MICROPY_PY_SYS_SETTRACE
#define MICROPY_PERSISTENT_CODE_SAVE (1)
@ -119,6 +125,9 @@
#define MICROPY_PY_SYS_PLATFORM "linux"
#endif
#endif
#ifndef MICROPY_PY_SYS_PATH_DEFAULT
#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython"
#endif
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_SYS_EXC_INFO (1)

View File

@ -51,7 +51,6 @@
#define MICROPY_PY_MATH_FACTORIAL (1)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
#define MICROPY_PY_IO_BUFFEREDWRITER (1)
#define MICROPY_PY_IO_RESOURCE_STREAM (1)
#define MICROPY_PY_UASYNCIO (1)
#define MICROPY_PY_URE_DEBUG (1)
#define MICROPY_PY_URE_MATCH_GROUPS (1)

View File

@ -12,15 +12,13 @@ CFLAGS += \
LDFLAGS += -fprofile-arcs -ftest-coverage
FROZEN_MANIFEST ?= $(VARIANT_DIR)/manifest.py
USER_C_MODULES = $(TOP)/examples/usercmodule
MICROPY_VFS_FAT = 1
MICROPY_VFS_LFS1 = 1
MICROPY_VFS_LFS2 = 1
FROZEN_DIR=variants/coverage/frzstr
FROZEN_MPY_DIR=variants/coverage/frzmpy
SRC_QRIO := $(patsubst ../../%,%,$(wildcard ../../shared-bindings/qrio/*.c ../../shared-module/qrio/*.c ../../lib/quirc/lib/*.c))
SRC_C += $(SRC_QRIO)

View File

@ -55,7 +55,8 @@
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_STREAMS_NON_BLOCK (0)
#define MICROPY_OPT_COMPUTED_GOTO (0)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0)
#define MICROPY_OPT_MAP_LOOKUP_CACHE (0)
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
#define MICROPY_CPYTHON_COMPAT (0)
@ -87,6 +88,9 @@
#define MICROPY_PY_SYS (1)
#define MICROPY_PY_SYS_EXIT (0)
#define MICROPY_PY_SYS_PLATFORM "linux"
#ifndef MICROPY_PY_SYS_PATH_DEFAULT
#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython"
#endif
#define MICROPY_PY_SYS_MAXSIZE (0)
#define MICROPY_PY_SYS_STDFILES (0)
#define MICROPY_PY_CMATH (0)

14
py/bc.c
View File

@ -314,24 +314,10 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
// The following table encodes the number of bytes that a specific opcode
// takes up. Some opcodes have an extra byte, defined by MP_BC_MASK_EXTRA_BYTE.
// There are 4 special opcodes that have an extra byte only when
// MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE is enabled (and they take a qstr):
// MP_BC_LOAD_NAME
// MP_BC_LOAD_GLOBAL
// MP_BC_LOAD_ATTR
// MP_BC_STORE_ATTR
uint mp_opcode_format(const byte *ip, size_t *opcode_size, bool count_var_uint) {
uint f = MP_BC_FORMAT(*ip);
const byte *ip_start = ip;
if (f == MP_BC_FORMAT_QSTR) {
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
if (*ip == MP_BC_LOAD_NAME
|| *ip == MP_BC_LOAD_GLOBAL
|| *ip == MP_BC_LOAD_ATTR
|| *ip == MP_BC_STORE_ATTR) {
ip += 1;
}
}
ip += 3;
} else {
int extra_byte = (*ip & MP_BC_MASK_EXTRA_BYTE) == 0;

View File

@ -119,13 +119,8 @@ extern const mp_obj_module_t mp_module_utimeq;
extern const mp_obj_module_t mp_module_machine;
extern const mp_obj_module_t mp_module_framebuf;
extern const mp_obj_module_t mp_module_btree;
extern const mp_obj_module_t ulab_user_cmodule;
extern mp_obj_module_t ulab_fft_module;
extern mp_obj_module_t ulab_filter_module;
extern mp_obj_module_t ulab_linalg_module;
extern mp_obj_module_t ulab_numerical_module;
extern mp_obj_module_t ulab_poly_module;
extern const mp_obj_module_t mp_module_ubluetooth;
extern const mp_obj_module_t mp_module_uplatform;
extern const char MICROPY_PY_BUILTINS_HELP_TEXT[];

View File

@ -69,22 +69,18 @@ STATIC void mp_help_add_from_map(mp_obj_t list, const mp_map_t *map) {
#if MICROPY_MODULE_FROZEN
STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) {
while (*name) {
size_t l = strlen(name);
size_t len = strlen(name);
// name should end in '.py' and we strip it off
mp_obj_list_append(list, mp_obj_new_str(name, l - 3));
name += l + 1;
mp_obj_list_append(list, mp_obj_new_str(name, len - 3));
name += len + 1;
}
}
#endif
// These externs were originally declared inside mp_help_print_modules(),
// but they triggered -Wnested-externs, so they were moved outside.
#if MICROPY_MODULE_FROZEN_STR
extern const char mp_frozen_str_names[];
#endif
#if MICROPY_MODULE_FROZEN_MPY
extern const char mp_frozen_mpy_names[];
#if MICROPY_MODULE_FROZEN
extern const char mp_frozen_names[];
#endif
STATIC void mp_help_print_modules(void) {
@ -92,12 +88,8 @@ STATIC void mp_help_print_modules(void) {
mp_help_add_from_map(list, &mp_builtin_module_map);
#if MICROPY_MODULE_FROZEN_STR
mp_help_add_from_names(list, mp_frozen_str_names);
#endif
#if MICROPY_MODULE_FROZEN_MPY
mp_help_add_from_names(list, mp_frozen_mpy_names);
#if MICROPY_MODULE_FROZEN
mp_help_add_from_names(list, mp_frozen_names);
#endif
// sort the list so it's printed in alphabetical order

View File

@ -5,6 +5,7 @@
*
* SPDX-FileCopyrightText: Copyright (c) 2013-2019 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
* Copyright (c) 2021 Jim Mussared
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -50,7 +51,11 @@
#if MICROPY_ENABLE_EXTERNAL_IMPORT
#define PATH_SEP_CHAR '/'
// Must be a string of one byte.
#define PATH_SEP_CHAR "/"
// Virtual sys.path entry that maps to the frozen modules.
#define MP_FROZEN_PATH_PREFIX ".frozen/"
bool mp_obj_is_package(mp_obj_t module) {
mp_obj_t dest[2];
@ -58,31 +63,33 @@ bool mp_obj_is_package(mp_obj_t module) {
return dest[0] != MP_OBJ_NULL;
}
// Stat either frozen or normal module by a given path
// (whatever is available, if at all).
STATIC mp_import_stat_t mp_import_stat_any(const char *path) {
// Wrapper for mp_import_stat (which is provided by the port, and typically
// uses mp_vfs_import_stat) to also search frozen modules. Given an exact
// path to a file or directory (e.g. "foo/bar", foo/bar.py" or "foo/bar.mpy"),
// will return whether the path is a file, directory, or doesn't exist.
STATIC mp_import_stat_t stat_path_or_frozen(const char *path) {
#if MICROPY_MODULE_FROZEN
if (strncmp(MP_FROZEN_FAKE_DIR_SLASH,
path,
MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
mp_import_stat_t st = mp_frozen_stat(path + MP_FROZEN_FAKE_DIR_SLASH_LENGTH);
if (st != MP_IMPORT_STAT_NO_EXIST) {
return st;
}
// Only try and load as a frozen module if it starts with .frozen/.
const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
if (strncmp(path, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
return mp_find_frozen_module(path + frozen_path_prefix_len, NULL, NULL);
}
#endif
return mp_import_stat(path);
}
// Given a path to a .py file, try and find this path as either a .py or .mpy
// in either the filesystem or frozen modules.
STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
mp_import_stat_t stat = stat_path_or_frozen(vstr_null_terminated_str(path));
if (stat == MP_IMPORT_STAT_FILE) {
return stat;
}
#if MICROPY_PERSISTENT_CODE_LOAD
// Didn't find .py -- try the .mpy instead by inserting an 'm' into the '.py'.
vstr_ins_byte(path, path->len - 2, 'm');
stat = mp_import_stat_any(vstr_null_terminated_str(path));
stat = stat_path_or_frozen(vstr_null_terminated_str(path));
if (stat == MP_IMPORT_STAT_FILE) {
return stat;
}
@ -91,8 +98,10 @@ STATIC mp_import_stat_t stat_file_py_or_mpy(vstr_t *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
// Given an import path (e.g. "foo/bar"), try and find "foo/bar" (a directory)
// or "foo/bar.(m)py" in either the filesystem or frozen modules.
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path));
mp_import_stat_t stat = stat_path_or_frozen(vstr_null_terminated_str(path));
DEBUG_printf("stat %s: %d\n", vstr_str(path), stat);
if (stat == MP_IMPORT_STAT_DIR) {
return stat;
@ -103,40 +112,41 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
return stat_file_py_or_mpy(path);
}
STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
// Given a top-level module, try and find it in each of the sys.path entries
// via stat_dir_or_file.
STATIC mp_import_stat_t stat_top_level_dir_or_file(qstr mod_name, vstr_t *dest) {
DEBUG_printf("stat_top_level_dir_or_file: '%s'\n", qstr_str(mod_name));
#if MICROPY_PY_SYS
// extract the list of paths
size_t path_num;
mp_obj_t *path_items;
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
if (path_num == 0) {
#endif
// mp_sys_path is empty, so just use the given file name
vstr_add_strn(dest, file_str, file_len);
return stat_dir_or_file(dest);
#if MICROPY_PY_SYS
} else {
// go through each path looking for a directory or file
for (size_t i = 0; i < path_num; i++) {
vstr_reset(dest);
size_t p_len;
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
if (p_len > 0) {
vstr_add_strn(dest, p, p_len);
vstr_add_char(dest, PATH_SEP_CHAR);
if (path_num > 0) {
// go through each path looking for a directory or file
for (size_t i = 0; i < path_num; i++) {
vstr_reset(dest);
size_t p_len;
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
if (p_len > 0) {
vstr_add_strn(dest, p, p_len);
vstr_add_char(dest, PATH_SEP_CHAR[0]);
}
vstr_add_str(dest, qstr_str(mod_name));
mp_import_stat_t stat = stat_dir_or_file(dest);
if (stat != MP_IMPORT_STAT_NO_EXIST) {
return stat;
}
}
vstr_add_strn(dest, file_str, file_len);
mp_import_stat_t stat = stat_dir_or_file(dest);
if (stat != MP_IMPORT_STAT_NO_EXIST) {
return stat;
}
}
// could not find a directory or file
return MP_IMPORT_STAT_NO_EXIST;
}
// could not find a directory or file
return MP_IMPORT_STAT_NO_EXIST;
}
#endif
// mp_sys_path is empty (or not enabled), so just stat the given path
// directly.
vstr_add_str(dest, qstr_str(mod_name));
return stat_dir_or_file(dest);
}
#if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER
@ -193,19 +203,17 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, co
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
#if MICROPY_MODULE_FROZEN || MICROPY_ENABLE_COMPILER || (MICROPY_PERSISTENT_CODE_LOAD && MICROPY_HAS_FILE_READER)
char *file_str = vstr_null_terminated_str(file);
const char *file_str = vstr_null_terminated_str(file);
#endif
#if MICROPY_MODULE_FROZEN || MICROPY_MODULE_FROZEN_MPY
if (strncmp(MP_FROZEN_FAKE_DIR_SLASH,
file_str,
MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
// If we support frozen modules (either as str or mpy) then try to find the
// requested filename in the list of frozen module filenames.
#if MICROPY_MODULE_FROZEN
void *modref;
int frozen_type = mp_find_frozen_module(file_str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH, file->len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH, &modref);
#endif
// If we support frozen modules (either as str or mpy) then try to find the
// requested filename in the list of frozen module filenames.
#if MICROPY_MODULE_FROZEN
void *modref;
int frozen_type;
const int frozen_path_prefix_len = strlen(MP_FROZEN_PATH_PREFIX);
if (strncmp(file_str, MP_FROZEN_PATH_PREFIX, frozen_path_prefix_len) == 0) {
mp_find_frozen_module(file_str + frozen_path_prefix_len, &frozen_type, &modref);
// If we support frozen str modules and the compiler is enabled, and we
// found the filename in the list of frozen files, then load and execute it.
@ -220,13 +228,12 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// its data) in the list of frozen files, execute it.
#if MICROPY_MODULE_FROZEN_MPY
if (frozen_type == MP_FROZEN_MPY) {
do_execute_raw_code(module_obj, modref, file_str);
do_execute_raw_code(module_obj, modref, file_str + frozen_path_prefix_len);
return;
}
#endif
}
#endif // MICROPY_MODULE_FROZEN || MICROPY_MODULE_FROZEN_MPY
#endif // MICROPY_MODULE_FROZEN
// If we support loading .mpy files then check if the file extension is of
// the correct format and, if so, load and execute the file.
@ -251,15 +258,212 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
#endif
}
STATIC void chop_component(const char *start, const char **end) {
const char *p = *end;
while (p > start) {
// Convert a relative (to the current module) import, going up "level" levels,
// into an absolute import.
STATIC void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) {
// What we want to do here is to take the name of the current module,
// remove <level> trailing components, and concatenate the passed-in
// module name.
// For example, level=3, module_name="foo.bar", __name__="a.b.c.d" --> "a.foo.bar"
// "Relative imports use a module's __name__ attribute to determine that
// module's position in the package hierarchy."
// http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
assert(current_module_name_obj != MP_OBJ_NULL);
#if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT
if (MP_OBJ_QSTR_VALUE(current_module_name_obj) == MP_QSTR___main__) {
// This is a module loaded by -m command-line switch (e.g. unix port),
// and so its __name__ has been set to "__main__". Get its real name
// that we stored during import in the __main__ attribute.
current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
}
#endif
// If we have a __path__ in the globals dict, then we're a package.
bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
#if DEBUG_PRINT
DEBUG_printf("Current module/package: ");
mp_obj_print_helper(MICROPY_DEBUG_PRINTER, current_module_name_obj, PRINT_REPR);
DEBUG_printf(", is_package: %d", is_pkg);
DEBUG_printf("\n");
#endif
size_t current_module_name_len;
const char *current_module_name = mp_obj_str_get_data(current_module_name_obj, &current_module_name_len);
const char *p = current_module_name + current_module_name_len;
if (is_pkg) {
// If we're evaluating relative to a package, then take off one fewer
// level (i.e. the relative search starts inside the package, rather
// than as a sibling of the package).
--level;
}
// Walk back 'level' dots (or run out of path).
while (level && p > current_module_name) {
if (*--p == '.') {
*end = p;
return;
--level;
}
}
*end = p;
// We must have some component left over to import from.
if (p == current_module_name) {
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import"));
}
// New length is len("<chopped path>.<module_name>"). Note: might be one byte
// more than we need if module_name is empty (for the extra . we will
// append).
uint new_module_name_len = (size_t)(p - current_module_name) + 1 + *module_name_len;
char *new_mod = mp_local_alloc(new_module_name_len);
memcpy(new_mod, current_module_name, p - current_module_name);
// Only append ".<module_name>" if there was one).
if (*module_name_len != 0) {
new_mod[p - current_module_name] = '.';
memcpy(new_mod + (p - current_module_name) + 1, *module_name, *module_name_len);
} else {
--new_module_name_len;
}
// Copy into a QSTR.
qstr new_mod_q = qstr_from_strn(new_mod, new_module_name_len);
mp_local_free(new_mod);
DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
*module_name = qstr_str(new_mod_q);
*module_name_len = new_module_name_len;
}
// Load a module at the specified absolute path, possibly as a submodule of the given outer module.
// full_mod_name: The full absolute path to this module (e.g. "foo.bar.baz").
// level_mod_name: The final component of the path (e.g. "baz").
// outer_module_obj: The parent module (we need to store this module as an
// attribute on it) (or MP_OBJ_NULL for top-level).
// path: The filesystem path where we found the parent module
// (or empty for a top level module).
// override_main: Whether to set the __name__ to "__main__" (and use __main__
// for the actual path).
STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, mp_obj_t outer_module_obj, vstr_t *path, bool override_main) {
mp_import_stat_t stat = MP_IMPORT_STAT_NO_EXIST;
// Exact-match of built-in (or already-loaded) takes priority.
mp_obj_t module_obj = mp_module_get_loaded_or_builtin(full_mod_name);
// Even if we find the module, go through the motions of searching for it
// because we may actually be in the process of importing a sub-module.
// So we need to (re-)find the correct path to be finding the sub-module
// on the next iteration of process_import_at_level.
if (outer_module_obj == MP_OBJ_NULL) {
DEBUG_printf("Searching for top-level module\n");
// First module in the dotted-name; search for a directory or file
// relative to all the locations in sys.path.
stat = stat_top_level_dir_or_file(full_mod_name, path);
// If the module "foo" doesn't exist on the filesystem, and it's not a
// builtin, try and find "ufoo" as a built-in. (This feature was
// formerly known as "weak links").
#if MICROPY_MODULE_WEAK_LINKS
if (stat == MP_IMPORT_STAT_NO_EXIST && module_obj == MP_OBJ_NULL) {
char *umodule_buf = vstr_str(path);
umodule_buf[0] = 'u';
strcpy(umodule_buf + 1, qstr_str(level_mod_name));
qstr umodule_name = qstr_from_str(umodule_buf);
module_obj = mp_module_get_builtin(umodule_name);
}
#endif
} else {
DEBUG_printf("Searching for sub-module\n");
// Add the current part of the module name to the path.
vstr_add_char(path, PATH_SEP_CHAR[0]);
vstr_add_str(path, qstr_str(level_mod_name));
// Because it's not top level, we already know which path the parent was found in.
stat = stat_dir_or_file(path);
}
DEBUG_printf("Current path: %.*s\n", (int)vstr_len(path), vstr_str(path));
if (module_obj == MP_OBJ_NULL) {
// Not a built-in and not already-loaded.
if (stat == MP_IMPORT_STAT_NO_EXIST) {
// And the file wasn't found -- fail.
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
#else
mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name);
#endif
}
// Not a built-in but found on the filesystem, try and load it.
DEBUG_printf("Found path: %.*s\n", (int)vstr_len(path), vstr_str(path));
// Prepare for loading from the filesystem. Create a new shell module.
module_obj = mp_obj_new_module(full_mod_name);
#if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
// If this module is being loaded via -m on unix, then
// override __name__ to "__main__". Do this only for *modules*
// however - packages never have their names replaced, instead
// they're -m'ed using a special __main__ submodule in them. (This all
// apparently is done to not touch the package name itself, which is
// important for future imports).
if (override_main && stat != MP_IMPORT_STAT_DIR) {
mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
#if MICROPY_CPYTHON_COMPAT
// Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
// Store real name in "__main__" attribute. Need this for
// resolving relative imports later. "__main__ was chosen
// semi-randonly, to reuse existing qstr's.
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(full_mod_name));
#endif
}
#endif // MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
if (stat == MP_IMPORT_STAT_DIR) {
// Directory -- execute "path/__init__.py".
DEBUG_printf("%.*s is dir\n", (int)vstr_len(path), vstr_str(path));
// Store the __path__ attribute onto this module.
// https://docs.python.org/3/reference/import.html
// "Specifically, any module that contains a __path__ attribute is considered a package."
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(path), vstr_len(path)));
size_t orig_path_len = path->len;
vstr_add_str(path, PATH_SEP_CHAR "__init__.py");
if (stat_file_py_or_mpy(path) == MP_IMPORT_STAT_FILE) {
do_load(module_obj, path);
} else {
// No-op. Nothing to load.
// mp_warning("%s is imported as namespace package", vstr_str(&path));
}
// Remove /__init__.py suffix.
path->len = orig_path_len;
} else { // MP_IMPORT_STAT_FILE
// File -- execute "path.(m)py".
do_load(module_obj, path);
// Note: This should be the last component in the import path. If
// there are remaining components then it's an ImportError
// because the current path(the module that was just loaded) is
// not a package. This will be caught on the next iteration
// because the file will not exist.
}
}
if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(MP_OBJ_TO_PTR(outer_module_obj))) {
// If it's a sub-module (not a built-in one), then make it available on
// the parent module.
mp_store_attr(outer_module_obj, level_mod_name, module_obj);
}
return module_obj;
}
mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
@ -267,14 +471,28 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
DEBUG_printf("__import__:\n");
for (size_t i = 0; i < n_args; i++) {
DEBUG_printf(" ");
mp_obj_print(args[i], PRINT_REPR);
mp_obj_print_helper(MICROPY_DEBUG_PRINTER, args[i], PRINT_REPR);
DEBUG_printf("\n");
}
#endif
mp_obj_t module_name = args[0];
// This is the import path, with any leading dots stripped.
// "import foo.bar" --> module_name="foo.bar"
// "from foo.bar import baz" --> module_name="foo.bar"
// "from . import foo" --> module_name=""
// "from ...foo.bar import baz" --> module_name="foo.bar"
mp_obj_t module_name_obj = args[0];
// These are the imported names.
// i.e. "from foo.bar import baz, zap" --> fromtuple=("baz", "zap",)
// Note: There's a special case on the Unix port, where this is set to mp_const_false which means that it's __main__.
mp_obj_t fromtuple = mp_const_none;
// Level is the number of leading dots in a relative import.
// i.e. "from . import foo" --> level=1
// i.e. "from ...foo.bar import baz" --> level=3
mp_int_t level = 0;
if (n_args >= 4) {
fromtuple = args[3];
if (n_args >= 5) {
@ -285,226 +503,64 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
}
}
size_t mod_len;
const char *mod_str = mp_obj_str_get_data(module_name, &mod_len);
size_t module_name_len;
const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len);
if (level != 0) {
// What we want to do here is to take name of current module,
// chop <level> trailing components, and concatenate with passed-in
// module name, thus resolving relative import name into absolute.
// This even appears to be correct per
// http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name
// "Relative imports use a module's __name__ attribute to determine that
// module's position in the package hierarchy."
level--;
mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
assert(this_name_q != MP_OBJ_NULL);
#if MICROPY_CPYTHON_COMPAT
if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) {
// This is a module run by -m command-line switch, get its real name from backup attribute
this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
}
#endif
mp_map_t *globals_map = &mp_globals_get()->map;
mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
bool is_pkg = (elem != NULL);
#if DEBUG_PRINT
DEBUG_printf("Current module/package: ");
mp_obj_print(this_name_q, PRINT_REPR);
DEBUG_printf(", is_package: %d", is_pkg);
DEBUG_printf("\n");
#endif
size_t this_name_l;
const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);
const char *p = this_name + this_name_l;
if (!is_pkg) {
// We have module, but relative imports are anchored at package, so
// go there.
chop_component(this_name, &p);
}
while (level--) {
chop_component(this_name, &p);
}
// We must have some component left over to import from
if (p == this_name) {
mp_raise_ImportError(MP_ERROR_TEXT("cannot perform relative import"));
}
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
char *new_mod = mp_local_alloc(new_mod_l);
memcpy(new_mod, this_name, p - this_name);
if (mod_len != 0) {
new_mod[p - this_name] = '.';
memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len);
}
qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l);
mp_local_free(new_mod);
DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
module_name = MP_OBJ_NEW_QSTR(new_mod_q);
mod_str = qstr_str(new_mod_q);
mod_len = new_mod_l;
// Turn "foo.bar" into "<current module minus 3 components>.foo.bar".
evaluate_relative_import(level, &module_name, &module_name_len);
}
if (mod_len == 0) {
if (module_name_len == 0) {
mp_raise_ValueError(NULL);
}
// check if module already exists
qstr module_name_qstr = mp_obj_str_get_qstr(module_name);
mp_obj_t module_obj = mp_module_get(module_name_qstr);
if (module_obj != MP_OBJ_NULL) {
DEBUG_printf("Module already loaded\n");
// If it's not a package, return module right away
char *p = strchr(mod_str, '.');
if (p == NULL) {
return module_obj;
}
// If fromlist is not empty, return leaf module
if (fromtuple != mp_const_none) {
return module_obj;
}
// Otherwise, we need to return top-level package
qstr pkg_name = qstr_from_strn(mod_str, p - mod_str);
return mp_module_get(pkg_name);
}
DEBUG_printf("Module not yet loaded\n");
DEBUG_printf("Starting module search for '%s'\n", module_name);
uint last = 0;
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
module_obj = MP_OBJ_NULL;
mp_obj_t top_module_obj = MP_OBJ_NULL;
mp_obj_t outer_module_obj = MP_OBJ_NULL;
uint i;
for (i = 1; i <= mod_len; i++) {
if (i == mod_len || mod_str[i] == '.') {
// create a qstr for the module name up to this depth
qstr mod_name = qstr_from_strn(mod_str, i);
DEBUG_printf("Processing module: %s\n", qstr_str(mod_name));
DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path));
// find the file corresponding to the module name
mp_import_stat_t stat;
if (vstr_len(&path) == 0) {
// first module in the dotted-name; search for a directory or file
DEBUG_printf("Find file =%.*s=\n", vstr_len(&path), vstr_str(&path));
stat = find_file(mod_str, i, &path);
} else {
// latter module in the dotted-name; append to path
vstr_add_char(&path, PATH_SEP_CHAR);
vstr_add_strn(&path, mod_str + last, i - last);
stat = stat_dir_or_file(&path);
}
DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path));
// Search for the end of each component.
size_t current_component_start = 0;
for (size_t i = 1; i <= module_name_len; i++) {
if (i == module_name_len || module_name[i] == '.') {
// The module name up to this depth (e.g. foo.bar.baz).
qstr full_mod_name = qstr_from_strn(module_name, i);
// The current level name (e.g. baz).
qstr level_mod_name = qstr_from_strn(module_name + current_component_start, i - current_component_start);
if (stat == MP_IMPORT_STAT_NO_EXIST) {
// This is just the module name after the previous .
qstr current_module_name = qstr_from_strn(mod_str + last, i - last);
mp_map_elem_t *el = NULL;
if (outer_module_obj == MP_OBJ_NULL) {
el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map,
MP_OBJ_NEW_QSTR(current_module_name),
MP_MAP_LOOKUP);
} else {
el = mp_map_lookup(&((mp_obj_module_t *)outer_module_obj)->globals->map,
MP_OBJ_NEW_QSTR(current_module_name),
MP_MAP_LOOKUP);
}
DEBUG_printf("Processing module: '%s' at level '%s'\n", qstr_str(full_mod_name), qstr_str(level_mod_name));
DEBUG_printf("Previous path: =%.*s=\n", (int)vstr_len(&path), vstr_str(&path));
if (el != NULL && mp_obj_is_type(el->value, &mp_type_module)) {
module_obj = el->value;
mp_module_call_init(mod_name, module_obj);
} else {
// couldn't find the file, so fail
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ImportError(MP_ERROR_TEXT("module not found"));
#else
mp_raise_msg_varg(&mp_type_ImportError,
MP_ERROR_TEXT("no module named '%q'"), mod_name);
#endif
}
} else {
// found the file, so get the module
module_obj = mp_module_get(mod_name);
}
#if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
// On unix, if this is being loaded via -m (magic mp_const_false),
// then handle that if it's the final component.
bool override_main = (i == module_name_len && fromtuple == mp_const_false);
#else
bool override_main = false;
#endif
if (module_obj == MP_OBJ_NULL) {
// module not already loaded, so load it!
// Import this module.
mp_obj_t module_obj = process_import_at_level(full_mod_name, level_mod_name, outer_module_obj, &path, override_main);
module_obj = mp_obj_new_module(mod_name);
// if args[3] (fromtuple) has magic value False, set up
// this module for command-line "-m" option (set module's
// name to __main__ instead of real name). Do this only
// for *modules* however - packages never have their names
// replaced, instead they're -m'ed using a special __main__
// submodule in them. (This all apparently is done to not
// touch package name itself, which is important for future
// imports).
if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) {
mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
#if MICROPY_CPYTHON_COMPAT
// Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules).
mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj);
// Store real name in "__main__" attribute. Chosen semi-randonly, to reuse existing qstr's.
mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name));
#endif
}
if (stat == MP_IMPORT_STAT_DIR) {
DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path));
// https://docs.python.org/3/reference/import.html
// "Specifically, any module that contains a __path__ attribute is considered a package."
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));
size_t orig_path_len = path.len;
vstr_add_char(&path, PATH_SEP_CHAR);
vstr_add_str(&path, "__init__.py");
if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) {
// mp_warning("%s is imported as namespace package", vstr_str(&path));
} else {
do_load(module_obj, &path);
}
path.len = orig_path_len;
} else { // MP_IMPORT_STAT_FILE
do_load(module_obj, &path);
// This should be the last component in the import path. If there are
// remaining components then it's an ImportError because the current path
// (the module that was just loaded) is not a package. This will be caught
// on the next iteration because the file will not exist.
}
// Loading a module thrashes the heap significantly so we explicitly clean up
// afterwards.
gc_collect();
}
if (outer_module_obj != MP_OBJ_NULL && VERIFY_PTR(MP_OBJ_TO_PTR(outer_module_obj))) {
qstr s = qstr_from_strn(mod_str + last, i - last);
mp_store_attr(outer_module_obj, s, module_obj);
// The above store can cause a dictionary rehash and new allocation. So,
// lets make sure the globals dictionary is still long lived.
mp_obj_module_set_globals(outer_module_obj,
make_dict_long_lived(mp_obj_module_get_globals(outer_module_obj), 10));
}
// Set this as the parent module, and remember the top-level module if it's the first.
outer_module_obj = module_obj;
if (top_module_obj == MP_OBJ_NULL) {
top_module_obj = module_obj;
}
last = i + 1;
current_component_start = i + 1;
}
}
// If fromlist is not empty, return leaf module
if (fromtuple != mp_const_none) {
return module_obj;
// If fromtuple is not empty, return leaf module
return outer_module_obj;
} else {
// Otherwise, we need to return top-level package
return top_module_obj;
}
// Otherwise, we need to return top-level package
return top_module_obj;
}
#else // MICROPY_ENABLE_EXTERNAL_IMPORT
@ -517,17 +573,19 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
// Check if module already exists, and return it if it does
qstr module_name_qstr = mp_obj_str_get_qstr(args[0]);
mp_obj_t module_obj = mp_module_get(module_name_qstr);
mp_obj_t module_obj = mp_module_get_loaded_or_builtin(module_name_qstr);
if (module_obj != MP_OBJ_NULL) {
return module_obj;
}
#if MICROPY_MODULE_WEAK_LINKS
// Check if there is a weak link to this module
module_obj = mp_module_search_umodule(qstr_str(module_name_qstr));
char umodule_buf[MICROPY_ALLOC_PATH_MAX];
umodule_buf[0] = 'u';
strcpy(umodule_buf + 1, args[0]);
qstr umodule_name_qstr = qstr_from_str(umodule_buf);
module_obj = mp_module_get_loaded_or_builtin(umodule_name_qstr);
if (module_obj != MP_OBJ_NULL) {
// Found weak-linked module
mp_module_call_init(module_name_qstr, module_obj);
return module_obj;
}
#endif

View File

@ -87,6 +87,7 @@ extern void common_hal_mcu_enable_interrupts(void);
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE)
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH)
#define MICROPY_OPT_MAP_LOOKUP_CACHE (CIRCUITPY_OPT_MAP_LOOKUP_CACHE)
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE)
#define MICROPY_PERSISTENT_CODE_LOAD (1)
@ -541,5 +542,16 @@ void supervisor_run_background_tasks_if_tick(void);
#define USB_MIDI_EP_NUM_IN (0)
#endif
#ifndef MICROPY_WRAP_MP_MAP_LOOKUP
#define MICROPY_WRAP_MP_MAP_LOOKUP PLACE_IN_ITCM
#endif
#ifndef MICROPY_WRAP_MP_BINARY_OP
#define MICROPY_WRAP_MP_BINARY_OP PLACE_IN_ITCM
#endif
#ifndef MICROPY_WRAP_MP_EXECUTE_BYTECODE
#define MICROPY_WRAP_MP_EXECUTE_BYTECODE PLACE_IN_ITCM
#endif
#endif // __INCLUDED_MPCONFIG_CIRCUITPY_H

View File

@ -162,13 +162,8 @@ CFLAGS += -DCIRCUITPY_COMPUTED_GOTO_SAVE_SPACE=$(CIRCUITPY_COMPUTED_GOTO_SAVE_SP
CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH ?= 1
CFLAGS += -DCIRCUITPY_OPT_LOAD_ATTR_FAST_PATH=$(CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH)
# This is disabled because it changes the bytecode format. We could choose to enable it
# when we go to 8.x, but probably not for 7.1.
CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ?= 0
CFLAGS += -DCIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE=$(CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE)
ifeq ($(CIRCUITPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE),1)
MPY_CROSS_FLAGS += -mcache-lookup-bc
endif
CIRCUITPY_OPT_MAP_LOOKUP_CACHE ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_OPT_MAP_LOOKUP_CACHE=$(CIRCUITPY_OPT_MAP_LOOKUP_CACHE)
CIRCUITPY_CONSOLE_UART ?= 0
CFLAGS += -DCIRCUITPY_CONSOLE_UART=$(CIRCUITPY_CONSOLE_UART)
@ -489,6 +484,7 @@ CFLAGS += -DLONGINT_IMPL_LONGLONG
else
$(error LONGINT_IMPL set to surprising value: "$(LONGINT_IMPL)")
endif
MPY_TOOL_FLAGS += $(MPY_TOOL_LONGINT_IMPL)
###
ifeq ($(LONGINT_IMPL),NONE)
@ -497,3 +493,16 @@ else ifeq ($(LONGINT_IMPL),LONGLONG)
else
$(error LONGINT_IMPL set to surprising value: "$(LONGINT_IMPL)")
endif
PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
ifneq ($(FROZEN_MPY_DIRS),)
$(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
$(ECHO) FREEZE $(FROZEN_MPY_DIRS)
$(Q)$(MKDIR) -p $@
$(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
$(BUILD)/manifest.py: $(BUILD)/frozen_mpy | $(TOP)/py/circuitpy_mpconfig.mk mpconfigport.mk boards/$(BOARD)/mpconfigboard.mk
$(ECHO) MKMANIFEST $(FROZEN_MPY_DIRS)
(cd $(BUILD)/frozen_mpy && find * -name \*.py -exec printf 'freeze_as_mpy("frozen_mpy", "%s")\n' {} \; )> $@.tmp && mv -f $@.tmp $@
FROZEN_MANIFEST=$(BUILD)/manifest.py
endif

View File

@ -61,6 +61,12 @@ typedef enum {
#undef DEF_RULE_NC
} pn_kind_t;
// Whether a mp_parse_node_struct_t that has pns->kind == PN_testlist_comp
// corresponds to a list comprehension or generator.
#define MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns) \
(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2 && \
MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for))
#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE
#if NEED_METHOD_TABLE
@ -319,25 +325,13 @@ STATIC void compile_delete_id(compiler_t *comp, qstr qst) {
}
}
STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
int total = 0;
if (!MP_PARSE_NODE_IS_NULL(pn)) {
compile_node(comp, pn);
total += 1;
}
if (pns_list != NULL) {
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
for (int i = 0; i < n; i++) {
compile_node(comp, pns_list->nodes[i]);
}
total += n;
}
EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE);
}
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
// a simple tuple expression
c_tuple(comp, MP_PARSE_NODE_NULL, pns);
size_t num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (size_t i = 0; i < num_nodes; i++) {
compile_node(comp, pns->nodes[i]);
}
EMIT_ARG(build, num_nodes, MP_EMIT_BUILD_TUPLE);
}
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
@ -454,21 +448,14 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("can't assign to expression"));
}
// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
STATIC void c_assign_tuple(compiler_t *comp, uint num_tail, mp_parse_node_t *nodes_tail) {
// look for star expression
uint have_star_index = -1;
if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
EMIT_ARG(unpack_ex, 0, num_tail);
have_star_index = 0;
}
for (uint i = 0; i < num_tail; i++) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
if (have_star_index == (uint)-1) {
EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
have_star_index = num_head + i;
EMIT_ARG(unpack_ex, i, num_tail - i - 1);
have_star_index = i;
} else {
compile_syntax_error(comp, nodes_tail[i], MP_ERROR_TEXT("multiple *x in assignment"));
return;
@ -476,17 +463,10 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
}
}
if (have_star_index == (uint)-1) {
EMIT_ARG(unpack_sequence, num_head + num_tail);
}
if (num_head != 0) {
if (0 == have_star_index) {
c_assign(comp, ((mp_parse_node_struct_t *)node_head)->nodes[0], ASSIGN_STORE);
} else {
c_assign(comp, node_head, ASSIGN_STORE);
}
EMIT_ARG(unpack_sequence, num_tail);
}
for (uint i = 0; i < num_tail; i++) {
if (num_head + i == have_star_index) {
if (i == have_star_index) {
c_assign(comp, ((mp_parse_node_struct_t *)nodes_tail[i])->nodes[0], ASSIGN_STORE);
} else {
c_assign(comp, nodes_tail[i], ASSIGN_STORE);
@ -528,7 +508,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
if (assign_kind != ASSIGN_STORE) {
goto cannot_assign;
}
c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
break;
case PN_atom_paren:
@ -553,13 +533,13 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
}
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// empty list, assignment allowed
c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
c_assign_tuple(comp, 0, NULL);
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
pns = (mp_parse_node_struct_t *)pns->nodes[0];
goto testlist_comp;
} else {
// brackets around 1 item
c_assign_tuple(comp, pns->nodes[0], 0, NULL);
c_assign_tuple(comp, 1, pns->nodes);
}
break;
@ -570,27 +550,10 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
testlist_comp:
// lhs is a sequence
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];
if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
// sequence of one item, with trailing comma
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
c_assign_tuple(comp, pns->nodes[0], 0, NULL);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
// sequence of many items
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
goto cannot_assign;
} else {
// sequence with 2 items
goto sequence_with_2_items;
}
} else {
// sequence with 2 items
sequence_with_2_items:
c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
goto cannot_assign;
}
c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
return;
}
return;
@ -993,32 +956,11 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
} else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp));
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
// TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) {
// sequence of one item, with trailing comma
assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0]));
c_del_stmt(comp, pns->nodes[0]);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) {
// sequence of many items
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
c_del_stmt(comp, pns->nodes[0]);
for (int i = 0; i < n; i++) {
c_del_stmt(comp, pns1->nodes[i]);
}
} else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) {
goto cannot_delete;
} else {
// sequence with 2 items
goto sequence_with_2_items;
}
} else {
// sequence with 2 items
sequence_with_2_items:
c_del_stmt(comp, pns->nodes[0]);
c_del_stmt(comp, pns->nodes[1]);
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
goto cannot_delete;
}
for (size_t i = 0; i < MP_PARSE_NODE_STRUCT_NUM_NODES(pns); ++i) {
c_del_stmt(comp, pns->nodes[i]);
}
}
} else {
@ -2502,31 +2444,16 @@ STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns,
STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// an empty tuple
c_tuple(comp, MP_PARSE_NODE_NULL, NULL);
EMIT_ARG(build, 0, MP_EMIT_BUILD_TUPLE);
} else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
pns = (mp_parse_node_struct_t *)pns->nodes[0];
assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1]));
if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1];
if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
// tuple of one item, with trailing comma
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
c_tuple(comp, pns->nodes[0], NULL);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
// tuple of many items
c_tuple(comp, pns->nodes[0], pns2);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
// generator expression
compile_comprehension(comp, pns, SCOPE_GEN_EXPR);
} else {
// tuple with 2 items
goto tuple_with_2_items;
}
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) {
// generator expression
compile_comprehension(comp, pns, SCOPE_GEN_EXPR);
} else {
// tuple with 2 items
tuple_with_2_items:
c_tuple(comp, MP_PARSE_NODE_NULL, pns);
// tuple with N items
compile_generic_tuple(comp, pns);
}
}
}
@ -2537,31 +2464,13 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns)
EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[0];
if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) {
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pns2->nodes[1];
if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) {
// list of one item, with trailing comma
assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0]));
compile_node(comp, pns2->nodes[0]);
EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) {
// list of many items
compile_node(comp, pns2->nodes[0]);
compile_generic_all_nodes(comp, pns3);
EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) {
// list comprehension
compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
} else {
// list with 2 items
goto list_with_2_items;
}
if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns2)) {
// list comprehension
compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
} else {
// list with 2 items
list_with_2_items:
compile_node(comp, pns2->nodes[0]);
compile_node(comp, pns2->nodes[1]);
EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST);
// list with N items
compile_generic_all_nodes(comp, pns2);
EMIT_ARG(build, MP_PARSE_NODE_STRUCT_NUM_NODES(pns2), MP_EMIT_BUILD_LIST);
}
} else {
// list with 1 item

View File

@ -46,7 +46,6 @@ ifeq ($(ARCH),x86)
# x86
CROSS =
CFLAGS += -m32 -fno-stack-protector
MPY_CROSS_FLAGS += -mcache-lookup-bc
MICROPY_FLOAT_IMPL ?= double
else ifeq ($(ARCH),x64)
@ -54,7 +53,6 @@ else ifeq ($(ARCH),x64)
# x64
CROSS =
CFLAGS += -fno-stack-protector
MPY_CROSS_FLAGS += -mcache-lookup-bc
MICROPY_FLOAT_IMPL ?= double
else ifeq ($(ARCH),armv7m)

View File

@ -560,9 +560,6 @@ void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) {
MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL);
(void)qst;
emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
emit_write_bytecode_raw_byte(emit, 0);
}
}
void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {
@ -596,9 +593,6 @@ void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) {
}
emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst);
}
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
emit_write_bytecode_raw_byte(emit, 0);
}
}
void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {

View File

@ -1588,6 +1588,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
int reg_base = REG_ARG_1;
int reg_index = REG_ARG_2;
emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_index);
need_reg_single(emit, REG_RET, 0);
switch (vtype_base) {
case VTYPE_PTR8: {
// pointer to 8-bit memory
@ -1651,6 +1652,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
int reg_index = REG_ARG_2;
emit_pre_pop_reg_flexible(emit, &vtype_index, &reg_index, REG_ARG_1, REG_ARG_1);
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
need_reg_single(emit, REG_RET, 0);
if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
MP_ERROR_TEXT("can't load with '%q' index"), vtype_to_qstr(vtype_index));

View File

@ -5,6 +5,7 @@
*
* Copyright (c) 2015 Paul Sokolovsky
* SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George
* SPDX-FileCopyrightText: Copyright (c) 2021 Jim Mussared
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -31,6 +32,13 @@
#include "py/lexer.h"
#include "py/frozenmod.h"
#if MICROPY_MODULE_FROZEN
// Null-separated frozen file names. All string-type entries are listed first,
// followed by mpy-type entries. Use mp_frozen_str_sizes to determine how
// many string entries.
extern const char mp_frozen_names[];
#if MICROPY_MODULE_FROZEN_STR
#ifndef MICROPY_MODULE_FROZEN_LEXER
@ -39,129 +47,89 @@
mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
#endif
extern const char mp_frozen_str_names[];
// Size in bytes of each string entry, followed by a zero (terminator).
extern const uint32_t mp_frozen_str_sizes[];
// Null-separated string content.
extern const char mp_frozen_str_content[];
// str_len is length of str. *len is set on on output to size of content
const char *mp_find_frozen_str(const char *str, size_t str_len, size_t *len) {
// If the frozen module pseudo dir (e.g., ".frozen/") is a prefix of str, remove it.
if (strncmp(str, MP_FROZEN_FAKE_DIR_SLASH, MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
str = str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
str_len = str_len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
}
const char *name = mp_frozen_str_names;
size_t offset = 0;
for (int i = 0; *name != 0; i++) {
size_t l = strlen(name);
if (l == str_len && !memcmp(str, name, l)) {
*len = mp_frozen_str_sizes[i];
return mp_frozen_str_content + offset;
}
name += l + 1;
offset += mp_frozen_str_sizes[i] + 1;
}
return NULL;
}
STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t str_len) {
size_t file_len;
const char *content = mp_find_frozen_str(str, str_len, &file_len);
if (content == NULL) {
return NULL;
}
qstr source = qstr_from_strn(str, str_len);
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, file_len, 0);
return lex;
}
#endif
#endif // MICROPY_MODULE_FROZEN_STR
#if MICROPY_MODULE_FROZEN_MPY
#include "py/emitglue.h"
extern const char mp_frozen_mpy_names[];
extern const mp_raw_code_t *const mp_frozen_mpy_content[];
STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t str_len) {
const char *name = mp_frozen_mpy_names;
for (size_t i = 0; *name != 0; i++) {
size_t l = strlen(name);
if (l == str_len && !memcmp(str, name, l)) {
return mp_frozen_mpy_content[i];
}
name += l + 1;
}
return NULL;
}
#endif // MICROPY_MODULE_FROZEN_MPY
#endif
#if MICROPY_MODULE_FROZEN
STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) {
// Search for "str" as a frozen entry, returning the stat result
// (no-exist/file/dir), as well as the type (none/str/mpy) and data.
// frozen_type can be NULL if its value isn't needed (and then data is assumed to be NULL).
mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data) {
size_t len = strlen(str);
const char *name = mp_frozen_names;
if (frozen_type != NULL) {
*frozen_type = MP_FROZEN_NONE;
}
// Count the number of str lengths we have to find how many str entries.
size_t num_str = 0;
#if MICROPY_MODULE_FROZEN_STR && MICROPY_MODULE_FROZEN_MPY
for (const uint32_t *s = mp_frozen_str_sizes; *s != 0; ++s) {
++num_str;
}
#endif
for (size_t i = 0; *name != 0; i++) {
size_t entry_len = strlen(name);
if (entry_len >= len && memcmp(str, name, len) == 0) {
// Query is a prefix of the current entry.
if (entry_len == len) {
// Exact match --> file.
if (frozen_type != NULL) {
#if MICROPY_MODULE_FROZEN_STR
if (i < num_str) {
*frozen_type = MP_FROZEN_STR;
// Use the size table to figure out where this index starts.
size_t offset = 0;
for (size_t j = 0; j < i; ++j) {
offset += mp_frozen_str_sizes[j] + 1;
}
size_t content_len = mp_frozen_str_sizes[i];
const char *content = &mp_frozen_str_content[offset];
// Note: str & len have been updated by find_frozen_entry to strip
// the ".frozen/" prefix (to avoid this being a distinct qstr to
// the original path QSTR in frozen_content.c).
qstr source = qstr_from_strn(str, len);
mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, content_len, 0);
*data = lex;
}
#endif
#if MICROPY_MODULE_FROZEN_MPY
if (i >= num_str) {
*frozen_type = MP_FROZEN_MPY;
// Load the corresponding index as a raw_code, taking
// into account any string entries to offset by.
*data = (void *)mp_frozen_mpy_content[i - num_str];
}
#endif
}
for (int i = 0; *name != 0; i++) {
size_t l = strlen(name);
if (l >= len && !memcmp(str, name, len)) {
if (name[len] == 0) {
return MP_IMPORT_STAT_FILE;
} else if (name[len] == '/') {
// Matches up to directory separator, this is a valid
// directory path.
return MP_IMPORT_STAT_DIR;
}
}
name += l + 1;
// Skip null separator.
name += entry_len + 1;
}
return MP_IMPORT_STAT_NO_EXIST;
}
mp_import_stat_t mp_frozen_stat(const char *str) {
mp_import_stat_t stat;
#if MICROPY_MODULE_FROZEN_STR
stat = mp_frozen_stat_helper(mp_frozen_str_names, str);
if (stat != MP_IMPORT_STAT_NO_EXIST) {
return stat;
}
#endif
#if MICROPY_MODULE_FROZEN_MPY
stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str);
if (stat != MP_IMPORT_STAT_NO_EXIST) {
return stat;
}
#endif
return MP_IMPORT_STAT_NO_EXIST;
}
int mp_find_frozen_module(const char *str, size_t len, void **data) {
// If the frozen module pseudo dir (e.g., ".frozen/") is a prefix of str, remove it.
if (strncmp(str, MP_FROZEN_FAKE_DIR_SLASH, MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) {
str = str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
len = len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH;
}
#if MICROPY_MODULE_FROZEN_STR
mp_lexer_t *lex = mp_lexer_frozen_str(str, len);
if (lex != NULL) {
*data = lex;
return MP_FROZEN_STR;
}
#endif
#if MICROPY_MODULE_FROZEN_MPY
const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len);
if (rc != NULL) {
*data = (void *)rc;
return MP_FROZEN_MPY;
}
#endif
return MP_FROZEN_NONE;
}
#endif
#endif // MICROPY_MODULE_FROZEN

View File

@ -35,18 +35,6 @@ enum {
MP_FROZEN_MPY,
};
// Frozen modules are in a pseudo-directory, so sys.path can control how they're found.
#define MP_FROZEN_FAKE_DIR ".frozen"
#define MP_FROZEN_FAKE_DIR_LENGTH (sizeof(MP_FROZEN_FAKE_DIR) - 1)
#define MP_FROZEN_FAKE_DIR_SLASH (MP_FROZEN_FAKE_DIR "/")
#define MP_FROZEN_FAKE_DIR_SLASH_LENGTH (sizeof(MP_FROZEN_FAKE_DIR_SLASH) - 1)
// This should match MP_FROZEN_FAKE_DIR.
#define MP_FROZEN_FAKE_DIR_QSTR MP_QSTR__dot_frozen
int mp_find_frozen_module(const char *str, size_t len, void **data);
const char *mp_find_frozen_str(const char *str, size_t str_len, size_t *len);
mp_import_stat_t mp_frozen_stat(const char *str);
mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data);
#endif // MICROPY_INCLUDED_PY_FROZENMOD_H

View File

@ -238,6 +238,7 @@ STATIC void gc_mark_subtree(size_t block) {
// Start with the block passed in the argument.
size_t sp = 0;
for (;;) {
MICROPY_GC_HOOK_LOOP
// work out number of consecutive blocks in the chain starting with this one
size_t n_blocks = 0;
do {
@ -247,6 +248,7 @@ STATIC void gc_mark_subtree(size_t block) {
// check this block's children
void **ptrs = (void **)PTR_FROM_BLOCK(block);
for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) {
MICROPY_GC_HOOK_LOOP
void *ptr = *ptrs;
if (VERIFY_PTR(ptr)) {
// Mark and push this pointer
@ -280,6 +282,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
// scan entire memory looking for blocks which have been marked but not their children
for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
MICROPY_GC_HOOK_LOOP
// trace (again) if mark bit set
if (ATB_GET_KIND(block) == AT_MARK) {
gc_mark_subtree(block);
@ -295,6 +298,7 @@ STATIC void gc_sweep(void) {
// free unmarked heads and their tails
int free_tail = 0;
for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
MICROPY_GC_HOOK_LOOP
switch (ATB_GET_KIND(block)) {
case AT_HEAD:
#if MICROPY_ENABLE_FINALISER
@ -407,6 +411,7 @@ static void *gc_get_ptr(void **ptrs, int i) {
void gc_collect_root(void **ptrs, size_t len) {
for (size_t i = 0; i < len; i++) {
MICROPY_GC_HOOK_LOOP
void *ptr = gc_get_ptr(ptrs, i);
gc_mark(ptr);
}

View File

@ -365,9 +365,16 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring)
// (MicroPython limitation) note: this is completely unaware of
// Python syntax and will not handle any expression containing '}' or ':'.
// e.g. f'{"}"}' or f'{foo({})}'.
while (!is_end(lex) && !is_char_or(lex, ':', '}')) {
unsigned int nested_bracket_level = 0;
while (!is_end(lex) && (nested_bracket_level != 0 || !is_char_or(lex, ':', '}'))) {
unichar c = CUR_CHAR(lex);
if (c == '[' || c == '{') {
nested_bracket_level += 1;
} else if (c == ']' || c == '}') {
nested_bracket_level -= 1;
}
// like the default case at the end of this function, stay 8-bit clean
vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex));
vstr_add_byte(&lex->fstring_args, c);
next_char(lex);
}
if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') {

View File

@ -42,6 +42,27 @@
#define DEBUG_printf(...) (void)0
#endif
#if MICROPY_OPT_MAP_LOOKUP_CACHE
// MP_STATE_VM(map_lookup_cache) provides a cache of index to the last known
// position of that index in any map. On a cache hit, this allows
// short-circuiting the full linear search in the case of an ordered map
// (i.e. all builtin modules and objects' locals dicts), and computation of
// the hash (and potentially some linear probing) in the case of a regular
// map. Note the same cache is shared across all maps.
// Gets the index into the cache for this index. Shift down by two to remove
// mp_obj_t tag bits.
#define MAP_CACHE_OFFSET(index) ((((uintptr_t)(index)) >> 2) % MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE)
// Gets the map cache entry for the corresponding index.
#define MAP_CACHE_ENTRY(index) (MP_STATE_VM(map_lookup_cache)[MAP_CACHE_OFFSET(index)])
// Retrieve the mp_obj_t at the location suggested by the cache.
#define MAP_CACHE_GET(map, index) (&(map)->table[MAP_CACHE_ENTRY(index) % (map)->alloc])
// Update the cache for this index.
#define MAP_CACHE_SET(index, pos) MAP_CACHE_ENTRY(index) = (pos) & 0xff;
#else
#define MAP_CACHE_SET(index, pos)
#endif
// This table of sizes is used to control the growth of hash tables.
// The first set of sizes are chosen so the allocation fits exactly in a
// 4-word GC block, and it's not so important for these small values to be
@ -134,10 +155,22 @@ STATIC void mp_map_rehash(mp_map_t *map) {
// - returns slot, with key non-null and value=MP_OBJ_NULL if it was added
// MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour:
// - returns NULL if not found, else the slot if was found in with key null and value non-null
mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
mp_map_elem_t *MICROPY_WRAP_MP_MAP_LOOKUP(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
// If the map is a fixed array then we must only be called for a lookup
assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP);
#if MICROPY_OPT_MAP_LOOKUP_CACHE
// Try the cache for lookup or add-if-not-found.
if (lookup_kind != MP_MAP_LOOKUP_REMOVE_IF_FOUND && map->alloc) {
mp_map_elem_t *slot = MAP_CACHE_GET(map, index);
// Note: Just comparing key for value equality will have false negatives, but
// these will be handled by the regular path below.
if (slot->key == index) {
return slot;
}
}
#endif
// Work out if we can compare just pointers
bool compare_only_ptrs = map->all_keys_are_qstrs;
if (compare_only_ptrs) {
@ -174,6 +207,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m
elem->value = value;
}
#endif
MAP_CACHE_SET(index, elem - map->table);
return elem;
}
}
@ -256,6 +290,7 @@ mp_map_elem_t *PLACE_IN_ITCM(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_m
}
// keep slot->value so that caller can access it if needed
}
MAP_CACHE_SET(index, pos);
return slot;
}

View File

@ -10,6 +10,15 @@ set(MICROPY_QSTRDEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h")
set(MICROPY_QSTRDEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h")
set(MICROPY_QSTRDEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h")
# Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen
# manifest handling is at the end of this file.
if(MICROPY_FROZEN_MANIFEST)
target_compile_definitions(${MICROPY_TARGET} PUBLIC
MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
MICROPY_MODULE_FROZEN_MPY=\(1\)
)
endif()
# Provide defaults for preprocessor flags if not already defined
if(NOT MICROPY_CPP_FLAGS)
get_target_property(MICROPY_CPP_INC ${MICROPY_TARGET} INCLUDE_DIRECTORIES)
@ -120,10 +129,7 @@ if(MICROPY_FROZEN_MANIFEST)
${MICROPY_FROZEN_CONTENT}
)
target_compile_definitions(${MICROPY_TARGET} PUBLIC
MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
MICROPY_MODULE_FROZEN_MPY=\(1\)
)
# Note: target_compile_definitions already added earlier.
if(NOT MICROPY_LIB_DIR)
set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)

View File

@ -125,46 +125,18 @@ $(MICROPY_MPYCROSS_DEPENDENCY):
$(MAKE) -C $(dir $@)
endif
ifneq ($(FROZEN_MANIFEST),)
# to build frozen_content.c from a manifest
$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
ifneq ($(FROZEN_DIR),)
$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST)
$(error Support for FROZEN_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html)
endif
ifneq ($(FROZEN_MPY_DIR),)
$(error FROZEN_MPY_DIR cannot be used in conjunction with FROZEN_MANIFEST)
endif
$(error Support for FROZEN_MPY_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html)
endif
ifneq ($(FROZEN_DIR),)
$(info Warning: FROZEN_DIR is deprecated in favour of FROZEN_MANIFEST)
$(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS)
$(STEPECHO) "Generating $@"
$(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@
endif
ifneq ($(FROZEN_MPY_DIRS),)
# Copy all the modules and single python files to freeze to a common area, omitting top-level dirs (the repo names).
# Do any preprocessing necessary: currently, this adds version information, removes examples, and
# non-library .py files in the modules (setup.py and conf.py)
# Then compile .mpy files from all the .py files, placing them in the same directories as the .py files.
$(BUILD)/frozen_mpy: $(FROZEN_MPY_DIRS)
$(ECHO) FREEZE $(FROZEN_MPY_DIRS)
$(Q)$(MKDIR) -p $@
$(Q)$(PREPROCESS_FROZEN_MODULES) -o $@ $(FROZEN_MPY_DIRS)
$(Q)$(CD) $@ && \
$(FIND) -L . -type f -name '*.py' | sed 's=^\./==' | \
xargs -n1 "$(abspath $(MICROPY_MPYCROSS_DEPENDENCY))" $(MPY_CROSS_FLAGS)
# to build frozen_mpy.c from all .mpy files
# You need to define MPY_TOOL_LONGINT_IMPL in mpconfigport.mk
# if the default will not work (mpz is the default).
$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h $(TOP)/tools/mpy-tool.py
$(STEPECHO) "Creating $@"
$(Q)$(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@
ifneq ($(FROZEN_MANIFEST),)
# to build frozen_content.c from a manifest
$(BUILD)/frozen_content.c: FORCE $(FROZEN_MANIFEST) $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY) $(TOP)/tools/makemanifest.py
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
endif
ifneq ($(PROG),)
@ -220,27 +192,6 @@ clean:
$(RM) -rf $(BUILD) $(CLEAN_EXTRA)
.PHONY: clean
# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup.
# We run rmdir below to avoid empty backup dir (it will silently fail if backup
# is non-empty).
clean-frozen:
if [ -n "$(FROZEN_MPY_DIR)" ]; then \
backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
rmdir ../$$backup_dir 2>/dev/null || true; \
git clean -d -f .; \
fi
if [ -n "$(FROZEN_DIR)" ]; then \
backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
| xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
rmdir ../$$backup_dir 2>/dev/null || true; \
git clean -d -f .; \
fi
.PHONY: clean-frozen
print-cfg:
$(ECHO) "PY_SRC = $(PY_SRC)"
$(ECHO) "BUILD = $(BUILD)"

View File

@ -786,6 +786,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
// Extra builtins as defined by a port
MICROPY_PORT_BUILTINS
MICROPY_PORT_EXTRA_BUILTINS
};
MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table);

View File

@ -212,50 +212,6 @@ STATIC const mp_obj_type_t mp_type_bufwriter = {
};
#endif // MICROPY_PY_IO_BUFFEREDWRITER
#if MICROPY_PY_IO_RESOURCE_STREAM
STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX);
size_t len;
// As an extension to pkg_resources.resource_stream(), we support
// package parameter being None, the path_in is interpreted as a
// raw path.
if (package_in != mp_const_none) {
// Pass "True" as sentinel value in fromlist to force returning of leaf module
mp_obj_t pkg = mp_import_name(mp_obj_str_get_qstr(package_in), mp_const_true, MP_OBJ_NEW_SMALL_INT(0));
mp_obj_t dest[2];
mp_load_method_maybe(pkg, MP_QSTR___path__, dest);
if (dest[0] == MP_OBJ_NULL) {
mp_raise_TypeError(NULL);
}
const char *path = mp_obj_str_get_data(dest[0], &len);
vstr_add_strn(&path_buf, path, len);
vstr_add_byte(&path_buf, '/');
}
const char *path = mp_obj_str_get_data(path_in, &len);
vstr_add_strn(&path_buf, path, len);
size_t file_len;
const char *data = mp_find_frozen_str(path_buf.buf, path_buf.len, &file_len);
if (data != NULL) {
mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
o->base.type = &mp_type_bytesio;
o->vstr = m_new_obj(vstr_t);
vstr_init_fixed_buf(o->vstr, file_len + 1, (char *)data);
o->vstr->len = file_len;
o->pos = 0;
return MP_OBJ_FROM_PTR(o);
}
mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len);
return mp_builtin_open(1, &path_out, (mp_map_t *)&mp_const_empty_map);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
#endif
STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
#if CIRCUITPY
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_io) },
@ -268,9 +224,6 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
#if MICROPY_PY_IO_IOBASE
{ MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) },
#endif
#if MICROPY_PY_IO_RESOURCE_STREAM
{ MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) },
#endif
#if MICROPY_PY_IO_FILEIO
{ MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) },
#if MICROPY_CPYTHON_COMPAT

View File

@ -158,7 +158,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_atexit_obj, mp_sys_atexit);
#endif
#if MICROPY_PY_SYS_SETTRACE
// settrace(tracefunc): Set the systems trace function.
// settrace(tracefunc): Set the system's trace function.
STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) {
return mp_prof_settrace(obj);
}

View File

@ -50,6 +50,31 @@
#define CIRCUITPY 0
#endif
// Disable all optional features (i.e. minimal port).
#define MICROPY_CONFIG_ROM_LEVEL_MINIMUM (0)
// Only enable core features (constrained flash, e.g. STM32L072)
#define MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES (10)
// Enable most common features (small on-device flash, e.g. STM32F411)
#define MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES (20)
// Enable convenience features (medium on-device flash, e.g. STM32F405)
#define MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES (30)
// Enable all common features (large/external flash, rp2, unix)
#define MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES (40)
// Enable everything (e.g. coverage)
#define MICROPY_CONFIG_ROM_LEVEL_EVERYTHING (50)
// Ports/boards should set this, but default to level=core.
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
#endif
// Helper macros for "have at least this level".
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES)
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES)
#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EVERYTHING)
// Any options not explicitly set in mpconfigport.h will get default
// values below.
@ -144,7 +169,7 @@
// Support automatic GC when reaching allocation threshold,
// configurable by gc.threshold().
#ifndef MICROPY_GC_ALLOC_THRESHOLD
#define MICROPY_GC_ALLOC_THRESHOLD (1)
#define MICROPY_GC_ALLOC_THRESHOLD (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Number of bytes to allocate initially when creating new chunks to store
@ -243,7 +268,11 @@
// Number of bytes used to store qstr hash
#ifndef MICROPY_QSTR_BYTES_IN_HASH
#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES
#define MICROPY_QSTR_BYTES_IN_HASH (2)
#else
#define MICROPY_QSTR_BYTES_IN_HASH (1)
#endif
#endif
// Avoid using C stack when making Python function calls. C stack still
@ -385,7 +414,7 @@
// Whether to include the compiler
#ifndef MICROPY_ENABLE_COMPILER
#define MICROPY_ENABLE_COMPILER (1)
#define MICROPY_ENABLE_COMPILER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether the compiler is dynamically configurable (ie at runtime)
@ -396,49 +425,47 @@
// Configure dynamic compiler macros
#if MICROPY_DYNAMIC_COMPILER
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode)
#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode)
#else
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
#define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE
#endif
// Whether to enable constant folding; eg 1+2 rewritten as 3
#ifndef MICROPY_COMP_CONST_FOLDING
#define MICROPY_COMP_CONST_FOLDING (1)
#define MICROPY_COMP_CONST_FOLDING (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to enable optimisations for constant literals, eg OrderedDict
#ifndef MICROPY_COMP_CONST_LITERAL
#define MICROPY_COMP_CONST_LITERAL (1)
#define MICROPY_COMP_CONST_LITERAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to enable lookup of constants in modules; eg module.CONST
#ifndef MICROPY_COMP_MODULE_CONST
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_MODULE_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to enable constant optimisation; id = const(value)
#ifndef MICROPY_COMP_CONST
#define MICROPY_COMP_CONST (1)
#define MICROPY_COMP_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to enable optimisation of: a, b = c, d
// Costs 124 bytes (Thumb2)
#ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to enable optimisation of: a, b, c = d, e, f
// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2)
#ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to enable optimisation of: return a if b else c
// Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use
#ifndef MICROPY_COMP_RETURN_IF_EXPR
#define MICROPY_COMP_RETURN_IF_EXPR (0)
#define MICROPY_COMP_RETURN_IF_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to include parsing of f-string literals
@ -511,23 +538,36 @@
#define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (0)
#endif
// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR,
// STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and
// uses a bit of extra code ROM, but greatly improves lookup speed.
#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
// Optimise the fast path for loading attributes from instance types. Increases
// Thumb2 code size by about 48 bytes.
#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH
#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Use extra RAM to cache map lookups by remembering the likely location of
// the index. Avoids the hash computation on unordered maps, and avoids the
// linear search on ordered (especially in-ROM) maps. Can provide a +10-15%
// performance improvement on benchmarks involving lots of attribute access
// or dictionary lookup.
#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE
#define MICROPY_OPT_MAP_LOOKUP_CACHE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// How much RAM (in bytes) to use for the map lookup cache.
#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE
#define MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE (128)
#endif
// Whether to use fast versions of bitwise operations (and, or, xor) when the
// arguments are both positive. Increases Thumb2 code size by about 250 bytes.
#ifndef MICROPY_OPT_MPZ_BITWISE
#define MICROPY_OPT_MPZ_BITWISE (0)
#define MICROPY_OPT_MPZ_BITWISE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether math.factorial is large, fast and recursive (1) or small and slow (0).
#ifndef MICROPY_OPT_MATH_FACTORIAL
#define MICROPY_OPT_MATH_FACTORIAL (0)
#define MICROPY_OPT_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
/*****************************************************************************/
@ -537,7 +577,7 @@
// When disabled, only importing of built-in modules is supported
// When enabled, a port must implement mp_import_stat (among other things)
#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT
#define MICROPY_ENABLE_EXTERNAL_IMPORT (1)
#define MICROPY_ENABLE_EXTERNAL_IMPORT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to use the POSIX reader for importing files
@ -587,9 +627,14 @@
#define MICROPY_ENABLE_GC (0)
#endif
// Hook to run code during time consuming garbage collector operations
#ifndef MICROPY_GC_HOOK_LOOP
#define MICROPY_GC_HOOK_LOOP
#endif
// Whether to enable finalisers in the garbage collector (ie call __del__)
#ifndef MICROPY_ENABLE_FINALISER
#define MICROPY_ENABLE_FINALISER (0)
#define MICROPY_ENABLE_FINALISER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to enable a separate allocator for the Python stack.
@ -606,7 +651,7 @@
// Whether to check C stack usage. C stack used for calling Python functions,
// etc. Not checking means segfault on overflow.
#ifndef MICROPY_STACK_CHECK
#define MICROPY_STACK_CHECK (0)
#define MICROPY_STACK_CHECK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to measure maximum stack excursion
@ -626,7 +671,7 @@
// Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function
#ifndef MICROPY_KBD_EXCEPTION
#define MICROPY_KBD_EXCEPTION (0)
#define MICROPY_KBD_EXCEPTION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt
@ -637,7 +682,7 @@
// Whether to include REPL helper function
#ifndef MICROPY_HELPER_REPL
#define MICROPY_HELPER_REPL (0)
#define MICROPY_HELPER_REPL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Allow enabling debug prints after each REPL line
@ -647,7 +692,7 @@
// Whether to include emacs-style readline behavior in REPL
#ifndef MICROPY_REPL_EMACS_KEYS
#define MICROPY_REPL_EMACS_KEYS (0)
#define MICROPY_REPL_EMACS_KEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to include emacs-style word movement/kill readline behavior in REPL.
@ -667,7 +712,7 @@
// Whether to implement auto-indent in REPL
#ifndef MICROPY_REPL_AUTO_INDENT
#define MICROPY_REPL_AUTO_INDENT (0)
#define MICROPY_REPL_AUTO_INDENT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether port requires event-driven REPL functions
@ -696,7 +741,7 @@ typedef long long mp_longint_impl_t;
// Whether to include information in the byte code to determine source
// line number (increases RAM usage, but doesn't slow byte code execution)
#ifndef MICROPY_ENABLE_SOURCE_LINE
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_SOURCE_LINE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to include doc strings (increases RAM usage)
@ -714,7 +759,13 @@ typedef long long mp_longint_impl_t;
#define MICROPY_ERROR_REPORTING_DETAILED (3)
#ifndef MICROPY_ERROR_REPORTING
#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
#elif MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
#else
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#endif
#endif
// Whether issue warnings during compiling/execution
@ -770,7 +821,7 @@ typedef double mp_float_t;
// TODO: Originally intended as generic category to not
// add bunch of once-off options. May need refactoring later
#ifndef MICROPY_CPYTHON_COMPAT
#define MICROPY_CPYTHON_COMPAT (1)
#define MICROPY_CPYTHON_COMPAT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Perform full checks as done by CPython. Disabling this
@ -779,12 +830,12 @@ typedef double mp_float_t;
// grave issues (in other words, only user app should be,
// affected, not system).
#ifndef MICROPY_FULL_CHECKS
#define MICROPY_FULL_CHECKS (1)
#define MICROPY_FULL_CHECKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether POSIX-semantics non-blocking streams are supported
#ifndef MICROPY_STREAMS_NON_BLOCK
#define MICROPY_STREAMS_NON_BLOCK (0)
#define MICROPY_STREAMS_NON_BLOCK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide stream functions with POSIX-like signatures
@ -795,17 +846,23 @@ typedef double mp_float_t;
// Whether to call __init__ when importing builtin modules for the first time
#ifndef MICROPY_MODULE_BUILTIN_INIT
#define MICROPY_MODULE_BUILTIN_INIT (0)
#define MICROPY_MODULE_BUILTIN_INIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support module-level __getattr__ (see PEP 562)
#ifndef MICROPY_MODULE_GETATTR
#define MICROPY_MODULE_GETATTR (1)
#define MICROPY_MODULE_GETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether module weak links are supported
#ifndef MICROPY_MODULE_WEAK_LINKS
#define MICROPY_MODULE_WEAK_LINKS (0)
#define MICROPY_MODULE_WEAK_LINKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to enable importing foo.py with __name__ set to '__main__'
// Used by the unix port for the -m flag.
#ifndef MICROPY_MODULE_OVERRIDE_MAIN_IMPORT
#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (0)
#endif
// Whether frozen modules are supported in the form of strings
@ -825,7 +882,7 @@ typedef double mp_float_t;
// Whether you can override builtins in the builtins module
#ifndef MICROPY_CAN_OVERRIDE_BUILTINS
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
#define MICROPY_CAN_OVERRIDE_BUILTINS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to check that the "self" argument of a builtin method has the
@ -834,7 +891,7 @@ typedef double mp_float_t;
// list.append([], 1). Without this check such calls will have undefined
// behaviour (usually segfault) if the first argument is the wrong type.
#ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to use internally defined errno's (otherwise system provided ones)
@ -849,7 +906,7 @@ typedef double mp_float_t;
// Support for internal scheduler
#ifndef MICROPY_ENABLE_SCHEDULER
#define MICROPY_ENABLE_SCHEDULER (0)
#define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Maximum number of entries in the scheduler
@ -884,41 +941,41 @@ typedef double mp_float_t;
// inheritance makes some C functions inherently recursive, and adds a bit of
// code overhead.
#ifndef MICROPY_MULTIPLE_INHERITANCE
#define MICROPY_MULTIPLE_INHERITANCE (1)
#define MICROPY_MULTIPLE_INHERITANCE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to implement attributes on functions
#ifndef MICROPY_PY_FUNCTION_ATTRS
#define MICROPY_PY_FUNCTION_ATTRS (0)
#define MICROPY_PY_FUNCTION_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support the descriptors __get__, __set__, __delete__
// This costs some code size and makes load/store/delete of instance
// attributes slower for the classes that use this feature
#ifndef MICROPY_PY_DESCRIPTORS
#define MICROPY_PY_DESCRIPTORS (0)
#define MICROPY_PY_DESCRIPTORS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support class __delattr__ and __setattr__ methods
// This costs some code size and makes store/delete of instance
// attributes slower for the classes that use this feature
#ifndef MICROPY_PY_DELATTR_SETATTR
#define MICROPY_PY_DELATTR_SETATTR (0)
#define MICROPY_PY_DELATTR_SETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Support for async/await/async for/async with
#ifndef MICROPY_PY_ASYNC_AWAIT
#define MICROPY_PY_ASYNC_AWAIT (1)
#define MICROPY_PY_ASYNC_AWAIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Support for literal string interpolation, f-strings (see PEP 498, Python 3.6+)
#ifndef MICROPY_PY_FSTRINGS
#define MICROPY_PY_FSTRINGS (0)
#define MICROPY_PY_FSTRINGS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Support for assignment expressions with := (see PEP 572, Python 3.8+)
#ifndef MICROPY_PY_ASSIGN_EXPR
#define MICROPY_PY_ASSIGN_EXPR (1)
#define MICROPY_PY_ASSIGN_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Non-standard .pend_throw() method for generators, allowing for
@ -927,7 +984,7 @@ typedef double mp_float_t;
// to generator's .send() or .__next__(). (This is useful to implement
// async schedulers.)
#ifndef MICROPY_PY_GENERATOR_PEND_THROW
#define MICROPY_PY_GENERATOR_PEND_THROW (1)
#define MICROPY_PY_GENERATOR_PEND_THROW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Issue a warning when comparing str and bytes objects
@ -937,7 +994,7 @@ typedef double mp_float_t;
// Whether str object is proper unicode
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to check for valid UTF-8 when converting bytes to str
@ -947,42 +1004,42 @@ typedef double mp_float_t;
// Whether str.center() method provided
#ifndef MICROPY_PY_BUILTINS_STR_CENTER
#define MICROPY_PY_BUILTINS_STR_CENTER (0)
#define MICROPY_PY_BUILTINS_STR_CENTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether str.count() method provided
#ifndef MICROPY_PY_BUILTINS_STR_COUNT
#define MICROPY_PY_BUILTINS_STR_COUNT (1)
#define MICROPY_PY_BUILTINS_STR_COUNT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether str % (...) formatting operator provided
#ifndef MICROPY_PY_BUILTINS_STR_OP_MODULO
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1)
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether str.partition()/str.rpartition() method provided
#ifndef MICROPY_PY_BUILTINS_STR_PARTITION
#define MICROPY_PY_BUILTINS_STR_PARTITION (0)
#define MICROPY_PY_BUILTINS_STR_PARTITION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether str.splitlines() method provided
#ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0)
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support bytearray object
#ifndef MICROPY_PY_BUILTINS_BYTEARRAY
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
#define MICROPY_PY_BUILTINS_BYTEARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support dict.fromkeys() class method
#ifndef MICROPY_PY_BUILTINS_DICT_FROMKEYS
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1)
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support memoryview object
#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support memoryview.itemsize attribute
@ -992,39 +1049,39 @@ typedef double mp_float_t;
// Whether to support set object
#ifndef MICROPY_PY_BUILTINS_SET
#define MICROPY_PY_BUILTINS_SET (1)
#define MICROPY_PY_BUILTINS_SET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support slice subscript operators and slice object
#ifndef MICROPY_PY_BUILTINS_SLICE
#define MICROPY_PY_BUILTINS_SLICE (1)
#define MICROPY_PY_BUILTINS_SLICE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support slice attribute read access,
// i.e. slice.start, slice.stop, slice.step
#ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support the .indices(len) method on slice objects
#ifndef MICROPY_PY_BUILTINS_SLICE_INDICES
#define MICROPY_PY_BUILTINS_SLICE_INDICES (0)
#define MICROPY_PY_BUILTINS_SLICE_INDICES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support frozenset object
#ifndef MICROPY_PY_BUILTINS_FROZENSET
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_FROZENSET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support property object
#ifndef MICROPY_PY_BUILTINS_PROPERTY
#define MICROPY_PY_BUILTINS_PROPERTY (1)
#define MICROPY_PY_BUILTINS_PROPERTY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to implement the start/stop/step attributes (readback) on
// the "range" builtin type. Rarely used, and costs ~60 bytes (x86).
#ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support binary ops [only (in)equality is defined] between range
@ -1042,7 +1099,7 @@ typedef double mp_float_t;
// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120
#ifndef MICROPY_PY_BUILTINS_ROUND_INT
#define MICROPY_PY_BUILTINS_ROUND_INT (0)
#define MICROPY_PY_BUILTINS_ROUND_INT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support complete set of special methods for user
@ -1051,7 +1108,7 @@ typedef double mp_float_t;
// "Reverse" methods are controlled by
// MICROPY_PY_REVERSE_SPECIAL_METHODS below.
#ifndef MICROPY_PY_ALL_SPECIAL_METHODS
#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
#define MICROPY_PY_ALL_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support all inplace arithmetic operarion methods
@ -1064,17 +1121,17 @@ typedef double mp_float_t;
// (__radd__, etc.). Additionally gated by
// MICROPY_PY_ALL_SPECIAL_METHODS.
#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support compile function
#ifndef MICROPY_PY_BUILTINS_COMPILE
#define MICROPY_PY_BUILTINS_COMPILE (0)
#define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support enumerate function(type)
#ifndef MICROPY_PY_BUILTINS_ENUMERATE
#define MICROPY_PY_BUILTINS_ENUMERATE (1)
#define MICROPY_PY_BUILTINS_ENUMERATE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support eval and exec functions
@ -1085,43 +1142,43 @@ typedef double mp_float_t;
// Whether to support the Python 2 execfile function
#ifndef MICROPY_PY_BUILTINS_EXECFILE
#define MICROPY_PY_BUILTINS_EXECFILE (0)
#define MICROPY_PY_BUILTINS_EXECFILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support filter function(type)
#ifndef MICROPY_PY_BUILTINS_FILTER
#define MICROPY_PY_BUILTINS_FILTER (1)
#define MICROPY_PY_BUILTINS_FILTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support reversed function(type)
#ifndef MICROPY_PY_BUILTINS_REVERSED
#define MICROPY_PY_BUILTINS_REVERSED (1)
#define MICROPY_PY_BUILTINS_REVERSED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to define "NotImplemented" special constant
#ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED
#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0)
#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide the built-in input() function. The implementation of this
// uses shared/readline, so can only be enabled if the port uses this readline.
#ifndef MICROPY_PY_BUILTINS_INPUT
#define MICROPY_PY_BUILTINS_INPUT (0)
#define MICROPY_PY_BUILTINS_INPUT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support min/max functions
#ifndef MICROPY_PY_BUILTINS_MIN_MAX
#define MICROPY_PY_BUILTINS_MIN_MAX (1)
#define MICROPY_PY_BUILTINS_MIN_MAX (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Support for calls to pow() with 3 integer arguments
#ifndef MICROPY_PY_BUILTINS_POW3
#define MICROPY_PY_BUILTINS_POW3 (0)
#define MICROPY_PY_BUILTINS_POW3 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide the help function
#ifndef MICROPY_PY_BUILTINS_HELP
#define MICROPY_PY_BUILTINS_HELP (0)
#define MICROPY_PY_BUILTINS_HELP (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Use this to configure the help text shown for help(). It should be a
@ -1132,17 +1189,17 @@ typedef double mp_float_t;
// Add the ability to list the available modules when executing help('modules')
#ifndef MICROPY_PY_BUILTINS_HELP_MODULES
#define MICROPY_PY_BUILTINS_HELP_MODULES (0)
#define MICROPY_PY_BUILTINS_HELP_MODULES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to set __file__ for imported modules
#ifndef MICROPY_PY___FILE__
#define MICROPY_PY___FILE__ (1)
#define MICROPY_PY___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to provide mem-info related functions in micropython module
#ifndef MICROPY_PY_MICROPYTHON_MEM_INFO
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "micropython.stack_use" function
@ -1159,13 +1216,13 @@ typedef double mp_float_t;
// underlying code is shared with "bytearray" builtin type, so to
// get real savings, it should be disabled too.
#ifndef MICROPY_PY_ARRAY
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_ARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to support slice assignments for array (and bytearray).
// This is rarely used, but adds ~0.5K of code.
#ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support nonstandard typecodes "O", "P" and "S"
@ -1177,22 +1234,22 @@ typedef double mp_float_t;
// Whether to support attrtuple type (MicroPython extension)
// It provides space-efficient tuples with attribute access
#ifndef MICROPY_PY_ATTRTUPLE
#define MICROPY_PY_ATTRTUPLE (1)
#define MICROPY_PY_ATTRTUPLE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to provide "collections" module
#ifndef MICROPY_PY_COLLECTIONS
#define MICROPY_PY_COLLECTIONS (1)
#define MICROPY_PY_COLLECTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to provide "ucollections.deque" type
#ifndef MICROPY_PY_COLLECTIONS_DEQUE
#define MICROPY_PY_COLLECTIONS_DEQUE (0)
#define MICROPY_PY_COLLECTIONS_DEQUE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "collections.OrderedDict" type
#ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide the _asdict function for namedtuple
@ -1202,22 +1259,22 @@ typedef double mp_float_t;
// Whether to provide "math" module
#ifndef MICROPY_PY_MATH
#define MICROPY_PY_MATH (1)
#define MICROPY_PY_MATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to provide special math functions: math.{erf,erfc,gamma,lgamma}
#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0)
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide math.factorial function
#ifndef MICROPY_PY_MATH_FACTORIAL
#define MICROPY_PY_MATH_FACTORIAL (0)
#define MICROPY_PY_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide math.isclose function
#ifndef MICROPY_PY_MATH_ISCLOSE
#define MICROPY_PY_MATH_ISCLOSE (0)
#define MICROPY_PY_MATH_ISCLOSE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide fix for atan2 Inf handling.
@ -1242,12 +1299,12 @@ typedef double mp_float_t;
// Whether to provide "cmath" module
#ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_CMATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "gc" module
#ifndef MICROPY_PY_GC
#define MICROPY_PY_GC (1)
#define MICROPY_PY_GC (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to return number of collected objects from gc.collect()
@ -1257,28 +1314,17 @@ typedef double mp_float_t;
// Whether to provide "io" module
#ifndef MICROPY_PY_IO
#define MICROPY_PY_IO (1)
#define MICROPY_PY_IO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to provide "io.IOBase" class to support user streams
#ifndef MICROPY_PY_IO_IOBASE
#define MICROPY_PY_IO_IOBASE (0)
#endif
// Whether to provide "uio.resource_stream()" function with
// the semantics of CPython's pkg_resources.resource_stream()
// (allows to access binary resources in frozen source packages).
// Note that the same functionality can be achieved in "pure
// Python" by prepocessing binary resources into Python source
// and bytecode-freezing it (with a simple helper module available
// e.g. in micropython-lib).
#ifndef MICROPY_PY_IO_RESOURCE_STREAM
#define MICROPY_PY_IO_RESOURCE_STREAM (0)
#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "io.FileIO" class
#ifndef MICROPY_PY_IO_FILEIO
#define MICROPY_PY_IO_FILEIO (0)
#define MICROPY_PY_IO_FILEIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "io.BytesIO" class
@ -1293,17 +1339,22 @@ typedef double mp_float_t;
// Whether to provide "struct" module
#ifndef MICROPY_PY_STRUCT
#define MICROPY_PY_STRUCT (1)
#define MICROPY_PY_STRUCT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to provide "sys" module
#ifndef MICROPY_PY_SYS
#define MICROPY_PY_SYS (1)
#define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif
// Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init()
#ifndef MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (MICROPY_PY_SYS)
#endif
// Whether to provide "sys.maxsize" constant
#ifndef MICROPY_PY_SYS_MAXSIZE
#define MICROPY_PY_SYS_MAXSIZE (0)
#define MICROPY_PY_SYS_MAXSIZE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "sys.modules" dictionary
@ -1339,18 +1390,18 @@ typedef double mp_float_t;
// Whether to provide sys.{stdin,stdout,stderr} objects
#ifndef MICROPY_PY_SYS_STDFILES
#define MICROPY_PY_SYS_STDFILES (0)
#define MICROPY_PY_SYS_STDFILES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide sys.{stdin,stdout,stderr}.buffer object
// This is implemented per-port
#ifndef MICROPY_PY_SYS_STDIO_BUFFER
#define MICROPY_PY_SYS_STDIO_BUFFER (0)
#define MICROPY_PY_SYS_STDIO_BUFFER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide "uerrno" module
#ifndef MICROPY_PY_UERRNO
#define MICROPY_PY_UERRNO (0)
#define MICROPY_PY_UERRNO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide the uerrno.errorcode dict
@ -1360,7 +1411,7 @@ typedef double mp_float_t;
// Whether to provide "uselect" module (baremetal implementation)
#ifndef MICROPY_PY_USELECT
#define MICROPY_PY_USELECT (0)
#define MICROPY_PY_USELECT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to enable the select() function in the "uselect" module (baremetal
@ -1406,11 +1457,11 @@ typedef double mp_float_t;
// Extended modules
#ifndef MICROPY_PY_UASYNCIO
#define MICROPY_PY_UASYNCIO (0)
#define MICROPY_PY_UASYNCIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_UCTYPES
#define MICROPY_PY_UCTYPES (0)
#define MICROPY_PY_UCTYPES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to provide SHORT, INT, LONG, etc. types in addition to
@ -1420,11 +1471,11 @@ typedef double mp_float_t;
#endif
#ifndef MICROPY_PY_UZLIB
#define MICROPY_PY_UZLIB (0)
#define MICROPY_PY_UZLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_UJSON
#define MICROPY_PY_UJSON (0)
#define MICROPY_PY_UJSON (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to support the "separators" argument to dump, dumps
@ -1437,7 +1488,7 @@ typedef double mp_float_t;
#endif
#ifndef MICROPY_PY_URE
#define MICROPY_PY_URE (0)
#define MICROPY_PY_URE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_URE_DEBUG
@ -1453,20 +1504,20 @@ typedef double mp_float_t;
#endif
#ifndef MICROPY_PY_URE_SUB
#define MICROPY_PY_URE_SUB (0)
#define MICROPY_PY_URE_SUB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_UHEAPQ
#define MICROPY_PY_UHEAPQ (0)
#define MICROPY_PY_UHEAPQ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Optimized heap queue for relative timestamps
// Optimized heap queue for relative timestamps (only used by uasyncio v2)
#ifndef MICROPY_PY_UTIMEQ
#define MICROPY_PY_UTIMEQ (0)
#endif
#ifndef MICROPY_PY_UHASHLIB
#define MICROPY_PY_UHASHLIB (0)
#define MICROPY_PY_UHASHLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_UHASHLIB_MD5
@ -1495,25 +1546,70 @@ typedef double mp_float_t;
#endif
#ifndef MICROPY_PY_UBINASCII
#define MICROPY_PY_UBINASCII (0)
#define MICROPY_PY_UBINASCII (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Depends on MICROPY_PY_UZLIB
#ifndef MICROPY_PY_UBINASCII_CRC32
#define MICROPY_PY_UBINASCII_CRC32 (0)
#define MICROPY_PY_UBINASCII_CRC32 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_URANDOM
#define MICROPY_PY_URANDOM (0)
#define MICROPY_PY_URANDOM (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
// Whether to include: randrange, randint, choice, random, uniform
#ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_MACHINE
#define MICROPY_PY_MACHINE (0)
#endif
// Whether to include: bitstream
#ifndef MICROPY_PY_MACHINE_BITSTREAM
#define MICROPY_PY_MACHINE_BITSTREAM (0)
#endif
// Whether to include: time_pulse_us
#ifndef MICROPY_PY_MACHINE_PULSE
#define MICROPY_PY_MACHINE_PULSE (0)
#endif
#ifndef MICROPY_PY_MACHINE_I2C
#define MICROPY_PY_MACHINE_I2C (0)
#endif
// Whether to provide the "machine.SoftI2C" class
#ifndef MICROPY_PY_MACHINE_SOFTI2C
#define MICROPY_PY_MACHINE_SOFTI2C (0)
#endif
#ifndef MICROPY_PY_MACHINE_SPI
#define MICROPY_PY_MACHINE_SPI (0)
#endif
// Whether to provide the "machine.SoftSPI" class
#ifndef MICROPY_PY_MACHINE_SOFTSPI
#define MICROPY_PY_MACHINE_SOFTSPI (0)
#endif
#ifndef MICROPY_PY_USSL
#define MICROPY_PY_USSL (0)
#endif
// Whether to add finaliser code to ussl objects
#ifndef MICROPY_PY_USSL_FINALISER
#define MICROPY_PY_USSL_FINALISER (0)
#endif
#ifndef MICROPY_PY_UWEBSOCKET
#define MICROPY_PY_UWEBSOCKET (0)
#endif
#ifndef MICROPY_PY_FRAMEBUF
#define MICROPY_PY_FRAMEBUF (0)
#define MICROPY_PY_FRAMEBUF (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
#endif
#ifndef MICROPY_PY_BTREE
@ -1523,6 +1619,12 @@ typedef double mp_float_t;
#ifndef MICROPY_HW_ENABLE_USB
#define MICROPY_HW_ENABLE_USB (0)
#endif
// Whether to provide the low-level "_onewire" module
#ifndef MICROPY_PY_ONEWIRE
#define MICROPY_PY_ONEWIRE (0)
#endif
/*****************************************************************************/
/* Hooks for a port to add builtins */
@ -1531,6 +1633,12 @@ typedef double mp_float_t;
#define MICROPY_PORT_BUILTINS
#endif
// Additional builtin function definitions for extension by command-line, boards or variants.
// See modbuiltins.c:mp_module_builtins_globals_table for format.
#ifndef MICROPY_PORT_EXTRA_BUILTINS
#define MICROPY_PORT_EXTRA_BUILTINS
#endif
// Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format.
#ifndef MICROPY_PORT_BUILTIN_MODULES
#define MICROPY_PORT_BUILTIN_MODULES
@ -1549,6 +1657,30 @@ typedef double mp_float_t;
/*****************************************************************************/
/* Hooks for a port to wrap functions with attributes */
#ifndef MICROPY_WRAP_MP_BINARY_OP
#define MICROPY_WRAP_MP_BINARY_OP(f) f
#endif
#ifndef MICROPY_WRAP_MP_EXECUTE_BYTECODE
#define MICROPY_WRAP_MP_EXECUTE_BYTECODE(f) f
#endif
#ifndef MICROPY_WRAP_MP_LOAD_GLOBAL
#define MICROPY_WRAP_MP_LOAD_GLOBAL(f) f
#endif
#ifndef MICROPY_WRAP_MP_LOAD_NAME
#define MICROPY_WRAP_MP_LOAD_NAME(f) f
#endif
#ifndef MICROPY_WRAP_MP_MAP_LOOKUP
#define MICROPY_WRAP_MP_MAP_LOOKUP(f) f
#endif
#ifndef MICROPY_WRAP_MP_OBJ_GET_TYPE
#define MICROPY_WRAP_MP_OBJ_GET_TYPE(f) f
#endif
#ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION
#define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f
#endif

View File

@ -44,7 +44,6 @@
#if MICROPY_DYNAMIC_COMPILER
typedef struct mp_dynamic_compiler_t {
uint8_t small_int_bits; // must be <= host small_int_bits
bool opt_cache_map_lookup_in_bytecode;
bool py_builtins_str_unicode;
uint8_t native_arch;
uint8_t nlr_buf_num_regs;
@ -165,9 +164,12 @@ typedef struct _mp_state_vm_t {
// dictionary for the __main__ module
mp_obj_dict_t dict_main;
// these two lists must be initialised per port, after the call to mp_init
#if MICROPY_PY_SYS
// If MICROPY_PY_SYS_PATH_ARGV_DEFAULTS is not enabled then these two lists
// must be initialised after the call to mp_init.
mp_obj_list_t mp_sys_path_obj;
mp_obj_list_t mp_sys_argv_obj;
#endif
// dictionary for overridden builtins
#if MICROPY_CAN_OVERRIDE_BUILTINS
@ -230,6 +232,11 @@ typedef struct _mp_state_vm_t {
// This is a global mutex used to make the VM/runtime thread-safe.
mp_thread_mutex_t gil_mutex;
#endif
#if MICROPY_OPT_MAP_LOOKUP_CACHE
// See mp_map_lookup.
uint8_t map_lookup_cache[MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE];
#endif
} mp_state_vm_t;
// This structure holds state that is specific to a given thread.

View File

@ -717,6 +717,7 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
if (val == 0) {
z->neg = 0;
z->len = 0;
return;
}
@ -903,10 +904,6 @@ bool mpz_is_even(const mpz_t *z) {
#endif
int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
// to catch comparison of -0 with +0
if (z1->len == 0 && z2->len == 0) {
return 0;
}
int cmp = (int)z2->neg - (int)z1->neg;
if (cmp != 0) {
return cmp;
@ -1056,7 +1053,9 @@ void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) {
if (dest != z) {
mpz_set(dest, z);
}
dest->neg = 1 - dest->neg;
if (dest->len) {
dest->neg = 1 - dest->neg;
}
}
/* computes dest = ~z (= -z - 1)
@ -1152,7 +1151,7 @@ void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
}
dest->neg = lhs->neg;
dest->neg = lhs->neg & !!dest->len;
}
/* computes dest = lhs - rhs
@ -1176,7 +1175,9 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
}
if (neg) {
if (dest->len == 0) {
dest->neg = 0;
} else if (neg) {
dest->neg = 1 - lhs->neg;
} else {
dest->neg = lhs->neg;
@ -1488,14 +1489,16 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary?
memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t));
dest_quo->neg = 0;
dest_quo->len = 0;
mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary?
mpz_set(dest_rem, lhs);
mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len);
dest_rem->neg &= !!dest_rem->len;
// check signs and do Python style modulo
if (lhs->neg != rhs->neg) {
dest_quo->neg = 1;
dest_quo->neg = !!dest_quo->len;
if (!mpz_is_zero(dest_rem)) {
mpz_t mpzone;
mpz_init_from_int(&mpzone, -1);

View File

@ -91,6 +91,7 @@ typedef int8_t mpz_dbl_dig_signed_t;
#define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE)
typedef struct _mpz_t {
// Zero has neg=0, len=0. Negative zero is not allowed.
size_t neg : 1;
size_t fixed_dig : 1;
size_t alloc : (8 * sizeof(size_t) - 2);
@ -119,7 +120,7 @@ static inline bool mpz_is_zero(const mpz_t *z) {
return z->len == 0;
}
static inline bool mpz_is_neg(const mpz_t *z) {
return z->len != 0 && z->neg != 0;
return z->neg != 0;
}
int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);

View File

@ -43,7 +43,7 @@
#include "supervisor/shared/stack.h"
#include "supervisor/shared/translate.h"
const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
const mp_obj_type_t *MICROPY_WRAP_MP_OBJ_GET_TYPE(mp_obj_get_type)(mp_const_obj_t o_in) {
#if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
if (mp_obj_is_obj(o_in)) {

View File

@ -617,6 +617,7 @@ struct _mp_obj_type_t {
//
// dest[0] = MP_OBJ_NULL means load
// return: for fail, do nothing
// for fail but continue lookup in locals_dict, dest[1] = MP_OBJ_SENTINEL
// for attr, dest[0] = value
// for method, dest[0] = method, dest[1] = self
//

View File

@ -39,8 +39,6 @@ typedef struct _mp_obj_fun_bc_t {
// the following extra_args array is allocated space to take (in order):
// - values of positional default args (if any)
// - a single slot for default kw args dict (if it has them)
// - a single slot for var args tuple (if it takes them)
// - a single slot for kw args dict (if it takes them)
mp_obj_t extra_args[];
} mp_obj_fun_bc_t;

View File

@ -36,6 +36,10 @@
#include "genhdr/moduledefs.h"
#if MICROPY_MODULE_BUILTIN_INIT
STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj);
#endif
STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
@ -279,47 +283,56 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table);
// returns MP_OBJ_NULL if not found
mp_obj_t mp_module_get(qstr module_name) {
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
// lookup module
mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name) {
// First try loaded modules.
mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
if (el == NULL) {
// module not found, look for builtin module names
el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
if (el == NULL) {
if (!elem) {
#if MICROPY_MODULE_WEAK_LINKS
return mp_module_get_builtin(module_name);
#else
// Otherwise try builtin.
elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
if (!elem) {
return MP_OBJ_NULL;
}
mp_module_call_init(module_name, el->value);
#if MICROPY_MODULE_BUILTIN_INIT
// If found, it's a newly loaded built-in, so init it.
mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
#endif
#endif
}
// module found, return it
return el->value;
}
void mp_module_register(qstr qst, mp_obj_t module) {
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
return elem->value;
}
#if MICROPY_MODULE_WEAK_LINKS
// Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found
mp_obj_t mp_module_search_umodule(const char *module_str) {
for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) {
const mp_map_elem_t *entry = (const mp_map_elem_t *)&mp_builtin_module_table[i];
const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key));
if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) {
return (mp_obj_t)entry->value;
}
// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL.
mp_obj_t mp_module_get_builtin(qstr module_name) {
// Try builtin.
mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
if (!elem) {
return MP_OBJ_NULL;
}
return MP_OBJ_NULL;
#if MICROPY_MODULE_BUILTIN_INIT
// If found, it's a newly loaded built-in, so init it.
mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value);
#endif
return elem->value;
}
#endif
#if MICROPY_MODULE_BUILTIN_INIT
void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
STATIC void mp_module_register(mp_obj_t module_name, mp_obj_t module) {
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
}
STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) {
// Look for __init__ and call it if it exists
mp_obj_t dest[2];
mp_load_method_maybe(module_obj, MP_QSTR___init__, dest);

View File

@ -30,18 +30,9 @@
extern const mp_map_t mp_builtin_module_map;
mp_obj_t mp_module_get(qstr module_name);
void mp_module_register(qstr qstr, mp_obj_t module);
mp_obj_t mp_module_search_umodule(const char *module_str);
#if MICROPY_MODULE_BUILTIN_INIT
void mp_module_call_init(qstr module_name, mp_obj_t module_obj);
#else
static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
(void)module_name;
(void)module_obj;
}
mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name);
#if MICROPY_MODULE_WEAK_LINKS
mp_obj_t mp_module_get_builtin(qstr module_name);
#endif
#endif // MICROPY_INCLUDED_PY_OBJMODULE_H

View File

@ -616,6 +616,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
assert(mp_obj_is_instance_type(mp_obj_get_type(self_in)));
mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
// Note: This is fast-path'ed in the VM for the MP_BC_LOAD_ATTR operation.
mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
if (elem != NULL) {
// object member, always treated as a value

View File

@ -802,9 +802,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
#endif
STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
// optimise away parenthesis around an expression if possible
// Simplify and optimise certain rules, to reduce memory usage and simplify the compiler.
if (rule_id == RULE_atom_paren) {
// there should be just 1 arg for this rule
// Remove parenthesis around a single expression if possible.
// This atom_paren rule always has a single argument, and after this
// optimisation that argument is either NULL or testlist_comp.
mp_parse_node_t pn = peek_result(parser, 0);
if (MP_PARSE_NODE_IS_NULL(pn)) {
// need to keep parenthesis for ()
@ -814,6 +816,34 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
// parenthesis around a single expression, so it's just the expression
return;
}
} else if (rule_id == RULE_testlist_comp) {
// The testlist_comp rule can be the sole argument to either atom_parent
// or atom_bracket, for (...) and [...] respectively.
assert(num_args == 2);
mp_parse_node_t pn = peek_result(parser, 0);
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3b) {
// tuple of one item, with trailing comma
pop_result(parser);
--num_args;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3c) {
// tuple of many items, convert testlist_comp_3c to testlist_comp
pop_result(parser);
assert(pn == peek_result(parser, 0));
pns->kind_num_nodes = rule_id | MP_PARSE_NODE_STRUCT_NUM_NODES(pns) << 8;
return;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_comp_for) {
// generator expression
} else {
// tuple with 2 items
}
} else {
// tuple with 2 items
}
} else if (rule_id == RULE_testlist_comp_3c) {
// steal first arg of outer testlist_comp rule
++num_args;
}
#if MICROPY_COMP_CONST_FOLDING
@ -833,6 +863,10 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id,
for (size_t i = num_args; i > 0; i--) {
pn->nodes[i - 1] = pop_result(parser);
}
if (rule_id == RULE_testlist_comp_3c) {
// need to push something non-null to replace stolen first arg of testlist_comp
push_result_node(parser, (mp_parse_node_t)pn);
}
push_result_node(parser, (mp_parse_node_t)pn);
}

View File

@ -41,16 +41,15 @@
#define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2)
#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2)
// The feature flag bits encode the compile-time config options that
// affect the generate bytecode.
// The feature flag bits encode the compile-time config options that affect
// the generate bytecode. Note: position 0 is now unused
// (formerly MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE).
#define MPY_FEATURE_FLAGS ( \
((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \
| ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \
((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \
)
// This is a version of the flags that can be configured at runtime.
#define MPY_FEATURE_FLAGS_DYNAMIC ( \
((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) << 0) \
| ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \
((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \
)
// Define the host architecture

View File

@ -540,9 +540,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
instruction->qstr_opname = MP_QSTR_LOAD_NAME;
instruction->arg = qst;
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
}
break;
case MP_BC_LOAD_GLOBAL:
@ -550,9 +547,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL;
instruction->arg = qst;
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
}
break;
case MP_BC_LOAD_ATTR:
@ -560,9 +554,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
instruction->qstr_opname = MP_QSTR_LOAD_ATTR;
instruction->arg = qst;
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
}
break;
case MP_BC_LOAD_METHOD:
@ -618,9 +609,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_
instruction->qstr_opname = MP_QSTR_STORE_ATTR;
instruction->arg = qst;
instruction->argobj = MP_OBJ_NEW_QSTR(qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++);
}
break;
case MP_BC_STORE_SUBSCR:

View File

@ -224,19 +224,6 @@ ifneq ($(FROZEN_MANIFEST),)
PY_O += $(BUILD)/$(BUILD)/frozen_content.o
endif
# object file for frozen files
ifneq ($(FROZEN_DIR),)
PY_O += $(BUILD)/frozen.o
endif
# Combine old singular FROZEN_MPY_DIR with new multiple value form.
FROZEN_MPY_DIRS += $(FROZEN_MPY_DIR)
# object file for frozen bytecode (frozen .mpy files)
ifneq ($(FROZEN_MPY_DIRS),)
PY_O += $(BUILD)/frozen_mpy.o
endif
# Sources that may contain qstrings
SRC_QSTR_IGNORE = py/nlr%
SRC_QSTR_EMITNATIVE = py/emitn%

View File

@ -169,6 +169,12 @@ STATIC qstr qstr_add(mp_uint_t hash, mp_uint_t len, const char *q_ptr) {
+ (sizeof(const char *) + sizeof(qstr_attr_t)) * new_pool_length;
qstr_pool_t *pool = (qstr_pool_t *)m_malloc_maybe(pool_size, true);
if (pool == NULL) {
// Keep qstr_last_chunk consistent with qstr_pool_t: qstr_last_chunk is not scanned
// at garbage collection since it's reachable from a qstr_pool_t. And the caller of
// this function expects q_ptr to be stored in a qstr_pool_t so it can be reached
// by the collector. If qstr_pool_t allocation failed, qstr_last_chunk needs to be
// NULL'd. Otherwise it may become a dangling pointer at the next garbage collection.
MP_STATE_VM(qstr_last_chunk) = NULL;
QSTR_EXIT();
m_malloc_fail(new_pool_length);
}

View File

@ -60,6 +60,10 @@ Q(<string>)
Q(<stdin>)
Q(utf-8)
#if MICROPY_MODULE_FROZEN
Q(.frozen)
#endif
#if MICROPY_ENABLE_PYSTACK
Q(pystack exhausted)
#endif

View File

@ -126,6 +126,15 @@ void mp_init(void) {
sizeof(MP_STATE_VM(fs_user_mount)) - MICROPY_FATFS_NUM_PERSISTENT);
#endif
#if MICROPY_PY_SYS_PATH_ARGV_DEFAULTS
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
#if MICROPY_MODULE_FROZEN
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
#endif
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
#endif
#if MICROPY_PY_SYS_ATEXIT
MP_STATE_VM(sys_exitfunc) = mp_const_none;
#endif
@ -157,7 +166,7 @@ void mp_deinit(void) {
#endif
}
mp_obj_t mp_load_name(qstr qst) {
mp_obj_t MICROPY_WRAP_MP_LOAD_NAME(mp_load_name)(qstr qst) {
// logic: search locals, globals, builtins
DEBUG_OP_printf("load name %s\n", qstr_str(qst));
// If we're at the outer scope (locals == globals), dispatch to load_global right away
@ -170,7 +179,7 @@ mp_obj_t mp_load_name(qstr qst) {
return mp_load_global(qst);
}
mp_obj_t mp_load_global(qstr qst) {
mp_obj_t MICROPY_WRAP_MP_LOAD_GLOBAL(mp_load_global)(qstr qst) {
// logic: search globals, builtins
DEBUG_OP_printf("load global %s\n", qstr_str(qst));
mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
@ -310,7 +319,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
}
}
mp_obj_t PLACE_IN_ITCM(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs);
// TODO correctly distinguish inplace operators for mutable objects
@ -1103,6 +1112,10 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
dest[0] = MP_OBJ_NULL;
dest[1] = MP_OBJ_NULL;
// Note: the specific case of obj being an instance type is fast-path'ed in the VM
// for the MP_BC_LOAD_ATTR opcode. Instance types handle type->attr and look up directly
// in their member's map.
// get the type
const mp_obj_type_t *type = mp_obj_get_type(obj);
@ -1124,7 +1137,14 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
if (attr_fun != NULL) {
// this type can do its own load, so call it
attr_fun(obj, attr, dest);
return;
// If type->attr has set dest[1] = MP_OBJ_SENTINEL, we should proceed
// with lookups below (i.e. in locals_dict). If not, return right away.
if (dest[1] != MP_OBJ_SENTINEL) {
return;
}
// Clear the fail flag set by type->attr so it's like it never ran.
dest[1] = MP_OBJ_NULL;
}
if (type->locals_dict != NULL) {
// generic method lookup
@ -1135,6 +1155,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
if (elem != NULL) {
mp_convert_member_lookup(obj, type, elem->value, dest);
}
return;
}
}
@ -1426,8 +1447,10 @@ mp_obj_t mp_make_raise_obj(mp_obj_t o) {
// create and return a new exception instance by calling o
// TODO could have an option to disable traceback, then builtin exceptions (eg TypeError)
// could have const instances in ROM which we return here instead
return mp_call_function_n_kw(o, 0, 0, NULL);
} else if (mp_obj_is_exception_instance(o)) {
o = mp_call_function_n_kw(o, 0, 0, NULL);
}
if (mp_obj_is_exception_instance(o)) {
// o is an instance of an exception, so use it as the exception
return o;
} else {

View File

@ -95,7 +95,9 @@ NORETURN void mp_arg_error_unimpl_kw(void);
mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name);
mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name);
mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name);
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name);
#endif
mp_uint_t mp_arg_validate_length_range(mp_uint_t length, mp_uint_t min, mp_uint_t max, qstr arg_name);
mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name);
mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name);

View File

@ -98,8 +98,8 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i
// raw bytecode dump
size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell;
mp_printf(print, "Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n",
prelude_size, len - prelude_size);
mp_printf(print, "Raw bytecode (code_info_size=%u, bytecode_size=%u):\n",
(unsigned)prelude_size, (unsigned)(len - prelude_size));
for (mp_uint_t i = 0; i < len; i++) {
if (i > 0 && i % 16 == 0) {
mp_printf(print, "\n");
@ -208,25 +208,16 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
case MP_BC_LOAD_NAME:
DECODE_QSTR;
mp_printf(print, "LOAD_NAME %s", qstr_str(qst));
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
mp_printf(print, " (cache=%u)", *ip++);
}
break;
case MP_BC_LOAD_GLOBAL:
DECODE_QSTR;
mp_printf(print, "LOAD_GLOBAL %s", qstr_str(qst));
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
mp_printf(print, " (cache=%u)", *ip++);
}
break;
case MP_BC_LOAD_ATTR:
DECODE_QSTR;
mp_printf(print, "LOAD_ATTR %s", qstr_str(qst));
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
mp_printf(print, " (cache=%u)", *ip++);
}
break;
case MP_BC_LOAD_METHOD:
@ -270,9 +261,6 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
case MP_BC_STORE_ATTR:
DECODE_QSTR;
mp_printf(print, "STORE_ATTR %s", qstr_str(qst));
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
mp_printf(print, " (cache=%u)", *ip++);
}
break;
case MP_BC_STORE_SUBSCR:
@ -531,7 +519,8 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) {
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
mp_printf(print, "STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {
mp_printf(print, "UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
mp_uint_t op = ip[-1] - MP_BC_UNARY_OP_MULTI;
mp_printf(print, "UNARY_OP " UINT_FMT " %s", op, qstr_str(mp_unary_op_method_name[op]));
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {
mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;
mp_printf(print, "BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op]));

106
py/vm.c
View File

@ -182,30 +182,13 @@
#define TRACE_TICK(current_ip, current_sp, is_exception)
#endif // MICROPY_PY_SYS_SETTRACE
#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
static inline mp_map_elem_t *mp_map_cached_lookup(mp_map_t *map, qstr qst, uint8_t *idx_cache) {
size_t idx = *idx_cache;
mp_obj_t key = MP_OBJ_NEW_QSTR(qst);
mp_map_elem_t *elem = NULL;
if (idx < map->alloc && map->table[idx].key == key) {
elem = &map->table[idx];
} else {
elem = mp_map_lookup(map, key, MP_MAP_LOOKUP);
if (elem != NULL) {
*idx_cache = (elem - &map->table[0]) & 0xff;
}
}
return elem;
}
#endif
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
// sp points to bottom of stack which grows up
// returns:
// MP_VM_RETURN_NORMAL, sp valid, return value in *sp
// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
// MP_VM_RETURN_EXCEPTION, exception in state[0]
mp_vm_return_kind_t PLACE_IN_ITCM(mp_execute_bytecode)(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
mp_vm_return_kind_t MICROPY_WRAP_MP_EXECUTE_BYTECODE(mp_execute_bytecode)(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
#define SELECTIVE_EXC_IP (0)
#if SELECTIVE_EXC_IP
#define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */
@ -373,84 +356,46 @@ dispatch_loop:
goto load_check;
}
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
ENTRY(MP_BC_LOAD_NAME): {
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
PUSH(mp_load_name(qst));
DISPATCH();
}
#else
ENTRY(MP_BC_LOAD_NAME): {
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_map_elem_t *elem = mp_map_cached_lookup(&mp_locals_get()->map, qst, (uint8_t*)ip);
mp_obj_t obj;
if (elem != NULL) {
obj = elem->value;
} else {
obj = mp_load_name(qst);
}
PUSH(obj);
ip++;
DISPATCH();
}
#endif
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
ENTRY(MP_BC_LOAD_GLOBAL): {
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
PUSH(mp_load_global(qst));
DISPATCH();
}
#else
ENTRY(MP_BC_LOAD_GLOBAL): {
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_map_elem_t *elem = mp_map_cached_lookup(&mp_globals_get()->map, qst, (uint8_t*)ip);
mp_obj_t obj;
if (elem != NULL) {
obj = elem->value;
} else {
obj = mp_load_global(qst);
}
PUSH(obj);
ip++;
DISPATCH();
}
#endif
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
ENTRY(MP_BC_LOAD_ATTR): {
FRAME_UPDATE();
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
SET_TOP(mp_load_attr(TOP(), qst));
DISPATCH();
}
#else
ENTRY(MP_BC_LOAD_ATTR): {
FRAME_UPDATE();
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_obj_t top = TOP();
mp_obj_t obj;
#if MICROPY_OPT_LOAD_ATTR_FAST_PATH
// For the specific case of an instance type, it implements .attr
// and forwards to its members map. Attribute lookups on instance
// types are extremely common, so avoid all the other checks and
// calls that normally happen first.
mp_map_elem_t *elem = NULL;
if (mp_obj_is_instance_type(mp_obj_get_type(top))) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);
elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
}
mp_obj_t obj;
if (elem != NULL) {
if (elem) {
obj = elem->value;
} else {
} else
#endif
{
obj = mp_load_attr(top, qst);
}
SET_TOP(obj);
ip++;
DISPATCH();
}
#endif
ENTRY(MP_BC_LOAD_METHOD): {
MARK_EXC_IP_SELECTIVE();
@ -506,7 +451,6 @@ dispatch_loop:
DISPATCH();
}
#if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
ENTRY(MP_BC_STORE_ATTR): {
FRAME_UPDATE();
MARK_EXC_IP_SELECTIVE();
@ -515,32 +459,6 @@ dispatch_loop:
sp -= 2;
DISPATCH();
}
#else
// This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or
// MICROPY_PY_DESCRIPTORS enabled because if the attr exists in
// self->members then it can't be a property or have descriptors. A
// consequence of this is that we can't use MP_MAP_LOOKUP_ADD_IF_NOT_FOUND
// in the fast-path below, because that store could override a property.
ENTRY(MP_BC_STORE_ATTR): {
FRAME_UPDATE();
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_map_elem_t *elem = NULL;
mp_obj_t top = TOP();
if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip);
}
if (elem != NULL) {
elem->value = sp[-1];
} else {
mp_store_attr(sp[0], qst, sp[-1]);
}
sp -= 2;
ip++;
DISPATCH();
}
#endif
ENTRY(MP_BC_STORE_SUBSCR):
MARK_EXC_IP_SELECTIVE();

View File

@ -25,6 +25,7 @@
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#ifndef likely
@ -68,6 +69,14 @@ void *memcpy(void *dst, const void *src, size_t n) {
return dst;
}
extern void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen);
void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen) {
if (len > slen) {
return NULL;
}
return memcpy(dest, src, len);
}
void *memmove(void *dest, const void *src, size_t n) {
if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) {
// need to copy backwards

View File

@ -55,21 +55,21 @@ int pyexec_system_exit = 0;
STATIC bool repl_display_debugging_info = 0;
#endif
#define EXEC_FLAG_PRINT_EOF (1)
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
#define EXEC_FLAG_IS_REPL (4)
#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8)
#define EXEC_FLAG_SOURCE_IS_VSTR (16)
#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
#define EXEC_FLAG_SOURCE_IS_READER (64)
#define EXEC_FLAG_SOURCE_IS_ATEXIT (128)
#define EXEC_FLAG_PRINT_EOF (1 << 0)
#define EXEC_FLAG_ALLOW_DEBUGGING (1 << 1)
#define EXEC_FLAG_IS_REPL (1 << 2)
#define EXEC_FLAG_SOURCE_IS_RAW_CODE (1 << 3)
#define EXEC_FLAG_SOURCE_IS_VSTR (1 << 4)
#define EXEC_FLAG_SOURCE_IS_FILENAME (1 << 5)
#define EXEC_FLAG_SOURCE_IS_READER (1 << 6)
#define EXEC_FLAG_SOURCE_IS_ATEXIT (1 << 7)
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) {
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, mp_uint_t exec_flags, pyexec_result_t *result) {
int ret = 0;
#if MICROPY_REPL_INFO
uint32_t start = 0;
@ -166,6 +166,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
mp_hal_stdout_tx_strn("\x04", 1);
}
// check for SystemExit
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
// at the moment, the value of SystemExit is unused
@ -745,7 +746,7 @@ int pyexec_file(const char *filename, pyexec_result_t *result) {
int pyexec_file_if_exists(const char *filename, pyexec_result_t *result) {
#if MICROPY_MODULE_FROZEN
if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) {
if (mp_find_frozen_module(filename, NULL, NULL) == MP_IMPORT_STAT_FILE) {
return pyexec_frozen_module(filename, result);
}
#endif
@ -758,7 +759,8 @@ int pyexec_file_if_exists(const char *filename, pyexec_result_t *result) {
#if MICROPY_MODULE_FROZEN
int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
void *frozen_data;
int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data);
int frozen_type;
mp_find_frozen_module(name, &frozen_type, &frozen_data);
switch (frozen_type) {
#if MICROPY_MODULE_FROZEN_STR

View File

@ -94,6 +94,9 @@ void upytest_execute_test(const char *src) {
gc_init(heap_start, heap_end);
mp_init();
mp_obj_list_init(mp_sys_path, 0);
#if MICROPY_MODULE_FROZEN
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen));
#endif
mp_obj_list_init(mp_sys_argv, 0);
nlr_buf_t nlr;

View File

@ -1,10 +1,13 @@
# test bignum comparisons
i = 1 << 65
cases = (0, 1, -1, i, -i, i + 1, -(i + 1))
print(i == 0)
print(i != 0)
print(i < 0)
print(i > 0)
print(i <= 0)
print(i >= 0)
for lhs in cases:
for rhs in cases:
print("{} == {} = {}".format(lhs, rhs, lhs == rhs))
print("{} != {} = {}".format(lhs, rhs, lhs != rhs))
print("{} < {} = {}".format(lhs, rhs, lhs < rhs))
print("{} > {} = {}".format(lhs, rhs, lhs > rhs))
print("{} <= {} = {}".format(lhs, rhs, lhs <= rhs))
print("{} >= {} = {}".format(lhs, rhs, lhs >= rhs))

View File

@ -1,4 +1,4 @@
# test [0,-0,1,-1] edge cases of bignum
# test [0,1,-1] edge cases of bignum
import skip_if
skip_if.no_bigint()
@ -16,7 +16,7 @@ print([~c for c in cases])
print([c >> 1 for c in cases])
print([c << 1 for c in cases])
# comparison of 0/-0/+0
# comparison of 0
print(long_zero == 0)
print(long_neg_zero == 0)
print(long_one - 1 == 0)
@ -29,3 +29,40 @@ print(long_neg_zero < 1)
print(long_neg_zero < -1)
print(long_neg_zero > 1)
print(long_neg_zero > -1)
# generate zeros that involve negative numbers
large = 1 << 70
large_plus_one = large + 1
zeros = (
large - large,
-large + large,
large + -large,
-(large - large),
large - large_plus_one + 1,
-large & (large - large),
-large ^ -large,
-large * (large - large),
(large - large) // -large,
-large // -large_plus_one,
-(large + large) % large,
(large + large) % -large,
-(large + large) % -large,
)
print(zeros)
# compute arithmetic operations that may have problems with -0
# (this checks that -0 is never generated in the zeros tuple)
cases = (0, 1, -1) + zeros
for lhs in cases:
print("-{} = {}".format(lhs, -lhs))
print("~{} = {}".format(lhs, ~lhs))
print("{} >> 1 = {}".format(lhs, lhs >> 1))
print("{} << 1 = {}".format(lhs, lhs << 1))
for rhs in cases:
print("{} == {} = {}".format(lhs, rhs, lhs == rhs))
print("{} + {} = {}".format(lhs, rhs, lhs + rhs))
print("{} - {} = {}".format(lhs, rhs, lhs - rhs))
print("{} * {} = {}".format(lhs, rhs, lhs * rhs))
print("{} | {} = {}".format(lhs, rhs, lhs | rhs))
print("{} & {} = {}".format(lhs, rhs, lhs & rhs))
print("{} ^ {} = {}".format(lhs, rhs, lhs ^ rhs))

View File

@ -22,6 +22,13 @@ def foo(a, b):
return f'{x}{y}{a}{b}'
print(foo(7, 8))
# ':' character within {...} that should not be interpreted as format specifiers.
print(f"a{[0,1,2][0:2]}")
print(f"a{[0,15,2][0:2][-1]:04x}")
# Nested '{' and '}' characters.
print(f"a{ {0,1,2}}")
# PEP-0498 specifies that '\\' and '#' must be disallowed explicitly, whereas
# MicroPython relies on the syntax error as a result of the substitution.

View File

@ -0,0 +1,39 @@
# test subclassing exceptions and providing __new__
class Dummy(BaseException):
pass
class GoodException(BaseException):
def __new__(cls, *args, **kwargs):
print("GoodException __new__")
return Dummy(*args, **kwargs)
class BadException(BaseException):
def __new__(cls, *args, **kwargs):
print("BadException __new__")
return 1
try:
raise GoodException("good message")
except BaseException as good:
print(type(good), good.args[0])
try:
raise BadException("bad message")
except Exception as bad:
# Should be TypeError 'exceptions must derive from BaseException'
print(type(bad), bad.args[0])
try:
def gen():
yield
gen().throw(BadException)
except Exception as genbad:
# Should be TypeError 'exceptions must derive from BaseException'
print(type(genbad), genbad.args[0])

View File

@ -0,0 +1,6 @@
GoodException __new__
<class 'Dummy'> good message
BadException __new__
<class 'TypeError'> exceptions must derive from BaseException
BadException __new__
<class 'TypeError'> exceptions must derive from BaseException

16
tests/basics/sys_path.py Normal file
View File

@ -0,0 +1,16 @@
# test sys.path
try:
import usys as sys
except ImportError:
import sys
# check that this script was executed from a file of the same name
if "__file__" not in globals() or "sys_path.py" not in __file__:
print("SKIP")
raise SystemExit
# test that sys.path[0] is the directory containing this script
with open(sys.path[0] + "/sys_path.py") as f:
for _ in range(4):
print(f.readline())

View File

@ -78,11 +78,11 @@ arg names:
45 STORE_NAME g
48 LOAD_CONST_OBJ \.\+
50 LOAD_METHOD format
53 LOAD_NAME b (cache=0)
57 CALL_METHOD n=1 nkw=0
59 STORE_NAME h
62 LOAD_CONST_NONE
63 RETURN_VALUE
53 LOAD_NAME b
56 CALL_METHOD n=1 nkw=0
58 STORE_NAME h
61 LOAD_CONST_NONE
62 RETURN_VALUE
mem: total=\\d\+, current=\\d\+, peak=\\d\+
stack: \\d\+ out of \\d\+
GC: total: \\d\+, used: \\d\+, free: \\d\+

View File

@ -15,9 +15,9 @@ def f():
c = [1, 2]
d = {1, 2}
e = {}
f = {1: 2}
g = "a"
h = b"a"
f = {1:2}
g = 'a'
h = b'a'
# unary/binary ops
i = 1
@ -59,7 +59,7 @@ def f():
# comprehensions
a = (b for c in d if e)
a = [b for c in d if e]
a = {b: b for c in d if e}
a = {b:b for c in d if e}
# function calls
a()
@ -108,10 +108,8 @@ def f():
# closed over variables
x = 1
def closure():
nonlocal x
a = x + 1
nonlocal x; a = x + 1
x = 1
del x
@ -128,14 +126,12 @@ def f():
return
return 1
# function with lots of locals
def f():
l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = 1
m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = m10 = 2
l10 + m10
# functions with default args
def f(a=1):
pass
@ -143,19 +139,16 @@ def f(a=1):
def f(b=2):
return b + a
# function which yields
def f():
yield
yield 1
yield from 1
# class
class Class:
pass
# delete name
del Class

View File

@ -1,13 +1,13 @@
File cmdline/cmd_showbc.py, code block '<module>' (descriptor: \.\+, bytecode @\.\+ bytes)
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
########
\.\+51 63
\.\+63
arg names:
(N_STATE 3)
(N_EXC_STACK 0)
bc=0 line=1
########
bc=\\d\+ line=167
bc=\\d\+ line=160
00 MAKE_FUNCTION \.\+
\\d\+ STORE_NAME f
\\d\+ MAKE_FUNCTION \.\+
@ -45,7 +45,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
(INIT_CELL 16)
bc=0 line=1
########
bc=\\d\+ line=129
bc=\\d\+ line=127
00 LOAD_CONST_NONE
01 LOAD_CONST_FALSE
02 BINARY_OP 27 __add__
@ -92,10 +92,10 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
58 BINARY_OP 27 __add__
\\d\+ STORE_FAST 8
\\d\+ LOAD_FAST 0
\\d\+ UNARY_OP 1
\\d\+ UNARY_OP 1 __neg__
\\d\+ STORE_FAST 9
\\d\+ LOAD_FAST 0
\\d\+ UNARY_OP 3
\\d\+ UNARY_OP 3
\\d\+ STORE_FAST 10
\\d\+ LOAD_FAST 0
\\d\+ LOAD_DEREF 14
@ -116,14 +116,14 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ LOAD_DEREF 14
\\d\+ LOAD_FAST 1
\\d\+ BINARY_OP 2 __eq__
\\d\+ UNARY_OP 3
\\d\+ UNARY_OP 3
\\d\+ STORE_FAST 10
\\d\+ LOAD_DEREF 14
\\d\+ LOAD_ATTR c (cache=0)
\\d\+ LOAD_ATTR c
\\d\+ STORE_FAST 11
\\d\+ LOAD_FAST 11
\\d\+ LOAD_DEREF 14
\\d\+ STORE_ATTR c (cache=0)
\\d\+ STORE_ATTR c
\\d\+ LOAD_DEREF 14
\\d\+ LOAD_CONST_SMALL_INT 0
\\d\+ LOAD_SUBSCR
@ -233,7 +233,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ LOAD_DEREF 16
\\d\+ POP_TOP
\\d\+ JUMP \\d\+
\\d\+ LOAD_GLOBAL y (cache=0)
\\d\+ LOAD_GLOBAL y
\\d\+ POP_TOP
\\d\+ JUMP \\d\+
\\d\+ LOAD_DEREF 14
@ -320,7 +320,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
(N_EXC_STACK 0)
bc=0 line=1
########
bc=\\d\+ line=136
bc=\\d\+ line=133
00 LOAD_CONST_SMALL_INT 1
01 DUP_TOP
02 STORE_FAST 0
@ -376,7 +376,7 @@ arg names: a
(N_EXC_STACK 0)
(INIT_CELL 0)
########
bc=\\d\+ line=143
bc=\\d\+ line=139
00 LOAD_CONST_SMALL_INT 2
01 BUILD_TUPLE 1
03 LOAD_NULL
@ -393,9 +393,9 @@ arg names:
(N_STATE 2)
(N_EXC_STACK 0)
bc=0 line=1
bc=0 line=149
bc=3 line=150
bc=6 line=151
bc=0 line=144
bc=3 line=145
bc=6 line=146
00 LOAD_CONST_NONE
01 YIELD_VALUE
02 POP_TOP
@ -418,13 +418,13 @@ arg names:
(N_EXC_STACK 0)
bc=0 line=1
########
bc=13 line=156
00 LOAD_NAME __name__ (cache=0)
04 STORE_NAME __module__
07 LOAD_CONST_STRING 'Class'
10 STORE_NAME __qualname__
13 LOAD_CONST_NONE
14 RETURN_VALUE
bc=12 line=150
00 LOAD_NAME __name__
03 STORE_NAME __module__
06 LOAD_CONST_STRING 'Class'
09 STORE_NAME __qualname__
12 LOAD_CONST_NONE
13 RETURN_VALUE
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
########
@ -433,9 +433,9 @@ arg names: self
(N_STATE 4)
(N_EXC_STACK 0)
bc=0 line=1
bc=0 line=164
00 LOAD_GLOBAL super (cache=0)
\\d\+ LOAD_GLOBAL __class__ (cache=0)
bc=0 line=157
00 LOAD_GLOBAL super
\\d\+ LOAD_GLOBAL __class__
\\d\+ LOAD_FAST 0
\\d\+ LOAD_SUPER_METHOD f
\\d\+ CALL_METHOD n=0 nkw=0
@ -517,7 +517,7 @@ arg names: *
(N_EXC_STACK 0)
bc=0 line=1
########
bc=\\d\+ line=116
bc=\\d\+ line=114
00 LOAD_DEREF 0
02 LOAD_CONST_SMALL_INT 1
03 BINARY_OP 27 __add__
@ -536,7 +536,7 @@ arg names: * b
(N_EXC_STACK 0)
bc=0 line=1
########
bc=\\d\+ line=144
bc=\\d\+ line=140
00 LOAD_FAST 1
01 LOAD_DEREF 0
03 BINARY_OP 27 __add__

View File

@ -8,12 +8,12 @@ arg names:
(N_EXC_STACK 0)
bc=0 line=1
bc=0 line=3
00 LOAD_NAME print (cache=0)
04 LOAD_CONST_SMALL_INT 1
05 CALL_FUNCTION n=1 nkw=0
07 POP_TOP
08 LOAD_CONST_NONE
09 RETURN_VALUE
00 LOAD_NAME print
03 LOAD_CONST_SMALL_INT 1
04 CALL_FUNCTION n=1 nkw=0
06 POP_TOP
07 LOAD_CONST_NONE
08 RETURN_VALUE
1
mem: total=\\d\+, current=\\d\+, peak=\\d\+
stack: \\d\+ out of \\d\+

View File

@ -1,12 +1,13 @@
"""
categories: Core
description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces
description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings
cause: MicroPython is optimised for code space.
workaround: Use the + operator between literal strings when either is an f-string
workaround: Use the + operator between literal strings when either or both are f-strings
"""
x = 1
print("aa" f"{x}")
print(f"{x}" "ab")
print("a{}a" f"{x}")
print(f"{x}" "a{}b")
x, y = 1, 2
print("aa" f"{x}") # works
print(f"{x}" "ab") # works
print("a{}a" f"{x}") # fails
print(f"{x}" "a{}b") # fails
print(f"{x}" f"{y}") # fails

View File

@ -1,9 +1,9 @@
"""
categories: Core
description: f-strings cannot support expressions that require parsing to resolve nested braces
description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets
cause: MicroPython is optimised for code space.
workaround: Only use simple expressions inside f-strings
workaround: Always use balanced braces and brackets in expressions inside f-strings
"""
f'{"hello {} world"}'
f"{repr({})}"
print(f'{"hello { world"}')
print(f'{"hello ] world"}')

View File

@ -22,8 +22,9 @@ async def factorial(name, number):
async def task(id):
print("start", id)
await asyncio.sleep(0.2)
await asyncio.sleep(0.02)
print("end", id)
return id
async def gather_task():
@ -36,12 +37,17 @@ async def main():
# Simple gather with return values
print(await asyncio.gather(factorial("A", 2), factorial("B", 3), factorial("C", 4)))
# Test return_exceptions, where one task is cancelled and the other finishes normally
tasks = [asyncio.create_task(task(1)), asyncio.create_task(task(2))]
tasks[0].cancel()
print(await asyncio.gather(*tasks, return_exceptions=True))
# Cancel a multi gather
# TODO doesn't work, Task should not forward cancellation from gather to sub-task
# but rather CancelledError should cancel the gather directly, which will then cancel
# all sub-tasks explicitly
# t = asyncio.create_task(gather_task())
# await asyncio.sleep(0.1)
# await asyncio.sleep(0.01)
# t.cancel()
# await asyncio.sleep(0.01)

View File

@ -8,3 +8,6 @@ Task B: factorial(3) = 6
Task C: Compute factorial(4)...
Task C: factorial(4) = 24
[2, 6, 24]
start 2
end 2
[CancelledError(), 2]

View File

@ -5,7 +5,9 @@ try:
except ImportError:
try:
import socket, select
except ImportError:
select.poll # Raises AttributeError for CPython implementations without poll()
except (ImportError, AttributeError):
print("SKIP")
raise SystemExit

View File

@ -1,125 +0,0 @@
# test importing of .mpy files with native code (x64 only)
import sys, uio
try:
uio.IOBase
import uos
uos.mount
except (ImportError, AttributeError):
print("SKIP")
raise SystemExit
if not (sys.platform == "linux" and sys.maxsize > 2**32):
print("SKIP")
raise SystemExit
class UserFile(uio.IOBase):
def __init__(self, data):
self.data = data
self.pos = 0
def read(self):
return self.data
def readinto(self, buf):
n = 0
while n < len(buf) and self.pos < len(self.data):
buf[n] = self.data[self.pos]
n += 1
self.pos += 1
return n
def ioctl(self, req, arg):
return 0
class UserFS:
def __init__(self, files):
self.files = files
def mount(self, readonly, mksfs):
pass
def umount(self):
pass
def stat(self, path):
if path in self.files:
return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0)
raise OSError
def open(self, path, mode):
return UserFile(self.files[path])
# these are the test .mpy files
user_files = {
# bad architecture
"/mod0.mpy": b"C\x05\xff\x00\x10",
# test loading of viper and asm
"/mod1.mpy": (
b"C\x05\x0b\x1f\x20" # header
b"\x20" # n bytes, bytecode
b"\x00\x08\x02m\x02m" # prelude
b"\x51" # LOAD_CONST_NONE
b"\x63" # RETURN_VALUE
b"\x00\x02" # n_obj, n_raw_code
b"\x22" # n bytes, viper code
b"\x00\x00\x00\x00\x00\x00" # dummy machine code
b"\x00\x00" # qstr0
b"\x01\x0c\x0aprint" # n_qstr, qstr0
b"\x00\x00\x00" # scope_flags, n_obj, n_raw_code
b"\x23" # n bytes, asm code
b"\x00\x00\x00\x00\x00\x00\x00\x00" # dummy machine code
b"\x00\x00\x00" # scope_flags, n_pos_args, type_sig
),
# test loading viper with truncated data
"/mod2.mpy": (
b"C\x05\x0b\x1f\x20" # header
b"\x20" # n bytes, bytecode
b"\x00\x08\x02m\x02m" # prelude
b"\x51" # LOAD_CONST_NONE
b"\x63" # RETURN_VALUE
b"\x00\x01" # n_obj, n_raw_code
b"\x12" # n bytes(=4), viper code
),
# test loading viper with additional scope flags and relocation
"/mod3.mpy": (
b"C\x05\x0b\x1f\x20" # header
b"\x20" # n bytes, bytecode
b"\x00\x08\x02m\x02m" # prelude
b"\x51" # LOAD_CONST_NONE
b"\x63" # RETURN_VALUE
b"\x00\x01" # n_obj, n_raw_code
b"\x12" # n bytes(=4), viper code
b"\x00\x00\x00\x00" # dummy machine code
b"\x00" # n_qstr
b"\x81\x60" # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC (0xe0 encoded over two bytes)
b"\x00\x00" # n_obj, n_raw_code
b"\x06rodata" # rodata, 6 bytes
b"\x04" # bss, 4 bytes
b"\x03\x01\x00" # dummy relocation of rodata
),
}
# create and mount a user filesystem
uos.mount(UserFS(user_files), "/userfs")
sys.path.append("/userfs")
# import .mpy files from the user filesystem
for i in range(len(user_files)):
mod = "mod%u" % i
try:
__import__(mod)
print(mod, "OK")
except ValueError as er:
print(mod, "ValueError", er)
except RuntimeError as er:
print(mod, "RuntimeError", er)
# unmount and undo path addition
uos.umount("/userfs")
sys.path.pop()

View File

@ -1,4 +0,0 @@
mod0 ValueError incompatible native .mpy architecture
mod1 OK
mod2 RuntimeError Corrupt .mpy file
mod3 OK

View File

@ -1,15 +0,0 @@
import uio
import sys
try:
uio.resource_stream
except AttributeError:
print("SKIP")
raise SystemExit
buf = uio.resource_stream("data", "file2")
print(buf.read())
# resource_stream(None, ...) look ups from current dir, hence sys.path[0] hack
buf = uio.resource_stream(None, sys.path[0] + "/data/file2")
print(buf.read())

View File

@ -1,2 +0,0 @@
1234
1234

View File

@ -1,4 +1,5 @@
# test constant optimisation
# This test will only work when MICROPY_COMP_CONST is enabled.
from micropython import const

View File

@ -48,8 +48,8 @@ class UserFS:
# Pre-compiled examples/natmod/features0 example for various architectures, keyed
# by the required value of sys.implementation.mpy.
features0_file_contents = {
# -march=x64 -mcache-lookup-bc
0xB05: b'C\x05\x0b\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08H\x8bk(\xff\xd5H\x8d5 \x00\x00\x00I\x89\xc4H\x8b\x05.\x00\x00\x00\x0f\xb78\xffShL\x89\xe7\xff\xd5H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial \x00\x00\r \x01"\xa1\x1c\x01\x1e\xff',
# -march=x64
0xA05: b'C\x05\x0a\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial \x00\x00\r \x01"\xa1\x1c\x01\x1e\xff',
# -march=armv7m
0x1605: b"C\x05\x16\x1f \x84\x12\x1a\xe0\x00\x00\x13\xb5\nK\nJ{D\x9cX\x02!\xe3h\x98G\x03F\x01 3\xb9\x02!#i\x01\x93\x02\xb0\xbd\xe8\x10@\x18GXC\x01;\xf4\xe7\x00\xbfj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\tN\tK~D\xf4X@hgi\xb8G\x05F\x07K\x07I\xf2XyD\x10\x88ck\x98G(F\xb8G h\xf8\xbd6\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x01\x84\x00\x12factorial \x00\x00\r<\x01>\xa18\x01:\xff",
}

View File

@ -52,11 +52,11 @@ class UserFS:
# fmt: off
user_files = {
# bad architecture
'/mod0.mpy': b'C\x05\xff\x00\x10',
'/mod0.mpy': b'C\x05\xfe\x00\x10',
# test loading of viper and asm
'/mod1.mpy': (
b'C\x05\x0b\x1f\x20' # header
b'C\x05\x0a\x1f\x20' # header
b'\x20' # n bytes, bytecode
b'\x00\x08\x02m\x02m' # prelude
@ -78,7 +78,7 @@ user_files = {
# test loading viper with additional scope flags and relocation
'/mod2.mpy': (
b'C\x05\x0b\x1f\x20' # header
b'C\x05\x0a\x1f\x20' # header
b'\x20' # n bytes, bytecode
b'\x00\x08\x02m\x02m' # prelude

View File

@ -0,0 +1,20 @@
# test viper with multiple subscripts in a single expression
@micropython.viper
def f1(b: ptr8):
b[0] += b[1]
@micropython.viper
def f2(b: ptr8, i: int):
b[0] += b[i]
b = bytearray(b"\x01\x02")
f1(b)
print(b)
b = bytearray(b"\x01\x02")
f2(b, 1)
print(b)

View File

@ -0,0 +1,2 @@
bytearray(b'\x03\x02')
bytearray(b'\x03\x02')

View File

@ -54,8 +54,8 @@ except NotImplementedError:
# str(...) with keywords not implemented
try:
str(b"abc", encoding="utf8")
except NotImplementedError:
print("NotImplementedError")
except TypeError:
print("TypeError")
# str.rsplit(None, n) not implemented
try:

View File

@ -5,7 +5,7 @@ NotImplementedError
NotImplementedError
TypeError, ValueError
NotImplementedError
NotImplementedError
TypeError
NotImplementedError
NotImplementedError
NotImplementedError

View File

@ -15,7 +15,7 @@ def transform_radix2(vector, inverse):
# Initialization
n = len(vector)
levels = int(math.log2(n))
levels = int(math.log(n) / math.log(2))
coef = (2 if inverse else -2) * cmath.pi / n
exptable = [cmath.rect(1, i * coef) for i in range(n // 2)]
vector = [vector[reverse(i, levels)] for i in range(n)] # Copy with bit-reversed permutation

View File

@ -112,7 +112,7 @@ def run_micropython(pyb, args, test_file, is_special=False):
def get(required=False):
rv = b""
while True:
ready = select.select([emulator], [], [], 0.02)
ready = select.select([emulator], [], [emulator], 0.02)
if ready[0] == [emulator]:
rv += os.read(emulator, 1024)
else:
@ -150,8 +150,8 @@ def run_micropython(pyb, args, test_file, is_special=False):
p.kill()
except ProcessLookupError:
pass
os.close(emulator)
os.close(subterminal)
os.close(emulator)
else:
output_mupy = subprocess.check_output(
args + [test_file], stderr=subprocess.STDOUT
@ -757,9 +757,7 @@ the last matching regex is used:
cmd_parser.add_argument(
"--via-mpy", action="store_true", help="compile .py files to .mpy first"
)
cmd_parser.add_argument(
"--mpy-cross-flags", default="-mcache-lookup-bc", help="flags to pass to mpy-cross"
)
cmd_parser.add_argument("--mpy-cross-flags", default="", help="flags to pass to mpy-cross")
cmd_parser.add_argument(
"--keep-path", action="store_true", help="do not clear MICROPYPATH when running tests"
)
@ -871,7 +869,7 @@ the last matching regex is used:
if not args.keep_path:
# clear search path to make sure tests use only builtin modules and those in extmod
os.environ["MICROPYPATH"] = os.pathsep + base_path("../extmod")
os.environ["MICROPYPATH"] = os.pathsep + ".frozen" + os.pathsep + base_path("../extmod")
try:
os.makedirs(args.result_dir, exist_ok=True)

View File

@ -89,12 +89,6 @@ try:
except ZeroDivisionError:
print("ZeroDivisionError")
# test loading a resource from a frozen string
import uio
buf = uio.resource_stream("frzstr_pkg2", "mod.py")
print(buf.read(21))
# test for MP_QSTR_NULL regression
from frzqstr import returns_NULL

View File

@ -44,10 +44,10 @@ ime
utime utimeq
argv byteorder exc_info exit
getsizeof implementation maxsize modules
path platform stderr stdin
stdout version version_info
argv atexit byteorder exc_info
exit getsizeof implementation maxsize
modules path platform stderr
stdin stdout version version_info
ementation
# attrtuple
(start=1, stop=2, step=3)
@ -165,15 +165,14 @@ cpp None
frzstr1
frzstr1.py
frzmpy1
.frozen/frzmpy1.py
frzmpy1.py
frzstr_pkg1.__init__
frzstr_pkg1/__init__.py 1
frzmpy_pkg1.__init__
.frozen/frzmpy_pkg1/__init__.py 1
frzmpy_pkg1/__init__.py 1
frzstr_pkg2.mod
1
frzmpy_pkg2.mod
1
ZeroDivisionError
b'# test frozen package'
NULL

116
tools/autobuild/build-boards.sh Executable file
View File

@ -0,0 +1,116 @@
#!/bin/bash
#
# The functions in this file can be run independently to build boards.
# For example:
#
# $ source build-boards.sh
# $ MICROPY_AUTOBUILD_MAKE=make build_rp2_boards -latest /tmp
function build_board {
# check/get parameters
if [ $# -lt 4 ]; then
echo "usage: $0 <board-json-file> <fw-tag> <dest-dir> <exts...>"
return 1
fi
board_json=$1
fw_tag=$2
dest_dir=$3
shift
shift
shift
board=$(echo $board_json | awk -F '/' '{ print $2 }')
descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))")
build_dir=/tmp/micropython-build-$board
echo "building $descr $board"
$MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && (
for ext in $@; do
dest=$dest_dir/$descr$fw_tag.$ext
if [ -r $build_dir/firmware.$ext ]; then
mv $build_dir/firmware.$ext $dest
else
# esp32 has micropython.elf and micropython.map
mv $build_dir/micropython.$ext $dest
fi
done
)
rm -rf $build_dir
}
function build_boards {
# check/get parameters
if [ $# -lt 4 ]; then
echo "usage: $0 <check-file> <fw-tag> <dest-dir> <exts...>"
return 1
fi
check_file=$1
shift
# check we are in the correct directory
if [ ! -r $check_file ]; then
echo "must be in directory containing $check_file"
return 1
fi
# build all boards that have a board.json file
for board_json in $(find boards/ -name board.json | sort); do
build_board $board_json $@
done
}
function build_esp32_boards {
# check/get parameters
if [ $# != 2 ]; then
echo "usage: $0 <fw-tag> <dest-dir>"
return 1
fi
fw_tag=$1
dest_dir=$2
# check we are in the correct directory
if [ ! -r modesp32.c ]; then
echo "must be in esp32 directory"
return 1
fi
# build the boards, based on the IDF version
for board_json in $(find boards/ -name board.json | sort); do
mcu=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('mcu', 'unknown'))")
if idf.py --version | grep -q v4.2; then
if [ $mcu = esp32 ]; then
# build standard esp32-based boards with IDF v4.2
if echo $board_json | grep -q GENERIC; then
# traditionally, GENERIC and GENERIC_SPIRAM boards used manifest_release.py
MICROPY_AUTOBUILD_MAKE="$MICROPY_AUTOBUILD_MAKE FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py" build_board $board_json $fw_tag $dest_dir bin elf map
else
build_board $board_json $fw_tag $dest_dir bin elf map
fi
fi
else
if [ $mcu != esp32 ]; then
# build esp32-s2/s3/c3 based boards with IDF v4.4+
build_board $board_json $fw_tag $dest_dir bin elf map
fi
fi
done
}
function build_mimxrt_boards {
build_boards modmimxrt.c $1 $2 bin hex
}
function build_rp2_boards {
build_boards modrp2.c $1 $2 uf2
}
function build_samd_boards {
build_boards samd_soc.c $1 $2 uf2
}
function build_stm32_boards {
build_boards modpyb.c $1 $2 dfu hex
}

View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
import glob
import json
import os
import sys
def main(repo_path, output_path):
boards_index = []
board_ids = set()
for board_json in glob.glob(os.path.join(repo_path, "ports/*/boards/*/board.json")):
# Relative path to the board directory (e.g. "ports/stm32/boards/PYBV11").
board_dir = os.path.dirname(board_json)
# Relative path to the port (e.g. "ports/stm32")
port_dir = os.path.dirname(os.path.dirname(board_dir))
with open(board_json, "r") as f:
blob = json.load(f)
# Use "id" if specified, otherwise default to board dir (e.g. "PYBV11").
# We allow boards to override ID for the historical build names.
blob["id"] = blob.get("id", os.path.basename(board_dir))
# Check for duplicate board IDs.
if blob["id"] in board_ids:
print("Duplicate board ID: '{}'".format(blob["id"]), file=sys.stderr)
board_ids.add(blob["id"])
# Add in default fields.
blob["port"] = os.path.basename(port_dir)
blob["build"] = os.path.basename(board_dir)
boards_index.append(blob)
# Create the board markdown, which is the concatenation of the
# default "board.md" file (if exists), as well as any flashing
# instructions.
board_markdown = os.path.join(board_dir, "board.md")
with open(os.path.join(output_path, blob["id"] + ".md"), "w") as f:
if os.path.exists(board_markdown):
with open(board_markdown, "r") as fin:
f.write(fin.read())
if blob["deploy"]:
f.write("\n\n## Installation instructions\n")
for deploy in blob["deploy"]:
with open(os.path.join(board_dir, deploy), "r") as fin:
f.write(fin.read())
# Write the full index for the website to load.
with open(os.path.join(output_path, "index.json"), "w") as f:
json.dump(boards_index, f, indent=4, sort_keys=True)
f.write("\n")
if __name__ == "__main__":
main(sys.argv[1], sys.argv[2])

Some files were not shown because too many files have changed in this diff Show More