Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : // Essentially normal Python has 1 type: Python objects
28 : : // Viper has more than 1 type, and is just a more complicated (a superset of) Python.
29 : : // If you declare everything in Viper as a Python object (ie omit type decls) then
30 : : // it should in principle be exactly the same as Python native.
31 : : // Having types means having more opcodes, like binary_op_nat_nat, binary_op_nat_obj etc.
32 : : // In practice we won't have a VM but rather do this in asm which is actually very minimal.
33 : :
34 : : // Because it breaks strict Python equivalence it should be a completely separate
35 : : // decorator. It breaks equivalence because overflow on integers wraps around.
36 : : // It shouldn't break equivalence if you don't use the new types, but since the
37 : : // type decls might be used in normal Python for other reasons, it's probably safest,
38 : : // cleanest and clearest to make it a separate decorator.
39 : :
40 : : // Actually, it does break equivalence because integers default to native integers,
41 : : // not Python objects.
42 : :
43 : : // for x in l[0:8]: can be compiled into a native loop if l has pointer type
44 : :
45 : : #include <stdio.h>
46 : : #include <string.h>
47 : : #include <assert.h>
48 : :
49 : : #include "py/emit.h"
50 : : #include "py/nativeglue.h"
51 : : #include "py/objfun.h"
52 : : #include "py/objstr.h"
53 : :
54 : : #if MICROPY_DEBUG_VERBOSE // print debugging info
55 : : #define DEBUG_PRINT (1)
56 : : #define DEBUG_printf DEBUG_printf
57 : : #else // don't print debugging info
58 : : #define DEBUG_printf(...) (void)0
59 : : #endif
60 : :
61 : : // wrapper around everything in this file
62 : : #if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN || N_RV32 || N_DEBUG
63 : :
64 : : // C stack layout for native functions:
65 : : // 0: nlr_buf_t [optional]
66 : : // return_value [optional word]
67 : : // exc_handler_unwind [optional word]
68 : : // emit->code_state_start: mp_code_state_native_t
69 : : // emit->stack_start: Python object stack | emit->n_state
70 : : // locals (reversed, L0 at end) |
71 : : //
72 : : // C stack layout for native generator functions:
73 : : // 0=emit->stack_start: nlr_buf_t
74 : : // return_value
75 : : // exc_handler_unwind [optional word]
76 : : //
77 : : // Then REG_GENERATOR_STATE points to:
78 : : // 0=emit->code_state_start: mp_code_state_native_t
79 : : // emit->stack_start: Python object stack | emit->n_state
80 : : // locals (reversed, L0 at end) |
81 : : //
82 : : // C stack layout for viper functions:
83 : : // 0: nlr_buf_t [optional]
84 : : // return_value [optional word]
85 : : // exc_handler_unwind [optional word]
86 : : // emit->code_state_start: fun_obj, old_globals [optional]
87 : : // emit->stack_start: Python object stack | emit->n_state
88 : : // locals (reversed, L0 at end) |
89 : : // (L0-L2 may be in regs instead)
90 : :
91 : : // Native emitter needs to know the following sizes and offsets of C structs (on the target):
92 : : #if MICROPY_DYNAMIC_COMPILER
93 : : #define SIZEOF_NLR_BUF (2 + mp_dynamic_compiler.nlr_buf_num_regs + 1) // the +1 is conservative in case MICROPY_ENABLE_PYSTACK enabled
94 : : #else
95 : : #define SIZEOF_NLR_BUF (sizeof(nlr_buf_t) / sizeof(uintptr_t))
96 : : #endif
97 : : #define SIZEOF_CODE_STATE (sizeof(mp_code_state_native_t) / sizeof(uintptr_t))
98 : : #define OFFSETOF_CODE_STATE_STATE (offsetof(mp_code_state_native_t, state) / sizeof(uintptr_t))
99 : : #define OFFSETOF_CODE_STATE_FUN_BC (offsetof(mp_code_state_native_t, fun_bc) / sizeof(uintptr_t))
100 : : #define OFFSETOF_CODE_STATE_IP (offsetof(mp_code_state_native_t, ip) / sizeof(uintptr_t))
101 : : #define OFFSETOF_CODE_STATE_SP (offsetof(mp_code_state_native_t, sp) / sizeof(uintptr_t))
102 : : #define OFFSETOF_CODE_STATE_N_STATE (offsetof(mp_code_state_native_t, n_state) / sizeof(uintptr_t))
103 : : #define OFFSETOF_OBJ_FUN_BC_CONTEXT (offsetof(mp_obj_fun_bc_t, context) / sizeof(uintptr_t))
104 : : #define OFFSETOF_OBJ_FUN_BC_CHILD_TABLE (offsetof(mp_obj_fun_bc_t, child_table) / sizeof(uintptr_t))
105 : : #define OFFSETOF_OBJ_FUN_BC_BYTECODE (offsetof(mp_obj_fun_bc_t, bytecode) / sizeof(uintptr_t))
106 : : #define OFFSETOF_MODULE_CONTEXT_QSTR_TABLE (offsetof(mp_module_context_t, constants.qstr_table) / sizeof(uintptr_t))
107 : : #define OFFSETOF_MODULE_CONTEXT_OBJ_TABLE (offsetof(mp_module_context_t, constants.obj_table) / sizeof(uintptr_t))
108 : : #define OFFSETOF_MODULE_CONTEXT_GLOBALS (offsetof(mp_module_context_t, module.globals) / sizeof(uintptr_t))
109 : :
110 : : // If not already defined, set parent args to same as child call registers
111 : : #ifndef REG_PARENT_RET
112 : : #define REG_PARENT_RET REG_RET
113 : : #define REG_PARENT_ARG_1 REG_ARG_1
114 : : #define REG_PARENT_ARG_2 REG_ARG_2
115 : : #define REG_PARENT_ARG_3 REG_ARG_3
116 : : #define REG_PARENT_ARG_4 REG_ARG_4
117 : : #endif
118 : :
119 : : // Word index of nlr_buf_t.ret_val
120 : : #define NLR_BUF_IDX_RET_VAL (1)
121 : :
122 : : // Whether the viper function needs access to fun_obj
123 : : #define NEED_FUN_OBJ(emit) ((emit)->scope->exc_stack_size > 0 \
124 : : || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_REFGLOBALS | MP_SCOPE_FLAG_HASCONSTS)))
125 : :
126 : : // Whether the native/viper function needs to be wrapped in an exception handler
127 : : #define NEED_GLOBAL_EXC_HANDLER(emit) ((emit)->scope->exc_stack_size > 0 \
128 : : || ((emit)->scope->scope_flags & (MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_REFGLOBALS)))
129 : :
130 : : // Whether a slot is needed to store LOCAL_IDX_EXC_HANDLER_UNWIND
131 : : #define NEED_EXC_HANDLER_UNWIND(emit) ((emit)->scope->exc_stack_size > 0)
132 : : #define NEED_THROW_VAL(emit) ((emit)->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)
133 : :
134 : : // Whether registers can be used to store locals (only true if there are no
135 : : // exception handlers, because otherwise an nlr_jump will restore registers to
136 : : // their state at the start of the function and updates to locals will be lost)
137 : : #define CAN_USE_REGS_FOR_LOCALS(emit) ((emit)->scope->exc_stack_size == 0 && !(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR))
138 : :
139 : : // Indices within the local C stack for various variables
140 : : #define LOCAL_IDX_EXC_VAL(emit) (NLR_BUF_IDX_RET_VAL)
141 : : #define LOCAL_IDX_EXC_HANDLER_PC(emit) (NLR_BUF_IDX_LOCAL_1)
142 : : #define LOCAL_IDX_EXC_HANDLER_UNWIND(emit) (SIZEOF_NLR_BUF + 1) // this needs a dedicated variable outside nlr_buf_t
143 : : #define LOCAL_IDX_THROW_VAL(emit) (SIZEOF_NLR_BUF + 2) // needs a dedicated variable outside nlr_buf_t, following inject_exc in py/vm.c
144 : : #define LOCAL_IDX_RET_VAL(emit) (SIZEOF_NLR_BUF) // needed when NEED_GLOBAL_EXC_HANDLER is true
145 : : #define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_FUN_BC)
146 : : #define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP)
147 : : #define LOCAL_IDX_GEN_PC(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP)
148 : : #define LOCAL_IDX_LOCAL_VAR(emit, local_num) ((emit)->stack_start + (emit)->n_state - 1 - (local_num))
149 : :
150 : : #if MICROPY_PERSISTENT_CODE_SAVE
151 : :
152 : : // When building with the ability to save native code to .mpy files:
153 : : // - Qstrs are indirect via qstr_table, and REG_LOCAL_3 always points to qstr_table.
154 : : // - In a generator no registers are used to store locals, and REG_LOCAL_2 points to the generator state.
155 : : // - At most 2 registers hold local variables (see CAN_USE_REGS_FOR_LOCALS for when this is possible).
156 : :
157 : : #define REG_GENERATOR_STATE (REG_LOCAL_2)
158 : : #define REG_QSTR_TABLE (REG_LOCAL_3)
159 : : #define MAX_REGS_FOR_LOCAL_VARS (2)
160 : :
161 : : static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {REG_LOCAL_1, REG_LOCAL_2};
162 : :
163 : : #else
164 : :
165 : : // When building without the ability to save native code to .mpy files:
166 : : // - Qstrs values are written directly into the machine code.
167 : : // - In a generator no registers are used to store locals, and REG_LOCAL_3 points to the generator state.
168 : : // - At most 3 registers hold local variables (see CAN_USE_REGS_FOR_LOCALS for when this is possible).
169 : :
170 : : #define REG_GENERATOR_STATE (REG_LOCAL_3)
171 : : #define MAX_REGS_FOR_LOCAL_VARS (3)
172 : :
173 : : static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {REG_LOCAL_1, REG_LOCAL_2, REG_LOCAL_3};
174 : :
175 : : #endif
176 : :
177 : : #define REG_LOCAL_LAST (reg_local_table[MAX_REGS_FOR_LOCAL_VARS - 1])
178 : :
179 : : #define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \
180 : : *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \
181 : : } while (0)
182 : :
183 : : #if N_RV32
184 : : #define FIT_SIGNED(value, bits) \
185 : : ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \
186 : : (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1)))
187 : : #endif
188 : :
189 : : typedef enum {
190 : : STACK_VALUE,
191 : : STACK_REG,
192 : : STACK_IMM,
193 : : } stack_info_kind_t;
194 : :
195 : : // these enums must be distinct and the bottom 4 bits
196 : : // must correspond to the correct MP_NATIVE_TYPE_xxx value
197 : : typedef enum {
198 : : VTYPE_PYOBJ = 0x00 | MP_NATIVE_TYPE_OBJ,
199 : : VTYPE_BOOL = 0x00 | MP_NATIVE_TYPE_BOOL,
200 : : VTYPE_INT = 0x00 | MP_NATIVE_TYPE_INT,
201 : : VTYPE_UINT = 0x00 | MP_NATIVE_TYPE_UINT,
202 : : VTYPE_PTR = 0x00 | MP_NATIVE_TYPE_PTR,
203 : : VTYPE_PTR8 = 0x00 | MP_NATIVE_TYPE_PTR8,
204 : : VTYPE_PTR16 = 0x00 | MP_NATIVE_TYPE_PTR16,
205 : : VTYPE_PTR32 = 0x00 | MP_NATIVE_TYPE_PTR32,
206 : :
207 : : VTYPE_PTR_NONE = 0x50 | MP_NATIVE_TYPE_PTR,
208 : :
209 : : VTYPE_UNBOUND = 0x60 | MP_NATIVE_TYPE_OBJ,
210 : : VTYPE_BUILTIN_CAST = 0x70 | MP_NATIVE_TYPE_OBJ,
211 : : } vtype_kind_t;
212 : :
213 : 72 : static qstr vtype_to_qstr(vtype_kind_t vtype) {
214 [ - + - + : 72 : switch (vtype) {
- - + +
+ ]
215 : : case VTYPE_PYOBJ:
216 : : return MP_QSTR_object;
217 : 0 : case VTYPE_BOOL:
218 : 0 : return MP_QSTR_bool;
219 : 32 : case VTYPE_INT:
220 : 32 : return MP_QSTR_int;
221 : 0 : case VTYPE_UINT:
222 : 0 : return MP_QSTR_uint;
223 : 8 : case VTYPE_PTR:
224 : 8 : return MP_QSTR_ptr;
225 : 0 : case VTYPE_PTR8:
226 : 0 : return MP_QSTR_ptr8;
227 : 0 : case VTYPE_PTR16:
228 : 0 : return MP_QSTR_ptr16;
229 : 4 : case VTYPE_PTR32:
230 : 4 : return MP_QSTR_ptr32;
231 : 8 : case VTYPE_PTR_NONE:
232 : : default:
233 : 8 : return MP_QSTR_None;
234 : : }
235 : : }
236 : :
237 : : typedef struct _stack_info_t {
238 : : vtype_kind_t vtype;
239 : : stack_info_kind_t kind;
240 : : union {
241 : : int u_reg;
242 : : mp_int_t u_imm;
243 : : } data;
244 : : } stack_info_t;
245 : :
246 : : #define UNWIND_LABEL_UNUSED (0x7fff)
247 : : #define UNWIND_LABEL_DO_FINAL_UNWIND (0x7ffe)
248 : :
249 : : typedef struct _exc_stack_entry_t {
250 : : uint16_t label : 15;
251 : : uint16_t is_finally : 1;
252 : : uint16_t unwind_label : 15;
253 : : uint16_t is_active : 1;
254 : : } exc_stack_entry_t;
255 : :
256 : : struct _emit_t {
257 : : mp_emit_common_t *emit_common;
258 : : mp_obj_t *error_slot;
259 : : uint *label_slot;
260 : : uint exit_label;
261 : : int pass;
262 : :
263 : : bool do_viper_types;
264 : :
265 : : mp_uint_t local_vtype_alloc;
266 : : vtype_kind_t *local_vtype;
267 : :
268 : : mp_uint_t stack_info_alloc;
269 : : stack_info_t *stack_info;
270 : : vtype_kind_t saved_stack_vtype;
271 : :
272 : : size_t exc_stack_alloc;
273 : : size_t exc_stack_size;
274 : : exc_stack_entry_t *exc_stack;
275 : :
276 : : int prelude_offset;
277 : : int prelude_ptr_index;
278 : : int start_offset;
279 : : int n_state;
280 : : uint16_t code_state_start;
281 : : uint16_t stack_start;
282 : : int stack_size;
283 : : uint16_t n_info;
284 : : uint16_t n_cell;
285 : :
286 : : scope_t *scope;
287 : :
288 : : ASM_T *as;
289 : : };
290 : :
291 : : static void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj);
292 : : static void emit_native_global_exc_entry(emit_t *emit);
293 : : static void emit_native_global_exc_exit(emit_t *emit);
294 : : static void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj);
295 : :
296 : 1456 : emit_t *EXPORT_FUN(new)(mp_emit_common_t * emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) {
297 : 1456 : emit_t *emit = m_new0(emit_t, 1);
298 : 1456 : emit->emit_common = emit_common;
299 : 1456 : emit->error_slot = error_slot;
300 : 1456 : emit->label_slot = label_slot;
301 : 1456 : emit->stack_info_alloc = 8;
302 : 1456 : emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
303 : 1456 : emit->exc_stack_alloc = 8;
304 : 1456 : emit->exc_stack = m_new(exc_stack_entry_t, emit->exc_stack_alloc);
305 : 1456 : emit->as = m_new0(ASM_T, 1);
306 : 1456 : mp_asm_base_init(&emit->as->base, max_num_labels);
307 : 1456 : return emit;
308 : : }
309 : :
310 : 1440 : void EXPORT_FUN(free)(emit_t * emit) {
311 : 1440 : mp_asm_base_deinit(&emit->as->base, false);
312 : 1440 : m_del_obj(ASM_T, emit->as);
313 : 1440 : m_del(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc);
314 : 1440 : m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc);
315 : 1440 : m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc);
316 : 1440 : m_del_obj(emit_t, emit);
317 : 1440 : }
318 : :
319 : : static void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg);
320 : :
321 : 26115 : static void emit_native_mov_reg_const(emit_t *emit, int reg_dest, int const_val) {
322 : 26115 : ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_FUN_TABLE, const_val);
323 : 26115 : }
324 : :
325 : 197423 : static void emit_native_mov_state_reg(emit_t *emit, int local_num, int reg_src) {
326 [ + + ]: 197423 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
327 : 18369 : ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, REG_GENERATOR_STATE, local_num);
328 : : } else {
329 : 179054 : ASM_MOV_LOCAL_REG(emit->as, local_num, reg_src);
330 : : }
331 : 197423 : }
332 : :
333 : 135907 : static void emit_native_mov_reg_state(emit_t *emit, int reg_dest, int local_num) {
334 [ + + ]: 135907 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
335 : 11681 : ASM_LOAD_REG_REG_OFFSET(emit->as, reg_dest, REG_GENERATOR_STATE, local_num);
336 : : } else {
337 : 124226 : ASM_MOV_REG_LOCAL(emit->as, reg_dest, local_num);
338 : : }
339 : 135907 : }
340 : :
341 : 84715 : static void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local_num) {
342 [ + + ]: 84715 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
343 : 8640 : ASM_MOV_REG_IMM(emit->as, reg_dest, local_num * ASM_WORD_SIZE);
344 : 8640 : ASM_ADD_REG_REG(emit->as, reg_dest, REG_GENERATOR_STATE);
345 : : } else {
346 : 76075 : ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, local_num);
347 : : }
348 : 84715 : }
349 : :
350 : 135443 : static void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) {
351 : : #if MICROPY_PERSISTENT_CODE_SAVE
352 : : ASM_LOAD16_REG_REG_OFFSET(emit->as, arg_reg, REG_QSTR_TABLE, mp_emit_common_use_qstr(emit->emit_common, qst));
353 : : #elif defined(ASM_MOV_REG_QSTR)
354 : : ASM_MOV_REG_QSTR(emit->as, arg_reg, qst);
355 : : #else
356 : 135443 : ASM_MOV_REG_IMM(emit->as, arg_reg, qst);
357 : : #endif
358 : 135443 : }
359 : :
360 : 24159 : static void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) {
361 : : #if MICROPY_PERSISTENT_CODE_SAVE
362 : : emit_load_reg_with_object(emit, reg_dest, MP_OBJ_NEW_QSTR(qst));
363 : : #else
364 : 24159 : ASM_MOV_REG_IMM(emit->as, reg_dest, (mp_uint_t)MP_OBJ_NEW_QSTR(qst));
365 : : #endif
366 : 24159 : }
367 : :
368 : : #define emit_native_mov_state_imm_via(emit, local_num, imm, reg_temp) \
369 : : do { \
370 : : ASM_MOV_REG_IMM((emit)->as, (reg_temp), (imm)); \
371 : : emit_native_mov_state_reg((emit), (local_num), (reg_temp)); \
372 : : } while (false)
373 : :
374 : 13151 : static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
375 : 13151 : DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);
376 : :
377 : 13151 : emit->pass = pass;
378 : 13151 : emit->do_viper_types = scope->emit_options == MP_EMIT_OPT_VIPER;
379 : 13151 : emit->stack_size = 0;
380 : 13151 : emit->scope = scope;
381 : :
382 : : // allocate memory for keeping track of the types of locals
383 [ + + ]: 13151 : if (emit->local_vtype_alloc < scope->num_locals) {
384 : 769 : emit->local_vtype = m_renew(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc, scope->num_locals);
385 : 769 : emit->local_vtype_alloc = scope->num_locals;
386 : : }
387 : :
388 : : // set default type for arguments
389 : 13151 : mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args;
390 [ + + ]: 13151 : if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
391 : 150 : num_args += 1;
392 : : }
393 [ + + ]: 13151 : if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) {
394 : 60 : num_args += 1;
395 : : }
396 [ + + ]: 22985 : for (mp_uint_t i = 0; i < num_args; i++) {
397 : 9834 : emit->local_vtype[i] = VTYPE_PYOBJ;
398 : : }
399 : :
400 : : // Set viper type for arguments
401 [ + + ]: 13151 : if (emit->do_viper_types) {
402 [ + + ]: 2456 : for (int i = 0; i < emit->scope->id_info_len; ++i) {
403 : 1734 : id_info_t *id = &emit->scope->id_info[i];
404 [ + + ]: 1734 : if (id->flags & ID_FLAG_IS_PARAM) {
405 [ - + ]: 996 : assert(id->local_num < emit->local_vtype_alloc);
406 : 996 : emit->local_vtype[id->local_num] = id->flags >> ID_FLAG_VIPER_TYPE_POS;
407 : : }
408 : : }
409 : : }
410 : :
411 : : // local variables begin unbound, and have unknown type
412 [ + + ]: 37200 : for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) {
413 [ + + ]: 47530 : emit->local_vtype[i] = emit->do_viper_types ? VTYPE_UNBOUND : VTYPE_PYOBJ;
414 : : }
415 : :
416 : : // values on stack begin unbound
417 [ + + ]: 129639 : for (mp_uint_t i = 0; i < emit->stack_info_alloc; i++) {
418 : 116488 : emit->stack_info[i].kind = STACK_VALUE;
419 : 116488 : emit->stack_info[i].vtype = VTYPE_UNBOUND;
420 : : }
421 : :
422 [ + + ]: 21949 : mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);
423 : :
424 : : // generate code for entry to function
425 : :
426 : : // Work out start of code state (mp_code_state_native_t or reduced version for viper)
427 : 13151 : emit->code_state_start = 0;
428 [ + + + + ]: 13151 : if (NEED_GLOBAL_EXC_HANDLER(emit)) {
429 : 9237 : emit->code_state_start = SIZEOF_NLR_BUF; // for nlr_buf_t
430 : 9237 : emit->code_state_start += 1; // for return_value
431 [ + + ]: 9237 : if (NEED_THROW_VAL(emit)) {
432 : 935 : emit->code_state_start += 2;
433 [ + + ]: 8302 : } else if (NEED_EXC_HANDLER_UNWIND(emit)) {
434 : 2175 : emit->code_state_start += 1;
435 : : }
436 : : }
437 : :
438 : 13151 : size_t fun_table_off = mp_emit_common_use_const_obj(emit->emit_common, MP_OBJ_FROM_PTR(&mp_fun_table));
439 : :
440 [ + + ]: 13151 : if (emit->do_viper_types) {
441 : : // Work out size of state (locals plus stack)
442 : : // n_state counts all stack and locals, even those in registers
443 : 722 : emit->n_state = scope->num_locals + scope->stack_size;
444 : 722 : int num_locals_in_regs = 0;
445 [ + + + + ]: 722 : if (CAN_USE_REGS_FOR_LOCALS(emit)) {
446 : 684 : num_locals_in_regs = scope->num_locals;
447 [ + + ]: 684 : if (num_locals_in_regs > MAX_REGS_FOR_LOCAL_VARS) {
448 : 120 : num_locals_in_regs = MAX_REGS_FOR_LOCAL_VARS;
449 : : }
450 : : // Need a spot for REG_LOCAL_LAST (see below)
451 [ + + ]: 684 : if (scope->num_pos_args >= MAX_REGS_FOR_LOCAL_VARS + 1) {
452 : 24 : --num_locals_in_regs;
453 : : }
454 : : }
455 : :
456 : : // Work out where the locals and Python stack start within the C stack
457 [ + + + + ]: 722 : if (NEED_GLOBAL_EXC_HANDLER(emit)) {
458 : : // Reserve 2 words for function object and old globals
459 : 288 : emit->stack_start = emit->code_state_start + 2;
460 [ + + ]: 434 : } else if (scope->scope_flags & MP_SCOPE_FLAG_HASCONSTS) {
461 : : // Reserve 1 word for function object, to access const table
462 : 12 : emit->stack_start = emit->code_state_start + 1;
463 : : } else {
464 : 422 : emit->stack_start = emit->code_state_start + 0;
465 : : }
466 : :
467 : : // Entry to function
468 : 722 : ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs);
469 : :
470 : : #if N_X86
471 : : asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);
472 : : #endif
473 : :
474 : : // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
475 : 722 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
476 : : #if MICROPY_PERSISTENT_CODE_SAVE
477 : : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_QSTR_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_QSTR_TABLE);
478 : : #endif
479 : 722 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
480 : 722 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, fun_table_off);
481 : :
482 : : // Store function object (passed as first arg) to stack if needed
483 [ + + + + ]: 722 : if (NEED_FUN_OBJ(emit)) {
484 : 296 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
485 : : }
486 : :
487 : : // Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_LAST
488 : : #if N_X86
489 : : asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_1);
490 : : asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2);
491 : : asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_LAST);
492 : : #else
493 : 722 : ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_PARENT_ARG_2);
494 : 722 : ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_3);
495 : 722 : ASM_MOV_REG_REG(emit->as, REG_LOCAL_LAST, REG_PARENT_ARG_4);
496 : : #endif
497 : :
498 : : // Check number of args matches this function, and call mp_arg_check_num_sig if not
499 : 722 : ASM_JUMP_IF_REG_NONZERO(emit->as, REG_ARG_2, *emit->label_slot + 4, true);
500 : 722 : ASM_MOV_REG_IMM(emit->as, REG_ARG_3, scope->num_pos_args);
501 : 722 : ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_3, *emit->label_slot + 5);
502 : 722 : mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 4);
503 : 722 : ASM_MOV_REG_IMM(emit->as, REG_ARG_3, MP_OBJ_FUN_MAKE_SIG(scope->num_pos_args, scope->num_pos_args, false));
504 : 722 : ASM_CALL_IND(emit->as, MP_F_ARG_CHECK_NUM_SIG);
505 : 722 : mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 5);
506 : :
507 : : // Store arguments into locals (reg or stack), converting to native if needed
508 [ + + ]: 1706 : for (int i = 0; i < emit->scope->num_pos_args; i++) {
509 : 984 : int r = REG_ARG_1;
510 : 984 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_LOCAL_LAST, i);
511 [ + + ]: 984 : if (emit->local_vtype[i] != VTYPE_PYOBJ) {
512 : 876 : emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, emit->local_vtype[i], REG_ARG_2);
513 : 876 : r = REG_RET;
514 : : }
515 : : // REG_LOCAL_LAST points to the args array so be sure not to overwrite it if it's still needed
516 [ + + + - : 984 : if (i < MAX_REGS_FOR_LOCAL_VARS && CAN_USE_REGS_FOR_LOCALS(emit) && (i != MAX_REGS_FOR_LOCAL_VARS - 1 || emit->scope->num_pos_args == MAX_REGS_FOR_LOCAL_VARS)) {
+ - + + +
+ ]
517 : 918 : ASM_MOV_REG_REG(emit->as, reg_local_table[i], r);
518 : : } else {
519 : 66 : emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, i), r);
520 : : }
521 : : }
522 : : // Get local from the stack back into REG_LOCAL_LAST if this reg couldn't be written to above
523 [ + + + - : 722 : if (emit->scope->num_pos_args >= MAX_REGS_FOR_LOCAL_VARS + 1 && CAN_USE_REGS_FOR_LOCALS(emit)) {
+ - ]
524 : 24 : ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_LAST, LOCAL_IDX_LOCAL_VAR(emit, MAX_REGS_FOR_LOCAL_VARS - 1));
525 : : }
526 : :
527 : 722 : emit_native_global_exc_entry(emit);
528 : :
529 : : } else {
530 : : // work out size of state (locals plus stack)
531 : 12429 : emit->n_state = scope->num_locals + scope->stack_size;
532 : :
533 : : // Store in the first machine-word an index used to the function's prelude.
534 : : // This is used at runtime by mp_obj_fun_native_get_prelude_ptr().
535 : 12429 : mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->prelude_ptr_index);
536 : :
537 [ + + ]: 12429 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
538 : 927 : mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset);
539 : 927 : ASM_ENTRY(emit->as, emit->code_state_start);
540 : :
541 : : // Reset the state size for the state pointed to by REG_GENERATOR_STATE
542 : 927 : emit->code_state_start = 0;
543 : 927 : emit->stack_start = SIZEOF_CODE_STATE;
544 : :
545 : : // Put address of code_state into REG_GENERATOR_STATE
546 : : #if N_X86
547 : : asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE);
548 : : #else
549 : 927 : ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1);
550 : : #endif
551 : :
552 : : // Put throw value into LOCAL_IDX_THROW_VAL slot, for yield/yield-from
553 : : #if N_X86
554 : : asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);
555 : : #endif
556 : 927 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_PARENT_ARG_2);
557 : :
558 : : // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
559 : 927 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit));
560 : 927 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONTEXT);
561 : : #if MICROPY_PERSISTENT_CODE_SAVE
562 : : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_QSTR_TABLE, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_QSTR_TABLE);
563 : : #endif
564 : 927 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
565 : 927 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_TEMP0, fun_table_off);
566 : : } else {
567 : : // The locals and stack start after the code_state structure
568 : 11502 : emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE;
569 : :
570 : : // Allocate space on C-stack for code_state structure, which includes state
571 : 11502 : ASM_ENTRY(emit->as, emit->stack_start + emit->n_state);
572 : :
573 : : // Prepare incoming arguments for call to mp_setup_code_state
574 : :
575 : : #if N_X86
576 : : asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);
577 : : asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);
578 : : asm_x86_mov_arg_to_r32(emit->as, 2, REG_PARENT_ARG_3);
579 : : asm_x86_mov_arg_to_r32(emit->as, 3, REG_PARENT_ARG_4);
580 : : #endif
581 : :
582 : : // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
583 : 11502 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
584 : : #if MICROPY_PERSISTENT_CODE_SAVE
585 : : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_QSTR_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_QSTR_TABLE);
586 : : #endif
587 : 11502 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
588 : 11502 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_FUN_TABLE, fun_table_off);
589 : :
590 : : // Set code_state.fun_bc
591 : 11502 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
592 : :
593 : : // Set code_state.n_state (only works on little endian targets due to n_state being uint16_t)
594 : 11502 : emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_N_STATE, emit->n_state, REG_ARG_1);
595 : :
596 : : // Put address of code_state into first arg
597 : 11502 : ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start);
598 : :
599 : : // Copy next 3 args if needed
600 : : #if REG_ARG_2 != REG_PARENT_ARG_2
601 : : ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_2);
602 : : #endif
603 : : #if REG_ARG_3 != REG_PARENT_ARG_3
604 : : ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_PARENT_ARG_3);
605 : : #endif
606 : : #if REG_ARG_4 != REG_PARENT_ARG_4
607 : : ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_PARENT_ARG_4);
608 : : #endif
609 : :
610 : : // Call mp_setup_code_state to prepare code_state structure
611 : : #if N_THUMB
612 : : asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4);
613 : : #elif N_ARM
614 : : asm_arm_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_ARM_REG_R4);
615 : : #else
616 : 11502 : ASM_CALL_IND(emit->as, MP_F_SETUP_CODE_STATE);
617 : : #endif
618 : : }
619 : :
620 : 12429 : emit_native_global_exc_entry(emit);
621 : :
622 : : // cache some locals in registers, but only if no exception handlers
623 [ + + + + ]: 12429 : if (CAN_USE_REGS_FOR_LOCALS(emit)) {
624 [ + + + + ]: 17850 : for (int i = 0; i < MAX_REGS_FOR_LOCAL_VARS && i < scope->num_locals; ++i) {
625 : 8493 : ASM_MOV_REG_LOCAL(emit->as, reg_local_table[i], LOCAL_IDX_LOCAL_VAR(emit, i));
626 : : }
627 : : }
628 : :
629 : : // set the type of closed over variables
630 [ + + ]: 68031 : for (mp_uint_t i = 0; i < scope->id_info_len; i++) {
631 : 55602 : id_info_t *id = &scope->id_info[i];
632 [ + + ]: 55602 : if (id->kind == ID_INFO_KIND_CELL) {
633 : 276 : emit->local_vtype[id->local_num] = VTYPE_PYOBJ;
634 : : }
635 : : }
636 : : }
637 : 13151 : }
638 : :
639 : 94501 : static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) {
640 : 94501 : mp_asm_base_data(&emit->as->base, 1, val);
641 : : }
642 : :
643 : 21069 : static inline void emit_native_write_code_info_qstr(emit_t *emit, qstr qst) {
644 : 21069 : mp_encode_uint(&emit->as->base, mp_asm_base_get_cur_to_write_bytes, mp_emit_common_use_qstr(emit->emit_common, qst));
645 : 21069 : }
646 : :
647 : 13135 : static bool emit_native_end_pass(emit_t *emit) {
648 : 13135 : emit_native_global_exc_exit(emit);
649 : :
650 [ + + ]: 13135 : if (!emit->do_viper_types) {
651 : 12429 : emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base);
652 : 12429 : emit->prelude_ptr_index = emit->emit_common->ct_cur_child;
653 : :
654 : 12429 : size_t n_state = emit->n_state;
655 : 12429 : size_t n_exc_stack = 0; // exc-stack not needed for native code
656 [ + + ]: 82021 : MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, emit->scope, emit_native_write_code_info_byte, emit);
657 : :
658 : 12429 : size_t n_info = emit->n_info;
659 : 12429 : size_t n_cell = emit->n_cell;
660 [ + + + + ]: 12480 : MP_BC_PRELUDE_SIZE_ENCODE(n_info, n_cell, emit_native_write_code_info_byte, emit);
661 : :
662 : : // bytecode prelude: source info (function and argument qstrs)
663 : 12429 : size_t info_start = mp_asm_base_get_code_pos(&emit->as->base);
664 : 12429 : emit_native_write_code_info_qstr(emit, emit->scope->simple_name);
665 [ + + ]: 21069 : for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
666 : 15375 : qstr qst = MP_QSTR__star_;
667 [ + + ]: 15375 : for (int j = 0; j < emit->scope->id_info_len; ++j) {
668 : 14778 : id_info_t *id = &emit->scope->id_info[j];
669 [ + + + + ]: 14778 : if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {
670 : 8043 : qst = id->qst;
671 : 8043 : break;
672 : : }
673 : : }
674 : 8640 : emit_native_write_code_info_qstr(emit, qst);
675 : : }
676 : 12429 : emit->n_info = mp_asm_base_get_code_pos(&emit->as->base) - info_start;
677 : :
678 : : // bytecode prelude: initialise closed over variables
679 : 12429 : size_t cell_start = mp_asm_base_get_code_pos(&emit->as->base);
680 [ + + ]: 68031 : for (int i = 0; i < emit->scope->id_info_len; i++) {
681 : 55602 : id_info_t *id = &emit->scope->id_info[i];
682 [ + + ]: 55602 : if (id->kind == ID_INFO_KIND_CELL) {
683 [ - + ]: 276 : assert(id->local_num <= 255);
684 : 276 : mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell
685 : : }
686 : : }
687 : 12429 : emit->n_cell = mp_asm_base_get_code_pos(&emit->as->base) - cell_start;
688 : :
689 : : }
690 : :
691 : 13135 : ASM_END_PASS(emit->as);
692 : :
693 : : // check stack is back to zero size
694 [ - + ]: 13135 : assert(emit->stack_size == 0);
695 [ - + ]: 13135 : assert(emit->exc_stack_size == 0);
696 : :
697 [ + + ]: 13135 : if (emit->pass == MP_PASS_EMIT) {
698 [ + + ]: 4353 : void *f = mp_asm_base_get_code(&emit->as->base);
699 [ + + ]: 4353 : mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base);
700 : :
701 : 4353 : mp_raw_code_t **children = emit->emit_common->children;
702 [ + + ]: 4353 : if (!emit->do_viper_types) {
703 : : #if MICROPY_EMIT_NATIVE_PRELUDE_SEPARATE_FROM_MACHINE_CODE
704 : : // Executable code cannot be accessed byte-wise on this architecture, so copy
705 : : // the prelude to a separate memory region that is byte-wise readable.
706 : : void *buf = emit->as->base.code_base + emit->prelude_offset;
707 : : size_t n = emit->as->base.code_offset - emit->prelude_offset;
708 : : const uint8_t *prelude_ptr = memcpy(m_new(uint8_t, n), buf, n);
709 : : #else
710 : : // Point to the prelude directly, at the end of the machine code data.
711 : 4143 : const uint8_t *prelude_ptr = (const uint8_t *)f + emit->prelude_offset;
712 : : #endif
713 : :
714 : : // Store the pointer to the prelude using the child_table.
715 [ - + ]: 4143 : assert(emit->prelude_ptr_index == emit->emit_common->ct_cur_child);
716 [ + + ]: 4143 : if (emit->prelude_ptr_index == 0) {
717 : : children = (void *)prelude_ptr;
718 : : } else {
719 : 998 : children = m_renew(mp_raw_code_t *, children, emit->prelude_ptr_index, emit->prelude_ptr_index + 1);
720 : 998 : children[emit->prelude_ptr_index] = (void *)prelude_ptr;
721 : : }
722 : : }
723 : :
724 : 4353 : mp_emit_glue_assign_native(emit->scope->raw_code,
725 : 4353 : emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,
726 : : f, f_len,
727 : : children,
728 : : #if MICROPY_PERSISTENT_CODE_SAVE
729 : : emit->emit_common->ct_cur_child,
730 : : emit->prelude_offset,
731 : : #endif
732 [ + + ]: 4353 : emit->scope->scope_flags, 0, 0);
733 : : }
734 : :
735 : 13135 : return true;
736 : : }
737 : :
738 : 373254 : static void ensure_extra_stack(emit_t *emit, size_t delta) {
739 [ + + ]: 373254 : if (emit->stack_size + delta > emit->stack_info_alloc) {
740 : 354 : size_t new_alloc = (emit->stack_size + delta + 8) & ~3;
741 : 354 : emit->stack_info = m_renew(stack_info_t, emit->stack_info, emit->stack_info_alloc, new_alloc);
742 : 354 : emit->stack_info_alloc = new_alloc;
743 : : }
744 : 373254 : }
745 : :
746 : 705436 : static void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
747 [ - + ]: 705436 : assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
748 [ - + ]: 705436 : assert((mp_int_t)emit->stack_size + stack_size_delta <= (mp_int_t)emit->stack_info_alloc);
749 : 705436 : emit->stack_size += stack_size_delta;
750 [ + - + + ]: 705436 : if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) {
751 : 16146 : emit->scope->stack_size = emit->stack_size;
752 : : }
753 : : #if DEBUG_PRINT
754 : : DEBUG_printf(" adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta);
755 : : for (int i = 0; i < emit->stack_size; i++) {
756 : : stack_info_t *si = &emit->stack_info[i];
757 : : DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->data.u_reg);
758 : : }
759 : : DEBUG_printf("\n");
760 : : #endif
761 : 705436 : }
762 : :
763 : 10488 : static void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
764 : 10488 : DEBUG_printf("adjust_stack_size(" INT_FMT ")\n", delta);
765 [ + + ]: 10488 : if (delta > 0) {
766 : 8868 : ensure_extra_stack(emit, delta);
767 : : }
768 : : // If we are adjusting the stack in a positive direction (pushing) then we
769 : : // need to fill in values for the stack kind and vtype of the newly-pushed
770 : : // entries. These should be set to "value" (ie not reg or imm) because we
771 : : // should only need to adjust the stack due to a jump to this part in the
772 : : // code (and hence we have settled the stack before the jump).
773 [ + + ]: 20406 : for (mp_int_t i = 0; i < delta; i++) {
774 : 9918 : stack_info_t *si = &emit->stack_info[emit->stack_size + i];
775 : 9918 : si->kind = STACK_VALUE;
776 : : // TODO we don't know the vtype to use here. At the moment this is a
777 : : // hack to get the case of multi comparison working.
778 [ + + ]: 9918 : if (delta == 1) {
779 : 8220 : si->vtype = emit->saved_stack_vtype;
780 : : } else {
781 : 1698 : si->vtype = VTYPE_PYOBJ;
782 : : }
783 : : }
784 : 10488 : adjust_stack(emit, delta);
785 : 10488 : }
786 : :
787 : 248081 : static void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) {
788 : 248081 : (void)emit;
789 : 248081 : (void)source_line;
790 : 248081 : }
791 : :
792 : : // this must be called at start of emit functions
793 : : static void emit_native_pre(emit_t *emit) {
794 : : (void)emit;
795 : : }
796 : :
797 : : // depth==0 is top, depth==1 is before top, etc
798 : 12883 : static stack_info_t *peek_stack(emit_t *emit, mp_uint_t depth) {
799 : 12883 : return &emit->stack_info[emit->stack_size - 1 - depth];
800 : : }
801 : :
802 : : // depth==0 is top, depth==1 is before top, etc
803 : 109518 : static vtype_kind_t peek_vtype(emit_t *emit, mp_uint_t depth) {
804 [ + + ]: 109518 : if (emit->do_viper_types) {
805 : 4080 : return peek_stack(emit, depth)->vtype;
806 : : } else {
807 : : // Type is always PYOBJ even if the intermediate stored value is not
808 : : return VTYPE_PYOBJ;
809 : : }
810 : : }
811 : :
812 : : // pos=1 is TOS, pos=2 is next, etc
813 : : // use pos=0 for no skipping
814 : 262274 : static void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
815 : 262274 : skip_stack_pos = emit->stack_size - skip_stack_pos;
816 [ + + ]: 838986 : for (int i = 0; i < emit->stack_size; i++) {
817 [ + + ]: 576712 : if (i != skip_stack_pos) {
818 : 363560 : stack_info_t *si = &emit->stack_info[i];
819 [ + + + + ]: 363560 : if (si->kind == STACK_REG && si->data.u_reg == reg_needed) {
820 : 33357 : si->kind = STACK_VALUE;
821 : 33357 : emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);
822 : : }
823 : : }
824 : : }
825 : 262274 : }
826 : :
827 : : // Ensures all unsettled registers that hold Python values are copied to the
828 : : // concrete Python stack. All registers are then free to use.
829 : 528611 : static void need_reg_all(emit_t *emit) {
830 [ + + ]: 1199995 : for (int i = 0; i < emit->stack_size; i++) {
831 : 671384 : stack_info_t *si = &emit->stack_info[i];
832 [ + + ]: 671384 : if (si->kind == STACK_REG) {
833 : 106566 : DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
834 : 106566 : si->kind = STACK_VALUE;
835 : 106566 : emit_native_mov_state_reg(emit, emit->stack_start + i, si->data.u_reg);
836 : : }
837 : : }
838 : 528611 : }
839 : :
840 : 60948 : static vtype_kind_t load_reg_stack_imm(emit_t *emit, int reg_dest, const stack_info_t *si, bool convert_to_pyobj) {
841 [ + + + + ]: 60948 : if (!convert_to_pyobj && emit->do_viper_types) {
842 : 644 : ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm);
843 : 644 : return si->vtype;
844 : : } else {
845 [ + + ]: 60304 : if (si->vtype == VTYPE_PYOBJ) {
846 : 882 : ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm);
847 [ + + ]: 59422 : } else if (si->vtype == VTYPE_BOOL) {
848 : 1893 : emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_FALSE_OBJ + si->data.u_imm);
849 [ + + ]: 57529 : } else if (si->vtype == VTYPE_INT || si->vtype == VTYPE_UINT) {
850 : 34542 : ASM_MOV_REG_IMM(emit->as, reg_dest, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm));
851 [ + + ]: 22987 : } else if (si->vtype == VTYPE_PTR_NONE) {
852 : 22983 : emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_NONE_OBJ);
853 : : } else {
854 : 4 : mp_raise_NotImplementedError(MP_ERROR_TEXT("conversion to object"));
855 : : }
856 : 60300 : return VTYPE_PYOBJ;
857 : : }
858 : : }
859 : :
860 : : // Copies all unsettled registers and immediates that are Python values into the
861 : : // concrete Python stack. This ensures the concrete Python stack holds valid
862 : : // values for the current stack_size.
863 : : // This function may clobber REG_TEMP1.
864 : 123729 : static void need_stack_settled(emit_t *emit) {
865 : 123729 : DEBUG_printf(" need_stack_settled; stack_size=%d\n", emit->stack_size);
866 : 123729 : need_reg_all(emit);
867 [ + + ]: 204648 : for (int i = 0; i < emit->stack_size; i++) {
868 : 80919 : stack_info_t *si = &emit->stack_info[i];
869 [ + + ]: 80919 : if (si->kind == STACK_IMM) {
870 : 3414 : DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i);
871 : 3414 : si->kind = STACK_VALUE;
872 : : // using REG_TEMP1 to avoid clobbering REG_TEMP0 (aka REG_RET)
873 : 3414 : si->vtype = load_reg_stack_imm(emit, REG_TEMP1, si, false);
874 : 3414 : emit_native_mov_state_reg(emit, emit->stack_start + i, REG_TEMP1);
875 : : }
876 : : }
877 : 123729 : }
878 : :
879 : : // pos=1 is TOS, pos=2 is next, etc
880 : 206965 : static void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int reg_dest) {
881 : 206965 : need_reg_single(emit, reg_dest, pos);
882 : 206965 : stack_info_t *si = &emit->stack_info[emit->stack_size - pos];
883 : 206965 : *vtype = si->vtype;
884 [ + + + - ]: 206965 : switch (si->kind) {
885 : 67874 : case STACK_VALUE:
886 : 67874 : emit_native_mov_reg_state(emit, reg_dest, emit->stack_start + emit->stack_size - pos);
887 : 67874 : break;
888 : :
889 : 106143 : case STACK_REG:
890 [ + + ]: 106143 : if (si->data.u_reg != reg_dest) {
891 : 99489 : ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg);
892 : : }
893 : : break;
894 : :
895 : 32948 : case STACK_IMM:
896 : 32948 : *vtype = load_reg_stack_imm(emit, reg_dest, si, false);
897 : 32948 : break;
898 : : }
899 : 206965 : }
900 : :
901 : : // does an efficient X=pop(); discard(); push(X)
902 : : // needs a (non-temp) register in case the popped element was stored in the stack
903 : 899 : static void emit_fold_stack_top(emit_t *emit, int reg_dest) {
904 : 899 : stack_info_t *si = &emit->stack_info[emit->stack_size - 2];
905 : 899 : si[0] = si[1];
906 [ + + ]: 899 : if (si->kind == STACK_VALUE) {
907 : : // if folded element was on the stack we need to put it in a register
908 : 885 : emit_native_mov_reg_state(emit, reg_dest, emit->stack_start + emit->stack_size - 1);
909 : 885 : si->kind = STACK_REG;
910 : 885 : si->data.u_reg = reg_dest;
911 : : }
912 : 899 : adjust_stack(emit, -1);
913 : 899 : }
914 : :
915 : : // If stacked value is in a register and the register is not r1 or r2, then
916 : : // *reg_dest is set to that register. Otherwise the value is put in *reg_dest.
917 : 8433 : static void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) {
918 : 8433 : stack_info_t *si = peek_stack(emit, 0);
919 [ + + + + : 8433 : if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) {
+ - ]
920 : 6187 : *vtype = si->vtype;
921 : 6187 : *reg_dest = si->data.u_reg;
922 : 6187 : need_reg_single(emit, *reg_dest, 1);
923 : : } else {
924 : 2246 : emit_access_stack(emit, 1, vtype, *reg_dest);
925 : : }
926 : 8433 : adjust_stack(emit, -1);
927 : 8433 : }
928 : :
929 : 48795 : static void emit_pre_pop_discard(emit_t *emit) {
930 : 48795 : adjust_stack(emit, -1);
931 : 48795 : }
932 : :
933 : 201422 : static void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest) {
934 : 201422 : emit_access_stack(emit, 1, vtype, reg_dest);
935 : 201422 : adjust_stack(emit, -1);
936 : 201422 : }
937 : :
938 : 24461 : static void emit_pre_pop_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb) {
939 : 24461 : emit_pre_pop_reg(emit, vtypea, rega);
940 : 24461 : emit_pre_pop_reg(emit, vtypeb, regb);
941 : 24461 : }
942 : :
943 : 3948 : static void emit_pre_pop_reg_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int rega, vtype_kind_t *vtypeb, int regb, vtype_kind_t *vtypec, int regc) {
944 : 3948 : emit_pre_pop_reg(emit, vtypea, rega);
945 : 3948 : emit_pre_pop_reg(emit, vtypeb, regb);
946 : 3948 : emit_pre_pop_reg(emit, vtypec, regc);
947 : 3948 : }
948 : :
949 : : static void emit_post(emit_t *emit) {
950 : : (void)emit;
951 : : }
952 : :
953 : 14 : static void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) {
954 : 14 : stack_info_t *si = &emit->stack_info[emit->stack_size - 1];
955 : 14 : si->vtype = new_vtype;
956 : 14 : }
957 : :
958 : 286071 : static void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {
959 : 286071 : ensure_extra_stack(emit, 1);
960 : 286071 : stack_info_t *si = &emit->stack_info[emit->stack_size];
961 : 286071 : si->vtype = vtype;
962 : 286071 : si->kind = STACK_REG;
963 : 286071 : si->data.u_reg = reg;
964 : 286071 : adjust_stack(emit, 1);
965 : 286071 : }
966 : :
967 : 60891 : static void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {
968 : 60891 : ensure_extra_stack(emit, 1);
969 : 60891 : stack_info_t *si = &emit->stack_info[emit->stack_size];
970 : 60891 : si->vtype = vtype;
971 : 60891 : si->kind = STACK_IMM;
972 : 60891 : si->data.u_imm = imm;
973 : 60891 : adjust_stack(emit, 1);
974 : 60891 : }
975 : :
976 : 6975 : static void emit_post_push_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb) {
977 : 6975 : emit_post_push_reg(emit, vtypea, rega);
978 : 6975 : emit_post_push_reg(emit, vtypeb, regb);
979 : 6975 : }
980 : :
981 : 336 : static void emit_post_push_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc) {
982 : 336 : emit_post_push_reg(emit, vtypea, rega);
983 : 336 : emit_post_push_reg(emit, vtypeb, regb);
984 : 336 : emit_post_push_reg(emit, vtypec, regc);
985 : 336 : }
986 : :
987 : 444 : static void emit_post_push_reg_reg_reg_reg(emit_t *emit, vtype_kind_t vtypea, int rega, vtype_kind_t vtypeb, int regb, vtype_kind_t vtypec, int regc, vtype_kind_t vtyped, int regd) {
988 : 444 : emit_post_push_reg(emit, vtypea, rega);
989 : 444 : emit_post_push_reg(emit, vtypeb, regb);
990 : 444 : emit_post_push_reg(emit, vtypec, regc);
991 : 444 : emit_post_push_reg(emit, vtyped, regd);
992 : 444 : }
993 : :
994 : 83550 : static void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) {
995 : 83550 : need_reg_all(emit);
996 : 83550 : ASM_CALL_IND(emit->as, fun_kind);
997 : 83550 : }
998 : :
999 : 76252 : static void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
1000 : 76252 : need_reg_all(emit);
1001 : 76252 : ASM_MOV_REG_IMM(emit->as, arg_reg, arg_val);
1002 : 76252 : ASM_CALL_IND(emit->as, fun_kind);
1003 : 76252 : }
1004 : :
1005 : 16200 : static void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) {
1006 : 16200 : need_reg_all(emit);
1007 : 16200 : ASM_MOV_REG_IMM(emit->as, arg_reg1, arg_val1);
1008 : 16200 : ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2);
1009 : 16200 : ASM_CALL_IND(emit->as, fun_kind);
1010 : 16200 : }
1011 : :
1012 : 135443 : static void emit_call_with_qstr_arg(emit_t *emit, mp_fun_kind_t fun_kind, qstr qst, int arg_reg) {
1013 : 135443 : need_reg_all(emit);
1014 : 135443 : emit_native_mov_reg_qstr(emit, arg_reg, qst);
1015 : 135443 : ASM_CALL_IND(emit->as, fun_kind);
1016 : 135443 : }
1017 : :
1018 : : // vtype of all n_pop objects is VTYPE_PYOBJ
1019 : : // Will convert any items that are not VTYPE_PYOBJ to this type and put them back on the stack.
1020 : : // If any conversions of non-immediate values are needed, then it uses REG_ARG_1, REG_ARG_2 and REG_RET.
1021 : : // Otherwise, it does not use any temporary registers (but may use reg_dest before loading it with stack pointer).
1022 : 67295 : static void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_pop) {
1023 : 67295 : need_reg_all(emit);
1024 : :
1025 : : // First, store any immediate values to their respective place on the stack.
1026 [ + + ]: 199737 : for (mp_uint_t i = 0; i < n_pop; i++) {
1027 : 132446 : stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
1028 : : // must push any imm's to stack
1029 : : // must convert them to VTYPE_PYOBJ for viper code
1030 [ + + ]: 132446 : if (si->kind == STACK_IMM) {
1031 : 24586 : si->kind = STACK_VALUE;
1032 : 24586 : si->vtype = load_reg_stack_imm(emit, reg_dest, si, true);
1033 : 24582 : emit_native_mov_state_reg(emit, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
1034 : : }
1035 : :
1036 : : // verify that this value is on the stack
1037 [ - + ]: 132442 : assert(si->kind == STACK_VALUE);
1038 : : }
1039 : :
1040 : : // Second, convert any non-VTYPE_PYOBJ to that type.
1041 [ + + ]: 199733 : for (mp_uint_t i = 0; i < n_pop; i++) {
1042 : 132442 : stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
1043 [ + + ]: 132442 : if (si->vtype != VTYPE_PYOBJ) {
1044 : 544 : mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i;
1045 : 544 : emit_native_mov_reg_state(emit, REG_ARG_1, local_num);
1046 : 544 : emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type
1047 : 544 : emit_native_mov_state_reg(emit, local_num, REG_RET);
1048 : 544 : si->vtype = VTYPE_PYOBJ;
1049 : 132442 : DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num);
1050 : : }
1051 : : }
1052 : :
1053 : : // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest.
1054 : 67291 : adjust_stack(emit, -n_pop);
1055 : 67291 : emit_native_mov_reg_state_addr(emit, reg_dest, emit->stack_start + emit->stack_size);
1056 : 67291 : }
1057 : :
1058 : : // vtype of all n_push objects is VTYPE_PYOBJ
1059 : 17424 : static void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_dest, mp_uint_t n_push) {
1060 : 17424 : need_reg_all(emit);
1061 : 17424 : ensure_extra_stack(emit, n_push);
1062 [ + + ]: 54978 : for (mp_uint_t i = 0; i < n_push; i++) {
1063 : 37554 : emit->stack_info[emit->stack_size + i].kind = STACK_VALUE;
1064 : 37554 : emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ;
1065 : : }
1066 : 17424 : emit_native_mov_reg_state_addr(emit, reg_dest, emit->stack_start + emit->stack_size);
1067 : 17424 : adjust_stack(emit, n_push);
1068 : 17424 : }
1069 : :
1070 : 6000 : static void emit_native_push_exc_stack(emit_t *emit, uint label, bool is_finally) {
1071 [ + + ]: 6000 : if (emit->exc_stack_size + 1 > emit->exc_stack_alloc) {
1072 : 6 : size_t new_alloc = emit->exc_stack_alloc + 4;
1073 : 6 : emit->exc_stack = m_renew(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc, new_alloc);
1074 : 6 : emit->exc_stack_alloc = new_alloc;
1075 : : }
1076 : :
1077 : 6000 : exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size++];
1078 : 6000 : e->label = label;
1079 : 6000 : e->is_finally = is_finally;
1080 : 6000 : e->unwind_label = UNWIND_LABEL_UNUSED;
1081 : 6000 : e->is_active = true;
1082 : :
1083 : 6000 : ASM_MOV_REG_PCREL(emit->as, REG_RET, label);
1084 : 6000 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);
1085 : 6000 : }
1086 : :
1087 : 10959 : static void emit_native_leave_exc_stack(emit_t *emit, bool start_of_handler) {
1088 [ - + ]: 10959 : assert(emit->exc_stack_size > 0);
1089 : :
1090 : : // Get current exception handler and deactivate it
1091 : 10959 : exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];
1092 : 10959 : e->is_active = false;
1093 : :
1094 : : // Find next innermost active exception handler, to restore as current handler
1095 [ + + + + ]: 11733 : for (--e; e >= emit->exc_stack && !e->is_active; --e) {
1096 : 774 : }
1097 : :
1098 : : // Update the PC of the new exception handler
1099 [ + + ]: 10959 : if (e < emit->exc_stack) {
1100 : : // No active handler, clear handler PC to zero
1101 [ + + ]: 10431 : if (start_of_handler) {
1102 : : // Optimisation: PC is already cleared by global exc handler
1103 : : return;
1104 : : }
1105 : 5646 : ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET);
1106 : : } else {
1107 : : // Found new active handler, get its PC
1108 : 528 : ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);
1109 : : }
1110 : 6174 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);
1111 : : }
1112 : :
1113 : 6000 : static exc_stack_entry_t *emit_native_pop_exc_stack(emit_t *emit) {
1114 [ - + ]: 6000 : assert(emit->exc_stack_size > 0);
1115 : 6000 : exc_stack_entry_t *e = &emit->exc_stack[--emit->exc_stack_size];
1116 [ - + ]: 6000 : assert(e->is_active == false);
1117 : 6000 : return e;
1118 : : }
1119 : :
1120 : 11166 : static void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) {
1121 : 11166 : emit->scope->scope_flags |= MP_SCOPE_FLAG_HASCONSTS;
1122 : 11166 : size_t table_off = mp_emit_common_use_const_obj(emit->emit_common, obj);
1123 : 11166 : emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit));
1124 : 11166 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CONTEXT);
1125 : 11166 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_MODULE_CONTEXT_OBJ_TABLE);
1126 : 11166 : ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off);
1127 : 11166 : }
1128 : :
1129 : 8718 : static void emit_load_reg_with_child(emit_t *emit, int reg, mp_raw_code_t *rc) {
1130 [ + + ]: 8718 : size_t table_off = mp_emit_common_alloc_const_child(emit->emit_common, rc);
1131 : 8718 : emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_FUN_OBJ(emit));
1132 : 8718 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_TEMP0, OFFSETOF_OBJ_FUN_BC_CHILD_TABLE);
1133 : 8718 : ASM_LOAD_REG_REG_OFFSET(emit->as, reg, REG_TEMP0, table_off);
1134 : 8718 : }
1135 : :
1136 : 73389 : static void emit_native_label_assign(emit_t *emit, mp_uint_t l) {
1137 : 73389 : DEBUG_printf("label_assign(" UINT_FMT ")\n", l);
1138 : :
1139 : 73389 : bool is_finally = false;
1140 [ + + ]: 73389 : if (emit->exc_stack_size > 0) {
1141 : 14781 : exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];
1142 [ + + + + ]: 14781 : is_finally = e->is_finally && e->label == l;
1143 : : }
1144 : :
1145 : 1041 : if (is_finally) {
1146 : : // Label is at start of finally handler: store TOS into exception slot
1147 : 1041 : vtype_kind_t vtype;
1148 : 1041 : emit_access_stack(emit, 1, &vtype, REG_TEMP0);
1149 : 1041 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
1150 : : }
1151 : :
1152 : 73389 : emit_native_pre(emit);
1153 : : // need to commit stack because we can jump here from elsewhere
1154 : 73389 : need_stack_settled(emit);
1155 : 73389 : mp_asm_base_label_assign(&emit->as->base, l);
1156 : 73389 : emit_post(emit);
1157 : :
1158 [ + + ]: 73389 : if (is_finally) {
1159 : : // Label is at start of finally handler: pop exception stack
1160 : 1041 : emit_native_leave_exc_stack(emit, false);
1161 : : }
1162 : 73389 : }
1163 : :
1164 : 13151 : static void emit_native_global_exc_entry(emit_t *emit) {
1165 : : // Note: 4 labels are reserved for this function, starting at *emit->label_slot
1166 : :
1167 : 13151 : emit->exit_label = *emit->label_slot;
1168 : :
1169 [ + + + + ]: 13151 : if (NEED_GLOBAL_EXC_HANDLER(emit)) {
1170 : 9237 : mp_uint_t nlr_label = *emit->label_slot + 1;
1171 : 9237 : mp_uint_t start_label = *emit->label_slot + 2;
1172 : 9237 : mp_uint_t global_except_label = *emit->label_slot + 3;
1173 : :
1174 [ + + ]: 9237 : if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
1175 : : // Set new globals
1176 : 8302 : emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_FUN_OBJ(emit));
1177 : 8302 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_CONTEXT);
1178 : 8302 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_ARG_1, OFFSETOF_MODULE_CONTEXT_GLOBALS);
1179 : 8302 : emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
1180 : :
1181 : : // Save old globals (or NULL if globals didn't change)
1182 : 8302 : emit_native_mov_state_reg(emit, LOCAL_IDX_OLD_GLOBALS(emit), REG_RET);
1183 : : }
1184 : :
1185 [ + + ]: 9237 : if (emit->scope->exc_stack_size == 0) {
1186 [ + + ]: 6786 : if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
1187 : : // Optimisation: if globals didn't change don't push the nlr context
1188 : 6127 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, false);
1189 : : }
1190 : :
1191 : : // Wrap everything in an nlr context
1192 : 6786 : ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0);
1193 : 6786 : emit_call(emit, MP_F_NLR_PUSH);
1194 : : #if N_NLR_SETJMP
1195 : : ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2);
1196 : : emit_call(emit, MP_F_SETJMP);
1197 : : #endif
1198 : 6786 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, start_label, true);
1199 : : } else {
1200 : : // Clear the unwind state
1201 : 2451 : ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0);
1202 : 2451 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_TEMP0);
1203 : :
1204 : : // clear nlr.ret_val, because it's passed to mp_native_raise regardless
1205 : : // of whether there was an exception or not
1206 : 2451 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
1207 : :
1208 : : // Put PC of start code block into REG_LOCAL_1
1209 : 2451 : ASM_MOV_REG_PCREL(emit->as, REG_LOCAL_1, start_label);
1210 : :
1211 : : // Wrap everything in an nlr context
1212 : 2451 : emit_native_label_assign(emit, nlr_label);
1213 : 2451 : ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0);
1214 : 2451 : emit_call(emit, MP_F_NLR_PUSH);
1215 : : #if N_NLR_SETJMP
1216 : : ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 2);
1217 : : emit_call(emit, MP_F_SETJMP);
1218 : : #endif
1219 : 2451 : ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, global_except_label, true);
1220 : :
1221 : : // Clear PC of current code block, and jump there to resume execution
1222 : 2451 : ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0);
1223 : 2451 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_TEMP0);
1224 : 2451 : ASM_JUMP_REG(emit->as, REG_LOCAL_1);
1225 : :
1226 : : // Global exception handler: check for valid exception handler
1227 : 2451 : emit_native_label_assign(emit, global_except_label);
1228 : 2451 : ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, LOCAL_IDX_EXC_HANDLER_PC(emit));
1229 : 2451 : ASM_JUMP_IF_REG_NONZERO(emit->as, REG_LOCAL_1, nlr_label, false);
1230 : : }
1231 : :
1232 [ + + ]: 9237 : if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
1233 : : // Restore old globals
1234 : 8302 : emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));
1235 : 8302 : emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
1236 : : }
1237 : :
1238 [ + + ]: 9237 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
1239 : : // Store return value in state[0]
1240 : 935 : ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit));
1241 : 935 : ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, OFFSETOF_CODE_STATE_STATE);
1242 : :
1243 : : // Load return kind
1244 : 935 : ASM_MOV_REG_IMM(emit->as, REG_PARENT_RET, MP_VM_RETURN_EXCEPTION);
1245 : :
1246 : 935 : ASM_EXIT(emit->as);
1247 : : } else {
1248 : : // Re-raise exception out to caller
1249 : 8302 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));
1250 : 8302 : emit_call(emit, MP_F_NATIVE_RAISE);
1251 : : }
1252 : :
1253 : : // Label for start of function
1254 : 9237 : emit_native_label_assign(emit, start_label);
1255 : :
1256 [ + + ]: 9237 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
1257 : 935 : emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_GEN_PC(emit));
1258 : 935 : ASM_JUMP_REG(emit->as, REG_TEMP0);
1259 : 935 : emit->start_offset = mp_asm_base_get_code_pos(&emit->as->base);
1260 : :
1261 : : // This is the first entry of the generator
1262 : :
1263 : : // Check LOCAL_IDX_THROW_VAL for any injected value
1264 : 935 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit));
1265 : 935 : ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL);
1266 : 935 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2);
1267 : 935 : emit_call(emit, MP_F_NATIVE_RAISE);
1268 : : }
1269 : : }
1270 : 13151 : }
1271 : :
1272 : 13135 : static void emit_native_global_exc_exit(emit_t *emit) {
1273 : : // Label for end of function
1274 : 13135 : emit_native_label_assign(emit, emit->exit_label);
1275 : :
1276 [ + + + + ]: 13135 : if (NEED_GLOBAL_EXC_HANDLER(emit)) {
1277 : : // Get old globals
1278 [ + + ]: 9225 : if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
1279 : 8298 : emit_native_mov_reg_state(emit, REG_ARG_1, LOCAL_IDX_OLD_GLOBALS(emit));
1280 : :
1281 [ + + ]: 8298 : if (emit->scope->exc_stack_size == 0) {
1282 : : // Optimisation: if globals didn't change then don't restore them and don't do nlr_pop
1283 : 6123 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, emit->exit_label + 1, false);
1284 : : }
1285 : :
1286 : : // Restore old globals
1287 : 8298 : emit_call(emit, MP_F_NATIVE_SWAP_GLOBALS);
1288 : : }
1289 : :
1290 : : // Pop the nlr context
1291 : 9225 : emit_call(emit, MP_F_NLR_POP);
1292 : :
1293 [ + + ]: 9225 : if (!(emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
1294 [ + + ]: 8298 : if (emit->scope->exc_stack_size == 0) {
1295 : : // Destination label for above optimisation
1296 : 6123 : emit_native_label_assign(emit, emit->exit_label + 1);
1297 : : }
1298 : : }
1299 : :
1300 : : // Load return value
1301 : 9225 : ASM_MOV_REG_LOCAL(emit->as, REG_PARENT_RET, LOCAL_IDX_RET_VAL(emit));
1302 : : }
1303 : :
1304 : 13135 : ASM_EXIT(emit->as);
1305 : 13135 : }
1306 : :
1307 : 2325 : static void emit_native_import_name(emit_t *emit, qstr qst) {
1308 : 2325 : DEBUG_printf("import_name %s\n", qstr_str(qst));
1309 : :
1310 : : // get arguments from stack: arg2 = fromlist, arg3 = level
1311 : : // If using viper types these arguments must be converted to proper objects, and
1312 : : // to accomplish this viper types are turned off for the emit_pre_pop_reg_reg call.
1313 : 2325 : bool orig_do_viper_types = emit->do_viper_types;
1314 : 2325 : emit->do_viper_types = false;
1315 : 2325 : vtype_kind_t vtype_fromlist;
1316 : 2325 : vtype_kind_t vtype_level;
1317 : 2325 : emit_pre_pop_reg_reg(emit, &vtype_fromlist, REG_ARG_2, &vtype_level, REG_ARG_3);
1318 [ - + ]: 2325 : assert(vtype_fromlist == VTYPE_PYOBJ);
1319 [ - + ]: 2325 : assert(vtype_level == VTYPE_PYOBJ);
1320 : 2325 : emit->do_viper_types = orig_do_viper_types;
1321 : :
1322 : 2325 : emit_call_with_qstr_arg(emit, MP_F_IMPORT_NAME, qst, REG_ARG_1); // arg1 = import name
1323 : 2325 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1324 : 2325 : }
1325 : :
1326 : 969 : static void emit_native_import_from(emit_t *emit, qstr qst) {
1327 : 969 : DEBUG_printf("import_from %s\n", qstr_str(qst));
1328 : 969 : emit_native_pre(emit);
1329 : 969 : vtype_kind_t vtype_module;
1330 : 969 : emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module
1331 [ - + ]: 969 : assert(vtype_module == VTYPE_PYOBJ);
1332 : 969 : emit_call_with_qstr_arg(emit, MP_F_IMPORT_FROM, qst, REG_ARG_2); // arg2 = import name
1333 : 969 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1334 : 969 : }
1335 : :
1336 : 117 : static void emit_native_import_star(emit_t *emit) {
1337 : 117 : DEBUG_printf("import_star\n");
1338 : 117 : vtype_kind_t vtype_module;
1339 : 117 : emit_pre_pop_reg(emit, &vtype_module, REG_ARG_1); // arg1 = module
1340 [ - + ]: 117 : assert(vtype_module == VTYPE_PYOBJ);
1341 : 117 : emit_call(emit, MP_F_IMPORT_ALL);
1342 : 117 : emit_post(emit);
1343 : 117 : }
1344 : :
1345 : 3411 : static void emit_native_import(emit_t *emit, qstr qst, int kind) {
1346 [ + + ]: 3411 : if (kind == MP_EMIT_IMPORT_NAME) {
1347 : 2325 : emit_native_import_name(emit, qst);
1348 [ + + ]: 1086 : } else if (kind == MP_EMIT_IMPORT_FROM) {
1349 : 969 : emit_native_import_from(emit, qst);
1350 : : } else {
1351 : 117 : emit_native_import_star(emit);
1352 : : }
1353 : 3411 : }
1354 : :
1355 : 23849 : static void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
1356 : 23849 : DEBUG_printf("load_const_tok(tok=%u)\n", tok);
1357 [ + + ]: 23849 : if (tok == MP_TOKEN_ELLIPSIS) {
1358 : 12 : emit_native_load_const_obj(emit, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));
1359 : : } else {
1360 : 23837 : emit_native_pre(emit);
1361 [ + + ]: 23837 : if (tok == MP_TOKEN_KW_NONE) {
1362 : 21932 : emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);
1363 : : } else {
1364 : 1905 : emit_post_push_imm(emit, VTYPE_BOOL, tok == MP_TOKEN_KW_FALSE ? 0 : 1);
1365 : : }
1366 : : }
1367 : 23849 : }
1368 : :
1369 : 35268 : static void emit_native_load_const_small_int(emit_t *emit, mp_int_t arg) {
1370 : 35268 : DEBUG_printf("load_const_small_int(int=" INT_FMT ")\n", arg);
1371 : 35268 : emit_native_pre(emit);
1372 : 35268 : emit_post_push_imm(emit, VTYPE_INT, arg);
1373 : 35268 : }
1374 : :
1375 : 24159 : static void emit_native_load_const_str(emit_t *emit, qstr qst) {
1376 : 24159 : emit_native_pre(emit);
1377 : : // TODO: Eventually we want to be able to work with raw pointers in viper to
1378 : : // do native array access. For now we just load them as any other object.
1379 : : /*
1380 : : if (emit->do_viper_types) {
1381 : : // load a pointer to the asciiz string?
1382 : : emit_post_push_imm(emit, VTYPE_PTR, (mp_uint_t)qstr_str(qst));
1383 : : } else
1384 : : */
1385 : : {
1386 : 24159 : need_reg_single(emit, REG_TEMP0, 0);
1387 : 24159 : emit_native_mov_reg_qstr_obj(emit, REG_TEMP0, qst);
1388 : 24159 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0);
1389 : : }
1390 : 24159 : }
1391 : :
1392 : 11166 : static void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) {
1393 : 11166 : emit_native_pre(emit);
1394 : 11166 : need_reg_single(emit, REG_RET, 0);
1395 : 11166 : emit_load_reg_with_object(emit, REG_RET, obj);
1396 : 11166 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1397 : 11166 : }
1398 : :
1399 : 882 : static void emit_native_load_null(emit_t *emit) {
1400 : 882 : emit_native_pre(emit);
1401 : 882 : emit_post_push_imm(emit, VTYPE_PYOBJ, 0);
1402 : 882 : }
1403 : :
1404 : 27165 : static void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
1405 : 27165 : DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
1406 : 27165 : vtype_kind_t vtype = emit->local_vtype[local_num];
1407 [ + + ]: 27165 : if (vtype == VTYPE_UNBOUND) {
1408 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("local '%q' used before type known"), qst);
1409 : : }
1410 : 27165 : emit_native_pre(emit);
1411 [ + + + + : 27165 : if (local_num < MAX_REGS_FOR_LOCAL_VARS && CAN_USE_REGS_FOR_LOCALS(emit)) {
+ + ]
1412 : 15000 : emit_post_push_reg(emit, vtype, reg_local_table[local_num]);
1413 : : } else {
1414 : 12165 : need_reg_single(emit, REG_TEMP0, 0);
1415 : 12165 : emit_native_mov_reg_state(emit, REG_TEMP0, LOCAL_IDX_LOCAL_VAR(emit, local_num));
1416 : 12165 : emit_post_push_reg(emit, vtype, REG_TEMP0);
1417 : : }
1418 : 27165 : }
1419 : :
1420 : 522 : static void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
1421 : 522 : DEBUG_printf("load_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
1422 : 522 : need_reg_single(emit, REG_RET, 0);
1423 : 522 : emit_native_load_fast(emit, qst, local_num);
1424 : 522 : vtype_kind_t vtype;
1425 : 522 : int reg_base = REG_RET;
1426 : 522 : emit_pre_pop_reg_flexible(emit, &vtype, ®_base, -1, -1);
1427 : 522 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_RET, reg_base, 1);
1428 : : // closed over vars are always Python objects
1429 : 522 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1430 : 522 : }
1431 : :
1432 : 26838 : static void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
1433 [ + + ]: 26838 : if (kind == MP_EMIT_IDOP_LOCAL_FAST) {
1434 : 26316 : emit_native_load_fast(emit, qst, local_num);
1435 : : } else {
1436 : 522 : emit_native_load_deref(emit, qst, local_num);
1437 : : }
1438 : 26838 : }
1439 : :
1440 : 81969 : static void emit_native_load_global(emit_t *emit, qstr qst, int kind) {
1441 : 81969 : MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_LOAD_NAME);
1442 : 81969 : MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_LOAD_GLOBAL);
1443 : 81969 : emit_native_pre(emit);
1444 [ + + ]: 81969 : if (kind == MP_EMIT_IDOP_GLOBAL_NAME) {
1445 : : DEBUG_printf("load_name(%s)\n", qstr_str(qst));
1446 : : } else {
1447 : 17535 : DEBUG_printf("load_global(%s)\n", qstr_str(qst));
1448 [ + + ]: 17535 : if (emit->do_viper_types) {
1449 : : // check for builtin casting operators
1450 : 594 : int native_type = mp_native_type_from_qstr(qst);
1451 [ + + ]: 594 : if (native_type >= MP_NATIVE_TYPE_BOOL) {
1452 : 100 : emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, native_type);
1453 : 100 : return;
1454 : : }
1455 : : }
1456 : : }
1457 : 81869 : emit_call_with_qstr_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1);
1458 : 81869 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1459 : : }
1460 : :
1461 : 9318 : static void emit_native_load_attr(emit_t *emit, qstr qst) {
1462 : : // depends on type of subject:
1463 : : // - integer, function, pointer to integers: error
1464 : : // - pointer to structure: get member, quite easy
1465 : : // - Python object: call mp_load_attr, and needs to be typed to convert result
1466 : 9318 : vtype_kind_t vtype_base;
1467 : 9318 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1468 [ - + ]: 9318 : assert(vtype_base == VTYPE_PYOBJ);
1469 : 9318 : emit_call_with_qstr_arg(emit, MP_F_LOAD_ATTR, qst, REG_ARG_2); // arg2 = attribute name
1470 : 9318 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1471 : 9318 : }
1472 : :
1473 : 15261 : static void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) {
1474 : 15261 : DEBUG_printf("load_method(%s, %d)\n", qstr_str(qst), is_super);
1475 [ + + ]: 15261 : if (is_super) {
1476 : 48 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr
1477 : 48 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr
1478 : 48 : emit_call_with_qstr_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name
1479 : : } else {
1480 : 15213 : vtype_kind_t vtype_base;
1481 : 15213 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1482 [ - + ]: 15213 : assert(vtype_base == VTYPE_PYOBJ);
1483 : 15213 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
1484 : 15213 : emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name
1485 : : }
1486 : 15261 : }
1487 : :
1488 : 1467 : static void emit_native_load_build_class(emit_t *emit) {
1489 : 1467 : emit_native_pre(emit);
1490 : 1467 : emit_call(emit, MP_F_LOAD_BUILD_CLASS);
1491 : 1467 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1492 : 1467 : }
1493 : :
1494 : 3962 : static void emit_native_load_subscr(emit_t *emit) {
1495 : 3962 : DEBUG_printf("load_subscr\n");
1496 : : // need to compile: base[index]
1497 : :
1498 : : // pop: index, base
1499 : : // optimise case where index is an immediate
1500 : 3962 : vtype_kind_t vtype_base = peek_vtype(emit, 1);
1501 : :
1502 [ + + ]: 3962 : if (vtype_base == VTYPE_PYOBJ) {
1503 : : // standard Python subscr
1504 : : // TODO factor this implicit cast code with other uses of it
1505 : 3816 : vtype_kind_t vtype_index = peek_vtype(emit, 0);
1506 [ + + ]: 3816 : if (vtype_index == VTYPE_PYOBJ) {
1507 : 3810 : emit_pre_pop_reg(emit, &vtype_index, REG_ARG_2);
1508 : : } else {
1509 : 6 : emit_pre_pop_reg(emit, &vtype_index, REG_ARG_1);
1510 : 6 : emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype_index, REG_ARG_2); // arg2 = type
1511 : 6 : ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
1512 : : }
1513 : 3816 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
1514 : 3816 : emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_SENTINEL, REG_ARG_3);
1515 : 3816 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
1516 : : } else {
1517 : : // viper load
1518 : : // TODO The different machine architectures have very different
1519 : : // capabilities and requirements for loads, so probably best to
1520 : : // write a completely separate load-optimiser for each one.
1521 : 146 : stack_info_t *top = peek_stack(emit, 0);
1522 [ + + ]: 146 : if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
1523 : : // index is an immediate
1524 : 70 : mp_int_t index_value = top->data.u_imm;
1525 : 70 : emit_pre_pop_discard(emit); // discard index
1526 : 70 : int reg_base = REG_ARG_1;
1527 : 70 : int reg_index = REG_ARG_2;
1528 : 70 : emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_index);
1529 : 70 : need_reg_single(emit, REG_RET, 0);
1530 [ + + + + ]: 70 : switch (vtype_base) {
1531 : 42 : case VTYPE_PTR8: {
1532 : : // pointer to 8-bit memory
1533 : : // TODO optimise to use thumb ldrb r1, [r2, r3]
1534 [ + + ]: 42 : if (index_value != 0) {
1535 : : // index is non-zero
1536 : : #if N_THUMB
1537 : : if (index_value > 0 && index_value < 32) {
1538 : : asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
1539 : : break;
1540 : : }
1541 : : #elif N_RV32
1542 : : if (FIT_SIGNED(index_value, 12)) {
1543 : : asm_rv32_opcode_lbu(emit->as, REG_RET, reg_base, index_value);
1544 : : break;
1545 : : }
1546 : : #endif
1547 : 30 : need_reg_single(emit, reg_index, 0);
1548 : 30 : ASM_MOV_REG_IMM(emit->as, reg_index, index_value);
1549 : 30 : ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
1550 : 30 : reg_base = reg_index;
1551 : : }
1552 : 42 : ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index)
1553 : 42 : break;
1554 : : }
1555 : 12 : case VTYPE_PTR16: {
1556 : : // pointer to 16-bit memory
1557 [ + + ]: 12 : if (index_value != 0) {
1558 : : // index is a non-zero immediate
1559 : : #if N_THUMB
1560 : : if (index_value > 0 && index_value < 32) {
1561 : : asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
1562 : : break;
1563 : : }
1564 : : #elif N_RV32
1565 : : if (FIT_SIGNED(index_value, 11)) {
1566 : : asm_rv32_opcode_lhu(emit->as, REG_RET, reg_base, index_value << 1);
1567 : : break;
1568 : : }
1569 : : #endif
1570 : 6 : need_reg_single(emit, reg_index, 0);
1571 : 6 : ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1);
1572 : 6 : ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
1573 : 6 : reg_base = reg_index;
1574 : : }
1575 : 12 : ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index)
1576 : 12 : break;
1577 : : }
1578 : 12 : case VTYPE_PTR32: {
1579 : : // pointer to 32-bit memory
1580 [ + + ]: 12 : if (index_value != 0) {
1581 : : // index is a non-zero immediate
1582 : : #if N_THUMB
1583 : : if (index_value > 0 && index_value < 32) {
1584 : : asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value);
1585 : : break;
1586 : : }
1587 : : #elif N_RV32
1588 : : if (FIT_SIGNED(index_value, 10)) {
1589 : : asm_rv32_opcode_lw(emit->as, REG_RET, reg_base, index_value << 2);
1590 : : break;
1591 : : }
1592 : : #endif
1593 : 6 : need_reg_single(emit, reg_index, 0);
1594 : 6 : ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2);
1595 : 6 : ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base
1596 : 6 : reg_base = reg_index;
1597 : : }
1598 : 12 : ASM_LOAD32_REG_REG(emit->as, REG_RET, reg_base); // load from (base+4*index)
1599 : 12 : break;
1600 : : }
1601 : 4 : default:
1602 : 70 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1603 : : MP_ERROR_TEXT("can't load from '%q'"), vtype_to_qstr(vtype_base));
1604 : : }
1605 : : } else {
1606 : : // index is not an immediate
1607 : 76 : vtype_kind_t vtype_index;
1608 : 76 : int reg_index = REG_ARG_2;
1609 : 76 : emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, REG_ARG_1);
1610 : 76 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
1611 : 76 : need_reg_single(emit, REG_RET, 0);
1612 [ + + ]: 76 : if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
1613 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1614 : : MP_ERROR_TEXT("can't load with '%q' index"), vtype_to_qstr(vtype_index));
1615 : : }
1616 [ + + + + ]: 76 : switch (vtype_base) {
1617 : 48 : case VTYPE_PTR8: {
1618 : : // pointer to 8-bit memory
1619 : : // TODO optimise to use thumb ldrb r1, [r2, r3]
1620 : 48 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1621 : 48 : ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index)
1622 : 48 : break;
1623 : : }
1624 : 12 : case VTYPE_PTR16: {
1625 : : // pointer to 16-bit memory
1626 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1627 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1628 : 12 : ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index)
1629 : 12 : break;
1630 : : }
1631 : 12 : case VTYPE_PTR32: {
1632 : : // pointer to word-size memory
1633 : : #if N_RV32
1634 : : asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2);
1635 : : asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2);
1636 : : asm_rv32_opcode_lw(emit->as, REG_RET, REG_ARG_1, 0);
1637 : : break;
1638 : : #endif
1639 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1640 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1641 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1642 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1643 : 12 : ASM_LOAD32_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+4*index)
1644 : 12 : break;
1645 : : }
1646 : 4 : default:
1647 : 76 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1648 : : MP_ERROR_TEXT("can't load from '%q'"), vtype_to_qstr(vtype_base));
1649 : : }
1650 : : }
1651 : 146 : emit_post_push_reg(emit, VTYPE_INT, REG_RET);
1652 : : }
1653 : 3962 : }
1654 : :
1655 : 6454 : static void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
1656 : 6454 : vtype_kind_t vtype;
1657 [ + + + + : 6454 : if (local_num < MAX_REGS_FOR_LOCAL_VARS && CAN_USE_REGS_FOR_LOCALS(emit)) {
+ + ]
1658 : 1261 : emit_pre_pop_reg(emit, &vtype, reg_local_table[local_num]);
1659 : : } else {
1660 : 5193 : emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
1661 : 5193 : emit_native_mov_state_reg(emit, LOCAL_IDX_LOCAL_VAR(emit, local_num), REG_TEMP0);
1662 : : }
1663 : 6454 : emit_post(emit);
1664 : :
1665 : : // check types
1666 [ + + ]: 6454 : if (emit->local_vtype[local_num] == VTYPE_UNBOUND) {
1667 : : // first time this local is assigned, so give it a type of the object stored in it
1668 : 312 : emit->local_vtype[local_num] = vtype;
1669 [ + + ]: 6142 : } else if (emit->local_vtype[local_num] != vtype) {
1670 : : // type of local is not the same as object stored in it
1671 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1672 : : MP_ERROR_TEXT("local '%q' has type '%q' but source is '%q'"),
1673 : : qst, vtype_to_qstr(emit->local_vtype[local_num]), vtype_to_qstr(vtype));
1674 : : }
1675 : 6454 : }
1676 : :
1677 : 327 : static void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
1678 : 327 : DEBUG_printf("store_deref(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
1679 : 327 : need_reg_single(emit, REG_TEMP0, 0);
1680 : 327 : need_reg_single(emit, REG_TEMP1, 0);
1681 : 327 : emit_native_load_fast(emit, qst, local_num);
1682 : 327 : vtype_kind_t vtype;
1683 : 327 : int reg_base = REG_TEMP0;
1684 : 327 : emit_pre_pop_reg_flexible(emit, &vtype, ®_base, -1, -1);
1685 : 327 : int reg_src = REG_TEMP1;
1686 : 327 : emit_pre_pop_reg_flexible(emit, &vtype, ®_src, reg_base, reg_base);
1687 : 327 : ASM_STORE_REG_REG_OFFSET(emit->as, reg_src, reg_base, 1);
1688 : 327 : emit_post(emit);
1689 : 327 : }
1690 : :
1691 : 6481 : static void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
1692 [ + + ]: 6481 : if (kind == MP_EMIT_IDOP_LOCAL_FAST) {
1693 : 6154 : emit_native_store_fast(emit, qst, local_num);
1694 : : } else {
1695 : 327 : emit_native_store_deref(emit, qst, local_num);
1696 : : }
1697 : 6481 : }
1698 : :
1699 : 22620 : static void emit_native_store_global(emit_t *emit, qstr qst, int kind) {
1700 : 22620 : MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_STORE_NAME);
1701 : 22620 : MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_STORE_GLOBAL);
1702 [ + + ]: 22620 : if (kind == MP_EMIT_IDOP_GLOBAL_NAME) {
1703 : : // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type))
1704 : 21783 : vtype_kind_t vtype;
1705 : 21783 : emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1706 [ - + ]: 21783 : assert(vtype == VTYPE_PYOBJ);
1707 : : } else {
1708 : 837 : vtype_kind_t vtype = peek_vtype(emit, 0);
1709 [ + + ]: 837 : if (vtype == VTYPE_PYOBJ) {
1710 : 831 : emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
1711 : : } else {
1712 : 6 : emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
1713 : 6 : emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type
1714 : 6 : ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
1715 : : }
1716 : : }
1717 : 22620 : emit_call_with_qstr_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name
1718 : 22620 : emit_post(emit);
1719 : 22620 : }
1720 : :
1721 : 2283 : static void emit_native_store_attr(emit_t *emit, qstr qst) {
1722 : 2283 : vtype_kind_t vtype_base;
1723 : 2283 : vtype_kind_t vtype_val = peek_vtype(emit, 1);
1724 [ + + ]: 2283 : if (vtype_val == VTYPE_PYOBJ) {
1725 : 2271 : emit_pre_pop_reg_reg(emit, &vtype_base, REG_ARG_1, &vtype_val, REG_ARG_3); // arg1 = base, arg3 = value
1726 : : } else {
1727 : 12 : emit_access_stack(emit, 2, &vtype_val, REG_ARG_1); // arg1 = value
1728 : 12 : emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype_val, REG_ARG_2); // arg2 = type
1729 : 12 : ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_RET); // arg3 = value (converted)
1730 : 12 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1731 : 12 : adjust_stack(emit, -1); // pop value
1732 : : }
1733 [ - + ]: 2283 : assert(vtype_base == VTYPE_PYOBJ);
1734 : 2283 : emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name
1735 : 2283 : emit_post(emit);
1736 : 2283 : }
1737 : :
1738 : 1472 : static void emit_native_store_subscr(emit_t *emit) {
1739 : 1472 : DEBUG_printf("store_subscr\n");
1740 : : // need to compile: base[index] = value
1741 : :
1742 : : // pop: index, base, value
1743 : : // optimise case where index is an immediate
1744 : 1472 : vtype_kind_t vtype_base = peek_vtype(emit, 1);
1745 : :
1746 [ + + ]: 1472 : if (vtype_base == VTYPE_PYOBJ) {
1747 : : // standard Python subscr
1748 : 1344 : vtype_kind_t vtype_index = peek_vtype(emit, 0);
1749 : 1344 : vtype_kind_t vtype_value = peek_vtype(emit, 2);
1750 [ + + ]: 1344 : if (vtype_index != VTYPE_PYOBJ || vtype_value != VTYPE_PYOBJ) {
1751 : : // need to implicitly convert non-objects to objects
1752 : : // TODO do this properly
1753 : 6 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, 3);
1754 : 6 : adjust_stack(emit, 3);
1755 : : }
1756 : 1344 : emit_pre_pop_reg_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1, &vtype_value, REG_ARG_3);
1757 : 1344 : emit_call(emit, MP_F_OBJ_SUBSCR);
1758 : : } else {
1759 : : // viper store
1760 : : // TODO The different machine architectures have very different
1761 : : // capabilities and requirements for stores, so probably best to
1762 : : // write a completely separate store-optimiser for each one.
1763 : 128 : stack_info_t *top = peek_stack(emit, 0);
1764 [ + + ]: 128 : if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
1765 : : // index is an immediate
1766 : 48 : mp_int_t index_value = top->data.u_imm;
1767 : 48 : emit_pre_pop_discard(emit); // discard index
1768 : 48 : vtype_kind_t vtype_value;
1769 : 48 : int reg_base = REG_ARG_1;
1770 : 48 : int reg_index = REG_ARG_2;
1771 : 48 : int reg_value = REG_ARG_3;
1772 : 48 : emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_value);
1773 : : #if N_X64 || N_X86
1774 : : // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
1775 : 48 : emit_pre_pop_reg(emit, &vtype_value, reg_value);
1776 : : #else
1777 : : emit_pre_pop_reg_flexible(emit, &vtype_value, ®_value, reg_base, reg_index);
1778 : : #endif
1779 [ + + ]: 48 : if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) {
1780 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1781 : : MP_ERROR_TEXT("can't store '%q'"), vtype_to_qstr(vtype_value));
1782 : : }
1783 [ + + + + ]: 48 : switch (vtype_base) {
1784 : 12 : case VTYPE_PTR8: {
1785 : : // pointer to 8-bit memory
1786 : : // TODO optimise to use thumb strb r1, [r2, r3]
1787 [ + + ]: 12 : if (index_value != 0) {
1788 : : // index is non-zero
1789 : : #if N_THUMB
1790 : : if (index_value > 0 && index_value < 32) {
1791 : : asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);
1792 : : break;
1793 : : }
1794 : : #elif N_RV32
1795 : : if (FIT_SIGNED(index_value, 12)) {
1796 : : asm_rv32_opcode_sb(emit->as, reg_value, reg_base, index_value);
1797 : : break;
1798 : : }
1799 : : #endif
1800 : 6 : ASM_MOV_REG_IMM(emit->as, reg_index, index_value);
1801 : : #if N_ARM
1802 : : asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
1803 : : return;
1804 : : #endif
1805 : 6 : ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
1806 : 6 : reg_base = reg_index;
1807 : : }
1808 : 12 : ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (base+index)
1809 : 12 : break;
1810 : : }
1811 : 12 : case VTYPE_PTR16: {
1812 : : // pointer to 16-bit memory
1813 [ + + ]: 12 : if (index_value != 0) {
1814 : : // index is a non-zero immediate
1815 : : #if N_THUMB
1816 : : if (index_value > 0 && index_value < 32) {
1817 : : asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);
1818 : : break;
1819 : : }
1820 : : #elif N_RV32
1821 : : if (FIT_SIGNED(index_value, 11)) {
1822 : : asm_rv32_opcode_sh(emit->as, reg_value, reg_base, index_value << 1);
1823 : : break;
1824 : : }
1825 : : #endif
1826 : 6 : ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1);
1827 : 6 : ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
1828 : 6 : reg_base = reg_index;
1829 : : }
1830 : 12 : ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index)
1831 : 12 : break;
1832 : : }
1833 : 16 : case VTYPE_PTR32: {
1834 : : // pointer to 32-bit memory
1835 [ + + ]: 16 : if (index_value != 0) {
1836 : : // index is a non-zero immediate
1837 : : #if N_THUMB
1838 : : if (index_value > 0 && index_value < 32) {
1839 : : asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value);
1840 : : break;
1841 : : }
1842 : : #elif N_RV32
1843 : : if (FIT_SIGNED(index_value, 10)) {
1844 : : asm_rv32_opcode_sw(emit->as, reg_value, reg_base, index_value << 2);
1845 : : break;
1846 : : }
1847 : : #elif N_ARM
1848 : : ASM_MOV_REG_IMM(emit->as, reg_index, index_value);
1849 : : asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
1850 : : return;
1851 : : #endif
1852 : 6 : ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2);
1853 : 6 : ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base
1854 : 6 : reg_base = reg_index;
1855 : : }
1856 : 16 : ASM_STORE32_REG_REG(emit->as, reg_value, reg_base); // store value to (base+4*index)
1857 : 16 : break;
1858 : : }
1859 : 8 : default:
1860 : 48 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1861 : : MP_ERROR_TEXT("can't store to '%q'"), vtype_to_qstr(vtype_base));
1862 : : }
1863 : : } else {
1864 : : // index is not an immediate
1865 : 80 : vtype_kind_t vtype_index, vtype_value;
1866 : 80 : int reg_index = REG_ARG_2;
1867 : 80 : int reg_value = REG_ARG_3;
1868 : 80 : emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, reg_value);
1869 : 80 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
1870 [ + + ]: 80 : if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
1871 : 8 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1872 : : MP_ERROR_TEXT("can't store with '%q' index"), vtype_to_qstr(vtype_index));
1873 : : }
1874 : : #if N_X64 || N_X86
1875 : : // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
1876 : 80 : emit_pre_pop_reg(emit, &vtype_value, reg_value);
1877 : : #else
1878 : : emit_pre_pop_reg_flexible(emit, &vtype_value, ®_value, REG_ARG_1, reg_index);
1879 : : #endif
1880 [ + + ]: 80 : if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) {
1881 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1882 : : MP_ERROR_TEXT("can't store '%q'"), vtype_to_qstr(vtype_value));
1883 : : }
1884 [ + + + + ]: 80 : switch (vtype_base) {
1885 : 48 : case VTYPE_PTR8: {
1886 : : // pointer to 8-bit memory
1887 : : // TODO optimise to use thumb strb r1, [r2, r3]
1888 : : #if N_ARM
1889 : : asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
1890 : : break;
1891 : : #endif
1892 : 48 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1893 : 48 : ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index)
1894 : 48 : break;
1895 : : }
1896 : 12 : case VTYPE_PTR16: {
1897 : : // pointer to 16-bit memory
1898 : : #if N_ARM
1899 : : asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
1900 : : break;
1901 : : #endif
1902 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1903 : 12 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1904 : 12 : ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index)
1905 : 12 : break;
1906 : : }
1907 : 16 : case VTYPE_PTR32: {
1908 : : // pointer to 32-bit memory
1909 : : #if N_ARM
1910 : : asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
1911 : : break;
1912 : : #elif N_RV32
1913 : : asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2);
1914 : : asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2);
1915 : : asm_rv32_opcode_sw(emit->as, reg_value, REG_ARG_1, 0);
1916 : : break;
1917 : : #endif
1918 : 16 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1919 : 16 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1920 : 16 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1921 : 16 : ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
1922 : 16 : ASM_STORE32_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+4*index)
1923 : 16 : break;
1924 : : }
1925 : 4 : default:
1926 : 80 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
1927 : : MP_ERROR_TEXT("can't store to '%q'"), vtype_to_qstr(vtype_base));
1928 : : }
1929 : : }
1930 : :
1931 : : }
1932 : 1472 : }
1933 : :
1934 : 300 : static void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
1935 [ + - ]: 300 : if (kind == MP_EMIT_IDOP_LOCAL_FAST) {
1936 : : // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL
1937 : : // to mark deleted vars but then every var would need to be checked on
1938 : : // each access. Very inefficient, so just set value to None to enable GC.
1939 : 300 : emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE);
1940 : 300 : emit_native_store_fast(emit, qst, local_num);
1941 : : } else {
1942 : : // TODO implement me!
1943 : 300 : }
1944 : 300 : }
1945 : :
1946 : 351 : static void emit_native_delete_global(emit_t *emit, qstr qst, int kind) {
1947 : 351 : MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME);
1948 : 351 : MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL);
1949 : 351 : emit_native_pre(emit);
1950 : 351 : emit_call_with_qstr_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1);
1951 : 351 : emit_post(emit);
1952 : 351 : }
1953 : :
1954 : 45 : static void emit_native_delete_attr(emit_t *emit, qstr qst) {
1955 : 45 : vtype_kind_t vtype_base;
1956 : 45 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
1957 [ - + ]: 45 : assert(vtype_base == VTYPE_PYOBJ);
1958 : 45 : ASM_XOR_REG_REG(emit->as, REG_ARG_3, REG_ARG_3); // arg3 = value (null for delete)
1959 : 45 : emit_call_with_qstr_arg(emit, MP_F_STORE_ATTR, qst, REG_ARG_2); // arg2 = attribute name
1960 : 45 : emit_post(emit);
1961 : 45 : }
1962 : :
1963 : 183 : static void emit_native_delete_subscr(emit_t *emit) {
1964 : 183 : vtype_kind_t vtype_index, vtype_base;
1965 : 183 : emit_pre_pop_reg_reg(emit, &vtype_index, REG_ARG_2, &vtype_base, REG_ARG_1); // index, base
1966 [ - + ]: 183 : assert(vtype_index == VTYPE_PYOBJ);
1967 [ - + ]: 183 : assert(vtype_base == VTYPE_PYOBJ);
1968 : 183 : emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);
1969 : 183 : }
1970 : :
1971 : 5617 : static void emit_native_subscr(emit_t *emit, int kind) {
1972 [ + + ]: 5617 : if (kind == MP_EMIT_SUBSCR_LOAD) {
1973 : 3962 : emit_native_load_subscr(emit);
1974 [ + + ]: 1655 : } else if (kind == MP_EMIT_SUBSCR_STORE) {
1975 : 1472 : emit_native_store_subscr(emit);
1976 : : } else {
1977 : 183 : emit_native_delete_subscr(emit);
1978 : : }
1979 : 5617 : }
1980 : :
1981 : 11646 : static void emit_native_attr(emit_t *emit, qstr qst, int kind) {
1982 [ + + ]: 11646 : if (kind == MP_EMIT_ATTR_LOAD) {
1983 : 9318 : emit_native_load_attr(emit, qst);
1984 [ + + ]: 2328 : } else if (kind == MP_EMIT_ATTR_STORE) {
1985 : 2283 : emit_native_store_attr(emit, qst);
1986 : : } else {
1987 : 45 : emit_native_delete_attr(emit, qst);
1988 : : }
1989 : 11646 : }
1990 : :
1991 : 6213 : static void emit_native_dup_top(emit_t *emit) {
1992 : 6213 : DEBUG_printf("dup_top\n");
1993 : 6213 : vtype_kind_t vtype;
1994 : 6213 : int reg = REG_TEMP0;
1995 : 6213 : emit_pre_pop_reg_flexible(emit, &vtype, ®, -1, -1);
1996 : 6213 : emit_post_push_reg_reg(emit, vtype, reg, vtype, reg);
1997 : 6213 : }
1998 : :
1999 : 444 : static void emit_native_dup_top_two(emit_t *emit) {
2000 : 444 : vtype_kind_t vtype0, vtype1;
2001 : 444 : emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1);
2002 : 444 : emit_post_push_reg_reg_reg_reg(emit, vtype1, REG_TEMP1, vtype0, REG_TEMP0, vtype1, REG_TEMP1, vtype0, REG_TEMP0);
2003 : 444 : }
2004 : :
2005 : 41845 : static void emit_native_pop_top(emit_t *emit) {
2006 : 41845 : DEBUG_printf("pop_top\n");
2007 : 41845 : emit_pre_pop_discard(emit);
2008 : 41845 : emit_post(emit);
2009 : 41845 : }
2010 : :
2011 : 762 : static void emit_native_rot_two(emit_t *emit) {
2012 : 762 : DEBUG_printf("rot_two\n");
2013 : 762 : vtype_kind_t vtype0, vtype1;
2014 : 762 : emit_pre_pop_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1);
2015 : 762 : emit_post_push_reg_reg(emit, vtype0, REG_TEMP0, vtype1, REG_TEMP1);
2016 : 762 : }
2017 : :
2018 : 336 : static void emit_native_rot_three(emit_t *emit) {
2019 : 336 : DEBUG_printf("rot_three\n");
2020 : 336 : vtype_kind_t vtype0, vtype1, vtype2;
2021 : 336 : emit_pre_pop_reg_reg_reg(emit, &vtype0, REG_TEMP0, &vtype1, REG_TEMP1, &vtype2, REG_TEMP2);
2022 : 336 : emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1);
2023 : 336 : }
2024 : :
2025 : 32183 : static void emit_native_jump(emit_t *emit, mp_uint_t label) {
2026 : 32183 : DEBUG_printf("jump(label=" UINT_FMT ")\n", label);
2027 : 32183 : emit_native_pre(emit);
2028 : : // need to commit stack because we are jumping elsewhere
2029 : 32183 : need_stack_settled(emit);
2030 : 32183 : ASM_JUMP(emit->as, label);
2031 : 32183 : emit_post(emit);
2032 : 32183 : mp_asm_base_suppress_code(&emit->as->base);
2033 : 32183 : }
2034 : :
2035 : 10780 : static void emit_native_jump_helper(emit_t *emit, bool cond, mp_uint_t label, bool pop) {
2036 : 10780 : vtype_kind_t vtype = peek_vtype(emit, 0);
2037 [ + + ]: 10780 : if (vtype == VTYPE_PYOBJ) {
2038 : 10512 : emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
2039 [ + + ]: 10512 : if (!pop) {
2040 : 249 : adjust_stack(emit, 1);
2041 : : }
2042 : 10512 : emit_call(emit, MP_F_OBJ_IS_TRUE);
2043 : : } else {
2044 : 268 : emit_pre_pop_reg(emit, &vtype, REG_RET);
2045 [ + + ]: 268 : if (!pop) {
2046 : 36 : adjust_stack(emit, 1);
2047 : : }
2048 [ + + ]: 268 : if (!(vtype == VTYPE_BOOL || vtype == VTYPE_INT || vtype == VTYPE_UINT)) {
2049 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2050 : : MP_ERROR_TEXT("can't implicitly convert '%q' to 'bool'"), vtype_to_qstr(vtype));
2051 : : }
2052 : : }
2053 : : // For non-pop need to save the vtype so that emit_native_adjust_stack_size
2054 : : // can use it. This is a bit of a hack.
2055 [ + + ]: 10780 : if (!pop) {
2056 : 285 : emit->saved_stack_vtype = vtype;
2057 : : }
2058 : : // need to commit stack because we may jump elsewhere
2059 : 10780 : need_stack_settled(emit);
2060 : : // Emit the jump
2061 [ + + ]: 10780 : if (cond) {
2062 [ + + ]: 2733 : ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label, vtype == VTYPE_PYOBJ);
2063 : : } else {
2064 [ + + ]: 8047 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, vtype == VTYPE_PYOBJ);
2065 : : }
2066 [ + + ]: 10780 : if (!pop) {
2067 : 285 : adjust_stack(emit, -1);
2068 : : }
2069 : 10780 : emit_post(emit);
2070 : 10780 : }
2071 : :
2072 : 10495 : static void emit_native_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {
2073 : 10495 : DEBUG_printf("pop_jump_if(cond=%u, label=" UINT_FMT ")\n", cond, label);
2074 : 10495 : emit_native_jump_helper(emit, cond, label, true);
2075 : 10495 : }
2076 : :
2077 : 285 : static void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {
2078 : 285 : DEBUG_printf("jump_if_or_pop(cond=%u, label=" UINT_FMT ")\n", cond, label);
2079 : 285 : emit_native_jump_helper(emit, cond, label, false);
2080 : 285 : }
2081 : :
2082 : 16898 : static void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
2083 [ + + ]: 16898 : if (except_depth > 0) {
2084 : 327 : exc_stack_entry_t *first_finally = NULL;
2085 : 327 : exc_stack_entry_t *prev_finally = NULL;
2086 : 327 : exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];
2087 [ + + ]: 969 : for (; except_depth > 0; --except_depth, --e) {
2088 [ + + + + ]: 642 : if (e->is_finally && e->is_active) {
2089 : : // Found an active finally handler
2090 [ + + ]: 291 : if (first_finally == NULL) {
2091 : 243 : first_finally = e;
2092 : : }
2093 [ + + ]: 291 : if (prev_finally != NULL) {
2094 : : // Mark prev finally as needed to unwind a jump
2095 : 48 : prev_finally->unwind_label = e->label;
2096 : : }
2097 : : prev_finally = e;
2098 : : }
2099 : : }
2100 [ + + ]: 327 : if (prev_finally == NULL) {
2101 : : // No finally, handle the jump ourselves
2102 : : // First, restore the exception handler address for the jump
2103 [ + - ]: 84 : if (e < emit->exc_stack) {
2104 : 84 : ASM_XOR_REG_REG(emit->as, REG_RET, REG_RET);
2105 : : } else {
2106 : 0 : ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);
2107 : : }
2108 : 84 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);
2109 : : } else {
2110 : : // Last finally should do our jump for us
2111 : : // Mark finally as needing to decide the type of jump
2112 : 243 : prev_finally->unwind_label = UNWIND_LABEL_DO_FINAL_UNWIND;
2113 : 243 : ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR);
2114 : 243 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET);
2115 : : // Cancel any active exception (see also emit_native_pop_except_jump)
2116 : 243 : ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)MP_OBJ_NULL);
2117 : 243 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET);
2118 : : // Jump to the innermost active finally
2119 : 243 : label = first_finally->label;
2120 : : }
2121 : : }
2122 : 16898 : emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR);
2123 : 16898 : }
2124 : :
2125 : 201 : static void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
2126 : : // the context manager is on the top of the stack
2127 : : // stack: (..., ctx_mgr)
2128 : :
2129 : : // get __exit__ method
2130 : 201 : vtype_kind_t vtype;
2131 : 201 : emit_access_stack(emit, 1, &vtype, REG_ARG_1); // arg1 = ctx_mgr
2132 [ - + ]: 201 : assert(vtype == VTYPE_PYOBJ);
2133 : 201 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
2134 : 201 : emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___exit__, REG_ARG_2);
2135 : : // stack: (..., ctx_mgr, __exit__, self)
2136 : :
2137 : 201 : emit_pre_pop_reg(emit, &vtype, REG_ARG_3); // self
2138 : 201 : emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // __exit__
2139 : 201 : emit_pre_pop_reg(emit, &vtype, REG_ARG_1); // ctx_mgr
2140 : 201 : emit_post_push_reg(emit, vtype, REG_ARG_2); // __exit__
2141 : 201 : emit_post_push_reg(emit, vtype, REG_ARG_3); // self
2142 : : // stack: (..., __exit__, self)
2143 : : // REG_ARG_1=ctx_mgr
2144 : :
2145 : : // get __enter__ method
2146 : 201 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
2147 : 201 : emit_call_with_qstr_arg(emit, MP_F_LOAD_METHOD, MP_QSTR___enter__, REG_ARG_2); // arg2 = method name
2148 : : // stack: (..., __exit__, self, __enter__, self)
2149 : :
2150 : : // call __enter__ method
2151 : 201 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2); // pointer to items, including meth and self
2152 : 201 : emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 0, REG_ARG_1, 0, REG_ARG_2);
2153 : 201 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // push return value of __enter__
2154 : : // stack: (..., __exit__, self, as_value)
2155 : :
2156 : : // need to commit stack because we may jump elsewhere
2157 : 201 : need_stack_settled(emit);
2158 : 201 : emit_native_push_exc_stack(emit, label, true);
2159 : :
2160 : 201 : emit_native_dup_top(emit);
2161 : : // stack: (..., __exit__, self, as_value, as_value)
2162 : 201 : }
2163 : :
2164 : 6000 : static void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) {
2165 : 6000 : DEBUG_printf("setup_block(%d, %d)\n", (int)label, kind);
2166 [ + + ]: 6000 : if (kind == MP_EMIT_SETUP_BLOCK_WITH) {
2167 : 201 : emit_native_setup_with(emit, label);
2168 : : } else {
2169 : : // Set up except and finally
2170 : 5799 : emit_native_pre(emit);
2171 : 5799 : need_stack_settled(emit);
2172 : 5799 : emit_native_push_exc_stack(emit, label, kind == MP_EMIT_SETUP_BLOCK_FINALLY);
2173 : 5799 : emit_post(emit);
2174 : : }
2175 : 6000 : }
2176 : :
2177 : 201 : static void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
2178 : : // Note: 3 labels are reserved for this function, starting at *emit->label_slot
2179 : :
2180 : : // stack: (..., __exit__, self, as_value)
2181 : 201 : emit_native_pre(emit);
2182 : 201 : emit_native_leave_exc_stack(emit, false);
2183 : 201 : adjust_stack(emit, -1);
2184 : : // stack: (..., __exit__, self)
2185 : :
2186 : : // Label for case where __exit__ is called from an unwind jump
2187 : 201 : emit_native_label_assign(emit, *emit->label_slot + 2);
2188 : :
2189 : : // call __exit__
2190 : 201 : emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);
2191 : 201 : emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);
2192 : 201 : emit_post_push_imm(emit, VTYPE_PTR_NONE, 0);
2193 : 201 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5);
2194 : 201 : emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2);
2195 : :
2196 : : // Replace exc with None and finish
2197 : 201 : emit_native_jump(emit, *emit->label_slot);
2198 : :
2199 : : // nlr_catch
2200 : : // Don't use emit_native_label_assign because this isn't a real finally label
2201 : 201 : mp_asm_base_label_assign(&emit->as->base, label);
2202 : :
2203 : : // Leave with's exception handler
2204 : 201 : emit_native_leave_exc_stack(emit, true);
2205 : :
2206 : : // Adjust stack counter for: __exit__, self (implicitly discard as_value which is above self)
2207 : 201 : emit_native_adjust_stack_size(emit, 2);
2208 : : // stack: (..., __exit__, self)
2209 : :
2210 : 201 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exc
2211 : :
2212 : : // Check if exc is MP_OBJ_NULL (i.e. zero) and jump to non-exc handler if it is
2213 : 201 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, *emit->label_slot + 2, false);
2214 : :
2215 : 201 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_1, 0); // get type(exc)
2216 : 201 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_2); // push type(exc)
2217 : 201 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_1); // push exc value
2218 : 201 : emit_post_push_imm(emit, VTYPE_PTR_NONE, 0); // traceback info
2219 : : // Stack: (..., __exit__, self, type(exc), exc, traceback)
2220 : :
2221 : : // call __exit__ method
2222 : 201 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 5);
2223 : 201 : emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, 3, REG_ARG_1, 0, REG_ARG_2);
2224 : : // Stack: (...)
2225 : :
2226 : : // If REG_RET is true then we need to replace exception with None (swallow exception)
2227 : 201 : if (REG_ARG_1 != REG_RET) {
2228 : 201 : ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_RET);
2229 : : }
2230 : 201 : emit_call(emit, MP_F_OBJ_IS_TRUE);
2231 : 201 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot + 1, true);
2232 : :
2233 : : // Replace exception with MP_OBJ_NULL.
2234 : 201 : emit_native_label_assign(emit, *emit->label_slot);
2235 : 201 : ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL);
2236 : 201 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
2237 : :
2238 : : // end of with cleanup nlr_catch block
2239 : 201 : emit_native_label_assign(emit, *emit->label_slot + 1);
2240 : :
2241 : : // Exception is in nlr_buf.ret_val slot
2242 : 201 : adjust_stack(emit, 1);
2243 : 201 : }
2244 : :
2245 : : #if MICROPY_PY_ASYNC_AWAIT
2246 : 42 : static void emit_native_async_with_setup_finally(emit_t *emit, mp_uint_t label_aexit_no_exc, mp_uint_t label_finally_block, mp_uint_t label_ret_unwind_jump) {
2247 : : // The async-with body has executed and no exception was raised, the execution fell through to this point.
2248 : : // Stack: (..., ctx_mgr)
2249 : :
2250 : : // Insert a dummy value into the stack so the stack has the same layout to execute the code starting at label_aexit_no_exc
2251 : 42 : emit_native_adjust_stack_size(emit, 1); // push dummy value, it won't ever be used
2252 : 42 : emit_native_rot_two(emit);
2253 : 42 : emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception
2254 : 42 : emit_native_rot_two(emit);
2255 : : // Stack: (..., <dummy>, None, ctx_mgr)
2256 : 42 : emit_native_jump(emit, label_aexit_no_exc); // jump to code to call __aexit__
2257 : 42 : emit_native_adjust_stack_size(emit, -1);
2258 : :
2259 : : // Start of "finally" block which is entered via one of: an exception propagating out, a return, an unwind jump.
2260 : 42 : emit_native_label_assign(emit, label_finally_block);
2261 : :
2262 : : // Detect which case we have by the local exception slot holding an exception or not.
2263 : 42 : emit_pre_pop_discard(emit);
2264 : 42 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exception
2265 : 42 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_1);
2266 : 42 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, label_ret_unwind_jump, false); // if not an exception then we have return or unwind jump.
2267 : 42 : }
2268 : : #endif
2269 : :
2270 : 6000 : static void emit_native_end_finally(emit_t *emit) {
2271 : : // logic:
2272 : : // exc = pop_stack
2273 : : // if exc == None: pass
2274 : : // else: raise exc
2275 : : // the check if exc is None is done in the MP_F_NATIVE_RAISE stub
2276 : 6000 : DEBUG_printf("end_finally\n");
2277 : :
2278 : 6000 : emit_pre_pop_discard(emit);
2279 : 6000 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit));
2280 : 6000 : emit_call(emit, MP_F_NATIVE_RAISE);
2281 : :
2282 : : // Get state for this finally and see if we need to unwind
2283 : 6000 : exc_stack_entry_t *e = emit_native_pop_exc_stack(emit);
2284 [ + + ]: 6000 : if (e->unwind_label != UNWIND_LABEL_UNUSED) {
2285 : 288 : ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_EXC_HANDLER_UNWIND(emit));
2286 : 288 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot, false);
2287 [ + + ]: 288 : if (e->unwind_label == UNWIND_LABEL_DO_FINAL_UNWIND) {
2288 : 240 : ASM_JUMP_REG(emit->as, REG_RET);
2289 : : } else {
2290 : 48 : emit_native_jump(emit, e->unwind_label);
2291 : : }
2292 : 288 : emit_native_label_assign(emit, *emit->label_slot);
2293 : : }
2294 : :
2295 : 6000 : emit_post(emit);
2296 : 6000 : }
2297 : :
2298 : 2248 : static void emit_native_get_iter(emit_t *emit, bool use_stack) {
2299 : : // perhaps the difficult one, as we want to rewrite for loops using native code
2300 : : // in cases where we iterate over a Python object, can we use normal runtime calls?
2301 : :
2302 : 2248 : DEBUG_printf("get_iter(%d)\n", use_stack);
2303 : :
2304 : 2248 : vtype_kind_t vtype;
2305 : 2248 : emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
2306 [ - + ]: 2248 : assert(vtype == VTYPE_PYOBJ);
2307 [ + + ]: 2248 : if (use_stack) {
2308 : 1263 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, MP_OBJ_ITER_BUF_NSLOTS);
2309 : 1263 : emit_call(emit, MP_F_NATIVE_GETITER);
2310 : : } else {
2311 : : // mp_getiter will allocate the iter_buf on the heap
2312 : 985 : ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0);
2313 : 985 : emit_call(emit, MP_F_NATIVE_GETITER);
2314 : 985 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2315 : : }
2316 : 2248 : }
2317 : :
2318 : 1359 : static void emit_native_for_iter(emit_t *emit, mp_uint_t label) {
2319 : 1359 : emit_native_pre(emit);
2320 : 1359 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS);
2321 : 1359 : adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS);
2322 : 1359 : emit_call(emit, MP_F_NATIVE_ITERNEXT);
2323 : : #if MICROPY_DEBUG_MP_OBJ_SENTINELS
2324 : : ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION);
2325 : : ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label);
2326 : : #else
2327 : 1359 : MP_STATIC_ASSERT(MP_OBJ_STOP_ITERATION == 0);
2328 : 1359 : ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label, false);
2329 : : #endif
2330 : 1359 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2331 : 1359 : }
2332 : :
2333 : 1359 : static void emit_native_for_iter_end(emit_t *emit) {
2334 : : // adjust stack counter (we get here from for_iter ending, which popped the value for us)
2335 : 1359 : emit_native_pre(emit);
2336 : 1359 : adjust_stack(emit, -MP_OBJ_ITER_BUF_NSLOTS);
2337 : 1359 : emit_post(emit);
2338 : 1359 : }
2339 : :
2340 : 9561 : static void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {
2341 [ + + ]: 9561 : if (within_exc_handler) {
2342 : : // Cancel any active exception so subsequent handlers don't see it
2343 : 4803 : ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL);
2344 : 4803 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
2345 : : } else {
2346 : 4758 : emit_native_leave_exc_stack(emit, false);
2347 : : }
2348 : 9561 : emit_native_jump(emit, label);
2349 : 9561 : }
2350 : :
2351 : 1292 : static void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
2352 : 1292 : vtype_kind_t vtype = peek_vtype(emit, 0);
2353 [ + + ]: 1292 : if (vtype == VTYPE_INT || vtype == VTYPE_UINT) {
2354 [ + + ]: 22 : if (op == MP_UNARY_OP_POSITIVE) {
2355 : : // No-operation, just leave the argument on the stack.
2356 [ + + ]: 16 : } else if (op == MP_UNARY_OP_NEGATIVE) {
2357 : 6 : int reg = REG_RET;
2358 : 6 : emit_pre_pop_reg_flexible(emit, &vtype, ®, reg, reg);
2359 : 6 : ASM_NEG_REG(emit->as, reg);
2360 : 6 : emit_post_push_reg(emit, vtype, reg);
2361 [ + + ]: 10 : } else if (op == MP_UNARY_OP_INVERT) {
2362 : : #ifdef ASM_NOT_REG
2363 : 6 : int reg = REG_RET;
2364 : 6 : emit_pre_pop_reg_flexible(emit, &vtype, ®, reg, reg);
2365 : 6 : ASM_NOT_REG(emit->as, reg);
2366 : : #else
2367 : : int reg = REG_RET;
2368 : : emit_pre_pop_reg_flexible(emit, &vtype, ®, REG_ARG_1, reg);
2369 : : ASM_MOV_REG_IMM(emit->as, REG_ARG_1, -1);
2370 : : ASM_XOR_REG_REG(emit->as, reg, REG_ARG_1);
2371 : : #endif
2372 : 6 : emit_post_push_reg(emit, vtype, reg);
2373 : : } else {
2374 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2375 : : MP_ERROR_TEXT("'not' not implemented"), mp_binary_op_method_name[op]);
2376 : : }
2377 [ + + ]: 1270 : } else if (vtype == VTYPE_PYOBJ) {
2378 : 1266 : emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
2379 : 1266 : emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1);
2380 : 1266 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2381 : : } else {
2382 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2383 : : MP_ERROR_TEXT("can't do unary op of '%q'"), vtype_to_qstr(vtype));
2384 : : }
2385 : 1292 : }
2386 : :
2387 : 18479 : static void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
2388 : 18479 : DEBUG_printf("binary_op(" UINT_FMT ")\n", op);
2389 : 18479 : vtype_kind_t vtype_lhs = peek_vtype(emit, 1);
2390 : 18479 : vtype_kind_t vtype_rhs = peek_vtype(emit, 0);
2391 [ + + ]: 18479 : if ((vtype_lhs == VTYPE_INT || vtype_lhs == VTYPE_UINT)
2392 [ + + ]: 878 : && (vtype_rhs == VTYPE_INT || vtype_rhs == VTYPE_UINT)) {
2393 : : // for integers, inplace and normal ops are equivalent, so use just normal ops
2394 [ + + ]: 874 : if (MP_BINARY_OP_INPLACE_OR <= op && op <= MP_BINARY_OP_INPLACE_POWER) {
2395 : 186 : op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR;
2396 : : }
2397 : :
2398 : : #if N_X64 || N_X86
2399 : : // special cases for x86 and shifting
2400 [ + + ]: 874 : if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {
2401 : : #if N_X64
2402 : 96 : emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET);
2403 : : #else
2404 : : emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET);
2405 : : #endif
2406 [ + + ]: 96 : if (op == MP_BINARY_OP_LSHIFT) {
2407 : 48 : ASM_LSL_REG(emit->as, REG_RET);
2408 : : } else {
2409 [ + + ]: 48 : if (vtype_lhs == VTYPE_UINT) {
2410 : 6 : ASM_LSR_REG(emit->as, REG_RET);
2411 : : } else {
2412 : 42 : ASM_ASR_REG(emit->as, REG_RET);
2413 : : }
2414 : : }
2415 : 96 : emit_post_push_reg(emit, vtype_lhs, REG_RET);
2416 : 212 : return;
2417 : : }
2418 : : #endif
2419 : :
2420 : : // special cases for floor-divide and module because we dispatch to helper functions
2421 [ + + ]: 778 : if (op == MP_BINARY_OP_FLOOR_DIVIDE || op == MP_BINARY_OP_MODULO) {
2422 : 20 : emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);
2423 [ + + ]: 20 : if (vtype_lhs != VTYPE_INT) {
2424 : 8 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2425 : : MP_ERROR_TEXT("div/mod not implemented for uint"), mp_binary_op_method_name[op]);
2426 : : }
2427 [ + + ]: 20 : if (op == MP_BINARY_OP_FLOOR_DIVIDE) {
2428 : 10 : emit_call(emit, MP_F_SMALL_INT_FLOOR_DIVIDE);
2429 : : } else {
2430 : 10 : emit_call(emit, MP_F_SMALL_INT_MODULO);
2431 : : }
2432 : 20 : emit_post_push_reg(emit, VTYPE_INT, REG_RET);
2433 : 20 : return;
2434 : : }
2435 : :
2436 : 758 : int reg_rhs = REG_ARG_3;
2437 : 758 : emit_pre_pop_reg_flexible(emit, &vtype_rhs, ®_rhs, REG_RET, REG_ARG_2);
2438 : 758 : emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2);
2439 : :
2440 : : #if !(N_X64 || N_X86)
2441 : : if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {
2442 : : if (op == MP_BINARY_OP_LSHIFT) {
2443 : : ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2444 : : } else {
2445 : : if (vtype_lhs == VTYPE_UINT) {
2446 : : ASM_LSR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2447 : : } else {
2448 : : ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2449 : : }
2450 : : }
2451 : : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2452 : : return;
2453 : : }
2454 : : #endif
2455 : :
2456 [ + + + + : 758 : if (op == MP_BINARY_OP_OR) {
+ + + + ]
2457 : 60 : ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2458 : 60 : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2459 : : } else if (op == MP_BINARY_OP_XOR) {
2460 : 24 : ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2461 : 24 : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2462 : : } else if (op == MP_BINARY_OP_AND) {
2463 : 60 : ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2464 : 60 : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2465 : : } else if (op == MP_BINARY_OP_ADD) {
2466 : 294 : ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2467 : 294 : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2468 : : } else if (op == MP_BINARY_OP_SUBTRACT) {
2469 : 24 : ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2470 : 24 : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2471 : : } else if (op == MP_BINARY_OP_MULTIPLY) {
2472 : 24 : ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
2473 : 24 : emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
2474 : : } else if (op == MP_BINARY_OP_LESS
2475 : : || op == MP_BINARY_OP_MORE
2476 : : || op == MP_BINARY_OP_EQUAL
2477 : : || op == MP_BINARY_OP_LESS_EQUAL
2478 : : || op == MP_BINARY_OP_MORE_EQUAL
2479 : : || op == MP_BINARY_OP_NOT_EQUAL) {
2480 : : // comparison ops
2481 : :
2482 [ + + ]: 268 : if (vtype_lhs != vtype_rhs) {
2483 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("comparison of int and uint"));
2484 : : }
2485 : :
2486 [ + + ]: 268 : size_t op_idx = op - MP_BINARY_OP_LESS + (vtype_lhs == VTYPE_UINT ? 0 : 6);
2487 : :
2488 : 268 : need_reg_single(emit, REG_RET, 0);
2489 : : #if N_X64
2490 : 268 : asm_x64_xor_r64_r64(emit->as, REG_RET, REG_RET);
2491 : 268 : asm_x64_cmp_r64_with_r64(emit->as, reg_rhs, REG_ARG_2);
2492 : 268 : static byte ops[6 + 6] = {
2493 : : // unsigned
2494 : : ASM_X64_CC_JB,
2495 : : ASM_X64_CC_JA,
2496 : : ASM_X64_CC_JE,
2497 : : ASM_X64_CC_JBE,
2498 : : ASM_X64_CC_JAE,
2499 : : ASM_X64_CC_JNE,
2500 : : // signed
2501 : : ASM_X64_CC_JL,
2502 : : ASM_X64_CC_JG,
2503 : : ASM_X64_CC_JE,
2504 : : ASM_X64_CC_JLE,
2505 : : ASM_X64_CC_JGE,
2506 : : ASM_X64_CC_JNE,
2507 : : };
2508 : 268 : asm_x64_setcc_r8(emit->as, ops[op_idx], REG_RET);
2509 : : #elif N_X86
2510 : : asm_x86_xor_r32_r32(emit->as, REG_RET, REG_RET);
2511 : : asm_x86_cmp_r32_with_r32(emit->as, reg_rhs, REG_ARG_2);
2512 : : static byte ops[6 + 6] = {
2513 : : // unsigned
2514 : : ASM_X86_CC_JB,
2515 : : ASM_X86_CC_JA,
2516 : : ASM_X86_CC_JE,
2517 : : ASM_X86_CC_JBE,
2518 : : ASM_X86_CC_JAE,
2519 : : ASM_X86_CC_JNE,
2520 : : // signed
2521 : : ASM_X86_CC_JL,
2522 : : ASM_X86_CC_JG,
2523 : : ASM_X86_CC_JE,
2524 : : ASM_X86_CC_JLE,
2525 : : ASM_X86_CC_JGE,
2526 : : ASM_X86_CC_JNE,
2527 : : };
2528 : : asm_x86_setcc_r8(emit->as, ops[op_idx], REG_RET);
2529 : : #elif N_THUMB
2530 : : asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs);
2531 : : if (asm_thumb_allow_armv7m(emit->as)) {
2532 : : static uint16_t ops[6 + 6] = {
2533 : : // unsigned
2534 : : ASM_THUMB_OP_ITE_CC,
2535 : : ASM_THUMB_OP_ITE_HI,
2536 : : ASM_THUMB_OP_ITE_EQ,
2537 : : ASM_THUMB_OP_ITE_LS,
2538 : : ASM_THUMB_OP_ITE_CS,
2539 : : ASM_THUMB_OP_ITE_NE,
2540 : : // signed
2541 : : ASM_THUMB_OP_ITE_LT,
2542 : : ASM_THUMB_OP_ITE_GT,
2543 : : ASM_THUMB_OP_ITE_EQ,
2544 : : ASM_THUMB_OP_ITE_LE,
2545 : : ASM_THUMB_OP_ITE_GE,
2546 : : ASM_THUMB_OP_ITE_NE,
2547 : : };
2548 : : asm_thumb_op16(emit->as, ops[op_idx]);
2549 : : asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1);
2550 : : asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0);
2551 : : } else {
2552 : : static uint16_t ops[6 + 6] = {
2553 : : // unsigned
2554 : : ASM_THUMB_CC_CC,
2555 : : ASM_THUMB_CC_HI,
2556 : : ASM_THUMB_CC_EQ,
2557 : : ASM_THUMB_CC_LS,
2558 : : ASM_THUMB_CC_CS,
2559 : : ASM_THUMB_CC_NE,
2560 : : // signed
2561 : : ASM_THUMB_CC_LT,
2562 : : ASM_THUMB_CC_GT,
2563 : : ASM_THUMB_CC_EQ,
2564 : : ASM_THUMB_CC_LE,
2565 : : ASM_THUMB_CC_GE,
2566 : : ASM_THUMB_CC_NE,
2567 : : };
2568 : : asm_thumb_bcc_rel9(emit->as, ops[op_idx], 6);
2569 : : asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0);
2570 : : asm_thumb_b_rel12(emit->as, 4);
2571 : : asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1);
2572 : : }
2573 : : #elif N_ARM
2574 : : asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);
2575 : : static uint ccs[6 + 6] = {
2576 : : // unsigned
2577 : : ASM_ARM_CC_CC,
2578 : : ASM_ARM_CC_HI,
2579 : : ASM_ARM_CC_EQ,
2580 : : ASM_ARM_CC_LS,
2581 : : ASM_ARM_CC_CS,
2582 : : ASM_ARM_CC_NE,
2583 : : // signed
2584 : : ASM_ARM_CC_LT,
2585 : : ASM_ARM_CC_GT,
2586 : : ASM_ARM_CC_EQ,
2587 : : ASM_ARM_CC_LE,
2588 : : ASM_ARM_CC_GE,
2589 : : ASM_ARM_CC_NE,
2590 : : };
2591 : : asm_arm_setcc_reg(emit->as, REG_RET, ccs[op_idx]);
2592 : : #elif N_XTENSA || N_XTENSAWIN
2593 : : static uint8_t ccs[6 + 6] = {
2594 : : // unsigned
2595 : : ASM_XTENSA_CC_LTU,
2596 : : 0x80 | ASM_XTENSA_CC_LTU, // for GTU we'll swap args
2597 : : ASM_XTENSA_CC_EQ,
2598 : : 0x80 | ASM_XTENSA_CC_GEU, // for LEU we'll swap args
2599 : : ASM_XTENSA_CC_GEU,
2600 : : ASM_XTENSA_CC_NE,
2601 : : // signed
2602 : : ASM_XTENSA_CC_LT,
2603 : : 0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args
2604 : : ASM_XTENSA_CC_EQ,
2605 : : 0x80 | ASM_XTENSA_CC_GE, // for LE we'll swap args
2606 : : ASM_XTENSA_CC_GE,
2607 : : ASM_XTENSA_CC_NE,
2608 : : };
2609 : : uint8_t cc = ccs[op_idx];
2610 : : if ((cc & 0x80) == 0) {
2611 : : asm_xtensa_setcc_reg_reg_reg(emit->as, cc, REG_RET, REG_ARG_2, reg_rhs);
2612 : : } else {
2613 : : asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2);
2614 : : }
2615 : : #elif N_RV32
2616 : : (void)op_idx;
2617 : : switch (op) {
2618 : : case MP_BINARY_OP_LESS:
2619 : : asm_rv32_meta_comparison_lt(emit->as, REG_ARG_2, reg_rhs, REG_RET, vtype_lhs == VTYPE_UINT);
2620 : : break;
2621 : :
2622 : : case MP_BINARY_OP_MORE:
2623 : : asm_rv32_meta_comparison_lt(emit->as, reg_rhs, REG_ARG_2, REG_RET, vtype_lhs == VTYPE_UINT);
2624 : : break;
2625 : :
2626 : : case MP_BINARY_OP_EQUAL:
2627 : : asm_rv32_meta_comparison_eq(emit->as, REG_ARG_2, reg_rhs, REG_RET);
2628 : : break;
2629 : :
2630 : : case MP_BINARY_OP_LESS_EQUAL:
2631 : : asm_rv32_meta_comparison_le(emit->as, REG_ARG_2, reg_rhs, REG_RET, vtype_lhs == VTYPE_UINT);
2632 : : break;
2633 : :
2634 : : case MP_BINARY_OP_MORE_EQUAL:
2635 : : asm_rv32_meta_comparison_le(emit->as, reg_rhs, REG_ARG_2, REG_RET, vtype_lhs == VTYPE_UINT);
2636 : : break;
2637 : :
2638 : : case MP_BINARY_OP_NOT_EQUAL:
2639 : : asm_rv32_meta_comparison_ne(emit->as, reg_rhs, REG_ARG_2, REG_RET);
2640 : : break;
2641 : :
2642 : : default:
2643 : : break;
2644 : : }
2645 : : #elif N_DEBUG
2646 : : asm_debug_setcc_reg_reg_reg(emit->as, op_idx, REG_RET, REG_ARG_2, reg_rhs);
2647 : : #else
2648 : : #error not implemented
2649 : : #endif
2650 : 268 : emit_post_push_reg(emit, VTYPE_BOOL, REG_RET);
2651 : : } else {
2652 : : // TODO other ops not yet implemented
2653 : 4 : adjust_stack(emit, 1);
2654 : 758 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2655 : : MP_ERROR_TEXT("binary op %q not implemented"), mp_binary_op_method_name[op]);
2656 : : }
2657 [ + + + - ]: 35206 : } else if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) {
2658 : 17601 : emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_3, &vtype_lhs, REG_ARG_2);
2659 : 17601 : bool invert = false;
2660 [ + + ]: 17601 : if (op == MP_BINARY_OP_NOT_IN) {
2661 : : invert = true;
2662 : : op = MP_BINARY_OP_IN;
2663 [ + + ]: 17451 : } else if (op == MP_BINARY_OP_IS_NOT) {
2664 : 576 : invert = true;
2665 : 576 : op = MP_BINARY_OP_IS;
2666 : : }
2667 : 17601 : emit_call_with_imm_arg(emit, MP_F_BINARY_OP, op, REG_ARG_1);
2668 [ + + ]: 17601 : if (invert) {
2669 : 726 : ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
2670 : 726 : emit_call_with_imm_arg(emit, MP_F_UNARY_OP, MP_UNARY_OP_NOT, REG_ARG_1);
2671 : : }
2672 : 17601 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2673 : : } else {
2674 : 4 : adjust_stack(emit, -1);
2675 : 18363 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2676 : : MP_ERROR_TEXT("can't do binary op between '%q' and '%q'"),
2677 : : vtype_to_qstr(vtype_lhs), vtype_to_qstr(vtype_rhs));
2678 : : }
2679 : : }
2680 : :
2681 : : #if MICROPY_PY_BUILTINS_SLICE
2682 : : static void emit_native_build_slice(emit_t *emit, mp_uint_t n_args);
2683 : : #endif
2684 : :
2685 : 7272 : static void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) {
2686 : : // for viper: call runtime, with types of args
2687 : : // if wrapped in byte_array, or something, allocates memory and fills it
2688 : 7272 : MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE);
2689 : 7272 : MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST);
2690 : 7272 : MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP);
2691 : 7272 : MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_F_BUILD_SET);
2692 : : #if MICROPY_PY_BUILTINS_SLICE
2693 [ + + ]: 7272 : if (kind == MP_EMIT_BUILD_SLICE) {
2694 : 906 : emit_native_build_slice(emit, n_args);
2695 : 906 : return;
2696 : : }
2697 : : #endif
2698 : 6366 : emit_native_pre(emit);
2699 [ + + ]: 6366 : if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST || kind == MP_EMIT_BUILD_SET) {
2700 : 5268 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
2701 : : }
2702 : 6366 : emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1);
2703 : 6366 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set
2704 : : }
2705 : :
2706 : 2097 : static void emit_native_store_map(emit_t *emit) {
2707 : 2097 : vtype_kind_t vtype_key, vtype_value, vtype_map;
2708 : 2097 : emit_pre_pop_reg_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3, &vtype_map, REG_ARG_1); // key, value, map
2709 [ - + ]: 2097 : assert(vtype_key == VTYPE_PYOBJ);
2710 [ - + ]: 2097 : assert(vtype_value == VTYPE_PYOBJ);
2711 [ - + ]: 2097 : assert(vtype_map == VTYPE_PYOBJ);
2712 : 2097 : emit_call(emit, MP_F_STORE_MAP);
2713 : 2097 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map
2714 : 2097 : }
2715 : :
2716 : : #if MICROPY_PY_BUILTINS_SLICE
2717 : 906 : static void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) {
2718 : 906 : DEBUG_printf("build_slice %d\n", n_args);
2719 [ + + ]: 906 : if (n_args == 2) {
2720 : 735 : vtype_kind_t vtype_start, vtype_stop;
2721 : 735 : emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
2722 [ - + ]: 735 : assert(vtype_start == VTYPE_PYOBJ);
2723 [ - + ]: 735 : assert(vtype_stop == VTYPE_PYOBJ);
2724 : 735 : emit_native_mov_reg_const(emit, REG_ARG_3, MP_F_CONST_NONE_OBJ); // arg3 = step
2725 : : } else {
2726 [ - + ]: 171 : assert(n_args == 3);
2727 : 171 : vtype_kind_t vtype_start, vtype_stop, vtype_step;
2728 : 171 : 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
2729 [ - + ]: 171 : assert(vtype_start == VTYPE_PYOBJ);
2730 [ - + ]: 171 : assert(vtype_stop == VTYPE_PYOBJ);
2731 [ - + ]: 171 : assert(vtype_step == VTYPE_PYOBJ);
2732 : : }
2733 : 906 : emit_call(emit, MP_F_NEW_SLICE);
2734 : 906 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2735 : 906 : }
2736 : : #endif
2737 : :
2738 : 189 : static void emit_native_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_index) {
2739 : 189 : mp_fun_kind_t f;
2740 [ + + ]: 189 : if (kind == SCOPE_LIST_COMP) {
2741 : 162 : vtype_kind_t vtype_item;
2742 : 162 : emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2);
2743 [ - + ]: 162 : assert(vtype_item == VTYPE_PYOBJ);
2744 : 162 : f = MP_F_LIST_APPEND;
2745 : : #if MICROPY_PY_BUILTINS_SET
2746 [ + + ]: 27 : } else if (kind == SCOPE_SET_COMP) {
2747 : 3 : vtype_kind_t vtype_item;
2748 : 3 : emit_pre_pop_reg(emit, &vtype_item, REG_ARG_2);
2749 [ - + ]: 3 : assert(vtype_item == VTYPE_PYOBJ);
2750 : 3 : f = MP_F_STORE_SET;
2751 : : #endif
2752 : : } else {
2753 : : // SCOPE_DICT_COMP
2754 : 24 : vtype_kind_t vtype_key, vtype_value;
2755 : 24 : emit_pre_pop_reg_reg(emit, &vtype_key, REG_ARG_2, &vtype_value, REG_ARG_3);
2756 [ - + ]: 24 : assert(vtype_key == VTYPE_PYOBJ);
2757 [ - + ]: 24 : assert(vtype_value == VTYPE_PYOBJ);
2758 : 24 : f = MP_F_STORE_MAP;
2759 : : }
2760 : 189 : vtype_kind_t vtype_collection;
2761 : 189 : emit_access_stack(emit, collection_index, &vtype_collection, REG_ARG_1);
2762 [ - + ]: 189 : assert(vtype_collection == VTYPE_PYOBJ);
2763 : 189 : emit_call(emit, f);
2764 : 189 : emit_post(emit);
2765 : 189 : }
2766 : :
2767 : 399 : static void emit_native_unpack_sequence(emit_t *emit, mp_uint_t n_args) {
2768 : 399 : DEBUG_printf("unpack_sequence %d\n", n_args);
2769 : 399 : vtype_kind_t vtype_base;
2770 : 399 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
2771 [ - + ]: 399 : assert(vtype_base == VTYPE_PYOBJ);
2772 : 399 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr
2773 : 399 : emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, n_args, REG_ARG_2); // arg2 = n_args
2774 : 399 : }
2775 : :
2776 : 99 : static void emit_native_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
2777 : 99 : DEBUG_printf("unpack_ex %d %d\n", n_left, n_right);
2778 : 99 : vtype_kind_t vtype_base;
2779 : 99 : emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
2780 [ - + ]: 99 : assert(vtype_base == VTYPE_PYOBJ);
2781 : 99 : emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr
2782 : 99 : emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right
2783 : 99 : }
2784 : :
2785 : 8505 : static void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
2786 : : // call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them
2787 : 8505 : emit_native_pre(emit);
2788 : 8505 : emit_native_mov_reg_state(emit, REG_ARG_2, LOCAL_IDX_FUN_OBJ(emit));
2789 : 8505 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_2, OFFSETOF_OBJ_FUN_BC_CONTEXT);
2790 [ + + ]: 8505 : if (n_pos_defaults == 0 && n_kw_defaults == 0) {
2791 : 8052 : need_reg_all(emit);
2792 : 8052 : ASM_MOV_REG_IMM(emit->as, REG_ARG_3, 0);
2793 : : } else {
2794 : 453 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2);
2795 : 453 : need_reg_all(emit);
2796 : : }
2797 : 8505 : emit_load_reg_with_child(emit, REG_ARG_1, scope->raw_code);
2798 : 8505 : ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_PROTO_FUN);
2799 : 8505 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2800 : 8505 : }
2801 : :
2802 : 213 : static void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
2803 : : // make function
2804 : 213 : emit_native_pre(emit);
2805 : 213 : emit_native_mov_reg_state(emit, REG_ARG_2, LOCAL_IDX_FUN_OBJ(emit));
2806 : 213 : ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_2, OFFSETOF_OBJ_FUN_BC_CONTEXT);
2807 [ + + ]: 213 : if (n_pos_defaults == 0 && n_kw_defaults == 0) {
2808 : 210 : need_reg_all(emit);
2809 : 210 : ASM_MOV_REG_IMM(emit->as, REG_ARG_3, 0);
2810 : : } else {
2811 : 3 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_closed_over);
2812 : 3 : adjust_stack(emit, 2 + n_closed_over);
2813 : 3 : need_reg_all(emit);
2814 : : }
2815 : 213 : emit_load_reg_with_child(emit, REG_ARG_1, scope->raw_code);
2816 : 213 : ASM_CALL_IND(emit->as, MP_F_MAKE_FUNCTION_FROM_PROTO_FUN);
2817 : :
2818 : : // make closure
2819 : : #if REG_ARG_1 != REG_RET
2820 : 213 : ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_RET);
2821 : : #endif
2822 : 213 : ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over);
2823 : 213 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over);
2824 [ + + ]: 213 : if (n_pos_defaults != 0 || n_kw_defaults != 0) {
2825 : 3 : adjust_stack(emit, -2);
2826 : : }
2827 : 213 : ASM_CALL_IND(emit->as, MP_F_NEW_CLOSURE);
2828 : 213 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2829 : 213 : }
2830 : :
2831 : 44306 : static void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
2832 : 44306 : DEBUG_printf("call_function(n_pos=" UINT_FMT ", n_kw=" UINT_FMT ", star_flags=" UINT_FMT ")\n", n_positional, n_keyword, star_flags);
2833 : :
2834 : : // TODO: in viper mode, call special runtime routine with type info for args,
2835 : : // and wanted type info for return, to remove need for boxing/unboxing
2836 : :
2837 : 44306 : emit_native_pre(emit);
2838 : 44306 : vtype_kind_t vtype_fun = peek_vtype(emit, n_positional + 2 * n_keyword);
2839 [ + + ]: 44306 : if (vtype_fun == VTYPE_BUILTIN_CAST) {
2840 : : // casting operator
2841 [ - + ]: 96 : assert(n_positional == 1 && n_keyword == 0);
2842 [ - + ]: 96 : assert(!star_flags);
2843 : 96 : DEBUG_printf(" cast to %d\n", vtype_fun);
2844 : 96 : vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm;
2845 [ + + + ]: 96 : switch (peek_vtype(emit, 0)) {
2846 : 78 : case VTYPE_PYOBJ: {
2847 : 78 : vtype_kind_t vtype;
2848 : 78 : emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
2849 : 78 : emit_pre_pop_discard(emit);
2850 : 78 : emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, vtype_cast, REG_ARG_2); // arg2 = type
2851 : 78 : emit_post_push_reg(emit, vtype_cast, REG_RET);
2852 : 78 : break;
2853 : : }
2854 : 14 : case VTYPE_BOOL:
2855 : : case VTYPE_INT:
2856 : : case VTYPE_UINT:
2857 : : case VTYPE_PTR:
2858 : : case VTYPE_PTR8:
2859 : : case VTYPE_PTR16:
2860 : : case VTYPE_PTR32:
2861 : : case VTYPE_PTR_NONE:
2862 : 14 : emit_fold_stack_top(emit, REG_ARG_1);
2863 : 14 : emit_post_top_set_vtype(emit, vtype_cast);
2864 : 14 : break;
2865 : : default:
2866 : : // this can happen when casting a cast: int(int)
2867 : 4 : mp_raise_NotImplementedError(MP_ERROR_TEXT("casting"));
2868 : : }
2869 : : } else {
2870 [ - + ]: 44210 : assert(vtype_fun == VTYPE_PYOBJ);
2871 [ + + ]: 44210 : if (star_flags) {
2872 : 336 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 2); // pointer to args
2873 : 336 : emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 0, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2);
2874 : 336 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2875 : : } else {
2876 [ + + ]: 43874 : if (n_positional != 0 || n_keyword != 0) {
2877 : 40340 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword); // pointer to args
2878 : : }
2879 : 43870 : emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function
2880 : 43870 : emit_call_with_imm_arg(emit, MP_F_NATIVE_CALL_FUNCTION_N_KW, n_positional | (n_keyword << 8), REG_ARG_2);
2881 : 43870 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2882 : : }
2883 : : }
2884 : 44298 : }
2885 : :
2886 : 15261 : static void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
2887 : 15261 : DEBUG_printf("call_method(%d, %d, %d)\n", n_positional, n_keyword, star_flags);
2888 [ + + ]: 15261 : if (star_flags) {
2889 : 114 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 3); // pointer to args
2890 : 114 : emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 1, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2);
2891 : 114 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2892 : : } else {
2893 : 15147 : emit_native_pre(emit);
2894 : 15147 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_positional + 2 * n_keyword); // pointer to items, including meth and self
2895 : 15147 : emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, n_positional, REG_ARG_1, n_keyword, REG_ARG_2);
2896 : 15147 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
2897 : : }
2898 : 15261 : }
2899 : :
2900 : 16553 : static void emit_native_return_value(emit_t *emit) {
2901 : 16553 : DEBUG_printf("return_value\n");
2902 : :
2903 [ + + ]: 16553 : if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) {
2904 : : // Save pointer to current stack position for caller to access return value
2905 : 1143 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1);
2906 : 1143 : emit_native_mov_state_reg(emit, OFFSETOF_CODE_STATE_SP, REG_TEMP0);
2907 : :
2908 : : // Put return type in return value slot
2909 : 1143 : ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_NORMAL);
2910 : 1143 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_TEMP0);
2911 : :
2912 : : // Do the unwinding jump to get to the return handler
2913 : 1143 : emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size);
2914 : 1143 : return;
2915 : : }
2916 : :
2917 [ + + ]: 15410 : if (emit->do_viper_types) {
2918 : 1028 : vtype_kind_t return_vtype = emit->scope->scope_flags >> MP_SCOPE_FLAG_VIPERRET_POS;
2919 [ + + ]: 1028 : if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) {
2920 : 712 : emit_pre_pop_discard(emit);
2921 [ + + ]: 712 : if (return_vtype == VTYPE_PYOBJ) {
2922 : 504 : emit_native_mov_reg_const(emit, REG_PARENT_RET, MP_F_CONST_NONE_OBJ);
2923 : : } else {
2924 : 208 : ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0);
2925 : : }
2926 : : } else {
2927 : 316 : vtype_kind_t vtype;
2928 [ + + ]: 512 : emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_PARENT_RET : REG_ARG_1);
2929 [ + + ]: 316 : if (vtype != return_vtype) {
2930 : 316 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
2931 : : MP_ERROR_TEXT("return expected '%q' but got '%q'"),
2932 : : vtype_to_qstr(return_vtype), vtype_to_qstr(vtype));
2933 : : }
2934 : : }
2935 [ + + ]: 1028 : if (return_vtype != VTYPE_PYOBJ) {
2936 : 404 : emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2);
2937 : : #if REG_RET != REG_PARENT_RET
2938 : : ASM_MOV_REG_REG(emit->as, REG_PARENT_RET, REG_RET);
2939 : : #endif
2940 : : }
2941 : : } else {
2942 : 14382 : vtype_kind_t vtype;
2943 : 14382 : emit_pre_pop_reg(emit, &vtype, REG_PARENT_RET);
2944 [ - + ]: 14382 : assert(vtype == VTYPE_PYOBJ);
2945 : : }
2946 [ + + + + ]: 15410 : if (NEED_GLOBAL_EXC_HANDLER(emit)) {
2947 : : // Save return value for the global exception handler to use
2948 : 10665 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_PARENT_RET);
2949 : : }
2950 : 15410 : emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size);
2951 : : }
2952 : :
2953 : 3112 : static void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {
2954 : 3112 : DEBUG_printf("raise_varargs(%d)\n", n_args);
2955 : 3112 : (void)n_args;
2956 [ - + ]: 3112 : assert(n_args == 1);
2957 : 3112 : vtype_kind_t vtype_exc;
2958 : 3112 : emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise
2959 [ + + ]: 3112 : if (vtype_exc != VTYPE_PYOBJ) {
2960 : 4 : EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("must raise an object"));
2961 : : }
2962 : : // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type))
2963 : 3112 : emit_call(emit, MP_F_NATIVE_RAISE);
2964 : 3112 : mp_asm_base_suppress_code(&emit->as->base);
2965 : 3112 : }
2966 : :
2967 : 1385 : static void emit_native_yield(emit_t *emit, int kind) {
2968 : : // Note: 1 (yield) or 3 (yield from) labels are reserved for this function, starting at *emit->label_slot
2969 : :
2970 : 1385 : DEBUG_printf("yield(%d)\n", kind);
2971 : :
2972 [ + + ]: 1385 : if (emit->do_viper_types) {
2973 : 8 : mp_raise_NotImplementedError(MP_ERROR_TEXT("native yield"));
2974 : : }
2975 : 1377 : emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
2976 : :
2977 : 1377 : need_stack_settled(emit);
2978 : :
2979 [ + + ]: 1377 : if (kind == MP_EMIT_YIELD_FROM) {
2980 : :
2981 : : // Top of yield-from loop, conceptually implementing:
2982 : : // for item in generator:
2983 : : // yield item
2984 : :
2985 : : // Jump to start of loop
2986 : 885 : emit_native_jump(emit, *emit->label_slot + 2);
2987 : :
2988 : : // Label for top of loop
2989 : 885 : emit_native_label_assign(emit, *emit->label_slot + 1);
2990 : : }
2991 : :
2992 : : // Save pointer to current stack position for caller to access yielded value
2993 : 1377 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_TEMP0, 1);
2994 : 1377 : emit_native_mov_state_reg(emit, OFFSETOF_CODE_STATE_SP, REG_TEMP0);
2995 : :
2996 : : // Put return type in return value slot
2997 : 1377 : ASM_MOV_REG_IMM(emit->as, REG_TEMP0, MP_VM_RETURN_YIELD);
2998 : 1377 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_TEMP0);
2999 : :
3000 : : // Save re-entry PC
3001 : 1377 : ASM_MOV_REG_PCREL(emit->as, REG_TEMP0, *emit->label_slot);
3002 : 1377 : emit_native_mov_state_reg(emit, LOCAL_IDX_GEN_PC(emit), REG_TEMP0);
3003 : :
3004 : : // Jump to exit handler
3005 : 1377 : ASM_JUMP(emit->as, emit->exit_label);
3006 : :
3007 : : // Label re-entry point
3008 : 1377 : mp_asm_base_label_assign(&emit->as->base, *emit->label_slot);
3009 : :
3010 : : // Re-open any active exception handler
3011 [ + + ]: 1377 : if (emit->exc_stack_size > 0) {
3012 : : // Find innermost active exception handler, to restore as current handler
3013 : 405 : exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];
3014 [ + + ]: 501 : for (; e >= emit->exc_stack; --e) {
3015 [ + + ]: 441 : if (e->is_active) {
3016 : : // Found active handler, get its PC
3017 : 345 : ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);
3018 : 345 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);
3019 : 345 : break;
3020 : : }
3021 : : }
3022 : : }
3023 : :
3024 : 1377 : emit_native_adjust_stack_size(emit, 1); // send_value
3025 : :
3026 [ + + ]: 1377 : if (kind == MP_EMIT_YIELD_VALUE) {
3027 : : // Check LOCAL_IDX_THROW_VAL for any injected value
3028 : 492 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit));
3029 : 492 : ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL);
3030 : 492 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2);
3031 : 492 : emit_call(emit, MP_F_NATIVE_RAISE);
3032 : : } else {
3033 : : // Label loop entry
3034 : 885 : emit_native_label_assign(emit, *emit->label_slot + 2);
3035 : :
3036 : : // Get the next item from the delegate generator
3037 : 885 : ASM_MOV_REG_LOCAL(emit->as, REG_ARG_3, LOCAL_IDX_THROW_VAL(emit)); // throw_value
3038 : 885 : ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL);
3039 : 885 : ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2);
3040 : 885 : vtype_kind_t vtype;
3041 : 885 : emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // send_value
3042 : 885 : emit_access_stack(emit, 1, &vtype, REG_ARG_1); // generator
3043 : 885 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_3);
3044 : 885 : emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 1); // ret_value
3045 : 885 : emit_call(emit, MP_F_NATIVE_YIELD_FROM);
3046 : :
3047 : : // If returned non-zero then generator continues
3048 : 885 : ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, *emit->label_slot + 1, true);
3049 : :
3050 : : // Pop exhausted gen, replace with ret_value
3051 : 885 : emit_native_adjust_stack_size(emit, 1); // ret_value
3052 : 885 : emit_fold_stack_top(emit, REG_ARG_1);
3053 : : }
3054 : 1377 : }
3055 : :
3056 : 4758 : static void emit_native_start_except_handler(emit_t *emit) {
3057 : : // Protected block has finished so leave the current exception handler
3058 : 4758 : emit_native_leave_exc_stack(emit, true);
3059 : :
3060 : : // Get and push nlr_buf.ret_val
3061 : 4758 : ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, LOCAL_IDX_EXC_VAL(emit));
3062 : 4758 : emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0);
3063 : 4758 : }
3064 : :
3065 : 4758 : static void emit_native_end_except_handler(emit_t *emit) {
3066 : 4758 : }
3067 : :
3068 : : const emit_method_table_t EXPORT_FUN(method_table) = {
3069 : : #if MICROPY_DYNAMIC_COMPILER
3070 : : EXPORT_FUN(new),
3071 : : EXPORT_FUN(free),
3072 : : #endif
3073 : :
3074 : : emit_native_start_pass,
3075 : : emit_native_end_pass,
3076 : : emit_native_adjust_stack_size,
3077 : : emit_native_set_source_line,
3078 : :
3079 : : {
3080 : : emit_native_load_local,
3081 : : emit_native_load_global,
3082 : : },
3083 : : {
3084 : : emit_native_store_local,
3085 : : emit_native_store_global,
3086 : : },
3087 : : {
3088 : : emit_native_delete_local,
3089 : : emit_native_delete_global,
3090 : : },
3091 : :
3092 : : emit_native_label_assign,
3093 : : emit_native_import,
3094 : : emit_native_load_const_tok,
3095 : : emit_native_load_const_small_int,
3096 : : emit_native_load_const_str,
3097 : : emit_native_load_const_obj,
3098 : : emit_native_load_null,
3099 : : emit_native_load_method,
3100 : : emit_native_load_build_class,
3101 : : emit_native_subscr,
3102 : : emit_native_attr,
3103 : : emit_native_dup_top,
3104 : : emit_native_dup_top_two,
3105 : : emit_native_pop_top,
3106 : : emit_native_rot_two,
3107 : : emit_native_rot_three,
3108 : : emit_native_jump,
3109 : : emit_native_pop_jump_if,
3110 : : emit_native_jump_if_or_pop,
3111 : : emit_native_unwind_jump,
3112 : : emit_native_setup_block,
3113 : : emit_native_with_cleanup,
3114 : : #if MICROPY_PY_ASYNC_AWAIT
3115 : : emit_native_async_with_setup_finally,
3116 : : #endif
3117 : : emit_native_end_finally,
3118 : : emit_native_get_iter,
3119 : : emit_native_for_iter,
3120 : : emit_native_for_iter_end,
3121 : : emit_native_pop_except_jump,
3122 : : emit_native_unary_op,
3123 : : emit_native_binary_op,
3124 : : emit_native_build,
3125 : : emit_native_store_map,
3126 : : emit_native_store_comp,
3127 : : emit_native_unpack_sequence,
3128 : : emit_native_unpack_ex,
3129 : : emit_native_make_function,
3130 : : emit_native_make_closure,
3131 : : emit_native_call_function,
3132 : : emit_native_call_method,
3133 : : emit_native_return_value,
3134 : : emit_native_raise_varargs,
3135 : : emit_native_yield,
3136 : :
3137 : : emit_native_start_except_handler,
3138 : : emit_native_end_except_handler,
3139 : : };
3140 : :
3141 : : #endif
|