Coverage Report

Created: 2017-04-15 07:07

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