summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
authorsommersoft <sommersoft@gmail.com>2019-07-31 16:44:43 -0500
committersommersoft <sommersoft@gmail.com>2019-07-31 16:44:43 -0500
commit9939d0c4f49db084f52a12b6ea5f6ce97b614146 (patch)
tree6c338f9e01c581793255757b4483d3d88824095f /py
parenta498bcd94d7f869e2cb2e992babacb981de688c0 (diff)
parent366fdcce18e148a6828b7a7074e1e4198fca3595 (diff)
Merge branch 'master' of https://github.com/adafruit/circuitpython into mixer_voice
Diffstat (limited to 'py')
-rw-r--r--py/binary.c22
-rw-r--r--py/circuitpy_defns.mk41
-rw-r--r--py/circuitpy_mpconfig.h86
-rw-r--r--py/circuitpy_mpconfig.mk83
-rw-r--r--py/emitglue.c7
-rwxr-xr-xpy/gc.c74
-rw-r--r--py/gc.h6
-rw-r--r--py/makemoduledefs.py107
-rw-r--r--py/mkrules.mk8
-rw-r--r--py/modbuiltins.c7
-rw-r--r--py/mpstate.h2
-rw-r--r--py/obj.c30
-rw-r--r--py/obj.h13
-rw-r--r--py/objexcept.c1
-rw-r--r--py/objint.c73
-rw-r--r--py/objint.h6
-rw-r--r--py/objlist.c4
-rw-r--r--py/objmodule.c7
-rw-r--r--py/objtype.c50
-rw-r--r--py/objtype.h2
-rw-r--r--py/persistentcode.c28
-rw-r--r--py/py.mk38
-rw-r--r--py/repl.c9
-rw-r--r--py/runtime.c20
-rw-r--r--py/runtime.h3
-rw-r--r--py/vmentrytable.h4
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
diff --git a/py/gc.c b/py/gc.c
index 1f5cd8d01..10b36950c 100755
--- a/py/gc.c
+++ b/py/gc.c
@@ -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);
diff --git a/py/gc.h b/py/gc.h
index 64f4b0d17..02bf45158 100644
--- a/py/gc.h
+++ b/py/gc.h
@@ -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
diff --git a/py/obj.c b/py/obj.c
index fb59eec82..322a302f9 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -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) {
diff --git a/py/obj.h b/py/obj.h
index 95e208021..6eead377d 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -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);
diff --git a/py/py.mk b/py/py.mk
index 11dd7a1e1..17cb79264 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -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
diff --git a/py/repl.c b/py/repl.c
index da0fefb3a..aa91c3f12 100644
--- a/py/repl.c
+++ b/py/repl.c
@@ -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__