Skip to content

Commit 9988618

Browse files
committed
py: Implement full func arg passing for native emitter.
This patch gets full function argument passing working with native emitter. Includes named args, keyword args, default args, var args and var keyword args. Fully Python compliant. It reuses the bytecode mp_setup_code_state function to do all the hard work. This function is slightly adjusted to accommodate native calls, and the native emitter is forced a bit to emit similar prelude and code-info as bytecode.
1 parent 18bd517 commit 9988618

17 files changed

Lines changed: 307 additions & 235 deletions

py/asmthumb.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ STATIC byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int num_bytes_to_
106106
}
107107
}
108108

109+
uint asm_thumb_get_code_pos(asm_thumb_t *as) {
110+
return as->code_offset;
111+
}
112+
109113
uint asm_thumb_get_code_size(asm_thumb_t *as) {
110114
return as->code_size;
111115
}

py/asmthumb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ asm_thumb_t *asm_thumb_new(uint max_num_labels);
7070
void asm_thumb_free(asm_thumb_t *as, bool free_code);
7171
void asm_thumb_start_pass(asm_thumb_t *as, uint pass);
7272
void asm_thumb_end_pass(asm_thumb_t *as);
73+
uint asm_thumb_get_code_pos(asm_thumb_t *as);
7374
uint asm_thumb_get_code_size(asm_thumb_t *as);
7475
void *asm_thumb_get_code(asm_thumb_t *as);
7576

py/asmx64.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ STATIC byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int num_bytes_to_writ
176176
}
177177
}
178178

179+
mp_uint_t asm_x64_get_code_pos(asm_x64_t *as) {
180+
return as->code_offset;
181+
}
182+
179183
mp_uint_t asm_x64_get_code_size(asm_x64_t *as) {
180184
return as->code_size;
181185
}
@@ -222,6 +226,21 @@ STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) {
222226
c[7] = IMM64_L7(w64);
223227
}
224228

