py: Simplify fastn in VM; reduce size of unique code struct.
We still have FAST_[0,1,2] byte codes, but they now just access the fastn array (before they had special local variables). It's now simpler, a bit faster, and uses a bit less stack space (on STM at least, which is most important). The only reason now to keep FAST_[0,1,2] byte codes is for compressed byte code size.
This commit is contained in:
parent
01fa4a9164
commit
d0691ccaec
2
py/obj.h
2
py/obj.h
@ -223,7 +223,7 @@ mp_obj_t mp_obj_new_range(int start, int stop, int step);
|
|||||||
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
|
mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step);
|
||||||
mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code);
|
mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code);
|
||||||
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
|
||||||
mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun);
|
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
|
||||||
mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args);
|
mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args);
|
||||||
mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple);
|
mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple);
|
||||||
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
|
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
typedef struct _mp_obj_gen_wrap_t {
|
typedef struct _mp_obj_gen_wrap_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
uint n_state;
|
|
||||||
mp_obj_t *fun;
|
mp_obj_t *fun;
|
||||||
} mp_obj_gen_wrap_t;
|
} mp_obj_gen_wrap_t;
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t
|
|||||||
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
|
nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mp_obj_new_gen_instance(bc_code, self->n_state, n_args, args);
|
return mp_obj_new_gen_instance(bc_code, bc_n_state, n_args, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mp_obj_type_t gen_wrap_type = {
|
const mp_obj_type_t gen_wrap_type = {
|
||||||
@ -44,11 +43,9 @@ const mp_obj_type_t gen_wrap_type = {
|
|||||||
.call = gen_wrap_call,
|
.call = gen_wrap_call,
|
||||||
};
|
};
|
||||||
|
|
||||||
mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun) {
|
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) {
|
||||||
mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t);
|
mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t);
|
||||||
o->base.type = &gen_wrap_type;
|
o->base.type = &gen_wrap_type;
|
||||||
// we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done
|
|
||||||
o->n_state = (n_locals < 3 ? 3 : n_locals) + n_stack;
|
|
||||||
o->fun = fun;
|
o->fun = fun;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
45
py/runtime.c
45
py/runtime.c
@ -44,11 +44,14 @@ typedef enum {
|
|||||||
} mp_code_kind_t;
|
} mp_code_kind_t;
|
||||||
|
|
||||||
typedef struct _mp_code_t {
|
typedef struct _mp_code_t {
|
||||||
mp_code_kind_t kind;
|
struct {
|
||||||
int n_args;
|
mp_code_kind_t kind : 8;
|
||||||
int n_locals;
|
bool is_generator : 1;
|
||||||
int n_stack;
|
};
|
||||||
bool is_generator;
|
struct {
|
||||||
|
uint n_args : 16;
|
||||||
|
uint n_state : 16;
|
||||||
|
};
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
byte *code;
|
byte *code;
|
||||||
@ -63,7 +66,7 @@ typedef struct _mp_code_t {
|
|||||||
};
|
};
|
||||||
} mp_code_t;
|
} mp_code_t;
|
||||||
|
|
||||||
static int next_unique_code_id;
|
static uint next_unique_code_id;
|
||||||
static machine_uint_t unique_codes_alloc = 0;
|
static machine_uint_t unique_codes_alloc = 0;
|
||||||
static mp_code_t *unique_codes = NULL;
|
static mp_code_t *unique_codes = NULL;
|
||||||
|
|
||||||
@ -187,30 +190,30 @@ void rt_deinit(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int rt_get_unique_code_id(void) {
|
uint rt_get_unique_code_id(void) {
|
||||||
return next_unique_code_id++;
|
return next_unique_code_id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alloc_unique_codes(void) {
|
static void alloc_unique_codes(void) {
|
||||||
if (next_unique_code_id > unique_codes_alloc) {
|
if (next_unique_code_id > unique_codes_alloc) {
|
||||||
|
DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id);
|
||||||
// increase size of unique_codes table
|
// increase size of unique_codes table
|
||||||
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, next_unique_code_id);
|
||||||
for (int i = unique_codes_alloc; i < next_unique_code_id; i++) {
|
for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) {
|
||||||
unique_codes[i].kind = MP_CODE_NONE;
|
unique_codes[i].kind = MP_CODE_NONE;
|
||||||
}
|
}
|
||||||
unique_codes_alloc = next_unique_code_id;
|
unique_codes_alloc = next_unique_code_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) {
|
void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) {
|
||||||
alloc_unique_codes();
|
alloc_unique_codes();
|
||||||
|
|
||||||
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
||||||
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
|
unique_codes[unique_code_id].kind = MP_CODE_BYTE;
|
||||||
unique_codes[unique_code_id].n_args = n_args;
|
|
||||||
unique_codes[unique_code_id].n_locals = n_locals;
|
|
||||||
unique_codes[unique_code_id].n_stack = n_stack;
|
|
||||||
unique_codes[unique_code_id].is_generator = is_generator;
|
unique_codes[unique_code_id].is_generator = is_generator;
|
||||||
|
unique_codes[unique_code_id].n_args = n_args;
|
||||||
|
unique_codes[unique_code_id].n_state = n_locals + n_stack;
|
||||||
unique_codes[unique_code_id].u_byte.code = code;
|
unique_codes[unique_code_id].u_byte.code = code;
|
||||||
unique_codes[unique_code_id].u_byte.len = len;
|
unique_codes[unique_code_id].u_byte.len = len;
|
||||||
|
|
||||||
@ -238,15 +241,14 @@ void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, i
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args) {
|
void rt_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
|
||||||
alloc_unique_codes();
|
alloc_unique_codes();
|
||||||
|
|
||||||
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
||||||
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
|
unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
|
||||||
unique_codes[unique_code_id].n_args = n_args;
|
|
||||||
unique_codes[unique_code_id].n_locals = 0;
|
|
||||||
unique_codes[unique_code_id].n_stack = 0;
|
|
||||||
unique_codes[unique_code_id].is_generator = false;
|
unique_codes[unique_code_id].is_generator = false;
|
||||||
|
unique_codes[unique_code_id].n_args = n_args;
|
||||||
|
unique_codes[unique_code_id].n_state = 0;
|
||||||
unique_codes[unique_code_id].u_native.fun = fun;
|
unique_codes[unique_code_id].u_native.fun = fun;
|
||||||
|
|
||||||
//printf("native code: %d bytes\n", len);
|
//printf("native code: %d bytes\n", len);
|
||||||
@ -271,15 +273,14 @@ void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_args) {
|
void rt_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
|
||||||
alloc_unique_codes();
|
alloc_unique_codes();
|
||||||
|
|
||||||
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
|
||||||
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].n_args = n_args;
|
|
||||||
unique_codes[unique_code_id].n_locals = 0;
|
|
||||||
unique_codes[unique_code_id].n_stack = 0;
|
|
||||||
unique_codes[unique_code_id].is_generator = false;
|
unique_codes[unique_code_id].is_generator = false;
|
||||||
|
unique_codes[unique_code_id].n_args = n_args;
|
||||||
|
unique_codes[unique_code_id].n_state = 0;
|
||||||
unique_codes[unique_code_id].u_inline_asm.fun = fun;
|
unique_codes[unique_code_id].u_inline_asm.fun = fun;
|
||||||
|
|
||||||
#ifdef DEBUG_PRINT
|
#ifdef DEBUG_PRINT
|
||||||
@ -678,7 +679,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
|
|||||||
mp_obj_t fun;
|
mp_obj_t fun;
|
||||||
switch (c->kind) {
|
switch (c->kind) {
|
||||||
case MP_CODE_BYTE:
|
case MP_CODE_BYTE:
|
||||||
fun = mp_obj_new_fun_bc(c->n_args, c->n_locals + c->n_stack, c->u_byte.code);
|
fun = mp_obj_new_fun_bc(c->n_args, c->n_state, c->u_byte.code);
|
||||||
break;
|
break;
|
||||||
case MP_CODE_NATIVE:
|
case MP_CODE_NATIVE:
|
||||||
fun = rt_make_function_n(c->n_args, c->u_native.fun);
|
fun = rt_make_function_n(c->n_args, c->u_native.fun);
|
||||||
@ -693,7 +694,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) {
|
|||||||
|
|
||||||
// check for generator functions and if so wrap in generator object
|
// check for generator functions and if so wrap in generator object
|
||||||
if (c->is_generator) {
|
if (c->is_generator) {
|
||||||
fun = mp_obj_new_gen_wrap(c->n_locals, c->n_stack, fun);
|
fun = mp_obj_new_gen_wrap(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fun;
|
return fun;
|
||||||
|
@ -78,7 +78,7 @@ extern void *const rt_fun_table[RT_F_NUMBER_OF];
|
|||||||
|
|
||||||
void rt_init(void);
|
void rt_init(void);
|
||||||
void rt_deinit(void);
|
void rt_deinit(void);
|
||||||
int rt_get_unique_code_id(void);
|
uint rt_get_unique_code_id(void);
|
||||||
void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator);
|
void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator);
|
||||||
void rt_assign_native_code(int unique_code_id, void *f, uint len, int n_args);
|
void rt_assign_native_code(uint unique_code_id, void *f, uint len, int n_args);
|
||||||
void rt_assign_inline_asm_code(int unique_code_id, void *f, uint len, int n_args);
|
void rt_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args);
|
||||||
|
40
py/vm.c
40
py/vm.c
@ -80,7 +80,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
machine_uint_t unum;
|
machine_uint_t unum;
|
||||||
qstr qst;
|
qstr qst;
|
||||||
mp_obj_t obj1, obj2;
|
mp_obj_t obj1, obj2;
|
||||||
mp_obj_t fast0 = fastn[0], fast1 = fastn[-1], fast2 = fastn[-2];
|
|
||||||
nlr_buf_t nlr;
|
nlr_buf_t nlr;
|
||||||
|
|
||||||
volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions
|
volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions
|
||||||
@ -88,8 +87,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
machine_uint_t *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack
|
machine_uint_t *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack
|
||||||
const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
|
const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
|
||||||
|
|
||||||
// TODO if an exception occurs, do fast[0,1,2] become invalid??
|
|
||||||
|
|
||||||
// outer exception handling loop
|
// outer exception handling loop
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (nlr_push(&nlr) == 0) {
|
if (nlr_push(&nlr) == 0) {
|
||||||
@ -146,15 +143,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_FAST_0:
|
case MP_BC_LOAD_FAST_0:
|
||||||
PUSH(fast0);
|
PUSH(fastn[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_FAST_1:
|
case MP_BC_LOAD_FAST_1:
|
||||||
PUSH(fast1);
|
PUSH(fastn[-1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_FAST_2:
|
case MP_BC_LOAD_FAST_2:
|
||||||
PUSH(fast2);
|
PUSH(fastn[-2]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_FAST_N:
|
case MP_BC_LOAD_FAST_N:
|
||||||
@ -164,16 +161,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
|
|
||||||
case MP_BC_LOAD_DEREF:
|
case MP_BC_LOAD_DEREF:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
if (unum == 0) {
|
PUSH(rt_get_cell(fastn[-unum]));
|
||||||
obj1 = fast0;
|
|
||||||
} else if (unum == 1) {
|
|
||||||
obj1 = fast1;
|
|
||||||
} else if (unum == 2) {
|
|
||||||
obj1 = fast2;
|
|
||||||
} else {
|
|
||||||
obj1 = fastn[-unum];
|
|
||||||
}
|
|
||||||
PUSH(rt_get_cell(obj1));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_LOAD_NAME:
|
case MP_BC_LOAD_NAME:
|
||||||
@ -202,15 +190,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_STORE_FAST_0:
|
case MP_BC_STORE_FAST_0:
|
||||||
fast0 = POP();
|
fastn[0] = POP();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_STORE_FAST_1:
|
case MP_BC_STORE_FAST_1:
|
||||||
fast1 = POP();
|
fastn[-1] = POP();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_STORE_FAST_2:
|
case MP_BC_STORE_FAST_2:
|
||||||
fast2 = POP();
|
fastn[-2] = POP();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_STORE_FAST_N:
|
case MP_BC_STORE_FAST_N:
|
||||||
@ -220,16 +208,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
|
|
||||||
case MP_BC_STORE_DEREF:
|
case MP_BC_STORE_DEREF:
|
||||||
DECODE_UINT;
|
DECODE_UINT;
|
||||||
if (unum == 0) {
|
rt_set_cell(fastn[-unum], POP());
|
||||||
obj1 = fast0;
|
|
||||||
} else if (unum == 1) {
|
|
||||||
obj1 = fast1;
|
|
||||||
} else if (unum == 2) {
|
|
||||||
obj1 = fast2;
|
|
||||||
} else {
|
|
||||||
obj1 = fastn[-unum];
|
|
||||||
}
|
|
||||||
rt_set_cell(obj1, POP());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_BC_STORE_NAME:
|
case MP_BC_STORE_NAME:
|
||||||
@ -511,9 +490,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob
|
|||||||
case MP_BC_YIELD_VALUE:
|
case MP_BC_YIELD_VALUE:
|
||||||
nlr_pop();
|
nlr_pop();
|
||||||
*ip_in_out = ip;
|
*ip_in_out = ip;
|
||||||
fastn[0] = fast0;
|
|
||||||
fastn[-1] = fast1;
|
|
||||||
fastn[-2] = fast2;
|
|
||||||
*sp_in_out = sp;
|
*sp_in_out = sp;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user