8000 py/emitglue: Introduce mp_proto_fun_t as a more general mp_raw_code_t. · micropython/micropython@e2ff00e · GitHub
[go: up one dir, main page]

Skip to content

Commit e2ff00e

Browse files
committed
py/emitglue: Introduce mp_proto_fun_t as a more general mp_raw_code_t.
Allows bytecode itself to be used instead of an mp_raw_code_t in the simple and common cases of a bytecode function without any children. This can be used to further reduce frozen code size, and has the potential to optimise other areas like importing. Signed-off-by: Damien George <damien@micropython.org>
1 parent 5e3006f commit e2ff00e

File tree

15 files changed

+63
-39
lines changed

15 files changed

+63
-39
lines changed

docs/develop/compiler.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ The most relevant method you should know about is this:
157157
mp_compile_to_raw_code(parse_tree, source_file, is_repl, &cm);
158158
159159
// Create and return a function object that executes the outer module.
160-
return mp_make_function_from_raw_code(cm.rc, cm.context, NULL);
160+
return mp_make_function_from_proto_fun(cm.rc, cm.context, NULL);
161161
}
162162
163163
The compiler compiles the code in four passes: scope, stack size, code size and emit.

ports/embed/port/embed_util.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ void mp_embed_exec_mpy(const uint8_t *mpy, size_t len) {
6969
mp_compiled_module_t cm;
7070
cm.context = ctx;
7171
mp_raw_code_load_mem(mpy, len, &cm);
72-
mp_obj_t f = mp_make_function_from_raw_code(cm.rc, ctx, MP_OBJ_NULL);
72+
mp_obj_t f = mp_make_function_from_proto_fun(cm.rc, ctx, MP_OBJ_NULL);
7373
mp_call_function_0(f);
7474
nlr_pop();
7575
} else {

py/bc.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@
4444
// prelude size : var uint
4545
// contains two values interleaved bit-wise as: xIIIIIIC repeated
4646
// x = extension another byte follows
47-
// I = n_info number of bytes in source info section
47+
// I = n_info number of bytes in source info section (always > 0)
4848
// C = n_cells number of bytes/cells in closure section
4949
//
5050
// source info section:
51-
// simple_name : var qstr
51+
// simple_name : var qstr always exists
5252
// argname0 : var qstr
5353
// ... : var qstr
5454
// argnameN : var qstr N = num_pos_args + num_kwonly_args - 1
@@ -226,7 +226,7 @@ typedef struct _mp_compiled_module_t {
226226
// Outer level struct defining a frozen module.
227227
typedef struct _mp_frozen_module_t {
228228
const mp_module_constants_t constants;
229-
const struct _mp_raw_code_t *rc;
229+
const void *proto_fun;
230230
} mp_frozen_module_t;
231231

232232
// State for an executing function.

py/builtinimport.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ STATIC void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) {
165165
#endif
166166

167167
#if (MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD) || MICROPY_MODULE_FROZEN_MPY
168-
STATIC void do_execute_raw_code(const mp_module_context_t *context, const mp_raw_code_t *rc, qstr source_name) {
168+
STATIC void do_execute_proto_fun(const mp_module_context_t *context, mp_proto_fun_t proto_fun, qstr source_name) {
169169
#if MICROPY_PY___FILE__
170170
mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
171171
#else
@@ -188,7 +188,7 @@ STATIC void do_execute_raw_code(const mp_module_context_t *context, const mp_raw
188188
nlr_push_jump_callback(&ctx.callback, mp_globals_locals_set_from_nlr_jump_callback);
189189

190190
// make and execute the function
191-
mp_obj_t module_fun = mp_make_function_from_raw_code(rc, context, NULL);
191+
mp_obj_t module_fun = mp_make_function_from_proto_fun(proto_fun, context, NULL);
192192
mp_call_function_0(module_fun);
193193

194194
// deregister exception handler and restore context
@@ -230,7 +230,7 @@ STATIC void do_load(mp_module_context_t *module_obj, vstr_t *file) {
230230
#else
231231
qstr frozen_file_qstr = MP_QSTRnull;
232232
#endif
233-
do_execute_raw_code(module_obj, frozen->rc, frozen_file_qstr);
233+
do_execute_proto_fun(module_obj, frozen->proto_fun, frozen_file_qstr);
234234
return;
235235
}
236236
#endif
@@ -247,7 +247,7 @@ STATIC void do_load(mp_module_context_t *module_obj, vstr_t *file) {
247247
mp_compiled_module_t cm;
248248
cm.context = module_obj;
249249
mp_raw_code_load_file(file_qstr, &cm);
250-
do_execute_raw_code(cm.context, cm.rc, file_qstr);
250+
do_execute_proto_fun(cm.context, cm.rc, file_qstr);
251251
return;
252252
}
253253
#endif

py/compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3667,7 +3667,7 @@ mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl)
36673667
cm.context->module.globals = mp_globals_get();
36683668
mp_compile_to_raw_code(parse_tree, source_file, is_repl, &cm);
36693669
// return function that executes the outer module
3670-
return mp_make_function_from_raw_code(cm.rc, cm.context, NULL);
3670+
return mp_make_function_from_proto_fun(cm.rc, cm.context, NULL);
36713671
}
36723672

36733673
#endif // MICROPY_ENABLE_COMPILER

py/dynruntime.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type
196196
#define mp_unary_op(op, obj) (mp_fun_table.unary_op((op), (obj)))
197197
#define mp_binary_op(op, lhs, rhs) (mp_fun_table.binary_op((op), (lhs), (rhs)))
198198

199-
#define mp_make_function_from_raw_code(rc, context, def_args) \
200-
(mp_fun_table.make_function_from_raw_code((rc), (context), (def_args)))
199+
#define mp_make_function_from_proto_fun(rc, context, def_args) \
200+
(mp_fun_table.make_function_from_proto_fun((rc), (context), (def_args)))
201201

202202
#define mp_call_function_n_kw(fun, n_args, n_kw, args) \
203203
(mp_fun_table.call_function_n_kw((fun), (n_args) | ((n_kw) << 8), args))
@@ -208,6 +208,8 @@ static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type
208208
#define MP_DYNRUNTIME_INIT_ENTRY \
209209
mp_obj_t old_globals = mp_fun_table.swap_globals(self->context->module.globals); \
210210
mp_raw_code_truncated_t rc; \
211+
rc.proto_fun_indicator[0] = MP_PROTO_FUN_INDICATOR_RAW_CODE_0; \
212+
rc.proto_fun_indicator[1] = MP_PROTO_FUN_INDICATOR_RAW_CODE_1; \
211213
rc.kind = MP_CODE_NATIVE_VIPER; \
212214
rc.is_generator = 0; \
213215
(void)rc;
@@ -217,7 +219,7 @@ static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type
217219
return mp_const_none;
218220

219221
#define MP_DYNRUNTIME_MAKE_FUNCTION(f) \
220-
(mp_make_function_from_raw_code((rc.fun_data = (f), (const mp_raw_code_t *)&rc), self->context, NULL))
222+
(mp_make_function_from_proto_fun((rc.fun_data = (f), (const mp_raw_code_t *)&rc), self->context, NULL))
221223

222224
#define mp_import_name(name, fromlist, level) \
223225
(mp_fun_table.import_name((name), (fromlist), (level)))

py/emitglue.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,19 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
173173
}
174174
#endif
175175

176-
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, const mp_obj_t *def_args) {
177-
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
178-
assert(rc != NULL);
176+
mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_module_context_t *context, const mp_obj_t *def_args) {
177+
DEBUG_OP_printf("make_function_from_proto_fun %p\n", proto_fun);
178+
assert(proto_fun != NULL);
179179

180180
// def_args must be MP_OBJ_NULL or a tuple
181181
assert(def_args == NULL || def_args[0] == MP_OBJ_NULL || mp_obj_is_type(def_args[0], &mp_type_tuple));
182182

183183
// def_kw_args must be MP_OBJ_NULL or a dict
184184
assert(def_args == NULL || def_args[1] == MP_OBJ_NULL || mp_obj_is_type(def_args[1], &mp_type_dict));
185185

186+
// the proto-function is a mp_raw_code_t
187+
const mp_raw_code_t *rc = proto_fun;
188+
186189
// make the function, depending on the raw code kind
187190
mp_obj_t fun;
188191
switch (rc->kind) {
@@ -221,16 +224,16 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module
221224
return fun;
222225
}
223226

224-
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args) {
225-
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
227+
mp_obj_t mp_make_closure_from_proto_fun(mp_proto_fun_t proto_fun, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args) {
228+
DEBUG_OP_printf("make_closure_from_proto_fun %p " UINT_FMT " %p\n", proto_fun, n_closed_over, args);
226229
// make function object
227230
mp_obj_t ffun;
228231
if (n_closed_over & 0x100) {
229232
// default positional and keyword args given
230-
ffun = mp_make_function_from_raw_code(rc, context, args);
233+
ffun = mp_make_function_from_proto_fun(proto_fun, context, args);
231234
} else {
232235
// default positional and keyword args not given
233-
ffun = mp_make_function_from_raw_code(rc, context, NULL);
236+
ffun = mp_make_function_from_proto_fun(proto_fun, context, NULL);
234237
}
235238
// wrap function in closure object
236239
return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2));

py/emitglue.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131

3232
// These variables and functions glue the code emitters to the runtime.
3333

34+
// Used with mp_raw_code_t::proto_fun_indicator to detect if a mp_proto_fun_t is a
35+
// mp_raw_code_t struct or a direct pointer to bytecode.
36+
#define MP_PROTO_FUN_INDICATOR_RAW_CODE_0 (0)
37+
#define MP_PROTO_FUN_INDICATOR_RAW_CODE_1 (0)
38+
3439
// These must fit in 8 bits; see scope.h
3540
enum {
3641
MP_EMIT_OPT_NONE,
@@ -49,14 +54,25 @@ typedef enum {
4954
MP_CODE_NATIVE_ASM,
5055
} mp_raw_code_kind_t;
5156

52-
// This mp_raw_code_t struct holds static information about a non-instantiated function.
57+
// An mp_proto_fun_t points to static information about a non-instantiated function.
5358
// A function object is created from this information, and that object can then be executed.
54-
//
55-
// This struct appears in the following places:
59+
// It points either to bytecode, or an mp_raw_code_t struct.
60+
typedef const void *mp_proto_fun_t;
61+
62+
// Bytecode is distinguished from an mp_raw_code_t struct by the first two bytes: bytecode
63+
// is guaranteed to have either its first or second byte non-zero. So if both bytes are
64+
// zero then the mp_proto_fun_t pointer must be an mp_raw_code_t.
65+
static inline bool mp_proto_fun_is_bytecode(mp_proto_fun_t proto_fun) {
66+
const uint8_t *header = proto_fun;
67+
return (header[0] | (header[1] << 8)) != (MP_PROTO_FUN_INDICATOR_RAW_CODE_0 | (MP_PROTO_FUN_INDICATOR_RAW_CODE_1 << 8));
68+
}
69+
70+
// The mp_raw_code_t struct appears in the following places:
5671
// compiled bytecode: instance in RAM, referenced by outer scope, usually freed after first (and only) use
5772
// mpy file: instance in RAM, created when .mpy file is loaded (same comments as above)
5873
// frozen: instance in ROM
5974
typedef struct _mp_raw_code_t {
75+
uint8_t proto_fun_indicator[2];
6076
uint8_t kind; // of type mp_raw_code_kind_t; only 3 bits used
6177
bool is_generator;
6278
const void *fun_data;
@@ -88,6 +104,7 @@ typedef struct _mp_raw_code_t {
88104
// only needed when the kind is MP_CODE_NATIVE_ASM. So this struct can be used when the
89105
// kind is MP_CODE_BYTECODE, MP_CODE_NATIVE_PY or MP_CODE_NATIVE_VIPER, to reduce its size.
90106
typedef struct _mp_raw_code_truncated_t {
107+
uint8_t proto_fun_indicator[2];
91108
uint8_t kind;
92109
bool is_generator;
93110
const void *fun_data;
@@ -127,7 +144,7 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
127144
#endif
128145
uint16_t scope_flags, uint32_t asm_n_pos_args, uint32_t asm_type_sig);
129146

130-
mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, const mp_obj_t *def_args);
131-
mp_obj_t mp_make_closure_from_raw_code(const mp_raw_code_t *rc, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args);
147+
mp_obj_t mp_make_function_from_proto_fun(mp_proto_fun_t proto_fun, const mp_module_context_t *context, const mp_obj_t *def_args);
148+
mp_obj_t mp_make_closure_from_proto_fun(mp_proto_fun_t proto_fun, const mp_module_context_t *context, mp_uint_t n_closed_over, const mp_obj_t *args);
132149

133150
#endif // MICROPY_INCLUDED_PY_EMITGLUE_H

py/emitnative.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,7 +2657,7 @@ STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_
26572657
need_reg_all(emit);
26582658
}
26592659
emit_load_reg_with_child(emit, REG_ARG_1, scope->raw_code);
2660-
ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_RAW_CODE);
2660+
ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_PROTO_FUN);
26612661
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
26622662
}
26632663

@@ -2675,7 +2675,7 @@ STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_c
26752675
need_reg_all(emit);
26762676
}
26772677
emit_load_reg_with_child(emit, REG_ARG_1, scope->raw_code);
2678-
ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_RAW_CODE);
2678+
ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_PROTO_FUN);
26792679

26802680
// make closure
26812681
#if REG_ARG_1 != REG_RET

py/emitnx86.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
3737
[MP_F_STORE_SET] = 2,
3838
[MP_F_LIST_APPEND] = 2,
3939
[MP_F_STORE_MAP] = 3,
40-
[MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3,
40+
[MP_F_MAKE_FUNCTION_FROM_PROTO_FUN] = 3,
4141
[MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3,
4242
[MP_F_CALL_METHOD_N_KW] = 3,
4343
[MP_F_CALL_METHOD_N_KW_VAR] = 3,

0 commit comments

Comments
 (0)
0