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