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 |