diff options
-rw-r--r-- | py/compile.c | 3 | ||||
-rw-r--r-- | py/emitglue.c | 74 | ||||
-rw-r--r-- | py/emitglue.h | 1 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objcomplex.c | 2 | ||||
-rw-r--r-- | py/objexcept.c | 6 | ||||
-rw-r--r-- | py/objgenerator.c | 2 | ||||
-rw-r--r-- | py/runtime.c | 14 | ||||
-rw-r--r-- | py/runtime.h | 4 | ||||
-rw-r--r-- | py/showbc.c | 11 | ||||
-rw-r--r-- | py/vm.c | 25 | ||||
-rw-r--r-- | stmhal/exti.c | 3 | ||||
-rw-r--r-- | stmhal/lcd.c | 11 | ||||
-rw-r--r-- | tests/basics/exceptpoly.py | 48 |
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); @@ -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); @@ -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 |