summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorTG-Techie <39284876+TG-Techie@users.noreply.github.com>2020-03-06 13:57:31 -0500
committerGitHub <noreply@github.com>2020-03-06 13:57:31 -0500
commit7198056bc31ebae22337af119c07c7dca03e85d5 (patch)
tree421b1c044250320ae15500f8578f6fec529937fa /py
parent6d4ffc69fdfe19366b15861694f97cbf77452937 (diff)
parentba0c14f9ddf01f6cf98d278cbc4769a476342db0 (diff)
Merge pull request #2 from adafruit/5.0.x
5.0.x
Diffstat (limited to 'py')
-rw-r--r--py/circuitpy_defns.mk46
-rw-r--r--py/circuitpy_mpconfig.h56
-rw-r--r--py/circuitpy_mpconfig.mk53
-rw-r--r--py/compile.c13
-rw-r--r--py/emitnative.c1
-rwxr-xr-xpy/gc.c98
-rw-r--r--py/gc.h13
-rwxr-xr-xpy/gc_long_lived.c5
-rw-r--r--py/makeqstrdata.py39
-rw-r--r--py/map.c4
-rw-r--r--py/modio.c2
-rwxr-xr-xpy/mpconfig.h17
-rw-r--r--py/mpstate.c3
-rw-r--r--py/mpstate.h2
-rw-r--r--py/nlr.h9
-rw-r--r--py/nlrthumb.c16
-rw-r--r--py/nlrx64.c2
-rw-r--r--py/nlrx86.c2
-rw-r--r--py/nlrxtensa.c2
-rw-r--r--py/obj.c5
-rw-r--r--py/objdict.c5
-rw-r--r--py/objexcept.c22
-rw-r--r--py/objfun.c4
-rw-r--r--py/objint.c37
-rw-r--r--py/objlist.c38
-rw-r--r--py/objnamedtuple.c1
-rw-r--r--py/objstr.c4
-rw-r--r--py/objstringio.c2
-rw-r--r--py/objtuple.c6
-rw-r--r--py/objtype.c19
-rw-r--r--py/proto.c50
-rw-r--r--py/proto.h43
-rw-r--r--py/py.mk9
-rwxr-xr-xpy/qstr.c4
-rw-r--r--py/runtime.c18
-rw-r--r--py/runtime.h11
-rw-r--r--py/sequence.c5
-rw-r--r--py/stream.c11
-rw-r--r--py/stream.h4
-rw-r--r--py/vm.c4
-rw-r--r--py/vmentrytable.h4
-rw-r--r--py/vstr.c3
42 files changed, 521 insertions, 171 deletions
diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk
index 211e85368..68fa25d8d 100644
--- a/py/circuitpy_defns.mk
+++ b/py/circuitpy_defns.mk
@@ -117,6 +117,9 @@ endif
ifeq ($(CIRCUITPY_AUDIOMIXER),1)
SRC_PATTERNS += audiomixer/%
endif
+ifeq ($(CIRCUITPY_AUDIOMP3),1)
+SRC_PATTERNS += audiomp3/%
+endif
ifeq ($(CIRCUITPY_BITBANGIO),1)
SRC_PATTERNS += bitbangio/%
endif
@@ -154,6 +157,9 @@ endif
ifeq ($(CIRCUITPY_MATH),1)
SRC_PATTERNS += math/%
endif
+ifeq ($(CIRCUITPY__EVE),1)
+SRC_PATTERNS += _eve/%
+endif
ifeq ($(CIRCUITPY_MICROCONTROLLER),1)
SRC_PATTERNS += microcontroller/%
endif
@@ -233,6 +239,7 @@ SRC_COMMON_HAL_ALL = \
_bleio/CharacteristicBuffer.c \
_bleio/Connection.c \
_bleio/Descriptor.c \
+ _bleio/PacketBuffer.c \
_bleio/Service.c \
_bleio/UUID.c \
analogio/AnalogIn.c \
@@ -294,7 +301,7 @@ $(filter $(SRC_PATTERNS), \
fontio/Glyph.c \
microcontroller/RunMode.c \
math/__init__.c \
- supervisor/__init__.c \
+ _eve/__init__.c \
)
SRC_BINDINGS_ENUMS += \
@@ -319,6 +326,8 @@ SRC_SHARED_MODULE_ALL = \
audiomixer/__init__.c \
audiomixer/Mixer.c \
audiomixer/MixerVoice.c \
+ audiomp3/__init__.c \
+ audiomp3/MP3Decoder.c \
bitbangio/I2C.c \
bitbangio/OneWire.c \
bitbangio/SPI.c \
@@ -354,7 +363,8 @@ SRC_SHARED_MODULE_ALL = \
uheap/__init__.c \
ustack/__init__.c \
_pew/__init__.c \
- _pew/PewPew.c
+ _pew/PewPew.c \
+ _eve/__init__.c
# All possible sources are listed here, and are filtered by SRC_PATTERNS.
SRC_SHARED_MODULE = $(filter $(SRC_PATTERNS), $(SRC_SHARED_MODULE_ALL))
@@ -371,6 +381,26 @@ SRC_SHARED_MODULE_ALL += \
touchio/TouchIn.c \
touchio/__init__.c
endif
+ifeq ($(CIRCUITPY_AUDIOMP3),1)
+SRC_MOD += $(addprefix lib/mp3/src/, \
+ bitstream.c \
+ buffers.c \
+ dct32.c \
+ dequant.c \
+ dqchan.c \
+ huffman.c \
+ hufftabs.c \
+ imdct.c \
+ mp3dec.c \
+ mp3tabs.c \
+ polyphase.c \
+ scalfact.c \
+ stproc.c \
+ subband.c \
+ trigtabs.c \
+)
+$(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "py/misc.h" -D'MPDEC_ALLOCATOR(x)=m_malloc(x,0)' -D'MPDEC_FREE(x)=m_free(x)'
+endif
# All possible sources are listed here, and are filtered by SRC_PATTERNS.
SRC_SHARED_MODULE_INTERNAL = \
@@ -403,6 +433,18 @@ $(addprefix lib/,\
)
endif
+ifdef LD_TEMPLATE_FILE
+# Generate a linker script (.ld file) from a template, for those builds that use it.
+GENERATED_LD_FILE = $(BUILD)/$(notdir $(patsubst %.template.ld,%.ld,$(LD_TEMPLATE_FILE)))
+#
+# ld_defines.pp is generated from ld_defines.c. See py/mkrules.mk.
+# Run gen_ld_files.py over ALL *.template.ld files, not just LD_TEMPLATE_FILE,
+# because it may include other template files.
+$(GENERATED_LD_FILE): $(BUILD)/ld_defines.pp boards/*.template.ld
+ $(STEPECHO) "GEN $@"
+ $(Q)$(PYTHON3) $(TOP)/tools/gen_ld_files.py --defines $< --out_dir $(BUILD) boards/*.template.ld
+endif
+
.PHONY: check-release-needs-clean-build
check-release-needs-clean-build:
diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h
index b1e7bc05a..53cd7b0bb 100644
--- a/py/circuitpy_mpconfig.h
+++ b/py/circuitpy_mpconfig.h
@@ -28,11 +28,12 @@
// sure that the same feature set and settings are used, such as in atmel-samd
// and nrf.
-#include <stdint.h>
-
#ifndef __INCLUDED_MPCONFIG_CIRCUITPY_H
#define __INCLUDED_MPCONFIG_CIRCUITPY_H
+#include <stdint.h>
+#include <stdatomic.h>
+
// This is CircuitPython.
#define CIRCUITPY 1
@@ -71,6 +72,7 @@
#define MICROPY_HELPER_REPL (1)
#define MICROPY_KBD_EXCEPTION (1)
#define MICROPY_MEM_STATS (0)
+#define MICROPY_MODULE_BUILTIN_INIT (1)
#define MICROPY_NONSTANDARD_TYPECODES (0)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_PERSISTENT_CODE_LOAD (1)
@@ -139,7 +141,6 @@
#define MICROPY_VFS_FAT (MICROPY_VFS)
#define MICROPY_READER_VFS (MICROPY_VFS)
-
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
@@ -167,20 +168,25 @@ typedef long mp_off_t;
#define mp_import_stat mp_vfs_import_stat
#define mp_builtin_open_obj mp_vfs_open_obj
+
// extra built in names to add to the global namespace
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
-// board specific definitions
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// board-specific definitions, which control and may override definitions below.
#include "mpconfigboard.h"
// CIRCUITPY_FULL_BUILD is defined in a *.mk file.
// Remove some lesser-used functionality to make small builds fit.
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (CIRCUITPY_FULL_BUILD)
-#define MICROPY_CPYTHON_COMPAT (CIRCUITPY_FULL_BUILD)
+//TODO: replace this with a rework of the FULL_BUILD system
+#if !defined(MICROPY_CPYTHON_COMPAT)
+ #define MICROPY_CPYTHON_COMPAT (CIRCUITPY_FULL_BUILD)
+#endif
#define MICROPY_MODULE_WEAK_LINKS (CIRCUITPY_FULL_BUILD)
#define MICROPY_PY_ALL_SPECIAL_METHODS (CIRCUITPY_FULL_BUILD)
#define MICROPY_PY_BUILTINS_COMPLEX (CIRCUITPY_FULL_BUILD)
@@ -191,7 +197,9 @@ typedef long mp_off_t;
#define MICROPY_PY_UERRNO (CIRCUITPY_FULL_BUILD)
// Opposite setting is deliberate.
#define MICROPY_PY_UERRNO_ERRORCODE (!CIRCUITPY_FULL_BUILD)
+#ifndef MICROPY_PY_URE
#define MICROPY_PY_URE (CIRCUITPY_FULL_BUILD)
+#endif
#define MICROPY_PY_URE_MATCH_GROUPS (CIRCUITPY_FULL_BUILD)
#define MICROPY_PY_URE_MATCH_SPAN_START_END (CIRCUITPY_FULL_BUILD)
#define MICROPY_PY_URE_SUB (CIRCUITPY_FULL_BUILD)
@@ -212,6 +220,9 @@ typedef long mp_off_t;
#define MP_SSIZE_MAX (0x7fffffff)
#endif
+#if INTERNAL_FLASH_FILESYSTEM == 0 && QSPI_FLASH_FILESYSTEM == 0 && SPI_FLASH_FILESYSTEM == 0 && !CIRCUITPY_MINIMAL_BUILD
+#error No *_FLASH_FILESYSTEM set!
+#endif
// These CIRCUITPY_xxx values should all be defined in the *.mk files as being on or off.
// So if any are not defined in *.mk, they'll throw an error here.
@@ -251,6 +262,13 @@ extern const struct _mp_obj_module_t audiomixer_module;
#define AUDIOMIXER_MODULE
#endif
+#if CIRCUITPY_AUDIOMP3
+#define AUDIOMP3_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiomp3), (mp_obj_t)&audiomp3_module },
+extern const struct _mp_obj_module_t audiomp3_module;
+#else
+#define AUDIOMP3_MODULE
+#endif
+
#if CIRCUITPY_AUDIOPWMIO
#define AUDIOPWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiopwmio), (mp_obj_t)&audiopwmio_module },
extern const struct _mp_obj_module_t audiopwmio_module;
@@ -314,7 +332,9 @@ extern const struct _mp_obj_module_t terminalio_module;
#define DISPLAYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_displayio), (mp_obj_t)&displayio_module },
#define FONTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_fontio), (mp_obj_t)&fontio_module },
#define TERMINALIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_terminalio), (mp_obj_t)&terminalio_module },
+#ifndef CIRCUITPY_DISPLAY_LIMIT
#define CIRCUITPY_DISPLAY_LIMIT (1)
+#endif
#else
#define DISPLAYIO_MODULE
#define FONTIO_MODULE
@@ -365,6 +385,13 @@ extern const struct _mp_obj_module_t math_module;
#define MATH_MODULE
#endif
+#if CIRCUITPY__EVE
+extern const struct _mp_obj_module_t _eve_module;
+#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module },
+#else
+#define _EVE_MODULE
+#endif
+
#if CIRCUITPY_MICROCONTROLLER
extern const struct _mp_obj_module_t microcontroller_module;
#define MICROCONTROLLER_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)&microcontroller_module },
@@ -581,6 +608,7 @@ extern const struct _mp_obj_module_t ustack_module;
AUDIOCORE_MODULE \
AUDIOIO_MODULE \
AUDIOMIXER_MODULE \
+ AUDIOMP3_MODULE \
AUDIOPWMIO_MODULE \
BITBANGIO_MODULE \
BLEIO_MODULE \
@@ -597,6 +625,7 @@ extern const struct _mp_obj_module_t ustack_module;
I2CSLAVE_MODULE \
JSON_MODULE \
MATH_MODULE \
+ _EVE_MODULE \
MICROCONTROLLER_MODULE \
NEOPIXEL_WRITE_MODULE \
NETWORK_MODULE \
@@ -652,17 +681,26 @@ extern const struct _mp_obj_module_t ustack_module;
FLASH_ROOT_POINTERS \
NETWORK_ROOT_POINTERS \
-void run_background_tasks(void);
-#define RUN_BACKGROUND_TASKS (run_background_tasks())
+void supervisor_run_background_tasks_if_tick(void);
+#define RUN_BACKGROUND_TASKS (supervisor_run_background_tasks_if_tick())
// TODO: Used in wiznet5k driver, but may not be needed in the long run.
#define MICROPY_THREAD_YIELD()
-#define MICROPY_VM_HOOK_LOOP run_background_tasks();
-#define MICROPY_VM_HOOK_RETURN run_background_tasks();
+#define MICROPY_VM_HOOK_LOOP RUN_BACKGROUND_TASKS;
+#define MICROPY_VM_HOOK_RETURN RUN_BACKGROUND_TASKS;
+// CIRCUITPY_AUTORELOAD_DELAY_MS = 0 will completely disable autoreload.
+#ifndef CIRCUITPY_AUTORELOAD_DELAY_MS
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
+#endif
+
+#ifndef CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS
#define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000
+#endif
+
#define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt"
+#define CIRCUITPY_VERBOSE_BLE 0
+
#endif // __INCLUDED_MPCONFIG_CIRCUITPY_H
diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk
index c1199571b..d6e033daf 100644
--- a/py/circuitpy_mpconfig.mk
+++ b/py/circuitpy_mpconfig.mk
@@ -23,7 +23,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-
# mpconfigboard.mk files can specify:
# CIRCUITPY_FULL_BUILD = 1 (which is the default)
# or
@@ -34,15 +33,19 @@
ifndef CIRCUITPY_FULL_BUILD
ifeq ($(CIRCUITPY_SMALL_BUILD),1)
CIRCUITPY_FULL_BUILD = 0
- CFLAGS += -DCIRCUITPY_FULL_BUILD=0
else
CIRCUITPY_FULL_BUILD = 1
- CFLAGS += -DCIRCUITPY_FULL_BUILD=1
endif
endif
+CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD)
# Setting CIRCUITPY_MINIMAL_BUILD = 1 will disable all features
# Use for for early stage or highly restricted ports
+ifndef CIRCUITPY_MINIMAL_BUILD
+CIRCUITPY_MINIMAL_BUILD = 0
+endif
+CFLAGS += -DCIRCUITPY_MINIMAL_BUILD=$(CIRCUITPY_MINIMAL_BUILD)
+
ifndef CIRCUITPY_DEFAULT_BUILD
ifeq ($(CIRCUITPY_MINIMAL_BUILD),1)
CIRCUITPY_FULL_BUILD = 0
@@ -51,12 +54,14 @@ ifndef CIRCUITPY_DEFAULT_BUILD
CIRCUITPY_DEFAULT_BUILD = 1
endif
endif
+CFLAGS += -DCIRCUITPY_DEFAULT_BUILD=$(CIRCUITPY_DEFAULT_BUILD)
# Some features have no unique HAL component, and thus there's never
-# a reason to not include them.
+# a reason to not include them.
ifndef CIRCUITPY_ALWAYS_BUILD
CIRCUITPY_ALWAYS_BUILD = 1
endif
+CFLAGS += -DCIRCUITPY_ALWAYS_BUILD=$(CIRCUITPY_ALWAYS_BUILD)
# All builtin modules are listed below, with default values (0 for off, 1 for on)
@@ -104,6 +109,15 @@ CIRCUITPY_AUDIOMIXER = $(CIRCUITPY_AUDIOIO)
endif
CFLAGS += -DCIRCUITPY_AUDIOMIXER=$(CIRCUITPY_AUDIOMIXER)
+ifndef CIRCUITPY_AUDIOMP3
+ifeq ($(CIRCUITPY_FULL_BUILD),1)
+CIRCUITPY_AUDIOMP3 = $(CIRCUITPY_AUDIOCORE)
+else
+CIRCUITPY_AUDIOMP3 = 0
+endif
+endif
+CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3)
+
ifndef CIRCUITPY_BITBANGIO
CIRCUITPY_BITBANGIO = $(CIRCUITPY_FULL_BUILD)
endif
@@ -160,6 +174,11 @@ CIRCUITPY_MATH = $(CIRCUITPY_ALWAYS_BUILD)
endif
CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH)
+ifndef CIRCUITPY__EVE
+CIRCUITPY__EVE = 0
+endif
+CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE)
+
ifndef CIRCUITPY_MICROCONTROLLER
CIRCUITPY_MICROCONTROLLER = $(CIRCUITPY_DEFAULT_BUILD)
endif
@@ -170,7 +189,7 @@ CIRCUITPY_NEOPIXEL_WRITE = $(CIRCUITPY_DEFAULT_BUILD)
endif
CFLAGS += -DCIRCUITPY_NEOPIXEL_WRITE=$(CIRCUITPY_NEOPIXEL_WRITE)
-# Only certain boards support NETWORK (Ethernet)
+# Enabled on SAMD51. Won't fit on SAMD21 builds. Not tested on nRF or STM32F4 builds.
ifndef CIRCUITPY_NETWORK
CIRCUITPY_NETWORK = 0
endif
@@ -289,12 +308,36 @@ CIRCUITPY_USTACK = 0
endif
CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK)
+# Non-module conditionals
ifndef CIRCUITPY_BITBANG_APA102
CIRCUITPY_BITBANG_APA102 = 0
endif
CFLAGS += -DCIRCUITPY_BITBANG_APA102=$(CIRCUITPY_BITBANG_APA102)
+# Should busio.I2C() check for pullups?
+# Some boards in combination with certain peripherals may not want this.
+ifndef CIRCUITPY_REQUIRE_I2C_PULLUPS
+CIRCUITPY_REQUIRE_I2C_PULLUPS = 1
+endif
+CFLAGS += -DCIRCUITPY_REQUIRE_I2C_PULLUPS=$(CIRCUITPY_REQUIRE_I2C_PULLUPS)
+
+# REPL over BLE
+ifndef CIRCUITPY_SERIAL_BLE
+CIRCUITPY_SERIAL_BLE = 0
+endif
+CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE)
+
+ifndef CIRCUITPY_BLE_FILE_SERVICE
+CIRCUITPY_BLE_FILE_SERVICE = 0
+endif
+CFLAGS += -DCIRCUITPY_BLE_FILE_SERVICE=$(CIRCUITPY_BLE_FILE_SERVICE)
+
+# REPL over UART
+ifndef CIRCUITPY_SERIAL_UART
+CIRCUITPY_SERIAL_UART = 0
+endif
+CFLAGS += -DCIRCUITPY_SERIAL_UART=$(CIRCUITPY_SERIAL_UART)
# Enabled micropython.native decorator (experimental)
ifndef CIRCUITPY_ENABLE_MPY_NATIVE
diff --git a/py/compile.c b/py/compile.c
index 8b17935bd..77715d3fe 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -775,13 +775,22 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_
qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
if (attr == MP_QSTR_bytecode) {
*emit_options = MP_EMIT_OPT_BYTECODE;
-#if MICROPY_EMIT_NATIVE
+ // @micropython.native decorator.
} else if (attr == MP_QSTR_native) {
+ // Different from MicroPython: native doesn't raise SyntaxError if native support isn't
+ // compiled, it just passes through the function unmodified.
+ #if MICROPY_EMIT_NATIVE
*emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
+ #else
+ return true;
+ #endif
+ #if MICROPY_EMIT_NATIVE
+ // @micropython.viper decorator.
} else if (attr == MP_QSTR_viper) {
*emit_options = MP_EMIT_OPT_VIPER;
-#endif
+ #endif
#if MICROPY_EMIT_INLINE_ASM
+ // @micropython.asm_thumb decorator.
} else if (attr == ASM_DECORATOR_QSTR) {
*emit_options = MP_EMIT_OPT_ASM;
#endif
diff --git a/py/emitnative.c b/py/emitnative.c
index 6d23bf097..60f31d15f 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -459,6 +459,7 @@ STATIC void emit_native_end_pass(emit_t *emit) {
type_sig |= (emit->local_vtype[i] & 0xf) << (i * 4 + 4);
}
+ #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
mp_emit_glue_assign_native(emit->scope->raw_code,
emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,
diff --git a/py/gc.c b/py/gc.c
index ac584d5d2..271bc9462 100755
--- a/py/gc.c
+++ b/py/gc.c
@@ -53,9 +53,6 @@
// detect untraced object still in use
#define CLEAR_ON_SWEEP (0)
-#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)
-#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
-
// ATB = allocation table byte
// 0b00 = FREE -- free block
// 0b01 = HEAD -- head of a chain of blocks
@@ -153,9 +150,13 @@ void gc_init(void *start, void *end) {
#endif
// Set first free ATB index to the start of the heap.
- MP_STATE_MEM(gc_first_free_atb_index) = 0;
+ for (size_t i = 0; i < MICROPY_ATB_INDICES; i++) {
+ MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
+ }
+
// Set last free ATB index to the end of the heap.
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
+
// Set the lowest long lived ptr to the end of the heap to start. This will be lowered as long
// lived objects are allocated.
MP_STATE_MEM(gc_lowest_long_lived_ptr) = (void*) PTR_FROM_BLOCK(MP_STATE_MEM(gc_alloc_table_byte_len * BLOCKS_PER_ATB));
@@ -209,13 +210,6 @@ bool gc_is_locked(void) {
return MP_STATE_MEM(gc_lock_depth) != 0;
}
-// ptr should be of type void*
-#define VERIFY_PTR(ptr) ( \
- ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
- && ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \
- && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \
- )
-
#ifndef TRACE_MARK
#if DEBUG_PRINT
#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr)
@@ -397,7 +391,9 @@ void gc_collect_root(void **ptrs, size_t len) {
void gc_collect_end(void) {
gc_deal_with_stack_overflow();
gc_sweep();
- MP_STATE_MEM(gc_first_free_atb_index) = 0;
+ for (size_t i = 0; i < MICROPY_ATB_INDICES; i++) {
+ MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
+ }
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
MP_STATE_MEM(gc_lock_depth)--;
GC_EXIT();
@@ -474,6 +470,10 @@ void gc_info(gc_info_t *info) {
GC_EXIT();
}
+bool gc_alloc_possible(void) {
+ return MP_STATE_MEM(gc_pool_start) != 0;
+}
+
// We place long lived objects at the end of the heap rather than the start. This reduces
// fragmentation by localizing the heap churn to one portion of memory (the start of the heap.)
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
@@ -519,14 +519,16 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
size_t crossover_block = BLOCK_FROM_PTR(MP_STATE_MEM(gc_lowest_long_lived_ptr));
while (keep_looking) {
int8_t direction = 1;
- size_t start = MP_STATE_MEM(gc_first_free_atb_index);
+ size_t bucket = MIN(n_blocks, MICROPY_ATB_INDICES) - 1;
+ size_t first_free = MP_STATE_MEM(gc_first_free_atb_index)[bucket];
+ size_t start = first_free;
if (long_lived) {
direction = -1;
start = MP_STATE_MEM(gc_last_free_atb_index);
}
n_free = 0;
// look for a run of n_blocks available blocks
- for (size_t i = start; keep_looking && MP_STATE_MEM(gc_first_free_atb_index) <= i && i <= MP_STATE_MEM(gc_last_free_atb_index); i += direction) {
+ for (size_t i = start; keep_looking && first_free <= i && i <= MP_STATE_MEM(gc_last_free_atb_index); i += direction) {
byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
// Four ATB states are packed into a single byte.
int j = 0;
@@ -571,22 +573,24 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
// Found free space ending at found_block inclusive.
// Also, set last free ATB index to block after last block we found, for start of
- // next scan. To reduce fragmentation, we only do this if we were looking
- // for a single free block, which guarantees that there are no free blocks
- // before this one. Also, whenever we free or shrink a block we must check
- // if this index needs adjusting (see gc_realloc and gc_free).
+ // next scan. Also, whenever we free or shrink a block we must check if this index needs
+ // adjusting (see gc_realloc and gc_free).
if (!long_lived) {
end_block = found_block;
start_block = found_block - n_free + 1;
- if (n_blocks == 1) {
- MP_STATE_MEM(gc_first_free_atb_index) = (found_block + 1) / BLOCKS_PER_ATB;
+ if (n_blocks < MICROPY_ATB_INDICES) {
+ size_t next_free_atb = (found_block + n_blocks) / BLOCKS_PER_ATB;
+ // Update all atb indices for larger blocks too.
+ for (size_t i = n_blocks - 1; i < MICROPY_ATB_INDICES; i++) {
+ MP_STATE_MEM(gc_first_free_atb_index)[i] = next_free_atb;
+ }
}
} else {
start_block = found_block;
end_block = found_block + n_free - 1;
- if (n_blocks == 1) {
- MP_STATE_MEM(gc_last_free_atb_index) = (found_block - 1) / BLOCKS_PER_ATB;
- }
+ // Always update the bounds of the long lived area because we assume it is contiguous. (It
+ // can still be reset by a sweep.)
+ MP_STATE_MEM(gc_last_free_atb_index) = (found_block - 1) / BLOCKS_PER_ATB;
}
#ifdef LOG_HEAP_ACTIVITY
@@ -677,32 +681,42 @@ void gc_free(void *ptr) {
if (ptr == NULL) {
GC_EXIT();
} else {
+ if (MP_STATE_MEM(gc_pool_start) == 0) {
+ reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
+ }
// get the GC block number corresponding to this pointer
assert(VERIFY_PTR(ptr));
- size_t block = BLOCK_FROM_PTR(ptr);
- assert(ATB_GET_KIND(block) == AT_HEAD);
+ size_t start_block = BLOCK_FROM_PTR(ptr);
+ assert(ATB_GET_KIND(start_block) == AT_HEAD);
#if MICROPY_ENABLE_FINALISER
- FTB_CLEAR(block);
+ FTB_CLEAR(start_block);
#endif
- // set the last_free pointer to this block if it's earlier in the heap
- if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_first_free_atb_index)) {
- MP_STATE_MEM(gc_first_free_atb_index) = block / BLOCKS_PER_ATB;
- }
- if (block / BLOCKS_PER_ATB > MP_STATE_MEM(gc_last_free_atb_index)) {
- MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB;
- }
-
// free head and all of its tail blocks
- #ifdef LOG_HEAP_ACTIVITY
- gc_log_change(block, 0);
- #endif
+ #ifdef LOG_HEAP_ACTIVITY
+ gc_log_change(start_block, 0);
+ #endif
+ size_t block = start_block;
do {
ATB_ANY_TO_FREE(block);
block += 1;
} while (ATB_GET_KIND(block) == AT_TAIL);
+ // Update the first free pointer for our size only. Not much calls gc_free directly so there
+ // is decent chance we'll want to allocate this size again. By only updating the specific
+ // size we don't risk something smaller fitting in.
+ size_t n_blocks = block - start_block;
+ size_t bucket = MIN(n_blocks, MICROPY_ATB_INDICES) - 1;
+ size_t new_free_atb = start_block / BLOCKS_PER_ATB;
+ if (new_free_atb < MP_STATE_MEM(gc_first_free_atb_index)[bucket]) {
+ MP_STATE_MEM(gc_first_free_atb_index)[bucket] = new_free_atb;
+ }
+ // set the last_free pointer to this block if it's earlier in the heap
+ if (new_free_atb > MP_STATE_MEM(gc_last_free_atb_index)) {
+ MP_STATE_MEM(gc_last_free_atb_index) = new_free_atb;
+ }
+
GC_EXIT();
#if EXTENSIVE_HEAP_PROFILING
@@ -873,11 +887,13 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
}
// set the last_free pointer to end of this block if it's earlier in the heap
- if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_first_free_atb_index)) {
- MP_STATE_MEM(gc_first_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
+ size_t new_free_atb = (block + new_blocks) / BLOCKS_PER_ATB;
+ size_t bucket = MIN(n_blocks - new_blocks, MICROPY_ATB_INDICES) - 1;
+ if (new_free_atb < MP_STATE_MEM(gc_first_free_atb_index)[bucket]) {
+ MP_STATE_MEM(gc_first_free_atb_index)[bucket] = new_free_atb;
}
- if ((block + new_blocks) / BLOCKS_PER_ATB > MP_STATE_MEM(gc_last_free_atb_index)) {
- MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
+ if (new_free_atb > MP_STATE_MEM(gc_last_free_atb_index)) {
+ MP_STATE_MEM(gc_last_free_atb_index) = new_free_atb;
}
GC_EXIT();
diff --git a/py/gc.h b/py/gc.h
index 02bf45158..2a0811f4e 100644
--- a/py/gc.h
+++ b/py/gc.h
@@ -29,8 +29,19 @@
#include <stdint.h>
#include "py/mpconfig.h"
+#include "py/mpstate.h"
#include "py/misc.h"
+#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)
+#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
+
+// ptr should be of type void*
+#define VERIFY_PTR(ptr) ( \
+ ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
+ && ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \
+ && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \
+ )
+
void gc_init(void *start, void *end);
void gc_deinit(void);
@@ -47,6 +58,8 @@ void gc_collect_ptr(void *ptr);
void gc_collect_root(void **ptrs, size_t len);
void gc_collect_end(void);
+// Is the gc heap available?
+bool gc_alloc_possible(void);
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived);
// Use this function to sweep the whole heap and run all finalisers
diff --git a/py/gc_long_lived.c b/py/gc_long_lived.c
index 49bf1fcd7..01c22a7af 100755
--- a/py/gc_long_lived.c
+++ b/py/gc_long_lived.c
@@ -126,6 +126,11 @@ mp_obj_t make_obj_long_lived(mp_obj_t obj, uint8_t max_depth){
if (obj == NULL) {
return obj;
}
+ // If not in the GC pool, do nothing. This can happen (at least) when
+ // there are frozen mp_type_bytes objects in ROM.
+ if (!VERIFY_PTR((void *)obj)) {
+ return obj;
+ }
if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_bc)) {
mp_obj_fun_bc_t *fun_bc = MP_OBJ_TO_PTR(obj);
return MP_OBJ_FROM_PTR(make_fun_bc_long_lived(fun_bc, max_depth));
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 8e3835d86..0d667959d 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -103,14 +103,10 @@ def compute_huffman_coding(translations, qstrs, compression_filename):
# go through each qstr and print it out
for _, _, qstr in qstrs.values():
all_strings.append(qstr)
- all_strings_concat = "".join(all_strings).encode("utf-8")
+ all_strings_concat = "".join(all_strings)
counts = collections.Counter(all_strings_concat)
- # add other values
- for i in range(256):
- if i not in counts:
- counts[i] = 0
cb = huffman.codebook(counts.items())
- values = bytearray()
+ values = []
length_count = {}
renumbered = 0
last_l = None
@@ -124,26 +120,27 @@ def compute_huffman_coding(translations, qstrs, compression_filename):
if last_l:
renumbered <<= (l - last_l)
canonical[ch] = '{0:0{width}b}'.format(renumbered, width=l)
- if chr(ch) in C_ESCAPES:
- s = C_ESCAPES[chr(ch)]
- else:
- s = chr(ch)
- print("//", ch, s, counts[ch], canonical[ch], renumbered)
+ s = C_ESCAPES.get(ch, ch)
+ print("//", ord(ch), s, counts[ch], canonical[ch], renumbered)
renumbered += 1
last_l = l
lengths = bytearray()
- for i in range(1, max(length_count) + 1):
+ print("// length count", length_count)
+ for i in range(1, max(length_count) + 2):
lengths.append(length_count.get(i, 0))
+ print("// values", values, "lengths", len(lengths), lengths)
+ print("// estimated total memory size", len(lengths) + 2*len(values) + sum(len(cb[u]) for u in all_strings_concat))
print("//", values, lengths)
+ values_type = "uint16_t" if max(ord(u) for u in values) > 255 else "uint8_t"
with open(compression_filename, "w") as f:
f.write("const uint8_t lengths[] = {{ {} }};\n".format(", ".join(map(str, lengths))))
- f.write("const uint8_t values[256] = {{ {} }};\n".format(", ".join(map(str, values))))
+ f.write("const {} values[] = {{ {} }};\n".format(values_type, ", ".join(str(ord(u)) for u in values)))
return values, lengths
def decompress(encoding_table, length, encoded):
values, lengths = encoding_table
#print(l, encoded)
- dec = bytearray(length)
+ dec = []
this_byte = 0
this_bit = 7
b = encoded[this_byte]
@@ -173,14 +170,14 @@ def decompress(encoding_table, length, encoded):
searched_length += lengths[bit_length]
v = values[searched_length + bits - max_code]
- dec[i] = v
- return dec
+ dec.append(v)
+ return ''.join(dec)
def compress(encoding_table, decompressed):
- if not isinstance(decompressed, bytes):
+ if not isinstance(decompressed, str):
raise TypeError()
values, lengths = encoding_table
- enc = bytearray(len(decompressed) * 2)
+ enc = bytearray(len(decompressed) * 3)
#print(decompressed)
#print(lengths)
current_bit = 7
@@ -228,7 +225,7 @@ def compress(encoding_table, decompressed):
if current_bit != 7:
current_byte += 1
if current_byte > len(decompressed):
- print("Note: compression increased length", repr(decompressed.decode('utf-8')), len(decompressed), current_byte, file=sys.stderr)
+ print("Note: compression increased length", repr(decompressed), len(decompressed), current_byte, file=sys.stderr)
return enc[:current_byte]
def qstr_escape(qst):
@@ -347,9 +344,9 @@ def print_qstr_data(encoding_table, qcfgs, qstrs, i18ns):
total_text_compressed_size = 0
for original, translation in i18ns:
translation_encoded = translation.encode("utf-8")
- compressed = compress(encoding_table, translation_encoded)
+ compressed = compress(encoding_table, translation)
total_text_compressed_size += len(compressed)
- decompressed = decompress(encoding_table, len(translation_encoded), compressed).decode("utf-8")
+ decompressed = decompress(encoding_table, len(translation_encoded), compressed)
for c in C_ESCAPES:
decompressed = decompressed.replace(c, C_ESCAPES[c])
print("TRANSLATION(\"{}\", {}, {{ {} }}) // {}".format(original, len(translation_encoded)+1, ", ".join(["0x{:02x}".format(x) for x in compressed]), decompressed))
diff --git a/py/map.c b/py/map.c
index 6abf4853f..57c11dbc9 100644
--- a/py/map.c
+++ b/py/map.c
@@ -33,6 +33,8 @@
#include "py/misc.h"
#include "py/runtime.h"
+#include "supervisor/linker.h"
+
#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
#else // don't print debugging info
@@ -143,7 +145,7 @@ 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 *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) {
+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) {
// 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);
diff --git a/py/modio.c b/py/modio.c
index d7c1a58a8..17840a6d8 100644
--- a/py/modio.c
+++ b/py/modio.c
@@ -90,6 +90,7 @@ STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, in
}
STATIC const mp_stream_p_t iobase_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.read = iobase_read,
.write = iobase_write,
.ioctl = iobase_ioctl,
@@ -185,6 +186,7 @@ STATIC const mp_rom_map_elem_t bufwriter_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(bufwriter_locals_dict, bufwriter_locals_dict_table);
STATIC const mp_stream_p_t bufwriter_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.write = bufwriter_write,
};
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 3ec383817..1512c7d3a 100755
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -244,6 +244,14 @@
#define alloca(x) m_malloc(x)
#endif
+// Number of atb indices to cache. Allocations of fewer blocks will be faster
+// because the search will be accelerated by the index cache. This only applies
+// to short lived allocations because we assume the long lived allocations are
+// contiguous.
+#ifndef MICROPY_ATB_INDICES
+#define MICROPY_ATB_INDICES (8)
+#endif
+
/*****************************************************************************/
/* MicroPython emitters */
@@ -1440,6 +1448,15 @@ typedef double mp_float_t;
#define MP_UNLIKELY(x) __builtin_expect((x), 0)
#endif
+// To annotate that code is unreachable
+#ifndef MP_UNREACHABLE
+#if defined(__GNUC__)
+#define MP_UNREACHABLE __builtin_unreachable();
+#else
+#define MP_UNREACHABLE for (;;);
+#endif
+#endif
+
#ifndef MP_HTOBE16
#if MP_ENDIANNESS_LITTLE
# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) ))
diff --git a/py/mpstate.c b/py/mpstate.c
index 6ce64adfd..32f1d60a5 100644
--- a/py/mpstate.c
+++ b/py/mpstate.c
@@ -25,9 +25,10 @@
*/
#include "py/mpstate.h"
+#include "supervisor/linker.h"
#if MICROPY_DYNAMIC_COMPILER
mp_dynamic_compiler_t mp_dynamic_compiler = {0};
#endif
-mp_state_ctx_t mp_state_ctx;
+mp_state_ctx_t PLACE_IN_DTCM_BSS(mp_state_ctx);
diff --git a/py/mpstate.h b/py/mpstate.h
index a3d7e5dcc..a5815776a 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -92,7 +92,7 @@ typedef struct _mp_state_mem_t {
size_t gc_alloc_threshold;
#endif
- size_t gc_first_free_atb_index;
+ size_t gc_first_free_atb_index[MICROPY_ATB_INDICES];
size_t gc_last_free_atb_index;
#if MICROPY_PY_GC_COLLECT_RETVAL
diff --git a/py/nlr.h b/py/nlr.h
index b442aaf8a..1b95002d3 100644
--- a/py/nlr.h
+++ b/py/nlr.h
@@ -54,7 +54,14 @@
#endif
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
#define MICROPY_NLR_THUMB (1)
- #define MICROPY_NLR_NUM_REGS (10)
+ #if defined(__SOFTFP__)
+ #define MICROPY_NLR_NUM_REGS (10)
+ #else
+ // With hardware FP registers s16-s31 are callee save so in principle
+ // should be saved and restored by the NLR code. gcc only uses s16-s21
+ // so only save/restore those as an optimisation.
+ #define MICROPY_NLR_NUM_REGS (10 + 6)
+ #endif
#elif defined(__xtensa__)
#define MICROPY_NLR_XTENSA (1)
#define MICROPY_NLR_NUM_REGS (10)
diff --git a/py/nlrthumb.c b/py/nlrthumb.c
index 69d3f868a..056aa358e 100644
--- a/py/nlrthumb.c
+++ b/py/nlrthumb.c
@@ -63,6 +63,11 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
"str r10, [r0, #36] \n" // store r10 into nlr_buf
"str r11, [r0, #40] \n" // store r11 into nlr_buf
"str r13, [r0, #44] \n" // store r13=sp into nlr_buf
+ #if MICROPY_NLR_NUM_REGS == 16
+ "vstr d8, [r0, #48] \n" // store s16-s17 into nlr_buf
+ "vstr d9, [r0, #56] \n" // store s18-s19 into nlr_buf
+ "vstr d10, [r0, #64] \n" // store s20-s21 into nlr_buf
+ #endif
"str lr, [r0, #8] \n" // store lr into nlr_buf
#endif
@@ -118,6 +123,11 @@ NORETURN void nlr_jump(void *val) {
"ldr r10, [r0, #36] \n" // load r10 from nlr_buf
"ldr r11, [r0, #40] \n" // load r11 from nlr_buf
"ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf
+ #if MICROPY_NLR_NUM_REGS == 16
+ "vldr d8, [r0, #48] \n" // load s16-s17 from nlr_buf
+ "vldr d9, [r0, #56] \n" // load s18-s19 from nlr_buf
+ "vldr d10, [r0, #64] \n" // load s20-s21 from nlr_buf
+ #endif
"ldr lr, [r0, #8] \n" // load lr from nlr_buf
#endif
"movs r0, #1 \n" // return 1, non-local return
@@ -127,11 +137,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- #if defined(__GNUC__)
- __builtin_unreachable();
- #else
- for (;;); // needed to silence compiler warning
- #endif
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_THUMB
diff --git a/py/nlrx64.c b/py/nlrx64.c
index 9b2b22c22..569ad84fb 100644
--- a/py/nlrx64.c
+++ b/py/nlrx64.c
@@ -108,7 +108,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- for (;;); // needed to silence compiler warning
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_X64
diff --git a/py/nlrx86.c b/py/nlrx86.c
index 4900a4c0d..6fbbe4432 100644
--- a/py/nlrx86.c
+++ b/py/nlrx86.c
@@ -100,7 +100,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- for (;;); // needed to silence compiler warning
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_X86
diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c
index d66c7a9a7..564035004 100644
--- a/py/nlrxtensa.c
+++ b/py/nlrxtensa.c
@@ -77,7 +77,7 @@ NORETURN void nlr_jump(void *val) {
: // clobbered registers
);
- for (;;); // needed to silence compiler warning
+ MP_UNREACHABLE
}
#endif // MICROPY_NLR_XTENSA
diff --git a/py/obj.c b/py/obj.c
index bd2aaf9d2..f1e00de1a 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -38,6 +38,7 @@
#include "py/stackctrl.h"
#include "py/stream.h" // for mp_obj_print
+#include "supervisor/linker.h"
#include "supervisor/shared/stack.h"
#include "supervisor/shared/translate.h"
@@ -128,7 +129,7 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
mp_print_str(print, "\n");
}
-bool mp_obj_is_true(mp_obj_t arg) {
+bool PLACE_IN_ITCM(mp_obj_is_true)(mp_obj_t arg) {
if (arg == mp_const_false) {
return 0;
} else if (arg == mp_const_true) {
@@ -489,6 +490,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
mp_obj_type_t *type = mp_obj_get_type(base);
+
if (type->subscr != NULL) {
mp_obj_t ret = type->subscr(base, index, value);
// May have called port specific C code. Make sure it didn't mess up the heap.
@@ -496,7 +498,6 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
if (ret != MP_OBJ_NULL) {
return ret;
}
- // TODO: call base classes here?
}
if (value == MP_OBJ_NULL) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
diff --git a/py/objdict.c b/py/objdict.c
index 683fcb748..3ec3cbe80 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -31,6 +31,7 @@
#include "py/builtin.h"
#include "py/objtype.h"
+#include "supervisor/linker.h"
#include "supervisor/shared/translate.h"
#define MP_OBJ_IS_DICT_TYPE(o) (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new)
@@ -324,7 +325,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
-STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+STATIC mp_obj_t PLACE_IN_ITCM(dict_update)(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
mp_ensure_not_fixed(self);
@@ -590,7 +591,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
return self->map.used;
}
-mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
+mp_obj_t PLACE_IN_ITCM(mp_obj_dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_ensure_not_fixed(self);
diff --git a/py/objexcept.c b/py/objexcept.c
index c33ada0d6..b7a536c5e 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -112,17 +112,23 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
if (o->args == NULL || o->args->len == 0) {
mp_print_str(print, "");
return;
- } else if (o->args->len == 1) {
+ }
+ if (MP_OBJ_IS_SMALL_INT(o->args->items[0]) &&
+ mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(o->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError)) &&
+ o->args->len <= 2) {
// try to provide a nice OSError error message
- if (MP_OBJ_IS_SMALL_INT(o->args->items[0]) &&
- mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(o->base.type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
- char decompressed[50];
- const char *msg = mp_common_errno_to_str(o->args->items[0], decompressed, sizeof(decompressed));
- if (msg != NULL) {
- mp_printf(print, "[Errno " INT_FMT "] %s", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), msg);
- return;
+ char decompressed[50];
+ const char *msg = mp_common_errno_to_str(o->args->items[0], decompressed, sizeof(decompressed));
+ if (msg != NULL) {
+ mp_printf(print, "[Errno " INT_FMT "] %s", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), msg);
+ // if second arg exists, it is filename.
+ if (o->args->len == 2) {
+ mp_printf(print, ": '%s'", mp_obj_str_get_str(o->args->items[1]));
}
+ return;
}
+ }
+ if (o->args->len == 1) {
mp_obj_print_helper(print, o->args->items[0], PRINT_STR);
return;
}
diff --git a/py/objfun.c b/py/objfun.c
index 7e5899456..c586a290a 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -34,6 +34,8 @@
#include "py/bc.h"
#include "py/stackctrl.h"
+#include "supervisor/linker.h"
+
#if MICROPY_DEBUG_VERBOSE // print debugging info
#define DEBUG_PRINT (1)
#else // don't print debugging info
@@ -249,7 +251,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args
}
#endif
-STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t PLACE_IN_ITCM(fun_bc_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
MP_STACK_CHECK();
DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw);
diff --git a/py/objint.c b/py/objint.c
index 9e11871f1..b78c9f25b 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -490,15 +490,24 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes);
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj));
-STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
- // TODO: Support signed param (assumes signed=False)
- (void)n_args;
-
- mp_int_t len = mp_obj_get_int(args[1]);
+STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_length, ARG_byteorder, ARG_signed };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_byteorder, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t len = args[ARG_length].u_int;
if (len < 0) {
mp_raise_ValueError(NULL);
}
- bool big_endian = args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little);
+
+ mp_obj_t self = pos_args[0];
+ bool big_endian = args[ARG_byteorder].u_obj != MP_OBJ_NEW_QSTR(MP_QSTR_little);
+ bool signed_ = args[ARG_signed].u_bool;
vstr_t vstr;
vstr_init_len(&vstr, len);
@@ -506,22 +515,26 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
memset(data, 0, len);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
- if (!MP_OBJ_IS_SMALL_INT(args[0])) {
- mp_obj_int_buffer_overflow_check(args[0], len, false);
- mp_obj_int_to_bytes_impl(args[0], big_endian, len, data);
+ if (!MP_OBJ_IS_SMALL_INT(self)) {
+ mp_obj_int_buffer_overflow_check(self, len, signed_);
+ mp_obj_int_to_bytes_impl(self, big_endian, len, data);
} else
#endif
{
- mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]);
+ mp_int_t val = MP_OBJ_SMALL_INT_VALUE(self);
// Small int checking is separate, to be fast.
- mp_small_int_buffer_overflow_check(val, len, false);
+ mp_small_int_buffer_overflow_check(val, len, signed_);
size_t l = MIN((size_t)len, sizeof(val));
+ if (val < 0) {
+ // Sign extend negative numbers.
+ memset(data, -1, len);
+ }
mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val);
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 3, 4, int_to_bytes);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(int_to_bytes_obj, 3, int_to_bytes);
STATIC const mp_rom_map_elem_t int_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) },
diff --git a/py/objlist.c b/py/objlist.c
index ea38e64e5..608ea9f6c 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -93,7 +93,7 @@ STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, const
}
STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
switch (op) {
case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
@@ -108,7 +108,7 @@ STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
- mp_obj_list_t *o = MP_OBJ_TO_PTR(lhs);
+ mp_obj_list_t *o = mp_instance_cast_to_native_base(lhs, &mp_type_list);
switch (op) {
case MP_BINARY_OP_ADD: {
if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) {
@@ -159,11 +159,11 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
}
STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
if (value == MP_OBJ_NULL) {
// delete
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
mp_raise_NotImplementedError(NULL);
@@ -179,12 +179,11 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
return mp_const_none;
}
#endif
- mp_obj_t args[2] = {self_in, index};
+ mp_obj_t args[2] = {self, index};
list_pop(2, args);
return mp_const_none;
} else if (value == MP_OBJ_SENTINEL) {
// load
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
@@ -201,7 +200,6 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
} else {
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
size_t value_len; mp_obj_t *value_items;
mp_obj_get_array(value, &value_len, &value_items);
mp_bound_slice_t slice_out;
@@ -230,7 +228,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
return mp_const_none;
}
#endif
- mp_obj_list_store(self_in, index, value);
+ mp_obj_list_store(self, index, value);
return mp_const_none;
}
}
@@ -241,7 +239,7 @@ STATIC mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
if (self->len >= self->alloc) {
self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2);
self->alloc *= 2;
@@ -254,8 +252,8 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
- mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
+ mp_obj_list_t *arg = mp_instance_cast_to_native_base(arg_in, &mp_type_list);
if (self->len + arg->len > self->alloc) {
// TODO: use alloc policy for "4"
@@ -274,7 +272,7 @@ STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) {
STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) {
mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(args[0], &mp_type_list);
if (self->len == 0) {
mp_raise_IndexError(translate("pop from empty list"));
}
@@ -334,7 +332,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(pos_args[0], &mp_type_list);
if (self->len > 1) {
mp_quicksort(self->items, self->items + self->len - 1,
@@ -347,7 +345,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
mp_obj_t mp_obj_list_clear(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
self->len = 0;
self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC);
self->alloc = LIST_MIN_ALLOC;
@@ -357,25 +355,25 @@ mp_obj_t mp_obj_list_clear(mp_obj_t self_in) {
STATIC mp_obj_t list_copy(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
return mp_obj_new_list(self->len, self->items);
}
STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
return mp_seq_count_obj(self->items, self->len, value);
}
STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) {
mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(args[0], &mp_type_list);
return mp_seq_index_obj(self->items, self->len, n_args, args);
}
STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
// insert has its own strange index logic
mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx);
if (index < 0) {
@@ -409,7 +407,7 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) {
STATIC mp_obj_t list_reverse(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list));
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
mp_int_t len = self->len;
for (mp_int_t i = 0; i < len/2; i++) {
@@ -486,7 +484,7 @@ mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) {
}
void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
*len = self->len;
*items = self->items;
}
@@ -499,7 +497,7 @@ void mp_obj_list_set_len(mp_obj_t self_in, size_t len) {
}
void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
- mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_list_t *self = mp_instance_cast_to_native_base(self_in, &mp_type_list);
size_t i = mp_get_index(self->base.type, self->len, index, false);
self->items[i] = value;
}
diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c
index a044fe3ff..84dcf7909 100644
--- a/py/objnamedtuple.c
+++ b/py/objnamedtuple.c
@@ -31,6 +31,7 @@
#include "py/runtime.h"
#include "py/objstr.h"
#include "py/objnamedtuple.h"
+#include "py/objtype.h"
#include "supervisor/shared/translate.h"
diff --git a/py/objstr.c b/py/objstr.c
index fde264681..a60f507e9 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -1352,7 +1352,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
terse_str_format_value_error();
} else {
mp_raise_ValueError_varg(
- translate("unknown format code '%c' for object of type 'float'"),
+ translate("unknown format code '%c' for object of type '%s'"),
type, mp_obj_get_type_str(arg));
}
}
@@ -1388,7 +1388,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
terse_str_format_value_error();
} else {
mp_raise_ValueError_varg(
- translate("unknown format code '%c' for object of type 'str'"),
+ translate("unknown format code '%c' for object of type '%s'"),
type, mp_obj_get_type_str(arg));
}
}
diff --git a/py/objstringio.c b/py/objstringio.c
index d2ca6decd..178e6446c 100644
--- a/py/objstringio.c
+++ b/py/objstringio.c
@@ -240,6 +240,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
STATIC const mp_stream_p_t stringio_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.read = stringio_read,
.write = stringio_write,
.ioctl = stringio_ioctl,
@@ -247,6 +248,7 @@ STATIC const mp_stream_p_t stringio_stream_p = {
};
STATIC const mp_stream_p_t bytesio_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
.read = stringio_read,
.write = stringio_write,
.ioctl = stringio_ioctl,
diff --git a/py/objtuple.c b/py/objtuple.c
index ed13cdcef..0a2ed6f4c 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -29,6 +29,7 @@
#include "py/objtuple.h"
#include "py/runtime.h"
+#include "py/objtype.h"
#include "supervisor/shared/translate.h"
@@ -181,6 +182,11 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) {
// load
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);
+ // when called with a native type (eg namedtuple) using mp_obj_tuple_subscr, get the native self
+ if (self->base.type->subscr != &mp_obj_tuple_subscr) {
+ self = mp_instance_cast_to_native_base(self_in, &mp_type_tuple);
+ }
+
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
diff --git a/py/objtype.c b/py/objtype.c
index 0212a78da..ad68b85d2 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -34,6 +34,7 @@
#include "py/objtype.h"
#include "py/runtime.h"
+#include "supervisor/shared/stack.h"
#include "supervisor/shared/translate.h"
#if MICROPY_DEBUG_VERBOSE // print debugging info
@@ -186,14 +187,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
return;
} else {
mp_obj_instance_t *obj = lookup->obj;
- mp_obj_t obj_obj;
- if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object is not a real type */) {
- // If we're dealing with native base class, then it applies to native sub-object
- obj_obj = obj->subobj[0];
- } else {
- obj_obj = MP_OBJ_FROM_PTR(obj);
- }
- mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest);
+ mp_convert_member_lookup(MP_OBJ_FROM_PTR(obj), type, elem->value, lookup->dest);
}
#if DEBUG_PRINT
printf("mp_obj_class_lookup: Returning: ");
@@ -851,8 +845,13 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 3;
}
- if (member[0] == MP_OBJ_SENTINEL) {
- return mp_obj_subscr(self->subobj[0], index, value);
+ if (member[0] == MP_OBJ_SENTINEL) { // native base subscr exists
+ mp_obj_type_t *subobj_type = mp_obj_get_type(self->subobj[0]);
+ // return mp_obj_subscr(self->subobj[0], index, value, instance);
+ mp_obj_t ret = subobj_type->subscr(self_in, index, value);
+ // May have called port specific C code. Make sure it didn't mess up the heap.
+ assert_heap_ok();
+ return ret;
} else if (member[0] != MP_OBJ_NULL) {
mp_obj_t args[3] = {self_in, index, value};
// TODO probably need to call mp_convert_member_lookup, and use mp_call_method_n_kw
diff --git a/py/proto.c b/py/proto.c
new file mode 100644
index 000000000..e5053130b
--- /dev/null
+++ b/py/proto.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * 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/obj.h"
+#include "py/proto.h"
+#include "py/runtime.h"
+
+#ifndef MICROPY_UNSAFE_PROTO
+const void *mp_proto_get(uint16_t name, mp_const_obj_t obj) {
+ mp_obj_type_t *type = mp_obj_get_type(obj);
+ if (!type->protocol) return NULL;
+ uint16_t proto_name = *(const uint16_t*) type->protocol;
+ if (proto_name == name) {
+ return type->protocol;
+ }
+ return NULL;
+}
+#endif
+
+const void *mp_proto_get_or_throw(uint16_t name, mp_const_obj_t obj) {
+ const void *proto = mp_proto_get(name, obj);
+ if (proto) {
+ return proto;
+ }
+ mp_raise_TypeError_varg(translate("'%s' object does not support '%q'"),
+ mp_obj_get_type_str(obj), name);
+}
diff --git a/py/proto.h b/py/proto.h
new file mode 100644
index 000000000..2d4f80565
--- /dev/null
+++ b/py/proto.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_PY_PROTO_H
+#define MICROPY_INCLUDED_PY_PROTO_H
+
+#ifdef MICROPY_UNSAFE_PROTO
+#define MP_PROTOCOL_HEAD /* NOTHING */
+#define MP_PROTO_IMPLEMENT(name) /* NOTHING */
+static inline void *mp_proto_get(uint16_t name, mp_const_obj_type_t obj) { return mp_obj_get_type(obj)->protocol; }
+#else
+#define MP_PROTOCOL_HEAD \
+ uint16_t name; // The name of this protocol, a qstr
+#define MP_PROTO_IMPLEMENT(n) .name = n,
+const void *mp_proto_get(uint16_t name, mp_const_obj_t obj);
+const void *mp_proto_get_or_throw(uint16_t name, mp_const_obj_t obj);
+#endif
+
+#endif
+
diff --git a/py/py.mk b/py/py.mk
index 17cb79264..a73b47f37 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -214,6 +214,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\
objtype.o \
objzip.o \
opmethods.o \
+ proto.o \
reload.o \
sequence.o \
stream.o \
@@ -303,12 +304,12 @@ FORCE:
$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)
$(STEPECHO) "GEN $@"
- $(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $@
+ $(Q)$(PYTHON3) $(PY_SRC)/makeversionhdr.py $@
# build a list of registered modules for py/objmodule.c.
$(HEADER_BUILD)/moduledefs.h: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h
- @$(ECHO) "GEN $@"
- $(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py --vpath="., $(TOP), $(USER_C_MODULES)" $(SRC_QSTR) > $@
+ @$(STEPECHO) "GEN $@"
+ $(Q)$(PYTHON3) $(PY_SRC)/makemoduledefs.py --vpath="., $(TOP), $(USER_C_MODULES)" $(SRC_QSTR) > $@
SRC_QSTR += $(HEADER_BUILD)/moduledefs.h
@@ -316,7 +317,7 @@ SRC_QSTR += $(HEADER_BUILD)/moduledefs.h
# overall config, so they need to be caught
MPCONFIGPORT_MK = $(wildcard mpconfigport.mk)
-$(HEADER_BUILD)/$(TRANSLATION).mo: $(TOP)/locale/$(TRANSLATION).po
+$(HEADER_BUILD)/$(TRANSLATION).mo: $(TOP)/locale/$(TRANSLATION).po | $(HEADER_BUILD)
$(Q)msgfmt -o $@ $^
$(HEADER_BUILD)/qstrdefs.preprocessed.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD)
diff --git a/py/qstr.c b/py/qstr.c
index eea57c1e0..bb8024435 100755
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -33,6 +33,8 @@
#include "py/qstr.h"
#include "py/gc.h"
+#include "supervisor/linker.h"
+
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
// ultimately we will replace this with a static hash table of some kind
// also probably need to include the length in the string data, to allow null bytes in the string
@@ -248,7 +250,7 @@ qstr qstr_from_strn(const char *str, size_t len) {
return q;
}
-mp_uint_t qstr_hash(qstr q) {
+mp_uint_t PLACE_IN_ITCM(qstr_hash)(qstr q) {
return Q_GET_HASH(find_qstr(q));
}
diff --git a/py/runtime.c b/py/runtime.c
index a786619bf..c1c311ae4 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -29,10 +29,12 @@
#include <string.h>
#include <assert.h>
+
#include "extmod/vfs.h"
#include "py/parsenum.h"
#include "py/compile.h"
+#include "py/mperrno.h"
#include "py/objstr.h"
#include "py/objtuple.h"
#include "py/objtype.h"
@@ -200,7 +202,7 @@ mp_obj_t mp_load_build_class(void) {
return MP_OBJ_FROM_PTR(&mp_builtin___build_class___obj);
}
-void mp_store_name(qstr qst, mp_obj_t obj) {
+void PLACE_IN_ITCM(mp_store_name)(qstr qst, mp_obj_t obj) {
DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qst), obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj);
}
@@ -211,7 +213,7 @@ void mp_delete_name(qstr qst) {
mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst));
}
-void mp_store_global(qstr qst, mp_obj_t obj) {
+void PLACE_IN_ITCM(mp_store_global)(qstr qst, mp_obj_t obj) {
DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qst), obj);
mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj);
}
@@ -283,7 +285,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
}
}
-mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
+mp_obj_t PLACE_IN_ITCM(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
@@ -641,7 +643,7 @@ mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args) {
#if !MICROPY_STACKLESS
STATIC
#endif
-void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) {
+void PLACE_IN_ITCM(mp_call_prepare_args_n_kw_var)(bool have_self, size_t n_args_n_kw, const mp_obj_t *args, mp_call_args_t *out_args) {
mp_obj_t fun = *args++;
mp_obj_t self = MP_OBJ_NULL;
if (have_self) {
@@ -1576,6 +1578,14 @@ NORETURN void mp_raise_OSError_msg(const compressed_string_t *msg) {
mp_raise_msg(&mp_type_OSError, msg);
}
+NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) {
+ mp_obj_t args[2] = {
+ MP_OBJ_NEW_SMALL_INT(errno_),
+ str,
+ };
+ nlr_raise(mp_obj_new_exception_args(&mp_type_OSError, 2, args));
+}
+
NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...) {
va_list argptr;
va_start(argptr,fmt);
diff --git a/py/runtime.h b/py/runtime.h
index e8398cf0e..f81103557 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -29,6 +29,8 @@
#include "py/mpstate.h"
#include "py/pystack.h"
+#include "supervisor/linker.h"
+
typedef enum {
MP_VM_RETURN_NORMAL,
MP_VM_RETURN_YIELD,
@@ -84,10 +86,10 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args,
NORETURN void mp_arg_error_terse_mismatch(void);
NORETURN void mp_arg_error_unimpl_kw(void);
-static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_THREAD(dict_locals); }
-static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; }
-static inline mp_obj_dict_t *mp_globals_get(void) { return MP_STATE_THREAD(dict_globals); }
-static inline void mp_globals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; }
+static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_locals_get)(void) { return MP_STATE_THREAD(dict_locals); }
+static inline void PLACE_IN_ITCM(mp_locals_set)(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; }
+static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_globals_get)(void) { return MP_STATE_THREAD(dict_globals); }
+static inline void PLACE_IN_ITCM(mp_globals_set)(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; }
mp_obj_t mp_load_name(qstr qst);
mp_obj_t mp_load_global(qstr qst);
@@ -159,6 +161,7 @@ NORETURN void mp_raise_RuntimeError(const compressed_string_t *msg);
NORETURN void mp_raise_ImportError(const compressed_string_t *msg);
NORETURN void mp_raise_IndexError(const compressed_string_t *msg);
NORETURN void mp_raise_OSError(int errno_);
+NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str);
NORETURN void mp_raise_OSError_msg(const compressed_string_t *msg);
NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...);
NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg);
diff --git a/py/sequence.c b/py/sequence.c
index a750e5bac..0e668ea2a 100644
--- a/py/sequence.c
+++ b/py/sequence.c
@@ -34,6 +34,11 @@
#define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; }
+#if __GNUC__ < 5
+// n.b. does not actually detect overflow!
+#define __builtin_mul_overflow(a, b, x) (*(x) = (a) * (b), false)
+#endif
+
// Detect when a multiply causes an overflow.
size_t mp_seq_multiply_len(size_t item_sz, size_t len) {
size_t new_len;
diff --git a/py/stream.c b/py/stream.c
index 1d25f6470..2ff2b76a6 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -86,8 +86,7 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode
}
const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) {
- mp_obj_type_t *type = mp_obj_get_type(self_in);
- const mp_stream_p_t *stream_p = type->protocol;
+ const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, self_in);
if (stream_p == NULL
|| ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL)
|| ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL)
@@ -522,7 +521,7 @@ int mp_stream_errno;
ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t out_sz = stream_p->write(stream, buf, len, &mp_stream_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
@@ -533,7 +532,7 @@ ssize_t mp_stream_posix_write(mp_obj_t stream, const void *buf, size_t len) {
ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t out_sz = stream_p->read(stream, buf, len, &mp_stream_errno);
if (out_sz == MP_STREAM_ERROR) {
return -1;
@@ -544,7 +543,7 @@ ssize_t mp_stream_posix_read(mp_obj_t stream, void *buf, size_t len) {
off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) {
const mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
struct mp_stream_seek_t seek_s;
seek_s.offset = offset;
seek_s.whence = whence;
@@ -557,7 +556,7 @@ off_t mp_stream_posix_lseek(mp_obj_t stream, off_t offset, int whence) {
int mp_stream_posix_fsync(mp_obj_t stream) {
mp_obj_base_t* o = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
- const mp_stream_p_t *stream_p = o->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(o);
mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_FLUSH, 0, &mp_stream_errno);
if (res == MP_STREAM_ERROR) {
return -1;
diff --git a/py/stream.h b/py/stream.h
index 03e24c746..543fe8c82 100644
--- a/py/stream.h
+++ b/py/stream.h
@@ -27,6 +27,7 @@
#define MICROPY_INCLUDED_PY_STREAM_H
#include "py/obj.h"
+#include "py/proto.h"
#include "py/mperrno.h"
#define MP_STREAM_ERROR ((mp_uint_t)-1)
@@ -64,6 +65,7 @@ struct mp_stream_seek_t {
// Stream protocol
typedef struct _mp_stream_p_t {
+ MP_PROTOCOL_HEAD
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
// are implementation-dependent, but will be exposed to user, e.g. via exception).
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
@@ -93,7 +95,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj);
// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods
static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) {
- return (const mp_stream_p_t*)((const mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type->protocol;
+ return mp_proto_get(MP_QSTR_protocol_stream, self);
}
const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags);
diff --git a/py/vm.c b/py/vm.c
index 353fc8810..4f0340681 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -35,6 +35,8 @@
#include "py/bc0.h"
#include "py/bc.h"
+#include "supervisor/linker.h"
+
#if 0
#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table);
#else
@@ -116,7 +118,7 @@
// 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 fastn[0]
-mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) {
+mp_vm_return_kind_t PLACE_IN_ITCM(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 */
diff --git a/py/vmentrytable.h b/py/vmentrytable.h
index a0e2d4065..31a96dbec 100644
--- a/py/vmentrytable.h
+++ b/py/vmentrytable.h
@@ -29,7 +29,9 @@
#pragma clang diagnostic ignored "-Winitializer-overrides"
#endif // __clang__
-static const void *const entry_table[256] = {
+#include "supervisor/linker.h"
+
+static const void *const PLACE_IN_DTCM_DATA(entry_table[256]) = {
[0 ... 255] = &&entry_default,
[MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE,
[MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE,
diff --git a/py/vstr.c b/py/vstr.c
index 869b27805..91cd7f584 100644
--- a/py/vstr.c
+++ b/py/vstr.c
@@ -50,6 +50,9 @@ void vstr_init(vstr_t *vstr, size_t alloc) {
// Init the vstr so it allocs exactly enough ram to hold a null-terminated
// string of the given length, and set the length.
void vstr_init_len(vstr_t *vstr, size_t len) {
+ if(len == SIZE_MAX) {
+ m_malloc_fail(len);
+ }
vstr_init(vstr, len + 1);
vstr->len = len;
}