emitbc.c 33.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

xbe's avatar
xbe committed
27
#include <stdbool.h>
Damien's avatar
Damien committed
28
29
30
31
32
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

33
#include "py/mpstate.h"
34
35
#include "py/emit.h"
#include "py/bc0.h"
Damien's avatar
Damien committed
36

37
38
39
#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7)
#define DUMMY_DATA_SIZE (BYTES_FOR_INT)

40
struct _emit_t {
41
    pass_kind_t pass : 8;
42
    mp_uint_t last_emit_was_return_value : 8;
43

Damien's avatar
Damien committed
44
45
46
47
    int stack_size;

    scope_t *scope;

48
49
    mp_uint_t last_source_line_offset;
    mp_uint_t last_source_line;
50

51
52
    mp_uint_t max_num_labels;
    mp_uint_t *label_offsets;
Damien's avatar
Damien committed
53

54
55
56
57
    mp_uint_t code_info_offset;
    mp_uint_t code_info_size;
    mp_uint_t bytecode_offset;
    mp_uint_t bytecode_size;
58
    byte *code_base; // stores both byte code and code info
59
    mp_uint_t *const_table;
60
    // Accessed as mp_uint_t, so must be aligned as such
61
    byte dummy_data[DUMMY_DATA_SIZE];
Damien's avatar
Damien committed
62
63
};

64
emit_t *emit_bc_new(void) {
65
    emit_t *emit = m_new0(emit_t, 1);
66
67
68
    return emit;
}

69
void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) {
70
    emit->max_num_labels = max_num_labels;
71
    emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels);
72
}
73

74
void emit_bc_free(emit_t *emit) {
75
    m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels);
76
77
78
    m_del_obj(emit_t, emit);
}

79
80
81
typedef byte *(*emit_allocator_t)(emit_t *emit, int nbytes);

STATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t val) {
82
83
84
85
86
87
88
89
    // We store each 7 bits in a separate byte, and that's how many bytes needed
    byte buf[BYTES_FOR_INT];
    byte *p = buf + sizeof(buf);
    // We encode in little-ending order, but store in big-endian, to help decoding
    do {
        *--p = val & 0x7f;
        val >>= 7;
    } while (val != 0);
90
    byte *c = allocator(emit, buf + sizeof(buf) - p);
91
92
93
94
95
96
    while (p != buf + sizeof(buf) - 1) {
        *c++ = *p++ | 0x80;
    }
    *c = *p;
}

97
// all functions must go through this one to emit code info
98
STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) {
99
    //printf("emit %d\n", num_bytes_to_write);
100
    if (emit->pass < MP_PASS_EMIT) {
101
102
103
104
105
106
107
108
        emit->code_info_offset += num_bytes_to_write;
        return emit->dummy_data;
    } else {
        assert(emit->code_info_offset + num_bytes_to_write <= emit->code_info_size);
        byte *c = emit->code_base + emit->code_info_offset;
        emit->code_info_offset += num_bytes_to_write;
        return c;
    }
Damien's avatar
Damien committed
109
110
}

111
STATIC void emit_align_code_info_to_machine_word(emit_t *emit) {
112
    emit->code_info_offset = (emit->code_info_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
113
114
}

115
116
117
118
119
STATIC void emit_write_code_info_byte(emit_t* emit, byte val) {
    *emit_get_cur_to_write_code_info(emit, 1) = val;
}

STATIC void emit_write_code_info_uint(emit_t* emit, mp_uint_t val) {
120
121
122
    emit_write_uint(emit, emit_get_cur_to_write_code_info, val);
}

123
STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) {
124
    emit_write_uint(emit, emit_get_cur_to_write_code_info, qst);
Damien's avatar
Damien committed
125
126
}

