summaryrefslogtreecommitdiff
path: root/py/runtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/runtime.c')
-rw-r--r--py/runtime.c126
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