diff options
Diffstat (limited to 'py/runtime.c')
| -rw-r--r-- | py/runtime.c | 126 |
1 files changed, 73 insertions, 53 deletions
diff --git a/py/runtime.c b/py/runtime.c index a7ff57a47..a9c0ef1e2 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -95,8 +95,10 @@ void mp_init(void) { MICROPY_PORT_INIT_FUNC; #endif + #if MICROPY_ENABLE_COMPILER // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; + #endif // init global module dict mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); @@ -118,7 +120,6 @@ void mp_init(void) { for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) { MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL; } - MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL; #endif #ifdef MICROPY_FSUSERMOUNT @@ -246,7 +247,7 @@ void mp_delete_global(qstr qst) { } mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { - DEBUG_OP_printf("unary " UINT_FMT " %p\n", op, arg); + DEBUG_OP_printf("unary " UINT_FMT " %q %p\n", op, mp_unary_op_method_name[op], arg); if (op == MP_UNARY_OP_NOT) { // "not x" is the negative of whether "x" is true per Python semantics @@ -307,7 +308,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { } mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { - DEBUG_OP_printf("binary " UINT_FMT " %p %p\n", op, lhs, rhs); + DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs); // TODO correctly distinguish inplace operators for mutable objects // lookup logic that CPython uses for +=: @@ -445,7 +446,6 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { // use standard precision return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); } - break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: @@ -520,10 +520,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return MP_OBJ_FROM_PTR(tuple); } - case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); break; - case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); break; - case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); break; - case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); break; + case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); default: goto unsupported_op; @@ -555,38 +555,12 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } } - /* deal with `in` - * - * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch - * needs to go below with swapped arguments - */ + // Convert MP_BINARY_OP_IN to MP_BINARY_OP_CONTAINS with swapped args. if (op == MP_BINARY_OP_IN) { - mp_obj_type_t *type = mp_obj_get_type(rhs); - if (type->binary_op != NULL) { - mp_obj_t res = type->binary_op(op, rhs, lhs); - if (res != MP_OBJ_NULL) { - return res; - } - } - if (type->getiter != NULL) { - /* second attempt, walk the iterator */ - mp_obj_iter_buf_t iter_buf; - mp_obj_t iter = mp_getiter(rhs, &iter_buf); - mp_obj_t next; - while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - if (mp_obj_equal(next, lhs)) { - return mp_const_true; - } - } - return mp_const_false; - } - - if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not iterable"); - } else { - mp_raise_TypeError_varg( - "'%s' object is not iterable", mp_obj_get_type_str(rhs)); - } + op = MP_BINARY_OP_CONTAINS; + mp_obj_t temp = lhs; + lhs = rhs; + rhs = temp; } // generic binary_op supplied by type @@ -615,6 +589,20 @@ generic_binary_op: } #endif + if (op == MP_BINARY_OP_CONTAINS) { + // If type didn't support containment then explicitly walk the iterator. + // mp_getiter will raise the appropriate exception if lhs is not iterable. + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = mp_getiter(lhs, &iter_buf); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_obj_equal(next, rhs)) { + return mp_const_true; + } + } + return mp_const_false; + } + unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("unsupported type for operator"); @@ -712,7 +700,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len); - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -733,7 +721,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len); - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -749,7 +737,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3; - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -766,7 +754,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (args2_len >= args2_alloc) { - args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2); + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), args2_alloc * 2 * sizeof(mp_obj_t)); args2_alloc *= 2; } args2[args2_len++] = item; @@ -792,8 +780,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ if (MP_MAP_SLOT_IS_FILLED(map, i)) { // the key must be a qstr, so intern it if it's a string mp_obj_t key = map->table[i].key; - if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { - key = mp_obj_str_intern(key); + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); } args2[args2_len++] = key; args2[args2_len++] = map->table[i].value; @@ -817,13 +805,13 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ if (new_alloc < 4) { new_alloc = 4; } - args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), new_alloc * sizeof(mp_obj_t)); args2_alloc = new_alloc; } // the key must be a qstr, so intern it if it's a string - if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { - key = mp_obj_str_intern(key); + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); } // get the value corresponding to the key @@ -849,7 +837,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args); mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); return res; } @@ -1144,6 +1132,22 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { } } +// Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_load_method_maybe(obj, attr, dest); + nlr_pop(); + } else { + if (!catch_all_exc + && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), + MP_OBJ_FROM_PTR(&mp_type_AttributeError))) { + // Re-raise the exception + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } +} + void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); mp_obj_type_t *type = mp_obj_get_type(base); @@ -1304,13 +1308,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th if (type->iternext != NULL && send_value == mp_const_none) { mp_obj_t ret = type->iternext(self_in); + *ret_val = ret; if (ret != MP_OBJ_STOP_ITERATION) { - *ret_val = ret; return MP_VM_RETURN_YIELD; } else { // Emulate raise StopIteration() // Special case, handled in vm.c - *ret_val = MP_OBJ_NULL; return MP_VM_RETURN_NORMAL; } } @@ -1372,7 +1375,7 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() - *ret_val = throw_value; + *ret_val = mp_make_raise_obj(throw_value); return MP_VM_RETURN_EXCEPTION; } } @@ -1426,6 +1429,8 @@ import_error: return dest[0]; } + #if MICROPY_ENABLE_EXTERNAL_IMPORT + // See if it's a package, then can try FS import if (!mp_obj_is_package(module)) { goto import_error; @@ -1436,11 +1441,12 @@ import_error: 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); - char *dot_name = alloca(dot_name_len); + char *dot_name = mp_local_alloc(dot_name_len); memcpy(dot_name, pkg_name, pkg_name_len); dot_name[pkg_name_len] = '.'; memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name)); qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len); + mp_local_free(dot_name); mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(dot_name_q); @@ -1451,6 +1457,13 @@ import_error: // TODO lookup __import__ and call that instead of going straight to builtin implementation return mp_builtin___import__(5, args); + + #else + + // Package import not supported with external imports disabled + goto import_error; + + #endif } void mp_import_all(mp_obj_t module) { @@ -1585,3 +1598,10 @@ NORETURN void mp_raise_OSError(int errno_) { NORETURN void mp_raise_NotImplementedError(const char *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } + +#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK +NORETURN void mp_raise_recursion_depth(void) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); +} +#endif |
