summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/compile.c3
-rw-r--r--py/emitglue.c74
-rw-r--r--py/emitglue.h1
-rw-r--r--py/obj.h1
-rw-r--r--py/objcomplex.c2
-rw-r--r--py/objexcept.c6
-rw-r--r--py/objgenerator.c2
-rw-r--r--py/runtime.c14
-rw-r--r--py/runtime.h4
-rw-r--r--py/showbc.c11
-rw-r--r--py/vm.c25
-rw-r--r--stmhal/exti.c3
-rw-r--r--stmhal/lcd.c11
-rw-r--r--tests/basics/exceptpoly.py48
14 files changed, 126 insertions, 79 deletions
diff --git a/py/compile.c b/py/compile.c
index b3a83715e0..48c9c08826 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -3312,7 +3312,8 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
return mp_const_true;
#else
// return function that executes the outer module
- return rt_make_function_from_id(unique_code_id, MP_OBJ_NULL);
+ // we can free the unique_code slot because no-one has reference to this unique_code_id anymore
+ return rt_make_function_from_id(unique_code_id, true, MP_OBJ_NULL);
#endif
}
}
diff --git a/py/emitglue.c b/py/emitglue.c
index 0ab9090924..47b1791eb7 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -1,6 +1,7 @@
// This code glues the code emitters to the runtime.
-#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
#include <assert.h>
#include "misc.h"
@@ -10,6 +11,7 @@
#include "runtime0.h"
#include "runtime.h"
#include "emitglue.h"
+#include "bc.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -22,7 +24,8 @@
#endif
typedef enum {
- MP_CODE_NONE,
+ MP_CODE_UNUSED,
+ MP_CODE_RESERVED,
MP_CODE_BYTE,
MP_CODE_NATIVE,
MP_CODE_INLINE_ASM,
@@ -48,39 +51,62 @@ typedef struct _mp_code_t {
} mp_code_t;
STATIC machine_uint_t unique_codes_alloc = 0;
+STATIC machine_uint_t unique_codes_total = 0; // always >= unique_codes_alloc
STATIC mp_code_t *unique_codes = NULL;
-STATIC uint next_unique_code_id;
+
+#ifdef WRITE_CODE
+FILE *fp_write_code = NULL;
+#endif
void mp_emit_glue_init(void) {
- next_unique_code_id = 0;
unique_codes_alloc = 0;
+ unique_codes_total = 0;
unique_codes = NULL;
+
+#ifdef WRITE_CODE
+ fp_write_code = fopen("out-code", "wb");
+#endif
}
void mp_emit_glue_deinit(void) {
+#ifdef WRITE_CODE
+ if (fp_write_code != NULL) {
+ fclose(fp_write_code);
+ }
+#endif
+
m_del(mp_code_t, unique_codes, unique_codes_alloc);
}
uint mp_emit_glue_get_unique_code_id(void) {
- return next_unique_code_id++;
+ // look for an existing unused slot
+ for (uint i = 0; i < unique_codes_alloc; i++) {
+ if (unique_codes[i].kind == MP_CODE_UNUSED) {
+ unique_codes[i].kind = MP_CODE_RESERVED;
+ return i;
+ }
+ }
+ // no existing slot
+ // return next available id, memory will be allocated later
+ return unique_codes_total++;
}
STATIC void mp_emit_glue_alloc_unique_codes(void) {
- if (next_unique_code_id > unique_codes_alloc) {
- DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id);
- // increase size of unique_codes table
- unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id);
- for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) {
- unique_codes[i].kind = MP_CODE_NONE;
+ if (unique_codes_total > unique_codes_alloc) {
+ DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, unique_codes_total);
+ // increase size of unique_codes table (all new entries are already reserved)
+ unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, unique_codes_total);
+ for (uint i = unique_codes_alloc; i < unique_codes_total; i++) {
+ unique_codes[i].kind = MP_CODE_RESERVED;
}
- unique_codes_alloc = next_unique_code_id;
+ unique_codes_alloc = unique_codes_total;
}
}
void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) {
mp_emit_glue_alloc_unique_codes();
- assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
+ assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
unique_codes[unique_code_id].scope_flags = scope_flags;
unique_codes[unique_code_id].n_args = n_args;
@@ -108,7 +134,7 @@ void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, in
void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
mp_emit_glue_alloc_unique_codes();
- assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
+ assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
unique_codes[unique_code_id].scope_flags = 0;
unique_codes[unique_code_id].n_args = n_args;
@@ -139,7 +165,7 @@ void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, i
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
mp_emit_glue_alloc_unique_codes();
- assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
+ assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
unique_codes[unique_code_id].scope_flags = 0;
unique_codes[unique_code_id].n_args = n_args;
@@ -164,9 +190,9 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
#endif
}
-mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
+mp_obj_t rt_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args) {
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
- if (unique_code_id >= next_unique_code_id) {
+ if (unique_code_id >= unique_codes_total) {
// illegal code id
return mp_const_none;
}
@@ -185,8 +211,9 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
break;
default:
+ // code id was never assigned (this should not happen)
assert(0);
- fun = mp_const_none;
+ return mp_const_none;
}
// check for generator functions and if so wrap in generator object
@@ -194,13 +221,20 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
fun = mp_obj_new_gen_wrap(fun);
}
+ // in some cases we can free the unique_code slot
+ // any dynamically allocade memory is now owned by the fun object
+ if (free_unique_code) {
+ memset(c, 0, sizeof *c); // make sure all pointers are zeroed
+ c->kind = MP_CODE_UNUSED;
+ }
+
return fun;
}
-mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) {
+mp_obj_t rt_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) {
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
// make function object
- mp_obj_t ffun = rt_make_function_from_id(unique_code_id, def_args);
+ mp_obj_t ffun = rt_make_function_from_id(unique_code_id, false, def_args);
// wrap function in closure object
return mp_obj_new_closure(ffun, closure_tuple);
}
diff --git a/py/emitglue.h b/py/emitglue.h
index e06578e220..8f69951c21 100644
--- a/py/emitglue.h
+++ b/py/emitglue.h
@@ -3,7 +3,6 @@
void mp_emit_glue_init(void);
void mp_emit_glue_deinit(void);
uint mp_emit_glue_get_unique_code_id(void);
-uint mp_emit_glue_get_unique_code(uint unique_code_id);
void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names);
void mp_emit_glue_assign_native_code(uint unique_code_id, void *f, uint len, int n_args);
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args);
diff --git a/py/obj.h b/py/obj.h
index af38253c56..500ffbdc04 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -231,6 +231,7 @@ extern const mp_obj_t mp_const_false;
extern const mp_obj_t mp_const_true;
extern const mp_obj_t mp_const_empty_tuple;
extern const mp_obj_t mp_const_ellipsis;
+extern const mp_obj_t mp_const_GeneratorExit;
// General API for objects
diff --git a/py/objcomplex.c b/py/objcomplex.c
index 91f6b081e3..c2b9d49104 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -30,7 +30,7 @@ STATIC void complex_print(void (*print)(void *env, const char *fmt, ...), void *
char buf[32];
if (o->real == 0) {
format_float(o->imag, buf, sizeof(buf), 'g', 6, '\0');
- print(env, "%s", buf);
+ print(env, "%sj", buf);
} else {
format_float(o->real, buf, sizeof(buf), 'g', 6, '\0');
print(env, "(%s+", buf);
diff --git a/py/objexcept.c b/py/objexcept.c
index 71874751b2..d4c4b12492 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -21,6 +21,12 @@ typedef struct mp_obj_exception_t {
mp_obj_tuple_t args;
} mp_obj_exception_t;
+// Instance of GeneratorExit exception - needed by generator.close()
+// This would belong to objgenerator.c, but to keep mp_obj_exception_t
+// definition module-private so far, have it here.
+STATIC mp_obj_exception_t GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, NULL, {{&tuple_type}, 0}};
+const mp_obj_t mp_const_GeneratorExit = (mp_obj_t)&GeneratorExit_obj;
+
STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_exception_t *o = o_in;
if (o->msg != NULL) {
diff --git a/py/objgenerator.c b/py/objgenerator.c
index aeb5f6219a..f6c7007a02 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -171,7 +171,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_ins
STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {
mp_obj_t ret;
- switch (mp_obj_gen_resume(self_in, mp_const_none, (mp_obj_t)&mp_type_GeneratorExit, &ret)) {
+ switch (mp_obj_gen_resume(self_in, mp_const_none, mp_const_GeneratorExit, &ret)) {
case MP_VM_RETURN_YIELD:
nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"));
diff --git a/py/runtime.c b/py/runtime.c
index 762924c20a..3f637a16f9 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -20,7 +20,6 @@
#if 0 // print debugging info
#define DEBUG_PRINT (1)
-#define WRITE_CODE (1)
#define DEBUG_printf DEBUG_printf
#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__)
#else // don't print debugging info
@@ -33,10 +32,6 @@ STATIC mp_map_t *map_locals;
STATIC mp_map_t *map_globals;
STATIC mp_map_t map_builtins;
-#ifdef WRITE_CODE
-FILE *fp_write_code = NULL;
-#endif
-
// a good optimising compiler will inline this if necessary
STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) {
mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
@@ -68,18 +63,9 @@ void rt_init(void) {
// for efficiency, left to platform-specific startup code
//sys_path = mp_obj_new_list(0, NULL);
//rt_store_attr(m_sys, MP_QSTR_path, sys_path);
-
-#ifdef WRITE_CODE
- fp_write_code = fopen("out-code", "wb");
-#endif
}
void rt_deinit(void) {
-#ifdef WRITE_CODE
- if (fp_write_code != NULL) {
- fclose(fp_write_code);
- }
-#endif
mp_map_free(map_globals);
mp_map_deinit(&map_builtins);
mp_module_deinit();
diff --git a/py/runtime.h b/py/runtime.h
index b27d12ff1d..a8f83e529d 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -18,11 +18,11 @@ void rt_store_global(qstr qstr, mp_obj_t obj);
void rt_delete_name(qstr qstr);
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
-mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args);
+mp_obj_t rt_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args);
mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments
mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun);
mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive
-mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args);
+mp_obj_t rt_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args);
mp_obj_t rt_call_function_0(mp_obj_t fun);
mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg);
mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
diff --git a/py/showbc.c b/py/showbc.c
index d4382de440..12bd901185 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -30,7 +30,16 @@ void mp_byte_code_print(const byte *ip, int len) {
machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
ip += code_info_size;
- // decode prelude
+ // bytecode prelude: state size and exception stack size; 16 bit uints
+ {
+ uint n_state = ip[0] | (ip[1] << 8);
+ uint n_exc_stack = ip[2] | (ip[3] << 8);
+ ip += 4;
+ printf("(N_STATE %u)\n", n_state);
+ printf("(N_EXC_STACK %u)\n", n_exc_stack);
+ }
+
+ // bytecode prelude: initialise closed over variables
{
uint n_local = *ip++;
printf("(NUM_LOCAL %u)\n", n_local);
diff --git a/py/vm.c b/py/vm.c
index 607f48cf79..1a1d345b2a 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -45,6 +45,14 @@ typedef enum {
#define TOP() (*sp)
#define SET_TOP(val) *sp = (val)
+#define SETUP_BLOCK() \
+ DECODE_ULABEL; /* except labels are always forward */ \
+ ++exc_sp; \
+ exc_sp->opcode = op; \
+ exc_sp->handler = ip + unum; \
+ exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
+ currently_in_except_block = 0; /* in a try block now */
+
mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret) {
const byte *ip = code;
@@ -401,12 +409,7 @@ unwind_jump:
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
case MP_BC_SETUP_EXCEPT:
case MP_BC_SETUP_FINALLY:
- DECODE_ULABEL; // except labels are always forward
- ++exc_sp;
- exc_sp->opcode = op;
- exc_sp->handler = ip + unum;
- exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block);
- currently_in_except_block = 0; // in a try block now
+ SETUP_BLOCK();
break;
case MP_BC_END_FINALLY:
@@ -415,8 +418,8 @@ unwind_jump:
// if TOS is None, just pops it and continues
// if TOS is an integer, does something else
// else error
- if (mp_obj_is_exception_instance(TOP())) {
- nlr_jump(TOP());
+ if (mp_obj_is_exception_type(TOP())) {
+ nlr_jump(sp[-1]);
}
if (TOP() == mp_const_none) {
sp--;
@@ -563,12 +566,12 @@ unwind_jump:
case MP_BC_MAKE_FUNCTION:
DECODE_UINT;
- PUSH(rt_make_function_from_id(unum, MP_OBJ_NULL));
+ PUSH(rt_make_function_from_id(unum, false, MP_OBJ_NULL));
break;
case MP_BC_MAKE_FUNCTION_DEFARGS:
DECODE_UINT;
- SET_TOP(rt_make_function_from_id(unum, TOP()));
+ SET_TOP(rt_make_function_from_id(unum, false, TOP()));
break;
case MP_BC_MAKE_CLOSURE:
@@ -769,7 +772,7 @@ yield:
// push(traceback, exc-val, exc-type)
PUSH(mp_const_none);
PUSH(nlr.ret_val);
- PUSH(nlr.ret_val); // TODO should be type(nlr.ret_val), I think...
+ PUSH(mp_obj_get_type(nlr.ret_val));
} else {
// propagate exception to higher level
diff --git a/stmhal/exti.c b/stmhal/exti.c
index c5378d835e..e5e9b53bda 100644
--- a/stmhal/exti.c
+++ b/stmhal/exti.c
@@ -66,6 +66,8 @@
// There is also a C API, so that drivers which require EXTI interrupt lines
// can also use this code. See exti.h for the available functions and
// usrsw.h for an example of using this.
+//
+// TODO Add python method to change callback object.
#define EXTI_OFFSET (EXTI_BASE - PERIPH_BASE)
@@ -302,6 +304,7 @@ void Handle_EXTI_Irq(uint32_t line) {
if (line < EXTI_NUM_VECTORS) {
exti_vector_t *v = &exti_vector[line];
if (v->callback_obj != mp_const_none) {
+ // TODO need to wrap this in an nlr_buf; really need a general function for this
rt_call_function_1(v->callback_obj, MP_OBJ_NEW_SMALL_INT(line));
}
}
diff --git a/stmhal/lcd.c b/stmhal/lcd.c
index d2db7b7ba1..c5952fa48c 100644
--- a/stmhal/lcd.c
+++ b/stmhal/lcd.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
#include <string.h>
#include <stm32f4xx_hal.h>
@@ -59,8 +60,12 @@
#define LCD_INSTR (0)
#define LCD_DATA (1)
+static void lcd_delay(void) {
+ __asm volatile ("nop\nnop");
+}
+
static void lcd_out(int instr_data, uint8_t i) {
- HAL_Delay(0);
+ lcd_delay();
PYB_LCD_PORT->BSRRH = PYB_LCD_CS1_PIN; // CS=0; enable
if (instr_data == LCD_INSTR) {
PYB_LCD_PORT->BSRRH = PYB_LCD_A0_PIN; // A0=0; select instr reg
@@ -69,7 +74,7 @@ static void lcd_out(int instr_data, uint8_t i) {
}
// send byte bigendian, latches on rising clock
for (uint32_t n = 0; n < 8; n++) {
- HAL_Delay(0);
+ lcd_delay();
PYB_LCD_PORT->BSRRH = PYB_LCD_SCL_PIN; // SCL=0
if ((i & 0x80) == 0) {
PYB_LCD_PORT->BSRRH = PYB_LCD_SI_PIN; // SI=0
@@ -77,7 +82,7 @@ static void lcd_out(int instr_data, uint8_t i) {
PYB_LCD_PORT->BSRRL = PYB_LCD_SI_PIN; // SI=1
}
i <<= 1;
- HAL_Delay(0);
+ lcd_delay();
PYB_LCD_PORT->BSRRL = PYB_LCD_SCL_PIN; // SCL=1
}
PYB_LCD_PORT->BSRRL = PYB_LCD_CS1_PIN; // CS=1; disable
diff --git a/tests/basics/exceptpoly.py b/tests/basics/exceptpoly.py
index b2fc11afbe..599a72b2a2 100644
--- a/tests/basics/exceptpoly.py
+++ b/tests/basics/exceptpoly.py
@@ -28,15 +28,15 @@ try:
except AttributeError:
print("Caught AttributeError")
-try:
- raise BufferError
-except Exception:
- print("Caught BufferError via Exception")
+#try:
+# raise BufferError
+#except Exception:
+# print("Caught BufferError via Exception")
-try:
- raise BufferError
-except BufferError:
- print("Caught BufferError")
+#try:
+# raise BufferError
+#except BufferError:
+# print("Caught BufferError")
#try:
# raise BytesWarning
@@ -88,15 +88,15 @@ try:
except Exception:
print("Caught Exception")
-try:
- raise FloatingPointError
-except ArithmeticError:
- print("Caught FloatingPointError via ArithmeticError")
+#try:
+# raise FloatingPointError
+#except ArithmeticError:
+# print("Caught FloatingPointError via ArithmeticError")
-try:
- raise FloatingPointError
-except FloatingPointError:
- print("Caught FloatingPointError")
+#try:
+# raise FloatingPointError
+#except FloatingPointError:
+# print("Caught FloatingPointError")
#try:
# raise FutureWarning
@@ -328,15 +328,15 @@ try:
except TypeError:
print("Caught TypeError")
-try:
- raise UnboundLocalError
-except NameError:
- print("Caught UnboundLocalError via NameError")
+#try:
+# raise UnboundLocalError
+#except NameError:
+# print("Caught UnboundLocalError via NameError")
-try:
- raise UnboundLocalError
-except UnboundLocalError:
- print("Caught UnboundLocalError")
+#try:
+# raise UnboundLocalError
+#except UnboundLocalError:
+# print("Caught UnboundLocalError")
#try:
# raise UserWarning