Skip to content

Commit b601d95

Browse files
committed
py: Improvements to native emitter.
Native emitter can now compile try/except blocks using nlr_push/nlr_pop. It probably only works for 1 level of exception handling. It doesn't work on Thumb (only x64). Native emitter can also handle some additional op codes. With this patch, 198 tests now pass using "-X emit=native" option to micropython.
1 parent 5813efd commit b601d95

6 files changed

Lines changed: 121 additions & 24 deletions

File tree

py/compile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,7 +1894,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
18941894
EMIT_ARG(jump, success_label); // jump over exception handler
18951895

18961896
EMIT_ARG(label_assign, l1); // start of exception handler
1897-
EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
1897+
EMIT(start_except_handler);
18981898

18991899
uint l2 = comp_next_label(comp);
19001900

@@ -1966,7 +1966,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
19661966

19671967
compile_decrease_except_level(comp);
19681968
EMIT(end_finally);
1969-
EMIT_ARG(adjust_stack_size, -5); // stack adjust
1969+
EMIT(end_except_handler);
19701970

19711971
EMIT_ARG(label_assign, success_label);
19721972
compile_node(comp, pn_else); // else block, can be null

py/emit.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ typedef struct _emit_method_table_t {
134134
void (*yield_value)(emit_t *emit);
135135
void (*yield_from)(emit_t *emit);
136136

137+
// these methods are used to control entry to/exit from an exception handler
138+
// they may or may not emit code
139+
void (*start_except_handler)(emit_t *emit);
140+
void (*end_except_handler)(emit_t *emit);
141+
137142
#if MICROPY_EMIT_CPYTHON
138143
// these methods are only needed for emitcpy
139144
void (*load_const_verbatim_str)(emit_t *emit, const char *str);

py/emitbc.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,14 @@ STATIC void emit_bc_yield_from(emit_t *emit) {
849849
emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM);
850850
}
851851

852+
STATIC void emit_bc_start_except_handler(emit_t *emit) {
853+
emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
854+
}
855+
856+
STATIC void emit_bc_end_except_handler(emit_t *emit) {
857+
emit_bc_adjust_stack_size(emit, -5); // stack adjust
858+
}
859+
852860
const emit_method_table_t emit_bc_method_table = {
853861
emit_bc_set_native_types,
854862
emit_bc_start_pass,
@@ -934,6 +942,9 @@ const emit_method_table_t emit_bc_method_table = {
934942
emit_bc_raise_varargs,
935943
emit_bc_yield_value,
936944
emit_bc_yield_from,
945+
946+
emit_bc_start_except_handler,
947+
emit_bc_end_except_handler,
937948
};
938949

939950
#endif // !MICROPY_EMIT_CPYTHON

py/emitcpy.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,14 @@ STATIC void emit_cpy_yield_from(emit_t *emit) {
792792
}
793793
}
794794

795+
STATIC void emit_cpy_start_except_handler(emit_t *emit) {
796+
emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items
797+
}
798+
799+
STATIC void emit_cpy_end_except_handler(emit_t *emit) {
800+
emit_cpy_adjust_stack_size(emit, -5); // stack adjust
801+
}
802+
795803
STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
796804
emit_pre(emit, 1, 3);
797805
if (emit->pass == MP_PASS_EMIT) {
@@ -899,6 +907,9 @@ const emit_method_table_t emit_cpython_method_table = {
899907
emit_cpy_yield_value,
900908
emit_cpy_yield_from,
901909

910+
emit_cpy_start_except_handler,
911+
emit_cpy_end_except_handler,
912+
902913
// emitcpy specific functions
903914
emit_cpy_load_const_verbatim_str,
904915
emit_cpy_load_closure,

py/emitnative.c

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <assert.h>
5050

5151
#include "mpconfig.h"
52+
#include "nlr.h"
5253
#include "misc.h"
5354
#include "qstr.h"
5455
#include "lexer.h"
@@ -723,7 +724,11 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
723724
assert(0);
724725
emit_post_push_imm(emit, VTYPE_PTR, (machine_uint_t)qstr_str(qstr));
725726
} else {
726-
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, mp_load_const_str, qstr, REG_ARG_1);
727+
if (bytes) {
728+
emit_call_with_imm_arg(emit, 0, mp_load_const_bytes, qstr, REG_ARG_1); // TODO need to add function to runtime table
729+
} else {
730+
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, mp_load_const_str, qstr, REG_ARG_1);
731+
}
727732
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
728733
}
729734
}
@@ -1057,17 +1062,33 @@ STATIC void emit_native_setup_with(emit_t *emit, uint label) {
10571062
// not supported, or could be with runtime call
10581063
assert(0);
10591064
}
1065+
10601066
STATIC void emit_native_with_cleanup(emit_t *emit) {
10611067
assert(0);
10621068
}
1069+
10631070
STATIC void emit_native_setup_except(emit_t *emit, uint label) {
1064-
assert(0);
1071+
emit_native_pre(emit);
1072+
// need to commit stack because we may jump elsewhere
1073+
need_stack_settled(emit);
1074+
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(machine_uint_t)); // arg1 = pointer to nlr buf
1075+
emit_call(emit, 0, nlr_push); // TODO need to add function to runtime table
1076+
#if N_X64
1077+
asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
1078+
asm_x64_jcc_label(emit->as, JCC_JNZ, label);
1079+
#elif N_THUMB
1080+
asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0);
1081+
asm_thumb_bcc_label(emit->as, THUMB_CC_NE, label);
1082+
#endif
1083+
emit_post(emit);
10651084
}
1085+
10661086
STATIC void emit_native_setup_finally(emit_t *emit, uint label) {
10671087
assert(0);
10681088
}
1089+
10691090
STATIC void emit_native_end_finally(emit_t *emit) {
1070-
assert(0);
1091+
//assert(0);
10711092
}
10721093

