From f26a30710c77299a715318bc487e1874d1bf9984 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 17 Apr 2014 05:44:51 +0300 Subject: [PATCH 1/6] objfun: Add local header. This follows pattern already used for objtuple, etc.: objfun.h's content is not public - each and every piece of code should not have access to it. It's not private either - with out architecture and implementation language (C) it doesn't make sense to keep implementation of each object strictly private and maintain cumbersome accessors. It's "local" - intended to be used by a small set of "friend" (in C++ terms) objects. --- py/objfun.c | 13 +------------ py/objfun.h | 12 ++++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 py/objfun.h diff --git a/py/objfun.c b/py/objfun.c index 8fadbc6119..66145f4a65 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -9,6 +9,7 @@ #include "qstr.h" #include "obj.h" #include "objtuple.h" +#include "objfun.h" #include "runtime0.h" #include "runtime.h" #include "bc.h" @@ -150,18 +151,6 @@ mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var /******************************************************************************/ /* byte code functions */ -typedef struct _mp_obj_fun_bc_t { - mp_obj_base_t base; - mp_obj_dict_t *globals; // the context within which this function was defined - machine_uint_t n_args : 15; // number of arguments this function takes - machine_uint_t n_def_args : 15; // number of default arguments - machine_uint_t takes_var_args : 1; // set if this function takes variable args - machine_uint_t takes_kw_args : 1; // set if this function takes keyword args - const byte *bytecode; // bytecode for the function - qstr *args; // argument names (needed to resolve positional args passed as keywords) - mp_obj_t extra_args[]; // values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them) -} mp_obj_fun_bc_t; - #if DEBUG_PRINT STATIC void dump_args(const mp_obj_t *a, int sz) { DEBUG_printf("%p: ", a); diff --git a/py/objfun.h b/py/objfun.h new file mode 100644 index 0000000000..07ca623ece --- /dev/null +++ b/py/objfun.h @@ -0,0 +1,12 @@ +typedef struct _mp_obj_fun_bc_t { + mp_obj_base_t base; + mp_obj_dict_t *globals; // the context within which this function was defined + machine_uint_t n_args : 15; // number of arguments this function takes + machine_uint_t n_def_args : 15; // number of default arguments + machine_uint_t takes_var_args : 1; // set if this function takes variable args + machine_uint_t takes_kw_args : 1; // set if this function takes keyword args + const byte *bytecode; // bytecode for the function + qstr *args; // argument names (needed to resolve positional args passed as keywords) + // values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them) + mp_obj_t extra_args[]; +} mp_obj_fun_bc_t; From b7e90ea07890392b7e31ae5079a539b474b16d81 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 17 Apr 2014 05:49:47 +0300 Subject: [PATCH 2/6] objgenerator: Generator must execute in its defining lexical context. I.e. with its own globals. So, just as for functions, we need to switch globals when resuming a generator. --- py/objgenerator.c | 16 ++++++++++++---- tests/basics/gen_context.py | 9 +++++++++ tests/basics/gen_context2.py | 2 ++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/basics/gen_context.py create mode 100644 tests/basics/gen_context2.py diff --git a/py/objgenerator.c b/py/objgenerator.c index 6468aa20db..9be7fb197b 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -9,6 +9,7 @@ #include "runtime.h" #include "bc.h" #include "objgenerator.h" +#include "objfun.h" /******************************************************************************/ /* generator wrapper */ @@ -18,11 +19,12 @@ typedef struct _mp_obj_gen_wrap_t { mp_obj_t *fun; } mp_obj_gen_wrap_t; -mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj_t *args, uint n_args2, const mp_obj_t *args2); +mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args, + uint n_args2, const mp_obj_t *args2); STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_gen_wrap_t *self = self_in; - mp_obj_t self_fun = self->fun; + mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun; assert(MP_OBJ_IS_TYPE(self_fun, &mp_type_fun_bc)); int bc_n_args; const byte *bc_code; @@ -34,7 +36,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp assert(0); } - return mp_obj_new_gen_instance(bc_code, len1, args1, len2, args2); + return mp_obj_new_gen_instance(self_fun->globals, bc_code, len1, args1, len2, args2); } const mp_obj_type_t mp_type_gen_wrap = { @@ -55,6 +57,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) { typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; + mp_obj_dict_t *globals; const byte *code_info; const byte *ip; mp_obj_t *sp; @@ -89,9 +92,12 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } else { *self->sp = send_value; } + mp_obj_dict_t *old_globals = mp_globals_get(); + mp_globals_set(self->globals); mp_vm_return_kind_t ret_kind = mp_execute_byte_code_2(self->code_info, &self->ip, &self->state[self->n_state - 1], &self->sp, (mp_exc_stack_t*)(self->state + self->n_state), &self->exc_sp, throw_value); + mp_globals_set(old_globals); switch (ret_kind) { case MP_VM_RETURN_NORMAL: @@ -225,7 +231,8 @@ const mp_obj_type_t mp_type_gen_instance = { .locals_dict = (mp_obj_t)&gen_instance_locals_dict, }; -mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj_t *args, uint n_args2, const mp_obj_t *args2) { +mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args, + uint n_args2, const mp_obj_t *args2) { const byte *code_info = bytecode; // get code info size, and skip the line number table machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24); @@ -239,6 +246,7 @@ mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_args, const mp_obj // allocate the generator object, with room for local stack and exception stack mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t)); o->base.type = &mp_type_gen_instance; + o->globals = globals; o->code_info = code_info; o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state o->exc_sp = (mp_exc_stack_t*)(o->state + n_state) - 1; diff --git a/tests/basics/gen_context.py b/tests/basics/gen_context.py new file mode 100644 index 0000000000..02f1531467 --- /dev/null +++ b/tests/basics/gen_context.py @@ -0,0 +1,9 @@ +import gen_context2 + +GLOBAL = "GLOBAL" + +def gen(): + print(GLOBAL) + yield 1 + +gen_context2.call(gen()) diff --git a/tests/basics/gen_context2.py b/tests/basics/gen_context2.py new file mode 100644 index 0000000000..0d8048afcc --- /dev/null +++ b/tests/basics/gen_context2.py @@ -0,0 +1,2 @@ +def call(g): + next(g) From de8292202edef4adf591c1d2562c509638b6c820 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 17 Apr 2014 18:26:07 +0300 Subject: [PATCH 3/6] unix modtime: Adhere to MICROPY_ENABLE_FLOAT better. --- unix/modtime.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/unix/modtime.c b/unix/modtime.c index 032528947c..daf72ff88a 100644 --- a/unix/modtime.c +++ b/unix/modtime.c @@ -11,18 +11,28 @@ #include "runtime.h" STATIC mp_obj_t mod_time_time() { +#if MICROPY_ENABLE_FLOAT + struct timeval tv; + gettimeofday(&tv, NULL); + mp_float_t val = tv.tv_sec + (mp_float_t)tv.tv_usec / 1000000; + return mp_obj_new_float(val); +#else return mp_obj_new_int((machine_int_t)time(NULL)); +#endif } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); // Note: this is deprecated since CPy3.3, but pystone still uses it. STATIC mp_obj_t mod_time_clock() { -// return mp_obj_new_int((machine_int_t)clock()); - // POSIX requires CLOCKS_PER_SEC equals 1000000, so that's what we assume +#if MICROPY_ENABLE_FLOAT + // POSIX requires CLOCKS_PER_SEC equals 1000000, so that's what we assume. // float cannot represent full range of int32 precisely, so we pre-divide // int to reduce resolution, and then actually do float division hoping // to preserve integer part resolution. return mp_obj_new_float((float)(clock() / 1000) / 1000.0); +#else + return mp_obj_new_int((machine_int_t)clock()); +#endif } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock); From eb2fc9787a28554ac74995ab50cf326907f81ff0 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 17 Apr 2014 18:28:38 +0300 Subject: [PATCH 4/6] unix modtime: Convert to static module structures. --- unix/main.c | 3 --- unix/modtime.c | 29 +++++++++++++++++++++++------ unix/mpconfigport.h | 4 ++++ unix/qstrdefsport.h | 4 ++++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/unix/main.c b/unix/main.c index b9b8fe0b9f..d5b04d565b 100644 --- a/unix/main.c +++ b/unix/main.c @@ -357,9 +357,6 @@ int main(int argc, char **argv) { #endif microsocket_init(); -#if MICROPY_MOD_TIME - time_init(); -#endif #if MICROPY_MOD_FFI ffi_init(); #endif diff --git a/unix/modtime.c b/unix/modtime.c index daf72ff88a..a0d7cd0462 100644 --- a/unix/modtime.c +++ b/unix/modtime.c @@ -51,9 +51,26 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); -void time_init() { - mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("time")); - mp_store_attr(m, QSTR_FROM_STR_STATIC("time"), (mp_obj_t)&mod_time_time_obj); - mp_store_attr(m, QSTR_FROM_STR_STATIC("clock"), (mp_obj_t)&mod_time_clock_obj); - mp_store_attr(m, QSTR_FROM_STR_STATIC("sleep"), (mp_obj_t)&mod_time_sleep_obj); -} +STATIC const mp_map_elem_t mp_module_time_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_time) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_clock), (mp_obj_t)&mod_time_clock_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mod_time_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mod_time_time_obj }, +}; + +STATIC const mp_obj_dict_t mp_module_time_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_time_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_time_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_time_globals_table, + }, +}; + +const mp_obj_module_t mp_module_time = { + .base = { &mp_type_module }, + .name = MP_QSTR_time, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index cf6e6fae26..bfbb49aee6 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -17,6 +17,10 @@ #define MICROPY_MOD_SYS_STDFILES (1) #define MICROPY_ENABLE_MOD_CMATH (1) +extern const struct _mp_obj_module_t mp_module_time; +#define MICROPY_EXTRA_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_time }, \ + // type definitions for the specific machine #ifdef __LP64__ diff --git a/unix/qstrdefsport.h b/unix/qstrdefsport.h index 42f20d2657..eb61e2a618 100644 --- a/unix/qstrdefsport.h +++ b/unix/qstrdefsport.h @@ -30,3 +30,7 @@ Q(fficallback) Q(ffivar) Q(func) Q(var) + +Q(time) +Q(clock) +Q(sleep) From 59a2f4828d809a47a71996791c216f5e2da91f6f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 17 Apr 2014 18:32:36 +0300 Subject: [PATCH 5/6] unix: Make mem_info() dump GC info too. mem_info() is already pretty hacky, let it be more hacky. --- unix/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/unix/main.c b/unix/main.c index d5b04d565b..2044e205e4 100644 --- a/unix/main.c +++ b/unix/main.c @@ -250,6 +250,7 @@ int usage(char **argv) { mp_obj_t mem_info(void) { printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated()); + gc_dump_info(); return mp_const_none; } From e1e4249a674397ab837a31b8b4821f64e655c74e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 17 Apr 2014 20:34:04 +0300 Subject: [PATCH 6/6] unix modsocket: Convert to static module structures. --- unix/main.c | 1 - unix/modsocket.c | 49 +++++++++++++++++++++++++-------------------- unix/mpconfigport.h | 2 ++ unix/qstrdefsport.h | 45 ++++++++++++++++++++++++++++------------- 4 files changed, 60 insertions(+), 37 deletions(-) diff --git a/unix/main.c b/unix/main.c index 2044e205e4..fd3419a1c7 100644 --- a/unix/main.c +++ b/unix/main.c @@ -357,7 +357,6 @@ int main(int argc, char **argv) { mp_store_name(qstr_from_str("gc"), (mp_obj_t)&pyb_gc_obj); #endif - microsocket_init(); #if MICROPY_MOD_FFI ffi_init(); #endif diff --git a/unix/modsocket.c b/unix/modsocket.c index 8f47a8b157..7b1aaa975d 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -322,12 +322,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod extern mp_obj_type_t sockaddr_in_type; -#define C(name) { #name, name } +STATIC const mp_map_elem_t mp_module_socket_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_microsocket) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)µsocket_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_socket_getaddrinfo_obj }, +#if MICROPY_SOCKET_EXTRA + { MP_OBJ_NEW_QSTR(MP_QSTR_sockaddr_in), (mp_obj_t)&sockaddr_in_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_htons), (mp_obj_t)&mod_socket_htons_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_inet_aton), (mp_obj_t)&mod_socket_inet_aton_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_gethostbyname), (mp_obj_t)&mod_socket_gethostbyname_obj }, +#endif -STATIC const struct sym_entry { - const char *sym; - int val; -} constants[] = { +#define C(name) { MP_OBJ_NEW_QSTR(MP_QSTR_ ## name), MP_OBJ_NEW_SMALL_INT(name) } C(AF_UNIX), C(AF_INET), C(AF_INET6), @@ -344,23 +350,22 @@ STATIC const struct sym_entry { C(SO_KEEPALIVE), C(SO_LINGER), C(SO_REUSEADDR), - - {NULL} +#undef C }; -#undef C +STATIC const mp_obj_dict_t mp_module_socket_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_socket_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_socket_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_socket_globals_table, + }, +}; -void microsocket_init() { - mp_obj_t m = mp_obj_new_module(MP_QSTR_microsocket); - mp_store_attr(m, MP_QSTR_socket, (mp_obj_t)µsocket_type); -#if MICROPY_SOCKET_EXTRA - mp_store_attr(m, MP_QSTR_sockaddr_in, (mp_obj_t)&sockaddr_in_type); - mp_store_attr(m, MP_QSTR_htons, (mp_obj_t)&mod_socket_htons_obj); - mp_store_attr(m, MP_QSTR_inet_aton, (mp_obj_t)&mod_socket_inet_aton_obj); - mp_store_attr(m, MP_QSTR_gethostbyname, (mp_obj_t)&mod_socket_gethostbyname_obj); -#endif - mp_store_attr(m, MP_QSTR_getaddrinfo, (mp_obj_t)&mod_socket_getaddrinfo_obj); - for (const struct sym_entry *p = constants; p->sym != NULL; p++) { - mp_store_attr(m, QSTR_FROM_STR_STATIC(p->sym), MP_OBJ_NEW_SMALL_INT((machine_int_t)p->val)); - } -} +const mp_obj_module_t mp_module_socket = { + .base = { &mp_type_module }, + .name = MP_QSTR_microsocket, + .globals = (mp_obj_dict_t*)&mp_module_socket_globals, +}; diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index bfbb49aee6..21d11ebeaf 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -18,8 +18,10 @@ #define MICROPY_ENABLE_MOD_CMATH (1) extern const struct _mp_obj_module_t mp_module_time; +extern const struct _mp_obj_module_t mp_module_socket; #define MICROPY_EXTRA_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_time }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_microsocket), (mp_obj_t)&mp_module_socket }, \ // type definitions for the specific machine diff --git a/unix/qstrdefsport.h b/unix/qstrdefsport.h index eb61e2a618..4de00aa11c 100644 --- a/unix/qstrdefsport.h +++ b/unix/qstrdefsport.h @@ -2,26 +2,12 @@ Q(Test) -Q(rawsocket) -Q(socket) -Q(sockaddr_in) -Q(htons) -Q(inet_aton) -Q(gethostbyname) -Q(getaddrinfo) -Q(microsocket) Q(fileno) Q(read) Q(readall) Q(readline) Q(write) Q(makefile) -Q(connect) -Q(bind) -Q(listen) -Q(accept) -Q(recv) -Q(setsockopt) Q(FileIO) Q(ffimod) @@ -34,3 +20,34 @@ Q(var) Q(time) Q(clock) Q(sleep) + +Q(socket) +Q(sockaddr_in) +Q(htons) +Q(inet_aton) +Q(gethostbyname) +Q(getaddrinfo) +Q(microsocket) +Q(connect) +Q(bind) +Q(listen) +Q(accept) +Q(recv) +Q(setsockopt) + +Q(AF_UNIX) +Q(AF_INET) +Q(AF_INET6) +Q(SOCK_STREAM) +Q(SOCK_DGRAM) +Q(SOCK_RAW) + +Q(MSG_DONTROUTE) +Q(MSG_DONTWAIT) + +Q(SOL_SOCKET) +Q(SO_BROADCAST) +Q(SO_ERROR) +Q(SO_KEEPALIVE) +Q(SO_LINGER) +Q(SO_REUSEADDR)