127
#if MICROPY_ENABLE_SOURCE_LINE
128
STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) {
129
    assert(bytes_to_skip > 0 || lines_to_skip > 0);
130
    //printf("  %d %d\n", bytes_to_skip, lines_to_skip);
131
    while (bytes_to_skip > 0 || lines_to_skip > 0) {
132
133
134
135
136
137
138
139
140
141
142
143
144
145
        mp_uint_t b, l;
        if (lines_to_skip <= 6) {
            // use 0b0LLBBBBB encoding
            b = MIN(bytes_to_skip, 0x1f);
            l = MIN(lines_to_skip, 0x3);
            *emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
        } else {
            // use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)
            b = MIN(bytes_to_skip, 0xf);
            l = MIN(lines_to_skip, 0x7ff);
            byte *ci = emit_get_cur_to_write_code_info(emit, 2);
            ci[0] = 0x80 | b | ((l >> 4) & 0x70);
            ci[1] = l;
        }
146
147
        bytes_to_skip -= b;
        lines_to_skip -= l;
148
    }
149
}
150
#endif
151
152

// all functions must go through this one to emit byte code
153
STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) {
Damien's avatar
Damien committed
154
    //printf("emit %d\n", num_bytes_to_write);
155
    if (emit->pass < MP_PASS_EMIT) {
156
        emit->bytecode_offset += num_bytes_to_write;
Damien's avatar
Damien committed
157
158
        return emit->dummy_data;
    } else {
159
160
161
        assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size);
        byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset;
        emit->bytecode_offset += num_bytes_to_write;
Damien's avatar
Damien committed
162
163
164
165
        return c;
    }
}

166
STATIC void emit_align_bytecode_to_machine_word(emit_t *emit) {
167
    emit->bytecode_offset = (emit->bytecode_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
168
169
}

170
171
STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) {
    byte *c = emit_get_cur_to_write_bytecode(emit, 1);
Damien's avatar
Damien committed
172
173
174
    c[0] = b1;
}

175
STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) {
Damien's avatar
Damien committed
176
    assert((b2 & (~0xff)) == 0);
177
    byte *c = emit_get_cur_to_write_bytecode(emit, 2);
Damien's avatar
Damien committed
178
179
180
181
    c[0] = b1;
    c[1] = b2;
}

182
// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign
183
STATIC void emit_write_bytecode_byte_int(emit_t *emit, byte b1, mp_int_t num) {
184
    emit_write_bytecode_byte(emit, b1);
185
186

    // We store each 7 bits in a separate byte, and that's how many bytes needed
187
    byte buf[BYTES_FOR_INT];
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    byte *p = buf + sizeof(buf);
    // We encode in little-ending order, but store in big-endian, to help decoding
    do {
        *--p = num & 0x7f;
        num >>= 7;
    } while (num != 0 && num != -1);
    // Make sure that highest bit we stored (mask 0x40) matches sign
    // of the number. If not, store extra byte just to encode sign
    if (num == -1 && (*p & 0x40) == 0) {
        *--p = 0x7f;
    } else if (num == 0 && (*p & 0x40) != 0) {
        *--p = 0;
    }

202
    byte *c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);
203
204
205
206
    while (p != buf + sizeof(buf) - 1) {
        *c++ = *p++ | 0x80;
    }
    *c = *p;
Damien's avatar
Damien committed
207
208
}

209
STATIC void emit_write_bytecode_byte_uint(emit_t *emit, byte b, mp_uint_t val) {
210
    emit_write_bytecode_byte(emit, b);
211
    emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
Damien's avatar
Damien committed
212
213
}

214
// aligns the pointer so it is friendly to GC
215
STATIC void emit_write_bytecode_byte_ptr(emit_t *emit, byte b, void *ptr) {
216
217
    emit_write_bytecode_byte(emit, b);
    emit_align_bytecode_to_machine_word(emit);
218
    mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
219
220
    // Verify thar c is already uint-aligned
    assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
221
    *c = (mp_uint_t)ptr;
222
223
}

224
STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qst) {
225
    emit_write_bytecode_byte_uint(emit, b, qst);
Damien's avatar
Damien committed
226
227
}

