py: Free unique_code slot for outer module.
Partly (very partly!) addresses issue #386. Most importantly, at the REPL command line, each invocation does not now lead to increased memory usage (unless you define a function/lambda).
This commit is contained in:
parent
682f9e639d
commit
d1e443d0bc
|
@ -3312,7 +3312,8 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
|
||||||
return mp_const_true;
|
return mp_const_true;
|
||||||
#else
|
#else
|
||||||
// return function that executes the outer module
|
// return function that executes the outer module
|
||||||
return rt_make_function_from_id(unique_code_id, MP_OBJ_NULL);
|
// we can free the unique_code slot because no-one has reference to this unique_code_id anymore
|
||||||
|
return rt_make_function_from_id(unique_code_id, true, MP_OBJ_NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// This code glues the code emitters to the runtime.
|
// This code glues the code emitters to the runtime.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
@ -23,7 +24,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MP_CODE_NONE,
|
MP_CODE_UNUSED,
|
||||||
|
MP_CODE_RESERVED,
|
||||||
MP_CODE_BYTE,
|
MP_CODE_BYTE,
|
||||||
MP_CODE_NATIVE,
|
MP_CODE_NATIVE,
|
||||||
MP_CODE_INLINE_ASM,
|
MP_CODE_INLINE_ASM,
|
||||||
|
@ -49,16 +51,16 @@ typedef struct _mp_code_t {
|
||||||
} mp_code_t;
|
} mp_code_t;
|
||||||
|
|
||||||
STATIC machine_uint_t unique_codes_alloc = 0;
|
STATIC machine_uint_t unique_codes_alloc = 0;
|
||||||
|
STATIC machine_uint_t unique_codes_total = 0; // always >= unique_codes_alloc
|
||||||
STATIC mp_code_t *unique_codes = NULL;
|
STATIC mp_code_t *unique_codes = NULL;
|
||||||
STATIC uint next_unique_code_id;
|
|
||||||
|
|
||||||
#ifdef WRITE_CODE
|
#ifdef WRITE_CODE
|
||||||
FILE *fp_write_code = NULL;
|
FILE *fp_write_code = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void mp_emit_glue_init(void) {
|
void mp_emit_glue_init(void) {
|
||||||
next_unique_code_id = 0;
|
|
||||||
unique_codes_alloc = 0;
|
unique_codes_alloc = 0;
|
||||||
|
unique_codes_total = 0;
|
||||||
unique_codes = NULL;
|
unique_codes = NULL;
|
||||||
|
|
||||||
#ifdef WRITE_CODE
|
#ifdef WRITE_CODE
|
||||||
|
@ -77,25 +79,34 @@ void mp_emit_glue_deinit(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint mp_emit_glue_get_unique_code_id(void) {
|
uint mp_emit_glue_get_unique_code_id(void) {
|
||||||
return next_unique_code_id++;
|
// look for an existing unused slot
|
||||||
|
for (uint i = 0; i < unique_codes_alloc; i++) {
|
||||||
|
if (unique_codes[i].kind == MP_CODE_UNUSED) {
|
||||||
|
unique_codes[i].kind = MP_CODE_RESERVED;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no existing slot
|
||||||
|
// return next available id, memory will be allocated later
|
||||||
|
return unique_codes_total++;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void mp_emit_glue_alloc_unique_codes(void) {
|
STATIC void mp_emit_glue_alloc_unique_codes(void) {
|
||||||
if (next_unique_code_id > unique_codes_alloc) {
|
if (unique_codes_total > unique_codes_alloc) {
|
||||||
DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id);
|
DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, unique_codes_total);
|
||||||
// increase size of unique_codes table
|
// increase size of unique_codes table (all new entries are already reserved)
|
||||||
unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id);
|
unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, unique_codes_total);
|
||||||
for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) {
|
for (uint i = unique_codes_alloc; i < unique_codes_total; i++) {
|
||||||
unique_codes[i].kind = MP_CODE_NONE;
|
unique_codes[i].kind = MP_CODE_RESERVED;
|
||||||
}
|
}
|
||||||
unique_codes_alloc = next_unique_code_id;
|
unique_codes_alloc = unique_codes_total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) {
|
void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names) {
|
||||||
mp_emit_glue_alloc_unique_codes();
|
mp_emit_glue_alloc_unique_codes();
|
||||||
|
|
||||||
assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
|
||||||
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
|
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
|
||||||
unique_codes[unique_code_id].scope_flags = scope_flags;
|
unique_codes[unique_code_id].scope_flags = scope_flags;
|
||||||
unique_codes[unique_code_id].n_args = n_args;
|
unique_codes[unique_code_id].n_args = n_args;
|
||||||
|
@ -123,7 +134,7 @@ void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, in
|
||||||
void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
|
void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
|
||||||
mp_emit_glue_alloc_unique_codes();
|
mp_emit_glue_alloc_unique_codes();
|
||||||
|
|
||||||
assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
|
||||||
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
|
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
|
||||||
unique_codes[unique_code_id].scope_flags = 0;
|
unique_codes[unique_code_id].scope_flags = 0;
|
||||||
unique_codes[unique_code_id].n_args = n_args;
|
unique_codes[unique_code_id].n_args = n_args;
|
||||||
|
@ -154,7 +165,7 @@ void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, i
|
||||||
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
|
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
|
||||||
mp_emit_glue_alloc_unique_codes();
|
mp_emit_glue_alloc_unique_codes();
|
||||||
|
|
||||||
assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
|
||||||
unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
|
unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
|
||||||
unique_codes[unique_code_id].scope_flags = 0;
|
unique_codes[unique_code_id].scope_flags = 0;
|
||||||
unique_codes[unique_code_id].n_args = n_args;
|
unique_codes[unique_code_id].n_args = n_args;
|
||||||
|
@ -179,9 +190,9 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
|
mp_obj_t rt_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args) {
|
||||||
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
|
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
|
||||||
if (unique_code_id >= next_unique_code_id) {
|
if (unique_code_id >= unique_codes_total) {
|
||||||
// illegal code id
|
// illegal code id
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
@ -200,8 +211,9 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
|
||||||
fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
|
fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// code id was never assigned (this should not happen)
|
||||||
assert(0);
|
assert(0);
|
||||||
fun = mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for generator functions and if so wrap in generator object
|
// check for generator functions and if so wrap in generator object
|
||||||
|
@ -209,13 +221,20 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
|
||||||
fun = mp_obj_new_gen_wrap(fun);
|
fun = mp_obj_new_gen_wrap(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in some cases we can free the unique_code slot
|
||||||
|
// any dynamically allocade memory is now owned by the fun object
|
||||||
|
if (free_unique_code) {
|
||||||
|
memset(c, 0, sizeof *c); // make sure all pointers are zeroed
|
||||||
|
c->kind = MP_CODE_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) {
|
mp_obj_t rt_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) {
|
||||||
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
|
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
|
||||||
// make function object
|
// make function object
|
||||||
mp_obj_t ffun = rt_make_function_from_id(unique_code_id, def_args);
|
mp_obj_t ffun = rt_make_function_from_id(unique_code_id, false, def_args);
|
||||||
// wrap function in closure object
|
// wrap function in closure object
|
||||||
return mp_obj_new_closure(ffun, closure_tuple);
|
return mp_obj_new_closure(ffun, closure_tuple);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
void mp_emit_glue_init(void);
|
void mp_emit_glue_init(void);
|
||||||
void mp_emit_glue_deinit(void);
|
void mp_emit_glue_deinit(void);
|
||||||
uint mp_emit_glue_get_unique_code_id(void);
|
uint mp_emit_glue_get_unique_code_id(void);
|
||||||
uint mp_emit_glue_get_unique_code(uint unique_code_id);
|
|
||||||
void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names);
|
void mp_emit_glue_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, uint scope_flags, qstr *arg_names);
|
||||||
void mp_emit_glue_assign_native_code(uint unique_code_id, void *f, uint len, int n_args);
|
void mp_emit_glue_assign_native_code(uint unique_code_id, void *f, uint len, int n_args);
|
||||||
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args);
|
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args);
|
||||||
|
|
|
@ -18,11 +18,11 @@ void rt_store_global(qstr qstr, mp_obj_t obj);
|
||||||
void rt_delete_name(qstr qstr);
|
void rt_delete_name(qstr qstr);
|
||||||
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
|
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
|
||||||
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
|
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
|
||||||
mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args);
|
mp_obj_t rt_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args);
|
||||||
mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments
|
mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments
|
||||||
mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun);
|
mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun);
|
||||||
mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive
|
mp_obj_t rt_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive
|
||||||
mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args);
|
mp_obj_t rt_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args);
|
||||||
mp_obj_t rt_call_function_0(mp_obj_t fun);
|
mp_obj_t rt_call_function_0(mp_obj_t fun);
|
||||||
mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg);
|
mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg);
|
||||||
mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
|
mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
|
||||||
|
|
4
py/vm.c
4
py/vm.c
|
@ -563,12 +563,12 @@ unwind_jump:
|
||||||
|
|
||||||
case MP_BC_MAKE_FUNCTION:
|
case MP_BC_MAKE_FUNCTION:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
PUSH(rt_make_function_from_id(unum, MP_OBJ_NULL));
|
PUSH(rt_make_function_from_id(unum, false, MP_OBJ_NULL));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
case MP_BC_MAKE_FUNCTION_DEFARGS:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
SET_TOP(rt_make_function_from_id(unum, TOP()));
|
SET_TOP(rt_make_function_from_id(unum, false, TOP()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_MAKE_CLOSURE:
|
case MP_BC_MAKE_CLOSURE:
|
||||||
|
|
Loading…
Reference in New Issue