8000 py: Free unique_code slot for outer module. · micropython/micropython@d1e443d · GitHub
[go: up one dir, main page]

Skip to content

Commit d1e443d

Browse files
committed
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).
1 parent 682f9e6 commit d1e443d

File tree

5 files changed

+44
-25
lines changed

5 files changed

+44
-25
lines changed

py/compile.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3312,7 +3312,8 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, bool is_repl) {
33123312
return mp_const_true;
33133313
#else
33143314
// return function that executes the outer module
3315-
return rt_make_function_from_id(unique_code_id, MP_OBJ_NULL);
3315+
// we can free the unique_code slot because no-one has reference to this unique_code_id anymore
3316+
return rt_make_function_from_id(unique_code_id, true, MP_OBJ_NULL);
33163317
#endif
33173318
}
33183319
}

py/emitglue.c

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// This code glues the code emitters to the runtime.
22

33
#include <stdio.h>
4+
#include <string.h>
45
#include <assert.h>
56

67
#include "misc.h"
@@ -23,7 +24,8 @@
2324
#endif
2425

2526
typedef enum {
26-
MP_CODE_NONE,
27+
MP_CODE_UNUSED,
28+
MP_CODE_RESERVED,
2729
MP_CODE_BYTE,
2830
MP_CODE_NATIVE,
2931
MP_CODE_INLINE_ASM,
@@ -49,16 +51,16 @@ typedef struct _mp_code_t {
4951
} mp_code_t;
5052

5153
STATIC machine_uint_t unique_codes_alloc = 0;
54+
STATIC machine_uint_t unique_codes_total = 0; // always >= unique_codes_alloc
5255
STATIC mp_code_t *unique_codes = NULL;
53-
STATIC uint next_unique_code_id;
5456

5557
#ifdef WRITE_CODE
5658
FILE *fp_write_code = NULL;
5759
#endif
5860

5961
void mp_emit_glue_init(void) {
60-
next_unique_code_id = 0;
6162
unique_codes_alloc = 0;
63+
unique_codes_total = 0;
6264
unique_codes = NULL;
6365

6466
#ifdef WRITE_CODE
@@ -77,25 +79,34 @@ void mp_emit_glue_deinit(void) {
7779
}
7880

7981
uint mp_emit_glue_get_unique_code_id(void) {
80-
return next_unique_code_id++;
82+
// look for an existing unused slot
83+
for (uint i = 0; i < unique_codes_alloc; i++) {
84+
if (unique_codes[i].kind == MP_CODE_UNUSED) {
85+
unique_codes[i].kind = MP_CODE_RESERVED;
86+
return i;
87+
}
88+
}
89+
// no existing slot
90+
// return next available id, memory will be allocated later
91+
return unique_codes_total++;
8192
}
8293

8394
STATIC void mp_emit_glue_alloc_unique_codes(void) {
84-
if (next_unique_code_id > unique_codes_alloc) {
85-
DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id);
86-
// increase size of unique_codes table
87-
unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id);
88-
for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) {
89-
unique_codes[i].kind = MP_CODE_NONE;
95+
if (unique_codes_total > unique_codes_alloc) {
96+
DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, unique_codes_total);
97+
// increase size of unique_codes table (all new entries are already reserved)
98+
unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, unique_codes_total);
99+
for (uint i = unique_codes_alloc; i < unique_codes_total; i++) {
100+
unique_codes[i].kind = MP_CODE_RESERVED;
90101
}
91-
unique_codes_alloc = next_unique_code_id;
102+
unique_codes_alloc = unique_codes_total;
92103
}
93104
}
94105

95106
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) {
96107
mp_emit_glue_alloc_unique_codes();
97108

98-
assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
109+
assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
99110
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
100111
unique_codes[unique_code_id].scope_flags = scope_flags;
101112
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
123134
void mp_emit_glue_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
124135
mp_emit_glue_alloc_unique_codes();
125136

126-
assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
137+
assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
127138
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
128139
unique_codes[unique_code_id].scope_flags = 0;
129140
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
154165
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
155166
mp_emit_glue_alloc_unique_codes();
156167

157-
assert(unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
168+
assert(unique_code_id < unique_codes_alloc && unique_codes[unique_code_id].kind == MP_CODE_RESERVED);
158169
unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
159170
unique_codes[unique_code_id].scope_flags = 0;
160171
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
179190
#endif
180191
}
181192

182-
mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
193+
mp_obj_t rt_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args) {
183194
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
184-
if (unique_code_id >= next_unique_code_id) {
195+
if (unique_code_id >= unique_codes_total) {
185196
// illegal code id
186197
return mp_const_none;
187198
}
@@ -200,22 +211,30 @@ mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
200211
fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
201212
break;
202213
default:
214+
// code id was never assigned (this should not happen)
203215
assert(0);
204-
fun = mp_const_none;
216+
return mp_const_none;
205217
}
206218

207219
// check for generator functions and if so wrap in generator object
208220
if ((c->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
209221
fun = mp_obj_new_gen_wrap(fun);
210222
}
211223

224+
// in some cases we can free the unique_code slot
225+
// any dynamically allocade memory is now owned by the fun object
226+
if (free_unique_code) {
227+
memset(c, 0, sizeof *c); // make sure all pointers are zeroed
228+
c->kind = MP_CODE_UNUSED;
229+
}
230+
212231
return fun;
213232
}
214233

215-
mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) {
234+
mp_obj_t rt_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args) {
216235
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
217236
// make function object
218-
mp_obj_t ffun = rt_make_function_from_id(unique_code_id, def_args);
237+
mp_obj_t ffun = rt_make_function_from_id(unique_code_id, false, def_args);
219238
// wrap function in closure object
220239
return mp_obj_new_closure(ffun, closure_tuple);
221240
}

py/emitglue.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
void mp_emit_glue_init(void);
44
void mp_emit_glue_deinit(void);
55
uint mp_emit_glue_get_unique_code_id(void);
6-
uint mp_emit_glue_get_unique_code(uint unique_code_id);
76
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);
87
void mp_emit_glue_assign_native_code(uint unique_code_id, void *f, uint len, int n_args);
98
void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args);

py/runtime.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ void rt_store_global(qstr qstr, mp_obj_t obj);
1818
void rt_delete_name(qstr qstr);
1919
mp_obj_t rt_unary_op(int op, mp_obj_t arg);
2020
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
21-
mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args);
21+
mp_obj_t rt_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args);
2222
mp_obj_t rt_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments
2323
mp_obj_t rt_make_function_var(int n_args_min, mp_fun_var_t fun);
2424
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
25-
mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args);
25+
mp_obj_t rt_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args);
2626
mp_obj_t rt_call_function_0(mp_obj_t fun);
2727
mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg);
2828
mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);

py/vm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,12 +563,12 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i
563563

564564
case MP_BC_MAKE_FUNCTION:
565565
DECODE_UINT;
566-
PUSH(rt_make_function_from_id(unum, MP_OBJ_NULL));
566+
PUSH(rt_make_function_from_id(unum, false, MP_OBJ_NULL));
567567
break;
568568

569569
case MP_BC_MAKE_FUNCTION_DEFARGS:
570570
DECODE_UINT;
571-
SET_TOP(rt_make_function_from_id(unum, TOP()));
571+
SET_TOP(rt_make_function_from_id(unum, false, TOP()));
572572
break;
573573

574574
case MP_BC_MAKE_CLOSURE:

0 commit comments

Comments
 (0)
0