Damien's avatar
Damien committed
228
// unsigned labels are relative to ip following this instruction, stored as 16 bits
229
STATIC void emit_write_bytecode_byte_unsigned_label(emit_t *emit, byte b1, mp_uint_t label) {
230
    mp_uint_t bytecode_offset;
231
    if (emit->pass < MP_PASS_EMIT) {
232
        bytecode_offset = 0;
Damien's avatar
Damien committed
233
    } else {
234
        bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3;
Damien's avatar
Damien committed
235
    }
236
    byte *c = emit_get_cur_to_write_bytecode(emit, 3);
Damien's avatar
Damien committed
237
    c[0] = b1;
238
239
    c[1] = bytecode_offset;
    c[2] = bytecode_offset >> 8;
Damien's avatar
Damien committed
240
241
242
}

// signed labels are relative to ip following this instruction, stored as 16 bits, in excess
243
STATIC void emit_write_bytecode_byte_signed_label(emit_t *emit, byte b1, mp_uint_t label) {
244
    int bytecode_offset;
245
    if (emit->pass < MP_PASS_EMIT) {
246
        bytecode_offset = 0;
Damien's avatar
Damien committed
247
    } else {
248
        bytecode_offset = emit->label_offsets[label] - emit->bytecode_offset - 3 + 0x8000;
Damien's avatar
Damien committed
249
    }
250
    byte *c = emit_get_cur_to_write_bytecode(emit, 3);
Damien's avatar
Damien committed
251
    c[0] = b1;
252
253
    c[1] = bytecode_offset;
    c[2] = bytecode_offset >> 8;
Damien's avatar
Damien committed
254
255
}

256
257
#if MICROPY_EMIT_NATIVE
STATIC void mp_emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
258
259
260
261
    (void)emit;
    (void)op;
    (void)arg1;
    (void)arg2;
Damien George's avatar
Damien George committed
262
}
263
#endif
Damien George's avatar
Damien George committed
264

265
void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
Damien George's avatar
Damien George committed
266
267
268
269
    emit->pass = pass;
    emit->stack_size = 0;
    emit->last_emit_was_return_value = false;
    emit->scope = scope;
270
271
    emit->last_source_line_offset = 0;
    emit->last_source_line = 1;
272
    if (pass < MP_PASS_EMIT) {
273
        memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t));
Damien George's avatar
Damien George committed
274
    }
275
    emit->bytecode_offset = 0;
276
277
    emit->code_info_offset = 0;

278
279
280
281
282
283
284
285
286
287
288
    // Write local state size and exception stack size.
    {
        mp_uint_t n_state = scope->num_locals + scope->stack_size;
        if (n_state == 0) {
            // Need at least 1 entry in the state, in the case an exception is
            // propagated through this function, the exception is returned in
            // the highest slot in the state (fastn[0], see vm.c).
            n_state = 1;
        }
        emit_write_code_info_uint(emit, n_state);
        emit_write_code_info_uint(emit, scope->exc_stack_size);
289
290
    }

291
292
293
294
295
296
297
    // Write scope flags and number of arguments.
    // TODO check that num args all fit in a byte
    emit_write_code_info_byte(emit, emit->scope->scope_flags);
    emit_write_code_info_byte(emit, emit->scope->num_pos_args);
    emit_write_code_info_byte(emit, emit->scope->num_kwonly_args);
    emit_write_code_info_byte(emit, emit->scope->num_def_pos_args);

298
299
300
301
302
303
304
    // Write size of the rest of the code info.  We don't know how big this
    // variable uint will be on the MP_PASS_CODE_SIZE pass so we reserve 2 bytes
    // for it and hope that is enough!  TODO assert this or something.
    if (pass == MP_PASS_EMIT) {
        emit_write_code_info_uint(emit, emit->code_info_size - emit->code_info_offset);
    } else  {
        emit_get_cur_to_write_code_info(emit, 2);
305
306
    }

