Skip to content

Instantly share code, notes, and snippets.

@jepler
Created December 10, 2024 00:06
Show Gist options
  • Save jepler/181ab2c5ccd4175d3635d459ee739e2c to your computer and use it in GitHub Desktop.
Save jepler/181ab2c5ccd4175d3635d459ee739e2c to your computer and use it in GitHub Desktop.
From 7188d09390183a4333562fcb6bba7f93b85d5ac4 Mon Sep 17 00:00:00 2001
From: Jeff Epler <[email protected]>
Date: Mon, 9 Dec 2024 18:06:17 -0600
Subject: [PATCH] proof of concept: mpy-cross -mno-long
This causes an OverflowError to be raised if an integer constant doesn't
fit on builds without long int support.
Hypothetically, circuitpython-build-tools could first run mpy-cross with
this flag; if it fails, put into some new metadata file "requires
long integers" and run again without the flag.
---
mpy-cross/main.c | 3 +++
py/mpstate.h | 1 +
py/persistentcode.c | 26 ++++++++++++++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/mpy-cross/main.c b/mpy-cross/main.c
index 611da76468..83913f33e8 100644
--- a/mpy-cross/main.c
+++ b/mpy-cross/main.c
@@ -274,6 +274,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
}
a += 1;
source_file = backslash_to_forwardslash(argv[a]);
+ } else if (strcmp(argv[a], "-mno-long") == 0) {
+ mp_printf(&mp_plat_print, "no-long");
+ mp_dynamic_compiler.no_long_int = true;
} else if (strncmp(argv[a], "-msmall-int-bits=", sizeof("-msmall-int-bits=") - 1) == 0) {
char *end;
mp_dynamic_compiler.small_int_bits =
diff --git a/py/mpstate.h b/py/mpstate.h
index 7308e57b58..f1709b68b5 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -74,6 +74,7 @@ typedef struct mp_dynamic_compiler_t {
uint8_t small_int_bits; // must be <= host small_int_bits
uint8_t native_arch;
uint8_t nlr_buf_num_regs;
+ bool no_long_int;
} mp_dynamic_compiler_t;
extern mp_dynamic_compiler_t mp_dynamic_compiler;
#endif
diff --git a/py/persistentcode.c b/py/persistentcode.c
index 09beeef451..ae69f99dea 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -69,6 +69,7 @@ typedef struct _bytecode_prelude_t {
#include "py/parsenum.h"
+}
static int read_byte(mp_reader_t *reader);
static size_t read_uint(mp_reader_t *reader);
@@ -476,6 +477,30 @@ void mp_raw_code_load_file(qstr filename, mp_compiled_module_t *context) {
#include "py/objstr.h"
+static void small_int_check(mp_obj_t o) {
+ #if MICROPY_DYNAMIC_COMPILER
+ if (!mp_dynamic_compiler.no_long_int) {
+ return;
+ }
+ if (!mp_obj_is_int(o)) {
+ return;
+ }
+ bool fail = false;
+ if (!mp_obj_is_small_int(o)) {
+ fail = true;
+ } else {
+ mp_int_t arg = MP_OBJ_SMALL_INT_VALUE(o);
+ mp_uint_t sign_mask = -((mp_uint_t)1 << (mp_dynamic_compiler.small_int_bits - 1));
+ if (!((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask)) {
+ fail = true;
+ }
+ }
+ if (fail) {
+ mp_raise_type(&mp_type_OverflowError);
+ }
+ #endif
+}
+
static void mp_print_bytes(mp_print_t *print, const byte *data, size_t len) {
print->print_strn(print->data, (const char *)data, len);
}
@@ -551,6 +576,7 @@ static void save_obj(mp_print_t *print, mp_obj_t o) {
byte obj_type;
if (mp_obj_is_int(o)) {
obj_type = MP_PERSISTENT_OBJ_INT;
+ small_int_check(o);
#if MICROPY_PY_BUILTINS_COMPLEX
} else if (mp_obj_is_type(o, &mp_type_complex)) {
obj_type = MP_PERSISTENT_OBJ_COMPLEX;
--
2.39.5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment