From 4ebdb1f2b217410cdc1cee0e0c0da8fceb7627f2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 11:06:20 +1100 Subject: py: Be more specific with MP_DECLARE_CONST_FUN_OBJ macros. In order to have more fine-grained control over how builtin functions are constructed, the MP_DECLARE_CONST_FUN_OBJ macros are made more specific, with suffix of _0, _1, _2, _3, _VAR, _VAR_BETEEN or _KW. These names now match the MP_DEFINE_CONST_FUN_OBJ macros. --- py/builtin.h | 96 +++++++++++++++++++++++++++++------------------------------- py/obj.h | 10 +++++-- py/objstr.h | 54 +++++++++++++++++----------------- py/stream.h | 24 +++++++-------- 4 files changed, 93 insertions(+), 91 deletions(-) (limited to 'py') diff --git a/py/builtin.h b/py/builtin.h index cd1be3ab8..df33e2b73 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -32,56 +32,55 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args); mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_compile_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_eval_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_exec_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_execfile_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_getattr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_setattr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_globals_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hasattr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hash_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hex_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_id_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_isinstance_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_issubclass_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_iter_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_len_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_list_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_locals_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_max_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_min_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_next_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_oct_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_ord_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_pow_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_print_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_round_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_abs_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_all_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_any_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_bin_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_callable_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_chr_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_globals_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hash_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hex_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_id_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_iter_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_print_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_repr_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj); // Defined by a port, but declared here for simplicity -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_help_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_input_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_open_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_namedtuple_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_namedtuple_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_contains_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_getitem_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_setitem_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_delitem_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_contains_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_getitem_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_op_setitem_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); extern const mp_obj_module_t mp_module___main__; extern const mp_obj_module_t mp_module_builtins; @@ -116,7 +115,4 @@ extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; -// extmod functions -MP_DECLARE_CONST_FUN_OBJ(pyb_mount_obj); - #endif // __MICROPY_INCLUDED_PY_BUILTIN_H__ diff --git a/py/obj.h b/py/obj.h index 72d79ce14..e4fa19ac9 100644 --- a/py/obj.h +++ b/py/obj.h @@ -270,7 +270,13 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local -#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_t obj_name #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ const mp_obj_fun_builtin_t obj_name = \ @@ -760,7 +766,7 @@ qstr mp_obj_fun_get_name(mp_const_obj_t fun); qstr mp_obj_code_get_name(const byte *code_info); mp_obj_t mp_identity(mp_obj_t self); -MP_DECLARE_CONST_FUN_OBJ(mp_identity_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj); // module typedef struct _mp_obj_module_t { diff --git a/py/objstr.h b/py/objstr.h index e14568dac..ad2777afb 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -74,32 +74,32 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s mp_obj_t index, bool is_slice); const byte *find_subbytes(const byte *haystack, mp_uint_t hlen, const byte *needle, mp_uint_t nlen, mp_int_t direction); -MP_DECLARE_CONST_FUN_OBJ(str_encode_obj); -MP_DECLARE_CONST_FUN_OBJ(str_find_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rfind_obj); -MP_DECLARE_CONST_FUN_OBJ(str_index_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rindex_obj); -MP_DECLARE_CONST_FUN_OBJ(str_join_obj); -MP_DECLARE_CONST_FUN_OBJ(str_split_obj); -MP_DECLARE_CONST_FUN_OBJ(str_splitlines_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rsplit_obj); -MP_DECLARE_CONST_FUN_OBJ(str_startswith_obj); -MP_DECLARE_CONST_FUN_OBJ(str_endswith_obj); -MP_DECLARE_CONST_FUN_OBJ(str_strip_obj); -MP_DECLARE_CONST_FUN_OBJ(str_lstrip_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rstrip_obj); -MP_DECLARE_CONST_FUN_OBJ(str_format_obj); -MP_DECLARE_CONST_FUN_OBJ(str_replace_obj); -MP_DECLARE_CONST_FUN_OBJ(str_count_obj); -MP_DECLARE_CONST_FUN_OBJ(str_partition_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj); -MP_DECLARE_CONST_FUN_OBJ(str_center_obj); -MP_DECLARE_CONST_FUN_OBJ(str_lower_obj); -MP_DECLARE_CONST_FUN_OBJ(str_upper_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isalpha_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isdigit_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isupper_obj); -MP_DECLARE_CONST_FUN_OBJ(str_islower_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_join_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(str_splitlines_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(str_format_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_partition_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_rpartition_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_center_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_lower_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_upper_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isspace_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj); #endif // __MICROPY_INCLUDED_PY_OBJSTR_H__ diff --git a/py/stream.h b/py/stream.h index 33d85e823..4cdea11eb 100644 --- a/py/stream.h +++ b/py/stream.h @@ -48,18 +48,18 @@ struct mp_stream_seek_t { int whence; }; -MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_read1_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_readinto_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_readall_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readline_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readlines_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_write_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_write1_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_seek_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_tell_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_flush_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_readall_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); // these are for mp_get_stream_raise and can be or'd together #define MP_STREAM_OP_READ (1) -- cgit v1.2.3 From 571e6f26dbd7e0e38441bc402f76d293303063b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 11:49:27 +1100 Subject: py: Specialise builtin funcs to use separate type for fixed arg count. Builtin functions with a fixed number of arguments (0, 1, 2 or 3) are quite common. Before this patch the wrapper for such a function cost 3 machine words. After this patch it only takes 2, which can reduce the code size by quite a bit (and pays off even more, the more functions are added). It also makes function dispatch slightly more efficient in CPU usage, and furthermore reduces stack usage for these cases. On x86 and Thumb archs the dispatch functions are now tail-call optimised by the compiler. The bare-arm port has its code size increase by 76 bytes, but stmhal drops by 904 bytes. Stack usage by these builtin functions is decreased by 48 bytes on Thumb2 archs. --- drivers/cc3000/src/ccspi.c | 2 +- py/obj.h | 67 +++++++++++++++++++++--------------- py/objfun.c | 86 ++++++++++++++++++++++++++++++++-------------- py/runtime.c | 8 ++++- 4 files changed, 108 insertions(+), 55 deletions(-) (limited to 'py') diff --git a/drivers/cc3000/src/ccspi.c b/drivers/cc3000/src/ccspi.c index 1606bfd57..64900efe4 100644 --- a/drivers/cc3000/src/ccspi.c +++ b/drivers/cc3000/src/ccspi.c @@ -99,7 +99,7 @@ STATIC tSpiInformation sSpiInformation; STATIC char spi_buffer[CC3000_RX_BUFFER_SIZE]; unsigned char wlan_tx_buffer[CC3000_TX_BUFFER_SIZE]; -STATIC const mp_obj_fun_builtin_t irq_callback_obj; +STATIC const mp_obj_fun_builtin_fixed_t irq_callback_obj; // set the pins to use to communicate with the CC3000 // the arguments must be of type pin_obj_t* and SPI_HandleTypeDef* diff --git a/py/obj.h b/py/obj.h index e4fa19ac9..61db65a9a 100644 --- a/py/obj.h +++ b/py/obj.h @@ -270,35 +270,35 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local -#define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_t obj_name -#define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_t obj_name -#define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_t obj_name -#define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_t obj_name -#define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_t obj_name -#define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_t obj_name -#define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_var_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_var_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_var_t obj_name #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 0, 0, .fun._0 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_0}, .fun._0 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 1, 1, .fun._1 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_1}, .fun._1 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 2, 2, .fun._2 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_2}, .fun._2 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 3, 3, .fun._3 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_3}, .fun._3 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.var = fun_name} + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.var = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, n_args_min, n_args_max, .fun.var = fun_name} + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, false, n_args_min, n_args_max, .fun.var = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.kw = fun_name} + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.kw = fun_name} // These macros are used to define constant map/dict objects // You can put "static" in front of the definition to make it local @@ -536,7 +536,11 @@ extern const mp_obj_type_t mp_type_zip; extern const mp_obj_type_t mp_type_array; extern const mp_obj_type_t mp_type_super; extern const mp_obj_type_t mp_type_gen_instance; -extern const mp_obj_type_t mp_type_fun_builtin; +extern const mp_obj_type_t mp_type_fun_builtin_0; +extern const mp_obj_type_t mp_type_fun_builtin_1; +extern const mp_obj_type_t mp_type_fun_builtin_2; +extern const mp_obj_type_t mp_type_fun_builtin_3; +extern const mp_obj_type_t mp_type_fun_builtin_var; extern const mp_obj_type_t mp_type_fun_bc; extern const mp_obj_type_t mp_type_module; extern const mp_obj_type_t mp_type_staticmethod; @@ -746,21 +750,28 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); // functions -#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below -typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go in ROM + +typedef struct _mp_obj_fun_builtin_fixed_t { mp_obj_base_t base; - bool is_kw : 1; - mp_uint_t n_args_min : 15; // inclusive - mp_uint_t n_args_max : 16; // inclusive union { mp_fun_0_t _0; mp_fun_1_t _1; mp_fun_2_t _2; mp_fun_3_t _3; + } fun; +} mp_obj_fun_builtin_fixed_t; + +#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below +typedef struct _mp_obj_fun_builtin_var_t { + mp_obj_base_t base; + bool is_kw : 1; + mp_uint_t n_args_min : 15; // inclusive + mp_uint_t n_args_max : 16; // inclusive + union { mp_fun_var_t var; mp_fun_kw_t kw; } fun; -} mp_obj_fun_builtin_t; +} mp_obj_fun_builtin_var_t; qstr mp_obj_fun_get_name(mp_const_obj_t fun); qstr mp_obj_code_get_name(const byte *code_info); diff --git a/py/objfun.c b/py/objfun.c index 405f38127..6b8fe6d38 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -50,11 +50,66 @@ /******************************************************************************/ /* builtin functions */ -// mp_obj_fun_builtin_t defined in obj.h +STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)args; + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return self->fun._0(); +} -STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin)); - mp_obj_fun_builtin_t *self = MP_OBJ_TO_PTR(self_in); +const mp_obj_type_t mp_type_fun_builtin_0 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_0_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 1, 1, false); + return self->fun._1(args[0]); +} + +const mp_obj_type_t mp_type_fun_builtin_1 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_1_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 2, 2, false); + return self->fun._2(args[0], args[1]); +} + +const mp_obj_type_t mp_type_fun_builtin_2 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_2_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 3, 3, false); + return self->fun._3(args[0], args[1], args[2]); +} + +const mp_obj_type_t mp_type_fun_builtin_3 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_3_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_var)); + mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); // check number of arguments mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw); @@ -68,25 +123,6 @@ STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c return self->fun.kw(n_args, args, &kw_args); - } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) { - // function requires a fixed number of arguments - - // dispatch function call - switch (self->n_args_min) { - case 0: - return self->fun._0(); - - case 1: - return self->fun._1(args[0]); - - case 2: - return self->fun._2(args[0], args[1]); - - case 3: - default: - return self->fun._3(args[0], args[1], args[2]); - } - } else { // function takes a variable number of arguments, but no keywords @@ -94,10 +130,10 @@ STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c } } -const mp_obj_type_t mp_type_fun_builtin = { +const mp_obj_type_t mp_type_fun_builtin_var = { { &mp_type_type }, .name = MP_QSTR_function, - .call = fun_builtin_call, + .call = fun_builtin_var_call, .unary_op = mp_generic_unary_op, }; diff --git a/py/runtime.c b/py/runtime.c index 6eda77ee9..c25557464 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -972,7 +972,13 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t || ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_generator))) { // only functions, closures and generators objects can be bound to self #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG - if (self == MP_OBJ_NULL && mp_obj_get_type(member) == &mp_type_fun_builtin) { + const mp_obj_type_t *m_type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type; + if (self == MP_OBJ_NULL + && (m_type == &mp_type_fun_builtin_0 + || m_type == &mp_type_fun_builtin_1 + || m_type == &mp_type_fun_builtin_2 + || m_type == &mp_type_fun_builtin_3 + || m_type == &mp_type_fun_builtin_var)) { // we extracted a builtin method without a first argument, so we must // wrap this function in a type checker dest[0] = mp_obj_new_checked_fun(type, member); -- cgit v1.2.3 From f64e806f50606902323c62cf7b479922724022b6 Mon Sep 17 00:00:00 2001 From: Erik Moqvist Date: Sun, 16 Oct 2016 16:40:56 +0200 Subject: lib/utils/pyhelp.c: Use mp_printf() instead of printf() This patch introduces MP_PYTHON_PRINTER for general use. --- lib/utils/pyhelp.c | 10 +++++----- py/mpprint.h | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'py') diff --git a/lib/utils/pyhelp.c b/lib/utils/pyhelp.c index 5c0b2c57b..30ff391c4 100644 --- a/lib/utils/pyhelp.c +++ b/lib/utils/pyhelp.c @@ -29,11 +29,11 @@ #include "lib/utils/pyhelp.h" STATIC void pyhelp_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { - printf(" "); + mp_printf(MP_PYTHON_PRINTER, " "); mp_obj_print(name_o, PRINT_STR); - printf(" -- "); + mp_printf(MP_PYTHON_PRINTER, " -- "); mp_obj_print(value, PRINT_STR); - printf("\n"); + mp_printf(MP_PYTHON_PRINTER, "\n"); } // Helper for 1-argument form of builtin help @@ -57,9 +57,9 @@ STATIC void pyhelp_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { // void pyhelp_print_obj(const mp_obj_t obj) { // try to print something sensible about the given object - printf("object "); + mp_printf(MP_PYTHON_PRINTER, "object "); mp_obj_print(obj, PRINT_STR); - printf(" is of type %s\n", mp_obj_get_type_str(obj)); + mp_printf(MP_PYTHON_PRINTER, " is of type %s\n", mp_obj_get_type_str(obj)); mp_map_t *map = NULL; if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { diff --git a/py/mpprint.h b/py/mpprint.h index 6e47409ec..f9204e322 100644 --- a/py/mpprint.h +++ b/py/mpprint.h @@ -39,6 +39,12 @@ #define PF_FLAG_ADD_PERCENT (0x100) #define PF_FLAG_SHOW_OCTAL_LETTER (0x200) +#if MICROPY_PY_IO +# define MP_PYTHON_PRINTER &mp_sys_stdout_print +#else +# define MP_PYTHON_PRINTER &mp_plat_print +#endif + typedef void (*mp_print_strn_t)(void *data, const char *str, size_t len); typedef struct _mp_print_t { -- cgit v1.2.3 From 3730090d8f028dc76aee33718b1282f0dad9de6c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 22 Oct 2016 01:07:07 +0300 Subject: py/{modbuiltins,obj}: Use MP_PYTHON_PRINTER where possible. --- py/modbuiltins.c | 9 ++------- py/obj.c | 6 +----- 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'py') diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 57e52efa5..b295dae62 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -430,13 +430,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print); STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) { if (o != mp_const_none) { - #if MICROPY_PY_IO - mp_obj_print_helper(&mp_sys_stdout_print, o, PRINT_REPR); - mp_print_str(&mp_sys_stdout_print, "\n"); - #else - mp_obj_print_helper(&mp_plat_print, o, PRINT_REPR); - mp_print_str(&mp_plat_print, "\n"); - #endif + mp_obj_print_helper(MP_PYTHON_PRINTER, o, PRINT_REPR); + mp_print_str(MP_PYTHON_PRINTER, "\n"); #if MICROPY_CAN_OVERRIDE_BUILTINS // Set "_" special variable mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o}; diff --git a/py/obj.c b/py/obj.c index 72b7a216b..5601a73fe 100644 --- a/py/obj.c +++ b/py/obj.c @@ -76,11 +76,7 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t } void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) { -#if MICROPY_PY_IO - mp_obj_print_helper(&mp_sys_stdout_print, o_in, kind); -#else - mp_obj_print_helper(&mp_plat_print, o_in, kind); -#endif + mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind); } // helper function to print an exception with traceback -- cgit v1.2.3 From bdb0d2d0bc146cc043d9bd0c066446d56266413a Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 22 Oct 2016 14:30:01 +1100 Subject: py/modbuiltins: Add builtin "slice", pointing to existing slice type. --- py/modbuiltins.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'py') diff --git a/py/modbuiltins.c b/py/modbuiltins.c index b295dae62..d52949b31 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -617,6 +617,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { #if MICROPY_PY_BUILTINS_SET { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mp_type_set) }, #endif + #if MICROPY_PY_BUILTINS_SLICE + { MP_ROM_QSTR(MP_QSTR_slice), MP_ROM_PTR(&mp_type_slice) }, + #endif { MP_ROM_QSTR(MP_QSTR_str), MP_ROM_PTR(&mp_type_str) }, { MP_ROM_QSTR(MP_QSTR_super), MP_ROM_PTR(&mp_type_super) }, { MP_ROM_QSTR(MP_QSTR_tuple), MP_ROM_PTR(&mp_type_tuple) }, -- cgit v1.2.3 From 5076e5c3394ca0a2166bb1870b4d73deaddc96ef Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 24 Oct 2016 13:50:03 +1100 Subject: py: Add "delattr" builtin, conditional on MICROPY_CPYTHON_COMPAT. --- py/builtin.h | 1 + py/modbuiltins.c | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'py') diff --git a/py/builtin.h b/py/builtin.h index df33e2b73..4477fd246 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -42,6 +42,7 @@ MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_bin_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_callable_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_chr_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index d52949b31..cbdcc9aae 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -542,6 +542,13 @@ STATIC mp_obj_t mp_builtin_setattr(mp_obj_t base, mp_obj_t attr, mp_obj_t value) } MP_DEFINE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj, mp_builtin_setattr); +#if MICROPY_CPYTHON_COMPAT +STATIC mp_obj_t mp_builtin_delattr(mp_obj_t base, mp_obj_t attr) { + return mp_builtin_setattr(base, attr, MP_OBJ_NULL); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); +#endif + STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { qstr attr = mp_obj_str_get_qstr(attr_in); @@ -645,6 +652,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mp_builtin_compile_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_chr), MP_ROM_PTR(&mp_builtin_chr_obj) }, + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_delattr), MP_ROM_PTR(&mp_builtin_delattr_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) }, { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) }, #if MICROPY_PY_BUILTINS_EVAL_EXEC -- cgit v1.2.3 From f00ecdb54d06f57e318d00db00df82e6450e5901 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 26 Oct 2016 02:08:37 +0300 Subject: extmod/moduos_dupterm: Renamed to uos_dupterm. As part of file naming clean up (moduos_dupterm doesn't implement a full module, so should skip "mod" prefix, similar to other files in extmod/). --- extmod/moduos_dupterm.c | 93 ------------------------------------------------- extmod/uos_dupterm.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++ py/py.mk | 2 +- 3 files changed, 94 insertions(+), 94 deletions(-) delete mode 100644 extmod/moduos_dupterm.c create mode 100644 extmod/uos_dupterm.c (limited to 'py') diff --git a/extmod/moduos_dupterm.c b/extmod/moduos_dupterm.c deleted file mode 100644 index d888099df..000000000 --- a/extmod/moduos_dupterm.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Paul Sokolovsky - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include "py/mpconfig.h" - -#include "py/nlr.h" -#include "py/runtime.h" -#include "py/objtuple.h" -#include "py/objarray.h" -#include "py/stream.h" - -#if MICROPY_PY_OS_DUPTERM - -void mp_uos_deactivate(const char *msg, mp_obj_t exc) { - mp_obj_t term = MP_STATE_PORT(term_obj); - MP_STATE_PORT(term_obj) = NULL; - mp_printf(&mp_plat_print, msg); - if (exc != MP_OBJ_NULL) { - mp_obj_print_exception(&mp_plat_print, exc); - } - mp_stream_close(term); -} - -void mp_uos_dupterm_tx_strn(const char *str, size_t len) { - if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t write_m[3]; - mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_write, write_m); - - mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); - void *org_items = arr->items; - arr->items = (void*)str; - arr->len = len; - write_m[2] = MP_STATE_PORT(dupterm_arr_obj); - mp_call_method_n_kw(1, 0, write_m); - arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); - arr->items = org_items; - arr->len = 1; - nlr_pop(); - } else { - mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val); - } - } -} - -STATIC mp_obj_t mp_uos_dupterm(mp_uint_t n_args, const mp_obj_t *args) { - if (n_args == 0) { - if (MP_STATE_PORT(term_obj) == MP_OBJ_NULL) { - return mp_const_none; - } else { - return MP_STATE_PORT(term_obj); - } - } else { - if (args[0] == mp_const_none) { - MP_STATE_PORT(term_obj) = MP_OBJ_NULL; - } else { - MP_STATE_PORT(term_obj) = args[0]; - if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) { - MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); - } - } - return mp_const_none; - } -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 0, 1, mp_uos_dupterm); - -#endif diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c new file mode 100644 index 000000000..d888099df --- /dev/null +++ b/extmod/uos_dupterm.c @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "py/mpconfig.h" + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/objtuple.h" +#include "py/objarray.h" +#include "py/stream.h" + +#if MICROPY_PY_OS_DUPTERM + +void mp_uos_deactivate(const char *msg, mp_obj_t exc) { + mp_obj_t term = MP_STATE_PORT(term_obj); + MP_STATE_PORT(term_obj) = NULL; + mp_printf(&mp_plat_print, msg); + if (exc != MP_OBJ_NULL) { + mp_obj_print_exception(&mp_plat_print, exc); + } + mp_stream_close(term); +} + +void mp_uos_dupterm_tx_strn(const char *str, size_t len) { + if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t write_m[3]; + mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_write, write_m); + + mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); + void *org_items = arr->items; + arr->items = (void*)str; + arr->len = len; + write_m[2] = MP_STATE_PORT(dupterm_arr_obj); + mp_call_method_n_kw(1, 0, write_m); + arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); + arr->items = org_items; + arr->len = 1; + nlr_pop(); + } else { + mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val); + } + } +} + +STATIC mp_obj_t mp_uos_dupterm(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + if (MP_STATE_PORT(term_obj) == MP_OBJ_NULL) { + return mp_const_none; + } else { + return MP_STATE_PORT(term_obj); + } + } else { + if (args[0] == mp_const_none) { + MP_STATE_PORT(term_obj) = MP_OBJ_NULL; + } else { + MP_STATE_PORT(term_obj) = args[0]; + if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) { + MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); + } + } + return mp_const_none; + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 0, 1, mp_uos_dupterm); + +#endif diff --git a/py/py.mk b/py/py.mk index ab07bbbde..767fcac52 100644 --- a/py/py.mk +++ b/py/py.mk @@ -230,7 +230,7 @@ PY_O_BASENAME = \ ../extmod/vfs_fat_lexer.o \ ../extmod/vfs_fat_misc.o \ ../extmod/utime_mphal.o \ - ../extmod/moduos_dupterm.o \ + ../extmod/uos_dupterm.o \ ../lib/embed/abort_.o \ ../lib/utils/printf.o \ -- cgit v1.2.3 From 8a49905a2f268255cba7f7deb6c334b830d5943a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 27 Oct 2016 22:12:59 +0300 Subject: py/stream: Typo fix in comment. --- py/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'py') diff --git a/py/stream.c b/py/stream.c index cc8a63ac2..dadfcf5d6 100644 --- a/py/stream.c +++ b/py/stream.c @@ -391,7 +391,7 @@ STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) if (mp_is_nonblocking_error(error)) { if (vstr.len == 1) { // We just incremented it, but otherwise we read nothing - // and immediately got EAGAIN. This is case is not well + // and immediately got EAGAIN. This case is not well // specified in // https://docs.python.org/3/library/io.html#io.IOBase.readline // unlike similar case for read(). But we follow the latter's -- cgit v1.2.3 From 76146b3d9ab0ab88ce0f0d1cfa0235ec0758a4a9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 30 Oct 2016 03:02:07 +0300 Subject: extmod/utime_mphal: Allow ticks functions period be configurable by a port. Using MICROPY_PY_UTIME_TICKS_PERIOD config var. --- extmod/utime_mphal.c | 8 ++++---- py/mpconfig.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'py') diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c index 609a0da84..1a32180cf 100644 --- a/extmod/utime_mphal.c +++ b/extmod/utime_mphal.c @@ -71,17 +71,17 @@ STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); STATIC mp_obj_t time_ticks_ms(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms); STATIC mp_obj_t time_ticks_us(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); STATIC mp_obj_t time_ticks_cpu(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu); @@ -97,7 +97,7 @@ STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) { // we assume that first argument come from ticks_xx so is small int uint32_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in); uint32_t delta = (uint32_t)mp_obj_get_int(delta_in); - return MP_OBJ_NEW_SMALL_INT((ticks + delta) & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add); diff --git a/py/mpconfig.h b/py/mpconfig.h index dcdaffe0f..fce997692 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -866,6 +866,16 @@ typedef double mp_float_t; #define MICROPY_PY_UTIME_MP_HAL (0) #endif +// Period of values returned by utime.ticks_ms(), ticks_us(), ticks_cpu() +// functions. Should be power of two. All functions above use the same +// period, so if underlying hardware/API has different periods, the +// minimum of them should be used. The value below is the maximum value +// this parameter can take (corresponding to 30 bit tick values on 32-bit +// system). +#ifndef MICROPY_PY_UTIME_TICKS_PERIOD +#define MICROPY_PY_UTIME_TICKS_PERIOD (MP_SMALL_INT_POSITIVE_MASK + 1) +#endif + // Whether to provide "_thread" module #ifndef MICROPY_PY_THREAD #define MICROPY_PY_THREAD (0) -- cgit v1.2.3 From 8908e505ce23ccd1f0ee49f3ffa80bf78cfaccfa Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Sun, 30 Oct 2016 14:25:04 -0200 Subject: py/sequence: Fix reverse slicing of lists. --- py/sequence.c | 49 +++++++++++++++++++++++++++++------------ tests/basics/list_slice_3arg.py | 19 ++++++++++++++++ 2 files changed, 54 insertions(+), 14 deletions(-) (limited to 'py') diff --git a/py/sequence.c b/py/sequence.c index 0acdd25be..bc2cfc077 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -53,15 +53,35 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice mp_int_t start, stop; mp_obj_slice_get(slice, &ostart, &ostop, &ostep); + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { + indexes->step = mp_obj_get_int(ostep); + if (indexes->step == 0) { + mp_raise_ValueError("slice step cannot be zero"); + } + } else { + indexes->step = 1; + } + if (ostart == mp_const_none) { - start = 0; + if (indexes->step > 0) { + start = 0; + } else { + start = len - 1; + } } else { start = mp_obj_get_int(ostart); } if (ostop == mp_const_none) { - stop = len; + if (indexes->step > 0) { + stop = len; + } else { + stop = 0; + } } else { stop = mp_obj_get_int(ostop); + if (stop >= 0 && indexes->step < 0) { + stop += 1; + } } // Unlike subscription, out-of-bounds slice indexes are never error @@ -70,29 +90,31 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice if (start < 0) { start = 0; } - } else if ((mp_uint_t)start > len) { + } else if (indexes->step > 0 && (mp_uint_t)start > len) { start = len; + } else if (indexes->step < 0 && (mp_uint_t)start > len - 1) { + start = len - 1; } if (stop < 0) { stop = len + stop; + if (indexes->step < 0) { + stop += 1; + } } else if ((mp_uint_t)stop > len) { stop = len; } // CPython returns empty sequence in such case, or point for assignment is at start - if (start > stop) { + if (indexes->step > 0 && start > stop) { stop = start; + } else if (indexes->step < 0 && start < stop) { + stop = start + 1; } indexes->start = start; indexes->stop = stop; - if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { - indexes->step = mp_obj_get_int(ostep); - return false; - } - indexes->step = 1; - return true; + return indexes->step == 1; } #endif @@ -106,10 +128,9 @@ mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice mp_obj_t res = mp_obj_new_list(0, NULL); if (step < 0) { - stop--; - while (start <= stop) { - mp_obj_list_append(res, seq[stop]); - stop += step; + while (start >= stop) { + mp_obj_list_append(res, seq[start]); + start += step; } } else { while (start < stop) { diff --git a/tests/basics/list_slice_3arg.py b/tests/basics/list_slice_3arg.py index b98ca3e4f..8578d5855 100644 --- a/tests/basics/list_slice_3arg.py +++ b/tests/basics/list_slice_3arg.py @@ -7,3 +7,22 @@ x = list(range(9)) print(x[::-1]) print(x[::2]) print(x[::-2]) + +x = list(range(5)) +print(x[:0:-1]) +print(x[:1:-1]) +print(x[:2:-1]) +print(x[0::-1]) +print(x[1::-1]) +print(x[2::-1]) + +x = list(range(5)) +print(x[0:0:-1]) +print(x[4:4:-1]) +print(x[5:5:-1]) + +x = list(range(10)) +print(x[-1:-1:-1]) +print(x[-1:-2:-1]) +print(x[-1:-11:-1]) +print(x[-10:-11:-1]) -- cgit v1.2.3 From 3679ee9b520db96772ef0917d0a108180aa70114 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Oct 2016 11:03:39 +0200 Subject: py: fix null pointer dereference in mpz.c, fix missing va_end in warning.c --- py/mpz.c | 5 ++++- py/warning.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'py') diff --git a/py/mpz.c b/py/mpz.c index cceb079cd..1dd177b8e 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1652,7 +1652,10 @@ char *mpz_as_str(const mpz_t *i, mp_uint_t base) { // assumes enough space as calculated by mp_int_format_size // returns length of string, not including null byte mp_uint_t mpz_as_str_inpl(const mpz_t *i, mp_uint_t base, const char *prefix, char base_char, char comma, char *str) { - if (str == NULL || base < 2 || base > 32) { + if (str == NULL) { + return 0; + } + if (base < 2 || base > 32) { str[0] = 0; return 0; } diff --git a/py/warning.c b/py/warning.c index eae145bd3..4cdf3b3f1 100644 --- a/py/warning.c +++ b/py/warning.c @@ -38,6 +38,7 @@ void mp_warning(const char *msg, ...) { mp_print_str(&mp_plat_print, "Warning: "); mp_vprintf(&mp_plat_print, msg, args); mp_print_str(&mp_plat_print, "\n"); + va_end(args); } void mp_emitter_warning(pass_kind_t pass, const char *msg) { -- cgit v1.2.3 From 7ffc959c00707c8328d3e8235e9c4741f227c25c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Oct 2016 11:05:33 +0200 Subject: py: remove asserts that are always true in emitbc.c --- py/emitbc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'py') diff --git a/py/emitbc.c b/py/emitbc.c index d6f2bf333..e11c9ae94 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -183,7 +183,6 @@ STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) { } STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) { - assert((b2 & (~0xff)) == 0); byte *c = emit_get_cur_to_write_bytecode(emit, 2); c[0] = b1; c[1] = b2; @@ -550,7 +549,6 @@ void mp_emit_bc_load_null(emit_t *emit) { void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; - assert(local_num >= 0); emit_bc_pre(emit, 1); if (local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); @@ -608,7 +606,6 @@ void mp_emit_bc_load_subscr(emit_t *emit) { void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; - assert(local_num >= 0); emit_bc_pre(emit, -1); if (local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); @@ -927,7 +924,7 @@ void mp_emit_bc_return_value(emit_t *emit) { } void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { - assert(0 <= n_args && n_args <= 2); + assert(n_args <= 2); emit_bc_pre(emit, -n_args); emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); } -- cgit v1.2.3 From ffb04a5845d2b24b99260d72ea8b99d9425ee1b4 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Thu, 2 Jun 2016 19:10:39 +0200 Subject: unix: fix symbol references for x86 Mac --- py/nlrx86.S | 34 ++++++++++++++++++++++++++-------- unix/Makefile | 6 +++++- unix/gccollect.c | 12 ++++++++++++ 3 files changed, 43 insertions(+), 9 deletions(-) (limited to 'py') diff --git a/py/nlrx86.S b/py/nlrx86.S index 8a96af81c..8c538ba17 100644 --- a/py/nlrx86.S +++ b/py/nlrx86.S @@ -37,9 +37,18 @@ #if defined(_WIN32) || defined(__CYGWIN__) #define NLR_OS_WINDOWS +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#define NLR_OS_MAC +#endif + +#if defined(NLR_OS_WINDOWS) || defined(NLR_OS_MAC) #define NLR_TOP (_mp_state_ctx + NLR_TOP_OFFSET) +#define MP_THREAD_GET_STATE _mp_thread_get_state #else #define NLR_TOP (mp_state_ctx + NLR_TOP_OFFSET) +#define MP_THREAD_GET_STATE mp_thread_get_state #endif // offset of nlr_top within mp_state_thread_t structure @@ -55,6 +64,9 @@ .globl _nlr_push .def _nlr_push; .scl 2; .type 32; .endef _nlr_push: +#elif defined(NLR_OS_MAC) + .globl _nlr_push +_nlr_push: #else .globl nlr_push .type nlr_push, @function @@ -75,7 +87,7 @@ nlr_push: mov %edx, NLR_TOP # stor new nlr_buf (to make linked list) #else // to check: stack is aligned to 16-byte boundary before this call - call mp_thread_get_state # get mp_state_thread ptr into eax + call MP_THREAD_GET_STATE # get mp_state_thread ptr into eax mov 4(%esp), %edx # load nlr_buf argument into edx (edx clobbered by call) mov NLR_TOP_TH_OFF(%eax), %ecx # get thread.nlr_top (last nlr_buf) mov %ecx, (%edx) # store it @@ -84,7 +96,7 @@ nlr_push: xor %eax, %eax # return 0, normal return ret # return -#if !defined(NLR_OS_WINDOWS) +#if !defined(NLR_OS_WINDOWS) && !defined(NLR_OS_MAC) .size nlr_push, .-nlr_push #endif @@ -95,6 +107,9 @@ nlr_push: .globl _nlr_pop .def _nlr_pop; .scl 2; .type 32; .endef _nlr_pop: +#elif defined(NLR_OS_MAC) + .globl _nlr_pop +_nlr_pop: #else .globl nlr_pop .type nlr_pop, @function @@ -106,14 +121,14 @@ nlr_pop: mov (%eax), %eax # load prev nlr_buf mov %eax, NLR_TOP # store nlr_top (to unlink list) #else - call mp_thread_get_state # get mp_state_thread ptr into eax + call MP_THREAD_GET_STATE # get mp_state_thread ptr into eax mov NLR_TOP_TH_OFF(%eax), %ecx # get thread.nlr_top (last nlr_buf) mov (%ecx), %ecx # load prev nlr_buf mov %ecx, NLR_TOP_TH_OFF(%eax) # store prev nlr_buf (to unlink list) #endif ret # return -#if !defined(NLR_OS_WINDOWS) +#if !defined(NLR_OS_WINDOWS) && !defined(NLR_OS_MAC) .size nlr_pop, .-nlr_pop #endif @@ -124,6 +139,9 @@ nlr_pop: .globl _nlr_jump .def _nlr_jump; .scl 2; .type 32; .endef _nlr_jump: +#elif defined(NLR_OS_MAC) + .globl _nlr_jump +_nlr_jump: #else .globl nlr_jump .type nlr_jump, @function @@ -133,7 +151,7 @@ nlr_jump: #if !MICROPY_PY_THREAD mov NLR_TOP, %edx # load nlr_top test %edx, %edx # check for nlr_top being NULL -#if defined(NLR_OS_WINDOWS) +#if defined(NLR_OS_WINDOWS) || defined(NLR_OS_MAC) je _nlr_jump_fail # fail if nlr_top is NULL #else je nlr_jump_fail # fail if nlr_top is NULL @@ -143,10 +161,10 @@ nlr_jump: mov (%edx), %eax # load prev nlr_top mov %eax, NLR_TOP # store nlr_top (to unlink list) #else - call mp_thread_get_state # get mp_state_thread ptr into eax + call MP_THREAD_GET_STATE # get mp_state_thread ptr into eax mov NLR_TOP_TH_OFF(%eax), %edx # get thread.nlr_top (last nlr_buf) test %edx, %edx # check for nlr_top being NULL -#if defined(NLR_OS_WINDOWS) +#if defined(NLR_OS_WINDOWS) || defined(NLR_OS_MAC) je _nlr_jump_fail # fail if nlr_top is NULL #else je nlr_jump_fail # fail if nlr_top is NULL @@ -167,7 +185,7 @@ nlr_jump: xor %eax, %eax # clear return register inc %al # increase to make 1, non-local return ret # return -#if !defined(NLR_OS_WINDOWS) +#if !defined(NLR_OS_WINDOWS) && !defined(NLR_OS_MAC) .size nlr_jump, .-nlr_jump #endif diff --git a/unix/Makefile b/unix/Makefile index d5ad928b3..fd98d2ced 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -58,10 +58,14 @@ endif # On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. # The unix port of micropython on OSX must be compiled with clang, -# while cross-compile ports require gcc, so we test here for OSX and +# while cross-compile ports require gcc, so we test here for OSX and # if necessary override the value of 'CC' set in py/mkenv.mk ifeq ($(UNAME_S),Darwin) +ifeq ($(MICROPY_FORCE_32BIT),1) +CC = clang -m32 +else CC = clang +endif # Use clang syntax for map file LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip else diff --git a/unix/gccollect.c b/unix/gccollect.c index 397c4ffe1..4ec8c2bf5 100644 --- a/unix/gccollect.c +++ b/unix/gccollect.c @@ -80,6 +80,18 @@ STATIC void gc_helper_get_regs(regs_t arr) { register long esi asm ("esi"); register long edi asm ("edi"); register long ebp asm ("ebp"); +#ifdef __clang__ + // TODO: + // This is dirty workaround for Clang. It tries to get around + // uncompliant (wrt to GCC) behavior of handling register variables. + // Application of this patch here is random, and done only to unbreak + // MacOS build. Better, cross-arch ways to deal with Clang issues should + // be found. + asm("" : "=r"(ebx)); + asm("" : "=r"(esi)); + asm("" : "=r"(edi)); + asm("" : "=r"(ebp)); +#endif arr[0] = ebx; arr[1] = esi; arr[2] = edi; -- cgit v1.2.3 From f9b6b37cf65c4f65c4ad461d439fbf624c0f10c1 Mon Sep 17 00:00:00 2001 From: Colin Hogben Date: Mon, 31 Oct 2016 14:05:56 +0000 Subject: py: Fix wrong assumption that m_renew will not move if shrinking In both parse.c and qstr.c, an internal chunking allocator tidies up by calling m_renew to shrink an allocated chunk to the size used, and assumes that the chunk will not move. However, when MICROPY_ENABLE_GC is false, m_renew calls the system realloc, which does not guarantee this behaviour. Environments where realloc may return a different pointer include: (1) mbed-os with MBED_HEAP_STATS_ENABLED (which adds a wrapper around malloc & friends; this is where I was hit by the bug); (2) valgrind on linux (how I diagnosed it). The fix is to call m_renew_maybe with allow_move=false. --- py/parse.c | 5 +++-- py/qstr.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'py') diff --git a/py/parse.c b/py/parse.c index 5920828fe..397d46d9f 100644 --- a/py/parse.c +++ b/py/parse.c @@ -1010,9 +1010,10 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // truncate final chunk and link into chain of chunks if (parser.cur_chunk != NULL) { - (void)m_renew(byte, parser.cur_chunk, + (void)m_renew_maybe(byte, parser.cur_chunk, sizeof(mp_parse_chunk_t) + parser.cur_chunk->alloc, - sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used); + sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used, + false); parser.cur_chunk->alloc = parser.cur_chunk->union_.used; parser.cur_chunk->union_.next = parser.tree.chunk; parser.tree.chunk = parser.cur_chunk; diff --git a/py/qstr.c b/py/qstr.c index 28df06ca3..5aa161064 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -199,7 +199,7 @@ qstr qstr_from_strn(const char *str, size_t len) { byte *new_p = m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_alloc) + n_bytes, false); if (new_p == NULL) { // could not grow existing memory; shrink it to fit previous - (void)m_renew(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used)); + (void)m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used), false); MP_STATE_VM(qstr_last_chunk) = NULL; } else { // could grow existing memory -- cgit v1.2.3 From 828df54bfeaa4a31040fa534dd2961cc9b4ac16e Mon Sep 17 00:00:00 2001 From: Colin Hogben Date: Mon, 31 Oct 2016 14:52:11 +0000 Subject: py: Change config default so m_malloc0 uses memset if GC not enabled. With MICROPY_ENABLE_GC set to false the alternate memory manager may not clear all memory that is allocated, so it must be cleared in m_malloc0. --- py/mpconfig.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'py') diff --git a/py/mpconfig.h b/py/mpconfig.h index fce997692..fd82b079c 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -110,10 +110,11 @@ // Be conservative and always clear to zero newly (re)allocated memory in the GC. // This helps eliminate stray pointers that hold on to memory that's no longer // used. It decreases performance due to unnecessary memory clearing. +// A memory manager which always clears memory can set this to 0. // TODO Do analysis to understand why some memory is not properly cleared and // find a more efficient way to clear it. #ifndef MICROPY_GC_CONSERVATIVE_CLEAR -#define MICROPY_GC_CONSERVATIVE_CLEAR (1) +#define MICROPY_GC_CONSERVATIVE_CLEAR (MICROPY_ENABLE_GC) #endif // Support automatic GC when reaching allocation threshold, -- cgit v1.2.3 From 561844f3ba2dc81ce37c58468099042e27cd422b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 3 Nov 2016 12:33:01 +1100 Subject: py: Add MICROPY_FLOAT_CONST macro for defining float constants. All float constants in the core should use this macro to prevent unnecessary creation of double-precision floats, which makes code less efficient. --- py/modmath.c | 9 ++++----- py/mpconfig.h | 2 ++ py/parsenum.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'py') diff --git a/py/modmath.c b/py/modmath.c index 0c70f34cd..7c51eab03 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -32,9 +32,8 @@ #include // M_PI is not part of the math.h standard and may not be defined -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif +// And by defining our own we can ensure it uses the correct const format. +#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) /// \module math - mathematical functions /// @@ -204,13 +203,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf); /// \function radians(x) STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) { - return mp_obj_new_float(mp_obj_get_float(x_obj) * M_PI / 180.0); + return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians); /// \function degrees(x) STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) { - return mp_obj_new_float(mp_obj_get_float(x_obj) * 180.0 / M_PI); + return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees); diff --git a/py/mpconfig.h b/py/mpconfig.h index fd82b079c..3945a1a5a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -505,10 +505,12 @@ typedef long long mp_longint_impl_t; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_FLOAT_CONST(x) x##F #define MICROPY_FLOAT_C_FUN(fun) fun##f typedef float mp_float_t; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_FLOAT_CONST(x) x #define MICROPY_FLOAT_C_FUN(fun) fun typedef double mp_float_t; #else diff --git a/py/parsenum.c b/py/parsenum.c index 1010ad305..b1c449c9b 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -227,7 +227,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } else { if (in == PARSE_DEC_IN_FRAC) { dec_val += dig * frac_mult; - frac_mult *= 0.1; + frac_mult *= MICROPY_FLOAT_CONST(0.1); } else { dec_val = 10 * dec_val + dig; } -- cgit v1.2.3 From bdf33bc1367fa6fc888c791ce00b326bbd279bdf Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 8 Nov 2016 14:28:30 +1100 Subject: py: Move frozen bytecode Makefile rules from ports to common mk files. Now, to use frozen bytecode all a port needs to do is define FROZEN_MPY_DIR to the directory containing the .py files to freeze, and define MICROPY_MODULE_FROZEN_MPY and MICROPY_QSTR_EXTRA_POOL. --- esp8266/Makefile | 20 -------------------- py/mkenv.mk | 2 ++ py/mkrules.mk | 17 +++++++++++++++++ py/py.mk | 6 ++++++ stmhal/Makefile | 14 -------------- unix/Makefile | 16 ---------------- 6 files changed, 25 insertions(+), 50 deletions(-) (limited to 'py') diff --git a/esp8266/Makefile b/esp8266/Makefile index 3fce1788c..b2191353a 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -14,9 +14,6 @@ FROZEN_MPY_DIR = modules # include py core make definitions include ../py/py.mk -MPY_CROSS = ../mpy-cross/mpy-cross -MPY_TOOL = ../tools/mpy-tool.py - PORT ?= /dev/ttyACM0 BAUD ?= 115200 FLASH_MODE ?= qio @@ -148,9 +145,6 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_S = \ gchelper.s \ -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) - OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -159,9 +153,6 @@ OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) -ifneq ($(FROZEN_MPY_DIR),) -OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o -endif #OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction @@ -184,17 +175,6 @@ $(BUILD)/uart.o: $(CONFVARS_FILE) FROZEN_EXTRA_DEPS = $(CONFVARS_FILE) -# to build .mpy files from .py files -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ - -# to build frozen_mpy.c from all .mpy files -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ - .PHONY: deploy deploy: $(BUILD)/firmware-combined.bin diff --git a/py/mkenv.mk b/py/mkenv.mk index e7262907c..14e23e074 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -59,6 +59,8 @@ LD += -m32 endif MAKE_FROZEN = ../tools/make-frozen.py +MPY_CROSS = ../mpy-cross/mpy-cross +MPY_TOOL = ../tools/mpy-tool.py all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index 26e4aeab3..9b6dc2470 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -106,6 +106,23 @@ $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DE $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif +ifneq ($(FROZEN_MPY_DIR),) +# make a list of all the .py files that need compiling and freezing +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) + +# to build .mpy files from .py files +$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ + +# to build frozen_mpy.c from all .mpy files +$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ +endif + ifneq ($(PROG),) # Build a standalone executable (unix does this) diff --git a/py/py.mk b/py/py.mk index 767fcac52..c71ab7a0c 100644 --- a/py/py.mk +++ b/py/py.mk @@ -237,10 +237,16 @@ PY_O_BASENAME = \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) +# object file for frozen files ifneq ($(FROZEN_DIR),) PY_O += $(BUILD)/$(BUILD)/frozen.o endif +# object file for frozen bytecode (frozen .mpy files) +ifneq ($(FROZEN_MPY_DIR),) +PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o +endif + # Sources that may contain qstrings SRC_QSTR_IGNORE = nlr% emitnx% emitnthumb% emitnarm% SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c) diff --git a/stmhal/Makefile b/stmhal/Makefile index a7a3018cc..59199ea0a 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -283,22 +283,8 @@ endif ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY -OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o -MPY_CROSS = ../mpy-cross/mpy-cross -MPY_TOOL = ../tools/mpy-tool.py - -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ - -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif .PHONY: deploy diff --git a/unix/Makefile b/unix/Makefile index a14ed215c..5e212ff70 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -175,26 +175,10 @@ SRC_QSTR_AUTO_DEPS += ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -MPY_CROSS = ../mpy-cross/mpy-cross -MPY_TOOL = ../tools/mpy-tool.py -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY CFLAGS += -DMICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE=0 # not supported CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs -OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o - -# to build .mpy files from .py files -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ - -# to build frozen_mpy.c from all .mpy files -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif -- cgit v1.2.3 From fcda6a2a786eeddc78af5493d28c0054a43027c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 8 Nov 2016 14:36:06 +1100 Subject: py: Strip leading dirs from frozen mpy files, so any path can be used. With this patch one can now do "make FROZEN_MPY_DIR=../../frozen" to specify a directory containing scripts to be frozen (as well as absolute paths). The compiled .mpy files are now stored in $(BUILD)/frozen_mpy/. --- py/mkrules.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'py') diff --git a/py/mkrules.mk b/py/mkrules.mk index 9b6dc2470..ea647e86f 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -108,11 +108,11 @@ endif ifneq ($(FROZEN_MPY_DIR),) # make a list of all the .py files that need compiling and freezing -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' -printf '%P\n') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) # to build .mpy files from .py files -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py @$(ECHO) "MPY $<" $(Q)$(MKDIR) -p $(dir $@) $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ -- cgit v1.2.3