10731094
STATIC void emit_native_get_iter(emit_t *emit) {
@@ -1107,19 +1128,31 @@ STATIC void emit_native_for_iter_end(emit_t *emit) {
11071128

11081129
STATIC void emit_native_pop_block(emit_t *emit) {
11091130
emit_native_pre(emit);
1131+
emit_call(emit, 0, nlr_pop); // TODO need to add function to runtime table
1132+
adjust_stack(emit, -(machine_int_t)(sizeof(nlr_buf_t) / sizeof(machine_uint_t)));
11101133
emit_post(emit);
11111134
}
11121135

11131136
STATIC void emit_native_pop_except(emit_t *emit) {
1114-
assert(0);
1137+
/*
1138+
emit_native_pre(emit);
1139+
emit_call(emit, 0, nlr_pop); // TODO need to add function to runtime table
1140+
adjust_stack(emit, -(machine_int_t)(sizeof(nlr_buf_t) / sizeof(machine_uint_t)));
1141+
emit_post(emit);
1142+
*/
11151143
}
11161144

11171145
STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
1118-
vtype_kind_t vtype;
1119-
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1120-
assert(vtype == VTYPE_PYOBJ);
1121-
emit_call_with_imm_arg(emit, MP_F_UNARY_OP, mp_unary_op, op, REG_ARG_1);
1122-
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1146+
if (op == MP_UNARY_OP_NOT) {
1147+
// we need to synthesise this operation
1148+
assert(0);
1149+
} else {
1150+
vtype_kind_t vtype;
1151+
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1152+
assert(vtype == VTYPE_PYOBJ);
1153+
emit_call_with_imm_arg(emit, MP_F_UNARY_OP, mp_unary_op, op, REG_ARG_1);
1154+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1155+
}
11231156
}
11241157

11251158
STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
@@ -1233,17 +1266,26 @@ STATIC void emit_native_set_add(emit_t *emit, int set_index) {
12331266

12341267
STATIC void emit_native_build_slice(emit_t *emit, int n_args) {
12351268
DEBUG_printf("build_slice %d\n", n_args);
1236-
assert(n_args == 2);
1237-
vtype_kind_t vtype_start, vtype_stop;
1238-
emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
1239-
assert(vtype_start == VTYPE_PYOBJ);
1240-
assert(vtype_stop == VTYPE_PYOBJ);
1241-
emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg3 = step
1242-
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1269+
if (n_args == 2) {
1270+
vtype_kind_t vtype_start, vtype_stop;
1271+
emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
1272+
assert(vtype_start == VTYPE_PYOBJ);
1273+
assert(vtype_stop == VTYPE_PYOBJ);
1274+
emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (machine_uint_t)mp_const_none, REG_ARG_3); // arg3 = step
1275+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1276+
} else {
1277+
assert(n_args == 3);
1278+
vtype_kind_t vtype_start, vtype_stop, vtype_step;
1279+
emit_pre_pop_reg_reg_reg(emit, &vtype_step, REG_ARG_3, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop, arg3 = step
1280+
assert(vtype_start == VTYPE_PYOBJ);
1281+
assert(vtype_stop == VTYPE_PYOBJ);
1282+
assert(vtype_step == VTYPE_PYOBJ);
1283+
emit_call(emit, MP_F_NEW_SLICE, mp_obj_new_slice);
1284+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1285+
}
12431286
}
12441287

12451288
STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) {
1246-
// TODO this is untested
12471289
DEBUG_printf("unpack_sequence %d\n", n_args);
12481290
vtype_kind_t vtype_base;
12491291
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
@@ -1253,13 +1295,12 @@ STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) {
12531295
}
12541296

12551297
STATIC void emit_native_unpack_ex(emit_t *emit, int n_left, int n_right) {
1256-
// TODO this is untested
12571298
DEBUG_printf("unpack_ex %d %d\n", n_left, n_right);
12581299
vtype_kind_t vtype_base;
12591300
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
12601301
assert(vtype_base == VTYPE_PYOBJ);
1261-
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right); // arg3 = dest ptr
1262-
emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left + n_right, REG_ARG_2); // arg2 = n_left + n_right
1302+
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr
1303+
emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right
12631304
}
12641305

12651306
STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
@@ -1368,9 +1409,16 @@ STATIC void emit_native_return_value(emit_t *emit) {
13681409
}
13691410

13701411
STATIC void emit_native_raise_varargs(emit_t *emit, int n_args) {
1371-
// call runtime
1372-
assert(0);
1412+
assert(n_args == 1);
1413+
vtype_kind_t vtype_err;
1414+
emit_pre_pop_reg(emit, &vtype_err, REG_ARG_1); // arg1 = object to raise
1415+
assert(vtype_err == VTYPE_PYOBJ);
1416+
emit_call(emit, 0, mp_make_raise_obj); // TODO need to add function to runtime table
1417+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1418+
emit_pre_pop_reg(emit, &vtype_err, REG_ARG_1);
1419+
emit_call(emit, 0, nlr_jump); // TODO need to add function to runtime table
13731420
}
1421+
13741422
STATIC void emit_native_yield_value(emit_t *emit) {
13751423
// not supported (for now)
13761424
assert(0);
@@ -1380,6 +1428,21 @@ STATIC void emit_native_yield_from(emit_t *emit) {
13801428
assert(0);
13811429
}
13821430

1431+
STATIC void emit_native_start_except_handler(emit_t *emit) {
1432+
// This instruction follows an nlr_pop, so the stack counter is back to zero, when really
1433+
// it should be up by a whole nlr_buf_t. We then want to pop the nlr_buf_t here, but save
1434+
// the first 2 elements, so we can get the thrown value.
1435+
adjust_stack(emit, 2);
1436+
vtype_kind_t vtype_nlr;
1437+
emit_pre_pop_reg(emit, &vtype_nlr, REG_ARG_1); // get the thrown value
1438+
emit_pre_pop_discard(emit, &vtype_nlr); // discard the linked-list pointer in the nlr_buf
1439+
emit_post_push_reg_reg_reg(emit, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1); // push the 3 exception items
1440+
}
1441+
1442+
STATIC void emit_native_end_except_handler(emit_t *emit) {
1443+
adjust_stack(emit, -3); // stack adjust (not sure why it's this much...)
1444+
}
1445+
13831446
const emit_method_table_t EXPORT_FUN(method_table) = {
13841447
emit_native_set_viper_types,
13851448
emit_native_start_pass,
@@ -1465,6 +1528,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
14651528
emit_native_raise_varargs,
14661529
emit_native_yield_value,
14671530
emit_native_yield_from,
1531+
1532+
emit_native_start_except_handler,
1533+
emit_native_end_except_handler,
14681534
};
14691535

14701536
#endif // (MICROPY_EMIT_X64 && N_X64) || (MICROPY_EMIT_THUMB && N_THUMB)

py/emitpass1.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ const emit_method_table_t emit_pass1_method_table = {
214214
(void*)emit_pass1_dummy,
215215
(void*)emit_pass1_dummy,
216216
(void*)emit_pass1_dummy,
217+
218+
(void*)emit_pass1_dummy,
219+
(void*)emit_pass1_dummy,
220+
217221
#if MICROPY_EMIT_CPYTHON
218222
(void*)emit_pass1_dummy,
219223
(void*)emit_pass1_dummy,

0 commit comments

Comments
 (0)