// File: /workspace/github_c_makefile_star2_O1/janet-lang[P]janet/src/core/peg.c
// Function: peg_unmarshal
static void *peg_unmarshal(JanetMarshalContext *ctx) {
    size_t bytecode_len = janet_unmarshal_size(ctx);
    uint32_t num_constants = (uint32_t) janet_unmarshal_int(ctx);

    /* Calculate offsets. Should match those in make_peg */
    size_t bytecode_start = size_padded(sizeof(JanetPeg), sizeof(uint32_t));
    size_t bytecode_size = bytecode_len * sizeof(uint32_t);
    size_t constants_start = size_padded(bytecode_start + bytecode_size, sizeof(Janet));
    size_t total_size = constants_start + sizeof(Janet) * (size_t) num_constants;

    /* DOS prevention? I.E. we could read bytecode and constants before
     * hand so we don't allocated a ton of memory on bad, short input */

    /* Allocate PEG */
    char *mem = janet_unmarshal_abstract(ctx, total_size);
    JanetPeg *peg = (JanetPeg *)mem;
    uint32_t *bytecode = (uint32_t *)(mem + bytecode_start);
    Janet *constants = (Janet *)(mem + constants_start);
    peg->bytecode = NULL;
    peg->constants = NULL;
    peg->bytecode_len = bytecode_len;
    peg->num_constants = num_constants;

    for (size_t i = 0; i < peg->bytecode_len; i++)
        bytecode[i] = (uint32_t) janet_unmarshal_int(ctx);
    for (uint32_t j = 0; j < peg->num_constants; j++)
        constants[j] = janet_unmarshal_janet(ctx);

    /* After here, no panics except for the bad: label. */

    /* Keep track at each index if an instruction was
     * reference (0x01) or is in a main bytecode position
     * (0x02). This lets us do a linear scan and not
     * need to a depth first traversal. It is stricter
     * than a dfs by not allowing certain kinds of unused
     * bytecode. */
    uint32_t blen = (int32_t) peg->bytecode_len;
    uint32_t clen = peg->num_constants;
    uint8_t *op_flags = janet_calloc(1, blen);
    if (NULL == op_flags) {
        JANET_OUT_OF_MEMORY;
    }

    /* verify peg bytecode */
    int32_t has_backref = 0;
    uint32_t i = 0;
    while (i < blen) {
        uint32_t instr = bytecode[i];
        uint32_t *rule = bytecode + i;
        op_flags[i] |= 0x02;
        switch (instr) {
            case RULE_LITERAL:
                i += 2 + ((rule[1] + 3) >> 2);
                break;
            case RULE_NCHAR:
            case RULE_NOTNCHAR:
            case RULE_RANGE:
            case RULE_POSITION:
            case RULE_LINE:
            case RULE_COLUMN:
                /* [1 word] */
                i += 2;
                break;
            case RULE_BACKMATCH:
                /* [1 word] */
                i += 2;
                has_backref = 1;
                break;
            case RULE_SET:
                /* [8 words] */
                i += 9;
                break;
            case RULE_LOOK:
                /* [offset, rule] */
                if (rule[2] >= blen) goto bad;
                op_flags[rule[2]] |= 0x1;
                i += 3;
                break;
            case RULE_CHOICE:
            case RULE_SEQUENCE:
                /* [len, rules...] */
            {
                uint32_t len = rule[1];
                for (uint32_t j = 0; j < len; j++) {
                    if (rule[2 + j] >= blen) goto bad;
                    op_flags[rule[2 + j]] |= 0x1;
                }
                i += 2 + len;
            }
            break;
            case RULE_IF:
            case RULE_IFNOT:
            case RULE_LENPREFIX:
                /* [rule_a, rule_b (b if not a)] */
                if (rule[1] >= blen) goto bad;
                if (rule[2] >= blen) goto bad;
                op_flags[rule[1]] |= 0x01;
                op_flags[rule[2]] |= 0x01;
                i += 3;
                break;
            case RULE_BETWEEN:
                /* [lo, hi, rule] */
                if (rule[3] >= blen) goto bad;
                op_flags[rule[3]] |= 0x01;
                i += 4;
                break;
            case RULE_ARGUMENT:
                /* [searchtag, tag] */
                i += 3;
                break;
            case RULE_GETTAG:
                /* [searchtag, tag] */
                i += 3;
                has_backref = 1;
                break;
            case RULE_CONSTANT:
                /* [constant, tag] */
                if (rule[1] >= clen) goto bad;
                i += 3;
                break;
            case RULE_CAPTURE_NUM:
                /* [rule, base, tag] */
                if (rule[1] >= blen) goto bad;
                op_flags[rule[1]] |= 0x01;
                i += 4;
                break;
            case RULE_ACCUMULATE:
            case RULE_GROUP:
            case RULE_CAPTURE:
            case RULE_UNREF:
                /* [rule, tag] */
                if (rule[1] >= blen) goto bad;
                op_flags[rule[1]] |= 0x01;
                i += 3;
                break;
            case RULE_REPLACE:
            case RULE_MATCHTIME:
                /* [rule, constant, tag] */
                if (rule[1] >= blen) goto bad;
                if (rule[2] >= clen) goto bad;
                op_flags[rule[1]] |= 0x01;
                i += 4;
                break;
            case RULE_SUB:
            case RULE_TIL:
            case RULE_SPLIT:
                /* [rule, rule] */
                if (rule[1] >= blen) goto bad;
                if (rule[2] >= blen) goto bad;
                op_flags[rule[1]] |= 0x01;
                op_flags[rule[2]] |= 0x01;
                i += 3;
                break;
            case RULE_ERROR:
            case RULE_DROP:
            case RULE_ONLY_TAGS:
            case RULE_NOT:
            case RULE_TO:
            case RULE_THRU:
                /* [rule] */
                if (rule[1] >= blen) goto bad;
                op_flags[rule[1]] |= 0x01;
                i += 2;
                break;
            case RULE_READINT:
                /* [ width | (endianness << 5) | (signedness << 6), tag ] */
                if (rule[1] > JANET_MAX_READINT_WIDTH) goto bad;
                i += 3;
                break;
            case RULE_NTH:
                /* [nth, rule, tag] */
                if (rule[2] >= blen) goto bad;
                op_flags[rule[2]] |= 0x01;
                i += 4;
                break;
            default:
                goto bad;
        }
    }

    /* last instruction cannot overflow */
    if (i != blen) goto bad;

    /* Make sure all referenced instructions are actually
     * in instruction positions. */
    for (i = 0; i < blen; i++)
        if (op_flags[i] == 0x01) goto bad;

    /* Good return */
    peg->bytecode = bytecode;
    peg->constants = constants;
    peg->has_backref = has_backref;
    janet_free(op_flags);
    return peg;

bad:
    janet_free(op_flags);
    janet_panic("invalid peg bytecode");
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdi, %r14
callq 0x3557b
movq %rax, %r12
movq 0x8(%r14), %rdi
leaq 0x18(%r14), %r15
movq %r15, %rsi
callq 0x354de
movl %eax, %ebp
leaq 0x27(,%r12,4), %r13
andq $-0x8, %r13
movl %eax, %eax
leaq (,%rax,8), %rsi
addq %r13, %rsi
movq %r14, %rdi
callq 0x3630d
movq %rax, %rbx
xorps %xmm0, %xmm0
movups %xmm0, (%rax)
movq %r12, 0x10(%rax)
movl %ebp, 0x18(%rax)
testq %r12, %r12
je 0x3e4e5
xorl %r12d, %r12d
movq 0x8(%r14), %rdi
movq %r15, %rsi
callq 0x354de
movl %eax, 0x20(%rbx,%r12,4)
incq %r12
cmpq 0x10(%rbx), %r12
jb 0x3e4cb
addq %rbx, %r13
movl 0x18(%rbx), %r12d
testl %r12d, %r12d
je 0x3e526
xorl %ebp, %ebp
leaq 0x10(%rsp), %r15
movq 0x8(%r14), %rdi
movq 0x18(%r14), %rsi
movl 0x10(%r14), %ecx
movq %r15, %rdx
callq 0x356d3
movq %rax, 0x18(%r14)
movq 0x10(%rsp), %rax
movq %rax, (%r13,%rbp,8)
incq %rbp
movl 0x18(%rbx), %r12d
cmpq %r12, %rbp
jb 0x3e4f8
movq 0x10(%rbx), %r15
movl %r15d, %r14d
movl $0x1, %edi
movq %r14, %rsi
callq 0x165b0
testq %rax, %rax
je 0x3e742
movq %rbx, %rcx
addq $0x20, %rcx
leaq 0x1d437(%rip), %rdi     # 0x5b988
xorl %ebp, %ebp
xorl %r9d, %r9d
cmpl %r15d, %r9d
jae 0x3e6eb
movl %r9d, %esi
movl (%rcx,%rsi,4), %r8d
orb $0x2, (%rax,%rsi)
movl $0xd, %r10d
cmpq $0x24, %r8
ja 0x3e6c6
leaq (%rcx,%rsi,4), %r11
movslq (%rdi,%r8,4), %rdx
addq %rdi, %rdx
jmpq *%rdx
movl 0x4(%r11), %esi
cmpl %r15d, %esi
jae 0x3e6c6
movl 0x8(%r11), %r8d
cmpl %r15d, %r8d
jae 0x3e6c6
orb $0x1, (%rax,%rsi)
orb $0x1, (%rax,%r8)
jmp 0x3e661
movl 0x4(%r11), %edx
cmpl %r15d, %edx
jae 0x3e6c6
orb $0x1, (%rax,%rdx)
addl $0x2, %r9d
jmp 0x3e6c3
movl 0x4(%r11), %edx
cmpl %r15d, %edx
jae 0x3e6c6
orb $0x1, (%rax,%rdx)
jmp 0x3e661
movl 0x4(%r11), %esi
cmpl %r15d, %esi
jae 0x3e6c6
cmpl %r12d, 0x8(%r11)
jae 0x3e6c6
orb $0x1, (%rax,%rsi)
jmp 0x3e6bf
movl %ebp, 0xc(%rsp)
movl 0x4(%r11), %esi
testq %rsi, %rsi
je 0x3e638
movq %rsi, %rbp
negq %rbp
movl $0x2, %r8d
movl %r8d, %edx
movl (%r11,%rdx,4), %edx
cmpl %r15d, %edx
jae 0x3e642
orb $0x1, (%rax,%rdx)
leaq (%r8,%rbp), %rdx
incq %rdx
incq %r8
cmpq $0x2, %rdx
jne 0x3e618
addl %esi, %r9d
addl $0x2, %r9d
xorl %r10d, %r10d
movl 0xc(%rsp), %ebp
jmp 0x3e6c6
movl 0x4(%r11), %edx
jmp 0x3e6b6
movl 0x8(%r11), %edx
jmp 0x3e6b6
movl 0x8(%r11), %esi
cmpl %r15d, %esi
jae 0x3e6c6
orb $0x1, (%rax,%rsi)
addl $0x3, %r9d
jmp 0x3e6c3
leal 0x3(%r9), %edx
cmpl $0x9, 0x4(%r11)
cmovael %r9d, %edx
movl $0x0, %r10d
movl $0xd, %esi
cmovael %esi, %r10d
jmp 0x3e6e6
movl 0x4(%r11), %edx
addl $0x3, %edx
shrl $0x2, %edx
addl %edx, %r9d
addl $0x2, %r9d
jmp 0x3e6c3
addl $0x9, %r9d
jmp 0x3e6c3
addl $0x2, %r9d
jmp 0x3e6a8
addl $0x3, %r9d
xorl %r10d, %r10d
movl $0x1, %ebp
jmp 0x3e6c6
movl 0xc(%r11), %edx
cmpl %r15d, %edx
jae 0x3e6c6
orb $0x1, (%rax,%rdx)
addl $0x4, %r9d
xorl %r10d, %r10d
testl %r10d, %r10d
je 0x3e556
jmp 0x3e716
leal 0x3(%r9), %edx
cmpl %r12d, 0x4(%r11)
cmovael %r9d, %edx
movl $0x0, %esi
cmovbl %esi, %r10d
movl %edx, %r9d
jmp 0x3e6c6
jne 0x3e72e
testl %r15d, %r15d
je 0x3e702
xorl %esi, %esi
cmpb $0x1, (%rax,%rsi)
je 0x3e72e
incq %rsi
cmpl %esi, %r14d
jne 0x3e6f4
movq %rcx, (%rbx)
movq %r13, 0x8(%rbx)
movl %ebp, 0x1c(%rbx)
movq %rax, %rdi
callq 0x160b0
jmp 0x3e71c
cmpl $0xd, %r10d
je 0x3e72e
movq %rbx, %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rdi
callq 0x160b0
leaq 0x6ee2d(%rip), %rdi     # 0xad56a
callq 0x188ee
callq 0x17b71