diff options
| author | sommersoft <sommersoft@gmail.com> | 2019-07-31 16:44:43 -0500 |
|---|---|---|
| committer | sommersoft <sommersoft@gmail.com> | 2019-07-31 16:44:43 -0500 |
| commit | 9939d0c4f49db084f52a12b6ea5f6ce97b614146 (patch) | |
| tree | 6c338f9e01c581793255757b4483d3d88824095f /py | |
| parent | a498bcd94d7f869e2cb2e992babacb981de688c0 (diff) | |
| parent | 366fdcce18e148a6828b7a7074e1e4198fca3595 (diff) | |
Merge branch 'master' of https://github.com/adafruit/circuitpython into mixer_voice
Diffstat (limited to 'py')
| -rw-r--r-- | py/binary.c | 22 | ||||
| -rw-r--r-- | py/circuitpy_defns.mk | 41 | ||||
| -rw-r--r-- | py/circuitpy_mpconfig.h | 86 | ||||
| -rw-r--r-- | py/circuitpy_mpconfig.mk | 83 | ||||
| -rw-r--r-- | py/emitglue.c | 7 | ||||
| -rwxr-xr-x | py/gc.c | 74 | ||||
| -rw-r--r-- | py/gc.h | 6 | ||||
| -rw-r--r-- | py/makemoduledefs.py | 107 | ||||
| -rw-r--r-- | py/mkrules.mk | 8 | ||||
| -rw-r--r-- | py/modbuiltins.c | 7 | ||||
| -rw-r--r-- | py/mpstate.h | 2 | ||||
| -rw-r--r-- | py/obj.c | 30 | ||||
| -rw-r--r-- | py/obj.h | 13 | ||||
| -rw-r--r-- | py/objexcept.c | 1 | ||||
| -rw-r--r-- | py/objint.c | 73 | ||||
| -rw-r--r-- | py/objint.h | 6 | ||||
| -rw-r--r-- | py/objlist.c | 4 | ||||
| -rw-r--r-- | py/objmodule.c | 7 | ||||
| -rw-r--r-- | py/objtype.c | 50 | ||||
| -rw-r--r-- | py/objtype.h | 2 | ||||
| -rw-r--r-- | py/persistentcode.c | 28 | ||||
| -rw-r--r-- | py/py.mk | 38 | ||||
| -rw-r--r-- | py/repl.c | 9 | ||||
| -rw-r--r-- | py/runtime.c | 20 | ||||
| -rw-r--r-- | py/runtime.h | 3 | ||||
| -rw-r--r-- | py/vmentrytable.h | 4 |
26 files changed, 635 insertions, 96 deletions
diff --git a/py/binary.c b/py/binary.c index 9c3a49e8f..6b46425cf 100644 --- a/py/binary.c +++ b/py/binary.c @@ -304,15 +304,20 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** break; } #endif - default: + default: { + bool signed_type = is_signed(val_type); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { + // It's a longint. + mp_obj_int_buffer_overflow_check(val_in, size, signed_type); mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p); return; } else #endif { val = mp_obj_get_int(val_in); + // Small int checking is separate, to be fast. + mp_small_int_buffer_overflow_check(val, size, signed_type); // zero/sign extend if needed if (BYTES_PER_WORD < 8 && size > sizeof(val)) { int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00; @@ -322,6 +327,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** } } } + } } mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val); @@ -343,16 +349,24 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v ((mp_obj_t*)p)[index] = val_in; break; #endif - default: + default: { + size_t size = mp_binary_get_size('@', typecode, NULL); + bool signed_type = is_signed(typecode); + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) { - size_t size = mp_binary_get_size('@', typecode, NULL); + // It's a long int. + mp_obj_int_buffer_overflow_check(val_in, size, signed_type); mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG, size, (uint8_t*)p + index * size); return; } #endif - mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in)); + mp_int_t val = mp_obj_get_int(val_in); + // Small int checking is separate, to be fast. + mp_small_int_buffer_overflow_check(val, size, signed_type); + mp_binary_set_val_array_from_int(typecode, p, index, val); + } } } diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 47a720730..bdefc18cc 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -108,6 +108,9 @@ endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif +ifeq ($(CIRCUITPY_AUDIOCORE),1) +SRC_PATTERNS += audiocore/% +endif ifeq ($(CIRCUITPY_BITBANGIO),1) SRC_PATTERNS += bitbangio/% endif @@ -124,7 +127,7 @@ ifeq ($(CIRCUITPY_DIGITALIO),1) SRC_PATTERNS += digitalio/% endif ifeq ($(CIRCUITPY_DISPLAYIO),1) -SRC_PATTERNS += displayio/% terminalio/% +SRC_PATTERNS += displayio/% terminalio/% fontio/% endif ifeq ($(CIRCUITPY_FREQUENCYIO),1) SRC_PATTERNS += frequencyio/% @@ -132,6 +135,9 @@ endif ifeq ($(CIRCUITPY_GAMEPAD),1) SRC_PATTERNS += gamepad/% endif +ifeq ($(CIRCUITPY_GAMEPADSHIFT),1) +SRC_PATTERNS += gamepadshift/% +endif ifeq ($(CIRCUITPY_I2CSLAVE),1) SRC_PATTERNS += i2cslave/% endif @@ -159,6 +165,9 @@ endif ifeq ($(CIRCUITPY_PULSEIO),1) SRC_PATTERNS += pulseio/% endif +ifeq ($(CIRCUITPY_PS2IO),1) +SRC_PATTERNS += ps2io/% +endif ifeq ($(CIRCUITPY_RANDOM),1) SRC_PATTERNS += random/% endif @@ -218,7 +227,7 @@ $(filter $(SRC_PATTERNS), \ audioio/AudioOut.c \ bleio/__init__.c \ bleio/Adapter.c \ - bleio/Broadcaster.c \ + bleio/Central.c \ bleio/Characteristic.c \ bleio/CharacteristicBuffer.c \ bleio/Descriptor.c \ @@ -249,6 +258,8 @@ $(filter $(SRC_PATTERNS), \ pulseio/PulseIn.c \ pulseio/PulseOut.c \ pulseio/__init__.c \ + ps2io/Ps2.c \ + ps2io/__init__.c \ rotaryio/IncrementalEncoder.c \ rotaryio/__init__.c \ rtc/RTC.c \ @@ -268,7 +279,7 @@ $(filter $(SRC_PATTERNS), \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ - displayio/Glyph.c \ + fontio/Glyph.c \ microcontroller/RunMode.c \ math/__init__.c \ supervisor/__init__.c \ @@ -281,8 +292,6 @@ SRC_BINDINGS_ENUMS += \ SRC_BINDINGS_ENUMS += \ $(filter $(SRC_PATTERNS), \ bleio/Address.c \ - bleio/AddressType.c \ - bleio/AdvertisementData.c \ bleio/ScanEntry.c \ ) @@ -295,28 +304,35 @@ $(filter $(SRC_PATTERNS), \ _stage/Text.c \ _stage/__init__.c \ audioio/__init__.c \ - audioio/Mixer.c \ - audioio/MixerVoice.c \ - audioio/RawSample.c \ - audioio/WaveFile.c \ + audiocore/__init__.c \ + audiocore/Mixer.c \ + audiocore/RawSample.c \ + audiocore/WaveFile.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/BuiltinFont.c \ displayio/ColorConverter.c \ displayio/Display.c \ displayio/FourWire.c \ displayio/Group.c \ + displayio/I2CDisplay.c \ displayio/OnDiskBitmap.c \ displayio/Palette.c \ displayio/Shape.c \ displayio/TileGrid.c \ displayio/__init__.c \ + fontio/BuiltinFont.c \ + fontio/__init__.c \ gamepad/GamePad.c \ gamepad/__init__.c \ + gamepadshift/GamePadShift.c \ + gamepadshift/__init__.c \ os/__init__.c \ random/__init__.c \ socket/__init__.c \ @@ -355,3 +371,8 @@ $(addprefix lib/,\ libm/atan2f.c \ ) endif + +.PHONY: check-release-needs-clean-build + +check-release-needs-clean-build: + @echo "RELEASE_NEEDS_CLEAN_BUILD = $(RELEASE_NEEDS_CLEAN_BUILD)" diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 00f3c7b3f..3440eb052 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -72,6 +72,7 @@ #define MICROPY_KBD_EXCEPTION (1) #define MICROPY_MEM_STATS (0) #define MICROPY_NONSTANDARD_TYPECODES (0) +#define MICROPY_OPT_COMPUTED_GOTO (1) #define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_PY_ARRAY (1) @@ -88,6 +89,8 @@ #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_MIN_MAX (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_BUILTINS_SET (1) #define MICROPY_PY_BUILTINS_SLICE (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) @@ -177,11 +180,11 @@ typedef long mp_off_t; // 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) #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) #define MICROPY_PY_BUILTINS_FROZENSET (CIRCUITPY_FULL_BUILD) -#define MICROPY_PY_BUILTINS_REVERSED (CIRCUITPY_FULL_BUILD) #define MICROPY_PY_BUILTINS_STR_CENTER (CIRCUITPY_FULL_BUILD) #define MICROPY_PY_BUILTINS_STR_PARTITION (CIRCUITPY_FULL_BUILD) #define MICROPY_PY_BUILTINS_STR_SPLITLINES (CIRCUITPY_FULL_BUILD) @@ -227,6 +230,13 @@ extern const struct _mp_obj_module_t audiobusio_module; #define AUDIOBUSIO_MODULE #endif +#if CIRCUITPY_AUDIOCORE +#define AUDIOCORE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiocore), (mp_obj_t)&audiocore_module }, +extern const struct _mp_obj_module_t audiocore_module; +#else +#define AUDIOCORE_MODULE +#endif + #if CIRCUITPY_AUDIOIO #define AUDIOIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, extern const struct _mp_obj_module_t audioio_module; @@ -251,8 +261,29 @@ extern const struct _mp_obj_module_t bleio_module; #if CIRCUITPY_BOARD #define BOARD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module }, extern const struct _mp_obj_module_t board_module; + +#define BOARD_I2C (defined(DEFAULT_I2C_BUS_SDA) && defined(DEFAULT_I2C_BUS_SCL)) +#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. + +#if BOARD_UART +#define BOARD_UART_ROOT_POINTER mp_obj_t shared_uart_bus; +#else +#define BOARD_UART_ROOT_POINTER +#endif + #else #define BOARD_MODULE +#define BOARD_I2C_ROOT_POINTER +#define BOARD_UART_ROOT_POINTER #endif #if CIRCUITPY_BUSIO @@ -271,12 +302,15 @@ extern const struct _mp_obj_module_t digitalio_module; #if CIRCUITPY_DISPLAYIO extern const struct _mp_obj_module_t displayio_module; +extern const struct _mp_obj_module_t fontio_module; 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) #else #define DISPLAYIO_MODULE +#define FONTIO_MODULE #define TERMINALIO_MODULE #define CIRCUITPY_DISPLAY_LIMIT (0) #endif @@ -290,13 +324,26 @@ extern const struct _mp_obj_module_t frequencyio_module; #if CIRCUITPY_GAMEPAD extern const struct _mp_obj_module_t gamepad_module; -// Scan gamepad every 32ms -#define CIRCUITPY_GAMEPAD_TICKS 0x1f #define GAMEPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_gamepad),(mp_obj_t)&gamepad_module }, #else #define GAMEPAD_MODULE #endif +#if CIRCUITPY_GAMEPADSHIFT +extern const struct _mp_obj_module_t gamepadshift_module; +#define GAMEPADSHIFT_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_gamepadshift),(mp_obj_t)&gamepadshift_module }, +#else +#define GAMEPADSHIFT_MODULE +#endif + +#if CIRCUITPY_GAMEPAD || CIRCUITPY_GAMEPADSHIFT +// Scan gamepad every 32ms +#define CIRCUITPY_GAMEPAD_TICKS 0x1f +#define GAMEPAD_ROOT_POINTERS mp_obj_t gamepad_singleton; +#else +#define GAMEPAD_ROOT_POINTERS +#endif + #if CIRCUITPY_I2CSLAVE extern const struct _mp_obj_module_t i2cslave_module; #define I2CSLAVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_i2cslave), (mp_obj_t)&i2cslave_module }, @@ -356,6 +403,13 @@ extern const struct _mp_obj_module_t os_module; #define OS_MODULE_ALT_NAME #endif +#if CIRCUITPY_PEW +extern const struct _mp_obj_module_t pew_module; +#define PEW_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__pew),(mp_obj_t)&pew_module }, +#else +#define PEW_MODULE +#endif + #if CIRCUITPY_PIXELBUF extern const struct _mp_obj_module_t pixelbuf_module; #define PIXELBUF_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__pixelbuf),(mp_obj_t)&pixelbuf_module }, @@ -370,6 +424,13 @@ extern const struct _mp_obj_module_t pulseio_module; #define PULSEIO_MODULE #endif +#if CIRCUITPY_PS2IO +extern const struct _mp_obj_module_t ps2io_module; +#define PS2IO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ps2io), (mp_obj_t)&ps2io_module }, +#else +#define PS2IO_MODULE +#endif + #if CIRCUITPY_RANDOM extern const struct _mp_obj_module_t random_module; #define RANDOM_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, @@ -470,13 +531,6 @@ extern const struct _mp_obj_module_t ustack_module; #define USTACK_MODULE #endif -#if CIRCUITPY_PEW -extern const struct _mp_obj_module_t pew_module; -#define PEW_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__pew),(mp_obj_t)&pew_module }, -#else -#define PEW_MODULE -#endif - // These modules are not yet in shared-bindings, but we prefer the non-uxxx names. #if MICROPY_PY_UERRNO #define ERRNO_MODULE { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, @@ -517,17 +571,20 @@ extern const struct _mp_obj_module_t pew_module; #define MICROPY_PORT_BUILTIN_MODULES_STRONG_LINKS \ ANALOGIO_MODULE \ AUDIOBUSIO_MODULE \ + AUDIOCORE_MODULE \ AUDIOIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ BOARD_MODULE \ BUSIO_MODULE \ DIGITALIO_MODULE \ - TERMINALIO_MODULE \ DISPLAYIO_MODULE \ + FONTIO_MODULE \ + TERMINALIO_MODULE \ ERRNO_MODULE \ FREQUENCYIO_MODULE \ GAMEPAD_MODULE \ + GAMEPADSHIFT_MODULE \ I2CSLAVE_MODULE \ JSON_MODULE \ MATH_MODULE \ @@ -539,8 +596,10 @@ extern const struct _mp_obj_module_t pew_module; PEW_MODULE \ PIXELBUF_MODULE \ PULSEIO_MODULE \ + PS2IO_MODULE \ RANDOM_MODULE \ RE_MODULE \ + ROTARYIO_MODULE \ RTC_MODULE \ SAMD_MODULE \ STAGE_MODULE \ @@ -577,9 +636,11 @@ extern const struct _mp_obj_module_t pew_module; const char *readline_hist[8]; \ vstr_t *repl_line; \ mp_obj_t rtc_time_source; \ - mp_obj_t gamepad_singleton; \ + 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 \ @@ -592,6 +653,7 @@ void run_background_tasks(void); #define MICROPY_VM_HOOK_RETURN run_background_tasks(); #define CIRCUITPY_AUTORELOAD_DELAY_MS 500 +#define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000 #define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" #endif // __INCLUDED_MPCONFIG_CIRCUITPY_H diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 0df6fff06..772a1c3e1 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -32,22 +32,35 @@ # CIRCUITPY_FULL_BUILD = 0 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 + 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 + +# Setting CIRCUITPY_MINIMAL_BUILD = 1 will disable all features +# Use for for early stage or highly restricted ports +ifndef CIRCUITPY_DEFAULT_BUILD + ifeq ($(CIRCUITPY_MINIMAL_BUILD),1) + CIRCUITPY_FULL_BUILD = 0 + CIRCUITPY_DEFAULT_BUILD = 0 + else + CIRCUITPY_DEFAULT_BUILD = 1 + endif endif + + # All builtin modules are listed below, with default values (0 for off, 1 for on) # Some are always on, some are always off, and some depend on CIRCUITPY_FULL_BUILD. # # *** You can override any of the defaults by defining them in your mpconfigboard.mk. ifndef CIRCUITPY_ANALOGIO -CIRCUITPY_ANALOGIO = 1 +CIRCUITPY_ANALOGIO = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_ANALOGIO=$(CIRCUITPY_ANALOGIO) @@ -61,6 +74,11 @@ CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) +ifndef CIRCUITPY_AUDIOCORE +CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOIO) +endif +CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) + ifndef CIRCUITPY_BITBANGIO CIRCUITPY_BITBANGIO = $(CIRCUITPY_FULL_BUILD) endif @@ -73,17 +91,17 @@ endif CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO) ifndef CIRCUITPY_BOARD -CIRCUITPY_BOARD = 1 +CIRCUITPY_BOARD = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD) ifndef CIRCUITPY_BUSIO -CIRCUITPY_BUSIO = 1 +CIRCUITPY_BUSIO = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) ifndef CIRCUITPY_DIGITALIO -CIRCUITPY_DIGITALIO = 1 +CIRCUITPY_DIGITALIO = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO) @@ -93,7 +111,7 @@ endif CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO) ifndef CIRCUITPY_FREQUENCYIO -CIRCUITPY_FREQUENCYIO = 1 +CIRCUITPY_FREQUENCYIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO) @@ -102,23 +120,28 @@ CIRCUITPY_GAMEPAD = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_GAMEPAD=$(CIRCUITPY_GAMEPAD) +ifndef CIRCUITPY_GAMEPADSHIFT +CIRCUITPY_GAMEPADSHIFT = 0 +endif +CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT) + ifndef CIRCUITPY_I2CSLAVE CIRCUITPY_I2CSLAVE = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_I2CSLAVE=$(CIRCUITPY_I2CSLAVE) ifndef CIRCUITPY_MATH -CIRCUITPY_MATH = 1 +CIRCUITPY_MATH = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH) ifndef CIRCUITPY_MICROCONTROLLER -CIRCUITPY_MICROCONTROLLER = 1 +CIRCUITPY_MICROCONTROLLER = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER) ifndef CIRCUITPY_NEOPIXEL_WRITE -CIRCUITPY_NEOPIXEL_WRITE = 1 +CIRCUITPY_NEOPIXEL_WRITE = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_NEOPIXEL_WRITE=$(CIRCUITPY_NEOPIXEL_WRITE) @@ -129,12 +152,12 @@ endif CFLAGS += -DCIRCUITPY_NETWORK=$(CIRCUITPY_NETWORK) ifndef CIRCUITPY_NVM -CIRCUITPY_NVM = 1 +CIRCUITPY_NVM = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_NVM=$(CIRCUITPY_NVM) ifndef CIRCUITPY_OS -CIRCUITPY_OS = 1 +CIRCUITPY_OS = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS) @@ -144,22 +167,28 @@ endif CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF) ifndef CIRCUITPY_PULSEIO -CIRCUITPY_PULSEIO = 1 +CIRCUITPY_PULSEIO = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_PULSEIO=$(CIRCUITPY_PULSEIO) +# Only for SAMD boards for the moment +ifndef CIRCUITPY_PS2IO +CIRCUITPY_PS2IO = 0 +endif +CFLAGS += -DCIRCUITPY_PS2IO=$(CIRCUITPY_PS2IO) + ifndef CIRCUITPY_RANDOM -CIRCUITPY_RANDOM = 1 +CIRCUITPY_RANDOM = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM) ifndef CIRCUITPY_ROTARYIO -CIRCUITPY_ROTARYIO = 1 +CIRCUITPY_ROTARYIO = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_ROTARYIO=$(CIRCUITPY_ROTARYIO) ifndef CIRCUITPY_RTC -CIRCUITPY_RTC = 1 +CIRCUITPY_RTC = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_RTC=$(CIRCUITPY_RTC) @@ -178,27 +207,27 @@ endif CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) ifndef CIRCUITPY_STORAGE -CIRCUITPY_STORAGE = 1 +CIRCUITPY_STORAGE = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_STORAGE=$(CIRCUITPY_STORAGE) ifndef CIRCUITPY_STRUCT -CIRCUITPY_STRUCT = 1 +CIRCUITPY_STRUCT = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_STRUCT=$(CIRCUITPY_STRUCT) ifndef CIRCUITPY_SUPERVISOR -CIRCUITPY_SUPERVISOR = 1 +CIRCUITPY_SUPERVISOR = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_SUPERVISOR=$(CIRCUITPY_SUPERVISOR) ifndef CIRCUITPY_TIME -CIRCUITPY_TIME = 1 +CIRCUITPY_TIME = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_TIME=$(CIRCUITPY_TIME) ifndef CIRCUITPY_TOUCHIO -CIRCUITPY_TOUCHIO = 1 +CIRCUITPY_TOUCHIO = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO) @@ -209,12 +238,12 @@ endif CFLAGS += -DCIRCUITPY_UHEAP=$(CIRCUITPY_UHEAP) ifndef CIRCUITPY_USB_HID -CIRCUITPY_USB_HID = 1 +CIRCUITPY_USB_HID = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID) ifndef CIRCUITPY_USB_MIDI -CIRCUITPY_USB_MIDI = 1 +CIRCUITPY_USB_MIDI = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI) diff --git a/py/emitglue.c b/py/emitglue.c index 74bf8ddca..7708689dd 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -142,11 +142,12 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig); break; #endif - default: - // rc->kind should always be set and BYTECODE is the only remaining case - assert(rc->kind == MP_CODE_BYTECODE); + case MP_CODE_BYTECODE: fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->data.u_byte.bytecode, rc->data.u_byte.const_table); break; + default: + // All other kinds are invalid. + mp_raise_RuntimeError(translate("Corrupt raw code")); } // check for generator functions and if so wrap in generator object @@ -31,6 +31,8 @@ #include "py/gc.h" #include "py/runtime.h" +#include "supervisor/shared/safe_mode.h" + #if MICROPY_ENABLE_GC #if MICROPY_DEBUG_VERBOSE // print debugging info @@ -174,6 +176,8 @@ void gc_init(void *start, void *end) { mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex)); #endif + MP_STATE_MEM(permanent_pointers) = NULL; + DEBUG_printf("GC layout:\n"); DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB); #if MICROPY_ENABLE_FINALISER @@ -182,6 +186,13 @@ void gc_init(void *start, void *end) { DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len); } +void gc_deinit(void) { + // Run any finalizers before we stop using the heap. + gc_sweep_all(); + + MP_STATE_MEM(gc_pool_start) = 0; +} + void gc_lock(void) { GC_ENTER(); MP_STATE_MEM(gc_lock_depth)++; @@ -334,6 +345,19 @@ STATIC void gc_sweep(void) { } } +// Mark can handle NULL pointers because it verifies the pointer is within the heap bounds. +STATIC void gc_mark(void* ptr) { + if (VERIFY_PTR(ptr)) { + size_t block = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(block) == AT_HEAD) { + // An unmarked head: mark it, and mark all its children + TRACE_MARK(block, ptr); + ATB_HEAD_TO_MARK(block); + gc_mark_subtree(block); + } + } +} + void gc_collect_start(void) { GC_ENTER(); MP_STATE_MEM(gc_lock_depth)++; @@ -350,6 +374,8 @@ void gc_collect_start(void) { size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk); gc_collect_root(ptrs + root_start / sizeof(void*), (root_end - root_start) / sizeof(void*)); + gc_mark(MP_STATE_MEM(permanent_pointers)); + #if MICROPY_ENABLE_PYSTACK // Trace root pointers from the Python stack. ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); @@ -357,18 +383,14 @@ void gc_collect_start(void) { #endif } +void gc_collect_ptr(void *ptr) { + gc_mark(ptr); +} + void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { void *ptr = ptrs[i]; - if (VERIFY_PTR(ptr)) { - size_t block = BLOCK_FROM_PTR(ptr); - if (ATB_GET_KIND(block) == AT_HEAD) { - // An unmarked head: mark it, and mark all its children - TRACE_MARK(block, ptr); - ATB_HEAD_TO_MARK(block); - gc_mark_subtree(block); - } - } + gc_mark(ptr); } } @@ -463,6 +485,10 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) { return NULL; } + if (MP_STATE_MEM(gc_pool_start) == 0) { + reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM); + } + GC_ENTER(); // check if GC is locked @@ -925,6 +951,36 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { } #endif // Alternative gc_realloc impl +bool gc_never_free(void *ptr) { + // Check to make sure the pointer is on the heap in the first place. + if (gc_nbytes(ptr) == 0) { + return false; + } + // Pointers are stored in a linked list where each block is BYTES_PER_BLOCK long and the first + // pointer is the next block of pointers. + void ** current_reference_block = MP_STATE_MEM(permanent_pointers); + while (current_reference_block != NULL) { + for (size_t i = 1; i < BYTES_PER_BLOCK / sizeof(void*); i++) { + if (current_reference_block[i] == NULL) { + current_reference_block[i] = ptr; + return true; + } + } + current_reference_block = current_reference_block[0]; + } + void** next_block = gc_alloc(BYTES_PER_BLOCK, false, true); + if (next_block == NULL) { + return false; + } + if (MP_STATE_MEM(permanent_pointers) == NULL) { + MP_STATE_MEM(permanent_pointers) = next_block; + } else { + current_reference_block[0] = next_block; + } + next_block[1] = ptr; + return true; +} + void gc_dump_info(void) { gc_info_t info; gc_info(&info); @@ -32,6 +32,7 @@ #include "py/misc.h" void gc_init(void *start, void *end); +void gc_deinit(void); // These lock/unlock functions can be nested. // They can be used to prevent the GC from allocating/freeing. @@ -42,6 +43,7 @@ bool gc_is_locked(void); // A given port must implement gc_collect by using the other collect functions. void gc_collect(void); void gc_collect_start(void); +void gc_collect_ptr(void *ptr); void gc_collect_root(void **ptrs, size_t len); void gc_collect_end(void); @@ -56,6 +58,10 @@ bool gc_has_finaliser(const void *ptr); void *gc_make_long_lived(void *old_ptr); void *gc_realloc(void *ptr, size_t n_bytes, bool allow_move); +// Prevents a pointer from ever being freed because it establishes a permanent reference to it. Use +// very sparingly because it can leak memory. +bool gc_never_free(void *ptr); + typedef struct _gc_info_t { size_t total; size_t used; diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py new file mode 100644 index 000000000..18d327f00 --- /dev/null +++ b/py/makemoduledefs.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +# This pre-processor parses provided objects' c files for +# MP_REGISTER_MODULE(module_name, obj_module, enabled_define) +# These are used to generate a header with the required entries for +# "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c + +from __future__ import print_function + +import re +import os +import argparse + + +pattern = re.compile( + r"[\n;]\s*MP_REGISTER_MODULE\((.*?),\s*(.*?),\s*(.*?)\);", + flags=re.DOTALL +) + + +def find_c_file(obj_file, vpath): + """ Search vpaths for the c file that matches the provided object_file. + + :param str obj_file: object file to find the matching c file for + :param List[str] vpath: List of base paths, similar to gcc vpath + :return: str path to c file or None + """ + c_file = None + relative_c_file = os.path.splitext(obj_file)[0] + ".c" + relative_c_file = relative_c_file.lstrip('/\\') + for p in vpath: + possible_c_file = os.path.join(p, relative_c_file) + if os.path.exists(possible_c_file): + c_file = possible_c_file + break + + return c_file + + +def find_module_registrations(c_file): + """ Find any MP_REGISTER_MODULE definitions in the provided c file. + + :param str c_file: path to c file to check + :return: List[(module_name, obj_module, enabled_define)] + """ + global pattern + + if c_file is None: + # No c file to match the object file, skip + return set() + + with open(c_file) as c_file_obj: + return set(re.findall(pattern, c_file_obj.read())) + + +def generate_module_table_header(modules): + """ Generate header with module table entries for builtin modules. + + :param List[(module_name, obj_module, enabled_define)] modules: module defs + :return: None + """ + + # Print header file for all external modules. + mod_defs = [] + print("// Automatically generated by makemoduledefs.py.\n") + for module_name, obj_module, enabled_define in modules: + mod_def = "MODULE_DEF_{}".format(module_name.upper()) + mod_defs.append(mod_def) + print(( + "#if ({enabled_define})\n" + " extern const struct _mp_obj_module_t {obj_module};\n" + " #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\n" + "#else\n" + " #define {mod_def}\n" + "#endif\n" + ).format(module_name=module_name, obj_module=obj_module, + enabled_define=enabled_define, mod_def=mod_def) + ) + + print("\n#define MICROPY_REGISTERED_MODULES \\") + + for mod_def in mod_defs: + print(" {mod_def} \\".format(mod_def=mod_def)) + + print("// MICROPY_REGISTERED_MODULES") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--vpath", default=".", + help="comma separated list of folders to search for c files in") + parser.add_argument("files", nargs="*", + help="list of c files to search") + args = parser.parse_args() + + vpath = [p.strip() for p in args.vpath.split(',')] + + modules = set() + for obj_file in args.files: + c_file = find_c_file(obj_file, vpath) + modules |= find_module_registrations(c_file) + + generate_module_table_header(sorted(modules)) + + +if __name__ == '__main__': + main() diff --git a/py/mkrules.mk b/py/mkrules.mk index aa94ba412..292d25746 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -20,12 +20,12 @@ endif # can be located. By following this scheme, it allows a single build rule # to be used to compile all .c files. -vpath %.S . $(TOP) +vpath %.S . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.S $(STEPECHO) "CC $<" $(Q)$(CC) $(CFLAGS) -c -o $@ $< -vpath %.s . $(TOP) +vpath %.s . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.s $(STEPECHO) "AS $<" $(Q)$(AS) -o $@ $< @@ -42,7 +42,7 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< $(RM) -f $(@:.o=.d) endef -vpath %.c . $(TOP) +vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.o: %.c $(call compile_c) @@ -56,7 +56,7 @@ $(BUILD)/%.o: %.c QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp -vpath %.c . $(TOP) +vpath %.c . $(TOP) $(USER_C_MODULES) $(BUILD)/%.pp: %.c $(STEPECHO) "PreProcess $<" diff --git a/py/modbuiltins.c b/py/modbuiltins.c index b4f4fca34..e764f1987 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -455,13 +455,13 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { return o_in; } - #if !MICROPY_PY_BUILTINS_ROUND_INT - mp_raise_NotImplementedError(NULL); - #else mp_int_t num_dig = mp_obj_get_int(args[1]); if (num_dig >= 0) { return o_in; } + #if !MICROPY_PY_BUILTINS_ROUND_INT + mp_raise_NotImplementedError(NULL); + #else mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig)); mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2)); @@ -722,6 +722,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_KeyError), MP_ROM_PTR(&mp_type_KeyError) }, { MP_ROM_QSTR(MP_QSTR_LookupError), MP_ROM_PTR(&mp_type_LookupError) }, { MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_MemoryError) }, + { MP_ROM_QSTR(MP_QSTR_MpyError), MP_ROM_PTR(&mp_type_MpyError) }, { MP_ROM_QSTR(MP_QSTR_NameError), MP_ROM_PTR(&mp_type_NameError) }, { MP_ROM_QSTR(MP_QSTR_NotImplementedError), MP_ROM_PTR(&mp_type_NotImplementedError) }, { MP_ROM_QSTR(MP_QSTR_OSError), MP_ROM_PTR(&mp_type_OSError) }, diff --git a/py/mpstate.h b/py/mpstate.h index eef8696d3..a3d7e5dcc 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -103,6 +103,8 @@ typedef struct _mp_state_mem_t { // This is a global mutex used to make the GC thread-safe. mp_thread_mutex_t gc_mutex; #endif + + void** permanent_pointers; } mp_state_mem_t; // This structure hold runtime and VM information. It includes a section @@ -531,6 +531,36 @@ mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) { return self; } +typedef struct { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t obj; + mp_int_t cur; +} mp_obj_generic_it_t; + +STATIC mp_obj_t generic_it_iternext(mp_obj_t self_in) { + mp_obj_generic_it_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_type_t *type = mp_obj_get_type(self->obj); + mp_obj_t current_length = type->unary_op(MP_UNARY_OP_LEN, self->obj); + if (self->cur < MP_OBJ_SMALL_INT_VALUE(current_length)) { + mp_obj_t o_out = type->subscr(self->obj, MP_OBJ_NEW_SMALL_INT(self->cur), MP_OBJ_SENTINEL); + self->cur += 1; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +mp_obj_t mp_obj_new_generic_iterator(mp_obj_t obj, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_generic_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_generic_it_t *o = (mp_obj_generic_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = generic_it_iternext; + o->obj = obj; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { mp_obj_type_t *type = mp_obj_get_type(obj); if (type->buffer_p.get_buffer == NULL) { @@ -338,6 +338,13 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name} #define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name} +// Declare a module as a builtin, processed by makemoduledefs.py +// param module_name: MP_QSTR_<module name> +// param obj_module: mp_obj_module_t instance +// prarm enabled_define: used as `#if (enabled_define) around entry` + +#define MP_REGISTER_MODULE(module_name, obj_module, enabled_define) + // Underlying map/hash table implementation (not dict object or map function) typedef struct _mp_map_elem_t { @@ -592,6 +599,7 @@ extern const mp_obj_type_t mp_type_ReloadException; extern const mp_obj_type_t mp_type_KeyError; extern const mp_obj_type_t mp_type_LookupError; extern const mp_obj_type_t mp_type_MemoryError; +extern const mp_obj_type_t mp_type_MpyError; extern const mp_obj_type_t mp_type_NameError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_OSError; @@ -755,6 +763,7 @@ void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list +mp_obj_t mp_obj_list_clear(mp_obj_t self_in); mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); @@ -811,6 +820,10 @@ mp_obj_t mp_identity(mp_obj_t self); MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj); mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf); +// Generic iterator that uses unary op and subscr to iterate over a native type. It will be slower +// than a custom iterator but applies broadly. +mp_obj_t mp_obj_new_generic_iterator(mp_obj_t self, mp_obj_iter_buf_t *iter_buf); + // module typedef struct _mp_obj_module_t { mp_obj_base_t base; diff --git a/py/objexcept.c b/py/objexcept.c index 0e9255db7..c33ada0d6 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -311,6 +311,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(UnicodeError, ValueError) //TODO: Implement more UnicodeError subclasses which take arguments #endif + MP_DEFINE_EXCEPTION(MpyError, ValueError) /* MP_DEFINE_EXCEPTION(Warning, Exception) MP_DEFINE_EXCEPTION(DeprecationWarning, Warning) diff --git a/py/objint.c b/py/objint.c index fd746d331..9e11871f1 100644 --- a/py/objint.c +++ b/py/objint.c @@ -300,6 +300,76 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co return b; } +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + +void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed) +{ + if (is_signed) { + // self must be < 2**(bits - 1) + mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT, + mp_obj_new_int(1), + mp_obj_new_int(nbytes * 8 - 1)); + + if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) { + // and >= -2**(bits - 1) + edge = mp_unary_op(MP_UNARY_OP_NEGATIVE, edge); + if (mp_binary_op(MP_BINARY_OP_MORE_EQUAL, self_in, edge) == mp_const_true) { + return; + } + } + } else { + // self must be >= 0 + if (mp_obj_int_sign(self_in) >= 0) { + // and < 2**(bits) + mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT, + mp_obj_new_int(1), + mp_obj_new_int(nbytes * 8)); + + if (mp_binary_op(MP_BINARY_OP_LESS, self_in, edge) == mp_const_true) { + return; + } + } + } + + mp_raise_OverflowError_varg(translate("value must fit in %d byte(s)"), nbytes); +} + +#endif // MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + +void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed) { + // Fast path for zero. + if (val == 0) { + return; + } + + // Trying to store negative values in unsigned bytes falls through to failure. + if (is_signed || val >= 0) { + + if (nbytes >= sizeof(val)) { + // All non-negative N bit signed integers fit in an unsigned N bit integer. + // This case prevents shifting too far below. + return; + } + + if (is_signed) { + mp_int_t edge = ((mp_int_t)1 << (nbytes * 8 - 1)); + if (-edge <= val && val < edge) { + return; + } + // Out of range, fall through to failure. + } else { + // Unsigned. We already know val >= 0. + mp_int_t edge = ((mp_int_t)1 << (nbytes * 8)); + if (val < edge) { + return; + } + } + // Fall through to failure. + } + + mp_raise_OverflowError_varg(translate("value must fit in %d byte(s)"), nbytes); +} + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE int mp_obj_int_sign(mp_obj_t self_in) { @@ -437,11 +507,14 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) { #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); } else #endif { mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]); + // Small int checking is separate, to be fast. + mp_small_int_buffer_overflow_check(val, len, false); size_t l = MIN((size_t)len, sizeof(val)); mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val); } diff --git a/py/objint.h b/py/objint.h index 4b95acde9..e8c9bc3e0 100644 --- a/py/objint.h +++ b/py/objint.h @@ -53,6 +53,12 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co int base, const char *prefix, char base_char, char comma); char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE +void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed); +#endif + +void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed); + mp_int_t mp_obj_int_hash(mp_obj_t self_in); mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); diff --git a/py/objlist.c b/py/objlist.c index 16ca4b353..558c4c611 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -340,7 +340,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ return mp_const_none; } -STATIC mp_obj_t list_clear(mp_obj_t self_in) { +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); self->len = 0; @@ -418,7 +418,7 @@ STATIC mp_obj_t list_reverse(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_append_obj, mp_obj_list_append); STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_extend_obj, list_extend); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, list_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_clear_obj, mp_obj_list_clear); STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_copy_obj, list_copy); STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_count_obj, list_count); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(list_index_obj, 2, 4, list_index); diff --git a/py/objmodule.c b/py/objmodule.c index 469a95976..627ba79e8 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -32,6 +32,8 @@ #include "py/runtime.h" #include "py/builtin.h" +#include "genhdr/moduledefs.h" + STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); @@ -252,6 +254,11 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES + #ifdef MICROPY_REGISTERED_MODULES + // builtin modules declared with MP_REGISTER_MODULE() + MICROPY_REGISTERED_MODULES + #endif + #if defined(MICROPY_DEBUG_MODULES) && defined(MICROPY_PORT_BUILTIN_DEBUG_MODULES) , MICROPY_PORT_BUILTIN_DEBUG_MODULES #endif diff --git a/py/objtype.c b/py/objtype.c index f205c224e..5133d849f 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -117,6 +117,16 @@ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_ return o; } +// When instances are first created they have the base_init wrapper as their native parent's +// instance because make_new combines __new__ and __init__. This object is invalid for the native +// code so it must call this method to ensure that the given object has been __init__'d and is +// valid. +void mp_obj_assert_native_inited(mp_obj_t native_object) { + if (native_object == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) { + mp_raise_NotImplementedError(translate("Call super().__init__() before accessing native object.")); + } +} + // TODO // This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO // http://python-history.blogspot.com/2010/06/method-resolution-order.html @@ -964,6 +974,21 @@ STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { #endif return false; } + +STATIC bool map_has_special_accessors(const mp_map_t *map) { + if (map == NULL) { + return false; + } + for (size_t i = 0; i < map->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(map, i)) { + const mp_map_elem_t *elem = &map->table[i]; + if (check_for_special_accessors(elem->key, elem->value)) { + return true; + } + } + } + return false; +} #endif STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -1158,20 +1183,6 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->locals_dict = make_dict_long_lived(locals_dict, 10); - #if ENABLE_SPECIAL_ACCESSORS - // Check if the class has any special accessor methods - if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { - for (size_t i = 0; i < o->locals_dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&o->locals_dict->map, i)) { - const mp_map_elem_t *elem = &o->locals_dict->map.table[i]; - if (check_for_special_accessors(elem->key, elem->value)) { - o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; - break; - } - } - } - } - #endif const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); @@ -1180,6 +1191,17 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } mp_map_t *locals_map = &o->locals_dict->map; + #if ENABLE_SPECIAL_ACCESSORS + // Check if the class has any special accessor methods + if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS) && + (map_has_special_accessors(locals_map) || + (num_native_bases == 1 && + native_base->locals_dict != NULL && + map_has_special_accessors(&native_base->locals_dict->map)))) { + o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + #endif + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); if (elem != NULL) { // __new__ slot exists; check if it is a function diff --git a/py/objtype.h b/py/objtype.h index 13613f01f..a32c87496 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -37,6 +37,8 @@ typedef struct _mp_obj_instance_t { // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them } mp_obj_instance_t; +void mp_obj_assert_native_inited(mp_obj_t native_object); + #if MICROPY_CPYTHON_COMPAT // this is needed for object.__new__ mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base); diff --git a/py/persistentcode.c b/py/persistentcode.c index b44b5e38d..eb69bd407 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -102,20 +102,35 @@ STATIC void extract_prelude(const byte **ip, const byte **ip2, bytecode_prelude_ #include "py/parsenum.h" +STATIC void raise_corrupt_mpy(void) { + mp_raise_RuntimeError(translate("Corrupt .mpy file")); +} + STATIC int read_byte(mp_reader_t *reader) { - return reader->readbyte(reader->data); + mp_uint_t b = reader->readbyte(reader->data); + if (b == MP_READER_EOF) { + raise_corrupt_mpy(); + } + return b; } STATIC void read_bytes(mp_reader_t *reader, byte *buf, size_t len) { while (len-- > 0) { - *buf++ = reader->readbyte(reader->data); + mp_uint_t b =reader->readbyte(reader->data); + if (b == MP_READER_EOF) { + raise_corrupt_mpy(); + } + *buf++ = b; } } STATIC size_t read_uint(mp_reader_t *reader) { size_t unum = 0; for (;;) { - byte b = reader->readbyte(reader->data); + mp_uint_t b = reader->readbyte(reader->data); + if (b == MP_READER_EOF) { + raise_corrupt_mpy(); + } unum = (unum << 7) | (b & 0x7f); if ((b & 0x80) == 0) { break; @@ -145,11 +160,12 @@ STATIC mp_obj_t load_obj(mp_reader_t *reader) { return mp_obj_new_str_from_vstr(obj_type == 's' ? &mp_type_str : &mp_type_bytes, &vstr); } else if (obj_type == 'i') { return mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL); - } else { - assert(obj_type == 'f' || obj_type == 'c'); + } else if (obj_type == 'f' || obj_type == 'c') { return mp_parse_num_decimal(vstr.buf, vstr.len, obj_type == 'c', false, NULL); } } + raise_corrupt_mpy(); + return MP_OBJ_FROM_PTR(&mp_const_none_obj); } STATIC void load_bytecode_qstrs(mp_reader_t *reader, byte *ip, byte *ip_top) { @@ -220,7 +236,7 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { || header[1] != MPY_VERSION || header[2] != MPY_FEATURE_FLAGS || header[3] > mp_small_int_bits()) { - mp_raise_ValueError(translate("Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info.")); + mp_raise_MpyError(translate("Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info.")); } mp_raw_code_t *rc = load_raw_code(reader); reader->close(reader->data); @@ -105,6 +105,24 @@ $(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) endif +# External modules written in C. +ifneq ($(USER_C_MODULES),) +# pre-define USERMOD variables as expanded so that variables are immediate +# expanded as they're added to them +SRC_USERMOD := +CFLAGS_USERMOD := +LDFLAGS_USERMOD := +$(foreach module, $(wildcard $(USER_C_MODULES)/*/micropython.mk), \ + $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\ + $(info Including User C Module from $(USERMOD_DIR))\ + $(eval include $(module))\ +) + +SRC_MOD += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD)) +CFLAGS_MOD += $(CFLAGS_USERMOD) +LDFLAGS_MOD += $(LDFLAGS_USERMOD) +endif + # py object files PY_CORE_O_BASENAME = $(addprefix py/,\ mpstate.o \ @@ -287,6 +305,13 @@ $(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD) $(STEPECHO) "GEN $@" $(Q)$(PYTHON) $(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) > $@ + +SRC_QSTR += $(HEADER_BUILD)/moduledefs.h + # mpconfigport.mk is optional, but changes to it may drastically change # overall config, so they need to be caught MPCONFIGPORT_MK = $(wildcard mpconfigport.mk) @@ -318,10 +343,23 @@ $(PY_BUILD)/qstr.o: $(HEADER_BUILD)/qstrdefs.generated.h $(PY_BUILD)/nlr%.o: CFLAGS += -Os # optimising gc for speed; 5ms down to 4ms on pybv2 +ifndef SUPEROPT_GC + SUPEROPT_GC = 1 +endif + +ifeq ($(SUPEROPT_GC),1) $(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT) +endif # optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster) +ifndef SUPEROPT_VM + SUPEROPT_VM = 1 +endif + +ifeq ($(SUPEROPT_VM),1) $(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT) +endif + # Optimizing vm.o for modern deeply pipelined CPUs with branch predictors # may require disabling tail jump optimization. This will make sure that # each opcode has its own dispatching jump which will improve branch @@ -187,6 +187,11 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { mp_load_method_protected(obj, q, dest, true); if (dest[0] != MP_OBJ_NULL) { + // special case; filter out words that begin with underscore + // unless there's already a partial match + if (s_len == 0 && d_str[0] == '_') { + continue; + } if (match_str == NULL) { match_str = d_str; match_len = d_len; @@ -210,6 +215,10 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print // nothing found if (q_first == 0) { + if (s_len == 0) { + *compl_str = " "; + return 4; + } // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { diff --git a/py/runtime.c b/py/runtime.c index 060748f1b..9968f26e0 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1590,6 +1590,26 @@ NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } +NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...) { + va_list argptr; + va_start(argptr,fmt); + mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_NotImplementedError, fmt, argptr); + va_end(argptr); + nlr_raise(exception); +} + +NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...) { + va_list argptr; + va_start(argptr,fmt); + mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_OverflowError, fmt, argptr); + va_end(argptr); + nlr_raise(exception); +} + +NORETURN void mp_raise_MpyError(const compressed_string_t *msg) { + mp_raise_msg(&mp_type_MpyError, msg); +} + #if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK NORETURN void mp_raise_recursion_depth(void) { mp_raise_RuntimeError(translate("maximum recursion depth exceeded")); diff --git a/py/runtime.h b/py/runtime.h index e52d3232e..e8398cf0e 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -162,6 +162,9 @@ NORETURN void mp_raise_OSError(int errno_); 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); +NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...); +NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...); +NORETURN void mp_raise_MpyError(const compressed_string_t *msg); NORETURN void mp_raise_recursion_depth(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 615f4e2ce..a0e2d4065 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#if __clang__ +#ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winitializer-overrides" #endif // __clang__ @@ -113,6 +113,6 @@ static const void *const entry_table[256] = { [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_BINARY_OP_MULTI, }; -#if __clang__ +#ifdef __clang__ #pragma clang diagnostic pop #endif // __clang__ |
