Skip to content

Commit dcdf8f2

Browse files
committed
py/objboundmeth: Allocate arg state on stack if heap alloc fails.
If the heap is locked, or memory allocation fails, then calling a bound method will still succeed by allocating the argument state on the stack. The new code also allocates less stack than before if less than 4 arguments are passed. It's also a tiny bit smaller in code size. This was done as part of the ESA project.
1 parent bb293e6 commit dcdf8f2

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

py/objboundmeth.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,25 @@ STATIC mp_obj_t bound_meth_call(mp_obj_t self_in, size_t n_args, size_t n_kw, co
5252

5353
// need to insert self->self before all other args and then call self->meth
5454

55-
mp_uint_t n_total = n_args + 2 * n_kw;
56-
if (n_total <= 4) {
57-
// use stack to allocate temporary args array
58-
mp_obj_t args2[5];
59-
args2[0] = self->self;
60-
memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t));
61-
return mp_call_function_n_kw(self->meth, n_args + 1, n_kw, &args2[0]);
62-
} else {
63-
// use heap to allocate temporary args array
64-
mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_total);
65-
args2[0] = self->self;
66-
memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t));
67-
mp_obj_t res = mp_call_function_n_kw(self->meth, n_args + 1, n_kw, &args2[0]);
68-
m_del(mp_obj_t, args2, 1 + n_total);
69-
return res;
55+
size_t n_total = n_args + 2 * n_kw;
56+
mp_obj_t *args2 = NULL;
57+
mp_obj_t *free_args2 = NULL;
58+
if (n_total > 4) {
59+
// try to use heap to allocate temporary args array
60+
args2 = m_new_maybe(mp_obj_t, 1 + n_total);
61+
free_args2 = args2;
7062
}
63+
if (args2 == NULL) {
64+
// (fallback to) use stack to allocate temporary args array
65+
args2 = alloca(sizeof(mp_obj_t) * (1 + n_total));
66+
}
67+
args2[0] = self->self;
68+
memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t));
69+
mp_obj_t res = mp_call_function_n_kw(self->meth, n_args + 1, n_kw, &args2[0]);
70+
if (free_args2 != NULL) {
71+
m_del(mp_obj_t, free_args2, 1 + n_total);
72+
}
73+
return res;
7174
}
7275

7376
#if MICROPY_PY_FUNCTION_ATTRS

0 commit comments

Comments
 (0)