Skip to content

Commit a8a5d1e

Browse files
committed
py: Provide mp_decode_uint_skip() to help reduce stack usage.
Taking the address of a local variable leads to increased stack usage, so the mp_decode_uint_skip() function is added to reduce the need for taking addresses. The changes in this patch reduce stack usage of a Python call by 8 bytes on ARM Thumb, by 16 bytes on non-windowing Xtensa archs, and by 16 bytes on x86-64. Code size is also slightly reduced on most archs by around 32 bytes.
1 parent 4352b94 commit a8a5d1e

5 files changed

Lines changed: 28 additions & 25 deletions

File tree

py/bc.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ mp_uint_t mp_decode_uint_value(const byte *ptr) {
6464
return mp_decode_uint(&ptr);
6565
}
6666

67+
// This function is used to help reduce stack usage at the caller, for the case when
68+
// the caller doesn't need the actual value and just wants to skip over it.
69+
const byte *mp_decode_uint_skip(const byte *ptr) {
70+
while ((*ptr++) & 0x80) {
71+
}
72+
return ptr;
73+
}
74+
6775
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
6876
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
6977
// generic message, used also for other argument issues
@@ -115,7 +123,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
115123

116124
// get params
117125
size_t n_state = mp_decode_uint(&code_state->ip);
118-
mp_decode_uint(&code_state->ip); // skip n_exc_stack
126+
code_state->ip = mp_decode_uint_skip(code_state->ip); // skip n_exc_stack
119127
size_t scope_flags = *code_state->ip++;
120128
size_t n_pos_args = *code_state->ip++;
121129
size_t n_kwonly_args = *code_state->ip++;

py/bc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ typedef struct _mp_code_state_t {
9292

9393
mp_uint_t mp_decode_uint(const byte **ptr);
9494
mp_uint_t mp_decode_uint_value(const byte *ptr);
95+
const byte *mp_decode_uint_skip(const byte *ptr);
9596

9697
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);
9798
mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args);

py/objfun.c

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,11 @@ const mp_obj_type_t mp_type_fun_builtin_var = {
141141
/* byte code functions */
142142

143143
qstr mp_obj_code_get_name(const byte *code_info) {
144-
mp_decode_uint(&code_info); // skip code_info_size entry
144+
code_info = mp_decode_uint_skip(code_info); // skip code_info_size entry
145145
#if MICROPY_PERSISTENT_CODE
146146
return code_info[0] | (code_info[1] << 8);
147147
#else
148-
return mp_decode_uint(&code_info);
148+
return mp_decode_uint_value(code_info);
149149
#endif
150150
}
151151

@@ -163,8 +163,8 @@ qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) {
163163
#endif
164164

165165
const byte *bc = fun->bytecode;
166-
mp_decode_uint(&bc); // skip n_state
167-
mp_decode_uint(&bc); // skip n_exc_stack
166+
bc = mp_decode_uint_skip(bc); // skip n_state
167+
bc = mp_decode_uint_skip(bc); // skip n_exc_stack
168168
bc++; // skip scope_params
169169
bc++; // skip n_pos_args
170170
bc++; // skip n_kwonly_args
@@ -205,12 +205,9 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args
205205
MP_STACK_CHECK();
206206
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
207207

208-
// get start of bytecode
209-
const byte *ip = self->bytecode;
210-
211208
// bytecode prelude: state size and exception stack size
212-
size_t n_state = mp_decode_uint(&ip);
213-
size_t n_exc_stack = mp_decode_uint(&ip);
209+
size_t n_state = mp_decode_uint_value(self->bytecode);
210+
size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode));
214211

215212
// allocate state for locals and stack
216213
size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
@@ -243,12 +240,9 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
243240
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
244241
DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
245242

246-
// get start of bytecode
247-
const byte *ip = self->bytecode;
248-
249243
// bytecode prelude: state size and exception stack size
250-
size_t n_state = mp_decode_uint(&ip);
251-
size_t n_exc_stack = mp_decode_uint(&ip);
244+
size_t n_state = mp_decode_uint_value(self->bytecode);
245+
size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode));
252246

253247
#if VM_DETECT_STACK_OVERFLOW
254248
n_state += 1;

py/objgenerator.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,9 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
5454
mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun;
5555
assert(self_fun->base.type == &mp_type_fun_bc);
5656

57-
// get start of bytecode
58-
const byte *ip = self_fun->bytecode;
59-
6057
// bytecode prelude: get state size and exception stack size
61-
mp_uint_t n_state = mp_decode_uint(&ip);
62-
mp_uint_t n_exc_stack = mp_decode_uint(&ip);
58+
size_t n_state = mp_decode_uint_value(self_fun->bytecode);
59+
size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self_fun->bytecode));
6360

6461
// allocate the generator object, with room for local stack and exception stack
6562
mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte,

py/vm.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,22 +1363,25 @@ unwind_jump:;
13631363
// TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj)
13641364
if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) {
13651365
const byte *ip = code_state->fun_bc->bytecode;
1366-
mp_decode_uint(&ip); // skip n_state
1367-
mp_decode_uint(&ip); // skip n_exc_stack
1366+
ip = mp_decode_uint_skip(ip); // skip n_state
1367+
ip = mp_decode_uint_skip(ip); // skip n_exc_stack
13681368
ip++; // skip scope_params
13691369
ip++; // skip n_pos_args
13701370
ip++; // skip n_kwonly_args
13711371
ip++; // skip n_def_pos_args
13721372
size_t bc = code_state->ip - ip;
1373-
size_t code_info_size = mp_decode_uint(&ip);
1373+
size_t code_info_size = mp_decode_uint_value(ip);
1374+
ip = mp_decode_uint_skip(ip); // skip code_info_size
13741375
bc -= code_info_size;
13751376
#if MICROPY_PERSISTENT_CODE
13761377
qstr block_name = ip[0] | (ip[1] << 8);
13771378
qstr source_file = ip[2] | (ip[3] << 8);
13781379
ip += 4;
13791380
#else
1380-
qstr block_name = mp_decode_uint(&ip);
1381-
qstr source_file = mp_decode_uint(&ip);
1381+
qstr block_name = mp_decode_uint_value(ip);
1382+
ip = mp_decode_uint_skip(ip);
1383+
qstr source_file = mp_decode_uint_value(ip);
1384+
ip = mp_decode_uint_skip(ip);
13821385
#endif
13831386
size_t source_line = 1;
13841387
size_t c;

0 commit comments

Comments
 (0)