summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/compile.c108
-rw-r--r--py/emit.h6
-rw-r--r--py/emitbc.c4
-rw-r--r--py/emitcpy.c4
-rw-r--r--py/emitglue.c11
-rw-r--r--py/emitglue.h3
-rw-r--r--py/emitinlinethumb.c2
-rw-r--r--py/emitnative.c79
-rw-r--r--py/mpconfig.h3
-rw-r--r--py/obj.h1
-rw-r--r--py/objfun.c83
-rw-r--r--py/parse.c2
-rw-r--r--py/qstrdefs.h6
-rw-r--r--py/runtime0.h6
14 files changed, 246 insertions, 72 deletions
diff --git a/py/compile.c b/py/compile.c
index 6ec57adcae..eb9cf9a948 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -48,8 +48,6 @@
// TODO need to mangle __attr names
-#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
-
typedef enum {
PN_none = 0,
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
@@ -1745,6 +1743,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(label_assign, break_label);
}
+#if !MICROPY_EMIT_CPYTHON
// TODO preload end and step onto stack if they are not constants
// Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
// And, if the loop never runs, the loop variable should never be assigned
@@ -1801,6 +1800,7 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p
EMIT_ARG(label_assign, break_label);
}
+#endif
void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
#if !MICROPY_EMIT_CPYTHON
@@ -2902,11 +2902,10 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
}
}
-STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star, bool allow_annotations) {
+STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) {
// TODO verify that *k and **k are last etc
qstr param_name = MP_QSTR_NULL;
uint param_flag = ID_FLAG_IS_PARAM;
- mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
if (MP_PARSE_NODE_IS_ID(pn)) {
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
if (comp->have_star) {
@@ -2921,24 +2920,6 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) {
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
- //int node_index = 1; unused
- if (allow_annotations) {
- if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
- // this parameter has an annotation
- pn_annotation = pns->nodes[1];
- }
- //node_index = 2; unused
- }
- /* this is obsolete now that num dict/default params are calculated in compile_funcdef_param
- if (!MP_PARSE_NODE_IS_NULL(pns->nodes[node_index])) {
- // this parameter has a default value
- if (comp->have_star) {
- comp->scope_cur->num_dict_params += 1;
- } else {
- comp->scope_cur->num_default_params += 1;
- }
- }
- */
if (comp->have_star) {
// comes after a star, so counts as a keyword-only parameter
comp->scope_cur->num_kwonly_args += 1;
@@ -2957,12 +2938,11 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
// named star
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
- } else if (allow_annotations && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
+ } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
// named star with possible annotation
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
pns = (mp_parse_node_struct_t*)pns->nodes[0];
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
- pn_annotation = pns->nodes[1];
} else {
// shouldn't happen
assert(0);
@@ -2970,10 +2950,6 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;
- if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
- // this parameter has an annotation
- pn_annotation = pns->nodes[1];
- }
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS;
} else {
// TODO anything to implement?
@@ -2982,9 +2958,6 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
}
if (param_name != MP_QSTR_NULL) {
- if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
- // TODO this parameter has an annotation
- }
bool added;
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added);
if (!added) {
@@ -2997,11 +2970,58 @@ STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn
}
STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
- compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
+ compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star);
}
STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
- compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
+ compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star);
+}
+
+STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) {
+ if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
+ // no annotation
+ return;
+ }
+
+ mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
+ if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_name) {
+ // named parameter with possible annotation
+ // fallthrough
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_star) {
+ if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
+ // named star with possible annotation
+ pns = (mp_parse_node_struct_t*)pns->nodes[0];
+ // fallthrough
+ } else {
+ // no annotation
+ return;
+ }
+ } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star) {
+ // double star with possible annotation
+ // fallthrough
+ } else {
+ // no annotation
+ return;
+ }
+
+ mp_parse_node_t pn_annotation = pns->nodes[1];
+
+ if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
+ #if MICROPY_EMIT_NATIVE
+ qstr param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
+ id_info_t *id_info = scope_find(comp->scope_cur, param_name);
+ assert(id_info != NULL);
+
+ if (comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER) {
+ if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
+ qstr arg_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
+ EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ARG, id_info->local_num, arg_type);
+ } else {
+ compile_syntax_error(comp, pn_annotation, "annotation must be an identifier");
+ }
+ }
+ #endif // MICROPY_EMIT_NATIVE
+ }
}
STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
@@ -3128,10 +3148,26 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
if (comp->pass == MP_PASS_SCOPE) {
comp->have_star = false;
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
+ } else {
+ // compile annotations; only needed on latter compiler passes
+
+ // argument annotations
+ apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_annotations);
+
+ // pns->nodes[2] is return/whole function annotation
+ #if MICROPY_EMIT_NATIVE
+ if (scope->emit_options == MP_EMIT_OPT_VIPER) {
+ // nodes[2] can be null or a test-expr
+ if (MP_PARSE_NODE_IS_ID(pns->nodes[2])) {
+ qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pns->nodes[2]);
+ EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_RETURN, 0, ret_type);
+ } else {
+ compile_syntax_error(comp, pns->nodes[2], "annotation must be an identifier");
+ }
+ }
+ #endif // MICROPY_EMIT_NATIVE
}
- // pns->nodes[2] is return/whole function annotation
-
compile_node(comp, pns->nodes[3]); // 3 is function body
// emit return if it wasn't the last opcode
if (!EMIT(last_emit_was_return_value)) {
@@ -3589,7 +3625,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
comp->emit_method_table = &emit_native_thumb_method_table;
#endif
comp->emit = emit_native;
- comp->emit_method_table->set_native_types(comp->emit, s->emit_options == MP_EMIT_OPT_VIPER);
+ comp->emit_method_table->set_native_type(comp->emit, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0);
// native emitters need an extra pass to compute stack size
compile_scope(comp, s, MP_PASS_STACK_SIZE);
diff --git a/py/emit.h b/py/emit.h
index c760344c1f..9a709a5c98 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -46,10 +46,14 @@ typedef enum {
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
+#define MP_EMIT_NATIVE_TYPE_ENABLE (0)
+#define MP_EMIT_NATIVE_TYPE_RETURN (1)
+#define MP_EMIT_NATIVE_TYPE_ARG (2)
+
typedef struct _emit_t emit_t;
typedef struct _emit_method_table_t {
- void (*set_native_types)(emit_t *emit, bool do_native_types);
+ void (*set_native_type)(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2);
void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
void (*end_pass)(emit_t *emit);
bool (*last_emit_was_return_value)(emit_t *emit);
diff --git a/py/emitbc.c b/py/emitbc.c
index 161e8c7f6d..a1eacb2986 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -265,7 +265,7 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, uint la
c[2] = bytecode_offset >> 8;
}
-STATIC void emit_bc_set_native_types(emit_t *emit, bool do_native_types) {
+STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
}
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -872,7 +872,7 @@ STATIC void emit_bc_end_except_handler(emit_t *emit) {
}
const emit_method_table_t emit_bc_method_table = {
- emit_bc_set_native_types,
+ emit_bc_set_native_type,
emit_bc_start_pass,
emit_bc_end_pass,
emit_bc_last_emit_was_return_value,
diff --git a/py/emitcpy.c b/py/emitcpy.c
index c0d15a8716..4d0c085225 100644
--- a/py/emitcpy.c
+++ b/py/emitcpy.c
@@ -63,7 +63,7 @@ emit_t *emit_cpython_new(uint max_num_labels) {
return emit;
}
-STATIC void emit_cpy_set_native_types(emit_t *emit, bool do_native_types) {
+STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
}
STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -822,7 +822,7 @@ STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
}
const emit_method_table_t emit_cpython_method_table = {
- emit_cpy_set_native_types,
+ emit_cpy_set_native_type,
emit_cpy_start_pass,
emit_cpy_end_pass,
emit_cpy_last_emit_was_return_value,
diff --git a/py/emitglue.c b/py/emitglue.c
index 91570bc63d..5be54a6fc5 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -86,12 +86,14 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
#endif
}
-void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun, uint len, int n_args) {
+#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
+void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun, uint len, int n_args, mp_uint_t type_sig) {
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
rc->kind = kind;
rc->scope_flags = 0;
rc->n_pos_args = n_args;
rc->u_native.fun = fun;
+ rc->u_native.type_sig = type_sig;
#ifdef DEBUG_PRINT
DEBUG_printf("assign native: kind=%d fun=%p len=%u n_args=%d\n", kind, fun, len, n_args);
@@ -111,6 +113,7 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
#endif
#endif
}
+#endif
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
@@ -128,13 +131,19 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
case MP_CODE_BYTECODE:
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
break;
+ #if MICROPY_EMIT_NATIVE
case MP_CODE_NATIVE_PY:
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
break;
case MP_CODE_NATIVE_VIPER:
+ fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun, rc->u_native.type_sig);
+ break;
+ #endif
+ #if MICROPY_EMIT_INLINE_THUMB
case MP_CODE_NATIVE_ASM:
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun);
break;
+ #endif
default:
// raw code was never set (this should not happen)
assert(0);
diff --git a/py/emitglue.h b/py/emitglue.h
index c6cbb6283d..f8363465e2 100644
--- a/py/emitglue.h
+++ b/py/emitglue.h
@@ -48,6 +48,7 @@ typedef struct _mp_code_t {
} u_byte;
struct {
void *fun;
+ mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
} u_native;
};
} mp_raw_code_t;
@@ -55,7 +56,7 @@ typedef struct _mp_code_t {
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
-void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *f, uint len, int n_args);
+void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *f, uint len, int n_args, mp_uint_t type_sig);
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args);
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index 3d0efd5645..89e128c084 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -99,7 +99,7 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
if (emit->pass == MP_PASS_EMIT) {
void *f = asm_thumb_get_code(emit->as);
- mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
+ mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
}
return emit->success;
diff --git a/py/emitnative.c b/py/emitnative.c
index dde582d095..7f3c73c2e4 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -126,10 +126,11 @@ typedef enum {
} stack_info_kind_t;
typedef enum {
+ VTYPE_PYOBJ = MP_NATIVE_TYPE_OBJ,
+ VTYPE_BOOL = MP_NATIVE_TYPE_BOOL,
+ VTYPE_INT = MP_NATIVE_TYPE_INT,
+ VTYPE_UINT = MP_NATIVE_TYPE_UINT,
VTYPE_UNBOUND,
- VTYPE_PYOBJ,
- VTYPE_BOOL,
- VTYPE_INT,
VTYPE_PTR,
VTYPE_PTR_NONE,
VTYPE_BUILTIN_V_INT,
@@ -149,6 +150,8 @@ struct _emit_t {
bool do_viper_types;
+ vtype_kind_t return_vtype;
+
uint local_vtype_alloc;
vtype_kind_t *local_vtype;
@@ -190,8 +193,30 @@ void EXPORT_FUN(free)(emit_t *emit) {
m_del_obj(emit_t, emit);
}
-STATIC void emit_native_set_viper_types(emit_t *emit, bool do_viper_types) {
- emit->do_viper_types = do_viper_types;
+STATIC void emit_native_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
+ switch (op) {
+ case MP_EMIT_NATIVE_TYPE_ENABLE:
+ emit->do_viper_types = arg1;
+ break;
+
+ default: {
+ vtype_kind_t type;
+ switch (arg2) {
+ case MP_QSTR_object: type = VTYPE_PYOBJ; break;
+ case MP_QSTR_bool: type = VTYPE_BOOL; break;
+ case MP_QSTR_int: type = VTYPE_INT; break;
+ case MP_QSTR_uint: type = VTYPE_UINT; break;
+ default: printf("ViperTypeError: unknown type %s\n", qstr_str(arg2)); return;
+ }
+ if (op == MP_EMIT_NATIVE_TYPE_RETURN) {
+ emit->return_vtype = type;
+ } else {
+ assert(arg1 < emit->local_vtype_alloc);
+ emit->local_vtype[arg1] = type;
+ }
+ break;
+ }
+ }
}
STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -214,23 +239,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
}
- if (emit->do_viper_types) {
- // TODO set types of arguments based on type signature
- for (int i = 0; i < emit->local_vtype_alloc; i++) {
- emit->local_vtype[i] = VTYPE_UNBOUND;
- }
- for (int i = 0; i < emit->stack_info_alloc; i++) {
- emit->stack_info[i].kind = STACK_VALUE;
- emit->stack_info[i].vtype = VTYPE_UNBOUND;
- }
- } else {
- for (int i = 0; i < emit->local_vtype_alloc; i++) {
- emit->local_vtype[i] = VTYPE_PYOBJ;
- }
- for (int i = 0; i < emit->stack_info_alloc; i++) {
- emit->stack_info[i].kind = STACK_VALUE;
- emit->stack_info[i].vtype = VTYPE_PYOBJ;
- }
+ // set default type for return and arguments
+ emit->return_vtype = VTYPE_PYOBJ;
+ for (int i = 0; i < emit->local_vtype_alloc; i++) {
+ emit->local_vtype[i] = VTYPE_PYOBJ;
+ }
+ for (int i = 0; i < emit->stack_info_alloc; i++) {
+ emit->stack_info[i].kind = STACK_VALUE;
+ emit->stack_info[i].vtype = VTYPE_PYOBJ;
}
#if N_X64
@@ -310,11 +326,20 @@ STATIC void emit_native_end_pass(emit_t *emit) {
if (emit->pass == MP_PASS_EMIT) {
#if N_X64
void *f = asm_x64_get_code(emit->as);
- mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, asm_x64_get_code_size(emit->as), emit->scope->num_pos_args);
+ mp_uint_t f_len = asm_x64_get_code_size(emit->as);
#elif N_THUMB
void *f = asm_thumb_get_code(emit->as);
- mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
+ mp_uint_t f_len = asm_thumb_get_code_size(emit->as);
#endif
+
+ // compute type signature
+ // TODO check that viper types here convert correctly to valid types for emit glue
+ mp_uint_t type_sig = emit->return_vtype & 3;
+ for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
+ type_sig |= (emit->local_vtype[i] & 3) << (i * 2 + 2);
+ }
+
+ mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->scope->num_pos_args, type_sig);
}
}
@@ -1394,7 +1419,9 @@ STATIC void emit_native_return_value(emit_t *emit) {
vtype_kind_t vtype;
emit_pre_pop_reg(emit, &vtype, REG_RET);
if (emit->do_viper_types) {
- assert(vtype == VTYPE_PTR_NONE);
+ if (vtype != emit->return_vtype) {
+ printf("ViperTypeError: incompatible return type\n");
+ }
} else {
assert(vtype == VTYPE_PYOBJ);
}
@@ -1444,7 +1471,7 @@ STATIC void emit_native_end_except_handler(emit_t *emit) {
}
const emit_method_table_t EXPORT_FUN(method_table) = {
- emit_native_set_viper_types,
+ emit_native_set_native_type,
emit_native_start_pass,
emit_native_end_pass,
emit_native_last_emit_was_return_value,
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 76e02be512..850d05524b 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -111,6 +111,9 @@
#define MICROPY_EMIT_INLINE_THUMB (0)
#endif
+// Convenience definition for whether any native emitter is enabled
+#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
+
/*****************************************************************************/
/* Compiler configuration */
diff --git a/py/obj.h b/py/obj.h
index 27d947a8ff..6fe671972f 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -378,6 +378,7 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, c
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!)
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
+mp_obj_t mp_obj_new_fun_viper(uint n_args, void *fun, mp_uint_t type_sig);
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
diff --git a/py/objfun.c b/py/objfun.c
index 409525c670..83e5ade5db 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -501,8 +501,89 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
}
/******************************************************************************/
+/* viper functions */
+
+#if MICROPY_EMIT_NATIVE
+
+typedef struct _mp_obj_fun_viper_t {
+ mp_obj_base_t base;
+ int n_args;
+ void *fun;
+ mp_uint_t type_sig;
+} mp_obj_fun_viper_t;
+
+typedef mp_uint_t (*viper_fun_0_t)();
+typedef mp_uint_t (*viper_fun_1_t)(mp_uint_t);
+typedef mp_uint_t (*viper_fun_2_t)(mp_uint_t, mp_uint_t);
+typedef mp_uint_t (*viper_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
+
+// convert a Micro Python object to a valid value for viper, based on wanted type
+STATIC mp_uint_t convert_obj_for_viper(mp_obj_t obj, mp_uint_t type) {
+ switch (type & 3) {
+ case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
+ case MP_NATIVE_TYPE_BOOL:
+ case MP_NATIVE_TYPE_INT:
+ case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
+ default: assert(0); return 0;
+ }
+}
+
+// convert a return value from viper to a Micro Python object based on viper return type
+STATIC mp_obj_t convert_val_from_viper(mp_uint_t val, mp_uint_t type) {
+ switch (type & 3) {
+ case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
+ case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
+ case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
+ case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
+ default: assert(0); return mp_const_none;
+ }
+}
+
+STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+ mp_obj_fun_viper_t *self = self_in;
+
+ mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
+
+ mp_uint_t ret;
+ if (n_args == 0) {
+ ret = ((viper_fun_0_t)self->fun)();
+ } else if (n_args == 1) {
+ ret = ((viper_fun_1_t)self->fun)(convert_obj_for_viper(args[0], self->type_sig >> 2));
+ } else if (n_args == 2) {
+ ret = ((viper_fun_2_t)self->fun)(convert_obj_for_viper(args[0], self->type_sig >> 2), convert_obj_for_viper(args[1], self->type_sig >> 4));
+ } else if (n_args == 3) {
+ ret = ((viper_fun_3_t)self->fun)(convert_obj_for_viper(args[0], self->type_sig >> 2), convert_obj_for_viper(args[1], self->type_sig >> 4), convert_obj_for_viper(args[2], self->type_sig >> 6));
+ } else {
+ assert(0);
+ ret = 0;
+ }
+
+ return convert_val_from_viper(ret, self->type_sig);
+}
+
+STATIC const mp_obj_type_t mp_type_fun_viper = {
+ { &mp_type_type },
+ .name = MP_QSTR_function,
+ .call = fun_viper_call,
+ .binary_op = fun_binary_op,
+};
+
+mp_obj_t mp_obj_new_fun_viper(uint n_args, void *fun, mp_uint_t type_sig) {
+ mp_obj_fun_viper_t *o = m_new_obj(mp_obj_fun_viper_t);
+ o->base.type = &mp_type_fun_viper;
+ o->n_args = n_args;
+ o->fun = fun;
+ o->type_sig = type_sig;
+ return o;
+}
+
+#endif // MICROPY_EMIT_NATIVE
+
+/******************************************************************************/
/* inline assembler functions */
+#if MICROPY_EMIT_INLINE_THUMB
+
typedef struct _mp_obj_fun_asm_t {
mp_obj_base_t base;
int n_args;
@@ -603,3 +684,5 @@ mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
o->fun = fun;
return o;
}
+
+#endif // MICROPY_EMIT_INLINE_THUMB
diff --git a/py/parse.c b/py/parse.c
index 2a74c59a8e..26713dfe71 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -578,7 +578,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
// never emit these rules if they have only 1 argument
// NOTE: can't put atom_paren here because we need it to distinguisg, for example, [a,b] from [(a,b)]
// TODO possibly put varargslist_name, varargslist_equal here as well
- if (rule->rule_id == RULE_else_stmt || rule->rule_id == RULE_testlist_comp_3b || rule->rule_id == RULE_import_as_names_paren || rule->rule_id == RULE_typedargslist_name || rule->rule_id == RULE_typedargslist_colon || rule->rule_id == RULE_typedargslist_equal || rule->rule_id == RULE_dictorsetmaker_colon || rule->rule_id == RULE_classdef_2 || rule->rule_id == RULE_with_item_as || rule->rule_id == RULE_assert_stmt_extra || rule->rule_id == RULE_as_name || rule->rule_id == RULE_raise_stmt_from || rule->rule_id == RULE_vfpdef) {
+ if (rule->rule_id == RULE_else_stmt || rule->rule_id == RULE_testlist_comp_3b || rule->rule_id == RULE_import_as_names_paren || rule->rule_id == RULE_typedargslist_name || rule->rule_id == RULE_typedargslist_colon || rule->rule_id == RULE_typedargslist_equal || rule->rule_id == RULE_dictorsetmaker_colon || rule->rule_id == RULE_classdef_2 || rule->rule_id == RULE_with_item_as || rule->rule_id == RULE_assert_stmt_extra || rule->rule_id == RULE_as_name || rule->rule_id == RULE_raise_stmt_from || rule->rule_id == RULE_vfpdef || rule->rule_id == RULE_funcdefrettype) {
emit_rule = false;
}
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index e154faf559..c83b54c241 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -67,9 +67,13 @@ Q(__lt__)
Q(micropython)
Q(bytecode)
+Q(const)
+
+#if MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB
Q(native)
Q(viper)
-Q(const)
+Q(uint)
+#endif
#if MICROPY_EMIT_INLINE_THUMB
Q(asm_thumb)
diff --git a/py/runtime0.h b/py/runtime0.h
index eea578237a..01504f59cf 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -39,6 +39,12 @@
*/
#define MP_SCOPE_FLAG_NOFREE 0x40
+// types for native (viper) function signature
+#define MP_NATIVE_TYPE_OBJ (0x00)
+#define MP_NATIVE_TYPE_BOOL (0x01)
+#define MP_NATIVE_TYPE_INT (0x02)
+#define MP_NATIVE_TYPE_UINT (0x03)
+
typedef enum {
MP_UNARY_OP_BOOL, // __bool__
MP_UNARY_OP_LEN, // __len__