Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/mast/compiler.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include "nodes.h"
3
4
/* Some constants. */
5
#define HEADER_SIZE                 92
6
1.21k
#define BYTECODE_VERSION            5
7
9.05k
#define FRAME_HEADER_SIZE           (11 * 4 + 3 * 2)
8
431
#define FRAME_HANDLER_SIZE          (4 * 4 + 2 * 2)
9
5.61k
#define FRAME_SLV_SIZE              (2 * 2 + 2 * 4)
10
3.41k
#define SC_DEP_SIZE                 4
11
1.21k
#define EXTOP_SIZE                  (4 + 8)
12
2.43k
#define SCDEP_HEADER_OFFSET         12
13
2.43k
#define EXTOP_HEADER_OFFSET         20
14
2.43k
#define FRAME_HEADER_OFFSET         28
15
2.43k
#define CALLSITE_HEADER_OFFSET      36
16
2.43k
#define STRING_HEADER_OFFSET        44
17
0
#define SCDATA_HEADER_OFFSET        52
18
2.43k
#define BYTECODE_HEADER_OFFSET      60
19
2.43k
#define ANNOTATION_HEADER_OFFSET    68
20
1.21k
#define HLL_NAME_HEADER_OFFSET      76
21
3.64k
#define SPECIAL_FRAME_HEADER_OFFSET 80
22
0
#define EXTOP_BASE                  1024
23
24
/* Frame flags. */
25
#define FRAME_FLAG_EXIT_HANDLER     1
26
#define FRAME_FLAG_IS_THUNK         2
27
4.52k
#define FRAME_FLAG_HAS_CODE_OBJ     4
28
#define FRAME_FLAG_NO_INLINE        8
29
8.68k
#define FRAME_FLAG_HAS_INDEX        32768
30
4.52k
#define FRAME_FLAG_HAS_SLV          65536
31
32
typedef struct {
33
    /* callsite ID */
34
    unsigned short callsite_id;
35
36
    /* the identifier for the callsite, to clean up later */
37
    unsigned char *identifier;
38
39
    /* the uthash hash handle. */
40
    UT_hash_handle hash_handle;
41
} CallsiteReuseEntry;
42
43
/* Information about a handler. */
44
typedef struct {
45
    /* Offset of start of protected region from frame start. */
46
    unsigned int start_offset;
47
48
    /* Offset of end of protected region, exclusive, from frame start. */
49
    unsigned int end_offset;
50
51
    /* Exception categry mask. */
52
    unsigned int category_mask;
53
54
    /* Handler action. */
55
    unsigned short action;
56
57
    /* Local holding block to invoke, if invokey handler. */
58
    unsigned short local;
59
60
    /* Label, which will need resolving. */
61
    MASTNode *label;
62
63
    /* Local holding a label in case we have a labeled loop. */
64
    unsigned short label_reg;
65
} FrameHandler;
66
67
/* Handler actions. */
68
317
#define HANDLER_UNWIND_GOTO      0
69
29
#define HANDLER_UNWIND_GOTO_OBJ  1
70
431
#define HANDLER_INVOKE           2
71
72
/* Information about a label. */
73
typedef struct {
74
    MAST_Label *label;
75
    MVMint32    offset;          /* Negative if unknown. */
76
    MVMuint16   num_resolve;
77
    MVMuint16   alloc_resolve;
78
    MVMuint32  *resolve;
79
} LabelInfo;
80
81
/* Describes the state for the frame we're currently compiling. */
82
typedef struct {
83
    /* Position of start of bytecode. */
84
    unsigned int bytecode_start;
85
86
    /* Position of start of frame entry. */
87
    unsigned int frame_start;
88
89
    /* Types of locals and lexicals, with counts. */
90
    unsigned short *local_types;
91
    unsigned short *lexical_types;
92
    unsigned int num_locals;
93
    unsigned int num_lexicals;
94
95
    /* Number of annotations. */
96
    unsigned int num_annotations;
97
98
    /* Handlers count and list. */
99
    unsigned int num_handlers;
100
    FrameHandler *handlers;
101
102
    /* Labels we have so far (either through finding them or finding a need
103
     * to fix them up). */
104
    LabelInfo *labels;
105
    unsigned int num_labels;
106
    unsigned int alloc_labels;
107
108
    /* Number of unresolved labels. */
109
    unsigned int unresolved_labels;
110
} FrameState;
111
112
/* Describes the current writer state for the compilation unit as a whole. */
113
typedef struct {
114
    /* The set of node types. */
115
    MASTNodeTypes *types;
116
117
    /* The current frame and frame count. */
118
    FrameState   *cur_frame;
119
    unsigned int  num_frames;
120
121
    /* String heap and seen hash mapping known strings to indexes. */
122
    MASTNode *strings;
123
    MASTNode *seen_strings;
124
125
    /* The SC dependencies segment; we know the size up front. */
126
    char         *scdep_seg;
127
    unsigned int  scdep_bytes;
128
129
    /* The extension ops segment; we know the size ahead of time. */
130
    char         *extops_seg;
131
    unsigned int  extops_bytes;
132
    unsigned int  num_extops;
133
134
    /* The frame segment. */
135
    char         *frame_seg;
136
    unsigned int  frame_pos;
137
    unsigned int  frame_alloc;
138
139
    /* The callsite segment and number of callsites. */
140
    char         *callsite_seg;
141
    unsigned int  callsite_pos;
142
    unsigned int  callsite_alloc;
143
    unsigned int  num_callsites;
144
145
    /* The bytecode segment. */
146
    char         *bytecode_seg;
147
    unsigned int  bytecode_pos;
148
    unsigned int  bytecode_alloc;
149
150
    /* The annotation segment. */
151
    char         *annotation_seg;
152
    unsigned int  annotation_pos;
153
    unsigned int  annotation_alloc;
154
155
    /* Current instruction info */
156
    const MVMOpInfo    *current_op_info;
157
158
    /* Zero-based index of current frame */
159
    unsigned int  current_frame_idx;
160
161
    /* Zero-based index of MAST instructions */
162
    unsigned int  current_ins_idx;
163
164
    /* Zero-based index of current operand */
165
    unsigned int  current_operand_idx;
166
167
    /* The compilation unit we're compiling. */
168
    MAST_CompUnit *cu;
169
170
    /* Hash for callsite descriptor strings to callsite IDs */
171
    CallsiteReuseEntry *callsite_reuse_head;
172
173
    /* Last Annotated node, for error reporting */
174
    MAST_Annotated *last_annotated;
175
} WriterState;
176
177
static unsigned int umax(unsigned int a, unsigned int b);
178
static void memcpy_endian(char *dest, const void *src, size_t size);
179
static void write_int64(char *buffer, size_t offset, unsigned long long value);
180
static void write_int32(char *buffer, size_t offset, unsigned int value);
181
static void write_int16(char *buffer, size_t offset, unsigned short value);
182
static void write_int8(char *buffer, size_t offset, unsigned char value);
183
static void write_double(char *buffer, size_t offset, double value);
184
static void ensure_space(VM, char **buffer, unsigned int *alloc, unsigned int pos, unsigned int need);
185
static void cleanup_frame(VM, FrameState *fs);
186
static void cleanup_all(VM, WriterState *ws);
187
static unsigned int get_string_heap_index(VM, WriterState *ws, VMSTR *strval);
188
static unsigned short get_frame_index(VM, WriterState *ws, MASTNode *frame);
189
static unsigned short type_to_local_type(VM, WriterState *ws, MASTNode *type);
190
static void compile_operand(VM, WriterState *ws, unsigned char op_flags, MASTNode *operand);
191
static unsigned short get_callsite_id(VM, WriterState *ws, MASTNode *flags, MASTNode *args);
192
static void compile_instruction(VM, WriterState *ws, MASTNode *node);
193
static void compile_frame(VM, WriterState *ws, MASTNode *node, unsigned short idx);
194
static char * form_string_heap(VM, WriterState *ws, unsigned int *string_heap_size);
195
static char * form_bytecode_output(VM, WriterState *ws, unsigned int *bytecode_size);
196
char * MVM_mast_compile(VM, MASTNode *node, MASTNodeTypes *types, unsigned int *size);
197
198
0
static unsigned int umax(unsigned int a, unsigned int b) {
199
0
    return a > b ? a : b;
200
0
}
201
202
/* copies memory dependent on endianness */
203
1.17M
static void memcpy_endian(char *dest, const void *src, size_t size) {
204
1.17M
#ifdef MVM_BIGENDIAN
205
    size_t i;
206
    char *srcbytes = (char *)src;
207
    for (i = 0; i < size; i++)
208
        dest[size - i - 1] = srcbytes[i];
209
#else
210
1.17M
    memcpy(dest, src, size);
211
1.17M
#endif
212
1.17M
}
213
214
/* Writes an int64 into a buffer. */
215
1.29k
static void write_int64(char *buffer, size_t offset, unsigned long long value) {
216
1.29k
    memcpy_endian(buffer + offset, &value, 8);
217
1.29k
}
218
219
/* Writes an int32 into a buffer. */
220
263k
static void write_int32(char *buffer, size_t offset, unsigned int value) {
221
263k
    memcpy_endian(buffer + offset, &value, 4);
222
263k
}
223
224
/* Writes an int16 into a buffer. */
225
909k
static void write_int16(char *buffer, size_t offset, unsigned short value) {
226
909k
    memcpy_endian(buffer + offset, &value, 2);
227
909k
}
228
229
/* Writes an int8 into a buffer. */
230
9.93k
static void write_int8(char *buffer, size_t offset, unsigned char value) {
231
9.93k
    memcpy(buffer + offset, &value, 1);
232
9.93k
}
233
234
/* Writes an double into a buffer. */
235
498
static void write_double(char *buffer, size_t offset, double value) {
236
498
    memcpy_endian(buffer + offset, &value, 8);
237
498
}
238
239
/* Ensures the specified buffer has enough space and expands it if so. */
240
879k
static void ensure_space(VM, char **buffer, unsigned int *alloc, unsigned int pos, unsigned int need) {
241
879k
    if (pos + need > *alloc) {
242
2.44k
        do { *alloc = *alloc * 2; } while (pos + need > *alloc);
243
2.44k
        *buffer = (char *)MVM_realloc(*buffer, *alloc);
244
2.44k
    }
245
879k
}
246
247
/* Cleans up all allocated memory related to a frame. */
248
4.52k
static void cleanup_frame(VM, FrameState *fs) {
249
4.52k
    if (fs->local_types)
250
4.52k
        MVM_free(fs->local_types);
251
4.52k
    if (fs->lexical_types)
252
4.52k
        MVM_free(fs->lexical_types);
253
4.52k
    if (fs->handlers)
254
124
        MVM_free(fs->handlers);
255
4.52k
    if (fs->labels) {
256
1.79k
        MVMuint32 i;
257
21.4k
        for (i = 0; i < fs->num_labels; i++)
258
19.6k
            if (fs->labels[i].alloc_resolve)
259
0
                MVM_free(fs->labels[i].resolve);
260
1.79k
        MVM_free(fs->labels);
261
1.79k
    }
262
4.52k
    MVM_free(fs);
263
4.52k
}
264
265
/* Cleans up all allocated memory related to this compilation. */
266
1.21k
static void cleanup_all(VM, WriterState *ws) {
267
1.21k
    CallsiteReuseEntry *current, *tmp;
268
1.21k
    unsigned bucket_tmp;
269
1.21k
    if (ws->cur_frame)
270
0
        cleanup_frame(vm, ws->cur_frame);
271
1.21k
    if (ws->scdep_seg)
272
1.12k
        MVM_free(ws->scdep_seg);
273
1.21k
    if (ws->extops_seg)
274
1.21k
        MVM_free(ws->extops_seg);
275
1.21k
    if (ws->frame_seg)
276
1.21k
        MVM_free(ws->frame_seg);
277
1.21k
    if (ws->callsite_seg)
278
1.21k
        MVM_free(ws->callsite_seg);
279
1.21k
    if (ws->bytecode_seg)
280
1.21k
        MVM_free(ws->bytecode_seg);
281
1.21k
    if (ws->annotation_seg)
282
1.21k
        MVM_free(ws->annotation_seg);
283
3.59k
    HASH_ITER(hash_handle, ws->callsite_reuse_head, current, tmp, bucket_tmp) {
284
3.59k
        MVM_free(current->identifier);
285
3.59k
    }
286
1.21k
    MVM_HASH_DESTROY(tc, hash_handle, CallsiteReuseEntry, ws->callsite_reuse_head);
287
1.21k
    MVM_free(ws);
288
1.21k
}
289
290
/* Gets the index of a string already in the string heap, or
291
 * adds it to the heap if it's not already there. */
292
72.4k
static unsigned int get_string_heap_index(VM, WriterState *ws, VMSTR *strval) {
293
72.4k
    if (EXISTSKEY(vm, ws->seen_strings, strval)) {
294
38.3k
        return (unsigned int)ATKEY_I(vm, ws->seen_strings, strval);
295
38.3k
    }
296
34.0k
    else {
297
34.0k
        unsigned int index = (unsigned int)ELEMS(vm, ws->strings);
298
34.0k
        if (index >= 0x7FFFFFFF) {
299
0
            cleanup_all(vm, ws);
300
0
            DIE(vm, "Too many strings in compilation unit");
301
0
        }
302
34.0k
        BINDPOS_S(vm, ws->strings, index, strval);
303
34.0k
        BINDKEY_I(vm, ws->seen_strings, strval, index);
304
34.0k
        return index;
305
34.0k
    }
306
72.4k
}
307
308
/* Locates the index of a frame. */
309
6.73k
static unsigned short get_frame_index(VM, WriterState *ws, MASTNode *frame) {
310
6.73k
    if (((MAST_Frame *)frame)->flags & FRAME_FLAG_HAS_INDEX) {
311
6.73k
        return (short)((MAST_Frame *)frame)->index;
312
6.73k
    }
313
0
    else {
314
0
        int num_frames = ELEMS(vm, ws->cu->frames);
315
0
        unsigned short i;
316
0
        for (i = 0; i < num_frames; i++)
317
0
            if (ATPOS(vm, ws->cu->frames, i) == frame)
318
0
                return i;
319
0
        cleanup_all(vm, ws);
320
0
        DIE(vm, "MAST::Frame passed for code ref not found in compilation unit");
321
0
    }
322
6.73k
}
323
324
/* Takes a 6model object type and turns it into a local/lexical type flag. */
325
61.4k
static unsigned short type_to_local_type(VM, WriterState *ws, MASTNode *type) {
326
61.4k
    const MVMStorageSpec *ss;
327
61.4k
    if (VM_OBJ_IS_NULL(type))
328
0
        return MVM_reg_obj;
329
61.4k
    ss = REPR(type)->get_storage_spec(vm, STABLE(type));
330
61.4k
    if (ss->inlineable) {
331
25.0k
        switch (ss->boxed_primitive) {
332
20.3k
            case MVM_STORAGE_SPEC_BP_INT:
333
20.3k
                if (ss->is_unsigned) {
334
0
                    switch (ss->bits) {
335
0
                        case 8:
336
0
                            return MVM_reg_uint8;
337
0
                        case 16:
338
0
                            return MVM_reg_uint16;
339
0
                        case 32:
340
0
                            return MVM_reg_uint32;
341
0
                        case 64:
342
0
                            return MVM_reg_uint64;
343
0
                        default:
344
0
                            cleanup_all(vm, ws);
345
0
                            DIE(vm, "Invalid int size for local/lexical");
346
0
                    }
347
0
                }
348
20.3k
                else {
349
20.3k
                    switch (ss->bits) {
350
2
                        case 8:
351
2
                            return MVM_reg_int8;
352
2
                        case 16:
353
2
                            return MVM_reg_int16;
354
2
                        case 32:
355
2
                            return MVM_reg_int32;
356
20.3k
                        case 64:
357
20.3k
                            return MVM_reg_int64;
358
0
                        default:
359
0
                            cleanup_all(vm, ws);
360
0
                            DIE(vm, "Invalid int size for local/lexical");
361
20.3k
                    }
362
20.3k
                }
363
0
                break;
364
759
            case MVM_STORAGE_SPEC_BP_NUM:
365
759
                switch (ss->bits) {
366
0
                    case 32:
367
0
                        return MVM_reg_num32;
368
759
                    case 64:
369
759
                        return MVM_reg_num64;
370
0
                    default:
371
0
                        cleanup_all(vm, ws);
372
0
                        DIE(vm, "Invalid num size for local/lexical");
373
759
                }
374
0
                break;
375
3.95k
            case MVM_STORAGE_SPEC_BP_STR:
376
3.95k
                return MVM_reg_str;
377
0
            default:
378
0
                cleanup_all(vm, ws);
379
0
                DIE(vm, "Type used for local/lexical has invalid boxed primitive in storage spec");
380
25.0k
        }
381
25.0k
    }
382
36.3k
    else {
383
36.3k
        return MVM_reg_obj;
384
36.3k
    }
385
61.4k
}
386
387
/* Grows label storage. */
388
19.6k
static void add_label(VM, FrameState *fs, MAST_Label *l, MVMint32 offset) {
389
19.6k
    if (fs->num_labels == fs->alloc_labels) {
390
3.43k
        if (fs->alloc_labels)
391
1.64k
            fs->alloc_labels *= 2;
392
3.43k
        else
393
1.79k
            fs->alloc_labels = 8;
394
3.43k
        fs->labels = MVM_realloc(fs->labels, fs->alloc_labels * sizeof(LabelInfo));
395
3.43k
    }
396
19.6k
    fs->labels[fs->num_labels].label         = l;
397
19.6k
    fs->labels[fs->num_labels].offset        = offset;
398
19.6k
    fs->labels[fs->num_labels].resolve       = NULL;
399
19.6k
    fs->labels[fs->num_labels].num_resolve   = 0;
400
19.6k
    fs->labels[fs->num_labels].alloc_resolve = 0;
401
19.6k
    fs->num_labels++;
402
19.6k
}
403
404
/* Takes a label and either writes its offset if we already saw it, or writes
405
 * a zero and records that a fixups is needed. */
406
31.1k
static void write_label_or_add_fixup(VM, WriterState *ws, MAST_Label *l) {
407
31.1k
    FrameState *fs   = ws->cur_frame;
408
31.1k
    LabelInfo  *info = NULL;
409
31.1k
    MVMuint32   i;
410
31.1k
411
31.1k
    /* Ensure we've space to write an offset. */
412
31.1k
    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 4);
413
31.1k
414
31.1k
    /* Look for the label. */
415
248k
    for (i = 0; i < fs->num_labels; i++) {
416
233k
        if (fs->labels[i].label == l) {
417
16.2k
            /* Found it. If we know its offset, write and we're done. */
418
16.2k
            MVMint32 offset = fs->labels[i].offset;
419
16.2k
            if (offset >= 0) {
420
6.72k
                write_int32(ws->bytecode_seg, ws->bytecode_pos, offset);
421
6.72k
                ws->bytecode_pos += 4;
422
6.72k
                return;
423
6.72k
            }
424
16.2k
425
16.2k
            /* Otherwise, note this label to add the resolve need to. */
426
9.57k
            info = &(fs->labels[i]);
427
9.57k
            break;
428
16.2k
        }
429
233k
    }
430
31.1k
431
31.1k
    /* If we don't have an entry for this label yet, add it. */
432
24.4k
    if (!info) {
433
14.8k
        add_label(vm, fs, l, -1);
434
14.8k
        info = &(fs->labels[fs->num_labels - 1]);
435
14.8k
    }
436
24.4k
    if (info->num_resolve == info->alloc_resolve) {
437
14.9k
        if (info->alloc_resolve)
438
109
            info->alloc_resolve *= 2;
439
14.9k
        else
440
14.8k
            info->alloc_resolve = 8;
441
14.9k
        info->resolve = MVM_realloc(info->resolve, info->alloc_resolve * sizeof(MVMuint32));
442
14.9k
    }
443
24.4k
    info->resolve[info->num_resolve] = ws->bytecode_pos;
444
24.4k
    info->num_resolve++;
445
24.4k
    fs->unresolved_labels++;
446
24.4k
447
24.4k
    /* Write zero, to be fixed up later. */
448
24.4k
    write_int32(ws->bytecode_seg, ws->bytecode_pos, 0);
449
24.4k
    ws->bytecode_pos += 4;
450
24.4k
}
451
452
/* Takes a label, and either adds it to the labels collection or, if it's been
453
 * seen already, resolves its fixups. */
454
19.6k
static void add_label_and_resolve_fixups(VM, WriterState *ws, MAST_Label *l) {
455
19.6k
    FrameState *fs     = ws->cur_frame;
456
19.6k
    MVMuint32   offset = ws->bytecode_pos - ws->cur_frame->bytecode_start;
457
19.6k
    MVMuint32   i, j;
458
19.6k
459
19.6k
    /* See if it has an existing entry. */
460
179k
    for (i = 0; i < fs->num_labels; i++) {
461
175k
        if (fs->labels[i].label == l) {
462
14.8k
            /* Found it. Must not already have an offset, or it's a dupe. */
463
14.8k
            if (fs->labels[i].offset < 0) {
464
14.8k
                /* Fix up existing usages. */
465
14.8k
                MVMuint32 *resolve = fs->labels[i].resolve;
466
14.8k
                MVMuint32  nr      = fs->labels[i].num_resolve;
467
39.2k
                for (j = 0; j < nr; j++)
468
24.4k
                    write_int32(ws->bytecode_seg, resolve[j], offset);
469
14.8k
                fs->labels[i].offset        = offset;
470
14.8k
                fs->labels[i].alloc_resolve = 0;
471
14.8k
                fs->labels[i].num_resolve   = 0;
472
14.8k
                fs->unresolved_labels      -= nr;
473
14.8k
                MVM_free(fs->labels[i].resolve);
474
14.8k
            }
475
0
            else {
476
0
                cleanup_all(vm, ws);
477
0
                DIE(vm, "Duplicate label");
478
0
            }
479
14.8k
            return;
480
14.8k
        }
481
175k
    }
482
19.6k
483
19.6k
    /* If we get here, no entry; create one. */
484
4.78k
    add_label(vm, fs, l, offset);
485
4.78k
}
486
487
/* Rreturns a label's offset, dying if it's not possible. */
488
static MVMuint32 demand_label_offset(VM, WriterState *ws, MAST_Label *l,
489
431
                                     const char *error) {
490
431
    FrameState *fs = ws->cur_frame;
491
431
    MVMuint32   nl = fs->num_labels;
492
431
    MVMuint32   i;
493
7.44k
    for (i = 0; i < nl; i++) {
494
7.44k
        if (fs->labels[i].label == l) {
495
431
            if (fs->labels[i].offset >= 0)
496
431
                return fs->labels[i].offset;
497
0
            break;
498
431
        }
499
7.44k
    }
500
0
    cleanup_all(vm, ws);
501
0
    DIE(vm, "%s", error);
502
0
}
503
504
/* Compiles the operand to an instruction; this involves checking
505
 * that we have a node of the correct type for it and writing out
506
 * the appropriate thing to the bytecode stream. */
507
545k
static void compile_operand(VM, WriterState *ws, unsigned char op_flags, MASTNode *operand) {
508
545k
    unsigned char op_rw   = op_flags & MVM_operand_rw_mask;
509
545k
    unsigned char op_type = op_flags & MVM_operand_type_mask;
510
545k
    unsigned short int local_type;
511
545k
    if (op_rw == MVM_operand_literal) {
512
119k
        /* Literal; go by type. */
513
119k
        switch (op_type) {
514
1.29k
            case MVM_operand_int64: {
515
1.29k
                if (ISTYPE(vm, operand, ws->types->IVal)) {
516
1.29k
                    MAST_IVal *iv = GET_IVal(operand);
517
1.29k
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 8);
518
1.29k
                    write_int64(ws->bytecode_seg, ws->bytecode_pos, iv->value);
519
1.29k
                    ws->bytecode_pos += 8;
520
1.29k
                }
521
0
                else {
522
0
                    cleanup_all(vm, ws);
523
0
                    DIE(vm, "Expected MAST::IVal, but didn't get one");
524
0
                }
525
1.29k
                break;
526
1.29k
            }
527
38.7k
            case MVM_operand_int16: {
528
38.7k
                if (ISTYPE(vm, operand, ws->types->IVal)) {
529
38.7k
                    MAST_IVal *iv = GET_IVal(operand);
530
38.7k
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
531
38.7k
                    if (iv->value > 32767 || iv->value < -32768) {
532
0
                        cleanup_all(vm, ws);
533
0
                        DIE(vm, "Value outside range of 16-bit MAST::IVal");
534
0
                    }
535
38.7k
                    write_int16(ws->bytecode_seg, ws->bytecode_pos, (short)iv->value);
536
38.7k
                    ws->bytecode_pos += 2;
537
38.7k
                }
538
0
                else {
539
0
                    cleanup_all(vm, ws);
540
0
                    DIE(vm, "Expected MAST::IVal, but didn't get one");
541
0
                }
542
38.7k
                break;
543
1.29k
            }
544
498
            case MVM_operand_num64: {
545
498
                if (ISTYPE(vm, operand, ws->types->NVal)) {
546
498
                    MAST_NVal *nv = GET_NVal(operand);
547
498
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 8);
548
498
                    write_double(ws->bytecode_seg, ws->bytecode_pos, nv->value);
549
498
                    ws->bytecode_pos += 8;
550
498
                }
551
0
                else {
552
0
                    cleanup_all(vm, ws);
553
0
                    DIE(vm, "Expected MAST::NVal, but didn't get one");
554
0
                }
555
498
                break;
556
1.29k
            }
557
42.1k
            case MVM_operand_str: {
558
42.1k
                if (ISTYPE(vm, operand, ws->types->SVal)) {
559
42.1k
                    MAST_SVal *sv = GET_SVal(operand);
560
42.1k
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 4);
561
42.1k
                    write_int32(ws->bytecode_seg, ws->bytecode_pos,
562
42.1k
                        get_string_heap_index(vm, ws, sv->value));
563
42.1k
                    ws->bytecode_pos += 4;
564
42.1k
                }
565
0
                else {
566
0
                    cleanup_all(vm, ws);
567
0
                    DIE(vm, "Expected MAST::SVal, but didn't get one");
568
0
                }
569
42.1k
                break;
570
1.29k
            }
571
31.1k
            case MVM_operand_ins: {
572
31.1k
                if (ISTYPE(vm, operand, ws->types->Label)) {
573
31.1k
                    write_label_or_add_fixup(vm, ws, GET_Label(operand));
574
31.1k
                }
575
0
                else {
576
0
                    cleanup_all(vm, ws);
577
0
                    DIE(vm, "Expected MAST::Label, but didn't get one");
578
0
                }
579
31.1k
                break;
580
1.29k
            }
581
5.36k
            case MVM_operand_coderef: {
582
5.36k
                if (ISTYPE(vm, operand, ws->types->Frame)) {
583
5.36k
                    /* Find the frame index in the compilation unit. */
584
5.36k
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
585
5.36k
                    write_int16(ws->bytecode_seg, ws->bytecode_pos,
586
5.36k
                        get_frame_index(vm, ws, operand));
587
5.36k
                    ws->bytecode_pos += 2;
588
5.36k
                }
589
0
                else {
590
0
                    cleanup_all(vm, ws);
591
0
                    DIE(vm, "Expected MAST::Frame, but didn't get one");
592
0
                }
593
5.36k
                break;
594
1.29k
            }
595
0
            default:
596
0
                cleanup_all(vm, ws);
597
0
                DIE(vm, "Unhandled literal type in MAST compiler");
598
119k
        }
599
119k
    }
600
426k
    else if (op_rw == MVM_operand_read_reg || op_rw == MVM_operand_write_reg) {
601
422k
        /* The operand node had best be a MAST::Local. */
602
422k
        if (ISTYPE(vm, operand, ws->types->Local)) {
603
422k
            MAST_Local *l = GET_Local(operand);
604
422k
605
422k
            /* Ensure it's within the set of known locals. */
606
422k
            if (l->index >= ws->cur_frame->num_locals) {
607
0
                cleanup_all(vm, ws);
608
0
                DIE(vm, "MAST::Local index out of range");
609
0
            }
610
422k
611
422k
            /* Check the type matches. */
612
422k
            local_type = ws->cur_frame->local_types[l->index];
613
422k
            if (op_type != local_type << 3 && op_type != MVM_operand_type_var) {
614
0
                unsigned int  current_frame_idx = ws->current_frame_idx;
615
0
                unsigned int  current_ins_idx = ws->current_ins_idx;
616
0
                const char *name = ws->current_op_info->name;
617
0
                unsigned int  current_operand_idx = ws->current_operand_idx;
618
0
                cleanup_all(vm, ws);
619
0
                DIE(vm, "At Frame %u, Instruction %u, op '%s', operand %u, "
620
0
                    "MAST::Local of wrong type (%u) specified; expected %u",
621
0
                    current_frame_idx, current_ins_idx,
622
0
                    name, current_operand_idx,
623
0
                    local_type, (op_type >> 3));
624
0
            }
625
422k
626
422k
            /* Write the operand type. */
627
422k
            if (l->index < 0 || l->index > 32768)
628
0
                DIE(vm, "Frame %u local access out of range", ws->current_frame_idx);
629
422k
            ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
630
422k
            write_int16(ws->bytecode_seg, ws->bytecode_pos, (unsigned short)l->index);
631
422k
            ws->bytecode_pos += 2;
632
422k
        }
633
0
        else {
634
0
            unsigned int  current_frame_idx = ws->current_frame_idx;
635
0
            unsigned int  current_ins_idx = ws->current_ins_idx;
636
0
            const char *name = ws->current_op_info->name;
637
0
            unsigned int  current_operand_idx = ws->current_operand_idx;
638
0
            cleanup_all(vm, ws);
639
0
            DIE(vm, "At Frame %u, Instruction %u, op '%s', operand %u, expected MAST::Local, but didn't get one",
640
0
                current_frame_idx, current_ins_idx, name, current_operand_idx);
641
0
        }
642
422k
    }
643
4.26k
    else if (op_rw == MVM_operand_read_lex || op_rw == MVM_operand_write_lex) {
644
4.26k
        /* The operand node should be a MAST::Lexical. */
645
4.26k
        if (ISTYPE(vm, operand, ws->types->Lexical)) {
646
4.26k
            MAST_Lexical *l = GET_Lexical(operand);
647
4.26k
648
4.26k
            /* Write the index, then the frame count. */
649
4.26k
            ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 4);
650
4.26k
            write_int16(ws->bytecode_seg, ws->bytecode_pos, (unsigned short)l->index);
651
4.26k
            ws->bytecode_pos += 2;
652
4.26k
            write_int16(ws->bytecode_seg, ws->bytecode_pos, (unsigned short)l->frames_out);
653
4.26k
            ws->bytecode_pos += 2;
654
4.26k
        }
655
0
        else {
656
0
            cleanup_all(vm, ws);
657
0
            DIE(vm, "Expected MAST::Lexical, but didn't get one");
658
0
        }
659
4.26k
    }
660
0
    else {
661
0
        cleanup_all(vm, ws);
662
0
        DIE(vm, "Unknown operand type cannot be compiled");
663
0
    }
664
545k
    ws->current_operand_idx++;
665
545k
}
666
667
/* Takes a set of flags describing a callsite. Writes out a callsite
668
 * descriptor and returns the index of it. */
669
14.9k
static unsigned short get_callsite_id(VM, WriterState *ws, MASTNode *flag_node, MASTNode *args) {
670
14.9k
    unsigned int        num_nameds = 0;
671
14.9k
    unsigned short      i, identifier_len;
672
14.9k
    unsigned char      *flags, *identifier;
673
14.9k
    unsigned int       *named_idxs;
674
14.9k
    CallsiteReuseEntry *entry = NULL;
675
14.9k
676
14.9k
    /* Get callsite elements and work out if a padding byte will be needed. */
677
14.9k
    unsigned short elems = (unsigned short)ELEMS(vm, flag_node);
678
14.9k
    unsigned short align = elems % 2;
679
14.9k
680
14.9k
    /* See if the callsite has any named args, and get string pool entries
681
14.9k
     * for them if so. */
682
14.9k
    flags      = (unsigned char *)MVM_malloc(elems);
683
14.9k
    named_idxs = (unsigned int *)MVM_malloc(elems * sizeof(int));
684
41.8k
    for (i = 0; i < elems; i++) {
685
26.9k
        flags[i] = (unsigned char)ATPOS_I_C(vm, flag_node, i);
686
26.9k
        if (flags[i] & (MVM_CALLSITE_ARG_NAMED)) {
687
3.12k
            MASTNode *argname = ATPOS(vm, args, i + num_nameds);
688
3.12k
            if (ISTYPE(vm, argname, ws->types->SVal)) {
689
3.12k
                named_idxs[num_nameds] = get_string_heap_index(vm, ws,
690
3.12k
                    ((MAST_SVal *)argname)->value);
691
3.12k
                num_nameds++;
692
3.12k
            }
693
0
            else {
694
0
                DIE(vm, "Malformed callsite args: missing MAST::SVal for argument name");
695
0
            }
696
3.12k
        }
697
26.9k
    }
698
14.9k
699
14.9k
    /* See if we already know this callsite. */
700
14.9k
    identifier_len = elems + num_nameds * sizeof(int);
701
14.9k
    identifier     = MVM_malloc(identifier_len);
702
14.9k
    memcpy(identifier, flags, elems);
703
14.9k
    memcpy(identifier + elems, named_idxs, identifier_len - elems);
704
14.9k
    HASH_FIND(hash_handle, ws->callsite_reuse_head, identifier, identifier_len, entry);
705
14.9k
    if (entry) {
706
11.3k
        MVM_free(flags);
707
11.3k
        MVM_free(named_idxs);
708
11.3k
        MVM_free(identifier);
709
11.3k
        return entry->callsite_id;
710
11.3k
    }
711
3.59k
    entry = (CallsiteReuseEntry *)MVM_malloc(sizeof(CallsiteReuseEntry));
712
3.59k
    entry->callsite_id = (unsigned short)ws->num_callsites;
713
3.59k
    entry->identifier = identifier;
714
3.59k
    HASH_ADD_KEYPTR(hash_handle, ws->callsite_reuse_head, identifier, identifier_len, entry);
715
3.59k
716
3.59k
    /* Emit callsite; be sure to pad if there's uneven number of flags. */
717
3.59k
    ensure_space(vm, &ws->callsite_seg, &ws->callsite_alloc, ws->callsite_pos,
718
3.59k
        2 + elems + align);
719
3.59k
    write_int16(ws->callsite_seg, ws->callsite_pos, elems);
720
3.59k
    ws->callsite_pos += 2;
721
10.7k
    for (i = 0; i < elems; i++)
722
7.14k
        write_int8(ws->callsite_seg, ws->callsite_pos++, flags[i]);
723
3.59k
    if (align)
724
2.78k
        write_int8(ws->callsite_seg, ws->callsite_pos++, 0);
725
3.59k
726
3.59k
    /* Emit any nameds. */
727
3.59k
    if (num_nameds) {
728
1.12k
        ensure_space(vm, &ws->callsite_seg, &ws->callsite_alloc, ws->callsite_pos,
729
1.12k
            4 * num_nameds);
730
2.38k
        for (i = 0; i < num_nameds; i++) {
731
1.25k
            write_int32(ws->callsite_seg, ws->callsite_pos, named_idxs[i]);
732
1.25k
            ws->callsite_pos += 4;
733
1.25k
        }
734
1.12k
    }
735
3.59k
736
3.59k
    MVM_free(flags);
737
3.59k
    MVM_free(named_idxs);
738
3.59k
739
3.59k
    return (unsigned short)ws->num_callsites++;
740
3.59k
}
741
742
19.8k
#define OVERRIDE_WITH_32 1
743
39.3k
#define OVERRIDE_WITH_16 2
744
745
/* Compiles an instruction (which may actaully be any of the
746
 * nodes valid directly in a Frame's instruction list, which
747
 * means labels are valid too). */
748
274k
static void compile_instruction(VM, WriterState *ws, MASTNode *node) {
749
274k
    if (ISTYPE(vm, node, ws->types->Op)) {
750
228k
        MAST_Op   *o = GET_Op(node);
751
228k
        const MVMOpInfo *info;
752
228k
        int        i;
753
228k
        unsigned char override_second_argument = 0;
754
228k
755
228k
        /* Look up opcode and get argument info. */
756
228k
        unsigned short op   = o->op;
757
228k
        info = MVM_op_get_op(op);
758
228k
        if (!info)
759
0
            DIE(vm, "Invalid op specified in instruction %d", op);
760
228k
        ws->current_op_info = info;
761
228k
        ws->current_operand_idx = 0;
762
228k
763
228k
        /* Ensure argument count matches up. */
764
228k
        if (info->num_operands != 0 && ELEMS(vm, o->operands) != info->num_operands) {
765
0
            unsigned int  current_frame_idx = ws->current_frame_idx;
766
0
            unsigned int  current_ins_idx = ws->current_ins_idx;
767
0
            const char *name = ws->current_op_info->name;
768
0
            cleanup_all(vm, ws);
769
0
            DIE(vm, "At Frame %u, Instruction %u, op '%s' has invalid number (%u) of operands; needs %u.",
770
0
                current_frame_idx, current_ins_idx, name,
771
0
                ELEMS(vm, o->operands), info->num_operands);
772
0
        }
773
228k
774
228k
        /* If we're outputting a const_i64 instruction, we may want to */
775
228k
        /* turn it into a const_i64_32 or const_i64_16 instead if it fits */
776
228k
        if (op == MVM_OP_const_i64) {
777
19.7k
            MASTNode *operand = ATPOS(vm, o->operands, 1);
778
19.7k
            MAST_IVal *iv = GET_IVal(operand);
779
19.7k
            if (INT16_MIN <= iv->value && iv->value <= INT16_MAX) {
780
19.6k
                override_second_argument = OVERRIDE_WITH_16;
781
86
            } else if (INT32_MIN <= iv->value && iv->value <= INT32_MAX) {
782
86
                override_second_argument = OVERRIDE_WITH_32;
783
86
            }
784
19.7k
        }
785
228k
786
228k
        /* Write opcode. */
787
228k
        ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
788
228k
        if (override_second_argument == 0)
789
208k
            write_int16(ws->bytecode_seg, ws->bytecode_pos, op);
790
19.7k
        else if (override_second_argument == OVERRIDE_WITH_16)
791
19.6k
            write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_const_i64_16);
792
86
        else if (override_second_argument == OVERRIDE_WITH_32)
793
86
            write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_const_i64_32);
794
228k
        ws->bytecode_pos += 2;
795
228k
796
228k
        /* Write operands. */
797
735k
        for (i = 0; i < info->num_operands; i++) {
798
507k
            if (i == 1 && override_second_argument) {
799
19.7k
                MASTNode *operand = ATPOS(vm, o->operands, 1);
800
19.7k
                MAST_IVal *iv = GET_IVal(operand);
801
19.7k
                if (override_second_argument == OVERRIDE_WITH_32) {
802
86
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 4);
803
86
                    write_int32(ws->bytecode_seg, ws->bytecode_pos, (MVMint32)iv->value);
804
86
                    ws->bytecode_pos += 4;
805
19.6k
                } else {
806
19.6k
                    ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
807
19.6k
                    write_int16(ws->bytecode_seg, ws->bytecode_pos, (MVMint16)iv->value);
808
19.6k
                    ws->bytecode_pos += 2;
809
19.6k
                }
810
487k
            } else {
811
487k
                compile_operand(vm, ws, info->operands[i], ATPOS(vm, o->operands, i));
812
487k
            }
813
507k
        }
814
228k
    }
815
46.4k
    else if (ISTYPE(vm, node, ws->types->ExtOp)) {
816
0
        MAST_ExtOp *o = GET_ExtOp(node);
817
0
        MASTNode   *operands;
818
0
        int         i, num_operands;
819
0
820
0
        /* Look up opcode and get argument info. */
821
0
        unsigned short op = o->op;
822
0
        if (op < EXTOP_BASE || (op - EXTOP_BASE) >= ELEMS(vm, ws->cu->extop_sigs))
823
0
            DIE(vm, "Invalid extension op %d specified", op);
824
0
        operands = ATPOS(vm, ws->cu->extop_sigs, op - EXTOP_BASE);
825
0
        if (VM_OBJ_IS_NULL(operands))
826
0
            DIE(vm, "Missing extension op operand array for instruction %d", op);
827
0
        ws->current_op_info = NULL;
828
0
        ws->current_operand_idx = 0;
829
0
830
0
        /* Ensure argument count matches up. */
831
0
        num_operands = ELEMS(vm, operands);
832
0
        if (ELEMS(vm, o->operands) != num_operands) {
833
0
            unsigned int  current_frame_idx = ws->current_frame_idx;
834
0
            unsigned int  current_ins_idx = ws->current_ins_idx;
835
0
            char *c_name = VM_STRING_TO_C_STRING(vm, o->name);
836
0
            char *waste[] = { c_name, NULL };
837
0
            cleanup_all(vm, ws);
838
0
            DIE_FREE(vm, waste, "At Frame %u, Instruction %u, op '%s' has invalid number (%u) of operands; needs %u.",
839
0
                current_frame_idx, current_ins_idx,
840
0
                c_name,
841
0
                ELEMS(vm, o->operands), num_operands);
842
0
        }
843
0
844
0
        /* Write opcode. */
845
0
        ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
846
0
        write_int16(ws->bytecode_seg, ws->bytecode_pos, op);
847
0
        ws->bytecode_pos += 2;
848
0
849
0
        /* Write operands. */
850
0
        for (i = 0; i < num_operands; i++)
851
0
            compile_operand(vm, ws, ATPOS_I(vm, operands, i), ATPOS(vm, o->operands, i));
852
0
    }
853
46.4k
    else if (ISTYPE(vm, node, ws->types->Label)) {
854
19.6k
        add_label_and_resolve_fixups(vm, ws, GET_Label(node));
855
19.6k
    }
856
26.8k
    else if (ISTYPE(vm, node, ws->types->Call)) {
857
14.9k
        MAST_Call *c           = GET_Call(node);
858
14.9k
        unsigned char res_type = 0;
859
14.9k
        unsigned short num_flags, flag_pos, arg_pos, arg_out_pos, callsite_id;
860
14.9k
        unsigned short call_op;
861
14.9k
        switch (c->op) {
862
0
            case 1: call_op = MVM_OP_nativeinvoke_v; break;
863
16
            case 2: call_op = MVM_OP_speshresolve; break;
864
14.9k
            default: call_op = MVM_OP_invoke_v; break;
865
14.9k
        }
866
14.9k
867
14.9k
        /* Emit callsite (may re-use existing one) and emit loading of it. */
868
14.9k
        callsite_id = get_callsite_id(vm, ws, c->flags, c->args);
869
14.9k
        ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 4);
870
14.9k
        write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_prepargs);
871
14.9k
        ws->bytecode_pos += 2;
872
14.9k
        write_int16(ws->bytecode_seg, ws->bytecode_pos, callsite_id);
873
14.9k
        ws->bytecode_pos += 2;
874
14.9k
875
14.9k
        /* for errors */
876
14.9k
        ws->current_op_info = MVM_op_get_op(MVM_OP_prepargs);
877
14.9k
        ws->current_operand_idx = 0;
878
14.9k
879
14.9k
        /* Set up args. */
880
14.9k
        num_flags = (unsigned short)ELEMS(vm, c->flags);
881
14.9k
        arg_pos = c->op == 1 ? 1 : 0;
882
14.9k
        arg_out_pos = 0;
883
41.8k
        for (flag_pos = 0; flag_pos < num_flags; flag_pos++) {
884
26.9k
            /* Handle any special flags. */
885
26.9k
            unsigned char flag = (unsigned char)ATPOS_I_C(vm, c->flags, flag_pos);
886
26.9k
            if (flag & MVM_CALLSITE_ARG_NAMED) {
887
3.12k
                if (c->op == 2) {
888
0
                    cleanup_all(vm, ws);
889
0
                    DIE(vm, "At Frame %u, Instruction %u, illegal named arg to speshresolve.",
890
0
                        ws->current_frame_idx, ws->current_ins_idx);
891
0
                }
892
3.12k
                ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 6);
893
3.12k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_argconst_s);
894
3.12k
                ws->bytecode_pos += 2;
895
3.12k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, arg_out_pos);
896
3.12k
                ws->bytecode_pos += 2;
897
3.12k
                compile_operand(vm, ws, MVM_operand_str, ATPOS(vm, c->args, arg_pos));
898
3.12k
                arg_pos++;
899
3.12k
                arg_out_pos++;
900
3.12k
            }
901
23.7k
            else if (flag & MVM_CALLSITE_ARG_FLAT) {
902
158
                if (c->op == 2) {
903
0
                    cleanup_all(vm, ws);
904
0
                    DIE(vm, "At Frame %u, Instruction %u, illegal flat arg to speshresolve.",
905
0
                        ws->current_frame_idx, ws->current_ins_idx);
906
0
                }
907
158
                /* don't need to do anything special */
908
158
            }
909
26.9k
910
26.9k
            /* Now go by flag type. */
911
26.9k
            ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 6);
912
26.9k
            if (c->op == 2 && !(flag & MVM_CALLSITE_ARG_OBJ)) {
913
0
                cleanup_all(vm, ws);
914
0
                DIE(vm, "At Frame %u, Instruction %u, illegal non-object arg to speshresolve.",
915
0
                    ws->current_frame_idx, ws->current_ins_idx);
916
0
            }
917
26.9k
            if (flag & MVM_CALLSITE_ARG_OBJ) {
918
13.4k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_arg_o);
919
13.4k
                ws->bytecode_pos += 2;
920
13.4k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, arg_out_pos);
921
13.4k
                ws->bytecode_pos += 2;
922
13.4k
                compile_operand(vm, ws, MVM_operand_read_reg | MVM_operand_obj,
923
13.4k
                    ATPOS(vm, c->args, arg_pos));
924
13.4k
            }
925
13.4k
            else if (flag & MVM_CALLSITE_ARG_STR) {
926
7.49k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_arg_s);
927
7.49k
                ws->bytecode_pos += 2;
928
7.49k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, arg_out_pos);
929
7.49k
                ws->bytecode_pos += 2;
930
7.49k
                compile_operand(vm, ws, MVM_operand_read_reg | MVM_operand_str,
931
7.49k
                    ATPOS(vm, c->args, arg_pos));
932
7.49k
            }
933
5.96k
            else if (flag & MVM_CALLSITE_ARG_INT) {
934
5.75k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_arg_i);
935
5.75k
                ws->bytecode_pos += 2;
936
5.75k
                write_int16(ws->bytecode_seg, ws->bytecode_pos, arg_out_pos);
937
5.75k
                ws->bytecode_pos += 2;
938
5.75k
                compile_operand(vm, ws, MVM_operand_read_reg | MVM_operand_int64,
939
5.75k
                    ATPOS(vm, c->args, arg_pos));
940
5.75k
            }
941
210
            else if (flag & MVM_CALLSITE_ARG_NUM) {
942
210
                write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_arg_n);
943
210
                ws->bytecode_pos += 2;
944
210
                write_int16(ws->bytecode_seg, ws->bytecode_pos, arg_out_pos);
945
210
                ws->bytecode_pos += 2;
946
210
                compile_operand(vm, ws, MVM_operand_read_reg | MVM_operand_num64,
947
210
                    ATPOS(vm, c->args, arg_pos));
948
210
            }
949
0
            else {
950
0
                unsigned int  current_frame_idx = ws->current_frame_idx;
951
0
                unsigned int  current_ins_idx = ws->current_ins_idx;
952
0
                const char *name = ws->current_op_info->name;
953
0
                cleanup_all(vm, ws);
954
0
                /*
955
0
                DIE(vm, "At Frame %u, Instruction %u, op '%s', "
956
0
                        "file %s, line %u, unhandled arg type %u.",
957
0
                    current_frame_idx, current_ins_idx, name,
958
0
                    ws->last_annotated ? VM_STRING_TO_C_STRING(vm, ws->last_annotated->file) : "",
959
0
                    ws->last_annotated ? ws->last_annotated->line : 0,
960
0
                    flag);
961
0
                */
962
0
                DIE(vm, "At Frame %u, Instruction %u, op '%s', unhandled arg type %u.",
963
0
                    current_frame_idx, current_ins_idx, name, flag);
964
0
            }
965
26.9k
966
26.9k
            arg_pos++;
967
26.9k
            arg_out_pos++;
968
26.9k
        }
969
14.9k
970
14.9k
        /* Select operation based on return type. */
971
14.9k
        if (c->op == 2) {
972
16
            if (ISTYPE(vm, c->result, ws->types->Local)) {
973
16
                MAST_Local *l = GET_Local(c->result);
974
16
                if (l->index >= ws->cur_frame->num_locals) {
975
0
                    cleanup_all(vm, ws);
976
0
                    DIE(vm, "MAST::Local index out of range");
977
0
                }
978
16
                if (ws->cur_frame->local_types[l->index] != MVM_reg_obj) {
979
0
                    cleanup_all(vm, ws);
980
0
                    DIE(vm, "At Frame %u, Instruction %u, speshresolve must have an object result.",
981
0
                        ws->current_frame_idx, ws->current_ins_idx);
982
0
                }
983
16
                res_type = MVM_operand_obj;
984
16
            }
985
0
            else {
986
0
                cleanup_all(vm, ws);
987
0
                DIE(vm, "At Frame %u, Instruction %u, speshresolve must have a result.",
988
0
                    ws->current_frame_idx, ws->current_ins_idx);
989
0
            }
990
16
        }
991
14.9k
        else if (ISTYPE(vm, c->result, ws->types->Local)) {
992
13.2k
            MAST_Local *l = GET_Local(c->result);
993
13.2k
994
13.2k
            /* Ensure it's within the set of known locals. */
995
13.2k
            if (l->index >= ws->cur_frame->num_locals) {
996
0
                cleanup_all(vm, ws);
997
0
                DIE(vm, "MAST::Local index out of range");
998
0
            }
999
13.2k
1000
13.2k
            /* Go by type. */
1001
13.2k
            switch (ws->cur_frame->local_types[l->index]) {
1002
1
                case MVM_reg_int64:
1003
1
                    call_op = c->op == 0 ? MVM_OP_invoke_i : MVM_OP_nativeinvoke_i;
1004
1
                    res_type = MVM_operand_int64;
1005
1
                    break;
1006
0
                case MVM_reg_num64:
1007
0
                    call_op = c->op == 0 ? MVM_OP_invoke_n : MVM_OP_nativeinvoke_n;
1008
0
                    res_type = MVM_operand_num64;
1009
0
                    break;
1010
288
                case MVM_reg_str:
1011
288
                    call_op = c->op == 0 ? MVM_OP_invoke_s : MVM_OP_nativeinvoke_s;
1012
288
                    res_type = MVM_operand_str;
1013
288
                    break;
1014
12.9k
                case MVM_reg_obj:
1015
12.9k
                    call_op = c->op == 0 ? MVM_OP_invoke_o : MVM_OP_nativeinvoke_o;
1016
12.9k
                    res_type = MVM_operand_obj;
1017
12.9k
                    break;
1018
0
                default:
1019
0
                    cleanup_all(vm, ws);
1020
0
                    DIE(vm, "Invalid MAST::Local type for return value");
1021
13.2k
            }
1022
13.2k
        }
1023
14.9k
1024
14.9k
        /* Emit the invocation op. */
1025
14.9k
        ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, c->op == 0 ? 6 : 8);
1026
14.9k
        write_int16(ws->bytecode_seg, ws->bytecode_pos, call_op);
1027
14.9k
        ws->bytecode_pos += 2;
1028
14.9k
        if (call_op != MVM_OP_invoke_v && call_op != MVM_OP_nativeinvoke_v)
1029
13.2k
            compile_operand(vm, ws, MVM_operand_read_reg | res_type, c->result);
1030
14.9k
        if (c->op == 2)
1031
16
            compile_operand(vm, ws, MVM_operand_str, c->target);
1032
14.9k
        else
1033
14.9k
            compile_operand(vm, ws, MVM_operand_read_reg | MVM_operand_obj, c->target);
1034
14.9k
        if (c->op == 1)
1035
0
            compile_operand(vm, ws, MVM_operand_read_reg | MVM_operand_obj, ATPOS(vm, c->args, 0));
1036
14.9k
    }
1037
11.8k
    else if (ISTYPE(vm, node, ws->types->Annotated)) {
1038
11.4k
        MAST_Annotated *a = GET_Annotated(node);
1039
11.4k
        unsigned int i;
1040
11.4k
        unsigned int num_ins = ELEMS(vm, a->instructions);
1041
11.4k
        unsigned int offset = ws->bytecode_pos - ws->cur_frame->bytecode_start;
1042
11.4k
1043
11.4k
        ws->last_annotated = a;
1044
11.4k
        ensure_space(vm, &ws->annotation_seg, &ws->annotation_alloc, ws->annotation_pos, 12);
1045
11.4k
        write_int32(ws->annotation_seg, ws->annotation_pos, offset);
1046
11.4k
        write_int32(ws->annotation_seg, ws->annotation_pos + 4, get_string_heap_index(vm, ws, a->file));
1047
11.4k
        write_int32(ws->annotation_seg, ws->annotation_pos + 8, (unsigned int)a->line);
1048
11.4k
        ws->annotation_pos += 12;
1049
11.4k
        ws->cur_frame->num_annotations++;
1050
11.4k
1051
96.3k
        for (i = 0; i < num_ins; i++)
1052
84.8k
            compile_instruction(vm, ws, ATPOS(vm, a->instructions, i));
1053
11.4k
    }
1054
431
    else if (ISTYPE(vm, node, ws->types->HandlerScope)) {
1055
431
        MAST_HandlerScope *hs = GET_HandlerScope(node);
1056
431
        unsigned int i;
1057
431
        unsigned int num_ins = ELEMS(vm, hs->instructions);
1058
431
        unsigned int start   = ws->bytecode_pos - ws->cur_frame->bytecode_start;
1059
431
        unsigned int end;
1060
431
1061
2.90k
        for (i = 0; i < num_ins; i++)
1062
2.47k
            compile_instruction(vm, ws, ATPOS(vm, hs->instructions, i));
1063
431
        end = ws->bytecode_pos - ws->cur_frame->bytecode_start;
1064
431
1065
431
        ws->cur_frame->num_handlers++;
1066
431
        if (ws->cur_frame->handlers)
1067
307
            ws->cur_frame->handlers = (FrameHandler *)MVM_realloc(ws->cur_frame->handlers,
1068
307
                ws->cur_frame->num_handlers * sizeof(FrameHandler));
1069
431
        else
1070
124
            ws->cur_frame->handlers = (FrameHandler *)MVM_malloc(
1071
124
                ws->cur_frame->num_handlers * sizeof(FrameHandler));
1072
431
1073
431
        i = ws->cur_frame->num_handlers - 1;
1074
431
        ws->cur_frame->handlers[i].start_offset = start;
1075
431
        ws->cur_frame->handlers[i].end_offset = end;
1076
431
        ws->cur_frame->handlers[i].category_mask = (unsigned int)hs->category_mask;
1077
431
        ws->cur_frame->handlers[i].action = (unsigned short)hs->action;
1078
431
        if (ws->cur_frame->handlers[i].category_mask & MVM_EX_CAT_LABELED) {
1079
31
            if (ISTYPE(vm, hs->label_local, ws->types->Local)) {
1080
31
                MAST_Local *l = GET_Local(hs->label_local);
1081
31
1082
31
                /* Ensure it's within the set of known locals and an object. */
1083
31
                if (l->index >= ws->cur_frame->num_locals) {
1084
0
                    cleanup_all(vm, ws);
1085
0
                    DIE(vm, "MAST::Local index out of range in HandlerScope");
1086
0
                }
1087
31
                if (ws->cur_frame->local_types[l->index] != MVM_reg_obj) {
1088
0
                    cleanup_all(vm, ws);
1089
0
                    DIE(vm, "MAST::Local for HandlerScope must be an object");
1090
0
                }
1091
31
1092
31
                /* Stash local index. */
1093
31
                ws->cur_frame->handlers[i].label_reg = (unsigned short)l->index;
1094
31
            }
1095
0
            else {
1096
0
                cleanup_all(vm, ws);
1097
0
                DIE(vm, "MAST::Local required for HandlerScope with loop label");
1098
0
            }
1099
31
        }
1100
431
1101
431
        /* Ensure we have a label. */
1102
431
        if (ISTYPE(vm, hs->goto_label, ws->types->Label)) {
1103
431
            ws->cur_frame->handlers[i].label = hs->goto_label;
1104
431
        }
1105
0
        else {
1106
0
            cleanup_all(vm, ws);
1107
0
            DIE(vm, "MAST::Label required for HandlerScope goto");
1108
0
        }
1109
431
1110
431
        /* May need a block also. */
1111
431
        if (hs->action == HANDLER_INVOKE) {
1112
114
            if (ISTYPE(vm, hs->block_local, ws->types->Local)) {
1113
114
                MAST_Local *l = GET_Local(hs->block_local);
1114
114
1115
114
                /* Ensure it's within the set of known locals and an object. */
1116
114
                if (l->index >= ws->cur_frame->num_locals) {
1117
0
                    cleanup_all(vm, ws);
1118
0
                    DIE(vm, "MAST::Local index out of range in HandlerScope");
1119
0
                }
1120
114
                if (ws->cur_frame->local_types[l->index] != MVM_reg_obj) {
1121
0
                    cleanup_all(vm, ws);
1122
0
                    DIE(vm, "MAST::Local for HandlerScope must be an object");
1123
0
                }
1124
114
1125
114
                /* Stash local index. */
1126
114
                ws->cur_frame->handlers[i].local = (unsigned short)l->index;
1127
114
            }
1128
0
            else {
1129
0
                cleanup_all(vm, ws);
1130
0
                DIE(vm, "MAST::Local required for HandlerScope invoke action");
1131
0
            }
1132
114
        }
1133
317
        else if (hs->action == HANDLER_UNWIND_GOTO || hs->action == HANDLER_UNWIND_GOTO_OBJ) {
1134
317
            ws->cur_frame->handlers[i].local = 0;
1135
317
        }
1136
0
        else {
1137
0
            cleanup_all(vm, ws);
1138
0
            DIE(vm, "Invalid action code for handler scope");
1139
0
        }
1140
431
    }
1141
0
    else {
1142
0
        cleanup_all(vm, ws);
1143
0
        DIE(vm, "Invalid MAST node in instruction list (must be Op, ExtOp, Call, Label, or Annotated)");
1144
0
    }
1145
274k
    ws->current_ins_idx++;
1146
274k
}
1147
1148
/* Compiles a frame. */
1149
4.52k
static void compile_frame(VM, WriterState *ws, MASTNode *node, unsigned short idx) {
1150
4.52k
    MAST_Frame  *f;
1151
4.52k
    FrameState  *fs;
1152
4.52k
    unsigned int i, num_ins, instructions_start;
1153
4.52k
    MASTNode *last_inst = NULL;
1154
4.52k
    MVMuint16 num_slvs;
1155
4.52k
1156
4.52k
    /* Ensure we have a node of the right type. */
1157
4.52k
    if (!ISTYPE(vm, node, ws->types->Frame)) {
1158
0
        cleanup_all(vm, ws);
1159
0
        DIE(vm, "Child of CompUnit must be a Frame");
1160
0
    }
1161
4.52k
    f = GET_Frame(node);
1162
4.52k
1163
4.52k
    /* Allocate frame state. */
1164
4.52k
    fs = ws->cur_frame    = (FrameState *)MVM_malloc(sizeof(FrameState));
1165
4.52k
    fs->bytecode_start    = ws->bytecode_pos;
1166
4.52k
    fs->frame_start       = ws->frame_pos;
1167
4.52k
    fs->labels            = NULL;
1168
4.52k
    fs->num_labels        = 0;
1169
4.52k
    fs->alloc_labels      = 0;
1170
4.52k
    fs->unresolved_labels = 0;
1171
4.52k
1172
4.52k
    /* Count locals and lexicals. */
1173
4.52k
    fs->num_locals   = ELEMS(vm, f->local_types);
1174
4.52k
    fs->num_lexicals = ELEMS(vm, f->lexical_types);
1175
4.52k
1176
4.52k
    if (fs->num_locals > (1 << 16)) {
1177
0
        cleanup_all(vm, ws);
1178
0
        DIE(vm, "Too many locals in this frame.");
1179
0
    }
1180
4.52k
1181
4.52k
    if (ELEMS(vm, f->lexical_names) != fs->num_lexicals) {
1182
0
        cleanup_all(vm, ws);
1183
0
        DIE(vm, "Lexical types list and lexical names list have unequal length");
1184
0
    }
1185
4.52k
1186
4.52k
    /* initialize number of annotation */
1187
4.52k
    fs->num_annotations = 0;
1188
4.52k
1189
4.52k
    /* initialize number of handlers and handlers pointer */
1190
4.52k
    fs->num_handlers = 0;
1191
4.52k
    fs->handlers = NULL;
1192
4.52k
1193
4.52k
    /* Ensure space is available to write frame entry, and write the
1194
4.52k
     * header, apart from the bytecode length, which we'll fill in
1195
4.52k
     * later. */
1196
4.52k
    ensure_space(vm, &ws->frame_seg, &ws->frame_alloc, ws->frame_pos,
1197
4.52k
        FRAME_HEADER_SIZE + fs->num_locals * 2 + fs->num_lexicals * 6);
1198
4.52k
    write_int32(ws->frame_seg, ws->frame_pos, fs->bytecode_start);
1199
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 4, 0); /* Filled in later. */
1200
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 8, fs->num_locals);
1201
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 12, fs->num_lexicals);
1202
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 16,
1203
4.52k
        get_string_heap_index(vm, ws, f->cuuid));
1204
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 20,
1205
4.52k
        get_string_heap_index(vm, ws, f->name));
1206
4.52k
1207
4.52k
    /* Handle outer. The current index means "no outer". */
1208
4.52k
    if (ISTYPE(vm, f->outer, ws->types->Frame)) {
1209
1.94k
        /* First, see if we have the index cached. If not, go hunting. */
1210
1.94k
        if (((MAST_Frame *)f->outer)->flags & FRAME_FLAG_HAS_INDEX) {
1211
1.94k
            write_int16(ws->frame_seg, ws->frame_pos + 24,
1212
1.94k
                ((MAST_Frame *)f->outer)->index);
1213
1.94k
        }
1214
0
        else {
1215
0
            unsigned short j, found, num_frames;
1216
0
            found = 0;
1217
0
            num_frames = (unsigned short)ELEMS(vm, ws->cu->frames);
1218
0
            for (j = 0; j < num_frames; j++) {
1219
0
                if (ATPOS(vm, ws->cu->frames, j) == f->outer) {
1220
0
                    write_int16(ws->frame_seg, ws->frame_pos + 24, j);
1221
0
                    found = 1;
1222
0
                    break;
1223
0
                }
1224
0
            }
1225
0
            if (!found) {
1226
0
                cleanup_all(vm, ws);
1227
0
                DIE(vm, "Could not locate outer frame in frame list");
1228
0
            }
1229
0
        }
1230
1.94k
    }
1231
2.58k
    else {
1232
2.58k
        write_int16(ws->frame_seg, ws->frame_pos + 24, idx);
1233
2.58k
    }
1234
4.52k
1235
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 26, ws->annotation_pos);
1236
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 30, 0); /* number of annotation; fill in later */
1237
4.52k
    write_int32(ws->frame_seg, ws->frame_pos + 34, 0); /* number of handlers; fill in later */
1238
4.52k
    write_int16(ws->frame_seg, ws->frame_pos + 38, (MVMint16)f->flags);
1239
4.52k
    num_slvs = f->flags & FRAME_FLAG_HAS_SLV
1240
415
        ? (MVMuint16)ELEMS(vm, f->static_lex_values) / 4
1241
4.11k
        : 0;
1242
4.52k
    write_int16(ws->frame_seg, ws->frame_pos + 40, num_slvs);
1243
4.52k
1244
4.52k
    if (f->flags & FRAME_FLAG_HAS_CODE_OBJ) {
1245
441
        write_int32(ws->frame_seg, ws->frame_pos + 42, f->code_obj_sc_dep_idx + 1);
1246
441
        write_int32(ws->frame_seg, ws->frame_pos + 46, f->code_obj_sc_idx);
1247
441
    }
1248
4.08k
    else {
1249
4.08k
        write_int32(ws->frame_seg, ws->frame_pos + 42, 0);
1250
4.08k
        write_int32(ws->frame_seg, ws->frame_pos + 46, 0);
1251
4.08k
    }
1252
4.52k
1253
4.52k
    ws->frame_pos += FRAME_HEADER_SIZE;
1254
4.52k
1255
4.52k
    /* Write locals, as well as collecting our own array of type info. */
1256
4.52k
    fs->local_types = (short unsigned int *)MVM_malloc(sizeof(unsigned short) * fs->num_locals);
1257
62.6k
    for (i = 0; i < fs->num_locals; i++) {
1258
58.1k
        unsigned short local_type = type_to_local_type(vm, ws, ATPOS(vm, f->local_types, i));
1259
58.1k
        fs->local_types[i] = local_type;
1260
58.1k
        write_int16(ws->frame_seg, ws->frame_pos, local_type);
1261
58.1k
        ws->frame_pos += 2;
1262
58.1k
    }
1263
4.52k
1264
4.52k
    /* Write lexicals. */
1265
4.52k
    fs->lexical_types = (short unsigned int *)MVM_malloc(sizeof(unsigned short) * fs->num_lexicals);
1266
7.76k
    for (i = 0; i < fs->num_lexicals; i++) {
1267
3.24k
        unsigned short lexical_type = type_to_local_type(vm, ws, ATPOS(vm, f->lexical_types, i));
1268
3.24k
        fs->lexical_types[i] = lexical_type;
1269
3.24k
        write_int16(ws->frame_seg, ws->frame_pos, lexical_type);
1270
3.24k
        ws->frame_pos += 2;
1271
3.24k
        write_int32(ws->frame_seg, ws->frame_pos,
1272
3.24k
            get_string_heap_index(vm, ws, ATPOS_S_C(vm, f->lexical_names, i)));
1273
3.24k
        ws->frame_pos += 4;
1274
3.24k
    }
1275
4.52k
1276
4.52k
    /* Save the location of the start of instructions */
1277
4.52k
    instructions_start = ws->bytecode_pos;
1278
4.52k
1279
4.52k
    /* Compile the instructions. */
1280
4.52k
    ws->current_ins_idx = 0;
1281
4.52k
    num_ins = ELEMS(vm, f->instructions);
1282
192k
    for (i = 0; i < num_ins; i++)
1283
187k
        compile_instruction(vm, ws, last_inst = ATPOS(vm, f->instructions, i));
1284
4.52k
1285
4.52k
    /* Fixup frames that don't have a return instruction, so
1286
4.52k
     * we don't have to check against bytecode length every
1287
4.52k
     * time through the runloop. */
1288
4.52k
    if (!last_inst || !ISTYPE(vm, last_inst, ws->types->Op)
1289
4.52k
            || (   GET_Op(last_inst)->op != MVM_OP_return
1290
4.19k
                && GET_Op(last_inst)->op != MVM_OP_return_i
1291
4.04k
                && GET_Op(last_inst)->op != MVM_OP_return_n
1292
4.00k
                && GET_Op(last_inst)->op != MVM_OP_return_s
1293
3.83k
                && GET_Op(last_inst)->op != MVM_OP_return_o
1294
0
            )) {
1295
0
        ensure_space(vm, &ws->bytecode_seg, &ws->bytecode_alloc, ws->bytecode_pos, 2);
1296
0
        write_int16(ws->bytecode_seg, ws->bytecode_pos, MVM_OP_return);
1297
0
        ws->bytecode_pos += 2;
1298
0
    }
1299
4.52k
1300
4.52k
    /* Fill in bytecode length. */
1301
4.52k
    write_int32(ws->frame_seg, fs->frame_start + 4, ws->bytecode_pos - instructions_start);
1302
4.52k
1303
4.52k
    /* Fill in number of annotations. */
1304
4.52k
    write_int32(ws->frame_seg, fs->frame_start + 30, fs->num_annotations);
1305
4.52k
1306
4.52k
    /* Fill in number of handlers. */
1307
4.52k
    write_int32(ws->frame_seg, fs->frame_start + 34, fs->num_handlers);
1308
4.52k
1309
4.52k
    /* Write handlers. */
1310
4.95k
    for (i = 0; i < fs->num_handlers; i++) {
1311
431
        ensure_space(vm, &ws->frame_seg, &ws->frame_alloc, ws->frame_pos,
1312
431
            FRAME_HANDLER_SIZE);
1313
431
        write_int32(ws->frame_seg, ws->frame_pos, fs->handlers[i].start_offset);
1314
431
        ws->frame_pos += 4;
1315
431
        write_int32(ws->frame_seg, ws->frame_pos, fs->handlers[i].end_offset);
1316
431
        ws->frame_pos += 4;
1317
431
        write_int32(ws->frame_seg, ws->frame_pos, fs->handlers[i].category_mask);
1318
431
        ws->frame_pos += 4;
1319
431
        write_int16(ws->frame_seg, ws->frame_pos, fs->handlers[i].action);
1320
431
        ws->frame_pos += 2;
1321
431
        write_int16(ws->frame_seg, ws->frame_pos, fs->handlers[i].local);
1322
431
        ws->frame_pos += 2;
1323
431
        if (ws->cur_frame->handlers[i].label)
1324
431
            write_int32(ws->frame_seg, ws->frame_pos,
1325
431
                demand_label_offset(vm, ws, GET_Label(fs->handlers[i].label),
1326
431
                    "HandlerScope uses unresolved label"));
1327
431
        else
1328
0
            write_int32(ws->frame_seg, ws->frame_pos, 0);
1329
431
        ws->frame_pos += 4;
1330
431
        if (fs->handlers[i].category_mask & MVM_EX_CAT_LABELED) {
1331
31
            ensure_space(vm, &ws->frame_seg, &ws->frame_alloc, ws->frame_pos, 2);
1332
31
            write_int16(ws->frame_seg, ws->frame_pos, fs->handlers[i].label_reg);
1333
31
            ws->frame_pos += 2;
1334
31
        }
1335
431
    }
1336
4.52k
1337
4.52k
    /* Write static lex values. */
1338
4.52k
    ensure_space(vm, &ws->frame_seg, &ws->frame_alloc, ws->frame_pos,
1339
4.52k
        FRAME_SLV_SIZE * num_slvs);
1340
5.61k
    for (i = 0; i < num_slvs; i++) {
1341
1.08k
        write_int16(ws->frame_seg, ws->frame_pos,
1342
1.08k
            (MVMuint16)ATPOS_I(vm, f->static_lex_values, 4 * i));
1343
1.08k
        write_int16(ws->frame_seg, ws->frame_pos + 2,
1344
1.08k
            (MVMuint16)ATPOS_I(vm, f->static_lex_values, 4 * i + 1));
1345
1.08k
        write_int32(ws->frame_seg, ws->frame_pos + 4,
1346
1.08k
            (MVMuint32)ATPOS_I(vm, f->static_lex_values, 4 * i + 2));
1347
1.08k
        write_int32(ws->frame_seg, ws->frame_pos + 8,
1348
1.08k
            (MVMuint32)ATPOS_I(vm, f->static_lex_values, 4 * i + 3));
1349
1.08k
        ws->frame_pos += FRAME_SLV_SIZE;
1350
1.08k
    }
1351
4.52k
1352
4.52k
    /* Any leftover labels? */
1353
4.52k
    if (fs->unresolved_labels) {
1354
0
        cleanup_all(vm, ws);
1355
0
        DIE(vm, "Frame has %u unresolved labels", fs->unresolved_labels);
1356
0
    }
1357
4.52k
1358
4.52k
    /* Free the frame state. */
1359
4.52k
    cleanup_frame(vm, fs);
1360
4.52k
    ws->cur_frame = NULL;
1361
4.52k
1362
4.52k
    /* Increment frame count. */
1363
4.52k
    ws->num_frames++;
1364
4.52k
}
1365
1366
/* Takes all of the strings and joins them into a heap, encoding them as
1367
 * UTF-8. */
1368
1.21k
static char * form_string_heap(VM, WriterState *ws, unsigned int *string_heap_size) {
1369
1.21k
    char         *heap;
1370
1.21k
    unsigned int  i, num_strings, heap_size, heap_alloc;
1371
1.21k
1372
1.21k
    /* If we've nothing to do, just return immediately. */
1373
1.21k
    num_strings = ELEMS(vm, ws->strings);
1374
1.21k
    if (num_strings == 0) {
1375
0
        *string_heap_size = 0;
1376
0
        return NULL;
1377
0
    }
1378
1.21k
1379
1.21k
    /* Allocate heap starting point (just a guess). */
1380
1.21k
    heap_size = 0;
1381
1.21k
    heap_alloc = num_strings * 32;
1382
1.21k
    heap = (char *)MVM_malloc(heap_alloc);
1383
1.21k
1384
1.21k
    /* Add each string to the heap. */
1385
35.2k
    for (i = 0; i < num_strings; i++) {
1386
34.0k
        MVMuint64 bytelen;
1387
34.0k
        char *encoded;
1388
34.0k
        MVMGraphemeIter gi;
1389
34.0k
        unsigned short align;
1390
34.0k
        unsigned int need;
1391
34.0k
1392
34.0k
        /* Decide if we can get away with Latin-1 with an assumption of the
1393
34.0k
         * string already being in NFG. Latin-1 is except \r, which we also
1394
34.0k
         * check for here. */
1395
34.0k
        MVMint32   need_utf8 = 0;
1396
34.0k
        MVMString *str       = ATPOS_S(vm, ws->strings, i);
1397
34.0k
        MVM_string_gi_init(tc, &gi, str);
1398
412k
        while (MVM_string_gi_has_more(tc, &gi)) {
1399
379k
            MVMGrapheme32 g = MVM_string_gi_get_grapheme(tc, &gi);
1400
379k
            if (g < 0 || g >= 0xFF || g == 0x0D) {
1401
97
                need_utf8 = 1;
1402
97
                break;
1403
97
            }
1404
379k
        }
1405
34.0k
1406
34.0k
        /* Encode it with the chosen algorithm. */
1407
34.0k
        encoded = need_utf8
1408
97
            ? MVM_string_utf8_encode(tc, str, &bytelen, 0)
1409
33.9k
            : MVM_string_latin1_encode(tc, str, &bytelen, 0);
1410
34.0k
        if (bytelen > 0x3FFFFFFF) {
1411
0
            cleanup_all(vm, ws);
1412
0
            DIE(vm, "String too long for string constants segment");
1413
0
        }
1414
34.0k
1415
34.0k
        /* Ensure we have space. */
1416
24.5k
        align = bytelen & 3 ? 4 - (bytelen & 3) : 0;
1417
34.0k
        need  = 4 + bytelen + align;
1418
34.0k
        if (heap_size + need >= heap_alloc) {
1419
0
            heap_alloc = umax(heap_alloc * 2, heap_size + need);
1420
0
            heap = (char *)MVM_realloc(heap, heap_alloc);
1421
0
        }
1422
34.0k
1423
34.0k
        /* Write byte length and UTF-8 flag into heap. */
1424
34.0k
        write_int32(heap, heap_size, (bytelen << 1) | need_utf8);
1425
34.0k
        heap_size += 4;
1426
34.0k
1427
34.0k
        /* Write string. */
1428
34.0k
        memcpy(heap + heap_size, encoded, bytelen);
1429
34.0k
        MVM_free(encoded);
1430
34.0k
        heap_size += bytelen;
1431
34.0k
1432
34.0k
        /* Add alignment. Whilst we never read this memory, it's useful to
1433
34.0k
           ensure it is initialised, otherwise valgrind (and similar tools)
1434
34.0k
           will rightly complain that we're writing garbage to disk. */
1435
34.0k
        if (align) {
1436
24.5k
            memset(heap + heap_size, 0, align);
1437
24.5k
            heap_size += align;
1438
24.5k
        }
1439
34.0k
    }
1440
1.21k
1441
1.21k
    *string_heap_size = heap_size;
1442
1.21k
    return heap;
1443
1.21k
}
1444
1445
/* Takes all the pieces and forms the bytecode output. */
1446
1.21k
static char * form_bytecode_output(VM, WriterState *ws, unsigned int *bytecode_size) {
1447
1.21k
    MVMuint32     size    = 0;
1448
1.21k
    MVMuint32     pos     = 0;
1449
1.21k
    char         *output;
1450
1.21k
    unsigned int  string_heap_size;
1451
1.21k
    char         *string_heap;
1452
1.21k
    unsigned int  hll_str_idx;
1453
1.21k
1454
1.21k
    /* Store HLL name string, if any. */
1455
1.21k
    if (!VM_STRING_IS_NULL(ws->cu->hll))
1456
1.11k
        hll_str_idx = get_string_heap_index(vm, ws, ws->cu->hll);
1457
1.21k
    else
1458
97
        hll_str_idx = get_string_heap_index(vm, ws, EMPTY_STRING(vm));
1459
1.21k
1460
1.21k
    /* Build string heap. */
1461
1.21k
    string_heap = form_string_heap(vm, ws, &string_heap_size);
1462
1.21k
1463
1.21k
    /* Work out total size. */
1464
1.21k
    size += MVM_ALIGN_SECTION(HEADER_SIZE);
1465
1.21k
    size += MVM_ALIGN_SECTION(string_heap_size);
1466
1.21k
    size += MVM_ALIGN_SECTION(ws->scdep_bytes);
1467
1.21k
    size += MVM_ALIGN_SECTION(ws->extops_bytes);
1468
1.21k
    size += MVM_ALIGN_SECTION(ws->frame_pos);
1469
1.21k
    size += MVM_ALIGN_SECTION(ws->callsite_pos);
1470
1.21k
    size += MVM_ALIGN_SECTION(ws->bytecode_pos);
1471
1.21k
    size += MVM_ALIGN_SECTION(ws->annotation_pos);
1472
1.21k
    if (vm->serialized)
1473
0
        size += MVM_ALIGN_SECTION(vm->serialized_size);
1474
1.21k
1475
1.21k
    /* Allocate space for the bytecode output. */
1476
1.21k
    output = (char *)MVM_calloc(1, size);
1477
1.21k
1478
1.21k
    /* Generate start of header. */
1479
1.21k
    memcpy(output, "MOARVM\r\n", 8);
1480
1.21k
    write_int32(output, 8, BYTECODE_VERSION);
1481
1.21k
    pos += MVM_ALIGN_SECTION(HEADER_SIZE);
1482
1.21k
1483
1.21k
    /* Add SC dependencies section and its header entries. */
1484
1.21k
    write_int32(output, SCDEP_HEADER_OFFSET, pos);
1485
1.21k
    write_int32(output, SCDEP_HEADER_OFFSET + 4, ELEMS(vm, ws->cu->sc_handles));
1486
1.21k
    memcpy(output + pos, ws->scdep_seg, ws->scdep_bytes);
1487
1.21k
    pos += MVM_ALIGN_SECTION(ws->scdep_bytes);
1488
1.21k
1489
1.21k
    /* Add extension ops section and its header entries. */
1490
1.21k
    write_int32(output, EXTOP_HEADER_OFFSET, pos);
1491
1.21k
    write_int32(output, EXTOP_HEADER_OFFSET + 4, ws->num_extops);
1492
1.21k
    memcpy(output + pos, ws->extops_seg, ws->extops_bytes);
1493
1.21k
    pos += MVM_ALIGN_SECTION(ws->extops_bytes);
1494
1.21k
1495
1.21k
    /* Add frames section and its header entries. */
1496
1.21k
    write_int32(output, FRAME_HEADER_OFFSET, pos);
1497
1.21k
    write_int32(output, FRAME_HEADER_OFFSET + 4, ws->num_frames);
1498
1.21k
    memcpy(output + pos, ws->frame_seg, ws->frame_pos);
1499
1.21k
    pos += MVM_ALIGN_SECTION(ws->frame_pos);
1500
1.21k
1501
1.21k
    /* Add callsites section and its header entries. */
1502
1.21k
    write_int32(output, CALLSITE_HEADER_OFFSET, pos);
1503
1.21k
    write_int32(output, CALLSITE_HEADER_OFFSET + 4, ws->num_callsites);
1504
1.21k
    memcpy(output + pos, ws->callsite_seg, ws->callsite_pos);
1505
1.21k
    pos += MVM_ALIGN_SECTION(ws->callsite_pos);
1506
1.21k
1507
1.21k
    /* Add strings heap section and its header entries. */
1508
1.21k
    write_int32(output, STRING_HEADER_OFFSET, pos);
1509
1.21k
    write_int32(output, STRING_HEADER_OFFSET + 4, ELEMS(vm, ws->strings));
1510
1.21k
    memcpy(output + pos, string_heap, string_heap_size);
1511
1.21k
    pos += MVM_ALIGN_SECTION(string_heap_size);
1512
1.21k
    if (string_heap) {
1513
1.21k
        MVM_free(string_heap);
1514
1.21k
        string_heap = NULL;
1515
1.21k
    }
1516
1.21k
1517
1.21k
    /* SC data. Write it if we have it. */
1518
1.21k
    if (vm->serialized) {
1519
0
        write_int32(output, SCDATA_HEADER_OFFSET, pos);
1520
0
        write_int32(output, SCDATA_HEADER_OFFSET + 4, vm->serialized_size);
1521
0
        memcpy(output + pos, vm->serialized, vm->serialized_size);
1522
0
        pos += MVM_ALIGN_SECTION(vm->serialized_size);
1523
0
        MVM_free(vm->serialized);
1524
0
        vm->serialized = NULL;
1525
0
        vm->serialized_size = 0;
1526
0
    }
1527
1.21k
1528
1.21k
    /* Add bytecode section and its header entries (offset, length). */
1529
1.21k
    write_int32(output, BYTECODE_HEADER_OFFSET, pos);
1530
1.21k
    write_int32(output, BYTECODE_HEADER_OFFSET + 4, ws->bytecode_pos);
1531
1.21k
    memcpy(output + pos, ws->bytecode_seg, ws->bytecode_pos);
1532
1.21k
    pos += MVM_ALIGN_SECTION(ws->bytecode_pos);
1533
1.21k
1534
1.21k
    /* Add annotation section and its header entries (offset, length). */
1535
1.21k
    write_int32(output, ANNOTATION_HEADER_OFFSET, pos);
1536
1.21k
    write_int32(output, ANNOTATION_HEADER_OFFSET + 4, ws->annotation_pos);
1537
1.21k
    memcpy(output + pos, ws->annotation_seg, ws->annotation_pos);
1538
1.21k
    pos += MVM_ALIGN_SECTION(ws->annotation_pos);
1539
1.21k
1540
1.21k
    /* Add HLL and special frame indexes. */
1541
1.21k
    write_int32(output, HLL_NAME_HEADER_OFFSET, hll_str_idx);
1542
1.21k
    if (VM_OBJ_IS_NULL(ws->cu->main_frame))
1543
1.07k
        write_int32(output, SPECIAL_FRAME_HEADER_OFFSET, 0);
1544
1.21k
    else
1545
143
        write_int32(output, SPECIAL_FRAME_HEADER_OFFSET, 1 + get_frame_index(vm, ws, ws->cu->main_frame));
1546
1.21k
    if (VM_OBJ_IS_NULL(ws->cu->load_frame))
1547
1.07k
        write_int32(output, SPECIAL_FRAME_HEADER_OFFSET + 4, 0);
1548
1.21k
    else
1549
143
        write_int32(output, SPECIAL_FRAME_HEADER_OFFSET + 4, 1 + get_frame_index(vm, ws, ws->cu->load_frame));
1550
1.21k
    if (VM_OBJ_IS_NULL(ws->cu->deserialize_frame))
1551
130
        write_int32(output, SPECIAL_FRAME_HEADER_OFFSET + 8, 0);
1552
1.21k
    else
1553
1.08k
        write_int32(output, SPECIAL_FRAME_HEADER_OFFSET + 8, 1 + get_frame_index(vm, ws, ws->cu->deserialize_frame));
1554
1.21k
1555
1.21k
    /* Sanity...should never fail. */
1556
1.21k
    if (pos != size)
1557
0
        DIE(vm, "Bytecode generated did not match expected size");
1558
1.21k
1559
1.21k
    *bytecode_size = size;
1560
1.21k
    return output;
1561
1.21k
}
1562
1563
/* Main entry point to the MAST to bytecode compiler. */
1564
1.21k
char * MVM_mast_compile(VM, MASTNode *node, MASTNodeTypes *types, unsigned int *size) {
1565
1.21k
    MAST_CompUnit  *cu;
1566
1.21k
    WriterState    *ws;
1567
1.21k
    char           *bytecode;
1568
1.21k
    unsigned short  i, num_depscs, num_frames;
1569
1.21k
    unsigned int    bytecode_size;
1570
1.21k
1571
1.21k
    /* Ensure we have a compilation unit. */
1572
1.21k
    if (!ISTYPE(vm, node, types->CompUnit))
1573
0
        DIE(vm, "Top-level MAST node must be a CompUnit");
1574
1.21k
    cu = GET_CompUnit(node);
1575
1.21k
1576
1.21k
    /* Initialize the writer state structure. */
1577
1.21k
    ws = (WriterState *)MVM_malloc(sizeof(WriterState));
1578
1.21k
    ws->types            = types;
1579
1.21k
    ws->strings          = NEWLIST_S(vm);
1580
1.21k
    ws->seen_strings     = NEWHASH(vm);
1581
1.21k
    ws->cur_frame        = NULL;
1582
1.21k
    ws->scdep_bytes      = ELEMS(vm, cu->sc_handles) * SC_DEP_SIZE;
1583
1.12k
    ws->scdep_seg        = ws->scdep_bytes ? (char *)MVM_malloc(ws->scdep_bytes) : NULL;
1584
1.21k
    ws->num_extops       = ELEMS(vm, cu->extop_names);
1585
1.21k
    ws->extops_bytes     = ws->num_extops * EXTOP_SIZE;
1586
1.21k
    ws->extops_seg       = (char *)MVM_malloc(ws->extops_bytes);
1587
1.21k
    ws->frame_pos        = 0;
1588
1.21k
    ws->frame_alloc      = 192 * ELEMS(vm, cu->frames);
1589
1.21k
    ws->frame_seg        = (char *)MVM_malloc(ws->frame_alloc);
1590
1.21k
    ws->num_frames       = 0;
1591
1.21k
    ws->callsite_pos     = 0;
1592
1.21k
    ws->callsite_alloc   = 4096;
1593
1.21k
    ws->callsite_seg     = (char *)MVM_malloc(ws->callsite_alloc);
1594
1.21k
    ws->num_callsites    = 0;
1595
1.21k
    ws->bytecode_pos     = 0;
1596
1.21k
    ws->bytecode_alloc   = 128 * ELEMS(vm, cu->frames);
1597
1.21k
    ws->bytecode_seg     = (char *)MVM_malloc(ws->bytecode_alloc);
1598
1.21k
    ws->annotation_pos   = 0;
1599
1.21k
    ws->annotation_alloc = 64 * ELEMS(vm, cu->frames);
1600
1.21k
    ws->annotation_seg   = (char *)MVM_malloc(ws->annotation_alloc);
1601
1.21k
    ws->cu               = cu;
1602
1.21k
    ws->current_frame_idx= 0;
1603
1.21k
1604
1.21k
    /* If we have any strings from serializing, then we'll seed our own string
1605
1.21k
     * heap with them. This means the compilation unit string heap will align
1606
1.21k
     * perfectly with what the serialization blob needs, and thus we can use
1607
1.21k
     * it in deserialization. Note we use get_string_heap_index for its side
1608
1.21k
     * effects only here. Start from 1, as 0 means NULL string. */
1609
1.21k
    if (vm->serialized_string_heap) {
1610
0
        MVMint64 elems = ELEMS(vm, vm->serialized_string_heap);
1611
0
        for (i = 1; i < elems; i++)
1612
0
            (void)get_string_heap_index(vm, ws, ATPOS_S(vm, vm->serialized_string_heap, i));
1613
0
        vm->serialized_string_heap = NULL;
1614
0
    }
1615
1.21k
1616
1.21k
    /* Initialize callsite reuse cache */
1617
1.21k
    ws->callsite_reuse_head = NULL;
1618
1.21k
1619
1.21k
    /* Store each of the dependent SCs. */
1620
1.21k
    num_depscs = ELEMS(vm, ws->cu->sc_handles);
1621
3.41k
    for (i = 0; i < num_depscs; i++)
1622
2.20k
        write_int32(ws->scdep_seg, i * SC_DEP_SIZE,
1623
2.20k
            get_string_heap_index(vm, ws,
1624
2.20k
                ATPOS_S_C(vm, ws->cu->sc_handles, i)));
1625
1.21k
1626
1.21k
    /* Store each of the extop names and signatures. */
1627
1.21k
    for (i = 0; i < ws->num_extops; i++) {
1628
0
        MASTNode *sig_array;
1629
0
        int num_operands, j;
1630
0
1631
0
        write_int32(ws->extops_seg, i * EXTOP_SIZE,
1632
0
            get_string_heap_index(vm, ws,
1633
0
                ATPOS_S_C(vm, ws->cu->extop_names, i)));
1634
0
1635
0
        sig_array = ATPOS(vm, ws->cu->extop_sigs, i);
1636
0
        num_operands = ELEMS(vm, sig_array);
1637
0
        for (j = 0; j < 8; j++)
1638
0
            write_int8(ws->extops_seg, i * EXTOP_SIZE + 4 + j,
1639
0
                j < num_operands
1640
0
                    ? ATPOS_I(vm, sig_array, j)
1641
0
                    : 0);
1642
0
    }
1643
1.21k
1644
1.21k
    /* Visit and compile each of the frames. */
1645
1.21k
    num_frames = (unsigned short)ELEMS(vm, cu->frames);
1646
5.74k
    for (i = 0; i < num_frames; i++)
1647
4.52k
        compile_frame(vm, ws, ATPOS(vm, cu->frames, i), ws->current_frame_idx = i);
1648
1.21k
1649
1.21k
    /* Join all the pieces into a bytecode file. */
1650
1.21k
    bytecode = form_bytecode_output(vm, ws, &bytecode_size);
1651
1.21k
1652
1.21k
    /* Cleanup and hand back result. */
1653
1.21k
    cleanup_all(vm, ws);
1654
1.21k
1655
1.21k
    *size = bytecode_size;
1656
1.21k
    return bytecode;
1657
1.21k
}