| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "gwion_util.h" | ||
| 2 | #include "gwion_ast.h" | ||
| 3 | #include "gwion_env.h" | ||
| 4 | #include "vm.h" | ||
| 5 | #include "instr.h" | ||
| 6 | #include "memoize.h" | ||
| 7 | #include "gwion.h" | ||
| 8 | #include "object.h" | ||
| 9 | #include "array.h" | ||
| 10 | #include "operator.h" | ||
| 11 | #include "import.h" | ||
| 12 | |||
| 13 | 14194 | ANN void free_instr(const Gwion gwion, const Instr instr) { | |
| 14 |
2/2✓ Branch 0 taken 69 times.
✓ Branch 1 taken 14125 times.
|
14194 | const f_freearg f = (f_freearg)( |
| 15 | 14194 | map_get(&gwion->data->freearg, instr->opcode) | |
| 16 | 14125 | ?: map_get(&gwion->data->freearg, (vtype)instr->execute)); | |
| 17 |
2/2✓ Branch 0 taken 131 times.
✓ Branch 1 taken 14063 times.
|
14194 | if (f) f(instr, gwion); |
| 18 | 14194 | mp_free(gwion->mp, Instr, instr); | |
| 19 | 14194 | } | |
| 20 | |||
| 21 | 730 | ANN void free_code_instr(const Vector v, const Gwion gwion) { | |
| 22 |
2/2✓ Branch 1 taken 14194 times.
✓ Branch 2 taken 730 times.
|
14924 | for (m_uint i = vector_size(v) + 1; --i;) { |
| 23 | 14194 | const Instr instr = (Instr)vector_at(v, i - 1); | |
| 24 | 14194 | free_instr(gwion, instr); | |
| 25 | } | ||
| 26 | 730 | } | |
| 27 | |||
| 28 | 82819 | ANN void free_vmcode(VM_Code a, Gwion gwion) { | |
| 29 |
2/2✓ Branch 0 taken 727 times.
✓ Branch 1 taken 82092 times.
|
82819 | if (!a->builtin) { |
| 30 | 727 | _mp_free(gwion->mp, vector_size(&a->instr) * BYTECODE_SZ, a->bytecode); | |
| 31 |
1/2✓ Branch 0 taken 727 times.
✗ Branch 1 not taken.
|
727 | if (likely(!a->callback)) { |
| 32 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 726 times.
|
727 | if(a->memoize) memoize_end(gwion->mp, a->memoize); |
| 33 | 727 | free_code_instr(&a->instr, gwion); | |
| 34 | } | ||
| 35 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 724 times.
|
727 | if (a->handlers.ptr) map_release(&a->handlers); |
| 36 |
2/2✓ Branch 0 taken 167 times.
✓ Branch 1 taken 560 times.
|
727 | if (a->live_values.ptr) m_vector_release(&a->live_values); |
| 37 | 727 | vector_release(&a->instr); | |
| 38 | } | ||
| 39 | 82819 | free_mstr(gwion->mp, a->name); | |
| 40 | 82819 | mp_free(gwion->mp, VM_Code, a); | |
| 41 | 82819 | } | |
| 42 | |||
| 43 | 2967 | static inline uint isgoto(const unsigned opcode) { | |
| 44 |
6/6✓ Branch 0 taken 2911 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2858 times.
✓ Branch 3 taken 53 times.
✓ Branch 4 taken 2842 times.
✓ Branch 5 taken 16 times.
|
2914 | return opcode == eGoto || opcode == eArrayTop || opcode == eBranchEqInt || |
| 45 |
4/4✓ Branch 0 taken 2841 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2840 times.
✓ Branch 3 taken 1 times.
|
2842 | opcode == eBranchNeqInt || opcode == eBranchEqFloat || |
| 46 |
4/4✓ Branch 0 taken 2837 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2835 times.
✓ Branch 3 taken 2 times.
|
2840 | opcode == eBranchNeqFloat || opcode == eHandleEffect || |
| 47 |
5/6✓ Branch 0 taken 2914 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 2835 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2833 times.
|
5881 | opcode == eRepeat || opcode == eRepeatIdx || opcode == eAutoLoop; |
| 48 | } | ||
| 49 | |||
| 50 | 17286 | ANN static inline void setpc(const m_bit *data, const m_uint i) { | |
| 51 | 17286 | *(m_uint *)(data + SZ_INT*3) = i + 1; | |
| 52 | 17286 | } | |
| 53 | |||
| 54 | 746 | ANN static m_bit *tobytecode(MemPool p, const VM_Code code) { | |
| 55 | 746 | const Vector v = &code->instr; | |
| 56 | 746 | const m_uint sz = vector_size(v); | |
| 57 | 746 | m_bit *const ptr = _mp_malloc(p, sz * BYTECODE_SZ); | |
| 58 | struct Vector_ nop; | ||
| 59 | 746 | vector_init(&nop); | |
| 60 |
2/2✓ Branch 0 taken 14341 times.
✓ Branch 1 taken 746 times.
|
15087 | for (m_uint i = 0; i < sz; ++i) { |
| 61 | 14341 | m_bit *const data = ptr + i * BYTECODE_SZ; | |
| 62 | 14341 | const Instr instr = (Instr)vector_at(v, i); | |
| 63 |
2/2✓ Branch 0 taken 14070 times.
✓ Branch 1 taken 271 times.
|
14341 | if (instr->opcode < eOP_MAX) { |
| 64 |
2/2✓ Branch 0 taken 1751 times.
✓ Branch 1 taken 12319 times.
|
14070 | if (instr->opcode == eRegMove) { |
| 65 | 1751 | m_int move = (m_int)instr->m_val; | |
| 66 | 1751 | m_uint j = 0; | |
| 67 | Instr next; | ||
| 68 |
1/2✓ Branch 1 taken 1787 times.
✗ Branch 2 not taken.
|
1787 | while ((next = (Instr)vector_at(v, i + j + 1)) && |
| 69 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1751 times.
|
1787 | next->opcode == eRegMove) { |
| 70 | 36 | ++j; | |
| 71 | 36 | vector_add(&nop, i + j); | |
| 72 | 36 | move += (m_int)next->m_val; | |
| 73 | 36 | next->opcode = eNoOp; | |
| 74 | } | ||
| 75 |
2/2✓ Branch 0 taken 1730 times.
✓ Branch 1 taken 21 times.
|
1751 | if ((instr->m_val = move)) { |
| 76 | // *(m_uint*)data = instr->opcode; | ||
| 77 | // memcpy(data, instr, SZ_INT); | ||
| 78 | // memcpy(data + SZ_INT*2, instr + SZ_INT, SZ_INT*2); | ||
| 79 | 1730 | memcpy(data, instr, BYTECODE_SZ); | |
| 80 | |||
| 81 | 1730 | setpc(data, i); | |
| 82 | } else { | ||
| 83 | 21 | vector_add(&nop, i); | |
| 84 | 21 | instr->opcode = eNoOp; | |
| 85 | } | ||
| 86 | 1751 | i += j; | |
| 87 | 1751 | continue; | |
| 88 |
2/2✓ Branch 0 taken 424 times.
✓ Branch 1 taken 11895 times.
|
12319 | } else if (instr->opcode == eRegPushMem) { |
| 89 | 424 | const Instr next = (Instr)vector_at(v, i+1); | |
| 90 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 389 times.
|
424 | if(next->opcode == eDotMember) { |
| 91 | 35 | instr->opcode = eDotMemberMem; | |
| 92 | 35 | instr->m_val2 = instr->m_val; | |
| 93 | 35 | instr->m_val = next->m_val; | |
| 94 | 35 | next->opcode = eNoOp; | |
| 95 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 383 times.
|
389 | } else if(next->opcode == eDotMember2) { |
| 96 | 6 | instr->opcode = eDotMemberMem2; | |
| 97 | 6 | instr->m_val2 = instr->m_val; | |
| 98 | 6 | instr->m_val = next->m_val; | |
| 99 | 6 | next->opcode = eNoOp; | |
| 100 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 372 times.
|
383 | } else if(next->opcode == eDotMember4) { |
| 101 | 11 | instr->opcode = eDotMemberMem4; | |
| 102 | 11 | instr->m_val2 = instr->m_val; | |
| 103 | 11 | instr->m_val = next->m_val; | |
| 104 | 11 | next->opcode = eNoOp; | |
| 105 | } | ||
| 106 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11894 times.
|
11895 | } else if (instr->opcode == eVM_IN) { |
| 107 | 1 | const Instr unroll = (Instr)instr->m_val; | |
| 108 | 1 | const m_uint pc = vector_find(v, (m_uint)unroll); | |
| 109 | 1 | m_uint reduce_pre = 0, reduce = 0; | |
| 110 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | for (m_uint j = 0; j < vector_size(&nop); ++j) { |
| 111 | ✗ | const m_uint at = vector_at(&nop, j); | |
| 112 | ✗ | if (at < pc) ++reduce_pre; | |
| 113 | ✗ | if (at >= pc) { | |
| 114 | ✗ | if (at > (pc + unroll->m_val2)) break; | |
| 115 | ✗ | ++reduce; | |
| 116 | } | ||
| 117 | } | ||
| 118 | 1 | m_bit *const unroll_data = ptr + (pc - reduce_pre) * BYTECODE_SZ; | |
| 119 | 1 | unroll->m_val2 -= reduce; | |
| 120 | 1 | *(m_uint *)(unroll_data + SZ_INT * 2) -= reduce; | |
| 121 | 1 | instr->opcode = eNoOp; | |
| 122 | 1 | vector_add(&nop, i); | |
| 123 | 1 | continue; | |
| 124 | } | ||
| 125 |
4/4✓ Branch 0 taken 195 times.
✓ Branch 1 taken 12123 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 109 times.
|
12318 | if (instr->opcode == eGoto && instr->m_val == i + 1) { |
| 126 | 86 | instr->opcode = eNoOp; | |
| 127 | 86 | vector_add(&nop, i); | |
| 128 |
2/2✓ Branch 0 taken 12164 times.
✓ Branch 1 taken 68 times.
|
12232 | } else if (instr->opcode != eNoOp) { |
| 129 | 12164 | memcpy(data, instr, BYTECODE_SZ); | |
| 130 | } else | ||
| 131 | 68 | vector_add(&nop, i); | |
| 132 | } else { | ||
| 133 | 271 | *(m_bit *)(data) = instr->opcode; | |
| 134 | 271 | *(Instr *)(data + SZ_INT) = instr; | |
| 135 | 271 | *(f_instr *)(data + SZ_INT * 2) = instr->execute; | |
| 136 | } | ||
| 137 | 12589 | setpc(data, i); | |
| 138 | } | ||
| 139 |
2/2✓ Branch 1 taken 598 times.
✓ Branch 2 taken 148 times.
|
746 | if (!vector_size(&nop)) { |
| 140 | 598 | vector_release(&nop); | |
| 141 | 598 | vm_prepare(NULL, ptr); | |
| 142 | 598 | return ptr; | |
| 143 | } | ||
| 144 | m_bit *const final = | ||
| 145 | 148 | _mp_malloc(p, sz * BYTECODE_SZ); // could use smaller size | |
| 146 |
2/2✓ Branch 0 taken 3179 times.
✓ Branch 1 taken 148 times.
|
3327 | for (m_uint i = 0, j = 0; i < sz; ++i) { |
| 147 | 3179 | const Instr instr = (Instr)vector_at(v, i); | |
| 148 | 3179 | const unsigned opcode = instr->opcode; | |
| 149 |
2/2✓ Branch 0 taken 2967 times.
✓ Branch 1 taken 212 times.
|
3179 | if (opcode != eNoOp) { |
| 150 | 2967 | m_bit *const base = ptr + i * BYTECODE_SZ, *const data = | |
| 151 | 2967 | final + j * BYTECODE_SZ; | |
| 152 | 2967 | memcpy(data, base, BYTECODE_SZ); | |
| 153 |
2/2✓ Branch 1 taken 134 times.
✓ Branch 2 taken 2833 times.
|
2967 | if (isgoto(opcode)) { |
| 154 | 134 | m_uint pc = 0; | |
| 155 |
2/2✓ Branch 1 taken 230 times.
✓ Branch 2 taken 72 times.
|
302 | for (pc = 0; pc < vector_size(&nop); ++pc) { |
| 156 |
2/2✓ Branch 1 taken 62 times.
✓ Branch 2 taken 168 times.
|
230 | if (instr->m_val <= vector_at(&nop, pc)) break; |
| 157 | } | ||
| 158 |
2/2✓ Branch 0 taken 131 times.
✓ Branch 1 taken 3 times.
|
134 | const m_uint new_pc = instr->m_val > pc ? instr->m_val - pc : 0; |
| 159 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 131 times.
|
134 | if (instr->opcode == eHandleEffect) { |
| 160 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (!code->handlers.ptr) map_init(&code->handlers); |
| 161 | 3 | map_set(&code->handlers, j, new_pc); | |
| 162 | } | ||
| 163 | 134 | *(m_uint *)(data + SZ_INT) = new_pc; | |
| 164 | 134 | instr->m_val = new_pc; | |
| 165 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2824 times.
|
2833 | } else if (opcode == eRecurs /*|| opcode == eSetCode*/) { |
| 166 | 9 | *(uint16_t *)(final + j * BYTECODE_SZ + SZ_INT * 2) = | |
| 167 | 9 | instr->udata.one += j + 1; | |
| 168 | } | ||
| 169 | 2967 | setpc(data, j); | |
| 170 | 2967 | ++j; | |
| 171 | } | ||
| 172 | } | ||
| 173 | 148 | vector_release(&nop); | |
| 174 | 148 | mp_free2(p, sz * BYTECODE_SZ, ptr); | |
| 175 | 148 | vm_prepare(NULL, final); | |
| 176 | 148 | return final; | |
| 177 | } | ||
| 178 | |||
| 179 | 94439 | VM_Code new_vmcode(MemPool p, const Vector instr, const M_Vector live_values, | |
| 180 | const m_str name, const uint16_t stack_depth, | ||
| 181 | const bool builtin, const bool dump) { | ||
| 182 | 94439 | VM_Code code = mp_calloc(p, VM_Code); | |
| 183 | 94439 | code->name = mstrdup(p, name); | |
| 184 |
2/2✓ Branch 0 taken 746 times.
✓ Branch 1 taken 93693 times.
|
94439 | if (instr) { |
| 185 | 746 | code->instr.ptr = instr->ptr; | |
| 186 | 746 | instr->ptr = NULL; | |
| 187 | 746 | code->bytecode = tobytecode(p, code); | |
| 188 | } | ||
| 189 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 94271 times.
|
94439 | if (live_values) code->live_values.ptr = live_values->ptr; |
| 190 | 94439 | code->stack_depth = stack_depth; | |
| 191 | 94439 | code->builtin = builtin; | |
| 192 | 94439 | code->ref = 1; | |
| 193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94439 times.
|
94439 | if (dump) dump_opcodes(code); |
| 194 | 94439 | return code; | |
| 195 | } | ||
| 196 | |||
| 197 | // TODO: handle native code | ||
| 198 | // TODO: do not re-create if code exists | ||
| 199 | ✗ | VM_Code vmcode_callback(MemPool mp, VM_Code base) { | |
| 200 | ✗ | char name[strlen(base->name) + 11]; | |
| 201 | ✗ | sprintf(name, "%s(callback)", base->name); | |
| 202 | ✗ | const Instr instr = (Instr)vector_back(&base->instr); | |
| 203 | ✗ | instr->opcode = eEOC; | |
| 204 | ✗ | const VM_Code code = new_vmcode(mp, &base->instr, &base->live_values, name, | |
| 205 | ✗ | base->stack_depth, base->builtin, false); | |
| 206 | ✗ | code->callback = 1; | |
| 207 | ✗ | instr->opcode = eFuncReturn; | |
| 208 | ✗ | return code; | |
| 209 | } | ||
| 210 |