Gwion coverage report


Directory: src/
File: src/vm/vm_code.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 139 154 90.3%
Functions: 7 8 87.5%
Branches: 86 98 87.8%

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