diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/compile.c | 19 | ||||
-rw-r--r-- | py/emit.h | 2 | ||||
-rw-r--r-- | py/emitbc.c | 10 | ||||
-rw-r--r-- | py/emitcpy.c | 4 | ||||
-rw-r--r-- | py/emitnative.c | 2 | ||||
-rw-r--r-- | py/malloc.c | 10 | ||||
-rw-r--r-- | py/mpconfig.h | 6 | ||||
-rw-r--r-- | py/obj.c | 4 | ||||
-rw-r--r-- | py/obj.h | 4 | ||||
-rw-r--r-- | py/objarray.c | 55 | ||||
-rw-r--r-- | py/objcomplex.c | 4 | ||||
-rw-r--r-- | py/objdict.c | 9 | ||||
-rw-r--r-- | py/objexcept.c | 18 | ||||
-rw-r--r-- | py/objfloat.c | 2 | ||||
-rw-r--r-- | py/objgenerator.c | 7 | ||||
-rw-r--r-- | py/objlist.c | 9 | ||||
-rw-r--r-- | py/objnone.c | 11 | ||||
-rw-r--r-- | py/objstr.c | 66 | ||||
-rw-r--r-- | py/objtuple.c | 9 | ||||
-rw-r--r-- | py/parse.c | 6 | ||||
-rw-r--r-- | py/qstr.c | 16 | ||||
-rw-r--r-- | py/qstr.h | 2 | ||||
-rw-r--r-- | py/runtime.c | 77 | ||||
-rw-r--r-- | py/runtime0.h | 10 | ||||
-rw-r--r-- | py/showbc.c | 8 | ||||
-rw-r--r-- | py/vm.c | 45 |
26 files changed, 243 insertions, 172 deletions
diff --git a/py/compile.c b/py/compile.c index e1b62a11bf..c1a7955dcd 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1912,7 +1912,21 @@ void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); +#if MICROPY_EMIT_CPYTHON EMIT_ARG(unary_op, RT_UNARY_OP_NOT); +#else + // eliminate use of NOT byte code + int l_load_false = comp_next_label(comp); + int l_done = comp_next_label(comp); + int stack_size = EMIT(get_stack_size); + EMIT_ARG(pop_jump_if_true, l_load_false); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_TRUE); + EMIT_ARG(jump, l_done); + EMIT_ARG(label_assign, l_load_false); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_FALSE); + EMIT_ARG(label_assign, l_done); + EMIT_ARG(set_stack_size, stack_size); // force stack size since it counts 1 pop and 2 pushes statically, but really it's 1 pop and 1 push dynamically +#endif } void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2487,7 +2501,7 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_NULL(pn)) { // pass } else if (MP_PARSE_NODE_IS_LEAF(pn)) { - int arg = MP_PARSE_NODE_LEAF_ARG(pn); + machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break; case MP_PARSE_NODE_SMALL_INT: EMIT_ARG(load_const_small_int, arg); break; @@ -3016,7 +3030,8 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { scope->flags |= SCOPE_FLAG_OPTIMISED; // TODO possibly other ways it can be nested - if (scope->parent->kind == SCOPE_FUNCTION || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) { + // Note that we don't actually use this information at the moment (for CPython compat only) + if ((SCOPE_FUNCTION <= scope->parent->kind && scope->parent->kind <= SCOPE_SET_COMP) || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) { scope->flags |= SCOPE_FLAG_NESTED; } } @@ -34,7 +34,7 @@ typedef struct _emit_method_table_t { void (*import_from)(emit_t *emit, qstr qstr); void (*import_star)(emit_t *emit); void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok); - void (*load_const_small_int)(emit_t *emit, int arg); + void (*load_const_small_int)(emit_t *emit, machine_int_t arg); void (*load_const_int)(emit_t *emit, qstr qstr); void (*load_const_dec)(emit_t *emit, qstr qstr); void (*load_const_id)(emit_t *emit, qstr qstr); diff --git a/py/emitbc.c b/py/emitbc.c index 9fa2880ecb..d74b065253 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -108,7 +108,7 @@ static void emit_write_byte_code_byte_byte(emit_t* emit, byte b1, uint b2) { } // integers (for small ints) are stored as 24 bits, in excess -static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, int num) { +static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t num) { num += 0x800000; assert(0 <= num && num <= 0xffffff); byte* c = emit_get_cur_to_write_byte_code(emit, 4); @@ -249,6 +249,7 @@ static void emit_bc_set_stack_size(emit_t *emit, int size) { static void emit_bc_set_source_line(emit_t *emit, int source_line) { //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->byte_code_offset); +#if MICROPY_ENABLE_SOURCE_LINE if (source_line > emit->last_source_line) { uint bytes_to_skip = emit->byte_code_offset - emit->last_source_line_offset; uint lines_to_skip = source_line - emit->last_source_line; @@ -257,6 +258,7 @@ static void emit_bc_set_source_line(emit_t *emit, int source_line) { emit->last_source_line_offset = emit->byte_code_offset; emit->last_source_line = source_line; } +#endif } static void emit_bc_load_id(emit_t *emit, qstr qstr) { @@ -319,7 +321,7 @@ static void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { } } -static void emit_bc_load_const_small_int(emit_t *emit, int arg) { +static void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) { emit_pre(emit, 1); emit_write_byte_code_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg); } @@ -390,7 +392,7 @@ static void emit_bc_load_attr(emit_t *emit, qstr qstr) { } static void emit_bc_load_method(emit_t *emit, qstr qstr) { - emit_pre(emit, 0); + emit_pre(emit, 1); emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_METHOD, qstr); } @@ -707,7 +709,7 @@ static void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, b if (have_dbl_star_arg) { s += 1; } - emit_pre(emit, -n_positional - 2 * n_keyword - s); + emit_pre(emit, -1 - n_positional - 2 * n_keyword - s); int op; if (have_star_arg) { if (have_dbl_star_arg) { diff --git a/py/emitcpy.c b/py/emitcpy.c index 71861c918d..2e5c34cb2b 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -149,10 +149,10 @@ static void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) { } } -static void emit_cpy_load_const_small_int(emit_t *emit, int arg) { +static void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) { emit_pre(emit, 1, 3); if (emit->pass == PASS_3) { - printf("LOAD_CONST %d\n", arg); + printf("LOAD_CONST " INT_FMT "\n", arg); } } diff --git a/py/emitnative.c b/py/emitnative.c index 258aa9fce5..1e5ea1fa9b 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -599,7 +599,7 @@ static void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { emit_post_push_imm(emit, vtype, val); } -static void emit_native_load_const_small_int(emit_t *emit, int arg) { +static void emit_native_load_const_small_int(emit_t *emit, machine_int_t arg) { emit_pre(emit); if (emit->do_viper_types) { emit_post_push_imm(emit, VTYPE_INT, arg); diff --git a/py/malloc.c b/py/malloc.c index 4f01dc63f5..a2c55eb06b 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -4,6 +4,12 @@ #include "misc.h" #include "mpconfig.h" +#if 0 // print debugging info +#define DEBUG_printf(args...) printf(args) +#else // don't print debugging info +#define DEBUG_printf(args...) (void)0 +#endif + #if MICROPY_MEM_STATS static int total_bytes_allocated = 0; static int current_bytes_allocated = 0; @@ -26,6 +32,7 @@ void *m_malloc(int num_bytes) { current_bytes_allocated += num_bytes; UPDATE_PEAK(); #endif + DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); return ptr; } @@ -43,6 +50,7 @@ void *m_malloc0(int num_bytes) { current_bytes_allocated += num_bytes; UPDATE_PEAK(); #endif + DEBUG_printf("malloc0 %d : %p\n", num_bytes, ptr); return ptr; } @@ -67,6 +75,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) { current_bytes_allocated += diff; UPDATE_PEAK(); #endif + DEBUG_printf("realloc %d, %d : %p\n", old_num_bytes, new_num_bytes, ptr); return ptr; } @@ -77,6 +86,7 @@ void m_free(void *ptr, int num_bytes) { #if MICROPY_MEM_STATS current_bytes_allocated -= num_bytes; #endif + DEBUG_printf("free %p, %d\n", ptr, num_bytes); } int m_get_total_bytes_allocated(void) { diff --git a/py/mpconfig.h b/py/mpconfig.h index 97e4b13875..38b74b733a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -76,6 +76,12 @@ typedef long long mp_longint_impl_t; #endif +// Whether to include information in the byte code to determine source +// line number (increases RAM usage, but doesn't slow byte code execution) +#ifndef MICROPY_ENABLE_SOURCE_LINE +#define MICROPY_ENABLE_SOURCE_LINE (0) +#endif + // Whether to support float and complex types #ifndef MICROPY_ENABLE_FLOAT #define MICROPY_ENABLE_FLOAT (0) @@ -57,7 +57,11 @@ void mp_obj_print_exception(mp_obj_t exc) { if (n > 0) { printf("Traceback (most recent call last):\n"); for (int i = n - 3; i >= 0; i -= 3) { +#if MICROPY_ENABLE_SOURCE_LINE printf(" File \"%s\", line %d, in %s\n", qstr_str(values[i]), (int)values[i + 1], qstr_str(values[i + 2])); +#else + printf(" File \"%s\", in %s\n", qstr_str(values[i]), qstr_str(values[i + 2])); +#endif } } } @@ -223,7 +223,7 @@ mp_obj_t mp_obj_new_range(int start, int stop, int step); mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step); mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code); mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun); -mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun); +mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple); mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items); @@ -291,6 +291,7 @@ uint mp_obj_str_get_len(mp_obj_t self_in); 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 byte *mp_obj_str_get_data(mp_obj_t self_in, uint *len); +void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len); // bytes extern const mp_obj_type_t bytes_type; @@ -348,6 +349,7 @@ extern const mp_obj_type_t zip_type; // array extern const mp_obj_type_t array_type; uint mp_obj_array_len(mp_obj_t self_in); +mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items); // functions typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM) diff --git a/py/objarray.c b/py/objarray.c index 4f36561153..42dbfcda05 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -124,17 +124,22 @@ static void array_set_el(mp_obj_array_t *o, int index, mp_obj_t val_in) { static void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_array_t *o = o_in; if (o->typecode == BYTEARRAY_TYPECODE) { - print(env, "bytearray([", o->typecode); + print(env, "bytearray(b", o->typecode); + mp_str_print_quoted(print, env, o->items, o->len); } else { - print(env, "array('%c', [", o->typecode); - } - for (int i = 0; i < o->len; i++) { - if (i > 0) { - print(env, ", "); + print(env, "array('%c'", o->typecode); + if (o->len > 0) { + print(env, ", [", o->typecode); + for (int i = 0; i < o->len; i++) { + if (i > 0) { + print(env, ", "); + } + print(env, "%d", array_get_el(o, i)); + } + print(env, "]"); } - print(env, "%d", array_get_el(o, i)); } - print(env, "])"); + print(env, ")"); } static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { @@ -164,20 +169,17 @@ static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { } static mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { - switch (n_args) { - case 2: - { - // TODO check args - uint l; - const byte *s = mp_obj_str_get_data(args[0], &l); - mp_obj_t initializer = args[1]; - return array_construct(*s, initializer); - } - - default: - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args)); + if (n_args < 1 || n_args > 2) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args)); + } + // TODO check args + uint l; + const byte *typecode = mp_obj_str_get_data(args[0], &l); + if (n_args == 1) { + return array_new(*typecode, 0); } - return NULL; + + return array_construct(*typecode, args[1]); } // This is top-level factory function, not virtual method @@ -269,6 +271,17 @@ mp_obj_t mp_obj_new_bytearray(uint n, void *items) { return o; } +// Create bytearray which references specified memory area +mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) { + mp_obj_array_t *o = m_new_obj(mp_obj_array_t); + o->base.type = &array_type; + o->typecode = BYTEARRAY_TYPECODE; + o->free = 0; + o->len = n; + o->items = items; + return o; +} + /******************************************************************************/ /* array iterator */ diff --git a/py/objcomplex.c b/py/objcomplex.c index af148a2786..24762e8b11 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -24,9 +24,9 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag); void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_complex_t *o = o_in; if (o->real == 0) { - print(env, "%.8gj", o->imag); + print(env, "%.8gj", (double) o->imag); } else { - print(env, "(%.8g+%.8gj)", o->real, o->imag); + print(env, "(%.8g+%.8gj)", (double) o->real, (double) o->imag); } } diff --git a/py/objdict.c b/py/objdict.c index 55a612913d..93ff1af90a 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -43,6 +43,14 @@ static mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp return rt_build_map(0); } +static mp_obj_t dict_unary_op(int op, mp_obj_t self_in) { + mp_obj_dict_t *self = self_in; + switch (op) { + case RT_UNARY_OP_NOT: if (self->map.used == 0) { return mp_const_true; } else { return mp_const_false; } + default: return MP_OBJ_NULL; // op not supported for None + } +} + static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_dict_t *o = lhs_in; switch (op) { @@ -436,6 +444,7 @@ const mp_obj_type_t dict_type = { "dict", .print = dict_print, .make_new = dict_make_new, + .unary_op = dict_unary_op, .binary_op = dict_binary_op, .getiter = dict_getiter, .methods = dict_type_methods, diff --git a/py/objexcept.c b/py/objexcept.c index c91b71dd9e..8eb4e966e9 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -13,20 +13,19 @@ // This is unified class for C-level and Python-level exceptions // Python-level exception have empty ->msg and all arguments are in -// args tuple. C-level excepttion likely have ->msg, and may as well -// have args tuple (or otherwise have it as NULL). +// args tuple. C-level excepttion likely have ->msg and args is empty. typedef struct mp_obj_exception_t { mp_obj_base_t base; mp_obj_t traceback; // a list object, holding (file,line,block) as numbers (not Python objects); a hack for now qstr id; - qstr msg; + vstr_t *msg; mp_obj_tuple_t args; } mp_obj_exception_t; void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = o_in; - if (o->msg != 0) { - print(env, "%s: %s", qstr_str(o->id), qstr_str(o->msg)); + if (o->msg != NULL) { + print(env, "%s: %s", qstr_str(o->id), vstr_str(o->msg)); } else { // Yes, that's how CPython has it if (kind == PRINT_REPR) { @@ -55,7 +54,7 @@ static mp_obj_t exception_call(mp_obj_t self_in, uint n_args, uint n_kw, const m mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args); o->base.type = &exception_type; o->id = base->id; - o->msg = 0; + o->msg = NULL; o->args.len = n_args; memcpy(o->args.items, args, n_args * sizeof(mp_obj_t)); return o; @@ -92,15 +91,14 @@ mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) { o->id = id; o->args.len = 0; if (fmt == NULL) { - o->msg = 0; + o->msg = NULL; } else { // render exception message - vstr_t *vstr = vstr_new(); + o->msg = vstr_new(); va_list ap; va_start(ap, fmt); - vstr_vprintf(vstr, fmt, ap); + vstr_vprintf(o->msg, fmt, ap); va_end(ap); - o->msg = qstr_from_strn_take(vstr->buf, vstr->alloc, vstr->len); } return o; diff --git a/py/objfloat.c b/py/objfloat.c index 9f1f478cab..69fd65e199 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -21,7 +21,7 @@ mp_obj_t mp_obj_new_float(mp_float_t value); static void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_float_t *o = o_in; - print(env, "%.8g", o->value); + print(env, "%.8g", (double) o->value); } static mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { diff --git a/py/objgenerator.c b/py/objgenerator.c index 91bbbceb2f..67f8eed59c 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -16,7 +16,6 @@ typedef struct _mp_obj_gen_wrap_t { mp_obj_base_t base; - uint n_state; mp_obj_t *fun; } mp_obj_gen_wrap_t; @@ -35,7 +34,7 @@ mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments")); } - return mp_obj_new_gen_instance(bc_code, self->n_state, n_args, args); + return mp_obj_new_gen_instance(bc_code, bc_n_state, n_args, args); } const mp_obj_type_t gen_wrap_type = { @@ -44,11 +43,9 @@ const mp_obj_type_t gen_wrap_type = { .call = gen_wrap_call, }; -mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun) { +mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) { mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t); o->base.type = &gen_wrap_type; - // we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done - o->n_state = (n_locals < 3 ? 3 : n_locals) + n_stack; o->fun = fun; return o; } diff --git a/py/objlist.c b/py/objlist.c index d21e16000d..fb68e2c566 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -122,6 +122,14 @@ static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { return true; } +static mp_obj_t list_unary_op(int op, mp_obj_t self_in) { + mp_obj_list_t *self = self_in; + switch (op) { + case RT_UNARY_OP_NOT: if (self->len == 0) { return mp_const_true; } else { return mp_const_false; } + default: return MP_OBJ_NULL; // op not supported for None + } +} + static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = lhs; switch (op) { @@ -399,6 +407,7 @@ const mp_obj_type_t list_type = { "list", .print = list_print, .make_new = list_make_new, + .unary_op = list_unary_op, .binary_op = list_binary_op, .getiter = list_getiter, .methods = list_type_methods, diff --git a/py/objnone.c b/py/objnone.c index ecc7c4b4e7..4151403b21 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -6,19 +6,28 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "runtime0.h" typedef struct _mp_obj_none_t { mp_obj_base_t base; } mp_obj_none_t; -void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +static void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { print(env, "None"); } +static mp_obj_t none_unary_op(int op, mp_obj_t o_in) { + switch (op) { + case RT_UNARY_OP_NOT: return mp_const_true; + default: return MP_OBJ_NULL; // op not supported for None + } +} + const mp_obj_type_t none_type = { { &mp_const_type }, "NoneType", .print = none_print, + .unary_op = none_unary_op, }; static const mp_obj_none_t none_obj = {{&none_type}}; diff --git a/py/objstr.c b/py/objstr.c index 84ac74bab9..c30da00d71 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -34,45 +34,49 @@ static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str); /******************************************************************************/ /* str */ -void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) { + // this escapes characters, but it will be very slow to print (calling print many times) + bool has_single_quote = false; + bool has_double_quote = false; + for (const byte *s = str_data, *top = str_data + str_len; (!has_single_quote || !has_double_quote) && s < top; s++) { + if (*s == '\'') { + has_single_quote = true; + } else if (*s == '"') { + has_double_quote = true; + } + } + int quote_char = '\''; + if (has_single_quote && !has_double_quote) { + quote_char = '"'; + } + print(env, "%c", quote_char); + for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { + if (*s == quote_char) { + print(env, "\\%c", quote_char); + } else if (*s == '\\') { + print(env, "\\\\"); + } else if (32 <= *s && *s <= 126) { + print(env, "%c", *s); + } else if (*s == '\n') { + print(env, "\\n"); + // TODO add more escape codes here if we want to match CPython + } else { + print(env, "\\x%02x", *s); + } + } + print(env, "%c", quote_char); +} + +static void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { GET_STR_DATA_LEN(self_in, str_data, str_len); bool is_bytes = MP_OBJ_IS_TYPE(self_in, &bytes_type); if (kind == PRINT_STR && !is_bytes) { print(env, "%.*s", str_len, str_data); } else { - // this escapes characters, but it will be very slow to print (calling print many times) - bool has_single_quote = false; - bool has_double_quote = false; - for (const byte *s = str_data, *top = str_data + str_len; (!has_single_quote || !has_double_quote) && s < top; s++) { - if (*s == '\'') { - has_single_quote = true; - } else if (*s == '"') { - has_double_quote = true; - } - } if (is_bytes) { print(env, "b"); } - int quote_char = '\''; - if (has_single_quote && !has_double_quote) { - quote_char = '"'; - } - print(env, "%c", quote_char); - for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { - if (*s == quote_char) { - print(env, "\\%c", quote_char); - } else if (*s == '\\') { - print(env, "\\\\"); - } else if (32 <= *s && *s <= 126) { - print(env, "%c", *s); - } else if (*s == '\n') { - print(env, "\\n"); - // TODO add more escape codes here if we want to match CPython - } else { - print(env, "\\x%02x", *s); - } - } - print(env, "%c", quote_char); + mp_str_print_quoted(print, env, str_data, str_len); } } diff --git a/py/objtuple.c b/py/objtuple.c index ec35ef8550..754fe4b662 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -73,6 +73,14 @@ static mp_obj_t tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m } } +static mp_obj_t tuple_unary_op(int op, mp_obj_t self_in) { + mp_obj_tuple_t *self = self_in; + switch (op) { + case RT_UNARY_OP_NOT: if (self->len == 0) { return mp_const_true; } else { return mp_const_false; } + default: return MP_OBJ_NULL; // op not supported for None + } +} + static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_tuple_t *o = lhs; switch (op) { @@ -97,6 +105,7 @@ const mp_obj_type_t tuple_type = { "tuple", .print = tuple_print, .make_new = tuple_make_new, + .unary_op = tuple_unary_op, .binary_op = tuple_binary_op, .getiter = tuple_getiter, }; diff --git a/py/parse.c b/py/parse.c index d9969d6785..d0776cefba 100644 --- a/py/parse.c +++ b/py/parse.c @@ -172,15 +172,15 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) { if (MP_PARSE_NODE_IS_NULL(pn)) { printf("NULL\n"); } else if (MP_PARSE_NODE_IS_LEAF(pn)) { - int arg = MP_PARSE_NODE_LEAF_ARG(pn); + machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break; - case MP_PARSE_NODE_SMALL_INT: printf("int(%d)\n", arg); break; + case MP_PARSE_NODE_SMALL_INT: printf("int(" INT_FMT ")\n", arg); break; case MP_PARSE_NODE_INTEGER: printf("int(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_DECIMAL: printf("dec(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_STRING: printf("str(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_BYTES: printf("bytes(%s)\n", qstr_str(arg)); break; - case MP_PARSE_NODE_TOKEN: printf("tok(%d)\n", arg); break; + case MP_PARSE_NODE_TOKEN: printf("tok(" INT_FMT ")\n", arg); break; default: assert(0); } } else { @@ -185,3 +185,19 @@ const byte *qstr_data(qstr q, uint *len) { *len = Q_GET_LENGTH(qd); return Q_GET_DATA(qd); } + +void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes) { + *n_pool = 0; + *n_qstr = 0; + *n_str_data_bytes = 0; + *n_total_bytes = 0; + for (qstr_pool_t *pool = last_pool; pool != NULL && pool != &const_pool; pool = pool->prev) { + *n_pool += 1; + *n_qstr += pool->len; + for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + *n_str_data_bytes += Q_GET_ALLOC(*q); + } + *n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc; + } + *n_total_bytes += *n_str_data_bytes; +} @@ -36,3 +36,5 @@ machine_uint_t qstr_hash(qstr q); const char* qstr_str(qstr q); uint qstr_len(qstr q); const byte* qstr_data(qstr q, uint *len); + +void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes); diff --git a/py/runtime.c b/py/runtime.c index 8ad98d5f12..6dd6921599 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -44,11 +44,14 @@ typedef enum { } mp_code_kind_t; typedef struct _mp_code_t { - mp_code_kind_t kind; - int n_args; - int n_locals; - int n_stack; - bool is_generator; + struct { + mp_code_kind_t kind : 8; + bool is_generator : 1; + }; + struct { + uint n_args : 16; + uint n_state : 16; + }; union { struct { byte *code; @@ -63,7 +66,7 @@ typedef struct _mp_code_t { }; } mp_code_t; -static int next_unique_code_id; +static uint next_unique_code_id; static machine_uint_t unique_codes_alloc = 0; static mp_code_t *unique_codes = NULL; @@ -130,7 +133,6 @@ void rt_init(void) { mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array); rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type); - rt_store_name(MP_QSTR_array, m_array); // built-in user functions mp_map_add_qstr(&map_builtins, MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj); @@ -188,37 +190,37 @@ void rt_deinit(void) { #endif } -int rt_get_unique_code_id(void) { +uint rt_get_unique_code_id(void) { return next_unique_code_id++; } static void alloc_unique_codes(void) { if (next_unique_code_id > unique_codes_alloc) { + DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id); // increase size of unique_codes table unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id); - for (int i = unique_codes_alloc; i < next_unique_code_id; i++) { + for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) { unique_codes[i].kind = MP_CODE_NONE; } unique_codes_alloc = next_unique_code_id; } } -void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) { +void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) { alloc_unique_codes(); assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); unique_codes[unique_code_id].kind = MP_CODE_BYTE; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].n_locals = n_locals; - unique_codes[unique_code_id].n_stack = n_stack; unique_codes[unique_code_id].is_generator = is_generator; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].n_state = n_locals + n_stack; unique_codes[unique_code_id].u_byte.code = code; unique_codes[unique_code_id].u_byte.len = len; //printf("byte code: %d bytes\n", len); #ifdef DEBUG_PRINT - DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args); + DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d n_locals=%d n_stack=%d\n", unique_code_id, code, len, n_args, n_locals, n_stack); for (int i = 0; i < 128 && i < len; i++) { if (i > 0 && i % 16 == 0) { DEBUG_printf("\n"); @@ -239,15 +241,14 @@ void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, i #endif } -void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args) { +void rt_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) { alloc_unique_codes(); assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); unique_codes[unique_code_id].kind = MP_CODE_NATIVE; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].n_locals = 0; - unique_codes[unique_code_id].n_stack = 0; unique_codes[unique_code_id].is_generator = false; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].n_state = 0; unique_codes[unique_code_id].u_native.fun = fun; //printf("native code: %d bytes\n", len); @@ -272,15 +273,14 @@ void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args) #endif } -void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_args) { +void rt_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) { alloc_unique_codes(); assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].n_locals = 0; - unique_codes[unique_code_id].n_stack = 0; unique_codes[unique_code_id].is_generator = false; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].n_state = 0; unique_codes[unique_code_id].u_inline_asm.fun = fun; #ifdef DEBUG_PRINT @@ -316,23 +316,18 @@ int rt_is_true(mp_obj_t arg) { return 0; } else if (arg == mp_const_true) { return 1; - } else if (MP_OBJ_IS_STR(arg)) { - return mp_obj_str_get_len(arg) != 0; - } else if (MP_OBJ_IS_TYPE(arg, &list_type)) { - uint len; - mp_obj_t *dummy; - mp_obj_list_get(arg, &len, &dummy); - return len != 0; - } else if (MP_OBJ_IS_TYPE(arg, &tuple_type)) { - uint len; - mp_obj_t *dummy; - mp_obj_tuple_get(arg, &len, &dummy); - return len != 0; - } else if (MP_OBJ_IS_TYPE(arg, &dict_type)) { - return mp_obj_dict_len(arg) != 0; } else { - assert(0); - return 0; + mp_obj_t len = mp_obj_len_maybe(arg); + if (len != MP_OBJ_NULL) { + // obj has a length, truth determined if len != 0 + return len != MP_OBJ_NEW_SMALL_INT(0); + } else { + // TODO check for __bool__ method + // TODO check floats and complex numbers + + // any other obj is true (TODO is that correct?) + return 1; + } } } @@ -481,7 +476,7 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) { if (MP_OBJ_IS_SMALL_INT(arg)) { mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); switch (op) { - case RT_UNARY_OP_NOT: if (val != 0) { return mp_const_true;} else { return mp_const_false; } + case RT_UNARY_OP_NOT: if (val == 0) { return mp_const_true;} else { return mp_const_false; } case RT_UNARY_OP_POSITIVE: break; case RT_UNARY_OP_NEGATIVE: val = -val; break; case RT_UNARY_OP_INVERT: val = ~val; break; @@ -684,7 +679,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) { mp_obj_t fun; switch (c->kind) { case MP_CODE_BYTE: - fun = mp_obj_new_fun_bc(c->n_args, c->n_locals + c->n_stack, c->u_byte.code); + fun = mp_obj_new_fun_bc(c->n_args, c->n_state, c->u_byte.code); break; case MP_CODE_NATIVE: fun = rt_make_function_n(c->n_args, c->u_native.fun); @@ -699,7 +694,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) { // check for generator functions and if so wrap in generator object if (c->is_generator) { - fun = mp_obj_new_gen_wrap(c->n_locals, c->n_stack, fun); + fun = mp_obj_new_gen_wrap(fun); } return fun; diff --git a/py/runtime0.h b/py/runtime0.h index 4fdcdc3cc9..cd82b1412b 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -1,5 +1,5 @@ typedef enum { - RT_UNARY_OP_NOT, + RT_UNARY_OP_NOT, // TODO remove this op since it's no longer needed RT_UNARY_OP_POSITIVE, RT_UNARY_OP_NEGATIVE, RT_UNARY_OP_INVERT, @@ -78,7 +78,7 @@ extern void *const rt_fun_table[RT_F_NUMBER_OF]; void rt_init(void); void rt_deinit(void); -int rt_get_unique_code_id(void); -void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator); -void rt_assign_native_code(int unique_code_id, void *f, uint len, int n_args); -void rt_assign_inline_asm_code(int unique_code_id, void *f, uint len, int n_args); +uint rt_get_unique_code_id(void); +void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator); +void rt_assign_native_code(uint unique_code_id, void *f, uint len, int n_args); +void rt_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args); diff --git a/py/showbc.c b/py/showbc.c index f914223933..d7ae17c2e3 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -68,12 +68,10 @@ void mp_byte_code_print(const byte *ip, int len) { printf("LOAD_CONST_INT %s", qstr_str(qstr)); break; - /* case MP_BC_LOAD_CONST_DEC: DECODE_QSTR; - PUSH(rt_load_const_dec(qstr)); + printf("LOAD_CONST_DEC %s", qstr_str(qstr)); break; - */ case MP_BC_LOAD_CONST_ID: DECODE_QSTR; @@ -351,12 +349,12 @@ void mp_byte_code_print(const byte *ip, int len) { case MP_BC_IMPORT_NAME: DECODE_QSTR; - printf("IMPORT NAME %s", qstr_str(qstr)); + printf("IMPORT_NAME %s", qstr_str(qstr)); break; case MP_BC_IMPORT_FROM: DECODE_QSTR; - printf("IMPORT NAME %s", qstr_str(qstr)); + printf("IMPORT_FROM %s", qstr_str(qstr)); break; default: @@ -26,8 +26,6 @@ #define SET_TOP(val) *sp = (val) mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, uint n_state) { - n_state += 1; // XXX there is a bug somewhere which doesn't count enough state... (conwaylife and mandel have the bug) - // allocate state for locals and stack mp_obj_t temp_state[10]; mp_obj_t *state = &temp_state[0]; @@ -82,7 +80,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob machine_uint_t unum; qstr qst; mp_obj_t obj1, obj2; - mp_obj_t fast0 = fastn[0], fast1 = fastn[-1], fast2 = fastn[-2]; nlr_buf_t nlr; volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions @@ -90,8 +87,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob machine_uint_t *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop) - // TODO if an exception occurs, do fast[0,1,2] become invalid?? - // outer exception handling loop for (;;) { if (nlr_push(&nlr) == 0) { @@ -148,15 +143,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob break; case MP_BC_LOAD_FAST_0: - PUSH(fast0); + PUSH(fastn[0]); break; case MP_BC_LOAD_FAST_1: - PUSH(fast1); + PUSH(fastn[-1]); break; case MP_BC_LOAD_FAST_2: - PUSH(fast2); + PUSH(fastn[-2]); break; case MP_BC_LOAD_FAST_N: @@ -166,16 +161,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_LOAD_DEREF: DECODE_UINT; - if (unum == 0) { - obj1 = fast0; - } else if (unum == 1) { - obj1 = fast1; - } else if (unum == 2) { - obj1 = fast2; - } else { - obj1 = fastn[-unum]; - } - PUSH(rt_get_cell(obj1)); + PUSH(rt_get_cell(fastn[-unum])); break; case MP_BC_LOAD_NAME: @@ -204,15 +190,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob break; case MP_BC_STORE_FAST_0: - fast0 = POP(); + fastn[0] = POP(); break; case MP_BC_STORE_FAST_1: - fast1 = POP(); + fastn[-1] = POP(); break; case MP_BC_STORE_FAST_2: - fast2 = POP(); + fastn[-2] = POP(); break; case MP_BC_STORE_FAST_N: @@ -222,16 +208,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_STORE_DEREF: DECODE_UINT; - if (unum == 0) { - obj1 = fast0; - } else if (unum == 1) { - obj1 = fast1; - } else if (unum == 2) { - obj1 = fast2; - } else { - obj1 = fastn[-unum]; - } - rt_set_cell(obj1, POP()); + rt_set_cell(fastn[-unum], POP()); break; case MP_BC_STORE_NAME: @@ -479,8 +456,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_MAKE_CLOSURE: DECODE_UINT; - obj1 = POP(); - PUSH(rt_make_closure_from_id(unum, obj1)); + SET_TOP(rt_make_closure_from_id(unum, TOP())); break; case MP_BC_CALL_FUNCTION: @@ -514,9 +490,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_YIELD_VALUE: nlr_pop(); *ip_in_out = ip; - fastn[0] = fast0; - fastn[-1] = fast1; - fastn[-2] = fast2; *sp_in_out = sp; return true; |