summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/bc.h1
-rw-r--r--py/builtinimport.c2
-rw-r--r--py/emitglue.c2
-rw-r--r--py/obj.h1
-rw-r--r--py/objexcept.c43
-rw-r--r--py/py.mk7
-rw-r--r--py/showbc.c18
-rw-r--r--py/vm.c46
8 files changed, 85 insertions, 35 deletions
diff --git a/py/bc.h b/py/bc.h
index fb672ea03b..964c29f045 100644
--- a/py/bc.h
+++ b/py/bc.h
@@ -13,6 +13,7 @@ typedef struct _mp_exc_stack {
mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret);
mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out, volatile mp_obj_t inject_exc);
void mp_byte_code_print(const byte *code, int len);
+void mp_byte_code_print2(const byte *code, int len);
// Helper macros to access pointer with least significant bit holding a flag
#define MP_TAGPTR_PTR(x) ((void*)((machine_uint_t)(x) & ~((machine_uint_t)1)))
diff --git a/py/builtinimport.c b/py/builtinimport.c
index 4a2f6510c3..07978e61d7 100644
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -122,7 +122,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
// TODO handle compile error correctly
mp_locals_set(old_locals);
mp_globals_set(old_globals);
- return;
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "Syntax error in imported module"));
}
// complied successfully, execute it
diff --git a/py/emitglue.c b/py/emitglue.c
index 8b1fd97021..dddeea1b57 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -159,7 +159,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
}
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) {
- DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, argrs);
+ DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, args);
// make function object
mp_obj_t ffun;
if (n_closed_over & 0x100) {
diff --git a/py/obj.h b/py/obj.h
index d62d376ab4..6bb264c1c3 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -351,6 +351,7 @@ mp_obj_t mp_obj_new_float(mp_float_t val);
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
#endif
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
+mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
diff --git a/py/objexcept.c b/py/objexcept.c
index 781a00405c..160cf09fd4 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -14,11 +14,11 @@
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
- mp_obj_tuple_t args;
+ mp_obj_tuple_t *args;
} mp_obj_exception_t;
// Instance of MemoryError exception - needed by mp_malloc_fail
-const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}};
+const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_OBJ_NULL, mp_const_empty_tuple};
// Local non-heap memory for allocating an exception when we run out of RAM
STATIC mp_obj_exception_t mp_emergency_exception_obj;
@@ -26,7 +26,7 @@ STATIC mp_obj_exception_t mp_emergency_exception_obj;
// Instance of GeneratorExit exception - needed by generator.close()
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
// definition module-private so far, have it here.
-const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}};
+const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, mp_const_empty_tuple};
STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_exception_t *o = o_in;
@@ -36,15 +36,15 @@ STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...
print(env, "%s: ", qstr_str(o->base.type->name));
}
if (kind == PRINT_STR || kind == PRINT_EXC) {
- if (o->args.len == 0) {
+ if (o->args == NULL || o->args->len == 0) {
print(env, "");
return;
- } else if (o->args.len == 1) {
- mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
+ } else if (o->args->len == 1) {
+ mp_obj_print_helper(print, env, o->args->items[0], PRINT_STR);
return;
}
}
- tuple_print(print, env, &o->args, kind);
+ tuple_print(print, env, o->args, kind);
}
STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
@@ -54,35 +54,35 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", mp_obj_get_type_str(type_in)));
}
- mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, n_args);
+ mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0);
if (o == NULL) {
// Couldn't allocate heap memory; use local data instead.
o = &mp_emergency_exception_obj;
// We can't store any args.
n_args = 0;
+ o->args = mp_const_empty_tuple;
+ } else {
+ o->args = mp_obj_new_tuple(n_args, args);
}
o->base.type = type;
o->traceback = MP_OBJ_NULL;
- o->args.base.type = &mp_type_tuple;
- o->args.len = n_args;
- memcpy(o->args.items, args, n_args * sizeof(mp_obj_t));
return o;
}
// Get exception "value" - that is, first argument, or None
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
mp_obj_exception_t *self = self_in;
- if (self->args.len == 0) {
+ if (self->args->len == 0) {
return mp_const_none;
} else {
- return self->args.items[0];
+ return self->args->items[0];
}
}
STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_exception_t *self = self_in;
if (attr == MP_QSTR_args) {
- dest[0] = &self->args;
+ dest[0] = self->args;
} else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {
dest[0] = mp_obj_exception_get_value(self);
}
@@ -191,6 +191,11 @@ mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
return mp_obj_new_exception_args(exc_type, 0, NULL);
}
+// "Optimized" version for common(?) case of having 1 exception arg
+mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
+ return mp_obj_new_exception_args(exc_type, 1, &arg);
+}
+
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args) {
assert(exc_type->make_new == mp_obj_exception_make_new);
return exc_type->make_new((mp_obj_t)exc_type, n_args, 0, args);
@@ -205,20 +210,18 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
assert(exc_type->make_new == mp_obj_exception_make_new);
// make exception object
- mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 1);
+ mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 0);
if (o == NULL) {
// Couldn't allocate heap memory; use local data instead.
// Unfortunately, we won't be able to format the string...
o = &mp_emergency_exception_obj;
o->base.type = exc_type;
o->traceback = MP_OBJ_NULL;
- o->args.base.type = &mp_type_tuple;
- o->args.len = 0;
+ o->args = mp_const_empty_tuple;
} else {
o->base.type = exc_type;
o->traceback = MP_OBJ_NULL;
- o->args.base.type = &mp_type_tuple;
- o->args.len = 1;
+ o->args = mp_obj_new_tuple(1, NULL);
if (fmt == NULL) {
// no message
@@ -231,7 +234,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
va_start(ap, fmt);
vstr_vprintf(vstr, fmt, ap);
va_end(ap);
- o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
+ o->args->items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
vstr_free(vstr);
}
}
diff --git a/py/py.mk b/py/py.mk
index 5b0dd3d3a8..aa282b3808 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -7,6 +7,9 @@ HEADER_BUILD = $(BUILD)/genhdr
# file containing qstr defs for the core Python bit
PY_QSTR_DEFS = $(PY_SRC)/qstrdefs.h
+# some code is performance bottleneck and compiled with other optimization options
+CSUPEROPT = -O3
+
# py object files
PY_O_BASENAME = \
nlrx86.o \
@@ -135,8 +138,8 @@ $(PY_BUILD)/emitnthumb.o: py/emitnative.c
$(call compile_c)
# optimising gc for speed; 5ms down to 4ms on pybv2
-$(PY_BUILD)/gc.o: CFLAGS += -O3
+$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)
# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster)
-$(PY_BUILD)/vm.o: CFLAGS += -O3
+$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT)
diff --git a/py/showbc.c b/py/showbc.c
index 4a8e12e68b..17cb2eadd6 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -28,6 +28,8 @@
ip += sizeof(machine_uint_t); \
} while (0)
+void mp_byte_code_print2(const byte *ip, int len);
+
void mp_byte_code_print(const byte *ip, int len) {
const byte *ip_start = ip;
@@ -71,7 +73,11 @@ void mp_byte_code_print(const byte *ip, int len) {
printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
}
}
+ mp_byte_code_print2(ip, len - 0);
+}
+void mp_byte_code_print2(const byte *ip, int len) {
+ const byte *ip_start = ip;
machine_uint_t unum;
qstr qstr;
while (ip - ip_start < len) {
@@ -418,15 +424,19 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("MAKE_FUNCTION_DEFARGS " UINT_FMT, unum);
break;
- case MP_BC_MAKE_CLOSURE:
+ case MP_BC_MAKE_CLOSURE: {
DECODE_PTR;
- printf("MAKE_CLOSURE " UINT_FMT, unum);
+ machine_uint_t n_closed_over = *ip++;
+ printf("MAKE_CLOSURE " UINT_FMT " " UINT_FMT, unum, n_closed_over);
break;
+ }
- case MP_BC_MAKE_CLOSURE_DEFARGS:
+ case MP_BC_MAKE_CLOSURE_DEFARGS: {
DECODE_PTR;
- printf("MAKE_CLOSURE_DEFARGS " UINT_FMT, unum);
+ machine_uint_t n_closed_over = *ip++;
+ printf("MAKE_CLOSURE_DEFARGS " UINT_FMT " " UINT_FMT, unum, n_closed_over);
break;
+ }
case MP_BC_CALL_FUNCTION:
DECODE_UINT;
diff --git a/py/vm.c b/py/vm.c
index b1c1719b72..8b4c926def 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -13,7 +13,18 @@
#include "bc.h"
#include "objgenerator.h"
+// With these macros you can tune the maximum number of state slots
+// that will be allocated on the stack. Any function that needs more
+// than this will use the heap.
+#define VM_MAX_STATE_ON_STACK (10)
+#define VM_MAX_EXC_STATE_ON_STACK (4)
+
#define DETECT_VM_STACK_OVERFLOW (0)
+#if 0
+#define TRACE(ip) mp_byte_code_print2(ip, 1);
+#else
+#define TRACE(ip)
+#endif
// Value stack grows up (this makes it incompatible with native C stack, but
// makes sure that arguments to functions are in natural order arg1..argN
@@ -80,20 +91,20 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args,
ip += 4;
// allocate state for locals and stack
- mp_obj_t temp_state[10];
+ mp_obj_t temp_state[VM_MAX_STATE_ON_STACK];
mp_obj_t *state = &temp_state[0];
#if DETECT_VM_STACK_OVERFLOW
n_state += 1;
#endif
- if (n_state > 10) {
+ if (n_state > VM_MAX_STATE_ON_STACK) {
state = m_new(mp_obj_t, n_state);
}
mp_obj_t *sp = &state[0] - 1;
// allocate state for exceptions
- mp_exc_stack_t exc_state[4];
+ mp_exc_stack_t exc_state[VM_MAX_EXC_STATE_ON_STACK];
mp_exc_stack_t *exc_stack = &exc_state[0];
- if (n_exc_stack > 4) {
+ if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
exc_stack = m_new(mp_exc_stack_t, n_exc_stack);
}
mp_exc_stack_t *exc_sp = &exc_stack[0] - 1;
@@ -140,19 +151,38 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args,
}
#endif
+ mp_vm_return_kind_t ret_kind;
switch (vm_return_kind) {
case MP_VM_RETURN_NORMAL:
+ // return value is in *sp
*ret = *sp;
- return MP_VM_RETURN_NORMAL;
+ ret_kind = MP_VM_RETURN_NORMAL;
+ break;
+
case MP_VM_RETURN_EXCEPTION:
+ // return value is in state[n_state - 1]
*ret = state[n_state - 1];
- return MP_VM_RETURN_EXCEPTION;
+ ret_kind = MP_VM_RETURN_EXCEPTION;
+ break;
+
case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
default:
assert(0);
*ret = mp_const_none;
- return MP_VM_RETURN_NORMAL;
+ ret_kind = MP_VM_RETURN_NORMAL;
}
+
+ // free the state if it was allocated on the heap
+ if (n_state > VM_MAX_STATE_ON_STACK) {
+ m_free(state, n_state);
+ }
+
+ // free the exception state if it was allocated on the heap
+ if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
+ m_free(exc_stack, n_exc_stack);
+ }
+
+ return ret_kind;
}
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
@@ -168,6 +198,7 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i
#if MICROPY_USE_COMPUTED_GOTO
#include "vmentrytable.h"
#define DISPATCH() do { \
+ TRACE(ip); \
save_ip = ip; \
op = *ip++; \
goto *entry_table[op]; \
@@ -223,6 +254,7 @@ dispatch_loop:
#if MICROPY_USE_COMPUTED_GOTO
DISPATCH();
#else
+ TRACE(ip);
save_ip = ip;
op = *ip++;