blob: a07657408fabe505bf7a443d1cc481ff6470e474 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
Alexander Steffen55f33242017-06-30 09:22:17 +02002 * This file is part of the MicroPython project, http://micropython.org/
Damien George04b91472014-05-03 23:27:38 +01003 *
4 * The MIT License (MIT)
5 *
Damien George8e7745e2019-08-22 14:55:16 +10006 * Copyright (c) 2013-2019 Damien P. George
Damien George04b91472014-05-03 23:27:38 +01007 *
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
xbeefe34222014-03-16 00:14:26 -070027#include <stdbool.h>
Damien429d7192013-10-04 19:53:11 +010028#include <stdint.h>
29#include <stdio.h>
30#include <string.h>
Damien George538c3c02022-03-16 09:37:58 +110031#include <unistd.h>
Damien429d7192013-10-04 19:53:11 +010032#include <assert.h>
33
Damien Georgeb4b10fd2015-01-01 23:30:53 +000034#include "py/mpstate.h"
Damien Georgee3de7232022-03-31 23:59:10 +110035#include "py/smallint.h"
Damien George51dfcb42015-01-01 20:27:54 +000036#include "py/emit.h"
37#include "py/bc0.h"
Damien429d7192013-10-04 19:53:11 +010038
Damien Georgedd5353a2015-12-18 12:35:44 +000039#if MICROPY_ENABLE_COMPILER
40
Damien Georgef2040bf2021-10-22 22:22:47 +110041#define DUMMY_DATA_SIZE (MP_ENCODE_UINT_MAX_BYTES)
Damien George95977712014-05-10 18:07:08 +010042
Damien415eb6f2013-10-05 12:19:06 +010043struct _emit_t {
Damien George999cedb2015-11-27 17:01:44 +000044 // Accessed as mp_obj_t, so must be aligned as such, and we rely on the
45 // memory allocator returning a suitably aligned pointer.
46 // Should work for cases when mp_obj_t is 64-bit on a 32-bit machine.
47 byte dummy_data[DUMMY_DATA_SIZE];
48
Damien George0fb80c32014-05-10 18:16:21 +010049 pass_kind_t pass : 8;
Damien George0fb80c32014-05-10 18:16:21 +010050
Damien Georgea5063352022-06-17 23:14:32 +100051 // Set to true if the code generator should suppress emitted code due to it
52 // being dead code. This can happen when opcodes immediately follow an
53 // unconditional flow control (eg jump or raise).
54 bool suppress;
55
Damien429d7192013-10-04 19:53:11 +010056 int stack_size;
Damien429d7192013-10-04 19:53:11 +010057
Damien Georgef2040bf2021-10-22 22:22:47 +110058 mp_emit_common_t *emit_common;
Damien429d7192013-10-04 19:53:11 +010059 scope_t *scope;
60
Damien George7ff996c2014-09-08 23:05:16 +010061 mp_uint_t last_source_line_offset;
62 mp_uint_t last_source_line;
Damien George08335002014-01-18 23:24:36 +000063
Damien George538c3c02022-03-16 09:37:58 +110064 size_t max_num_labels;
65 size_t *label_offsets;
Damien429d7192013-10-04 19:53:11 +010066
Damien George999cedb2015-11-27 17:01:44 +000067 size_t code_info_offset;
68 size_t code_info_size;
69 size_t bytecode_offset;
70 size_t bytecode_size;
Damien George08335002014-01-18 23:24:36 +000071 byte *code_base; // stores both byte code and code info
Damien Georgeacd2c5c2022-03-18 13:18:59 +110072 bool overflow;
Damien Georgec8e9c0d2015-11-02 17:27:18 +000073
Damien Georgec8c0fd42019-09-25 15:45:47 +100074 size_t n_info;
75 size_t n_cell;
Damien429d7192013-10-04 19:53:11 +010076};
77
Damien Georgef2040bf2021-10-22 22:22:47 +110078emit_t *emit_bc_new(mp_emit_common_t *emit_common) {
Damien George08335002014-01-18 23:24:36 +000079 emit_t *emit = m_new0(emit_t, 1);
Damien Georgef2040bf2021-10-22 22:22:47 +110080 emit->emit_common = emit_common;
Damien Georgea210c772015-03-26 15:49:53 +000081 return emit;
82}
83
Damien George4dea9222015-04-09 15:29:54 +000084void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) {
Damien6cdd3af2013-10-05 18:08:26 +010085 emit->max_num_labels = max_num_labels;
Damien George538c3c02022-03-16 09:37:58 +110086 emit->label_offsets = m_new(size_t, emit->max_num_labels);
Damien6cdd3af2013-10-05 18:08:26 +010087}
Damien4b03e772013-10-05 14:17:09 +010088
Damien George41d02b62014-01-24 22:42:28 +000089void emit_bc_free(emit_t *emit) {
Damien George538c3c02022-03-16 09:37:58 +110090 m_del(size_t, emit->label_offsets, emit->max_num_labels);
Paul Sokolovskyf46d87a2014-01-24 16:20:11 +020091 m_del_obj(emit_t, emit);
92}
93
Damien George08335002014-01-18 23:24:36 +000094// all functions must go through this one to emit code info
Damien Georgef2040bf2021-10-22 22:22:47 +110095STATIC uint8_t *emit_get_cur_to_write_code_info(void *emit_in, size_t num_bytes_to_write) {
96 emit_t *emit = emit_in;
Damien George36db6bc2014-05-07 17:24:22 +010097 if (emit->pass < MP_PASS_EMIT) {
Damien George08335002014-01-18 23:24:36 +000098 emit->code_info_offset += num_bytes_to_write;
Damien429d7192013-10-04 19:53:11 +010099 return emit->dummy_data;
100 } else {
Damien George08335002014-01-18 23:24:36 +0000101 assert(emit->code_info_offset + num_bytes_to_write <= emit->code_info_size);
102 byte *c = emit->code_base + emit->code_info_offset;
103 emit->code_info_offset += num_bytes_to_write;
Damien429d7192013-10-04 19:53:11 +0100104 return c;
105 }
106}
107
Damien George69661f32020-02-27 15:36:53 +1100108STATIC void emit_write_code_info_byte(emit_t *emit, byte val) {
Damien George9b7f5832015-03-18 17:47:47 +0000109 *emit_get_cur_to_write_code_info(emit, 1) = val;
110}
111
Damien George4dea9222015-04-09 15:29:54 +0000112STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) {
Damien Georgef2040bf2021-10-22 22:22:47 +1100113 mp_encode_uint(emit, emit_get_cur_to_write_code_info, mp_emit_common_use_qstr(emit->emit_common, qst));
Damien George08335002014-01-18 23:24:36 +0000114}
115
Damien George73496fb2014-04-13 14:51:56 +0100116#if MICROPY_ENABLE_SOURCE_LINE
Damien George4dea9222015-04-09 15:29:54 +0000117STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) {
Damien George73496fb2014-04-13 14:51:56 +0100118 assert(bytes_to_skip > 0 || lines_to_skip > 0);
119 while (bytes_to_skip > 0 || lines_to_skip > 0) {
Damien George4747bec2014-07-31 16:12:01 +0000120 mp_uint_t b, l;
Damien Georgecc2dbdd2017-02-10 11:58:10 +1100121 if (lines_to_skip <= 6 || bytes_to_skip > 0xf) {
Damien George4747bec2014-07-31 16:12:01 +0000122 // use 0b0LLBBBBB encoding
123 b = MIN(bytes_to_skip, 0x1f);
Damien Georgecc2dbdd2017-02-10 11:58:10 +1100124 if (b < bytes_to_skip) {
125 // we can't skip any lines until we skip all the bytes
126 l = 0;
127 } else {
128 l = MIN(lines_to_skip, 0x3);
129 }
Damien George4747bec2014-07-31 16:12:01 +0000130 *emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
131 } else {
132 // use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)
133 b = MIN(bytes_to_skip, 0xf);
134 l = MIN(lines_to_skip, 0x7ff);
135 byte *ci = emit_get_cur_to_write_code_info(emit, 2);
136 ci[0] = 0x80 | b | ((l >> 4) & 0x70);
137 ci[1] = l;
138 }
Damien George73496fb2014-04-13 14:51:56 +0100139 bytes_to_skip -= b;
140 lines_to_skip -= l;
Damien George28eb5772014-01-25 11:43:20 +0000141 }
Damien George08335002014-01-18 23:24:36 +0000142}
Damien George73496fb2014-04-13 14:51:56 +0100143#endif
Damien George08335002014-01-18 23:24:36 +0000144
145// all functions must go through this one to emit byte code
Damien Georgef2040bf2021-10-22 22:22:47 +1100146STATIC uint8_t *emit_get_cur_to_write_bytecode(void *emit_in, size_t num_bytes_to_write) {
147 emit_t *emit = emit_in;
Damien Georgea5063352022-06-17 23:14:32 +1000148 if (emit->suppress) {
149 return emit->dummy_data;
150 }
Damien George36db6bc2014-05-07 17:24:22 +0100151 if (emit->pass < MP_PASS_EMIT) {
Damien George3417bc22014-05-10 10:36:38 +0100152 emit->bytecode_offset += num_bytes_to_write;
Damien George08335002014-01-18 23:24:36 +0000153 return emit->dummy_data;
154 } else {
Damien George3417bc22014-05-10 10:36:38 +0100155 assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size);
156 byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset;
157 emit->bytecode_offset += num_bytes_to_write;
Damien George08335002014-01-18 23:24:36 +0000158 return c;
159 }
160}
161
Damien George8e7745e2019-08-22 14:55:16 +1000162STATIC void emit_write_bytecode_raw_byte(emit_t *emit, byte b1) {
Damien George4dea9222015-04-09 15:29:54 +0000163 byte *c = emit_get_cur_to_write_bytecode(emit, 1);
Damien429d7192013-10-04 19:53:11 +0100164 c[0] = b1;
165}
166
Damien George8e7745e2019-08-22 14:55:16 +1000167STATIC void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) {
168 mp_emit_bc_adjust_stack_size(emit, stack_adj);
169 byte *c = emit_get_cur_to_write_bytecode(emit, 1);
170 c[0] = b1;
171}
172
Damien Georgef2040bf2021-10-22 22:22:47 +1100173// Similar to mp_encode_uint(), just some extra handling to encode sign
Damien George8e7745e2019-08-22 14:55:16 +1000174STATIC void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) {
175 emit_write_bytecode_byte(emit, stack_adj, b1);
Paul Sokolovsky047cd402014-02-19 15:47:59 +0200176
177 // We store each 7 bits in a separate byte, and that's how many bytes needed
Damien Georgef2040bf2021-10-22 22:22:47 +1100178 byte buf[MP_ENCODE_UINT_MAX_BYTES];
Paul Sokolovsky047cd402014-02-19 15:47:59 +0200179 byte *p = buf + sizeof(buf);
180 // We encode in little-ending order, but store in big-endian, to help decoding
181 do {
182 *--p = num & 0x7f;
183 num >>= 7;
184 } while (num != 0 && num != -1);
185 // Make sure that highest bit we stored (mask 0x40) matches sign
186 // of the number. If not, store extra byte just to encode sign
187 if (num == -1 && (*p & 0x40) == 0) {
188 *--p = 0x7f;
189 } else if (num == 0 && (*p & 0x40) != 0) {
190 *--p = 0;
191 }
192
Damien George4dea9222015-04-09 15:29:54 +0000193 byte *c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);
Paul Sokolovsky047cd402014-02-19 15:47:59 +0200194 while (p != buf + sizeof(buf) - 1) {
195 *c++ = *p++ | 0x80;
196 }
197 *c = *p;
Damien429d7192013-10-04 19:53:11 +0100198}
199
Damien George8e7745e2019-08-22 14:55:16 +1000200STATIC void emit_write_bytecode_byte_uint(emit_t *emit, int stack_adj, byte b, mp_uint_t val) {
201 emit_write_bytecode_byte(emit, stack_adj, b);
Damien Georgef2040bf2021-10-22 22:22:47 +1100202 mp_encode_uint(emit, emit_get_cur_to_write_bytecode, val);
Damien429d7192013-10-04 19:53:11 +0100203}
204
Damien Georgef2040bf2021-10-22 22:22:47 +1100205STATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n) {
Damien George8e7745e2019-08-22 14:55:16 +1000206 emit_write_bytecode_byte_uint(emit, stack_adj, b, n);
Damien Georgec8e9c0d2015-11-02 17:27:18 +0000207}
Damien Georgedf8127a2014-04-13 11:04:33 +0100208
Damien George69661f32020-02-27 15:36:53 +1100209STATIC void emit_write_bytecode_byte_qstr(emit_t *emit, int stack_adj, byte b, qstr qst) {
Damien Georgef2040bf2021-10-22 22:22:47 +1100210 emit_write_bytecode_byte_uint(emit, stack_adj, b, mp_emit_common_use_qstr(emit->emit_common, qst));
Damien Georgec8e9c0d2015-11-02 17:27:18 +0000211}
212
Damien George8e7745e2019-08-22 14:55:16 +1000213STATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp_obj_t obj) {
Damien George85885252022-05-07 15:51:41 +1000214 emit_write_bytecode_byte_const(emit, stack_adj, b, mp_emit_common_use_const_obj(emit->emit_common, obj));
Damien Georgec8e9c0d2015-11-02 17:27:18 +0000215}
216
Damien Georgef2040bf2021-10-22 22:22:47 +1100217STATIC void emit_write_bytecode_byte_child(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) {
Damien George8e7745e2019-08-22 14:55:16 +1000218 emit_write_bytecode_byte_const(emit, stack_adj, b,
Damien Georgef2040bf2021-10-22 22:22:47 +1100219 mp_emit_common_alloc_const_child(emit->emit_common, rc));
Milan Rossa310b3d12019-08-14 16:09:36 +0200220 #if MICROPY_PY_SYS_SETTRACE
221 rc->line_of_definition = emit->last_source_line;
222 #endif
Damien429d7192013-10-04 19:53:11 +0100223}
224
Damien George538c3c02022-03-16 09:37:58 +1100225// Emit a jump opcode to a destination label.
226// The offset to the label is relative to the ip following this instruction.
227// The offset is encoded as either 1 or 2 bytes, depending on how big it is.
228// The encoding of this jump opcode can change size from one pass to the next,
229// but it must only ever decrease in size on successive passes.
230STATIC void emit_write_bytecode_byte_label(emit_t *emit, int stack_adj, byte b1, mp_uint_t label) {
Damien George8e7745e2019-08-22 14:55:16 +1000231 mp_emit_bc_adjust_stack_size(emit, stack_adj);
Damien03c9cfb2013-11-05 22:06:08 +0000232
Damien Georgea5063352022-06-17 23:14:32 +1000233 if (emit->suppress) {
234 return;
235 }
236
Damien George538c3c02022-03-16 09:37:58 +1100237 // Determine if the jump offset is signed or unsigned, based on the opcode.
Damien George6d11c692022-03-21 16:36:13 +1100238 const bool is_signed = b1 <= MP_BC_POP_JUMP_IF_FALSE;
Damien George538c3c02022-03-16 09:37:58 +1100239
240 // Default to a 2-byte encoding (the largest) with an unknown jump offset.
241 unsigned int jump_encoding_size = 1;
242 ssize_t bytecode_offset = 0;
243
244 // Compute the jump size and offset only when code size is known.
245 if (emit->pass >= MP_PASS_CODE_SIZE) {
246 // The -2 accounts for this jump opcode taking 2 bytes (at least).
247 bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 2;
248
249 // Check if the bytecode_offset is small enough to use a 1-byte encoding.
250 if ((is_signed && -64 <= bytecode_offset && bytecode_offset <= 63)
251 || (!is_signed && (size_t)bytecode_offset <= 127)) {
252 // Use a 1-byte jump offset.
253 jump_encoding_size = 0;
254 }
255
256 // Adjust the offset depending on the size of the encoding of the offset.
257 bytecode_offset -= jump_encoding_size;
258
259 assert(is_signed || bytecode_offset >= 0);
Damien03c9cfb2013-11-05 22:06:08 +0000260 }
Damien George538c3c02022-03-16 09:37:58 +1100261
262 // Emit the opcode.
263 byte *c = emit_get_cur_to_write_bytecode(emit, 2 + jump_encoding_size);
Damien03c9cfb2013-11-05 22:06:08 +0000264 c[0] = b1;
Damien George538c3c02022-03-16 09:37:58 +1100265 if (jump_encoding_size == 0) {
266 if (is_signed) {
267 bytecode_offset += 0x40;
268 }
269 assert(0 <= bytecode_offset && bytecode_offset <= 0x7f);
270 c[1] = bytecode_offset;
271 } else {
272 if (is_signed) {
273 bytecode_offset += 0x4000;
274 }
Damien Georgeacd2c5c2022-03-18 13:18:59 +1100275 if (emit->pass == MP_PASS_EMIT && !(0 <= bytecode_offset && bytecode_offset <= 0x7fff)) {
276 emit->overflow = true;
277 }
Damien George538c3c02022-03-16 09:37:58 +1100278 c[1] = 0x80 | (bytecode_offset & 0x7f);
279 c[2] = bytecode_offset >> 7;
280 }
Damien429d7192013-10-04 19:53:11 +0100281}
282
Damien George41125902015-03-26 16:44:14 +0000283void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
Damien George6baf76e2013-12-30 22:32:17 +0000284 emit->pass = pass;
285 emit->stack_size = 0;
Damien Georgea5063352022-06-17 23:14:32 +1000286 emit->suppress = false;
Damien George6baf76e2013-12-30 22:32:17 +0000287 emit->scope = scope;
Damien George08335002014-01-18 23:24:36 +0000288 emit->last_source_line_offset = 0;
289 emit->last_source_line = 1;
Damien George3417bc22014-05-10 10:36:38 +0100290 emit->bytecode_offset = 0;
Damien George08335002014-01-18 23:24:36 +0000291 emit->code_info_offset = 0;
Damien Georgeacd2c5c2022-03-18 13:18:59 +1100292 emit->overflow = false;
Damien George08335002014-01-18 23:24:36 +0000293
Damien Georgeb5ebfad2019-09-16 22:12:59 +1000294 // Write local state size, exception stack size, scope flags and number of arguments
Damien George9b7f5832015-03-18 17:47:47 +0000295 {
296 mp_uint_t n_state = scope->num_locals + scope->stack_size;
297 if (n_state == 0) {
298 // Need at least 1 entry in the state, in the case an exception is
299 // propagated through this function, the exception is returned in
300 // the highest slot in the state (fastn[0], see vm.c).
301 n_state = 1;
302 }
Damien George6d199342019-01-04 17:09:41 +1100303 #if MICROPY_DEBUG_VM_STACK_OVERFLOW
304 // An extra slot in the stack is needed to detect VM stack overflow
305 n_state += 1;
306 #endif
Damien George08335002014-01-18 23:24:36 +0000307
Damien Georgeb5ebfad2019-09-16 22:12:59 +1000308 size_t n_exc_stack = scope->exc_stack_size;
309 MP_BC_PRELUDE_SIG_ENCODE(n_state, n_exc_stack, scope, emit_write_code_info_byte, emit);
310 }
Damien George3a3db4d2015-10-22 23:45:37 +0100311
Damien Georgec8c0fd42019-09-25 15:45:47 +1000312 // Write number of cells and size of the source code info
Damien Georgef2040bf2021-10-22 22:22:47 +1100313 if (emit->pass >= MP_PASS_CODE_SIZE) {
314 size_t n_info = emit->n_info;
315 size_t n_cell = emit->n_cell;
316 MP_BC_PRELUDE_SIZE_ENCODE(n_info, n_cell, emit_write_code_info_byte, emit);
Damien George8dcc0c72014-03-27 10:55:21 +0000317 }
318
Damien Georgec8c0fd42019-09-25 15:45:47 +1000319 emit->n_info = emit->code_info_offset;
320
Damien Georgef2040bf2021-10-22 22:22:47 +1100321 // Write the name of this function.
Damien George9b7f5832015-03-18 17:47:47 +0000322 emit_write_code_info_qstr(emit, scope->simple_name);
Damien George9b7f5832015-03-18 17:47:47 +0000323
Damien Georgef2040bf2021-10-22 22:22:47 +1100324 // Write argument names, needed to resolve positional args passed as keywords.
325 {
Damien George713ea182015-10-23 01:23:11 +0100326 // For a given argument position (indexed by i) we need to find the
327 // corresponding id_info which is a parameter, as it has the correct
328 // qstr name to use as the argument name. Note that it's not a simple
329 // 1-1 mapping (ie i!=j in general) because of possible closed-over
330 // variables. In the case that the argument i has no corresponding
331 // parameter we use "*" as its name (since no argument can ever be named
332 // "*"). We could use a blank qstr but "*" is better for debugging.
333 // Note: there is some wasted RAM here for the case of storing a qstr
334 // for each closed-over variable, and maybe there is a better way to do
335 // it, but that would require changes to mp_setup_code_state.
336 for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {
337 qstr qst = MP_QSTR__star_;
338 for (int j = 0; j < scope->id_info_len; ++j) {
339 id_info_t *id = &scope->id_info[j];
340 if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {
341 qst = id->qst;
342 break;
343 }
344 }
Damien Georgef2040bf2021-10-22 22:22:47 +1100345 emit_write_code_info_qstr(emit, qst);
Damien George713ea182015-10-23 01:23:11 +0100346 }
347 }
Damien George6baf76e2013-12-30 22:32:17 +0000348}
349
Damien George538c3c02022-03-16 09:37:58 +1100350bool mp_emit_bc_end_pass(emit_t *emit) {
Damien Georgea210c772015-03-26 15:49:53 +0000351 if (emit->pass == MP_PASS_SCOPE) {
Damien George538c3c02022-03-16 09:37:58 +1100352 return true;
Damien Georgea210c772015-03-26 15:49:53 +0000353 }
354
Damien George6baf76e2013-12-30 22:32:17 +0000355 // check stack is back to zero size
Damien George7385b012016-09-27 15:46:50 +1000356 assert(emit->stack_size == 0);
Damien George6baf76e2013-12-30 22:32:17 +0000357
Damien Georgec8c0fd42019-09-25 15:45:47 +1000358 // Calculate size of source code info section
359 emit->n_info = emit->code_info_offset - emit->n_info;
360
361 // Emit closure section of prelude
362 emit->n_cell = 0;
363 for (size_t i = 0; i < emit->scope->id_info_len; ++i) {
364 id_info_t *id = &emit->scope->id_info[i];
365 if (id->kind == ID_INFO_KIND_CELL) {
366 assert(id->local_num <= 255);
367 emit_write_code_info_byte(emit, id->local_num); // write the local which should be converted to a cell
368 ++emit->n_cell;
369 }
370 }
371
Damien George36db6bc2014-05-07 17:24:22 +0100372 if (emit->pass == MP_PASS_CODE_SIZE) {
Damien Georgeb534e1b2014-09-04 14:44:01 +0100373 // calculate size of total code-info + bytecode, in bytes
Damien George08335002014-01-18 23:24:36 +0000374 emit->code_info_size = emit->code_info_offset;
Damien George3417bc22014-05-10 10:36:38 +0100375 emit->bytecode_size = emit->bytecode_offset;
376 emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
Damien George6baf76e2013-12-30 22:32:17 +0000377
Damien George36db6bc2014-05-07 17:24:22 +0100378 } else if (emit->pass == MP_PASS_EMIT) {
Damien George538c3c02022-03-16 09:37:58 +1100379 // Code info and/or bytecode can shrink during this pass.
380 assert(emit->code_info_offset <= emit->code_info_size);
381 assert(emit->bytecode_offset <= emit->bytecode_size);
382
383 if (emit->code_info_offset != emit->code_info_size
384 || emit->bytecode_offset != emit->bytecode_size) {
385 // Code info and/or bytecode changed size in this pass, so request the
386 // compiler to do another pass with these updated sizes.
387 emit->code_info_size = emit->code_info_offset;
388 emit->bytecode_size = emit->bytecode_offset;
389 return false;
390 }
391
Damien Georgeacd2c5c2022-03-18 13:18:59 +1100392 if (emit->overflow) {
393 mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("bytecode overflow"));
394 }
395
Damien George538c3c02022-03-16 09:37:58 +1100396 // Bytecode is finalised, assign it to the raw code object.
Damien George3417bc22014-05-10 10:36:38 +0100397 mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
Damien George5604b712018-02-14 18:41:17 +1100398 #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
Damien George713ea182015-10-23 01:23:11 +0100399 emit->code_info_size + emit->bytecode_size,
Damien George5604b712018-02-14 18:41:17 +1100400 #endif
Damien Georgef2040bf2021-10-22 22:22:47 +1100401 emit->emit_common->children,
Damien Georged8c834c2015-11-02 21:55:42 +0000402 #if MICROPY_PERSISTENT_CODE_SAVE
Damien Georgef2040bf2021-10-22 22:22:47 +1100403 emit->emit_common->ct_cur_child,
Damien Georged8c834c2015-11-02 21:55:42 +0000404 #endif
405 emit->scope->scope_flags);
Damien George6baf76e2013-12-30 22:32:17 +0000406 }
Damien George538c3c02022-03-16 09:37:58 +1100407
408 return true;
Damien George6baf76e2013-12-30 22:32:17 +0000409}
410
Damien George41125902015-03-26 16:44:14 +0000411void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {
Damien George8f064e42017-05-25 20:42:30 +1000412 if (emit->pass == MP_PASS_SCOPE) {
413 return;
414 }
415 assert((mp_int_t)emit->stack_size + delta >= 0);
Damien Georged66ae182014-04-10 17:28:54 +0000416 emit->stack_size += delta;
Damien George8f064e42017-05-25 20:42:30 +1000417 if (emit->stack_size > emit->scope->stack_size) {
418 emit->scope->stack_size = emit->stack_size;
419 }
Damien George8f064e42017-05-25 20:42:30 +1000420}
421
Damien George41125902015-03-26 16:44:14 +0000422void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
Damien George69661f32020-02-27 15:36:53 +1100423 #if MICROPY_ENABLE_SOURCE_LINE
Damien Georgeb4b10fd2015-01-01 23:30:53 +0000424 if (MP_STATE_VM(mp_optimise_value) >= 3) {
Paul Sokolovskyb8f117d2014-06-02 19:39:15 +0300425 // If we compile with -O3, don't store line numbers.
426 return;
427 }
Damien George08335002014-01-18 23:24:36 +0000428 if (source_line > emit->last_source_line) {
Damien George7ff996c2014-09-08 23:05:16 +0100429 mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
430 mp_uint_t lines_to_skip = source_line - emit->last_source_line;
Damien George28eb5772014-01-25 11:43:20 +0000431 emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);
Damien George3417bc22014-05-10 10:36:38 +0100432 emit->last_source_line_offset = emit->bytecode_offset;
Damien George08335002014-01-18 23:24:36 +0000433 emit->last_source_line = source_line;
434 }
Damien George69661f32020-02-27 15:36:53 +1100435 #else
Damien George3a2171e2015-09-04 16:53:46 +0100436 (void)emit;
437 (void)source_line;
Damien George69661f32020-02-27 15:36:53 +1100438 #endif
Damien George08335002014-01-18 23:24:36 +0000439}
440
Damien George41125902015-03-26 16:44:14 +0000441void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
Damien Georgeb1229ef2023-03-08 14:10:02 +1100442 // Assigning a label ends any dead-code region, and all following opcodes
Damien Georgea5063352022-06-17 23:14:32 +1000443 // should be emitted (until another unconditional flow control).
444 emit->suppress = false;
445
Damien George8e7745e2019-08-22 14:55:16 +1000446 mp_emit_bc_adjust_stack_size(emit, 0);
Damien Georgea210c772015-03-26 15:49:53 +0000447 if (emit->pass == MP_PASS_SCOPE) {
448 return;
449 }
Damien George538c3c02022-03-16 09:37:58 +1100450
451 // Label offsets can change from one pass to the next, but they must only
452 // decrease (ie code can only shrink). There will be multiple MP_PASS_EMIT
453 // stages until the labels no longer change, which is when the code size
454 // stays constant after a MP_PASS_EMIT.
Damienb05d7072013-10-05 13:37:10 +0100455 assert(l < emit->max_num_labels);
Damien George538c3c02022-03-16 09:37:58 +1100456 assert(emit->pass == MP_PASS_STACK_SIZE || emit->bytecode_offset <= emit->label_offsets[l]);
457
458 // Assign label offset.
459 emit->label_offsets[l] = emit->bytecode_offset;
Damien429d7192013-10-04 19:53:11 +0100460}
461
Damien Georged97906c2018-05-22 21:58:25 +1000462void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) {
463 MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME);
464 MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM);
Damien George8e7745e2019-08-22 14:55:16 +1000465 int stack_adj = kind == MP_EMIT_IMPORT_FROM ? 1 : -1;
Damien Georged97906c2018-05-22 21:58:25 +1000466 if (kind == MP_EMIT_IMPORT_STAR) {
Damien George8e7745e2019-08-22 14:55:16 +1000467 emit_write_bytecode_byte(emit, stack_adj, MP_BC_IMPORT_STAR);
Damien Georged97906c2018-05-22 21:58:25 +1000468 } else {
Damien George8e7745e2019-08-22 14:55:16 +1000469 emit_write_bytecode_byte_qstr(emit, stack_adj, MP_BC_IMPORT_NAME + kind, qst);
Damien Georged97906c2018-05-22 21:58:25 +1000470 }
Damien429d7192013-10-04 19:53:11 +0100471}
472
Damien George41125902015-03-26 16:44:14 +0000473void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
Damien George3d9bd802019-08-22 14:36:27 +1000474 MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_NONE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_NONE);
475 MP_STATIC_ASSERT(MP_BC_LOAD_CONST_FALSE + (MP_TOKEN_KW_TRUE - MP_TOKEN_KW_FALSE) == MP_BC_LOAD_CONST_TRUE);
Damien George3d9bd802019-08-22 14:36:27 +1000476 if (tok == MP_TOKEN_ELLIPSIS) {
Damien George8e7745e2019-08-22 14:55:16 +1000477 emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj));
Damien George3d9bd802019-08-22 14:36:27 +1000478 } else {
Damien George8e7745e2019-08-22 14:55:16 +1000479 emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_CONST_FALSE + (tok - MP_TOKEN_KW_FALSE));
Damien429d7192013-10-04 19:53:11 +0100480 }
481}
482
Damien George41125902015-03-26 16:44:14 +0000483void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
Damien Georgee3de7232022-03-31 23:59:10 +1100484 assert(MP_SMALL_INT_FITS(arg));
Damien George870e9002019-09-12 12:19:49 +1000485 if (-MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS <= arg
486 && arg < MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM - MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS) {
487 emit_write_bytecode_byte(emit, 1,
488 MP_BC_LOAD_CONST_SMALL_INT_MULTI + MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS + arg);
Damien George8456cc02014-10-25 16:43:46 +0100489 } else {
Damien George8e7745e2019-08-22 14:55:16 +1000490 emit_write_bytecode_byte_int(emit, 1, MP_BC_LOAD_CONST_SMALL_INT, arg);
Damien George8456cc02014-10-25 16:43:46 +0100491 }
Damien429d7192013-10-04 19:53:11 +0100492}
493
Damien George59fba2d2015-06-25 14:42:13 +0000494void mp_emit_bc_load_const_str(emit_t *emit, qstr qst) {
Damien George8e7745e2019-08-22 14:55:16 +1000495 emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_CONST_STRING, qst);
Damien429d7192013-10-04 19:53:11 +0100496}
497
Damien George5d66b422015-11-27 12:41:25 +0000498void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj) {
Damien George8e7745e2019-08-22 14:55:16 +1000499 emit_write_bytecode_byte_obj(emit, 1, MP_BC_LOAD_CONST_OBJ, obj);
Damien Georgedab13852015-01-13 15:55:54 +0000500}
501
Damien George41125902015-03-26 16:44:14 +0000502void mp_emit_bc_load_null(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000503 emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_NULL);
Damien George280fb4d2017-09-13 20:36:06 +1000504}
Damien George523b5752014-03-31 11:59:23 +0100505
Damien George0a25fff2018-05-19 00:11:04 +1000506void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
507 MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N);
508 MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF);
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000509 (void)qst;
Damien George0a25fff2018-05-19 00:11:04 +1000510 if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) {
Damien George8e7745e2019-08-22 14:55:16 +1000511 emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_FAST_MULTI + local_num);
Damien George8456cc02014-10-25 16:43:46 +0100512 } else {
Damien George8e7745e2019-08-22 14:55:16 +1000513 emit_write_bytecode_byte_uint(emit, 1, MP_BC_LOAD_FAST_N + kind, local_num);
Damien429d7192013-10-04 19:53:11 +0100514 }
515}
516
Damien Georged2980132018-05-22 21:16:30 +1000517void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) {
518 MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME);
519 MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL);
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000520 (void)qst;
Damien George8e7745e2019-08-22 14:55:16 +1000521 emit_write_bytecode_byte_qstr(emit, 1, MP_BC_LOAD_NAME + kind, qst);
Damien429d7192013-10-04 19:53:11 +0100522}
523
Damien Georgedd11af22017-04-19 09:45:59 +1000524void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {
Damien George8e7745e2019-08-22 14:55:16 +1000525 int stack_adj = 1 - 2 * is_super;
526 emit_write_bytecode_byte_qstr(emit, stack_adj, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst);
Damien429d7192013-10-04 19:53:11 +0100527}
528
Damien George41125902015-03-26 16:44:14 +0000529void mp_emit_bc_load_build_class(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000530 emit_write_bytecode_byte(emit, 1, MP_BC_LOAD_BUILD_CLASS);
Damien429d7192013-10-04 19:53:11 +0100531}
532
Damien Georgea4941a82018-05-22 21:31:56 +1000533void mp_emit_bc_subscr(emit_t *emit, int kind) {
534 if (kind == MP_EMIT_SUBSCR_LOAD) {
Damien George8e7745e2019-08-22 14:55:16 +1000535 emit_write_bytecode_byte(emit, -1, MP_BC_LOAD_SUBSCR);
Damien Georgea4941a82018-05-22 21:31:56 +1000536 } else {
537 if (kind == MP_EMIT_SUBSCR_DELETE) {
538 mp_emit_bc_load_null(emit);
539 mp_emit_bc_rot_three(emit);
540 }
Damien George8e7745e2019-08-22 14:55:16 +1000541 emit_write_bytecode_byte(emit, -3, MP_BC_STORE_SUBSCR);
Damien Georgea4941a82018-05-22 21:31:56 +1000542 }
Damien George729f7b42014-04-17 22:10:53 +0100543}
544
Damien George6211d972018-05-22 21:43:41 +1000545void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) {
546 if (kind == MP_EMIT_ATTR_LOAD) {
Damien George8e7745e2019-08-22 14:55:16 +1000547 emit_write_bytecode_byte_qstr(emit, 0, MP_BC_LOAD_ATTR, qst);
Damien George6211d972018-05-22 21:43:41 +1000548 } else {
549 if (kind == MP_EMIT_ATTR_DELETE) {
550 mp_emit_bc_load_null(emit);
551 mp_emit_bc_rot_two(emit);
552 }
Damien George8e7745e2019-08-22 14:55:16 +1000553 emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst);
Damien George6211d972018-05-22 21:43:41 +1000554 }
Damien George6211d972018-05-22 21:43:41 +1000555}
556
Damien George0a25fff2018-05-19 00:11:04 +1000557void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
558 MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N);
559 MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF);
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000560 (void)qst;
Damien George0a25fff2018-05-19 00:11:04 +1000561 if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) {
Damien George8e7745e2019-08-22 14:55:16 +1000562 emit_write_bytecode_byte(emit, -1, MP_BC_STORE_FAST_MULTI + local_num);
Damien George8456cc02014-10-25 16:43:46 +0100563 } else {
Damien George8e7745e2019-08-22 14:55:16 +1000564 emit_write_bytecode_byte_uint(emit, -1, MP_BC_STORE_FAST_N + kind, local_num);
Damien429d7192013-10-04 19:53:11 +0100565 }
566}
567
Damien Georged2980132018-05-22 21:16:30 +1000568void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) {
569 MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME);
570 MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL);
Damien George8e7745e2019-08-22 14:55:16 +1000571 emit_write_bytecode_byte_qstr(emit, -1, MP_BC_STORE_NAME + kind, qst);
Damien429d7192013-10-04 19:53:11 +0100572}
573
Damien George0a25fff2018-05-19 00:11:04 +1000574void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
575 MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST);
576 MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF);
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000577 (void)qst;
Damien George8e7745e2019-08-22 14:55:16 +1000578 emit_write_bytecode_byte_uint(emit, 0, MP_BC_DELETE_FAST + kind, local_num);
Damien9ecbcff2013-12-11 00:41:43 +0000579}
580
Damien Georged2980132018-05-22 21:16:30 +1000581void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) {
582 MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME);
583 MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL);
Damien George8e7745e2019-08-22 14:55:16 +1000584 emit_write_bytecode_byte_qstr(emit, 0, MP_BC_DELETE_NAME + kind, qst);
Damien429d7192013-10-04 19:53:11 +0100585}
586
Damien George41125902015-03-26 16:44:14 +0000587void mp_emit_bc_dup_top(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000588 emit_write_bytecode_byte(emit, 1, MP_BC_DUP_TOP);
Damien429d7192013-10-04 19:53:11 +0100589}
590
Damien George41125902015-03-26 16:44:14 +0000591void mp_emit_bc_dup_top_two(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000592 emit_write_bytecode_byte(emit, 2, MP_BC_DUP_TOP_TWO);
Damien429d7192013-10-04 19:53:11 +0100593}
594
Damien George41125902015-03-26 16:44:14 +0000595void mp_emit_bc_pop_top(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000596 emit_write_bytecode_byte(emit, -1, MP_BC_POP_TOP);
Damien429d7192013-10-04 19:53:11 +0100597}
598
Damien George41125902015-03-26 16:44:14 +0000599void mp_emit_bc_rot_two(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000600 emit_write_bytecode_byte(emit, 0, MP_BC_ROT_TWO);
Damien429d7192013-10-04 19:53:11 +0100601}
602
Damien George41125902015-03-26 16:44:14 +0000603void mp_emit_bc_rot_three(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000604 emit_write_bytecode_byte(emit, 0, MP_BC_ROT_THREE);
Damien429d7192013-10-04 19:53:11 +0100605}
606
Damien George41125902015-03-26 16:44:14 +0000607void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) {
Damien George538c3c02022-03-16 09:37:58 +1100608 emit_write_bytecode_byte_label(emit, 0, MP_BC_JUMP, label);
Damien Georgea5063352022-06-17 23:14:32 +1000609 emit->suppress = true;
Damien429d7192013-10-04 19:53:11 +0100610}
611
Damien George41125902015-03-26 16:44:14 +0000612void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {
Damien George63f38322015-02-28 15:04:06 +0000613 if (cond) {
Damien George538c3c02022-03-16 09:37:58 +1100614 emit_write_bytecode_byte_label(emit, -1, MP_BC_POP_JUMP_IF_TRUE, label);
Damien George63f38322015-02-28 15:04:06 +0000615 } else {
Damien George538c3c02022-03-16 09:37:58 +1100616 emit_write_bytecode_byte_label(emit, -1, MP_BC_POP_JUMP_IF_FALSE, label);
Damien George63f38322015-02-28 15:04:06 +0000617 }
Damien429d7192013-10-04 19:53:11 +0100618}
619
Damien George41125902015-03-26 16:44:14 +0000620void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {
Damien George63f38322015-02-28 15:04:06 +0000621 if (cond) {
Damien George538c3c02022-03-16 09:37:58 +1100622 emit_write_bytecode_byte_label(emit, -1, MP_BC_JUMP_IF_TRUE_OR_POP, label);
Damien George63f38322015-02-28 15:04:06 +0000623 } else {
Damien George538c3c02022-03-16 09:37:58 +1100624 emit_write_bytecode_byte_label(emit, -1, MP_BC_JUMP_IF_FALSE_OR_POP, label);
Damien George63f38322015-02-28 15:04:06 +0000625 }
Damien429d7192013-10-04 19:53:11 +0100626}
627
Damien George41125902015-03-26 16:44:14 +0000628void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
Damien Georgecbddb272014-02-01 20:08:18 +0000629 if (except_depth == 0) {
Damien George25c84642014-05-30 15:20:41 +0100630 if (label & MP_EMIT_BREAK_FROM_FOR) {
631 // need to pop the iterator if we are breaking out of a for loop
Damien George8e7745e2019-08-22 14:55:16 +1000632 emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP);
Damien Georgef4df3aa2016-01-09 23:59:52 +0000633 // also pop the iter_buf
Damien George60656ea2017-03-23 16:36:08 +1100634 for (size_t i = 0; i < MP_OBJ_ITER_BUF_NSLOTS - 1; ++i) {
Damien George8e7745e2019-08-22 14:55:16 +1000635 emit_write_bytecode_raw_byte(emit, MP_BC_POP_TOP);
Damien Georgef4df3aa2016-01-09 23:59:52 +0000636 }
Damien George25c84642014-05-30 15:20:41 +0100637 }
Damien George538c3c02022-03-16 09:37:58 +1100638 emit_write_bytecode_byte_label(emit, 0, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
Damien George25c84642014-05-30 15:20:41 +0100639 } else {
Damien George538c3c02022-03-16 09:37:58 +1100640 emit_write_bytecode_byte_label(emit, 0, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
Damien George8e7745e2019-08-22 14:55:16 +1000641 emit_write_bytecode_raw_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth);
Damien Georgecbddb272014-02-01 20:08:18 +0000642 }
Damien Georgea5063352022-06-17 23:14:32 +1000643 emit->suppress = true;
Damien429d7192013-10-04 19:53:11 +0100644}
645
Damien George18e63582018-05-22 22:33:26 +1000646void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) {
647 MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH);
648 MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT);
649 MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY);
Damien Georgef0406852016-09-27 12:37:21 +1000650 // The SETUP_WITH opcode pops ctx_mgr from the top of the stack
651 // and then pushes 3 entries: __exit__, ctx_mgr, as_value.
Damien George8e7745e2019-08-22 14:55:16 +1000652 int stack_adj = kind == MP_EMIT_SETUP_BLOCK_WITH ? 2 : 0;
Damien George538c3c02022-03-16 09:37:58 +1100653 emit_write_bytecode_byte_label(emit, stack_adj, MP_BC_SETUP_WITH + kind, label);
Damien429d7192013-10-04 19:53:11 +0100654}
655
Damien Georgece8b4e82016-04-07 08:50:38 +0100656void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
Damien Georgece8b4e82016-04-07 08:50:38 +0100657 mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE);
658 mp_emit_bc_label_assign(emit, label);
Damien George8e7745e2019-08-22 14:55:16 +1000659 // The +2 is to ensure we have enough stack space to call the __exit__ method
660 emit_write_bytecode_byte(emit, 2, MP_BC_WITH_CLEANUP);
661 // Cancel the +2 above, plus the +2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH)
662 mp_emit_bc_adjust_stack_size(emit, -4);
Damien429d7192013-10-04 19:53:11 +0100663}
664
Damien George41125902015-03-26 16:44:14 +0000665void mp_emit_bc_end_finally(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000666 emit_write_bytecode_byte(emit, -1, MP_BC_END_FINALLY);
Damien429d7192013-10-04 19:53:11 +0100667}
668
Damien Georgef4df3aa2016-01-09 23:59:52 +0000669void mp_emit_bc_get_iter(emit_t *emit, bool use_stack) {
Damien George8e7745e2019-08-22 14:55:16 +1000670 int stack_adj = use_stack ? MP_OBJ_ITER_BUF_NSLOTS - 1 : 0;
671 emit_write_bytecode_byte(emit, stack_adj, use_stack ? MP_BC_GET_ITER_STACK : MP_BC_GET_ITER);
Damien429d7192013-10-04 19:53:11 +0100672}
673
Damien George41125902015-03-26 16:44:14 +0000674void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) {
Damien George538c3c02022-03-16 09:37:58 +1100675 emit_write_bytecode_byte_label(emit, 1, MP_BC_FOR_ITER, label);
Damien429d7192013-10-04 19:53:11 +0100676}
677
Damien George30b42dd2017-01-17 15:30:18 +1100678void mp_emit_bc_for_iter_end(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000679 mp_emit_bc_adjust_stack_size(emit, -MP_OBJ_ITER_BUF_NSLOTS);
Damien429d7192013-10-04 19:53:11 +0100680}
681
Damien George5a2599d2019-02-15 12:18:59 +1100682void mp_emit_bc_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {
683 (void)within_exc_handler;
Damien George538c3c02022-03-16 09:37:58 +1100684 emit_write_bytecode_byte_label(emit, 0, MP_BC_POP_EXCEPT_JUMP, label);
Damien Georgea5063352022-06-17 23:14:32 +1000685 emit->suppress = true;
Damien429d7192013-10-04 19:53:11 +0100686}
687
Damien George41125902015-03-26 16:44:14 +0000688void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
Damien George8e7745e2019-08-22 14:55:16 +1000689 emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + op);
Damien429d7192013-10-04 19:53:11 +0100690}
691
Damien George41125902015-03-26 16:44:14 +0000692void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
Damien George9aa2a522014-02-01 23:04:09 +0000693 bool invert = false;
Damien Georged17926d2014-03-30 13:35:08 +0100694 if (op == MP_BINARY_OP_NOT_IN) {
Damien George9aa2a522014-02-01 23:04:09 +0000695 invert = true;
Damien Georged17926d2014-03-30 13:35:08 +0100696 op = MP_BINARY_OP_IN;
697 } else if (op == MP_BINARY_OP_IS_NOT) {
Damien George9aa2a522014-02-01 23:04:09 +0000698 invert = true;
Damien Georged17926d2014-03-30 13:35:08 +0100699 op = MP_BINARY_OP_IS;
Damien George9aa2a522014-02-01 23:04:09 +0000700 }
Damien George8e7745e2019-08-22 14:55:16 +1000701 emit_write_bytecode_byte(emit, -1, MP_BC_BINARY_OP_MULTI + op);
Damien George9aa2a522014-02-01 23:04:09 +0000702 if (invert) {
Damien George8e7745e2019-08-22 14:55:16 +1000703 emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NOT);
Damien George9aa2a522014-02-01 23:04:09 +0000704 }
Damien429d7192013-10-04 19:53:11 +0100705}
706
Damien George26b57542018-05-19 00:41:40 +1000707void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) {
708 MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE);
709 MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST);
710 MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP);
Damien George436e0d42018-05-22 22:18:42 +1000711 MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET);
712 MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE);
Damien George8e7745e2019-08-22 14:55:16 +1000713 int stack_adj = kind == MP_EMIT_BUILD_MAP ? 1 : 1 - n_args;
714 emit_write_bytecode_byte_uint(emit, stack_adj, MP_BC_BUILD_TUPLE + kind, n_args);
Damien429d7192013-10-04 19:53:11 +0100715}
716
Damien George41125902015-03-26 16:44:14 +0000717void mp_emit_bc_store_map(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000718 emit_write_bytecode_byte(emit, -2, MP_BC_STORE_MAP);
Damien429d7192013-10-04 19:53:11 +0100719}
720
Damien Georgea5624bf2016-09-18 23:59:47 +1000721void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) {
Damien Georgeadaf0d82016-09-19 08:46:01 +1000722 int t;
Damien Georgea5624bf2016-09-18 23:59:47 +1000723 int n;
Damien Georgea5624bf2016-09-18 23:59:47 +1000724 if (kind == SCOPE_LIST_COMP) {
Damien Georgeadaf0d82016-09-19 08:46:01 +1000725 n = 0;
726 t = 0;
727 } else if (!MICROPY_PY_BUILTINS_SET || kind == SCOPE_DICT_COMP) {
728 n = 1;
729 t = 1;
730 } else if (MICROPY_PY_BUILTINS_SET) {
731 n = 0;
732 t = 2;
Damien Georgea5624bf2016-09-18 23:59:47 +1000733 }
Damien Georgeadaf0d82016-09-19 08:46:01 +1000734 // the lower 2 bits of the opcode argument indicate the collection type
Damien George8e7745e2019-08-22 14:55:16 +1000735 emit_write_bytecode_byte_uint(emit, -1 - n, MP_BC_STORE_COMP, ((collection_stack_index + n) << 2) | t);
Damien Georgea5624bf2016-09-18 23:59:47 +1000736}
737
Damien George41125902015-03-26 16:44:14 +0000738void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) {
Damien George8e7745e2019-08-22 14:55:16 +1000739 emit_write_bytecode_byte_uint(emit, -1 + n_args, MP_BC_UNPACK_SEQUENCE, n_args);
Damien429d7192013-10-04 19:53:11 +0100740}
741
Damien George41125902015-03-26 16:44:14 +0000742void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
Damien George8e7745e2019-08-22 14:55:16 +1000743 emit_write_bytecode_byte_uint(emit, -1 + n_left + n_right + 1, MP_BC_UNPACK_EX, n_left | (n_right << 8));
Damien429d7192013-10-04 19:53:11 +0100744}
745
Damien George41125902015-03-26 16:44:14 +0000746void mp_emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
Damien Georgee337f1e2014-03-31 15:18:37 +0100747 if (n_pos_defaults == 0 && n_kw_defaults == 0) {
Damien Georgef2040bf2021-10-22 22:22:47 +1100748 emit_write_bytecode_byte_child(emit, 1, MP_BC_MAKE_FUNCTION, scope->raw_code);
Damien Georgefb083ea2014-02-01 18:29:40 +0000749 } else {
Damien Georgef2040bf2021-10-22 22:22:47 +1100750 emit_write_bytecode_byte_child(emit, -1, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code);
Paul Sokolovsky90750022014-02-01 15:05:04 +0200751 }
Damien429d7192013-10-04 19:53:11 +0100752}
753
Damien George41125902015-03-26 16:44:14 +0000754void mp_emit_bc_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) {
Damien Georgee337f1e2014-03-31 15:18:37 +0100755 if (n_pos_defaults == 0 && n_kw_defaults == 0) {
Damien George8e7745e2019-08-22 14:55:16 +1000756 int stack_adj = -n_closed_over + 1;
Damien Georgef2040bf2021-10-22 22:22:47 +1100757 emit_write_bytecode_byte_child(emit, stack_adj, MP_BC_MAKE_CLOSURE, scope->raw_code);
Damien George8e7745e2019-08-22 14:55:16 +1000758 emit_write_bytecode_raw_byte(emit, n_closed_over);
Paul Sokolovsky2447a5b2014-03-26 23:14:59 +0200759 } else {
Damien George3558f622014-04-20 17:50:40 +0100760 assert(n_closed_over <= 255);
Damien George8e7745e2019-08-22 14:55:16 +1000761 int stack_adj = -2 - (mp_int_t)n_closed_over + 1;
Damien Georgef2040bf2021-10-22 22:22:47 +1100762 emit_write_bytecode_byte_child(emit, stack_adj, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code);
Damien George8e7745e2019-08-22 14:55:16 +1000763 emit_write_bytecode_raw_byte(emit, n_closed_over);
Paul Sokolovsky2447a5b2014-03-26 23:14:59 +0200764 }
Damien429d7192013-10-04 19:53:11 +0100765}
766
Damien George8e7745e2019-08-22 14:55:16 +1000767STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
Damien George922ddd62014-04-09 12:43:17 +0100768 if (star_flags) {
David Lechner1e99d292020-03-24 21:39:46 -0500769 // each positional arg is one object, each kwarg is two objects, the key
770 // and the value and one extra object for the star args bitmap.
771 stack_adj -= (int)n_positional + 2 * (int)n_keyword + 1;
Damien George8e7745e2019-08-22 14:55:16 +1000772 emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
Damien429d7192013-10-04 19:53:11 +0100773 } else {
Damien George8e7745e2019-08-22 14:55:16 +1000774 stack_adj -= (int)n_positional + 2 * (int)n_keyword;
775 emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
Damien429d7192013-10-04 19:53:11 +0100776 }
Damien George523b5752014-03-31 11:59:23 +0100777}
778
Damien George41125902015-03-26 16:44:14 +0000779void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
Damien George922ddd62014-04-09 12:43:17 +0100780 emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, star_flags);
Damien429d7192013-10-04 19:53:11 +0100781}
782
Damien George41125902015-03-26 16:44:14 +0000783void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
Damien George922ddd62014-04-09 12:43:17 +0100784 emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, star_flags);
Damien429d7192013-10-04 19:53:11 +0100785}
786
Damien George41125902015-03-26 16:44:14 +0000787void mp_emit_bc_return_value(emit_t *emit) {
Damien George8e7745e2019-08-22 14:55:16 +1000788 emit_write_bytecode_byte(emit, -1, MP_BC_RETURN_VALUE);
Damien Georgea5063352022-06-17 23:14:32 +1000789 emit->suppress = true;
Damien429d7192013-10-04 19:53:11 +0100790}
791
Damien George41125902015-03-26 16:44:14 +0000792void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) {
Damien George02db91a2019-08-22 12:39:07 +1000793 MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 1 == MP_BC_RAISE_OBJ);
794 MP_STATIC_ASSERT(MP_BC_RAISE_LAST + 2 == MP_BC_RAISE_FROM);
Pavol Rusnak7ffc9592016-10-25 11:05:33 +0200795 assert(n_args <= 2);
Damien George02db91a2019-08-22 12:39:07 +1000796 emit_write_bytecode_byte(emit, -n_args, MP_BC_RAISE_LAST + n_args);
Damien Georgea5063352022-06-17 23:14:32 +1000797 emit->suppress = true;
Damien429d7192013-10-04 19:53:11 +0100798}
799
Damien Georgee686c942018-05-19 00:30:42 +1000800void mp_emit_bc_yield(emit_t *emit, int kind) {
801 MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM);
Damien George8e7745e2019-08-22 14:55:16 +1000802 emit_write_bytecode_byte(emit, -kind, MP_BC_YIELD_VALUE + kind);
Damien George36db6bc2014-05-07 17:24:22 +0100803 emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
Damien429d7192013-10-04 19:53:11 +0100804}
805
Damien George41125902015-03-26 16:44:14 +0000806void mp_emit_bc_start_except_handler(emit_t *emit) {
Damien Georgef0406852016-09-27 12:37:21 +1000807 mp_emit_bc_adjust_stack_size(emit, 4); // stack adjust for the exception instance, +3 for possible UNWIND_JUMP state
Damien Georgeb601d952014-06-30 05:17:25 +0100808}
809
Damien George41125902015-03-26 16:44:14 +0000810void mp_emit_bc_end_except_handler(emit_t *emit) {
Damien Georgef0406852016-09-27 12:37:21 +1000811 mp_emit_bc_adjust_stack_size(emit, -3); // stack adjust
Damien Georgeb601d952014-06-30 05:17:25 +0100812}
813
Damien George41125902015-03-26 16:44:14 +0000814#if MICROPY_EMIT_NATIVE
Damien6cdd3af2013-10-05 18:08:26 +0100815const emit_method_table_t emit_bc_method_table = {
Damien Georged9d92f22019-03-09 10:59:25 +1100816 #if MICROPY_DYNAMIC_COMPILER
817 NULL,
818 NULL,
819 #endif
820
Damien George41125902015-03-26 16:44:14 +0000821 mp_emit_bc_start_pass,
822 mp_emit_bc_end_pass,
Damien George41125902015-03-26 16:44:14 +0000823 mp_emit_bc_adjust_stack_size,
824 mp_emit_bc_set_source_line,
Damien415eb6f2013-10-05 12:19:06 +0100825
Damien George542bd6b2015-03-26 14:42:40 +0000826 {
Damien George0a25fff2018-05-19 00:11:04 +1000827 mp_emit_bc_load_local,
Damien George41125902015-03-26 16:44:14 +0000828 mp_emit_bc_load_global,
Damien George542bd6b2015-03-26 14:42:40 +0000829 },
830 {
Damien George0a25fff2018-05-19 00:11:04 +1000831 mp_emit_bc_store_local,
Damien George41125902015-03-26 16:44:14 +0000832 mp_emit_bc_store_global,
Damien George542bd6b2015-03-26 14:42:40 +0000833 },
834 {
Damien George0a25fff2018-05-19 00:11:04 +1000835 mp_emit_bc_delete_local,
Damien George41125902015-03-26 16:44:14 +0000836 mp_emit_bc_delete_global,
Damien George542bd6b2015-03-26 14:42:40 +0000837 },
Damien4b03e772013-10-05 14:17:09 +0100838
Damien George41125902015-03-26 16:44:14 +0000839 mp_emit_bc_label_assign,
Damien Georged97906c2018-05-22 21:58:25 +1000840 mp_emit_bc_import,
Damien George41125902015-03-26 16:44:14 +0000841 mp_emit_bc_load_const_tok,
842 mp_emit_bc_load_const_small_int,
843 mp_emit_bc_load_const_str,
844 mp_emit_bc_load_const_obj,
845 mp_emit_bc_load_null,
Damien George41125902015-03-26 16:44:14 +0000846 mp_emit_bc_load_method,
847 mp_emit_bc_load_build_class,
Damien Georgea4941a82018-05-22 21:31:56 +1000848 mp_emit_bc_subscr,
Damien George6211d972018-05-22 21:43:41 +1000849 mp_emit_bc_attr,
Damien George41125902015-03-26 16:44:14 +0000850 mp_emit_bc_dup_top,
851 mp_emit_bc_dup_top_two,
852 mp_emit_bc_pop_top,
853 mp_emit_bc_rot_two,
854 mp_emit_bc_rot_three,
855 mp_emit_bc_jump,
856 mp_emit_bc_pop_jump_if,
857 mp_emit_bc_jump_if_or_pop,
858 mp_emit_bc_unwind_jump,
Damien George18e63582018-05-22 22:33:26 +1000859 mp_emit_bc_setup_block,
Damien George41125902015-03-26 16:44:14 +0000860 mp_emit_bc_with_cleanup,
Damien George41125902015-03-26 16:44:14 +0000861 mp_emit_bc_end_finally,
862 mp_emit_bc_get_iter,
863 mp_emit_bc_for_iter,
864 mp_emit_bc_for_iter_end,
Damien George5a2599d2019-02-15 12:18:59 +1100865 mp_emit_bc_pop_except_jump,
Damien George41125902015-03-26 16:44:14 +0000866 mp_emit_bc_unary_op,
867 mp_emit_bc_binary_op,
Damien George26b57542018-05-19 00:41:40 +1000868 mp_emit_bc_build,
Damien George41125902015-03-26 16:44:14 +0000869 mp_emit_bc_store_map,
Damien Georgea5624bf2016-09-18 23:59:47 +1000870 mp_emit_bc_store_comp,
Damien George41125902015-03-26 16:44:14 +0000871 mp_emit_bc_unpack_sequence,
872 mp_emit_bc_unpack_ex,
873 mp_emit_bc_make_function,
874 mp_emit_bc_make_closure,
875 mp_emit_bc_call_function,
876 mp_emit_bc_call_method,
877 mp_emit_bc_return_value,
878 mp_emit_bc_raise_varargs,
Damien Georgee686c942018-05-19 00:30:42 +1000879 mp_emit_bc_yield,
Damien Georgeb601d952014-06-30 05:17:25 +0100880
Damien George41125902015-03-26 16:44:14 +0000881 mp_emit_bc_start_except_handler,
882 mp_emit_bc_end_except_handler,
Damien415eb6f2013-10-05 12:19:06 +0100883};
Damien George41125902015-03-26 16:44:14 +0000884#else
885const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = {
Damien George0a25fff2018-05-19 00:11:04 +1000886 mp_emit_bc_load_local,
Damien George41125902015-03-26 16:44:14 +0000887 mp_emit_bc_load_global,
888};
889
890const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = {
Damien George0a25fff2018-05-19 00:11:04 +1000891 mp_emit_bc_store_local,
Damien George41125902015-03-26 16:44:14 +0000892 mp_emit_bc_store_global,
893};
894
895const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = {
Damien George0a25fff2018-05-19 00:11:04 +1000896 mp_emit_bc_delete_local,
Damien George41125902015-03-26 16:44:14 +0000897 mp_emit_bc_delete_global,
898};
899#endif
Damien Georgedd5353a2015-12-18 12:35:44 +0000900
stijn84fa3312020-04-16 09:13:57 +0200901#endif // MICROPY_ENABLE_COMPILER