diff options
| author | Chris Osterwood <osterwood@gmail.com> | 2020-01-20 13:11:57 -0500 |
|---|---|---|
| committer | Chris Osterwood <osterwood@gmail.com> | 2020-01-20 13:11:57 -0500 |
| commit | 97420994e85f65a4f2ddb802d532acd56c1e5879 (patch) | |
| tree | 11709251ee3b05ea46b7d262f3ba0ed28532e8cd /py | |
| parent | 137a4f8a5d21f5e37277031887a3908e6c4e371e (diff) | |
| parent | 85c731734a0388c28c8e3895ec1cecd1d9491e0c (diff) | |
Merge remote-tracking branch 'origin/master' into capablerobot-usbhub
Diffstat (limited to 'py')
| -rw-r--r-- | py/binary.c | 2 | ||||
| -rw-r--r-- | py/circuitpy_defns.mk | 126 | ||||
| -rw-r--r-- | py/circuitpy_mpconfig.h | 74 | ||||
| -rw-r--r-- | py/circuitpy_mpconfig.mk | 92 | ||||
| -rw-r--r-- | py/compile.c | 15 | ||||
| -rw-r--r-- | py/emitnative.c | 18 | ||||
| -rwxr-xr-x | py/gc.c | 18 | ||||
| -rw-r--r-- | py/gc.h | 13 | ||||
| -rwxr-xr-x | py/gc_long_lived.c | 5 | ||||
| -rw-r--r-- | py/makeqstrdata.py | 39 | ||||
| -rw-r--r-- | py/modio.c | 2 | ||||
| -rwxr-xr-x | py/mpconfig.h | 9 | ||||
| -rw-r--r-- | py/nlr.h | 56 | ||||
| -rw-r--r-- | py/nlrthumb.c | 16 | ||||
| -rw-r--r-- | py/nlrx64.c | 2 | ||||
| -rw-r--r-- | py/nlrx86.c | 2 | ||||
| -rw-r--r-- | py/nlrxtensa.c | 2 | ||||
| -rw-r--r-- | py/obj.c | 5 | ||||
| -rw-r--r-- | py/obj.h | 2 | ||||
| -rw-r--r-- | py/objfun.c | 2 | ||||
| -rw-r--r-- | py/objlist.c | 13 | ||||
| -rw-r--r-- | py/objnamedtuple.c | 1 | ||||
| -rw-r--r-- | py/objstr.c | 30 | ||||
| -rw-r--r-- | py/objstr.h | 3 | ||||
| -rw-r--r-- | py/objstringio.c | 2 | ||||
| -rw-r--r-- | py/objtuple.c | 9 | ||||
| -rw-r--r-- | py/objtype.c | 16 | ||||
| -rw-r--r-- | py/proto.c | 50 | ||||
| -rw-r--r-- | py/proto.h | 43 | ||||
| -rw-r--r-- | py/py.mk | 9 | ||||
| -rw-r--r-- | py/ringbuf.h | 7 | ||||
| -rw-r--r-- | py/runtime.c | 2 | ||||
| -rw-r--r-- | py/showbc.c | 2 | ||||
| -rw-r--r-- | py/stream.c | 14 | ||||
| -rw-r--r-- | py/stream.h | 4 | ||||
| -rw-r--r-- | py/vm.c | 2 | ||||
| -rw-r--r-- | py/vstr.c | 3 |
37 files changed, 547 insertions, 163 deletions
diff --git a/py/binary.c b/py/binary.c index 6b46425cf..2ec12fa93 100644 --- a/py/binary.c +++ b/py/binary.c @@ -184,7 +184,7 @@ long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, con val = -1; } for (uint i = 0; i < size; i++) { - val <<= 8; + val *= 256; val |= *src; src += delta; } diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index a6dde61da..1f2d6c73e 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -114,11 +114,21 @@ endif ifeq ($(CIRCUITPY_AUDIOCORE),1) SRC_PATTERNS += audiocore/% 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 +# Some builds need bitbang SPI for the dotstar but don't make bitbangio available so include it separately. +ifeq ($(CIRCUITPY_BITBANG_APA102),1) +SRC_PATTERNS += bitbangio/SPI% +endif ifeq ($(CIRCUITPY_BLEIO),1) -SRC_PATTERNS += bleio/% +SRC_PATTERNS += _bleio/% endif ifeq ($(CIRCUITPY_BOARD),1) SRC_PATTERNS += board/% @@ -217,9 +227,18 @@ ifeq ($(CIRCUITPY_PEW),1) SRC_PATTERNS += _pew/% endif -# All possible sources are listed here, and are filtered by SRC_PATTERNS. -SRC_COMMON_HAL = \ -$(filter $(SRC_PATTERNS), \ +# All possible sources are listed here, and are filtered by SRC_PATTERNS in SRC_COMMON_HAL +SRC_COMMON_HAL_ALL = \ + _bleio/__init__.c \ + _bleio/Adapter.c \ + _bleio/Attribute.c \ + _bleio/Characteristic.c \ + _bleio/CharacteristicBuffer.c \ + _bleio/Connection.c \ + _bleio/Descriptor.c \ + _bleio/PacketBuffer.c \ + _bleio/Service.c \ + _bleio/UUID.c \ analogio/AnalogIn.c \ analogio/AnalogOut.c \ analogio/__init__.c \ @@ -230,16 +249,6 @@ $(filter $(SRC_PATTERNS), \ audiopwmio/PWMAudioOut.c \ audioio/__init__.c \ audioio/AudioOut.c \ - bleio/__init__.c \ - bleio/Adapter.c \ - bleio/Central.c \ - bleio/Characteristic.c \ - bleio/CharacteristicBuffer.c \ - bleio/Descriptor.c \ - bleio/Peripheral.c \ - bleio/Scanner.c \ - bleio/Service.c \ - bleio/UUID.c \ board/__init__.c \ busio/I2C.c \ busio/SPI.c \ @@ -271,38 +280,35 @@ $(filter $(SRC_PATTERNS), \ rtc/__init__.c \ supervisor/Runtime.c \ supervisor/__init__.c \ - time/__init__.c \ - touchio/TouchIn.c \ - touchio/__init__.c \ -) + time/__init__.c + +SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL)) # These don't have corresponding files in each port but are still located in # shared-bindings to make it clear what the contents of the modules are. # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ + _bleio/Address.c \ + _bleio/Attribute.c \ + _bleio/ScanEntry.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ fontio/Glyph.c \ microcontroller/RunMode.c \ math/__init__.c \ - supervisor/__init__.c \ ) SRC_BINDINGS_ENUMS += \ help.c \ util.c -SRC_BINDINGS_ENUMS += \ -$(filter $(SRC_PATTERNS), \ - bleio/Address.c \ - bleio/ScanEntry.c \ -) - -# All possible sources are listed here, and are filtered by SRC_PATTERNS. -SRC_SHARED_MODULE = \ -$(filter $(SRC_PATTERNS), \ +SRC_SHARED_MODULE_ALL = \ + _bleio/Address.c \ + _bleio/Attribute.c \ + _bleio/ScanEntry.c \ + _bleio/ScanResults.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ _stage/Layer.c \ @@ -311,20 +317,23 @@ $(filter $(SRC_PATTERNS), \ audiopwmio/__init__.c \ audioio/__init__.c \ audiocore/__init__.c \ - audiocore/Mixer.c \ audiocore/RawSample.c \ audiocore/WaveFile.c \ + audiomixer/__init__.c \ + audiomixer/Mixer.c \ + audiomixer/MixerVoice.c \ + audiomp3/__init__.c \ + audiomp3/MP3Decoder.c \ bitbangio/I2C.c \ bitbangio/OneWire.c \ bitbangio/SPI.c \ bitbangio/__init__.c \ board/__init__.c \ - bleio/Address.c \ - bleio/ScanEntry.c \ busio/OneWire.c \ displayio/Bitmap.c \ displayio/ColorConverter.c \ displayio/Display.c \ + displayio/EPaperDisplay.c \ displayio/FourWire.c \ displayio/Group.c \ displayio/I2CDisplay.c \ @@ -350,7 +359,48 @@ $(filter $(SRC_PATTERNS), \ uheap/__init__.c \ ustack/__init__.c \ _pew/__init__.c \ - _pew/PewPew.c \ + _pew/PewPew.c + +# All possible sources are listed here, and are filtered by SRC_PATTERNS. +SRC_SHARED_MODULE = $(filter $(SRC_PATTERNS), $(SRC_SHARED_MODULE_ALL)) + +# Use the native touchio if requested. This flag is set conditionally in, say, mpconfigport.h. +# The presence of common-hal/touchio/* # does not imply it's available for all chips in a port, +# so there is an explicit flag. For example, SAMD21 touchio is native, but SAMD51 is not. +ifeq ($(CIRCUITPY_TOUCHIO_USE_NATIVE),1) +SRC_COMMON_HAL_ALL += \ + touchio/TouchIn.c \ + touchio/__init__.c +else +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 = \ +$(filter $(SRC_PATTERNS), \ + displayio/display_core.c \ ) ifeq ($(INTERNAL_LIBM),1) @@ -378,6 +428,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 d88d6538e..5b705a088 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 @@ -56,8 +57,8 @@ #define MICROPY_COMP_MODULE_CONST (1) #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) #define MICROPY_DEBUG_PRINTERS (0) -#define MICROPY_EMIT_INLINE_THUMB (0) -#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (CIRCUITPY_ENABLE_MPY_NATIVE) +#define MICROPY_EMIT_THUMB (CIRCUITPY_ENABLE_MPY_NATIVE) #define MICROPY_EMIT_X64 (0) #define MICROPY_ENABLE_DOC_STRING (0) #define MICROPY_ENABLE_FINALISER (1) @@ -139,7 +140,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 +167,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 +196,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 +219,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. @@ -244,6 +254,20 @@ extern const struct _mp_obj_module_t audioio_module; #define AUDIOIO_MODULE #endif +#if CIRCUITPY_AUDIOMIXER +#define AUDIOMIXER_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiomixer), (mp_obj_t)&audiomixer_module }, +extern const struct _mp_obj_module_t audiomixer_module; +#else +#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; @@ -259,7 +283,7 @@ extern const struct _mp_obj_module_t bitbangio_module; #endif #if CIRCUITPY_BLEIO -#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bleio), (mp_obj_t)&bleio_module }, +#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__bleio), (mp_obj_t)&bleio_module }, extern const struct _mp_obj_module_t bleio_module; #else #define BLEIO_MODULE @@ -273,13 +297,7 @@ extern const struct _mp_obj_module_t board_module; #define BOARD_SPI (defined(DEFAULT_SPI_BUS_SCK) && defined(DEFAULT_SPI_BUS_MISO) && defined(DEFAULT_SPI_BUS_MOSI)) #define BOARD_UART (defined(DEFAULT_UART_BUS_RX) && defined(DEFAULT_UART_BUS_TX)) -#if BOARD_I2C -#define BOARD_I2C_ROOT_POINTER mp_obj_t shared_i2c_bus; -#else -#define BOARD_I2C_ROOT_POINTER -#endif - -// SPI is always allocated off the heap. +// I2C and SPI are always allocated off the heap. #if BOARD_UART #define BOARD_UART_ROOT_POINTER mp_obj_t shared_uart_bus; @@ -289,7 +307,6 @@ extern const struct _mp_obj_module_t board_module; #else #define BOARD_MODULE -#define BOARD_I2C_ROOT_POINTER #define BOARD_UART_ROOT_POINTER #endif @@ -314,7 +331,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 }, -#define CIRCUITPY_DISPLAY_LIMIT (3) +#ifndef CIRCUITPY_DISPLAY_LIMIT +#define CIRCUITPY_DISPLAY_LIMIT (1) +#endif #else #define DISPLAYIO_MODULE #define FONTIO_MODULE @@ -580,6 +599,8 @@ extern const struct _mp_obj_module_t ustack_module; AUDIOBUSIO_MODULE \ AUDIOCORE_MODULE \ AUDIOIO_MODULE \ + AUDIOMIXER_MODULE \ + AUDIOMP3_MODULE \ AUDIOPWMIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ @@ -603,8 +624,8 @@ extern const struct _mp_obj_module_t ustack_module; WIZNET_MODULE \ PEW_MODULE \ PIXELBUF_MODULE \ - PULSEIO_MODULE \ PS2IO_MODULE \ + PULSEIO_MODULE \ RANDOM_MODULE \ RE_MODULE \ ROTARYIO_MODULE \ @@ -647,21 +668,30 @@ extern const struct _mp_obj_module_t ustack_module; GAMEPAD_ROOT_POINTERS \ mp_obj_t pew_singleton; \ mp_obj_t terminal_tilegrid_tiles; \ - BOARD_I2C_ROOT_POINTER \ BOARD_UART_ROOT_POINTER \ FLASH_ROOT_POINTERS \ NETWORK_ROOT_POINTERS \ -void run_background_tasks(void); +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 a408cd7ac..93175e136 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,24 +33,35 @@ 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 - CIRCUITPY_DEFAULT_BUILD = 0 + CIRCUITPY_FULL_BUILD = 0 + CIRCUITPY_DEFAULT_BUILD = 0 else - CIRCUITPY_DEFAULT_BUILD = 1 + 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. +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) @@ -74,6 +84,12 @@ CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) +ifndef CIRCUITPY_AUDIOIO_COMPAT +CIRCUITPY_AUDIOIO_COMPAT = $(CIRCUITPY_AUDIOIO) +endif +CFLAGS += -DCIRCUITPY_AUDIOIO_COMPAT=$(CIRCUITPY_AUDIOIO_COMPAT) + + ifndef CIRCUITPY_AUDIOPWMIO CIRCUITPY_AUDIOPWMIO = 0 endif @@ -88,12 +104,26 @@ endif endif CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) +ifndef CIRCUITPY_AUDIOMIXER +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 CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO) -# Explicitly enabled for boards that support bleio. +# Explicitly enabled for boards that support _bleio. ifndef CIRCUITPY_BLEIO CIRCUITPY_BLEIO = 0 endif @@ -140,7 +170,7 @@ endif CFLAGS += -DCIRCUITPY_I2CSLAVE=$(CIRCUITPY_I2CSLAVE) ifndef CIRCUITPY_MATH -CIRCUITPY_MATH = $(CIRCUITPY_DEFAULT_BUILD) +CIRCUITPY_MATH = $(CIRCUITPY_ALWAYS_BUILD) endif CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH) @@ -154,7 +184,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 @@ -221,20 +251,26 @@ endif CFLAGS += -DCIRCUITPY_STORAGE=$(CIRCUITPY_STORAGE) ifndef CIRCUITPY_STRUCT -CIRCUITPY_STRUCT = $(CIRCUITPY_DEFAULT_BUILD) +CIRCUITPY_STRUCT = $(CIRCUITPY_ALWAYS_BUILD) endif CFLAGS += -DCIRCUITPY_STRUCT=$(CIRCUITPY_STRUCT) ifndef CIRCUITPY_SUPERVISOR -CIRCUITPY_SUPERVISOR = $(CIRCUITPY_DEFAULT_BUILD) +CIRCUITPY_SUPERVISOR = $(CIRCUITPY_ALWAYS_BUILD) endif CFLAGS += -DCIRCUITPY_SUPERVISOR=$(CIRCUITPY_SUPERVISOR) ifndef CIRCUITPY_TIME -CIRCUITPY_TIME = $(CIRCUITPY_DEFAULT_BUILD) +CIRCUITPY_TIME = $(CIRCUITPY_ALWAYS_BUILD) endif CFLAGS += -DCIRCUITPY_TIME=$(CIRCUITPY_TIME) +# touchio might be native or generic. See circuitpy_defns.mk. +ifndef CIRCUITPY_TOUCHIO_USE_NATIVE +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 +endif +CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE) + ifndef CIRCUITPY_TOUCHIO CIRCUITPY_TOUCHIO = $(CIRCUITPY_DEFAULT_BUILD) endif @@ -266,3 +302,35 @@ ifndef CIRCUITPY_USTACK 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) + +# 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 +CIRCUITPY_ENABLE_MPY_NATIVE = 0 +endif +CFLAGS += -DCIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE) diff --git a/py/compile.c b/py/compile.c index 1218aa07e..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 @@ -3207,7 +3216,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } if (pass > MP_PASS_SCOPE) { mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]); - for (uint j = 1; j < n_args; j++) { + for (int j = 1; j < n_args; j++) { if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) { compile_syntax_error(comp, nodes[i], translate("'data' requires integer arguments")); return; diff --git a/py/emitnative.c b/py/emitnative.c index 67b0025c6..6d23bf097 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -58,6 +58,22 @@ #define DEBUG_printf(...) (void)0 #endif +#ifndef N_X64 + #define N_X64 (0) +#endif +#ifndef N_X86 + #define N_X86 (0) +#endif +#ifndef N_THUMB + #define N_THUMB (0) +#endif +#ifndef N_ARM + #define N_ARM (0) +#endif +#ifndef N_XTENSA + #define N_XTENSA (0) +#endif + // wrapper around everything in this file #if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA @@ -443,10 +459,12 @@ STATIC void emit_native_end_pass(emit_t *emit) { type_sig |= (emit->local_vtype[i] & 0xf) << (i * 4 + 4); } + #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, f, f_len, (mp_uint_t*)((byte*)f + emit->const_table_offset), emit->scope->num_pos_args, emit->scope->scope_flags, type_sig); + #pragma GCC diagnostic pop } } @@ -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 @@ -209,13 +206,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) @@ -474,6 +464,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) { @@ -509,7 +503,6 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) { gc_collect(); collected = 1; GC_ENTER(); - collected = true; } #endif @@ -678,6 +671,9 @@ 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); @@ -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/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..a0d211bfa 100755 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1440,6 +1440,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) )) @@ -36,33 +36,45 @@ // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch #if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP -#define MICROPY_NLR_SETJMP (0) // A lot of nlr-related things need different treatment on Windows -#if defined(_WIN32) || defined(__CYGWIN__) -#define MICROPY_NLR_OS_WINDOWS 1 -#else -#define MICROPY_NLR_OS_WINDOWS 0 -#endif -#if defined(__i386__) - #define MICROPY_NLR_X86 (1) - #define MICROPY_NLR_NUM_REGS (6) -#elif defined(__x86_64__) - #define MICROPY_NLR_X64 (1) - #if MICROPY_NLR_OS_WINDOWS - #define MICROPY_NLR_NUM_REGS (10) + #if defined(_WIN32) || defined(__CYGWIN__) + #define MICROPY_NLR_OS_WINDOWS 1 #else - #define MICROPY_NLR_NUM_REGS (8) + #define MICROPY_NLR_OS_WINDOWS 0 #endif -#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) - #define MICROPY_NLR_THUMB (1) - #define MICROPY_NLR_NUM_REGS (10) -#elif defined(__xtensa__) - #define MICROPY_NLR_XTENSA (1) - #define MICROPY_NLR_NUM_REGS (10) -#else - #define MICROPY_NLR_SETJMP (1) + #if defined(__i386__) + #define MICROPY_NLR_X86 (1) + #define MICROPY_NLR_NUM_REGS (6) + #elif defined(__x86_64__) + #define MICROPY_NLR_X64 (1) + #if MICROPY_NLR_OS_WINDOWS + #define MICROPY_NLR_NUM_REGS (10) + #else + #define MICROPY_NLR_NUM_REGS (8) + #endif + #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) + #define MICROPY_NLR_THUMB (1) + #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) + #else + #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" + #endif #endif + +// If MICROPY_NLR_SETJMP is not defined above - define/disable it here + +#if !defined(MICROPY_NLR_SETJMP) + #define MICROPY_NLR_SETJMP (0) #endif #if MICROPY_NLR_SETJMP 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 @@ -63,6 +63,9 @@ const char *mp_obj_get_type_str(mp_const_obj_t o_in) { void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { // There can be data structures nested too deep, or just recursive MP_STACK_CHECK(); + #ifdef RUN_BACKGROUND_TASKS + RUN_BACKGROUND_TASKS; + #endif #ifndef NDEBUG if (o_in == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); @@ -486,6 +489,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. @@ -493,7 +497,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) { @@ -647,6 +647,7 @@ mp_obj_t mp_obj_new_str(const char* data, size_t len); mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len); mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); +mp_obj_t mp_obj_new_bytes_of_zeros(size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, void *items); mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n); mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items); @@ -668,6 +669,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items); +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable); mp_obj_t mp_obj_new_dict(size_t n_args); mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items); mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step); diff --git a/py/objfun.c b/py/objfun.c index b8364815b..7e5899456 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -546,7 +546,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_obj_fun_asm_t *self = self_in; - mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false); + mp_arg_check_num_kw_array(n_args, n_kw, self->n_args, self->n_args, false); void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data); diff --git a/py/objlist.c b/py/objlist.c index 558c4c611..b32f82085 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -68,6 +68,11 @@ STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { return list; } +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable) { + mp_obj_t list = mp_obj_new_list(0, NULL); + return list_extend_from_iter(list, iterable); +} + STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { (void)type_in; mp_arg_check_num(n_args, kw_args, 0, 1, false); @@ -154,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); @@ -174,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; @@ -196,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; @@ -225,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; } } 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 ebd11d5cc..fde264681 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -31,6 +31,7 @@ #include "py/unicode.h" #include "py/objstr.h" #include "py/objlist.h" +#include "py/objtype.h" #include "py/runtime.h" #include "py/stackctrl.h" @@ -41,6 +42,12 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); +const char nibble_to_hex_upper[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + +const char nibble_to_hex_lower[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + /******************************************************************************/ /* str */ @@ -220,10 +227,6 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, cons return MP_OBJ_FROM_PTR(o); } - if (n_args > 1) { - goto wrong_args; - } - if (MP_OBJ_IS_SMALL_INT(args[0])) { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); if (len < 0) { @@ -235,6 +238,17 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, cons return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } + if (n_args > 1) { + goto wrong_args; + } + + // check if __bytes__ exists, and if so delegate to it + mp_obj_t dest[2]; + mp_load_method_maybe(args[0], MP_QSTR___bytes__, dest); + if (dest[0] != MP_OBJ_NULL) { + return mp_call_method_n_kw(0, 0, dest); + } + // check if argument has the buffer protocol mp_buffer_info_t bufinfo; if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { @@ -2088,6 +2102,14 @@ mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { return mp_obj_new_str_copy(&mp_type_bytes, data, len); } +mp_obj_t mp_obj_new_bytes_of_zeros(size_t len) { + vstr_t vstr; + vstr_init_len(&vstr, len); + memset(vstr.buf, 0, len); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + + bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { if (MP_OBJ_IS_QSTR(s1) && MP_OBJ_IS_QSTR(s2)) { return s1 == s2; diff --git a/py/objstr.h b/py/objstr.h index 0efe62a80..61a11d0bd 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -77,6 +77,9 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s mp_obj_t index, bool is_slice); const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction); +const char nibble_to_hex_upper[16]; +const char nibble_to_hex_lower[16]; + MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj); 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 474f81c1a..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; @@ -251,7 +257,8 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { } void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + // type check is done on getiter method to allow tuple, namedtuple, attrtuple + mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = &self->items[0]; diff --git a/py/objtype.c b/py/objtype.c index 5133d849f..a5e733208 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 @@ -336,8 +337,10 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, cons mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw); args2[0] = MP_OBJ_FROM_PTR(self); memcpy(args2 + 1, args, n_args * sizeof(mp_obj_t)); - // copy in kwargs - memcpy(args2 + 1 + n_args, kw_args->table, 2 * n_kw * sizeof(mp_obj_t)); + if (kw_args) { + // copy in kwargs + memcpy(args2 + 1 + n_args, kw_args->table, 2 * n_kw * sizeof(mp_obj_t)); + } new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2); m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); } @@ -849,8 +852,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 + @@ -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/ringbuf.h b/py/ringbuf.h index 5f82cc096..7fc35d266 100644 --- a/py/ringbuf.h +++ b/py/ringbuf.h @@ -99,4 +99,11 @@ static inline void ringbuf_put_n(ringbuf_t* r, uint8_t* buf, uint8_t bufsize) } } } + +static inline void ringbuf_get_n(ringbuf_t* r, uint8_t* buf, uint8_t bufsize) +{ + for(uint8_t i=0; i < bufsize; i++) { + buf[i] = ringbuf_get(r); + } +} #endif // MICROPY_INCLUDED_PY_RINGBUF_H diff --git a/py/runtime.c b/py/runtime.c index 9968f26e0..a786619bf 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -31,8 +31,6 @@ #include "extmod/vfs.h" -// #include "py/mpstate.h" -// #include "py/nlr.h" #include "py/parsenum.h" #include "py/compile.h" #include "py/objstr.h" diff --git a/py/showbc.c b/py/showbc.c index 3deb18cd3..e71d8a253 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -185,7 +185,7 @@ const byte *mp_bytecode_print_str(const byte *ip) { num--; } do { - num = (num << 7) | (*ip & 0x7f); + num = (num * 128) | (*ip & 0x7f); } while ((*ip++ & 0x80) != 0); printf("LOAD_CONST_SMALL_INT " INT_FMT, num); break; diff --git a/py/stream.c b/py/stream.c index 08c749cc3..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) @@ -341,6 +340,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { p = vstr_extend(&vstr, DEFAULT_BUFFER_SIZE); current_read = DEFAULT_BUFFER_SIZE; } + #ifdef RUN_BACKGROUND_TASKS + RUN_BACKGROUND_TASKS; + #endif } vstr.len = total_size; @@ -519,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; @@ -530,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; @@ -541,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; @@ -554,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); @@ -758,7 +758,7 @@ unwind_jump:; } else { PUSH(value); // push the next iteration value } - DISPATCH(); + DISPATCH_WITH_PEND_EXC_CHECK(); } // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH @@ -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; } |