229+
// align must be a multiple of 2
230+
void asm_x64_align(asm_x64_t* as, mp_uint_t align) {
231+
// TODO fill unused data with NOPs?
232+
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
233+
}
234+
235+
void asm_x64_data(asm_x64_t* as, mp_uint_t bytesize, mp_uint_t val) {
236+
byte *c = asm_x64_get_cur_to_write_bytes(as, bytesize);
237+
// machine is little endian
238+
for (uint i = 0; i < bytesize; i++) {
239+
*c++ = val;
240+
val >>= 8;
241+
}
242+
}
243+
225244
/* unused
226245
STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) {
227246
byte* c;

py/asmx64.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,13 @@ asm_x64_t* asm_x64_new(mp_uint_t max_num_labels);
7878
void asm_x64_free(asm_x64_t* as, bool free_code);
7979
void asm_x64_start_pass(asm_x64_t *as, uint pass);
8080
void asm_x64_end_pass(asm_x64_t *as);
81+
mp_uint_t asm_x64_get_code_pos(asm_x64_t *as);
8182
mp_uint_t asm_x64_get_code_size(asm_x64_t* as);
8283
void* asm_x64_get_code(asm_x64_t* as);
8384

85+
void asm_x64_align(asm_x64_t *as, mp_uint_t align);
86+
void asm_x64_data(asm_x64_t *as, mp_uint_t bytesize, mp_uint_t val);
87+
8488
void asm_x64_nop(asm_x64_t* as);
8589
void asm_x64_push_r64(asm_x64_t* as, int src_r64);
8690
void asm_x64_pop_r64(asm_x64_t* as, int dest_r64);

py/asmx86.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ STATIC byte *asm_x86_get_cur_to_write_bytes(asm_x86_t *as, int num_bytes_to_writ
162162
}
163163
}
164164

165+
mp_uint_t asm_x86_get_code_pos(asm_x86_t *as) {
166+
return as->code_offset;
167+
}
168+
165169
mp_uint_t asm_x86_get_code_size(asm_x86_t *as) {
166170
return as->code_size;
167171
}
@@ -196,6 +200,21 @@ STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {
196200
c[3] = IMM32_L3(w32);
197201
}
198202

203+
// align must be a multiple of 2
204+
void asm_x86_align(asm_x86_t* as, mp_uint_t align) {
205+
// TODO fill unused data with NOPs?
206+
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
207+
}
208+
209+
void asm_x86_data(asm_x86_t* as, mp_uint_t bytesize, mp_uint_t val) {
210+
byte *c = asm_x86_get_cur_to_write_bytes(as, bytesize);
211+
// machine is little endian
212+
for (uint i = 0; i < bytesize; i++) {
213+
*c++ = val;
214+
val >>= 8;
215+
}
216+
}
217+
199218
STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) {
200219
assert(disp_r32 != ASM_X86_REG_ESP);
201220

@@ -541,7 +560,13 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32)
541560

542561
void asm_x86_call_ind(asm_x86_t *as, void *ptr, mp_uint_t n_args, int temp_r32) {
543562
// TODO align stack on 16-byte boundary before the call
544-
assert(n_args <= 3);
563+
assert(n_args <= 5);
564+
if (n_args > 4) {
565+
asm_x86_push_r32(as, ASM_X86_REG_ARG_5);
566+
}
567+
if (n_args > 3) {
568+
asm_x86_push_r32(as, ASM_X86_REG_ARG_4);
569+
}
545570
if (n_args > 2) {
546571
asm_x86_push_r32(as, ASM_X86_REG_ARG_3);
547572
}

py/asmx86.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
#define ASM_X86_REG_ARG_1 ASM_X86_REG_EAX
6262
#define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX
6363
#define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX
64+
#define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX
65+
#define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI
6466

6567
// condition codes, used for jcc and setcc (despite their j-name!)
6668
#define ASM_X86_CC_JB (0x2) // below, unsigned
@@ -79,9 +81,13 @@ asm_x86_t* asm_x86_new(mp_uint_t max_num_labels);
7981
void asm_x86_free(asm_x86_t* as, bool free_code);
8082
void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass);
8183
void asm_x86_end_pass(asm_x86_t *as);
84+
mp_uint_t asm_x86_get_code_pos(asm_x86_t *as);
8285
mp_uint_t asm_x86_get_code_size(asm_x86_t* as);
8386
void* asm_x86_get_code(asm_x86_t* as);
8487

88+
void asm_x86_align(asm_x86_t *as, mp_uint_t align);
89+
void asm_x86_data(asm_x86_t *as, mp_uint_t bytesize, mp_uint_t val);
90+
8591
void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
8692
void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);
8793
void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32);

py/bc.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,13 @@ STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
7878
#define dump_args(...) (void)0
7979
#endif
8080

81-
// code_state should have ->ip filled in (pointing past code info block),
82-
// as well as ->n_state.
81+
// On entry code_state should be allocated somewhere (stack/heap) and
82+
// contain the following valid entries:
83+
// - code_state->code_info should be the offset in bytes from the start of
84+
// the bytecode chunk to the start of the code-info within the bytecode
85+
// - code_state->ip should contain the offset in bytes from the start of
86+
// the bytecode chunk to the start of the prelude within the bytecode
87+
// - code_state->n_state should be set to the state size (locals plus stack)
8388
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
8489
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
8590
// usage for the common case of positional only args.
@@ -89,7 +94,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
8994
#if MICROPY_STACKLESS
9095
code_state->prev = NULL;
9196
#endif
92-
code_state->code_info = self->bytecode;
97+
code_state->code_info = self->bytecode + (mp_uint_t)code_state->code_info;
9398
code_state->sp = &code_state->state[0] - 1;
9499
code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
95100

@@ -227,7 +232,7 @@ continue2:;
227232
}
228233

229234
// bytecode prelude: initialise closed over variables
230-
const byte *ip = code_state->ip;
235+
const byte *ip = self->bytecode + (mp_uint_t)code_state->ip;
231236
mp_uint_t local_num;
232237
while ((local_num = *ip++) != 255) {
233238
code_state->state[n_state - 1 - local_num] =

py/emitglue.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len,
8686
}
8787

8888
#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
89-
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) {
89+
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags, mp_uint_t type_sig) {
9090
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
9191
rc->kind = kind;
92-
rc->scope_flags = 0;
93-
rc->n_pos_args = n_args;
92+
rc->scope_flags = scope_flags;
93+
rc->n_pos_args = n_pos_args;
94+
rc->n_kwonly_args = n_kwonly_args;
9495
rc->data.u_native.fun_data = fun_data;
9596
rc->data.u_native.type_sig = type_sig;
9697

9798
#ifdef DEBUG_PRINT
98-
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
99+
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, n_kwonly_args, (uint)scope_flags);
99100
for (mp_uint_t i = 0; i < fun_len; i++) {
100101
if (i > 0 && i % 16 == 0) {
101102
DEBUG_printf("\n");
@@ -134,7 +135,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
134135
break;
135136
#if MICROPY_EMIT_NATIVE
136137
case MP_CODE_NATIVE_PY:
137-
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->data.u_native.fun_data);
138+
fun = mp_obj_new_fun_native(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->data.u_native.fun_data);
138139
break;
139140
case MP_CODE_NATIVE_VIPER:
140141
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig);

py/emitglue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ typedef struct _mp_raw_code_t mp_raw_code_t;
4444
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
4545

4646
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags);
47-
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
47+
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags, mp_uint_t type_sig);
4848

4949
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
5050
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);

py/emitinlinethumb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
9090

9191
if (emit->pass == MP_PASS_EMIT) {
9292
void *f = asm_thumb_get_code(emit->as);
93-
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
93+
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0, 0, 0);
9494
}
9595
}
9696

0 commit comments

Comments
 (0)