307
308
309
310
    // Write the name and source file of this function.
    emit_write_code_info_qstr(emit, scope->simple_name);
    emit_write_code_info_qstr(emit, scope->source_file);

311
    // bytecode prelude: initialise closed over variables
Damien George's avatar
Damien George committed
312
313
314
    for (int i = 0; i < scope->id_info_len; i++) {
        id_info_t *id = &scope->id_info[i];
        if (id->kind == ID_INFO_KIND_CELL) {
315
            assert(id->local_num < 255);
316
            emit_write_bytecode_byte(emit, id->local_num); // write the local which should be converted to a cell
Damien George's avatar
Damien George committed
317
318
        }
    }
319
    emit_write_bytecode_byte(emit, 255); // end of list sentinel
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348

    if (pass == MP_PASS_EMIT) {
        // Write argument names (needed to resolve positional args passed as
        // keywords).  We store them as full word-sized objects for efficient access
        // in mp_setup_code_state this is the start of the prelude and is guaranteed
        // to be aligned on a word boundary.

        // For a given argument position (indexed by i) we need to find the
        // corresponding id_info which is a parameter, as it has the correct
        // qstr name to use as the argument name.  Note that it's not a simple
        // 1-1 mapping (ie i!=j in general) because of possible closed-over
        // variables.  In the case that the argument i has no corresponding
        // parameter we use "*" as its name (since no argument can ever be named
        // "*").  We could use a blank qstr but "*" is better for debugging.
        // Note: there is some wasted RAM here for the case of storing a qstr
        // for each closed-over variable, and maybe there is a better way to do
        // it, but that would require changes to mp_setup_code_state.
        for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {
            qstr qst = MP_QSTR__star_;
            for (int j = 0; j < scope->id_info_len; ++j) {
                id_info_t *id = &scope->id_info[j];
                if ((id->flags & ID_FLAG_IS_PARAM) && id->local_num == i) {
                    qst = id->qst;
                    break;
                }
            }
            emit->const_table[i] = (mp_uint_t)MP_OBJ_NEW_QSTR(qst);
        }
    }
Damien George's avatar
Damien George committed
349
350
}

351
void mp_emit_bc_end_pass(emit_t *emit) {
352
353
354
355
    if (emit->pass == MP_PASS_SCOPE) {
        return;
    }

Damien George's avatar
Damien George committed
356
357
    // check stack is back to zero size
    if (emit->stack_size != 0) {
358
        mp_printf(&mp_plat_print, "ERROR: stack size not back to zero; got %d\n", emit->stack_size);
Damien George's avatar
Damien George committed
359
360
    }

361
    emit_write_code_info_byte(emit, 0); // end of line number info
362

363
    if (emit->pass == MP_PASS_CODE_SIZE) {
364
        // so bytecode is aligned
365
366
367
        emit_align_code_info_to_machine_word(emit);

        // calculate size of total code-info + bytecode, in bytes
368
        emit->code_info_size = emit->code_info_offset;
369
370
        emit->bytecode_size = emit->bytecode_offset;
        emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
Damien George's avatar
Damien George committed
371

372
373
        emit->const_table = m_new0(mp_uint_t, emit->scope->num_pos_args + emit->scope->num_kwonly_args);

374
    } else if (emit->pass == MP_PASS_EMIT) {
375
        mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
376
377
            emit->code_info_size + emit->bytecode_size,
            emit->const_table, emit->scope->scope_flags);
Damien George's avatar
Damien George committed
378
379
380
    }
}

381
bool mp_emit_bc_last_emit_was_return_value(emit_t *emit) {
Damien's avatar
Damien committed
382
383
384
    return emit->last_emit_was_return_value;
}

385
void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {
386
    emit->stack_size += delta;
Damien's avatar
Damien committed
387
388
}

389
void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
390
    //printf("source: line %d -> %d  offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset);
391
#if MICROPY_ENABLE_SOURCE_LINE
392
    if (MP_STATE_VM(mp_optimise_value) >= 3) {
393
394
395
        // If we compile with -O3, don't store line numbers.
        return;
    }
396
    if (source_line > emit->last_source_line) {
397
398
        mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
        mp_uint_t lines_to_skip = source_line - emit->last_source_line;
399
        emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);
400
        emit->last_source_line_offset = emit->bytecode_offset;
401
402
        emit->last_source_line = source_line;
    }
403
404
405
#else
    (void)emit;
    (void)source_line;
406
#endif
407
408
}

409
STATIC void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) {
410
411
412
    if (emit->pass == MP_PASS_SCOPE) {
        return;
    }
413
    assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
414
415
416
    emit->stack_size += stack_size_delta;
    if (emit->stack_size > emit->scope->stack_size) {
        emit->scope->stack_size = emit->stack_size;
Damien's avatar
Damien committed
417
418
419
420
    }
    emit->last_emit_was_return_value = false;
}

421
void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
422
    emit_bc_pre(emit, 0);
423
424
425
    if (emit->pass == MP_PASS_SCOPE) {
        return;
    }
426
    assert(l < emit->max_num_labels);
427
    if (emit->pass < MP_PASS_EMIT) {
428
        // assign label offset
429
        assert(emit->label_offsets[l] == (mp_uint_t)-1);
430
        emit->label_offsets[l] = emit->bytecode_offset;
431
432
    } else {
        // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
433
434
        //printf("l%d: (at %d vs %d)\n", l, emit->bytecode_offset, emit->label_offsets[l]);
        assert(emit->label_offsets[l] == emit->bytecode_offset);
Damien's avatar
Damien committed
435
436
437
    }
}

438
void mp_emit_bc_import_name(emit_t *emit, qstr qst) {
439
    emit_bc_pre(emit, -1);
440
    emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qst);
Damien's avatar
Damien committed
441
442
}

443
void mp_emit_bc_import_from(emit_t *emit, qstr qst) {
444
    emit_bc_pre(emit, 1);
445
    emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qst);
Damien's avatar
Damien committed
446
447
}

448
void mp_emit_bc_import_star(emit_t *emit) {
449
    emit_bc_pre(emit, -1);
450
    emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR);
Damien's avatar
Damien committed
451
452
}

453
void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
454
    emit_bc_pre(emit, 1);
Damien's avatar
Damien committed
455
    switch (tok) {
456
457
458
        case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break;
        case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break;
        case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break;
459
        no_other_choice:
460
        case MP_TOKEN_ELLIPSIS: emit_write_bytecode_byte_ptr(emit, MP_BC_LOAD_CONST_OBJ, (void*)&mp_const_ellipsis_obj); break;
461
        default: assert(0); goto no_other_choice; // to help flow control analysis
Damien's avatar
Damien committed
462
463
464
    }
}

465
void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
466
    emit_bc_pre(emit, 1);
467
468
469
470
471
    if (-16 <= arg && arg <= 47) {
        emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg);
    } else {
        emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
    }
Damien's avatar
Damien committed
472
473
}

474
void mp_emit_bc_load_const_str(emit_t *emit, qstr qst) {
475
    emit_bc_pre(emit, 1);
476
    emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qst);
Damien's avatar
Damien committed
477
478
}

479
void mp_emit_bc_load_const_obj(emit_t *emit, void *obj) {
480
481
482
483
    emit_bc_pre(emit, 1);
    emit_write_bytecode_byte_ptr(emit, MP_BC_LOAD_CONST_OBJ, obj);
}

484
void mp_emit_bc_load_null(emit_t *emit) {
485
    emit_bc_pre(emit, 1);
486
    emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL);
487
488
};

489
void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
490
    (void)qst;
Damien's avatar
Damien committed
491
    assert(local_num >= 0);
492
    emit_bc_pre(emit, 1);
493
494
495
496
    if (local_num <= 15) {
        emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num);
    } else {
        emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num);
Damien's avatar
Damien committed
497
498
499
    }
}

500
void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
501
    (void)qst;
502
    emit_bc_pre(emit, 1);
503
    emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
Damien's avatar
Damien committed
504
505
}

506
void mp_emit_bc_load_name(emit_t *emit, qstr qst) {
507
    (void)qst;
508
    emit_bc_pre(emit, 1);
509
    emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst);
510
511
512
    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
        emit_write_bytecode_byte(emit, 0);
    }
Damien's avatar
Damien committed
513
514
}

515
void mp_emit_bc_load_global(emit_t *emit, qstr qst) {
516
    (void)qst;
517
    emit_bc_pre(emit, 1);
518
    emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst);
519
520
521
    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
        emit_write_bytecode_byte(emit, 0);
    }
Damien's avatar
Damien committed
522
523
}

524
void mp_emit_bc_load_attr(emit_t *emit, qstr qst) {
525
    emit_bc_pre(emit, 0);
526
    emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst);
527
528
529
    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
        emit_write_bytecode_byte(emit, 0);
    }
Damien's avatar
Damien committed
530
531
}

532
void mp_emit_bc_load_method(emit_t *emit, qstr qst) {
533
    emit_bc_pre(emit, 1);
534
    emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_METHOD, qst);
Damien's avatar
Damien committed
535
536
}

537
void mp_emit_bc_load_build_class(emit_t *emit) {
538
    emit_bc_pre(emit, 1);
539
    emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS);
Damien's avatar
Damien committed
540
541
}

542
void mp_emit_bc_load_subscr(emit_t *emit) {
543
    emit_bc_pre(emit, -1);
544
    emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR);
545
546
}

547
void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
548
    (void)qst;
Damien's avatar
Damien committed
549
    assert(local_num >= 0);
550
    emit_bc_pre(emit, -1);
551
552
553
554
    if (local_num <= 15) {
        emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num);
    } else {
        emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num);
Damien's avatar
Damien committed
555
556
557
    }
}

558
void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
559
    (void)qst;
560
    emit_bc_pre(emit, -1);
561
    emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
Damien's avatar
Damien committed
562
563
}

564
void mp_emit_bc_store_name(emit_t *emit, qstr qst) {
565
    emit_bc_pre(emit, -1);
566
    emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst);
Damien's avatar
Damien committed
567
568
}

569
void mp_emit_bc_store_global(emit_t *emit, qstr qst) {
570
    emit_bc_pre(emit, -1);
571
    emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qst);
Damien's avatar
Damien committed
572
573
}

574
void mp_emit_bc_store_attr(emit_t *emit, qstr qst) {
575
    emit_bc_pre(emit, -2);
576
    emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst);
577
578
579
    if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
        emit_write_bytecode_byte(emit, 0);
    }
Damien's avatar
Damien committed
580
581
}

582
void mp_emit_bc_store_subscr(emit_t *emit) {
583
    emit_bc_pre(emit, -3);
584
    emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR);
Damien's avatar
Damien committed
585
586
}

587
void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
588
    (void)qst;
589
    emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
Damien's avatar
Damien committed
590
591
}

592
void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
593
    (void)qst;
594
    emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
Damien's avatar
Damien committed
595
596
}

597
void mp_emit_bc_delete_name(emit_t *emit, qstr qst) {
598
    emit_bc_pre(emit, 0);
599
    emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qst);
Damien's avatar
Damien committed
600
601
}

602
void mp_emit_bc_delete_global(emit_t *emit, qstr qst) {
603
    emit_bc_pre(emit, 0);
604
    emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qst);
Damien's avatar
Damien committed
605
606
}

607
608
609
610
void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) {
    mp_emit_bc_load_null(emit);
    mp_emit_bc_rot_two(emit);
    mp_emit_bc_store_attr(emit, qst);
Damien's avatar
Damien committed
611
612
}

613
614
615
616
void mp_emit_bc_delete_subscr(emit_t *emit) {
    mp_emit_bc_load_null(emit);
    mp_emit_bc_rot_three(emit);
    mp_emit_bc_store_subscr(emit);
Damien's avatar
Damien committed
617
618
}

619
void mp_emit_bc_dup_top(emit_t *emit) {
620
    emit_bc_pre(emit, 1);
621
    emit_write_bytecode_byte(emit, MP_BC_DUP_TOP);
Damien's avatar
Damien committed
622
623
}

624
void mp_emit_bc_dup_top_two(emit_t *emit) {
625
    emit_bc_pre(emit, 2);
626
    emit_write_bytecode_byte(emit, MP_BC_DUP_TOP_TWO);
Damien's avatar
Damien committed
627
628
}

629
void mp_emit_bc_pop_top(emit_t *emit) {
630
    emit_bc_pre(emit, -1);
631
    emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
Damien's avatar
Damien committed
632
633
}

634
void mp_emit_bc_rot_two(emit_t *emit) {
635
    emit_bc_pre(emit, 0);
636
    emit_write_bytecode_byte(emit, MP_BC_ROT_TWO);
Damien's avatar
Damien committed
637
638
}

639
void mp_emit_bc_rot_three(emit_t *emit) {
640
    emit_bc_pre(emit, 0);
641
    emit_write_bytecode_byte(emit, MP_BC_ROT_THREE);
Damien's avatar
Damien committed
642
643
}

644
void mp_emit_bc_jump(emit_t *emit, mp_uint_t label) {
645
    emit_bc_pre(emit, 0);
646
    emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label);
Damien's avatar
Damien committed
647
648
}

649
void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {
650
    emit_bc_pre(emit, -1);
651
652
653
654
655
    if (cond) {
        emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label);
    } else {
        emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label);
    }
Damien's avatar
Damien committed
656
657
}

658
void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {
659
    emit_bc_pre(emit, -1);
660
661
662
663
664
    if (cond) {
        emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label);
    } else {
        emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label);
    }
Damien's avatar
Damien committed
665
666
}

667
void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
668
    if (except_depth == 0) {
669
        emit_bc_pre(emit, 0);
670
671
672
673
674
675
676
677
        if (label & MP_EMIT_BREAK_FROM_FOR) {
            // need to pop the iterator if we are breaking out of a for loop
            emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
        }
        emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
    } else {
        emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
        emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth);
678
    }
Damien's avatar
Damien committed
679
680
}

681
void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) {
682
683
684
685
    // TODO We can probably optimise the amount of needed stack space, since
    // we don't actually need 4 slots during the entire with block, only in
    // the cleanup handler in certain cases.  It needs some thinking.
    emit_bc_pre(emit, 4);
686
    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
Damien's avatar
Damien committed
687
688
}

689
void mp_emit_bc_with_cleanup(emit_t *emit) {
690
    emit_bc_pre(emit, -4);
691
    emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP);
Damien's avatar
Damien committed
692
693
}

694
void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) {
695
    emit_bc_pre(emit, 0);
696
    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
Damien's avatar
Damien committed
697
698
}

699
void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label) {
700
    emit_bc_pre(emit, 0);
701
    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
Damien's avatar
Damien committed
702
703
}

704
void mp_emit_bc_end_finally(emit_t *emit) {
705
    emit_bc_pre(emit, -1);
706
    emit_write_bytecode_byte(emit, MP_BC_END_FINALLY);
Damien's avatar
Damien committed
707
708
}

709
void mp_emit_bc_get_iter(emit_t *emit) {
710
    emit_bc_pre(emit, 0);
711
    emit_write_bytecode_byte(emit, MP_BC_GET_ITER);
Damien's avatar
Damien committed
712
713
}

714
void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label) {
715
    emit_bc_pre(emit, 1);
716
    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label);
Damien's avatar
Damien committed
717
718
}

719
void mp_emit_bc_for_iter_end(emit_t *emit) {
720
    emit_bc_pre(emit, -1);
Damien's avatar
Damien committed
721
722
}

723
void mp_emit_bc_pop_block(emit_t *emit) {
724
    emit_bc_pre(emit, 0);
725
    emit_write_bytecode_byte(emit, MP_BC_POP_BLOCK);
Damien's avatar
Damien committed
726
727
}

728
void mp_emit_bc_pop_except(emit_t *emit) {
729
    emit_bc_pre(emit, 0);
730
    emit_write_bytecode_byte(emit, MP_BC_POP_EXCEPT);
Damien's avatar
Damien committed
731
732
}

733
void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
Damien George's avatar
Damien George committed
734
    if (op == MP_UNARY_OP_NOT) {
735
        emit_bc_pre(emit, 0);
736
        emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_BOOL);
737
        emit_bc_pre(emit, 0);
738
        emit_write_bytecode_byte(emit, MP_BC_NOT);
739
    } else {
740
        emit_bc_pre(emit, 0);
741
        emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op);
742
    }
Damien's avatar
Damien committed
743
744
}

745
void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
746
    bool invert = false;
Damien George's avatar
Damien George committed
747
    if (op == MP_BINARY_OP_NOT_IN) {
748
        invert = true;
Damien George's avatar
Damien George committed
749
750
        op = MP_BINARY_OP_IN;
    } else if (op == MP_BINARY_OP_IS_NOT) {
751
        invert = true;
Damien George's avatar
Damien George committed
752
        op = MP_BINARY_OP_IS;
753
    }
754
    emit_bc_pre(emit, -1);
755
    emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op);
756
    if (invert) {
757
        emit_bc_pre(emit, 0);
758
        emit_write_bytecode_byte(emit, MP_BC_NOT);
759
    }
Damien's avatar
Damien committed
760
761
}

762
void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args) {
763
    emit_bc_pre(emit, 1 - n_args);
764
    emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args);
Damien's avatar
Damien committed
765
766
}

767
void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args) {
768
    emit_bc_pre(emit, 1 - n_args);
769
    emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args);
Damien's avatar
Damien committed
770
771
}

772
void mp_emit_bc_list_append(emit_t *emit, mp_uint_t list_stack_index) {
773
    emit_bc_pre(emit, -1);
774
    emit_write_bytecode_byte_uint(emit, MP_BC_LIST_APPEND, list_stack_index);
Damien's avatar
Damien committed
775
776
}

777
void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args) {
778
    emit_bc_pre(emit, 1);
779
    emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args);
Damien's avatar
Damien committed
780
781
}

782
void mp_emit_bc_store_map(emit_t *emit) {
783
    emit_bc_pre(emit, -2);
784
    emit_write_bytecode_byte(emit, MP_BC_STORE_MAP);
Damien's avatar
Damien committed
785
786
}

787
void mp_emit_bc_map_add(emit_t *emit, mp_uint_t map_stack_index) {
788
    emit_bc_pre(emit, -2);
789
    emit_write_bytecode_byte_uint(emit, MP_BC_MAP_ADD, map_stack_index);
Damien's avatar
Damien committed
790
791
}

792
#if MICROPY_PY_BUILTINS_SET
793
void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args) {
794
    emit_bc_pre(emit, 1 - n_args);
795
    emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args);
Damien's avatar
Damien committed
796
797
}

798
void mp_emit_bc_set_add(emit_t *emit, mp_uint_t set_stack_index) {
799
    emit_bc_pre(emit, -1);
800
    emit_write_bytecode_byte_uint(emit, MP_BC_SET_ADD, set_stack_index);
Damien's avatar
Damien committed
801
}
802
#endif
Damien's avatar
Damien committed
803

804
#if MICROPY_PY_BUILTINS_SLICE
805
void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) {
806
    emit_bc_pre(emit, 1 - n_args);
807
    emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args);
Damien's avatar
Damien committed
808
}
809
#endif
Damien's avatar
Damien committed
810

</