diff options
| author | Glenn Ruben Bakke <glennbakke@gmail.com> | 2017-04-09 17:45:32 +0200 |
|---|---|---|
| committer | Glenn Ruben Bakke <glennbakke@gmail.com> | 2017-04-09 17:45:32 +0200 |
| commit | 360243af92bd096522153521bce323f60bdb1b80 (patch) | |
| tree | e3b0e94099da7ce5e9d895e22e02435c61f205e0 /py | |
| parent | 5d06aa32609959115b496ac0e596438bfdbda038 (diff) | |
| parent | b87432b8fb8332548be11b63c9139065ce565f91 (diff) | |
Merge branch 'master' into nrf5_no_sdk
Diffstat (limited to 'py')
48 files changed, 630 insertions, 437 deletions
diff --git a/py/argcheck.c b/py/argcheck.c index 8cef10b16..9f225345d 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -37,7 +37,7 @@ void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - mp_raise_msg(&mp_type_TypeError, "function does not take keyword arguments"); + mp_raise_TypeError("function does not take keyword arguments"); } } @@ -115,7 +115,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - mp_raise_msg(&mp_type_TypeError, "extra positional arguments given"); + mp_raise_TypeError("extra positional arguments given"); } } if (kws_found < kws->used) { @@ -123,7 +123,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - mp_raise_msg(&mp_type_TypeError, "extra keyword arguments given"); + mp_raise_TypeError("extra keyword arguments given"); } } } @@ -136,7 +136,7 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || _MSC_VER NORETURN void mp_arg_error_terse_mismatch(void) { - mp_raise_msg(&mp_type_TypeError, "argument num/types mismatch"); + mp_raise_TypeError("argument num/types mismatch"); } #endif @@ -54,6 +54,16 @@ mp_uint_t mp_decode_uint(const byte **ptr) { return unum; } +// This function is used to help reduce stack usage at the caller, for the case when +// the caller doesn't need to increase the ptr argument. If ptr is a local variable +// and the caller uses mp_decode_uint(&ptr) instead of this function, then the compiler +// must allocate a slot on the stack for ptr, and this slot cannot be reused for +// anything else in the function because the pointer may have been stored in a global +// and reused later in the function. +mp_uint_t mp_decode_uint_value(const byte *ptr) { + return mp_decode_uint(&ptr); +} + STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues @@ -86,25 +96,26 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // On entry code_state should be allocated somewhere (stack/heap) and // contain the following valid entries: -// - code_state->ip should contain the offset in bytes from the start of -// the bytecode chunk to just after n_state and n_exc_stack -// - code_state->n_state should be set to the state size (locals plus stack) -void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { +// - code_state->fun_bc should contain a pointer to the function object +// - code_state->ip should contain the offset in bytes from the pointer +// code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native) +void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. - size_t n_state = code_state->n_state; + + // get the function object that we want to set up (could be bytecode or native code) + mp_obj_fun_bc_t *self = code_state->fun_bc; // ip comes in as an offset into bytecode, so turn it into a true pointer code_state->ip = self->bytecode + (size_t)code_state->ip; - // store pointer to constant table - code_state->const_table = self->const_table; - #if MICROPY_STACKLESS code_state->prev = NULL; #endif // get params + size_t n_state = mp_decode_uint(&code_state->ip); + mp_decode_uint(&code_state->ip); // skip n_exc_stack size_t scope_flags = *code_state->ip++; size_t n_pos_args = *code_state->ip++; size_t n_kwonly_args = *code_state->ip++; @@ -168,7 +179,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, siz } // get pointer to arg_names array - const mp_obj_t *arg_names = (const mp_obj_t*)code_state->const_table; + const mp_obj_t *arg_names = (const mp_obj_t*)self->const_table; for (size_t i = 0; i < n_kw; i++) { // the keys in kwargs are expected to be qstr objects @@ -185,7 +196,12 @@ void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, siz } // Didn't find name match with positional args if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { - mp_raise_msg(&mp_type_TypeError, "function does not take keyword arguments"); + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_TypeError("unexpected keyword argument"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "unexpected keyword argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name))); + } } mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); continue2:; @@ -234,7 +250,7 @@ continue2:; } else { // no keyword arguments given if (n_kwonly_args != 0) { - mp_raise_msg(&mp_type_TypeError, "function missing keyword-only argument"); + mp_raise_TypeError("function missing keyword-only argument"); } if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { *var_pos_kw_args = mp_obj_new_dict(0); @@ -244,13 +260,8 @@ continue2:; // get the ip and skip argument names const byte *ip = code_state->ip; - // store pointer to code_info and jump over it - { - code_state->code_info = ip; - const byte *ip2 = ip; - size_t code_info_size = mp_decode_uint(&ip2); - ip += code_info_size; - } + // jump over code info (source file and line-number mapping) + ip += mp_decode_uint_value(ip); // bytecode prelude: initialise closed over variables size_t local_num; @@ -28,6 +28,7 @@ #include "py/runtime.h" #include "py/obj.h" +#include "py/objfun.h" // bytecode layout: // @@ -70,9 +71,12 @@ typedef struct _mp_exc_stack_t { } mp_exc_stack_t; typedef struct _mp_code_state_t { - const byte *code_info; + // The fun_bc entry points to the underlying function object that is being executed. + // It is needed to access the start of bytecode and the const_table. + // It is also needed to prevent the GC from reclaiming the bytecode during execution, + // because the ip pointer below will always point to the interior of the bytecode. + mp_obj_fun_bc_t *fun_bc; const byte *ip; - const mp_uint_t *const_table; mp_obj_t *sp; // bit 0 is saved currently_in_except_block value mp_exc_stack_t *exc_sp; @@ -80,7 +84,6 @@ typedef struct _mp_code_state_t { #if MICROPY_STACKLESS struct _mp_code_state_t *prev; #endif - size_t n_state; // Variable-length mp_obj_t state[0]; // Variable-length, never accessed by name, only as (void*)(state + n_state) @@ -88,11 +91,11 @@ typedef struct _mp_code_state_t { } mp_code_state_t; mp_uint_t mp_decode_uint(const byte **ptr); +mp_uint_t mp_decode_uint_value(const byte *ptr); mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); -struct _mp_obj_fun_bc_t; -void mp_setup_code_state(mp_code_state_t *code_state, struct _mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); void mp_bytecode_print2(const byte *code, size_t len, const mp_uint_t *const_table); const byte *mp_bytecode_print_str(const byte *ip); diff --git a/py/builtinevex.c b/py/builtinevex.c index b0514ee99..d9a3833cc 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -78,7 +78,7 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { (void)n_args; // get the source - mp_uint_t str_len; + size_t str_len; const char *str = mp_obj_str_get_data(args[0], &str_len); // get the filename @@ -95,7 +95,7 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break; case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break; default: - mp_raise_msg(&mp_type_ValueError, "bad compile mode"); + mp_raise_ValueError("bad compile mode"); } mp_obj_code_t *code = m_new_obj(mp_obj_code_t); @@ -128,7 +128,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i } #endif - mp_uint_t str_len; + size_t str_len; const char *str = mp_obj_str_get_data(args[0], &str_len); // create the lexer diff --git a/py/builtinimport.c b/py/builtinimport.c index 96846b963..cf17d5305 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -97,7 +97,7 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) { STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) { #if MICROPY_PY_SYS // extract the list of paths - mp_uint_t path_num; + size_t path_num; mp_obj_t *path_items; mp_obj_list_get(mp_sys_path, &path_num, &path_items); @@ -111,7 +111,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d // go through each path looking for a directory or file for (mp_uint_t i = 0; i < path_num; i++) { vstr_reset(dest); - mp_uint_t p_len; + size_t p_len; const char *p = mp_obj_str_get_data(path_items[i], &p_len); if (p_len > 0) { vstr_add_strn(dest, p, p_len); @@ -265,7 +265,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } } - mp_uint_t mod_len; + size_t mod_len; const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); if (level != 0) { @@ -296,7 +296,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("\n"); #endif - mp_uint_t this_name_l; + size_t this_name_l; const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l); const char *p = this_name + this_name_l; @@ -341,7 +341,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); if (new_mod_q == MP_QSTR_) { - mp_raise_msg(&mp_type_ValueError, "cannot perform relative import"); + mp_raise_ValueError("cannot perform relative import"); } module_name = MP_OBJ_NEW_QSTR(new_mod_q); mod_str = new_mod; diff --git a/py/compile.c b/py/compile.c index ca21d8294..cf9e5079b 100644 --- a/py/compile.c +++ b/py/compile.c @@ -456,8 +456,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ break; } } else { - compile_syntax_error(comp, pn, "can't assign to literal"); - return; + goto cannot_assign; } } else { // pn must be a struct @@ -472,7 +471,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ case PN_exprlist: // lhs is a tuple if (assign_kind != ASSIGN_STORE) { - goto bad_aug; + goto cannot_assign; } c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes); break; @@ -485,7 +484,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); if (assign_kind != ASSIGN_STORE) { - goto bad_aug; + goto cannot_assign; } pns = (mp_parse_node_struct_t*)pns->nodes[0]; goto testlist_comp; @@ -495,7 +494,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ case PN_atom_bracket: // lhs is something in brackets if (assign_kind != ASSIGN_STORE) { - goto bad_aug; + goto cannot_assign; } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty list, assignment allowed @@ -543,10 +542,6 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ cannot_assign: compile_syntax_error(comp, pn, "can't assign to expression"); - return; - - bad_aug: - compile_syntax_error(comp, pn, "illegal expression for augmented assignment"); } // stuff for lambda and comprehensions and generators: @@ -1449,8 +1444,9 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { pn_range_start = args[0]; pn_range_end = args[1]; pn_range_step = args[2]; - // We need to know sign of step. This is possible only if it's constant - if (!MP_PARSE_NODE_IS_SMALL_INT(pn_range_step)) { + // the step must be a non-zero constant integer to do the optimisation + if (!MP_PARSE_NODE_IS_SMALL_INT(pn_range_step) + || MP_PARSE_NODE_LEAF_SMALL_INT(pn_range_step) == 0) { optimize = false; } } @@ -1529,7 +1525,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { // this is a catch all exception handler if (i + 1 != n_except) { - compile_syntax_error(comp, pn_excepts[i], "default 'except:' must be last"); + compile_syntax_error(comp, pn_excepts[i], "default 'except' must be last"); compile_decrease_except_level(comp); return; } @@ -2190,9 +2186,10 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar compile_load_id(comp, MP_QSTR___class__); // look for first argument to function (assumes it's "self") for (int i = 0; i < comp->scope_cur->id_info_len; i++) { - if (comp->scope_cur->id_info[i].flags & ID_FLAG_IS_PARAM) { + id_info_t *id = &comp->scope_cur->id_info[i]; + if (id->flags & ID_FLAG_IS_PARAM) { // first argument found; load it and call super - EMIT_LOAD_FAST(MP_QSTR_, comp->scope_cur->id_info[i].local_num); + compile_load_id(comp, id->qst); EMIT_ARG(call_function, 2, 0, 0); return; } @@ -2437,13 +2434,21 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pn_i); if (is_dict) { if (!is_key_value) { - compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dictionary"); + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "invalid syntax"); + } else { + compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dict"); + } return; } EMIT(store_map); } else { if (is_key_value) { - compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting just a value for set"); + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + compile_syntax_error(comp, (mp_parse_node_t)pns, "invalid syntax"); + } else { + compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting just a value for set"); + } return; } } @@ -3005,6 +3010,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { // There are 4 slots on the stack for the iterator, and the first one is // NULL to indicate that the second one points to the iterator object. if (scope->kind == SCOPE_GEN_EXPR) { + // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4 EMIT(load_null); compile_load_id(comp, qstr_arg); EMIT(load_null); diff --git a/py/emitbc.c b/py/emitbc.c index 0076c147e..673cd405f 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -735,7 +735,7 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept // need to pop the iterator if we are breaking out of a for loop emit_write_bytecode_byte(emit, MP_BC_POP_TOP); // also pop the iter_buf - for (size_t i = 0; i < sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t) - 1; ++i) { + for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) { emit_write_bytecode_byte(emit, MP_BC_POP_TOP); } } @@ -778,7 +778,7 @@ void mp_emit_bc_end_finally(emit_t *emit) { } void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) { - emit_bc_pre(emit, use_stack ? sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t) - 1 : 0); + emit_bc_pre(emit, use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0); emit_write_bytecode_byte(emit, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER); } @@ -788,7 +788,7 @@ void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) { } void mp_emit_bc_for_iter_end(emit_t *emit) { - emit_bc_pre(emit, -(sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t))); + emit_bc_pre(emit, -MP_OBJ_ITER_BUF_NSLOTS); } void mp_emit_bc_pop_block(emit_t *emit) { diff --git a/py/emitnative.c b/py/emitnative.c index 55eb6cadf..3ab001f8d 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -407,43 +407,29 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop #endif // prepare incoming arguments for call to mp_setup_code_state + #if N_X86 - asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_2); - asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_3); - asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_4); - asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_5); - #else - #if N_THUMB - ASM_MOV_REG_REG(emit->as, ASM_THUMB_REG_R4, REG_ARG_4); - #elif N_ARM - ASM_MOV_REG_REG(emit->as, ASM_ARM_REG_R4, REG_ARG_4); - #else - ASM_MOV_REG_REG(emit->as, REG_ARG_5, REG_ARG_4); - #endif - ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_ARG_3); - ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_ARG_2); - ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_3); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_4); #endif + // set code_state.fun_bc + ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_1, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)); + // set code_state.ip (offset from start of this function to prelude info) // XXX this encoding may change size - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(mp_uint_t), REG_ARG_1); - - // set code_state.n_state - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state_t, n_state) / sizeof(mp_uint_t), REG_ARG_1); + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), REG_ARG_1); // put address of code_state into first arg ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); // call mp_setup_code_state to prepare code_state structure #if N_THUMB - asm_thumb_op16(emit->as, 0xb400 | (1 << ASM_THUMB_REG_R4)); // push 5th arg asm_thumb_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4); - asm_thumb_op16(emit->as, 0xbc00 | (1 << REG_RET)); // pop dummy (was 5th arg) #elif N_ARM - asm_arm_push(emit->as, 1 << ASM_ARM_REG_R4); // push 5th arg asm_arm_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_ARM_REG_R4); - asm_arm_pop(emit->as, 1 << REG_RET); // pop dummy (was 5th arg) #else ASM_CALL_IND(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE); #endif @@ -477,6 +463,9 @@ STATIC void emit_native_end_pass(emit_t *emit) { if (!emit->do_viper_types) { emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base); + mp_asm_base_data(&emit->as->base, 1, 0x80 | ((emit->n_state >> 7) & 0x7f)); + mp_asm_base_data(&emit->as->base, 1, emit->n_state & 0x7f); + mp_asm_base_data(&emit->as->base, 1, 0); // n_exc_stack mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args); @@ -1772,7 +1761,7 @@ STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { emit_pre_pop_reg(emit, &vtype, REG_ARG_1); assert(vtype == VTYPE_PYOBJ); if (use_stack) { - emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t)); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_GETITER); } else { // mp_getiter will allocate the iter_buf on the heap @@ -1784,8 +1773,8 @@ STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t)); - adjust_stack(emit, 4); + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); + adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_ITERNEXT); ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1); ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); @@ -1795,7 +1784,7 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { STATIC void emit_native_for_iter_end(emit_t *emit) { // adjust stack counter (we get here from for_iter ending, which popped the value for us) emit_native_pre(emit); - adjust_stack(emit, -(sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t))); + adjust_stack(emit, -MP_OBJ_ITER_BUF_NSLOTS); emit_post(emit); } diff --git a/py/lexer.c b/py/lexer.c index fadaee6f3..05651abec 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -159,7 +159,6 @@ STATIC void next_char(mp_lexer_t *lex) { STATIC void indent_push(mp_lexer_t *lex, size_t indent) { if (lex->num_indent_level >= lex->alloc_indent_level) { - // TODO use m_renew_maybe and somehow indicate an error if it fails... probably by using MP_TOKEN_MEMORY_ERROR lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC); lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC; } @@ -177,7 +176,6 @@ STATIC void indent_pop(mp_lexer_t *lex) { // some tricky operator encoding: // <op> = begin with <op>, if this opchar matches then begin here // e<op> = end with <op>, if this opchar matches then end -// E<op> = mandatory end with <op>, this opchar must match, then end // c<op> = continue with <op>, if this opchar matches then continue matching // this means if the start of two ops are the same then they are equal til the last char @@ -194,7 +192,7 @@ STATIC const char *const tok_enc = "%e=" // % %= "^e=" // ^ ^= "=e=" // = == - "!E="; // != + "!."; // start of special cases: != . ... // TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries STATIC const uint8_t tok_enc_kind[] = { @@ -214,7 +212,6 @@ STATIC const uint8_t tok_enc_kind[] = { MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL, MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL, MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL, - MP_TOKEN_OP_NOT_EQUAL, }; // must have the same order as enum in lexer.h @@ -604,20 +601,6 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } } - } else if (is_char(lex, '.')) { - // special handling for . and ... operators, because .. is not a valid operator - - // get first char - next_char(lex); - - if (is_char_and(lex, '.', '.')) { - next_char(lex); - next_char(lex); - lex->tok_kind = MP_TOKEN_ELLIPSIS; - } else { - lex->tok_kind = MP_TOKEN_DEL_PERIOD; - } - } else { // search for encoded delimiter or operator @@ -626,9 +609,6 @@ void mp_lexer_to_next(mp_lexer_t *lex) { for (; *t != 0 && !is_char(lex, *t); t += 1) { if (*t == 'e' || *t == 'c') { t += 1; - } else if (*t == 'E') { - tok_enc_index -= 1; - t += 1; } tok_enc_index += 1; } @@ -639,55 +619,48 @@ void mp_lexer_to_next(mp_lexer_t *lex) { // didn't match any delimiter or operator characters lex->tok_kind = MP_TOKEN_INVALID; + } else if (*t == '!') { + // "!=" is a special case because "!" is not a valid operator + if (is_char(lex, '=')) { + next_char(lex); + lex->tok_kind = MP_TOKEN_OP_NOT_EQUAL; + } else { + lex->tok_kind = MP_TOKEN_INVALID; + } + + } else if (*t == '.') { + // "." and "..." are special cases because ".." is not a valid operator + if (is_char_and(lex, '.', '.')) { + next_char(lex); + next_char(lex); + lex->tok_kind = MP_TOKEN_ELLIPSIS; + } else { + lex->tok_kind = MP_TOKEN_DEL_PERIOD; + } + } else { // matched a delimiter or operator character // get the maximum characters for a valid token t += 1; size_t t_index = tok_enc_index; - for (;;) { - for (; *t == 'e'; t += 1) { - t += 1; - t_index += 1; - if (is_char(lex, *t)) { - next_char(lex); - tok_enc_index = t_index; - break; - } - } - - if (*t == 'E') { - t += 1; - if (is_char(lex, *t)) { - next_char(lex); - tok_enc_index = t_index; - } else { - lex->tok_kind = MP_TOKEN_INVALID; - goto tok_enc_no_match; - } - break; - } - - if (*t == 'c') { - t += 1; - t_index += 1; - if (is_char(lex, *t)) { - next_char(lex); - tok_enc_index = t_index; - t += 1; - } else { + while (*t == 'c' || *t == 'e') { + t_index += 1; + if (is_char(lex, t[1])) { + next_char(lex); + tok_enc_index = t_index; + if (*t == 'e') { break; } - } else { + } else if (*t == 'c') { break; } + t += 2; } // set token kind lex->tok_kind = tok_enc_kind[tok_enc_index]; - tok_enc_no_match: - // compute bracket level for implicit line joining if (lex->tok_kind == MP_TOKEN_DEL_PAREN_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACKET_OPEN || lex->tok_kind == MP_TOKEN_DEL_BRACE_OPEN) { lex->nested_bracket_level += 1; diff --git a/py/mkrules.mk b/py/mkrules.mk index bc6389144..2ba57e0ee 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -142,8 +142,15 @@ clean-prog: endif LIBMICROPYTHON = libmicropython.a + +# We can execute extra commands after library creation using +# LIBMICROPYTHON_EXTRA_CMD. This may be needed e.g. to integrate +# with 3rd-party projects which don't have proper dependency +# tracking. Then LIBMICROPYTHON_EXTRA_CMD can e.g. touch some +# other file to cause needed effect, e.g. relinking with new lib. lib $(LIBMICROPYTHON): $(OBJ) $(AR) rcs $(LIBMICROPYTHON) $^ + $(LIBMICROPYTHON_EXTRA_CMD) clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 13312d229..e8119456d 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -180,7 +180,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { str[3] = (c & 0x3F) | 0x80; len = 4; } else { - mp_raise_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"); + mp_raise_ValueError("chr() arg not in range(0x110000)"); } return mp_obj_new_str(str, len, true); #else @@ -189,7 +189,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { char str[1] = {ord}; return mp_obj_new_str(str, 1, true); } else { - mp_raise_msg(&mp_type_ValueError, "chr() arg not in range(256)"); + mp_raise_ValueError("chr() arg not in range(256)"); } #endif } @@ -289,7 +289,7 @@ STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t if (default_elem != NULL) { best_obj = default_elem->value; } else { - mp_raise_msg(&mp_type_ValueError, "arg is an empty sequence"); + mp_raise_ValueError("arg is an empty sequence"); } } return best_obj; @@ -336,7 +336,7 @@ STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE if (MP_OBJ_IS_STR(o_in)) { @@ -397,9 +397,9 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t * mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP); mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP); const char *sep_data = " "; - mp_uint_t sep_len = 1; + size_t sep_len = 1; const char *end_data = "\n"; - mp_uint_t end_len = 1; + size_t end_len = 1; if (sep_elem != NULL && sep_elem->value != mp_const_none) { sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len); } @@ -473,22 +473,16 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { mp_float_t val = mp_obj_get_float(o_in); mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig); // TODO may lead to overflow - mp_float_t rounded = MICROPY_FLOAT_C_FUN(round)(val * mult) / mult; + mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult; return mp_obj_new_float(rounded); } mp_float_t val = mp_obj_get_float(o_in); - mp_float_t rounded = MICROPY_FLOAT_C_FUN(round)(val); - mp_int_t r = rounded; - // make rounded value even if it was halfway between ints - if (val - rounded == 0.5) { - r = (r + 1) & (~1); - } else if (val - rounded == -0.5) { - r &= ~1; - } + mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val); + return mp_obj_new_int_from_float(rounded); #else mp_int_t r = mp_obj_get_int(o_in); -#endif return mp_obj_new_int(r); +#endif } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj, 1, 2, mp_builtin_round); @@ -510,7 +504,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { if (n_args > 1) { - mp_raise_msg(&mp_type_TypeError, "must use keyword argument for key function"); + mp_raise_TypeError("must use keyword argument for key function"); } mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args); mp_obj_list_sort(1, &self, kwargs); diff --git a/py/modmath.c b/py/modmath.c index 7c51eab03..ddab337d0 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -57,7 +57,7 @@ STATIC NORETURN void math_error(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); #define MATH_FUN_1_TO_INT(py_name, c_name) \ - STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { mp_int_t x = MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj)); return mp_obj_new_int(x); } \ + STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); #define MATH_FUN_1_ERRCOND(py_name, c_name, error_condition) \ diff --git a/py/modmicropython.c b/py/modmicropython.c index 675d169cc..a74e6aa3c 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -29,6 +29,7 @@ #include "py/mpstate.h" #include "py/builtin.h" #include "py/stackctrl.h" +#include "py/runtime.h" #include "py/gc.h" // Various builtins specific to MicroPython runtime, @@ -128,6 +129,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf); #endif +#if MICROPY_ENABLE_SCHEDULER +STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) { + if (!mp_sched_schedule(function, arg)) { + mp_raise_msg(&mp_type_RuntimeError, "schedule stack full"); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_schedule); +#endif + STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, @@ -151,6 +162,9 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) }, { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) }, #endif + #if MICROPY_ENABLE_SCHEDULER + { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython_globals_table); diff --git a/py/modthread.c b/py/modthread.c index dda9e9348..d0e71dad3 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -215,7 +215,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) thread_entry_args_t *th_args; // get positional arguments - mp_uint_t pos_args_len; + size_t pos_args_len; mp_obj_t *pos_args_items; mp_obj_get_array(args[1], &pos_args_len, &pos_args_items); @@ -227,7 +227,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) } else { // positional and keyword arguments if (mp_obj_get_type(args[2]) != &mp_type_dict) { - mp_raise_msg(&mp_type_TypeError, "expecting a dict for keyword args"); + mp_raise_TypeError("expecting a dict for keyword args"); } mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); diff --git a/py/mpconfig.h b/py/mpconfig.h index 7e3bd8bdb..06c19f72b 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -556,6 +556,15 @@ typedef double mp_float_t; #define MICROPY_CPYTHON_COMPAT (1) #endif +// Perform full checks as done by CPython. Disabling this +// may produce incorrect results, if incorrect data is fed, +// but should not lead to MicroPython crashes or similar +// grave issues (in other words, only user app should be, +// affected, not system). +#ifndef MICROPY_FULL_CHECKS +#define MICROPY_FULL_CHECKS (1) +#endif + // Whether POSIX-semantics non-blocking streams are supported #ifndef MICROPY_STREAMS_NON_BLOCK #define MICROPY_STREAMS_NON_BLOCK (0) @@ -616,6 +625,16 @@ typedef double mp_float_t; #define MICROPY_USE_INTERNAL_PRINTF (1) #endif +// Support for internal scheduler +#ifndef MICROPY_ENABLE_SCHEDULER +#define MICROPY_ENABLE_SCHEDULER (0) +#endif + +// Maximum number of entries in the scheduler +#ifndef MICROPY_SCHEDULER_DEPTH +#define MICROPY_SCHEDULER_DEPTH (4) +#endif + // Support for generic VFS sub-system #ifndef MICROPY_VFS #define MICROPY_VFS (0) @@ -1095,6 +1114,11 @@ typedef double mp_float_t; #define STATIC static #endif +// Number of bytes in a word +#ifndef BYTES_PER_WORD +#define BYTES_PER_WORD (sizeof(mp_uint_t)) +#endif + #define BITS_PER_BYTE (8) #define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD) // mp_int_t value with most significant bit set diff --git a/py/mpstate.h b/py/mpstate.h index 9e4f54ae5..0134dd8e8 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -50,6 +50,16 @@ typedef struct mp_dynamic_compiler_t { extern mp_dynamic_compiler_t mp_dynamic_compiler; #endif +// These are the values for sched_state +#define MP_SCHED_IDLE (1) +#define MP_SCHED_LOCKED (-1) +#define MP_SCHED_PENDING (0) // 0 so it's a quick check in the VM + +typedef struct _mp_sched_item_t { + mp_obj_t func; + mp_obj_t arg; +} mp_sched_item_t; + // This structure hold information about the memory allocation system. typedef struct _mp_state_mem_t { #if MICROPY_MEM_STATS @@ -129,6 +139,12 @@ typedef struct _mp_state_vm_t { // pending exception object (MP_OBJ_NULL if not pending) volatile mp_obj_t mp_pending_exception; + #if MICROPY_ENABLE_SCHEDULER + volatile int16_t sched_state; + uint16_t sched_sp; + mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; + #endif + // current exception being handled, for sys.exc_info() #if MICROPY_PY_SYS_EXC_INFO mp_obj_base_t *cur_exception; @@ -222,7 +238,6 @@ typedef struct _mp_state_ctx_t { extern mp_state_ctx_t mp_state_ctx; -#define MP_STATE_CTX(x) MP_STATE_THREAD(x) #define MP_STATE_VM(x) (mp_state_ctx.vm.x) #define MP_STATE_MEM(x) (mp_state_ctx.mem.x) diff --git a/py/nlrx86.c b/py/nlrx86.c index 07ba72628..58aaa1a57 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -49,10 +49,9 @@ unsigned int nlr_push(nlr_buf_t *nlr) { __asm volatile ( // Check for Zephyr, which uses a different calling convention // by default. - // TODO: Better check for Zephyr. // TODE: Better support for various x86 calling conventions // (unfortunately, __attribute__((naked)) is not supported on x86). - #ifndef CONFIG_SOC_IA32 + #ifndef __ZEPHYR__ "pop %ebp \n" // undo function's prelude #endif "mov 4(%esp), %edx \n" // load nlr_buf @@ -229,7 +229,7 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return mp_obj_int_get_checked(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "can't convert to int"); + mp_raise_TypeError("can't convert to int"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); @@ -279,7 +279,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) { return mp_obj_float_get(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "can't convert to float"); + mp_raise_TypeError("can't convert to float"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); @@ -310,7 +310,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { mp_obj_complex_get(arg, real, imag); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "can't convert to complex"); + mp_raise_TypeError("can't convert to complex"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); @@ -321,14 +321,14 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { #endif // note: returned value in *items may point to the interior of a GC block -void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { +void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) { if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) { mp_obj_list_get(o, len, items); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "expected tuple/list"); + mp_raise_TypeError("expected tuple/list"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); @@ -337,12 +337,12 @@ void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { } // note: returned value in *items may point to the interior of a GC block -void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) { - mp_uint_t seq_len; +void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) { + size_t seq_len; mp_obj_get_array(o, &seq_len, items); if (seq_len != len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ValueError, "tuple/list has wrong length"); + mp_raise_ValueError("tuple/list has wrong length"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", (int)len, (int)seq_len)); @@ -351,13 +351,13 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) { } // is_slice determines whether the index is a slice index -mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) { +size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) { mp_int_t i; if (MP_OBJ_IS_SMALL_INT(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "indices must be integers"); + mp_raise_TypeError("indices must be integers"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q indices must be integers, not %s", @@ -384,7 +384,9 @@ mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, } } } - return i; + + // By this point 0 <= i <= len and so fits in a size_t + return (size_t)i; } mp_obj_t mp_obj_id(mp_obj_t o_in) { @@ -410,7 +412,7 @@ mp_obj_t mp_obj_len(mp_obj_t o_in) { mp_obj_t len = mp_obj_len_maybe(o_in); if (len == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object has no len"); + mp_raise_TypeError("object has no len"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); @@ -451,7 +453,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } if (value == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object does not support item deletion"); + mp_raise_TypeError("object does not support item deletion"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base))); @@ -466,7 +468,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object does not support item assignment"); + mp_raise_TypeError("object does not support item assignment"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); @@ -500,7 +502,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { if (!mp_get_buffer(obj, bufinfo, flags)) { - mp_raise_msg(&mp_type_TypeError, "object with buffer protocol required"); + mp_raise_TypeError("object with buffer protocol required"); } } @@ -422,6 +422,10 @@ typedef struct _mp_obj_iter_buf_t { mp_obj_t buf[3]; } mp_obj_iter_buf_t; +// The number of slots that an mp_obj_iter_buf_t needs on the Python value stack. +// It's rounded up in case mp_obj_base_t is smaller than mp_obj_t (eg for OBJ_REPR_D). +#define MP_OBJ_ITER_BUF_NSLOTS ((sizeof(mp_obj_iter_buf_t) + sizeof(mp_obj_t) - 1) / sizeof(mp_obj_t)) + typedef void (*mp_print_fun_t)(const mp_print_t *print, mp_obj_t o, mp_print_kind_t kind); typedef mp_obj_t (*mp_make_new_fun_t)(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, size_t n_args, size_t n_kw, const mp_obj_t *args); @@ -672,9 +676,9 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif //qstr mp_obj_get_qstr(mp_obj_t arg); -void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items); // *items may point inside a GC block -void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items); // *items may point inside a GC block -mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice); +void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block +void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block +size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_id(mp_obj_t o_in); mp_obj_t mp_obj_len(mp_obj_t o_in); mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); // may return MP_OBJ_NULL @@ -708,12 +712,13 @@ void mp_init_emergency_exception_buf(void); bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2); qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated -const char *mp_obj_str_get_data(mp_obj_t self_in, mp_uint_t *len); +const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len); mp_obj_t mp_obj_str_intern(mp_obj_t str); void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes); #if MICROPY_PY_BUILTINS_FLOAT // float +static inline mp_int_t mp_float_hash(mp_float_t val) { return (mp_int_t)val; } mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported // complex @@ -724,7 +729,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t #endif // tuple -void mp_obj_tuple_get(mp_obj_t self_in, mp_uint_t *len, mp_obj_t **items); +void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); @@ -733,7 +738,7 @@ struct _mp_obj_list_t; void mp_obj_list_init(struct _mp_obj_list_t *o, size_t n); 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, mp_uint_t *len, mp_obj_t **items); +void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); void mp_obj_list_set_len(mp_obj_t self_in, size_t len); void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); @@ -819,17 +824,17 @@ typedef struct { mp_int_t step; } mp_bound_slice_t; -void mp_seq_multiply(const void *items, mp_uint_t item_sz, mp_uint_t len, mp_uint_t times, void *dest); +void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest); #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); #endif #define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t)) #define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); } -bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, mp_uint_t len1, const byte *data2, mp_uint_t len2); -bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const mp_obj_t *items2, mp_uint_t len2); -mp_obj_t mp_seq_index_obj(const mp_obj_t *items, mp_uint_t len, mp_uint_t n_args, const mp_obj_t *args); -mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value); -mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes); +bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2); +bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2); +mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args); +mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value); +mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes); // Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems #define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz)) #define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \ @@ -838,9 +843,10 @@ mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice /*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * (item_sz));*/ \ memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), (dest_len - end) * (item_sz)); +// Note: dest and slice regions may overlap #define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \ /*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * (item_sz));*/ \ - memmove(((char*)dest) + (beg + len_adj) * (item_sz), ((char*)dest) + (beg) * (item_sz), (dest_len - beg) * (item_sz)); \ - memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); + memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \ + memmove(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); #endif // __MICROPY_INCLUDED_PY_OBJ_H__ diff --git a/py/objarray.c b/py/objarray.c index a84a63151..21479a800 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -162,8 +162,7 @@ STATIC mp_obj_t array_make_new(const mp_obj_type_t *type_in, size_t n_args, size mp_arg_check_num(n_args, n_kw, 1, 2, false); // get typecode - mp_uint_t l; - const char *typecode = mp_obj_str_get_data(args[0], &l); + const char *typecode = mp_obj_str_get_str(args[0]); if (n_args == 1) { // 1 arg: make an empty array @@ -392,7 +391,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { compat_error: - mp_raise_msg(&mp_type_ValueError, "lhs and rhs should be compatible"); + mp_raise_ValueError("lhs and rhs should be compatible"); } src_len = src_slice->len; src_items = src_slice->items; @@ -471,7 +470,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value return MP_OBJ_FROM_PTR(res); #endif } else { - mp_uint_t index = mp_get_index(o->base.type, o->len, index_in, false); + size_t index = mp_get_index(o->base.type, o->len, index_in, false); #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { index += o->free; diff --git a/py/objcomplex.c b/py/objcomplex.c index 426e76e5f..7ec47edb5 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -80,7 +80,7 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, si case 1: if (MP_OBJ_IS_STR(args[0])) { // a string, parse it - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, true, true, NULL); } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { @@ -117,6 +117,7 @@ STATIC mp_obj_t complex_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->real != 0 || o->imag != 0); + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag)); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag); default: return MP_OBJ_NULL; // op not supported diff --git a/py/objdict.c b/py/objdict.c index 013cc0a04..f6929d23f 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -386,7 +386,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg if (key == MP_OBJ_STOP_ITERATION || value == MP_OBJ_STOP_ITERATION || stop != MP_OBJ_STOP_ITERATION) { - mp_raise_msg(&mp_type_ValueError, "dictionary update sequence has the wrong length"); + mp_raise_ValueError("dict update sequence has wrong length"); } else { mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; } diff --git a/py/objfloat.c b/py/objfloat.c index 9292490a9..2c355d355 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -89,7 +89,7 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size default: if (MP_OBJ_IS_STR(args[0])) { // a string, parse it - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, false, false, NULL); } else if (mp_obj_is_float(args[0])) { @@ -106,6 +106,7 @@ STATIC mp_obj_t float_unary_op(mp_uint_t op, mp_obj_t o_in) { mp_float_t val = mp_obj_float_get(o_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(val != 0); + case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val)); case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-val); default: return MP_OBJ_NULL; // op not supported diff --git a/py/objfun.c b/py/objfun.c index a823f49e5..08d031c8d 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -220,9 +220,9 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args return NULL; } - code_state->ip = (byte*)(ip - self->bytecode); // offset to after n_state/n_exc_stack - code_state->n_state = n_state; - mp_setup_code_state(code_state, self, n_args, n_kw, args); + code_state->fun_bc = self; + code_state->ip = 0; + mp_setup_code_state(code_state, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); @@ -265,9 +265,9 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const state_size = 0; // indicate that we allocated using alloca } - code_state->ip = (byte*)(ip - self->bytecode); // offset to after n_state/n_exc_stack - code_state->n_state = n_state; - mp_setup_code_state(code_state, self, n_args, n_kw, args); + code_state->fun_bc = self; + code_state->ip = 0; + mp_setup_code_state(code_state, n_args, n_kw, args); // execute the byte code with the correct globals context code_state->old_globals = mp_globals_get(); @@ -501,7 +501,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return mp_obj_int_get_truncated(obj); } else if (MP_OBJ_IS_STR(obj)) { // pointer to the string (it's probably constant though!) - mp_uint_t l; + size_t l; return (mp_uint_t)mp_obj_str_get_data(obj, &l); } else { mp_obj_type_t *type = mp_obj_get_type(obj); @@ -513,7 +513,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { #endif } else if (type == &mp_type_tuple || type == &mp_type_list) { // pointer to start of tuple (could pass length, but then could use len(x) for that) - mp_uint_t len; + size_t len; mp_obj_t *items; mp_obj_get_array(obj, &len, &items); return (mp_uint_t)items; diff --git a/py/objgenerator.c b/py/objgenerator.c index 654b18670..2e57fdf4b 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -67,9 +67,9 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons o->base.type = &mp_type_gen_instance; o->globals = self_fun->globals; - o->code_state.n_state = n_state; - o->code_state.ip = (byte*)(ip - self_fun->bytecode); // offset to prelude - mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args); + o->code_state.fun_bc = self_fun; + o->code_state.ip = 0; + mp_setup_code_state(&o->code_state, n_args, n_kw, args); return MP_OBJ_FROM_PTR(o); } @@ -92,7 +92,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) { STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "<generator object '%q' at %p>", mp_obj_code_get_name(self->code_state.code_info), self); + mp_printf(print, "<generator object '%q' at %p>", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self); } mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { @@ -105,7 +105,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { - mp_raise_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator"); + mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { *self->code_state.sp = send_value; @@ -134,10 +134,12 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } break; - case MP_VM_RETURN_EXCEPTION: + case MP_VM_RETURN_EXCEPTION: { + size_t n_state = mp_decode_uint_value(self->code_state.fun_bc->bytecode); self->code_state.ip = 0; - *ret_val = self->code_state.state[self->code_state.n_state - 1]; + *ret_val = self->code_state.state[n_state - 1]; break; + } } return ret_kind; diff --git a/py/objint.c b/py/objint.c index 5aa6a95cc..46f9b1666 100644 --- a/py/objint.c +++ b/py/objint.c @@ -56,7 +56,7 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, return args[0]; } else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { // a string, parse it - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_integer(s, l, 0, NULL); #if MICROPY_PY_BUILTINS_FLOAT @@ -72,7 +72,7 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, default: { // should be a string, parse it // TODO proper error checking of argument types - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]), NULL); } @@ -80,7 +80,14 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, } #if MICROPY_PY_BUILTINS_FLOAT -mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { + +typedef enum { + MP_FP_CLASS_FIT_SMALLINT, + MP_FP_CLASS_FIT_LONGINT, + MP_FP_CLASS_OVERFLOW +} mp_fp_as_int_class_t; + +STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { union { mp_float_t f; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT @@ -103,7 +110,12 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE e |= u.i[MP_ENDIANNESS_BIG] != 0; #endif - e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32; + if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) { + // handle case of -0 (when sign is set but rest of bits are zero) + e = 0; + } else { + e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32; + } } else { e &= ~((1 << MP_FLOAT_EXP_SHIFT_I32) - 1); } @@ -125,6 +137,35 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { } #undef MP_FLOAT_SIGN_SHIFT_I32 #undef MP_FLOAT_EXP_SHIFT_I32 + +mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { + int cl = fpclassify(val); + if (cl == FP_INFINITE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int")); + } else if (cl == FP_NAN) { + mp_raise_ValueError("can't convert NaN to int"); + } else { + mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); + if (icl == MP_FP_CLASS_FIT_SMALLINT) { + return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + } else { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + mpz_set_from_float(&o->mpz, val); + return MP_OBJ_FROM_PTR(o); + } + #else + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + } else if (icl == MP_FP_CLASS_FIT_LONGINT) { + return mp_obj_new_int_from_ll((long long)val); + #endif + } else { + mp_raise_ValueError("float too big"); + } + #endif + } +} + #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG @@ -318,24 +359,6 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { return mp_const_none; } -#if MICROPY_PY_BUILTINS_FLOAT -mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { - int cl = fpclassify(val); - if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); - } else if (cl == FP_NAN) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); - } else { - mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); - if (icl == MP_FP_CLASS_FIT_SMALLINT) { - return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big")); - } - } -} -#endif - mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); diff --git a/py/objint.h b/py/objint.h index 7205761ad..da56c1862 100644 --- a/py/objint.h +++ b/py/objint.h @@ -41,18 +41,13 @@ typedef struct _mp_obj_int_t { extern const mp_obj_int_t mp_maxsize_obj; #if MICROPY_PY_BUILTINS_FLOAT -typedef enum { - MP_FP_CLASS_FIT_SMALLINT, - MP_FP_CLASS_FIT_LONGINT, - MP_FP_CLASS_OVERFLOW -} mp_fp_as_int_class_t; - -mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val); mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in); -#endif // MICROPY_PY_BUILTINS_FLOAT +#endif size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); +mp_obj_int_t *mp_obj_int_new_mpz(void); + void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); char *mp_obj_int_formatted(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); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 4ab49f337..540cfebd0 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -263,26 +263,6 @@ mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { return o; } -#if MICROPY_PY_BUILTINS_FLOAT -mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { - int cl = fpclassify(val); - if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); - } else if (cl == FP_NAN) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); - } else { - mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); - if (icl == MP_FP_CLASS_FIT_SMALLINT) { - return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); - } else if (icl == MP_FP_CLASS_FIT_LONGINT) { - return mp_obj_new_int_from_ll((long long)val); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big")); - } - } -} -#endif - mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated // TODO check overflow diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 2cdf22505..2353bd8d6 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -74,7 +74,7 @@ const mp_obj_int_t mp_maxsize_obj = { #undef NUM_DIG #endif -STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { +mp_obj_int_t *mp_obj_int_new_mpz(void) { mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; mpz_init_zero(&o->mpz); @@ -277,7 +277,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_INPLACE_RSHIFT: { mp_int_t irhs = mp_obj_int_get_checked(rhs_in); if (irhs < 0) { - mp_raise_msg(&mp_type_ValueError, "negative shift count"); + mp_raise_ValueError("negative shift count"); } if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { mpz_shl_inpl(&res->mpz, zlhs, irhs); @@ -387,26 +387,6 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { return mp_obj_new_int_from_ull(value); } -#if MICROPY_PY_BUILTINS_FLOAT -mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { - int cl = fpclassify(val); - if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); - } else if (cl == FP_NAN) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); - } else { - mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); - if (icl == MP_FP_CLASS_FIT_SMALLINT) { - return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); - } else { - mp_obj_int_t *o = mp_obj_int_new_mpz(); - mpz_set_from_float(&o->mpz, val); - return MP_OBJ_FROM_PTR(o); - } - } -} -#endif - mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_obj_int_t *o = mp_obj_int_new_mpz(); size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); diff --git a/py/objlist.c b/py/objlist.c index ba7898415..45e69c8bc 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -186,13 +186,13 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return MP_OBJ_FROM_PTR(res); } #endif - mp_uint_t index_val = mp_get_index(self->base.type, self->len, index, false); + size_t index_val = mp_get_index(self->base.type, self->len, index, false); return self->items[index_val]; } else { #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); - mp_uint_t value_len; mp_obj_t *value_items; + size_t value_len; mp_obj_t *value_items; mp_obj_get_array(value, &value_len, &value_items); mp_bound_slice_t slice_out; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { @@ -268,7 +268,7 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { if (self->len == 0) { mp_raise_msg(&mp_type_IndexError, "pop from empty list"); } - mp_uint_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); + size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; self->len -= 1; memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t)); @@ -475,7 +475,7 @@ mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items) { return MP_OBJ_FROM_PTR(o); } -void mp_obj_list_get(mp_obj_t self_in, mp_uint_t *len, mp_obj_t **items) { +void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = self->items; @@ -490,7 +490,7 @@ void mp_obj_list_set_len(mp_obj_t self_in, size_t len) { void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); - mp_uint_t i = mp_get_index(self->base.type, self->len, index, false); + size_t i = mp_get_index(self->base.type, self->len, index, false); self->items[i] = value; } diff --git a/py/objmap.c b/py/objmap.c index 0b2189016..111c964fd 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -31,7 +31,7 @@ typedef struct _mp_obj_map_t { mp_obj_base_t base; - mp_uint_t n_iters; + size_t n_iters; mp_obj_t fun; mp_obj_t iters[]; } mp_obj_map_t; @@ -42,7 +42,7 @@ STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ o->base.type = type; o->n_iters = n_args - 1; o->fun = args[0]; - for (mp_uint_t i = 0; i < n_args - 1; i++) { + for (size_t i = 0; i < n_args - 1; i++) { o->iters[i] = mp_getiter(args[i + 1], NULL); } return MP_OBJ_FROM_PTR(o); @@ -53,7 +53,7 @@ STATIC mp_obj_t map_iternext(mp_obj_t self_in) { mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); - for (mp_uint_t i = 0; i < self->n_iters; i++) { + for (size_t i = 0; i < self->n_iters; i++) { mp_obj_t next = mp_iternext(self->iters[i]); if (next == MP_OBJ_STOP_ITERATION) { m_del(mp_obj_t, nextses, self->n_iters); diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 18931a16c..52468747b 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -36,7 +36,7 @@ typedef struct _mp_obj_namedtuple_type_t { mp_obj_type_t base; - mp_uint_t n_fields; + size_t n_fields; qstr fields[]; } mp_obj_namedtuple_type_t; @@ -44,13 +44,13 @@ typedef struct _mp_obj_namedtuple_t { mp_obj_tuple_t tuple; } mp_obj_namedtuple_t; -STATIC mp_uint_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { - for (mp_uint_t i = 0; i < type->n_fields; i++) { +STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { + for (size_t i = 0; i < type->n_fields; i++) { if (type->fields[i] == name) { return i; } } - return -1; + return (size_t)-1; } STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { @@ -65,8 +65,8 @@ STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // load attribute mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); - int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); - if (id == -1) { + size_t id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); + if (id == (size_t)-1) { return; } dest[0] = self->tuple.items[id]; @@ -102,14 +102,14 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, arg_objects = alloca(alloc_size); memset(arg_objects, 0, alloc_size); - for (mp_uint_t i = 0; i < n_args; i++) { + for (size_t i = 0; i < n_args; i++) { arg_objects[i] = args[i]; } - for (mp_uint_t i = n_args; i < n_args + 2 * n_kw; i += 2) { + for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) { qstr kw = mp_obj_str_get_qstr(args[i]); - int id = namedtuple_find_field(type, kw); - if (id == -1) { + size_t id = namedtuple_find_field(type, kw); + if (id == (size_t)-1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { @@ -136,7 +136,7 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, STATIC const mp_rom_obj_tuple_t namedtuple_base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_tuple)}}; -STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj_t *fields) { +STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields); memset(&o->base, 0, sizeof(o->base)); o->base.base.type = &mp_type_type; @@ -150,7 +150,7 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj o->base.getiter = mp_obj_tuple_getiter; o->base.bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&namedtuple_base_tuple; o->n_fields = n_fields; - for (mp_uint_t i = 0; i < n_fields; i++) { + for (size_t i = 0; i < n_fields; i++) { o->fields[i] = mp_obj_str_get_qstr(fields[i]); } return MP_OBJ_FROM_PTR(o); @@ -158,7 +158,7 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { qstr name = mp_obj_str_get_qstr(name_in); - mp_uint_t n_fields; + size_t n_fields; mp_obj_t *fields; #if MICROPY_CPYTHON_COMPAT if (MP_OBJ_IS_STR(fields_in)) { diff --git a/py/objobject.c b/py/objobject.c index b33dc491c..f9a7d17c3 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -50,7 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { - mp_raise_msg(&mp_type_TypeError, "__new__ arg must be a user-type"); + mp_raise_TypeError("__new__ arg must be a user-type"); } mp_obj_t o = MP_OBJ_SENTINEL; mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o); diff --git a/py/objrange.c b/py/objrange.c index dd074a98a..c78c53f11 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -105,8 +105,10 @@ STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t o->start = mp_obj_get_int(args[0]); o->stop = mp_obj_get_int(args[1]); if (n_args == 3) { - // TODO check step is non-zero o->step = mp_obj_get_int(args[2]); + if (o->step == 0) { + mp_raise_ValueError("zero step"); + } } } @@ -155,7 +157,7 @@ STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return MP_OBJ_FROM_PTR(o); } #endif - uint index_val = mp_get_index(self->base.type, len, index, false); + size_t index_val = mp_get_index(self->base.type, len, index, false); return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step); } else { return MP_OBJ_NULL; // op not supported diff --git a/py/objstr.c b/py/objstr.c index 2331004a5..70de0a693 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -236,7 +236,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { mp_int_t val = mp_obj_get_int(item); - #if MICROPY_CPYTHON_COMPAT + #if MICROPY_FULL_CHECKS if (val < 0 || val > 255) { mp_raise_ValueError("bytes value out of range"); } @@ -284,7 +284,7 @@ mp_obj_t mp_obj_str_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // check for modulo if (op == MP_BINARY_OP_MODULO) { mp_obj_t *args = &rhs_in; - mp_uint_t n_args = 1; + size_t n_args = 1; mp_obj_t dict = MP_OBJ_NULL; if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) { // TODO: Support tuple subclasses? @@ -388,7 +388,7 @@ mp_obj_t mp_obj_str_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // objstrunicode defines own version const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, mp_obj_t index, bool is_slice) { - mp_uint_t index_val = mp_get_index(type, self_len, index, is_slice); + size_t index_val = mp_get_index(type, self_len, index, is_slice); return self_data + index_val; } #endif @@ -408,7 +408,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start); } #endif - mp_uint_t index_val = mp_get_index(type, self_len, index, false); + size_t index_val = mp_get_index(type, self_len, index, false); // If we have unicode enabled the type will always be bytes, so take the short cut. if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); @@ -428,7 +428,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { GET_STR_DATA_LEN(self_in, sep_str, sep_len); // process args - mp_uint_t seq_len; + size_t seq_len; mp_obj_t *seq_items; if (!MP_OBJ_IS_TYPE(arg, &mp_type_list) && !MP_OBJ_IS_TYPE(arg, &mp_type_tuple)) { @@ -513,7 +513,7 @@ mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { bad_implicit_conversion(sep); } - mp_uint_t sep_len; + size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { @@ -611,7 +611,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { if (sep == mp_const_none) { mp_not_implemented("rsplit(None,n)"); } else { - mp_uint_t sep_len; + size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { @@ -1306,12 +1306,12 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar switch (type) { case '\0': // no explicit format type implies 's' case 's': { - mp_uint_t slen; + size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (precision < 0) { precision = slen; } - if (slen > (mp_uint_t)precision) { + if (slen > (size_t)precision) { slen = precision; } mp_print_strn(&print, s, slen, flags, fill, width); @@ -1452,7 +1452,7 @@ not_enough_args: switch (*str) { case 'c': if (MP_OBJ_IS_STR(arg)) { - mp_uint_t slen; + size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { mp_raise_TypeError("%%c requires int or char"); @@ -2065,9 +2065,10 @@ STATIC void bad_implicit_conversion(mp_obj_t self_in) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to str implicitly"); } else { + const qstr src_name = mp_obj_get_type(self_in)->name; nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, - "can't convert '%s' object to str implicitly", - mp_obj_get_type_str(self_in))); + "can't convert '%q' object to %q implicitly", + src_name, src_name == MP_QSTR_str ? MP_QSTR_bytes : MP_QSTR_str)); } } @@ -2096,7 +2097,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) { } } -const char *mp_obj_str_get_data(mp_obj_t self_in, mp_uint_t *len) { +const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { GET_STR_DATA_LEN(self_in, s, l); *len = l; diff --git a/py/objstringio.c b/py/objstringio.c index 61a30752e..88659deb8 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -39,7 +39,7 @@ #if MICROPY_CPYTHON_COMPAT STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { if (o->vstr == NULL) { - mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file"); + mp_raise_ValueError("I/O operation on closed file"); } } #else diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 441ec293d..9a6ce9b9a 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -120,7 +120,7 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s // so it must handle bytes. if (type == &mp_type_bytes) { // Taken from objstr.c:str_index_to_ptr() - mp_uint_t index_val = mp_get_index(type, self_len, index, is_slice); + size_t index_val = mp_get_index(type, self_len, index, is_slice); return self_data + index_val; } diff --git a/py/objtuple.c b/py/objtuple.c index b28807c0d..eaf0e37f4 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -138,7 +138,8 @@ mp_obj_t mp_obj_tuple_unary_op(mp_uint_t op, mp_obj_t self_in) { mp_obj_t mp_obj_tuple_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_tuple_t *o = MP_OBJ_TO_PTR(lhs); switch (op) { - case MP_BINARY_OP_ADD: { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: { if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(rhs)), MP_OBJ_FROM_PTR(&mp_type_tuple))) { return MP_OBJ_NULL; // op not supported } @@ -186,7 +187,7 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return MP_OBJ_FROM_PTR(res); } #endif - mp_uint_t index_value = mp_get_index(self->base.type, self->len, index, false); + size_t index_value = mp_get_index(self->base.type, self->len, index, false); return self->items[index_value]; } else { return MP_OBJ_NULL; // op not supported @@ -244,7 +245,7 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { return MP_OBJ_FROM_PTR(o); } -void mp_obj_tuple_get(mp_obj_t self_in, mp_uint_t *len, mp_obj_t **items) { +void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; diff --git a/py/objtype.c b/py/objtype.c index a4c424929..dd170b4c6 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -48,7 +48,7 @@ STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_ /******************************************************************************/ // instance object -STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, uint subobjs) { +STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) { mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); o->base.type = class; mp_map_init(&o->members, 0); @@ -57,11 +57,11 @@ STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, uint subobjs) { } STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { - mp_uint_t len = type->bases_tuple->len; + size_t len = type->bases_tuple->len; mp_obj_t *items = type->bases_tuple->items; int count = 0; - for (uint i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]); if (bt == &mp_type_object) { @@ -96,7 +96,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t struct class_lookup_data { mp_obj_instance_t *obj; qstr attr; - mp_uint_t meth_offset; + size_t meth_offset; mp_obj_t *dest; bool is_type; }; @@ -165,12 +165,12 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ return; } - mp_uint_t len = type->bases_tuple->len; + size_t len = type->bases_tuple->len; mp_obj_t *items = type->bases_tuple->items; if (len == 0) { return; } - for (uint i = 0; i < len - 1; i++) { + for (size_t i = 0; i < len - 1; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]); if (bt == &mp_type_object) { @@ -239,7 +239,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size assert(mp_obj_is_instance_type(self)); const mp_obj_type_t *native_base; - uint num_native_bases = instance_count_native_bases(self, &native_base); + size_t num_native_bases = instance_count_native_bases(self, &native_base); assert(num_native_bases < 2); mp_obj_instance_t *o = MP_OBJ_TO_PTR(mp_obj_new_instance(self, num_native_bases)); @@ -311,7 +311,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size } if (init_ret != mp_const_none) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "__init__() should return None"); + mp_raise_TypeError("__init__() should return None"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); @@ -477,7 +477,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // it will not result in modifications to the actual instance members. mp_map_t *map = &self->members; mp_obj_t attr_dict = mp_obj_new_dict(map->used); - for (mp_uint_t i = 0; i < map->alloc; ++i) { + for (size_t i = 0; i < map->alloc; ++i) { if (MP_MAP_SLOT_IS_FILLED(map, i)) { mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value); } @@ -688,7 +688,7 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value .dest = member, .is_type = false, }; - uint meth_args; + size_t meth_args; if (value == MP_OBJ_NULL) { // delete item lookup.attr = MP_QSTR___delitem__; @@ -744,7 +744,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons mp_obj_t call = mp_obj_instance_get_call(self_in, member); if (call == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object not callable"); + mp_raise_TypeError("object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in))); @@ -826,7 +826,7 @@ STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); default: - mp_raise_msg(&mp_type_TypeError, "type takes 1 or 3 arguments"); + mp_raise_TypeError("type takes 1 or 3 arguments"); } } @@ -837,7 +837,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (self->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "cannot create instance"); + mp_raise_TypeError("cannot create instance"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%q' instances", self->name)); @@ -916,16 +916,16 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // TODO might need to make a copy of locals_dict; at least that's how CPython does it // Basic validation of base classes - mp_uint_t len; + size_t len; mp_obj_t *items; mp_obj_tuple_get(bases_tuple, &len, &items); - for (uint i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); mp_obj_type_t *t = MP_OBJ_TO_PTR(items[i]); // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "type is not an acceptable base type"); + mp_raise_TypeError("type is not an acceptable base type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "type '%q' is not an acceptable base type", t->name)); @@ -957,9 +957,9 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->locals_dict = MP_OBJ_TO_PTR(locals_dict); const mp_obj_type_t *native_base; - uint num_native_bases = instance_count_native_bases(o, &native_base); + size_t num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { - mp_raise_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"); + mp_raise_TypeError("multiple bases have instance lay-out conflict"); } mp_map_t *locals_map = &o->locals_dict->map; @@ -1020,7 +1020,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } - mp_uint_t len = type->bases_tuple->len; + size_t len = type->bases_tuple->len; mp_obj_t *items = type->bases_tuple->items; struct class_lookup_data lookup = { .obj = MP_OBJ_TO_PTR(self->obj), @@ -1029,7 +1029,7 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { .dest = dest, .is_type = false, }; - for (uint i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i])); if (dest[0] != MP_OBJ_NULL) { @@ -1079,14 +1079,14 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { } // get the base objects (they should be type objects) - mp_uint_t len = self->bases_tuple->len; + size_t len = self->bases_tuple->len; mp_obj_t *items = self->bases_tuple->items; if (len == 0) { return false; } // iterate through the base objects - for (uint i = 0; i < len - 1; i++) { + for (size_t i = 0; i < len - 1; i++) { if (mp_obj_is_subclass_fast(items[i], classinfo)) { return true; } @@ -1098,7 +1098,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { } STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { - mp_uint_t len; + size_t len; mp_obj_t *items; if (MP_OBJ_IS_TYPE(classinfo, &mp_type_type)) { len = 1; @@ -1106,10 +1106,10 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { - mp_raise_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes"); + mp_raise_TypeError("issubclass() arg 2 must be a class or a tuple of classes"); } - for (uint i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { // We explicitly check for 'object' here since no-one explicitly derives from it if (items[i] == MP_OBJ_FROM_PTR(&mp_type_object) || mp_obj_is_subclass_fast(object, items[i])) { return mp_const_true; @@ -1120,7 +1120,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { - mp_raise_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class"); + mp_raise_TypeError("issubclass() arg 1 must be a class"); } return mp_obj_is_subclass(object, classinfo); } diff --git a/py/objzip.c b/py/objzip.c index 5d9ba48e7..6f72d1595 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -32,7 +32,7 @@ typedef struct _mp_obj_zip_t { mp_obj_base_t base; - mp_uint_t n_iters; + size_t n_iters; mp_obj_t iters[]; } mp_obj_zip_t; @@ -42,7 +42,7 @@ STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_obj_zip_t *o = m_new_obj_var(mp_obj_zip_t, mp_obj_t, n_args); o->base.type = type; o->n_iters = n_args; - for (mp_uint_t i = 0; i < n_args; i++) { + for (size_t i = 0; i < n_args; i++) { o->iters[i] = mp_getiter(args[i], NULL); } return MP_OBJ_FROM_PTR(o); @@ -56,7 +56,7 @@ STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { } mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->n_iters, NULL)); - for (mp_uint_t i = 0; i < self->n_iters; i++) { + for (size_t i = 0; i < self->n_iters; i++) { mp_obj_t next = mp_iternext(self->iters[i]); if (next == MP_OBJ_STOP_ITERATION) { mp_obj_tuple_del(MP_OBJ_FROM_PTR(tuple)); diff --git a/py/parsenum.c b/py/parsenum.c index 2e41801ee..177118843 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -55,7 +55,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m // check radix base if ((base != 0 && base < 2) || base > 36) { // this won't be reached if lex!=NULL - mp_raise_msg(&mp_type_ValueError, "int() arg 2 must be >= 2 and <= 36"); + mp_raise_ValueError("int() arg 2 must be >= 2 and <= 36"); } // skip leading space @@ -16,9 +16,6 @@ endif # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 -INC += -I../lib -INC += -I../lib/netutils - # this sets the config file for FatFs CFLAGS_MOD += -DFFCONF_H=\"lib/oofatfs/ffconf.h\" @@ -143,6 +140,7 @@ PY_O_BASENAME = \ persistentcode.o \ runtime.o \ runtime_utils.o \ + scheduler.o \ nativeglue.o \ stackctrl.o \ argcheck.o \ @@ -153,7 +153,7 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t mp_obj_t obj = MP_OBJ_NULL; for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - mp_uint_t d_len; + size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { obj = dict->map.table[i].value; @@ -197,7 +197,7 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t mp_uint_t match_len = 0; for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - mp_uint_t d_len; + size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { if (match_str == NULL) { @@ -247,7 +247,7 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t int line_len = MAX_LINE_LEN; // force a newline for first word for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - mp_uint_t d_len; + size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; diff --git a/py/runtime.c b/py/runtime.c index 1f69290ba..1df6740b2 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -63,6 +63,10 @@ void mp_init(void) { // no pending exceptions to start with MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + #if MICROPY_ENABLE_SCHEDULER + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + MP_STATE_VM(sched_sp) = 0; + #endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF mp_init_emergency_exception_buf(); @@ -93,7 +97,8 @@ void mp_init(void) { mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(dict_main)), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) - MP_STATE_CTX(dict_locals) = MP_STATE_CTX(dict_globals) = &MP_STATE_VM(dict_main); + mp_locals_set(&MP_STATE_VM(dict_main)); + mp_globals_set(&MP_STATE_VM(dict_main)); #if MICROPY_CAN_OVERRIDE_BUILTINS // start with no extensions to builtins @@ -132,8 +137,8 @@ mp_obj_t mp_load_name(qstr qst) { // logic: search locals, globals, builtins DEBUG_OP_printf("load name %s\n", qstr_str(qst)); // If we're at the outer scope (locals == globals), dispatch to load_global right away - if (MP_STATE_CTX(dict_locals) != MP_STATE_CTX(dict_globals)) { - mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_CTX(dict_locals)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + if (mp_locals_get() != mp_globals_get()) { + mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { return elem->value; } @@ -144,7 +149,7 @@ mp_obj_t mp_load_name(qstr qst) { mp_obj_t mp_load_global(qstr qst) { // logic: search globals, builtins DEBUG_OP_printf("load global %s\n", qstr_str(qst)); - mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_CTX(dict_globals)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem == NULL) { #if MICROPY_CAN_OVERRIDE_BUILTINS if (MP_STATE_VM(mp_module_builtins_override_dict) != NULL) { @@ -184,24 +189,24 @@ mp_obj_t mp_load_build_class(void) { void mp_store_name(qstr qst, mp_obj_t obj) { DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qst), obj); - mp_obj_dict_store(MP_OBJ_FROM_PTR(MP_STATE_CTX(dict_locals)), MP_OBJ_NEW_QSTR(qst), obj); + mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst), obj); } void mp_delete_name(qstr qst) { DEBUG_OP_printf("delete name %s\n", qstr_str(qst)); // TODO convert KeyError to NameError if qst not found - mp_obj_dict_delete(MP_OBJ_FROM_PTR(MP_STATE_CTX(dict_locals)), MP_OBJ_NEW_QSTR(qst)); + mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_locals_get()), MP_OBJ_NEW_QSTR(qst)); } void mp_store_global(qstr qst, mp_obj_t obj) { DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qst), obj); - mp_obj_dict_store(MP_OBJ_FROM_PTR(MP_STATE_CTX(dict_globals)), MP_OBJ_NEW_QSTR(qst), obj); + mp_obj_dict_store(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst), obj); } void mp_delete_global(qstr qst) { DEBUG_OP_printf("delete global %s\n", qstr_str(qst)); // TODO convert KeyError to NameError if qst not found - mp_obj_dict_delete(MP_OBJ_FROM_PTR(MP_STATE_CTX(dict_globals)), MP_OBJ_NEW_QSTR(qst)); + mp_obj_dict_delete(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(qst)); } mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { @@ -247,7 +252,7 @@ mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "unsupported type for operator"); + mp_raise_TypeError("unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported type for %q: '%s'", @@ -339,7 +344,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_LSHIFT: { if (rhs_val < 0) { // negative shift not allowed - mp_raise_msg(&mp_type_ValueError, "negative shift count"); + mp_raise_ValueError("negative shift count"); } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); @@ -354,7 +359,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_RSHIFT: if (rhs_val < 0) { // negative shift not allowed - mp_raise_msg(&mp_type_ValueError, "negative shift count"); + mp_raise_ValueError("negative shift count"); } else { // standard precision is enough for right-shift if (rhs_val >= (mp_int_t)BITS_PER_WORD) { @@ -430,7 +435,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { lhs = mp_obj_new_float(lhs_val); goto generic_binary_op; #else - mp_raise_msg(&mp_type_ValueError, "negative power with no float support"); + mp_raise_ValueError("negative power with no float support"); #endif } else { mp_int_t ans = 1; @@ -532,7 +537,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object not iterable"); + mp_raise_TypeError("object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(rhs))); @@ -554,7 +559,7 @@ generic_binary_op: unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "unsupported type for operator"); + mp_raise_TypeError("unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported types for %q: '%s', '%s'", @@ -596,7 +601,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object not callable"); + mp_raise_TypeError("object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in))); @@ -665,7 +670,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // optimise the case of a tuple and list // get the items - mp_uint_t len; + size_t len; mp_obj_t *items; mp_obj_get_array(pos_seq, &len, &items); @@ -794,7 +799,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob // unpacked items are stored in reverse order into the array pointed to by items void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { - mp_uint_t seq_len; + size_t seq_len; if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); @@ -825,14 +830,14 @@ void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); + mp_raise_ValueError("wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } too_long: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); + mp_raise_ValueError("wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", (int)num)); @@ -844,7 +849,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { size_t num_left = num_in & 0xff; size_t num_right = (num_in >> 8) & 0xff; DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); - mp_uint_t seq_len; + size_t seq_len; if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { mp_obj_t *seq_items; mp_obj_get_array(seq_in, &seq_len, &seq_items); @@ -889,7 +894,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); + mp_raise_ValueError("wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); @@ -928,7 +933,7 @@ STATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]); if (arg0_type != self->type) { if (MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED) { - mp_raise_msg(&mp_type_TypeError, "argument has wrong type"); + mp_raise_TypeError("argument has wrong type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "argument should be a '%q' not a '%q'", self->type->name, arg0_type->name)); @@ -1119,7 +1124,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { // object not iterable if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object not iterable"); + mp_raise_TypeError("object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); @@ -1141,7 +1146,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { return mp_call_method_n_kw(0, 0, dest); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object not an iterator"); + mp_raise_TypeError("object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); @@ -1177,7 +1182,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_msg(&mp_type_TypeError, "object not an iterator"); + mp_raise_TypeError("object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); @@ -1325,7 +1330,7 @@ import_error: } mp_load_method_maybe(module, MP_QSTR___name__, dest); - mp_uint_t pkg_name_len; + size_t pkg_name_len; const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len); const uint dot_name_len = pkg_name_len + 1 + qstr_len(name); diff --git a/py/runtime.h b/py/runtime.h index 954833b67..177869145 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -64,6 +64,16 @@ extern const qstr mp_binary_op_method_name[]; void mp_init(void); void mp_deinit(void); +void mp_handle_pending(void); +void mp_handle_pending_tail(mp_uint_t atomic_state); + +#if MICROPY_ENABLE_SCHEDULER +void mp_sched_lock(void); +void mp_sched_unlock(void); +static inline unsigned int mp_sched_num_pending(void) { return MP_STATE_VM(sched_sp); } +bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg); +#endif + // extra printing method specifically for mp_obj_t's which are integral type int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); @@ -73,10 +83,10 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, NORETURN void mp_arg_error_terse_mismatch(void); NORETURN void mp_arg_error_unimpl_kw(void); -static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_CTX(dict_locals); } -static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_CTX(dict_locals) = d; } -static inline mp_obj_dict_t *mp_globals_get(void) { return MP_STATE_CTX(dict_globals); } -static inline void mp_globals_set(mp_obj_dict_t *d) { MP_STATE_CTX(dict_globals) = d; } +static inline mp_obj_dict_t *mp_locals_get(void) { return MP_STATE_THREAD(dict_locals); } +static inline void mp_locals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_locals) = d; } +static inline mp_obj_dict_t *mp_globals_get(void) { return MP_STATE_THREAD(dict_globals); } +static inline void mp_globals_set(mp_obj_dict_t *d) { MP_STATE_THREAD(dict_globals) = d; } mp_obj_t mp_load_name(qstr qst); mp_obj_t mp_load_global(qstr qst); diff --git a/py/scheduler.c b/py/scheduler.c new file mode 100644 index 000000000..30851a4d2 --- /dev/null +++ b/py/scheduler.c @@ -0,0 +1,117 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> + +#include "py/runtime.h" + +#if MICROPY_ENABLE_SCHEDULER + +// A variant of this is inlined in the VM at the pending exception check +void mp_handle_pending(void) { + if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + if (obj != MP_OBJ_NULL) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + if (!mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + nlr_raise(obj); + } + mp_handle_pending_tail(atomic_state); + } +} + +// This function should only be called be mp_sched_handle_pending, +// or by the VM's inlined version of that function. +void mp_handle_pending_tail(mp_uint_t atomic_state) { + MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; + if (MP_STATE_VM(sched_sp) > 0) { + mp_sched_item_t item = MP_STATE_VM(sched_stack)[--MP_STATE_VM(sched_sp)]; + MICROPY_END_ATOMIC_SECTION(atomic_state); + mp_call_function_1_protected(item.func, item.arg); + } else { + MICROPY_END_ATOMIC_SECTION(atomic_state); + } + mp_sched_unlock(); +} + +void mp_sched_lock(void) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + if (MP_STATE_VM(sched_state) < 0) { + --MP_STATE_VM(sched_state); + } else { + MP_STATE_VM(sched_state) = MP_SCHED_LOCKED; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); +} + +void mp_sched_unlock(void) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + if (++MP_STATE_VM(sched_state) == 0) { + // vm became unlocked + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } else { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + } + MICROPY_END_ATOMIC_SECTION(atomic_state); +} + +bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg) { + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + bool ret; + if (MP_STATE_VM(sched_sp) < MICROPY_SCHEDULER_DEPTH) { + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } + MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].func = function; + MP_STATE_VM(sched_stack)[MP_STATE_VM(sched_sp)].arg = arg; + ++MP_STATE_VM(sched_sp); + ret = true; + } else { + // schedule stack is full + ret = false; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + return ret; +} + +#else // MICROPY_ENABLE_SCHEDULER + +// A variant of this is inlined in the VM at the pending exception check +void mp_handle_pending(void) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } +} + +#endif // MICROPY_ENABLE_SCHEDULER diff --git a/py/sequence.c b/py/sequence.c index bc2cfc077..cd1a96617 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -38,9 +38,9 @@ // Implements backend of sequence * integer operation. Assumes elements are // memory-adjacent in sequence. -void mp_seq_multiply(const void *items, mp_uint_t item_sz, mp_uint_t len, mp_uint_t times, void *dest) { - for (mp_uint_t i = 0; i < times; i++) { - uint copy_sz = item_sz * len; +void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest) { + for (size_t i = 0; i < times; i++) { + size_t copy_sz = item_sz * len; memcpy(dest, items, copy_sz); dest = (char*)dest + copy_sz; } @@ -119,7 +119,7 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice #endif -mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes) { +mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes) { (void)len; // TODO can we remove len from the arg list? mp_int_t start = indexes->start, stop = indexes->stop; @@ -143,7 +143,7 @@ mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice // Special-case comparison function for sequences of bytes // Don't pass MP_BINARY_OP_NOT_EQUAL here -bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, mp_uint_t len1, const byte *data2, mp_uint_t len2) { +bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2) { if (op == MP_BINARY_OP_EQUAL && len1 != len2) { return false; } @@ -151,14 +151,14 @@ bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, mp_uint_t len1, const byt // Let's deal only with > & >= if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { SWAP(const byte*, data1, data2); - SWAP(uint, len1, len2); + SWAP(size_t, len1, len2); if (op == MP_BINARY_OP_LESS) { op = MP_BINARY_OP_MORE; } else { op = MP_BINARY_OP_MORE_EQUAL; } } - uint min_len = len1 < len2 ? len1 : len2; + size_t min_len = len1 < len2 ? len1 : len2; int res = memcmp(data1, data2, min_len); if (op == MP_BINARY_OP_EQUAL) { // If we are checking for equality, here're the answer @@ -187,7 +187,7 @@ bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, mp_uint_t len1, const byt // Special-case comparison function for sequences of mp_obj_t // Don't pass MP_BINARY_OP_NOT_EQUAL here -bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const mp_obj_t *items2, mp_uint_t len2) { +bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2) { if (op == MP_BINARY_OP_EQUAL && len1 != len2) { return false; } @@ -195,7 +195,7 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const // Let's deal only with > & >= if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { SWAP(const mp_obj_t *, items1, items2); - SWAP(uint, len1, len2); + SWAP(size_t, len1, len2); if (op == MP_BINARY_OP_LESS) { op = MP_BINARY_OP_MORE; } else { @@ -203,8 +203,8 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const } } - mp_uint_t len = len1 < len2 ? len1 : len2; - for (mp_uint_t i = 0; i < len; i++) { + size_t len = len1 < len2 ? len1 : len2; + for (size_t i = 0; i < len; i++) { // If current elements equal, can't decide anything - go on if (mp_obj_equal(items1[i], items2[i])) { continue; @@ -236,11 +236,11 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const } // Special-case of index() which searches for mp_obj_t -mp_obj_t mp_seq_index_obj(const mp_obj_t *items, mp_uint_t len, mp_uint_t n_args, const mp_obj_t *args) { +mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args) { mp_obj_type_t *type = mp_obj_get_type(args[0]); mp_obj_t value = args[1]; - uint start = 0; - uint stop = len; + size_t start = 0; + size_t stop = len; if (n_args >= 3) { start = mp_get_index(type, len, args[2], true); @@ -249,19 +249,19 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, mp_uint_t len, mp_uint_t n_args } } - for (mp_uint_t i = start; i < stop; i++) { + for (size_t i = start; i < stop; i++) { if (mp_obj_equal(items[i], value)) { // Common sense says this cannot overflow small int return MP_OBJ_NEW_SMALL_INT(i); } } - mp_raise_msg(&mp_type_ValueError, "object not in sequence"); + mp_raise_ValueError("object not in sequence"); } -mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value) { - mp_uint_t count = 0; - for (uint i = 0; i < len; i++) { +mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value) { + size_t count = 0; + for (size_t i = 0; i < len; i++) { if (mp_obj_equal(items[i], value)) { count++; } @@ -38,7 +38,7 @@ #include "py/bc.h" #if 0 -#define TRACE(ip) printf("sp=%d ", (int)(sp - code_state->sp)); mp_bytecode_print2(ip, 1, code_state->const_table); +#define TRACE(ip) printf("sp=%d ", (int)(sp - &code_state->state[0] + 1)); mp_bytecode_print2(ip, 1, code_state->fun_bc->const_table); #else #define TRACE(ip) #endif @@ -73,10 +73,10 @@ typedef enum { ip += 2; #define DECODE_PTR \ DECODE_UINT; \ - void *ptr = (void*)(uintptr_t)code_state->const_table[unum] + void *ptr = (void*)(uintptr_t)code_state->fun_bc->const_table[unum] #define DECODE_OBJ \ DECODE_UINT; \ - mp_obj_t obj = (mp_obj_t)code_state->const_table[unum] + mp_obj_t obj = (mp_obj_t)code_state->fun_bc->const_table[unum] #else @@ -162,8 +162,9 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp run_code_state: ; #endif // Pointers which are constant for particular invocation of mp_execute_bytecode() - mp_obj_t * /*const*/ fastn = &code_state->state[code_state->n_state - 1]; - mp_exc_stack_t * /*const*/ exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state); + size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); + mp_obj_t * /*const*/ fastn = &code_state->state[n_state - 1]; + mp_exc_stack_t * /*const*/ exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions @@ -284,12 +285,12 @@ dispatch_loop: DECODE_QSTR; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_uint_t x = *ip; - if (x < MP_STATE_CTX(dict_locals)->map.alloc && MP_STATE_CTX(dict_locals)->map.table[x].key == key) { - PUSH(MP_STATE_CTX(dict_locals)->map.table[x].value); + if (x < mp_locals_get()->map.alloc && mp_locals_get()->map.table[x].key == key) { + PUSH(mp_locals_get()->map.table[x].value); } else { - mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_CTX(dict_locals)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&mp_locals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { - *(byte*)ip = (elem - &MP_STATE_CTX(dict_locals)->map.table[0]) & 0xff; + *(byte*)ip = (elem - &mp_locals_get()->map.table[0]) & 0xff; PUSH(elem->value); } else { PUSH(mp_load_name(MP_OBJ_QSTR_VALUE(key))); @@ -313,12 +314,12 @@ dispatch_loop: DECODE_QSTR; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); mp_uint_t x = *ip; - if (x < MP_STATE_CTX(dict_globals)->map.alloc && MP_STATE_CTX(dict_globals)->map.table[x].key == key) { - PUSH(MP_STATE_CTX(dict_globals)->map.table[x].value); + if (x < mp_globals_get()->map.alloc && mp_globals_get()->map.table[x].key == key) { + PUSH(mp_globals_get()->map.table[x].value); } else { - mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_CTX(dict_globals)->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem != NULL) { - *(byte*)ip = (elem - &MP_STATE_CTX(dict_globals)->map.table[0]) & 0xff; + *(byte*)ip = (elem - &mp_globals_get()->map.table[0]) & 0xff; PUSH(elem->value); } else { PUSH(mp_load_global(MP_OBJ_QSTR_VALUE(key))); @@ -683,7 +684,7 @@ unwind_jump:; if (unum != 0) { // pop iter and iter_buf sp--; - sp -= sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t); + sp -= MP_OBJ_ITER_BUF_NSLOTS; } DISPATCH_WITH_PEND_EXC_CHECK(); } @@ -728,19 +729,20 @@ unwind_jump:; SET_TOP(mp_getiter(TOP(), NULL)); DISPATCH(); - // An iterator for a for-loop takes 4 slots on the stack. They are either - // used to store the iterator object itself, or the first slot is NULL and + // An iterator for a for-loop takes MP_OBJ_ITER_BUF_NSLOTS slots on + // the Python value stack. These slots are either used to store the + // iterator object itself, or the first slot is MP_OBJ_NULL and // the second slot holds a reference to the iterator object. ENTRY(MP_BC_GET_ITER_STACK): { MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = TOP(); mp_obj_iter_buf_t *iter_buf = (mp_obj_iter_buf_t*)sp; - sp += sizeof(mp_obj_iter_buf_t) / sizeof(mp_obj_t) - 1; + sp += MP_OBJ_ITER_BUF_NSLOTS - 1; obj = mp_getiter(obj, iter_buf); if (obj != MP_OBJ_FROM_PTR(iter_buf)) { // Iterator didn't use the stack so indicate that with MP_OBJ_NULL. - sp[-3] = MP_OBJ_NULL; - sp[-2] = obj; + sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] = MP_OBJ_NULL; + sp[-MP_OBJ_ITER_BUF_NSLOTS + 2] = obj; } DISPATCH(); } @@ -750,14 +752,14 @@ unwind_jump:; DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->sp = sp; mp_obj_t obj; - if (sp[-3] == MP_OBJ_NULL) { - obj = sp[-2]; + if (sp[-MP_OBJ_ITER_BUF_NSLOTS + 1] == MP_OBJ_NULL) { + obj = sp[-MP_OBJ_ITER_BUF_NSLOTS + 2]; } else { - obj = MP_OBJ_FROM_PTR(&sp[-3]); + obj = MP_OBJ_FROM_PTR(&sp[-MP_OBJ_ITER_BUF_NSLOTS + 1]); } mp_obj_t value = mp_iternext_allow_raise(obj); if (value == MP_OBJ_STOP_ITERATION) { - sp -= 4; // pop the exhausted iterator + sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator ip += ulab; // jump to after for-block } else { PUSH(value); // push the next iteration value @@ -1266,12 +1268,32 @@ yield: pending_exception_check: MICROPY_VM_HOOK_LOOP + + #if MICROPY_ENABLE_SCHEDULER + // This is an inlined variant of mp_handle_pending + if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { + MARK_EXC_IP_SELECTIVE(); + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + if (obj != MP_OBJ_NULL) { + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + if (!mp_sched_num_pending()) { + MP_STATE_VM(sched_state) = MP_SCHED_IDLE; + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + RAISE(obj); + } + mp_handle_pending_tail(atomic_state); + } + #else + // This is an inlined variant of mp_handle_pending if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { MARK_EXC_IP_SELECTIVE(); mp_obj_t obj = MP_STATE_VM(mp_pending_exception); MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; RAISE(obj); } + #endif #if MICROPY_PY_THREAD_GIL #if MICROPY_PY_THREAD_GIL_VM_DIVISOR @@ -1280,8 +1302,14 @@ pending_exception_check: #else { #endif + #if MICROPY_ENABLE_SCHEDULER + // can only switch threads if the scheduler is unlocked + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) + #endif + { MP_THREAD_GIL_EXIT(); MP_THREAD_GIL_ENTER(); + } } #endif @@ -1307,7 +1335,7 @@ exception_handler: const byte *ip = code_state->ip + 1; DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward code_state->ip = ip + ulab; // jump to after for-block - code_state->sp -= 4; // pop the exhausted iterator + code_state->sp -= MP_OBJ_ITER_BUF_NSLOTS; // pop the exhausted iterator goto outer_dispatch_loop; // continue with dispatch loop } else if (*code_state->ip == MP_BC_YIELD_FROM) { // StopIteration inside yield from call means return a value of @@ -1327,8 +1355,16 @@ unwind_loop: // But consider how to handle nested exceptions. // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj) if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) { - const byte *ip = code_state->code_info; + const byte *ip = code_state->fun_bc->bytecode; + mp_decode_uint(&ip); // skip n_state + mp_decode_uint(&ip); // skip n_exc_stack + ip++; // skip scope_params + ip++; // skip n_pos_args + ip++; // skip n_kwonly_args + ip++; // skip n_def_pos_args + size_t bc = code_state->ip - ip; size_t code_info_size = mp_decode_uint(&ip); + bc -= code_info_size; #if MICROPY_PERSISTENT_CODE qstr block_name = ip[0] | (ip[1] << 8); qstr source_file = ip[2] | (ip[3] << 8); @@ -1337,7 +1373,6 @@ unwind_loop: qstr block_name = mp_decode_uint(&ip); qstr source_file = mp_decode_uint(&ip); #endif - size_t bc = code_state->ip - code_state->code_info - code_info_size; size_t source_line = 1; size_t c; while ((c = *ip)) { @@ -1393,8 +1428,8 @@ unwind_loop: } else if (code_state->prev != NULL) { mp_globals_set(code_state->old_globals); code_state = code_state->prev; - fastn = &code_state->state[code_state->n_state - 1]; - exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state); + fastn = &code_state->state[n_state - 1]; + exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); // variables that are visible to the exception handler (declared volatile) currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack |
