Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/core/bytecode.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Some constants. */
4
2.80k
#define HEADER_SIZE                 92
5
2.80k
#define MIN_BYTECODE_VERSION        5
6
2.80k
#define MAX_BYTECODE_VERSION        5
7
756k
#define FRAME_HEADER_SIZE           (11 * 4 + 3 * 2)
8
326k
#define FRAME_HANDLER_SIZE          (4 * 4 + 2 * 2)
9
751k
#define FRAME_SLV_SIZE              (2 * 2 + 2 * 4)
10
5.60k
#define SCDEP_HEADER_OFFSET         12
11
5.60k
#define EXTOP_HEADER_OFFSET         20
12
5.60k
#define FRAME_HEADER_OFFSET         28
13
5.60k
#define CALLSITE_HEADER_OFFSET      36
14
5.60k
#define STRING_HEADER_OFFSET        44
15
5.60k
#define SCDATA_HEADER_OFFSET        52
16
5.60k
#define BYTECODE_HEADER_OFFSET      60
17
5.60k
#define ANNOTATION_HEADER_OFFSET    68
18
2.80k
#define HLL_NAME_HEADER_OFFSET      76
19
8.40k
#define SPECIAL_FRAME_HEADER_OFFSET 80
20
21
/* Frame flags. */
22
319k
#define FRAME_FLAG_EXIT_HANDLER     1
23
319k
#define FRAME_FLAG_IS_THUNK         2
24
319k
#define FRAME_FLAG_NO_INLINE        8
25
26
/* Describes the current reader state. */
27
typedef struct {
28
    /* General info. */
29
    MVMuint32 version;
30
31
    /* The string heap. */
32
    MVMuint8  *string_seg;
33
    MVMuint32  expected_strings;
34
35
    /* The SC dependencies segment. */
36
    MVMuint32  expected_scs;
37
    MVMuint8  *sc_seg;
38
39
    /* The extension ops segment. */
40
    MVMuint8 *extop_seg;
41
    MVMuint32 expected_extops;
42
43
    /* The frame segment. */
44
    MVMuint32  expected_frames;
45
    MVMuint8  *frame_seg;
46
    MVMuint16 *frame_outer_fixups;
47
48
    /* The callsites segment. */
49
    MVMuint8  *callsite_seg;
50
    MVMuint32  expected_callsites;
51
52
    /* The bytecode segment. */
53
    MVMuint32  bytecode_size;
54
    MVMuint8  *bytecode_seg;
55
56
    /* The annotations segment */
57
    MVMuint8  *annotation_seg;
58
    MVMuint32  annotation_size;
59
60
    /* HLL name string index */
61
    MVMuint32  hll_str_idx;
62
63
    /* The limit we can not read beyond. */
64
    MVMuint8 *read_limit;
65
66
    /* Array of frames. */
67
    MVMStaticFrame **frames;
68
69
    /* Special frame indexes */
70
    MVMuint32  main_frame;
71
    MVMuint32  load_frame;
72
    MVMuint32  deserialize_frame;
73
74
} ReaderState;
75
76
/* copies memory dependent on endianness */
77
7.68M
static void memcpy_endian(void *dest, MVMuint8 *src, size_t size) {
78
7.68M
#ifdef MVM_BIGENDIAN
79
    size_t i;
80
    MVMuint8 *destbytes = (MVMuint8 *)dest;
81
    for (i = 0; i < size; i++)
82
        destbytes[size - i - 1] = src[i];
83
#else
84
7.68M
    memcpy(dest, src, size);
85
7.68M
#endif
86
7.68M
}
87
88
/* Reads a uint32 from a buffer. */
89
4.23M
static MVMuint32 read_int32(MVMuint8 *buffer, size_t offset) {
90
4.23M
    MVMuint32 value;
91
4.23M
    memcpy_endian(&value, buffer + offset, 4);
92
4.23M
    return value;
93
4.23M
}
94
95
/* Reads an uint16 from a buffer. */
96
3.44M
static MVMuint16 read_int16(MVMuint8 *buffer, size_t offset) {
97
3.44M
    MVMuint16 value;
98
3.44M
    memcpy_endian(&value, buffer + offset, 2);
99
3.44M
    return value;
100
3.44M
}
101
102
/* Reads an uint8 from a buffer. */
103
256k
static MVMuint8 read_int8(MVMuint8 *buffer, size_t offset) {
104
256k
    return buffer[offset];
105
256k
}
106
107
/* Cleans up reader state. */
108
2.80k
static void cleanup_all(MVMThreadContext *tc, ReaderState *rs) {
109
2.80k
    MVM_free(rs->frames);
110
2.80k
    MVM_free(rs->frame_outer_fixups);
111
2.80k
    MVM_free(rs);
112
2.80k
}
113
114
/* Ensures we can read a certain amount of bytes without overrunning the end
115
 * of the stream. */
116
1.29M
MVM_STATIC_INLINE void ensure_can_read(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs, MVMuint8 *pos, MVMuint32 size) {
117
1.29M
    if (pos + size > rs->read_limit) {
118
0
        cleanup_all(tc, rs);
119
0
        MVM_exception_throw_adhoc(tc, "Read past end of bytecode stream");
120
0
    }
121
1.29M
}
122
123
/* Reads a string index, looks up the string and returns it. Bounds
124
 * checks the string heap index too. */
125
852k
static MVMString * get_heap_string(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs, MVMuint8 *buffer, size_t offset) {
126
852k
    MVMuint32 heap_index = read_int32(buffer, offset);
127
852k
    if (heap_index >= cu->body.num_strings) {
128
0
        if (rs)
129
0
            cleanup_all(tc, rs);
130
0
        MVM_exception_throw_adhoc(tc, "String heap index beyond end of string heap");
131
0
    }
132
852k
    return MVM_cu_string(tc, cu, heap_index);
133
852k
}
134
135
/* Dissects the bytecode stream and hands back a reader pointing to the
136
 * various parts of it. */
137
2.80k
static ReaderState * dissect_bytecode(MVMThreadContext *tc, MVMCompUnit *cu) {
138
2.80k
    MVMCompUnitBody *cu_body = &cu->body;
139
2.80k
    ReaderState *rs = NULL;
140
2.80k
    MVMuint32 version, offset, size;
141
2.80k
142
2.80k
    /* Sanity checks. */
143
2.80k
    if (cu_body->data_size < HEADER_SIZE)
144
0
        MVM_exception_throw_adhoc(tc, "Bytecode stream shorter than header");
145
2.80k
    if (memcmp(cu_body->data_start, "MOARVM\r\n", 8) != 0)
146
0
        MVM_exception_throw_adhoc(tc, "Bytecode stream corrupt (missing magic string)");
147
2.80k
    version = read_int32(cu_body->data_start, 8);
148
2.80k
    if (version < MIN_BYTECODE_VERSION)
149
0
        MVM_exception_throw_adhoc(tc, "Bytecode stream version too low");
150
2.80k
    if (version > MAX_BYTECODE_VERSION)
151
0
        MVM_exception_throw_adhoc(tc, "Bytecode stream version too high");
152
2.80k
153
2.80k
    /* Allocate reader state. */
154
2.80k
    rs = (ReaderState *)MVM_calloc(1, sizeof(ReaderState));
155
2.80k
    rs->version = version;
156
2.80k
    rs->read_limit = cu_body->data_start + cu_body->data_size;
157
2.80k
    cu->body.bytecode_version = version;
158
2.80k
159
2.80k
    /* Locate SC dependencies segment. */
160
2.80k
    offset = read_int32(cu_body->data_start, SCDEP_HEADER_OFFSET);
161
2.80k
    if (offset > cu_body->data_size) {
162
0
        cleanup_all(tc, rs);
163
0
        MVM_exception_throw_adhoc(tc, "Serialization contexts segment starts after end of stream");
164
0
    }
165
2.80k
    rs->sc_seg       = cu_body->data_start + offset;
166
2.80k
    rs->expected_scs = read_int32(cu_body->data_start, SCDEP_HEADER_OFFSET + 4);
167
2.80k
168
2.80k
    /* Locate extension ops segment. */
169
2.80k
    offset = read_int32(cu_body->data_start, EXTOP_HEADER_OFFSET);
170
2.80k
    if (offset > cu_body->data_size) {
171
0
        cleanup_all(tc, rs);
172
0
        MVM_exception_throw_adhoc(tc, "Extension ops segment starts after end of stream");
173
0
    }
174
2.80k
    rs->extop_seg       = cu_body->data_start + offset;
175
2.80k
    rs->expected_extops = read_int32(cu_body->data_start, EXTOP_HEADER_OFFSET + 4);
176
2.80k
177
2.80k
    /* Locate frames segment. */
178
2.80k
    offset = read_int32(cu_body->data_start, FRAME_HEADER_OFFSET);
179
2.80k
    if (offset > cu_body->data_size) {
180
0
        cleanup_all(tc, rs);
181
0
        MVM_exception_throw_adhoc(tc, "Frames segment starts after end of stream");
182
0
    }
183
2.80k
    rs->frame_seg       = cu_body->data_start + offset;
184
2.80k
    rs->expected_frames = read_int32(cu_body->data_start, FRAME_HEADER_OFFSET + 4);
185
2.80k
186
2.80k
    /* Locate callsites segment. */
187
2.80k
    offset = read_int32(cu_body->data_start, CALLSITE_HEADER_OFFSET);
188
2.80k
    if (offset > cu_body->data_size) {
189
0
        cleanup_all(tc, rs);
190
0
        MVM_exception_throw_adhoc(tc, "Callsites segment starts after end of stream");
191
0
    }
192
2.80k
    rs->callsite_seg       = cu_body->data_start + offset;
193
2.80k
    rs->expected_callsites = read_int32(cu_body->data_start, CALLSITE_HEADER_OFFSET + 4);
194
2.80k
195
2.80k
    /* Locate strings segment. */
196
2.80k
    offset = read_int32(cu_body->data_start, STRING_HEADER_OFFSET);
197
2.80k
    if (offset > cu_body->data_size) {
198
0
        cleanup_all(tc, rs);
199
0
        MVM_exception_throw_adhoc(tc, "Strings segment starts after end of stream");
200
0
    }
201
2.80k
    rs->string_seg       = cu_body->data_start + offset;
202
2.80k
    rs->expected_strings = read_int32(cu_body->data_start, STRING_HEADER_OFFSET + 4);
203
2.80k
204
2.80k
    /* Get SC data, if any. */
205
2.80k
    offset = read_int32(cu_body->data_start, SCDATA_HEADER_OFFSET);
206
2.80k
    size = read_int32(cu_body->data_start, SCDATA_HEADER_OFFSET + 4);
207
2.80k
    if (offset > cu_body->data_size || offset + size > cu_body->data_size) {
208
0
        cleanup_all(tc, rs);
209
0
        MVM_exception_throw_adhoc(tc, "Serialized data segment overflows end of stream");
210
0
    }
211
2.80k
    if (offset) {
212
1.58k
        cu_body->serialized = cu_body->data_start + offset;
213
1.58k
        cu_body->serialized_size = size;
214
1.58k
    }
215
2.80k
216
2.80k
    /* Locate bytecode segment. */
217
2.80k
    offset = read_int32(cu_body->data_start, BYTECODE_HEADER_OFFSET);
218
2.80k
    size = read_int32(cu_body->data_start, BYTECODE_HEADER_OFFSET + 4);
219
2.80k
    if (offset > cu_body->data_size || offset + size > cu_body->data_size) {
220
0
        cleanup_all(tc, rs);
221
0
        MVM_exception_throw_adhoc(tc, "Bytecode segment overflows end of stream");
222
0
    }
223
2.80k
    rs->bytecode_seg  = cu_body->data_start + offset;
224
2.80k
    rs->bytecode_size = size;
225
2.80k
226
2.80k
    /* Locate annotations segment. */
227
2.80k
    offset = read_int32(cu_body->data_start, ANNOTATION_HEADER_OFFSET);
228
2.80k
    size = read_int32(cu_body->data_start, ANNOTATION_HEADER_OFFSET + 4);
229
2.80k
    if (offset > cu_body->data_size || offset + size > cu_body->data_size) {
230
0
        cleanup_all(tc, rs);
231
0
        MVM_exception_throw_adhoc(tc, "Annotation segment overflows end of stream");
232
0
    }
233
2.80k
    rs->annotation_seg  = cu_body->data_start + offset;
234
2.80k
    rs->annotation_size = size;
235
2.80k
236
2.80k
    /* Locate HLL name */
237
2.80k
    rs->hll_str_idx = read_int32(cu_body->data_start, HLL_NAME_HEADER_OFFSET);
238
2.80k
239
2.80k
    /* Locate special frame indexes. Note, they are 0 for none, and the
240
2.80k
     * index + 1 if there is one. */
241
2.80k
    rs->main_frame = read_int32(cu_body->data_start, SPECIAL_FRAME_HEADER_OFFSET);
242
2.80k
    rs->load_frame = read_int32(cu_body->data_start, SPECIAL_FRAME_HEADER_OFFSET + 4);
243
2.80k
    rs->deserialize_frame = read_int32(cu_body->data_start, SPECIAL_FRAME_HEADER_OFFSET + 8);
244
2.80k
    if (rs->main_frame > rs->expected_frames
245
2.80k
            || rs->load_frame > rs->expected_frames
246
2.80k
            || rs->deserialize_frame > rs->expected_frames) {
247
0
        MVM_exception_throw_adhoc(tc, "Special frame index out of bounds");
248
0
    }
249
2.80k
250
2.80k
    return rs;
251
2.80k
}
252
253
/* Loads the SC dependencies list. */
254
2.80k
static void deserialize_sc_deps(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) {
255
2.80k
    MVMCompUnitBody *cu_body = &cu->body;
256
2.80k
    MVMuint32 i, sh_idx;
257
2.80k
    MVMuint8  *pos;
258
2.80k
259
2.80k
    /* Allocate SC lists in compilation unit. */
260
2.80k
    cu_body->scs = MVM_malloc(rs->expected_scs * sizeof(MVMSerializationContext *));
261
2.80k
    cu_body->scs_to_resolve = MVM_malloc(rs->expected_scs * sizeof(MVMSerializationContextBody *));
262
2.80k
    cu_body->sc_handle_idxs = MVM_malloc(rs->expected_scs * sizeof(MVMint32));
263
2.80k
    cu_body->num_scs = rs->expected_scs;
264
2.80k
265
2.80k
    /* Resolve all the things. */
266
2.80k
    pos = rs->sc_seg;
267
10.4k
    for (i = 0; i < rs->expected_scs; i++) {
268
7.68k
        MVMSerializationContextBody *scb;
269
7.68k
        MVMString *handle;
270
7.68k
271
7.68k
        /* Grab string heap index. */
272
7.68k
        ensure_can_read(tc, cu, rs, pos, 4);
273
7.68k
        sh_idx = read_int32(pos, 0);
274
7.68k
        pos += 4;
275
7.68k
276
7.68k
        /* Resolve to string. */
277
7.68k
        if (sh_idx >= cu_body->num_strings) {
278
0
            cleanup_all(tc, rs);
279
0
            MVM_exception_throw_adhoc(tc, "String heap index beyond end of string heap");
280
0
        }
281
7.68k
        cu_body->sc_handle_idxs[i] = sh_idx;
282
7.68k
        handle = MVM_cu_string(tc, cu, sh_idx);
283
7.68k
284
7.68k
        /* See if we can resolve it. */
285
7.68k
        uv_mutex_lock(&tc->instance->mutex_sc_registry);
286
7.68k
        MVM_HASH_GET(tc, tc->instance->sc_weakhash, handle, scb);
287
7.68k
        if (scb && scb->sc) {
288
3.93k
            cu_body->scs_to_resolve[i] = NULL;
289
3.93k
            MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->scs[i], scb->sc);
290
3.93k
            scb->claimed = 1;
291
3.93k
        }
292
3.74k
        else {
293
3.74k
            if (!scb) {
294
1.58k
                scb = MVM_calloc(1, sizeof(MVMSerializationContextBody));
295
1.58k
                scb->handle = handle;
296
1.58k
                MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, scb);
297
1.58k
                MVM_sc_add_all_scs_entry(tc, scb);
298
1.58k
            }
299
3.74k
            cu_body->scs_to_resolve[i] = scb;
300
3.74k
            cu_body->scs[i] = NULL;
301
3.74k
        }
302
7.68k
        uv_mutex_unlock(&tc->instance->mutex_sc_registry);
303
7.68k
    }
304
2.80k
}
305
306
/* Loads the extension op records. */
307
2.80k
static MVMExtOpRecord * deserialize_extop_records(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) {
308
2.80k
    MVMExtOpRecord *extops;
309
2.80k
    MVMuint32 num = rs->expected_extops;
310
2.80k
    MVMuint8 *pos;
311
2.80k
    MVMuint32 i;
312
2.80k
313
2.80k
    if (num == 0)
314
2.80k
        return NULL;
315
2.80k
316
0
    extops = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa,
317
0
        num * sizeof(MVMExtOpRecord));
318
0
319
0
    pos = rs->extop_seg;
320
0
    for (i = 0; i < num; i++) {
321
0
        MVMuint32 name_idx;
322
0
        MVMuint16 operand_bytes = 0;
323
0
        MVMuint8 *operand_descriptor = extops[i].operand_descriptor;
324
0
325
0
        /* Read name string index. */
326
0
        ensure_can_read(tc, cu, rs, pos, 4);
327
0
        name_idx = read_int32(pos, 0);
328
0
        pos += 4;
329
0
330
0
        /* Lookup name string. */
331
0
        if (name_idx >= cu->body.num_strings) {
332
0
            cleanup_all(tc, rs);
333
0
            MVM_exception_throw_adhoc(tc,
334
0
                    "String heap index beyond end of string heap");
335
0
        }
336
0
        extops[i].name = MVM_cu_string(tc, cu, name_idx);
337
0
338
0
        /* Read operand descriptor. */
339
0
        ensure_can_read(tc, cu, rs, pos, 8);
340
0
        memcpy(operand_descriptor, pos, 8);
341
0
        pos += 8;
342
0
343
0
        /* Validate operand descriptor.
344
0
         * TODO: Unify with validation in MVM_ext_register_extop? */
345
0
        {
346
0
            MVMuint8 j = 0;
347
0
348
0
            for(; j < 8; j++) {
349
0
                MVMuint8 flags = operand_descriptor[j];
350
0
351
0
                if (!flags)
352
0
                    break;
353
0
354
0
                switch (flags & MVM_operand_rw_mask) {
355
0
                    case MVM_operand_literal:
356
0
                        goto check_literal;
357
0
358
0
                    case MVM_operand_read_reg:
359
0
                    case MVM_operand_write_reg:
360
0
                        operand_bytes += 2;
361
0
                        goto check_reg;
362
0
363
0
                    case MVM_operand_read_lex:
364
0
                    case MVM_operand_write_lex:
365
0
                        operand_bytes += 4;
366
0
                        goto check_reg;
367
0
368
0
                    default:
369
0
                        goto fail;
370
0
                }
371
0
372
0
            check_literal:
373
0
                switch (flags & MVM_operand_type_mask) {
374
0
                    case MVM_operand_int8:
375
0
                        operand_bytes += 1;
376
0
                        continue;
377
0
378
0
                    case MVM_operand_int16:
379
0
                        operand_bytes += 2;
380
0
                        continue;
381
0
382
0
                    case MVM_operand_int32:
383
0
                        operand_bytes += 4;
384
0
                        continue;
385
0
386
0
                    case MVM_operand_int64:
387
0
                        operand_bytes += 8;
388
0
                        continue;
389
0
390
0
                    case MVM_operand_num32:
391
0
                        operand_bytes += 4;
392
0
                        continue;
393
0
394
0
                    case MVM_operand_num64:
395
0
                        operand_bytes += 8;
396
0
                        continue;
397
0
398
0
                    case MVM_operand_str:
399
0
                        operand_bytes += 2;
400
0
                        continue;
401
0
402
0
                    case MVM_operand_coderef:
403
0
                        operand_bytes += 2;
404
0
                        continue;
405
0
406
0
                    case MVM_operand_ins:
407
0
                    case MVM_operand_callsite:
408
0
                    default:
409
0
                        goto fail;
410
0
                }
411
0
412
0
            check_reg:
413
0
                switch (flags & MVM_operand_type_mask) {
414
0
                    case MVM_operand_int8:
415
0
                    case MVM_operand_int16:
416
0
                    case MVM_operand_int32:
417
0
                    case MVM_operand_int64:
418
0
                    case MVM_operand_num32:
419
0
                    case MVM_operand_num64:
420
0
                    case MVM_operand_str:
421
0
                    case MVM_operand_obj:
422
0
                    case MVM_operand_type_var:
423
0
                    case MVM_operand_uint8:
424
0
                    case MVM_operand_uint16:
425
0
                    case MVM_operand_uint32:
426
0
                    case MVM_operand_uint64:
427
0
                        continue;
428
0
429
0
                    default:
430
0
                        goto fail;
431
0
                }
432
0
433
0
            fail:
434
0
                cleanup_all(tc, rs);
435
0
                MVM_exception_throw_adhoc(tc, "Invalid operand descriptor");
436
0
            }
437
0
        }
438
0
439
0
        extops[i].operand_bytes = operand_bytes;
440
0
    }
441
0
442
0
    return extops;
443
0
}
444
445
/* Loads the static frame information (what locals we have, bytecode offset,
446
 * lexicals, etc.) and returns a list of them. */
447
2.80k
static MVMStaticFrame ** deserialize_frames(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) {
448
2.80k
    MVMStaticFrame **frames;
449
2.80k
    MVMuint8        *pos;
450
2.80k
    MVMuint32        bytecode_pos, bytecode_size, i, j;
451
2.80k
452
2.80k
    /* Allocate frames array. */
453
2.80k
    if (rs->expected_frames == 0) {
454
0
        cleanup_all(tc, rs);
455
0
        MVM_exception_throw_adhoc(tc, "Bytecode file must have at least one frame");
456
0
    }
457
2.80k
    frames = MVM_malloc(sizeof(MVMStaticFrame *) * rs->expected_frames);
458
2.80k
459
2.80k
    /* Allocate outer fixup list for frames. */
460
2.80k
    rs->frame_outer_fixups = MVM_malloc(sizeof(MVMuint16) * rs->expected_frames);
461
2.80k
462
2.80k
    /* Load frames. */
463
2.80k
    pos = rs->frame_seg;
464
322k
    for (i = 0; i < rs->expected_frames; i++) {
465
319k
        MVMStaticFrame *static_frame;
466
319k
        MVMStaticFrameBody *static_frame_body;
467
319k
468
319k
        /* Ensure we can read a frame here. */
469
319k
        ensure_can_read(tc, cu, rs, pos, FRAME_HEADER_SIZE);
470
319k
471
319k
        /* Allocate frame and get/check bytecode start/length. */
472
319k
        static_frame = (MVMStaticFrame *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTStaticFrame);
473
319k
        MVM_ASSIGN_REF(tc, &(cu->common.header), frames[i], static_frame);
474
319k
        static_frame_body = &static_frame->body;
475
319k
        bytecode_pos = read_int32(pos, 0);
476
319k
        bytecode_size = read_int32(pos, 4);
477
319k
        if (bytecode_pos >= rs->bytecode_size) {
478
0
            cleanup_all(tc, rs);
479
0
            MVM_exception_throw_adhoc(tc, "Frame has invalid bytecode start point");
480
0
        }
481
319k
        if (bytecode_pos + bytecode_size > rs->bytecode_size) {
482
0
            cleanup_all(tc, rs);
483
0
            MVM_exception_throw_adhoc(tc, "Frame bytecode overflows bytecode stream");
484
0
        }
485
319k
        static_frame_body->bytecode      = rs->bytecode_seg + bytecode_pos;
486
319k
        static_frame_body->bytecode_size = bytecode_size;
487
319k
        static_frame_body->orig_bytecode = static_frame_body->bytecode;
488
319k
489
319k
        /* Get number of locals and lexicals. */
490
319k
        static_frame_body->num_locals   = read_int32(pos, 8);
491
319k
        static_frame_body->num_lexicals = read_int32(pos, 12);
492
319k
493
319k
        /* Get compilation unit unique ID and name. */
494
319k
        MVM_ASSIGN_REF(tc, &(static_frame->common.header), static_frame_body->cuuid, get_heap_string(tc, cu, rs, pos, 16));
495
319k
        MVM_ASSIGN_REF(tc, &(static_frame->common.header), static_frame_body->name, get_heap_string(tc, cu, rs, pos, 20));
496
319k
497
319k
        /* Add frame outer fixup to fixup list. */
498
319k
        rs->frame_outer_fixups[i] = read_int16(pos, 24);
499
319k
500
319k
        /* Get annotations details */
501
319k
        {
502
319k
            MVMuint32 annot_offset    = read_int32(pos, 26);
503
319k
            MVMuint32 num_annotations = read_int32(pos, 30);
504
319k
            if (annot_offset + num_annotations * 12 > rs->annotation_size) {
505
0
                cleanup_all(tc, rs);
506
0
                MVM_exception_throw_adhoc(tc, "Frame annotation segment overflows bytecode stream");
507
0
            }
508
319k
            static_frame_body->annotations_data = rs->annotation_seg + annot_offset;
509
319k
            static_frame_body->num_annotations  = num_annotations;
510
319k
        }
511
319k
512
319k
        /* Read number of handlers. */
513
319k
        static_frame_body->num_handlers = read_int32(pos, 34);
514
319k
515
319k
        /* Read exit handler flag (version 2 and higher). */
516
319k
        if (rs->version >= 2) {
517
319k
            MVMint16 flags = read_int16(pos, 38);
518
319k
            static_frame_body->has_exit_handler = flags & FRAME_FLAG_EXIT_HANDLER;
519
319k
            static_frame_body->is_thunk         = flags & FRAME_FLAG_IS_THUNK;
520
319k
            static_frame_body->no_inline        = flags & FRAME_FLAG_NO_INLINE;
521
319k
        }
522
319k
523
319k
        /* Read code object SC indexes (version 4 and higher). */
524
319k
        if (rs->version >= 4) {
525
319k
            static_frame_body->code_obj_sc_dep_idx = read_int32(pos, 42);
526
319k
            static_frame_body->code_obj_sc_idx     = read_int32(pos, 46);
527
319k
        }
528
319k
529
319k
        /* Associate frame with compilation unit. */
530
319k
        MVM_ASSIGN_REF(tc, &(static_frame->common.header), static_frame_body->cu, cu);
531
319k
532
319k
        /* Stash position for lazy deserialization of the rest. */
533
319k
        static_frame_body->frame_data_pos = pos;
534
319k
535
319k
        /* Skip over the rest, making sure it's readable. */
536
319k
        {
537
319k
            MVMuint32 skip = 2 * static_frame_body->num_locals +
538
319k
                             6 * static_frame_body->num_lexicals;
539
319k
            MVMuint16 slvs = read_int16(pos, 40);
540
319k
            pos += FRAME_HEADER_SIZE;
541
319k
            ensure_can_read(tc, cu, rs, pos, skip);
542
319k
            pos += skip;
543
454k
            for (j = 0; j < static_frame_body->num_handlers; j++) {
544
135k
                ensure_can_read(tc, cu, rs, pos, FRAME_HANDLER_SIZE);
545
135k
                if (read_int32(pos, 8) & MVM_EX_CAT_LABELED) {
546
31
                    pos += FRAME_HANDLER_SIZE;
547
31
                    ensure_can_read(tc, cu, rs, pos, 2);
548
31
                    pos += 2;
549
31
                }
550
135k
                else {
551
135k
                    pos += FRAME_HANDLER_SIZE;
552
135k
                }
553
135k
            }
554
319k
            ensure_can_read(tc, cu, rs, pos, slvs * FRAME_SLV_SIZE);
555
319k
            pos += slvs * FRAME_SLV_SIZE;
556
319k
        }
557
319k
    }
558
2.80k
559
2.80k
    /* Fixup outers. */
560
322k
    for (i = 0; i < rs->expected_frames; i++) {
561
319k
        if (rs->frame_outer_fixups[i] != i) {
562
310k
            if (rs->frame_outer_fixups[i] < rs->expected_frames) {
563
310k
                MVM_ASSIGN_REF(tc, &(frames[i]->common.header), frames[i]->body.outer, frames[rs->frame_outer_fixups[i]]);
564
310k
            }
565
0
            else {
566
0
                cleanup_all(tc, rs);
567
0
                MVM_exception_throw_adhoc(tc, "Invalid frame outer index; cannot fixup");
568
0
            }
569
310k
        }
570
319k
    }
571
2.80k
572
2.80k
    return frames;
573
2.80k
}
574
575
/* Finishes up reading and exploding of a frame. */
576
void MVM_bytecode_finish_frame(MVMThreadContext *tc, MVMCompUnit *cu,
577
117k
                               MVMStaticFrame *sf, MVMint32 dump_only) {
578
117k
    MVMuint32 j;
579
117k
    MVMuint8 *pos;
580
117k
    MVMuint16 slvs;
581
117k
582
117k
    /* Ensure we've not already done this. */
583
117k
    if (sf->body.fully_deserialized)
584
0
        return;
585
117k
586
117k
    /* Acquire the update mutex on the CompUnit. */
587
117k
    MVMROOT(tc, cu, {
588
117k
    MVMROOT(tc, sf, {
589
117k
        MVM_reentrantmutex_lock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
590
117k
    });
591
117k
    });
592
117k
593
117k
    /* Ensure no other thread has done this for us in the mean time. */
594
117k
    if (sf->body.fully_deserialized) {
595
0
        MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
596
0
        return;
597
0
    }
598
117k
599
117k
    /* Locate start of frame body. */
600
117k
    pos = sf->body.frame_data_pos;
601
117k
602
117k
    /* Get the number of static lex values we'll need to apply. */
603
117k
    slvs = read_int16(pos, 40);
604
117k
605
117k
    /* Skip past header. */
606
117k
    pos += FRAME_HEADER_SIZE;
607
117k
608
117k
    /* Read the local types. */
609
117k
    if (sf->body.num_locals) {
610
117k
        sf->body.local_types = MVM_malloc(sizeof(MVMuint16) * sf->body.num_locals);
611
1.98M
        for (j = 0; j < sf->body.num_locals; j++)
612
1.87M
            sf->body.local_types[j] = read_int16(pos, 2 * j);
613
117k
        pos += 2 * sf->body.num_locals;
614
117k
    }
615
117k
616
117k
    /* Read the lexical types. */
617
117k
    if (sf->body.num_lexicals) {
618
39.6k
        /* Allocate names hash and types list. */
619
39.6k
        sf->body.lexical_types = MVM_malloc(sizeof(MVMuint16) * sf->body.num_lexicals);
620
39.6k
621
39.6k
        /* Read in data. */
622
39.6k
        if (sf->body.num_lexicals) {
623
39.6k
            sf->body.lexical_names_list = MVM_malloc(sizeof(MVMLexicalRegistry *) * sf->body.num_lexicals);
624
39.6k
        }
625
170k
        for (j = 0; j < sf->body.num_lexicals; j++) {
626
130k
            MVMString *name = get_heap_string(tc, cu, NULL, pos, 6 * j + 2);
627
130k
            MVMLexicalRegistry *entry = MVM_calloc(1, sizeof(MVMLexicalRegistry));
628
130k
629
130k
            MVM_ASSIGN_REF(tc, &(sf->common.header), entry->key, name);
630
130k
            sf->body.lexical_names_list[j] = entry;
631
130k
            entry->value = j;
632
130k
633
130k
            sf->body.lexical_types[j] = read_int16(pos, 6 * j);
634
130k
            MVM_HASH_BIND(tc, sf->body.lexical_names, name, entry)
635
130k
        }
636
39.6k
        pos += 6 * sf->body.num_lexicals;
637
39.6k
    }
638
117k
639
117k
    /* Read in handlers. */
640
117k
    if (sf->body.num_handlers) {
641
14.8k
        /* Allocate space for handler data. */
642
14.8k
        sf->body.handlers = MVM_malloc(sf->body.num_handlers * sizeof(MVMFrameHandler));
643
14.8k
644
14.8k
        /* Read each handler. */
645
71.4k
        for (j = 0; j < sf->body.num_handlers; j++) {
646
56.5k
            sf->body.handlers[j].start_offset  = read_int32(pos, 0);
647
56.5k
            sf->body.handlers[j].end_offset    = read_int32(pos, 4);
648
56.5k
            sf->body.handlers[j].category_mask = read_int32(pos, 8);
649
56.5k
            sf->body.handlers[j].action        = read_int16(pos, 12);
650
56.5k
            sf->body.handlers[j].block_reg     = read_int16(pos, 14);
651
56.5k
            sf->body.handlers[j].goto_offset   = read_int32(pos, 16);
652
56.5k
            pos += FRAME_HANDLER_SIZE;
653
56.5k
            if (sf->body.handlers[j].category_mask & MVM_EX_CAT_LABELED) {
654
31
                sf->body.handlers[j].label_reg = read_int16(pos, 0);
655
31
                pos += 2;
656
31
            }
657
56.5k
            sf->body.handlers[j].inlinee = -1;
658
56.5k
        }
659
14.8k
    }
660
117k
661
117k
    /* Allocate default lexical environment storage. */
662
117k
    sf->body.env_size         = sf->body.num_lexicals * sizeof(MVMRegister);
663
117k
    sf->body.static_env       = MVM_calloc(1, sf->body.env_size);
664
117k
    sf->body.static_env_flags = MVM_calloc(1, sf->body.num_lexicals);
665
117k
666
117k
    /* Stash static lexical segment offset, so we can easily locate it to
667
117k
     * resolve them later. */
668
20.2k
    sf->body.frame_static_lex_pos = slvs ? pos : NULL;
669
117k
670
117k
    /* Read in static lexical flags. */
671
170k
    for (j = 0; j < slvs; j++) {
672
53.6k
        MVMuint16 lex_idx = read_int16(pos, 0);
673
53.6k
        MVMuint16 flags   = read_int16(pos, 2);
674
53.6k
675
53.6k
        if (lex_idx >= sf->body.num_lexicals) {
676
0
            MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
677
0
            MVM_exception_throw_adhoc(tc, "Lexical index out of bounds: %d > %d", lex_idx, sf->body.num_lexicals);
678
0
        }
679
53.6k
680
53.6k
        sf->body.static_env_flags[lex_idx] = flags;
681
53.6k
        if (flags == 2 && !dump_only) {
682
2
            /* State variable; need to resolve wval immediately. Other kinds
683
2
             * can wait. */
684
2
            MVMSerializationContext *sc = MVM_sc_get_sc(tc, cu, read_int32(pos, 4));
685
2
            if (sc == NULL) {
686
0
                MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
687
0
                MVM_exception_throw_adhoc(tc, "SC not yet resolved; lookup failed");
688
0
            }
689
2
            MVM_ASSIGN_REF(tc, &(sf->common.header), sf->body.static_env[lex_idx].o,
690
2
                MVM_sc_get_object(tc, sc, read_int32(pos, 8)));
691
2
        }
692
53.6k
        pos += FRAME_SLV_SIZE;
693
53.6k
    }
694
117k
695
117k
    /* Mark the frame fully deserialized. */
696
117k
    sf->body.fully_deserialized = 1;
697
117k
698
117k
    /* Release the update mutex again */
699
117k
    MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
700
117k
}
701
702
/* Gets the SC reference for a given static lexical var for
703
 * vivification purposes */
704
6.80k
MVMuint8 MVM_bytecode_find_static_lexical_scref(MVMThreadContext *tc, MVMCompUnit *cu, MVMStaticFrame *sf, MVMuint16 index, MVMint32 *sc, MVMint32 *id) {
705
6.80k
    MVMuint16 slvs, i;
706
6.80k
707
6.80k
    MVMuint8 *pos = sf->body.frame_static_lex_pos;
708
6.80k
    if (!pos)
709
145
        return 0;
710
6.80k
711
6.66k
    slvs = read_int16(sf->body.frame_data_pos, 40);
712
65.4k
    for (i = 0; i < slvs; i++) {
713
65.4k
        if (read_int16(pos, 0) == index) {
714
6.66k
            *sc = read_int32(pos, 4);
715
6.66k
            *id = read_int32(pos, 8);
716
6.66k
            return 1;
717
6.66k
        }
718
58.7k
        pos += FRAME_SLV_SIZE;
719
58.7k
    }
720
6.66k
721
0
    return 0;
722
6.66k
}
723
724
/* Loads the callsites. */
725
2.80k
static MVMCallsite ** deserialize_callsites(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) {
726
2.80k
    MVMCallsite **callsites;
727
2.80k
    MVMuint8     *pos;
728
2.80k
    MVMuint32     i, j, elems;
729
2.80k
    MVMCompUnitBody *cu_body = &cu->body;
730
2.80k
731
2.80k
    /* Allocate space for callsites. */
732
2.80k
    if (rs->expected_callsites == 0)
733
89
        return NULL;
734
2.71k
    callsites = MVM_fixed_size_alloc(tc, tc->instance->fsa,
735
2.71k
        sizeof(MVMCallsite *) * rs->expected_callsites);
736
2.71k
737
2.71k
    /* Load callsites. */
738
2.71k
    pos = rs->callsite_seg;
739
78.6k
    for (i = 0; i < rs->expected_callsites; i++) {
740
75.9k
        MVMuint8 has_flattening = 0;
741
75.9k
        MVMuint32 positionals = 0;
742
75.9k
        MVMuint32 nameds_slots = 0;
743
75.9k
        MVMuint32 nameds_non_flattening = 0;
744
75.9k
745
75.9k
        /* Ensure we can read at least an element count. */
746
75.9k
        ensure_can_read(tc, cu, rs, pos, 2);
747
75.9k
        elems = read_int16(pos, 0);
748
75.9k
        pos += 2;
749
75.9k
750
75.9k
        /* Allocate space for the callsite. */
751
75.9k
        callsites[i] = MVM_malloc(sizeof(MVMCallsite));
752
75.9k
        callsites[i]->flag_count = elems;
753
75.9k
        if (elems)
754
74.1k
            callsites[i]->arg_flags = MVM_malloc(elems * sizeof(MVMCallsiteEntry));
755
75.9k
        else
756
1.74k
            callsites[i]->arg_flags = NULL;
757
75.9k
758
75.9k
        /* Ensure we can read in a callsite of this size, and do so. */
759
75.9k
        ensure_can_read(tc, cu, rs, pos, elems);
760
332k
        for (j = 0; j < elems; j++)
761
256k
            callsites[i]->arg_flags[j] = read_int8(pos, j);
762
75.9k
        pos += elems;
763
75.9k
764
75.9k
        /* Add alignment. */
765
75.9k
        pos += elems % 2;
766
75.9k
767
75.9k
        /* Count positional arguments, and validate that all positionals come
768
75.9k
         * before all nameds (flattening named counts as named). */
769
332k
        for (j = 0; j < elems; j++) {
770
256k
            if (callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_FLAT) {
771
5.19k
                if (!(callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_OBJ))
772
0
                    MVM_exception_throw_adhoc(tc, "Flattened positional args must be objects");
773
5.19k
                if (nameds_slots)
774
0
                    MVM_exception_throw_adhoc(tc, "Flattened positional args must appear before named args");
775
5.19k
                has_flattening = 1;
776
5.19k
                positionals++;
777
5.19k
            }
778
251k
            else if (callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_FLAT_NAMED) {
779
3.31k
                if (!(callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_OBJ))
780
0
                    MVM_exception_throw_adhoc(tc, "Flattened named args must be objects");
781
3.31k
                has_flattening = 1;
782
3.31k
                nameds_slots++;
783
3.31k
            }
784
248k
            else if (callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) {
785
81.9k
                nameds_slots += 2;
786
81.9k
                nameds_non_flattening++;
787
81.9k
            }
788
166k
            else if (nameds_slots) {
789
0
                MVM_exception_throw_adhoc(tc, "All positional args must appear before named args");
790
0
            }
791
166k
            else {
792
166k
                positionals++;
793
166k
            }
794
256k
        }
795
75.9k
        callsites[i]->num_pos        = positionals;
796
75.9k
        callsites[i]->arg_count      = positionals + nameds_slots;
797
75.9k
        callsites[i]->has_flattening = has_flattening;
798
75.9k
        callsites[i]->is_interned    = 0;
799
75.9k
        callsites[i]->with_invocant  = NULL;
800
75.9k
801
75.9k
        if (rs->version >= 3 && nameds_non_flattening) {
802
42.6k
            ensure_can_read(tc, cu, rs, pos, nameds_non_flattening * 4);
803
42.6k
            callsites[i]->arg_names = MVM_malloc(nameds_non_flattening * sizeof(MVMString*));
804
124k
            for (j = 0; j < nameds_non_flattening; j++) {
805
81.9k
                callsites[i]->arg_names[j] = get_heap_string(tc, cu, rs, pos, 0);
806
81.9k
                pos += 4;
807
81.9k
            }
808
33.2k
        } else {
809
33.2k
            callsites[i]->arg_names = NULL;
810
33.2k
        }
811
75.9k
812
75.9k
        /* Track maximum callsite size we've seen. (Used for now, though
813
75.9k
         * in the end we probably should calculate it by frame.) */
814
75.9k
        if (callsites[i]->arg_count > cu_body->max_callsite_size)
815
4.46k
            cu_body->max_callsite_size = callsites[i]->arg_count;
816
75.9k
817
75.9k
        /* Try to intern the callsite (that is, see if it matches one the
818
75.9k
         * VM already knows about). If it does, it will free the memory
819
75.9k
         * associated and replace it with the interned one. Otherwise it
820
75.9k
         * will store this one, provided it meets the interning rules. */
821
75.9k
        MVM_callsite_try_intern(tc, &(callsites[i]));
822
75.9k
    }
823
2.71k
824
2.71k
    /* Add one on to the maximum, to allow space for unshifting an extra
825
2.71k
     * arg in the "supply invoked code object" case. */
826
2.71k
    cu_body->max_callsite_size++;
827
2.71k
828
2.71k
    return callsites;
829
2.80k
}
830
831
/* Creates code objects to go with each of the static frames. */
832
2.80k
static void create_code_objects(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) {
833
2.80k
    MVMuint32  i;
834
2.80k
    MVMObject *code_type;
835
2.80k
    MVMCompUnitBody *cu_body = &cu->body;
836
2.80k
837
2.80k
    cu_body->coderefs = MVM_malloc(cu_body->num_frames * sizeof(MVMObject *));
838
2.80k
839
2.80k
    code_type = tc->instance->boot_types.BOOTCode;
840
322k
    for (i = 0; i < cu_body->num_frames; i++) {
841
319k
        MVMCode *coderef = (MVMCode *)REPR(code_type)->allocate(tc, STABLE(code_type));
842
319k
        MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->coderefs[i], coderef);
843
319k
        MVM_ASSIGN_REF(tc, &(coderef->common.header), coderef->body.sf, rs->frames[i]);
844
319k
        MVM_ASSIGN_REF(tc, &(coderef->common.header), coderef->body.name, rs->frames[i]->body.name);
845
319k
        MVM_ASSIGN_REF(tc, &(rs->frames[i]->common.header), rs->frames[i]->body.static_code, coderef);
846
319k
    }
847
2.80k
}
848
849
/* Takes a compilation unit pointing at a bytecode stream (which actually
850
 * has more than just the executive bytecode, but also various declarations,
851
 * like frames). Unpacks it and populates the compilation unit. */
852
2.80k
void MVM_bytecode_unpack(MVMThreadContext *tc, MVMCompUnit *cu) {
853
2.80k
    ReaderState *rs;
854
2.80k
    MVMCompUnitBody *cu_body = &cu->body;
855
2.80k
    /* Allocate directly in generation 2 so the object is not moving around. */
856
2.80k
    MVM_gc_allocate_gen2_default_set(tc);
857
2.80k
858
2.80k
    /* Dissect the bytecode into its parts. */
859
2.80k
    rs = dissect_bytecode(tc, cu);
860
2.80k
861
2.80k
    /* Allocate space for the strings heap; we deserialize it lazily. */
862
2.80k
    cu_body->strings = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa,
863
2.80k
        rs->expected_strings * sizeof(MVMString *));
864
2.80k
    cu_body->num_strings = rs->expected_strings;
865
2.80k
    cu_body->orig_strings = rs->expected_strings;
866
2.80k
    cu_body->string_heap_fast_table = MVM_calloc(
867
2.80k
        (rs->expected_strings / MVM_STRING_FAST_TABLE_SPAN) + 1,
868
2.80k
        sizeof(MVMuint32));
869
2.80k
    cu_body->string_heap_start = rs->string_seg;
870
2.80k
    cu_body->string_heap_read_limit = rs->read_limit;
871
2.80k
872
2.80k
    /* Load SC dependencies. */
873
2.80k
    deserialize_sc_deps(tc, cu, rs);
874
2.80k
875
2.80k
    /* Load the extension op records. */
876
2.80k
    cu_body->extops = deserialize_extop_records(tc, cu, rs);
877
2.80k
    cu_body->num_extops = rs->expected_extops;
878
2.80k
879
2.80k
    /* Load the static frame info and give each one a code reference. */
880
2.80k
    rs->frames = deserialize_frames(tc, cu, rs);
881
2.80k
    cu_body->num_frames = rs->expected_frames;
882
2.80k
    cu_body->orig_frames = rs->expected_frames;
883
2.80k
    create_code_objects(tc, cu, rs);
884
2.80k
885
2.80k
    /* Load callsites. */
886
2.80k
    cu_body->max_callsite_size = MVM_MIN_CALLSITE_SIZE;
887
2.80k
    cu_body->callsites = deserialize_callsites(tc, cu, rs);
888
2.80k
    cu_body->num_callsites = rs->expected_callsites;
889
2.80k
    cu_body->orig_callsites = rs->expected_callsites;
890
2.80k
891
2.80k
    if (rs->hll_str_idx > rs->expected_strings)
892
0
        MVM_exception_throw_adhoc(tc, "Unpacking bytecode: HLL name string index out of range: %d > %d", rs->hll_str_idx, rs->expected_strings);
893
2.80k
894
2.80k
    /* Resolve HLL name. */
895
2.80k
    MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->hll_name,
896
2.80k
        MVM_cu_string(tc, cu, rs->hll_str_idx));
897
2.80k
898
2.80k
    /* Resolve special frames. */
899
2.80k
    MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->main_frame,
900
2.80k
        rs->main_frame ? rs->frames[rs->main_frame - 1] : rs->frames[0]);
901
2.80k
    if (rs->load_frame)
902
1.72k
        MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->load_frame, rs->frames[rs->load_frame - 1]);
903
2.80k
    if (rs->deserialize_frame)
904
2.67k
        MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->deserialize_frame, rs->frames[rs->deserialize_frame - 1]);
905
2.80k
906
2.80k
    /* Clean up reader state. */
907
2.80k
    cleanup_all(tc, rs);
908
2.80k
909
2.80k
    /* Restore normal GC allocation. */
910
2.80k
    MVM_gc_allocate_gen2_default_clear(tc);
911
2.80k
}
912
913
/* returns the annotation for that bytecode offset */
914
21.1k
MVMBytecodeAnnotation * MVM_bytecode_resolve_annotation(MVMThreadContext *tc, MVMStaticFrameBody *sfb, MVMuint32 offset) {
915
21.1k
    MVMBytecodeAnnotation *ba = NULL;
916
21.1k
    MVMuint32 i;
917
21.1k
918
21.1k
    if (sfb->num_annotations && offset < sfb->bytecode_size) {
919
10.2k
        MVMuint8 *cur_anno = sfb->annotations_data;
920
10.4k
        for (i = 0; i < sfb->num_annotations; i++) {
921
10.4k
            MVMint32 ann_offset = read_int32(cur_anno, 0);
922
10.4k
            if (ann_offset > offset)
923
10.2k
                break;
924
258
            cur_anno += 12;
925
258
        }
926
10.2k
        if (i)
927
18
            cur_anno -= 12;
928
10.2k
        ba = MVM_malloc(sizeof(MVMBytecodeAnnotation));
929
10.2k
        ba->bytecode_offset = read_int32(cur_anno, 0);
930
10.2k
        ba->filename_string_heap_index = read_int32(cur_anno, 4);
931
10.2k
        ba->line_number = read_int32(cur_anno, 8);
932
10.2k
        ba->ann_offset = cur_anno - sfb->annotations_data;
933
10.2k
        ba->ann_index  = i;
934
10.2k
    }
935
21.1k
936
21.1k
    return ba;
937
21.1k
}
938
939
10.8k
void MVM_bytecode_advance_annotation(MVMThreadContext *tc, MVMStaticFrameBody *sfb, MVMBytecodeAnnotation *ba) {
940
10.8k
    MVMuint32 i = ba->ann_index + 1;
941
10.8k
942
10.8k
    MVMuint8 *cur_anno = sfb->annotations_data + ba->ann_offset;
943
10.8k
    cur_anno += 12;
944
10.8k
    if (i >= sfb->num_annotations) {
945
1.42k
        ba->bytecode_offset = -1;
946
1.42k
        ba->filename_string_heap_index = 0;
947
1.42k
        ba->line_number = 0;
948
1.42k
        ba->ann_offset = -1;
949
1.42k
        ba->ann_index = -1;
950
9.43k
    } else {
951
9.43k
        ba->bytecode_offset = read_int32(cur_anno, 0);
952
9.43k
        ba->filename_string_heap_index = read_int32(cur_anno, 4);
953
9.43k
        ba->line_number = read_int32(cur_anno, 8);
954
9.43k
        ba->ann_offset = cur_anno - sfb->annotations_data;
955
9.43k
        ba->ann_index  = i;
956
9.43k
    }
957
10.8k
}