GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 "gwion.h" |
||
6 |
#include "instr.h" |
||
7 |
#include "emit.h" |
||
8 |
#include "object.h" |
||
9 |
#include "array.h" |
||
10 |
#include "traverse.h" |
||
11 |
#include "template.h" |
||
12 |
#include "escape.h" |
||
13 |
#include "parse.h" |
||
14 |
#include "memoize.h" |
||
15 |
#include "operator.h" |
||
16 |
#include "import.h" |
||
17 |
#include "match.h" |
||
18 |
#include "parser.h" |
||
19 |
#include "specialid.h" |
||
20 |
#include "vararg.h" |
||
21 |
|||
22 |
#undef insert_symbol |
||
23 |
#define insert_symbol(a) insert_symbol(emit->gwion->st, (a)) |
||
24 |
|||
25 |
#undef ERR_B |
||
26 |
#define ERR_B(a, b, ...) { env_err(emit->env, (a), (b), ## __VA_ARGS__); return GW_ERROR; } |
||
27 |
#undef ERR_O |
||
28 |
#define ERR_O(a, b, ...) { env_err(emit->env, (a), (b), ## __VA_ARGS__); return NULL; } |
||
29 |
|||
30 |
typedef struct Local_ { |
||
31 |
Type type; |
||
32 |
m_uint offset; |
||
33 |
} Local; |
||
34 |
|||
35 |
70 |
static inline void emit_pop(const Emitter emit, const m_uint scope) { env_pop(emit->env, scope); } |
|
36 |
53 |
static inline m_uint emit_push(const Emitter emit, const Type type, const Nspc nspc) { |
|
37 |
53 |
return env_push(emit->env, type, nspc); |
|
38 |
} |
||
39 |
10 |
static inline m_uint emit_push_type(const Emitter emit, const Type type) { |
|
40 |
10 |
return env_push_type(emit->env, type); |
|
41 |
} |
||
42 |
6 |
static inline m_uint emit_push_global(const Emitter emit) { |
|
43 |
6 |
return env_push_global(emit->env); |
|
44 |
} |
||
45 |
|||
46 |
813 |
ANEW static Frame* new_frame(MemPool p) { |
|
47 |
813 |
Frame* frame = mp_calloc(p, Frame); |
|
48 |
813 |
vector_init(&frame->stack); |
|
49 |
813 |
vector_add(&frame->stack, (vtype)NULL); |
|
50 |
813 |
return frame; |
|
51 |
} |
||
52 |
|||
53 |
813 |
ANN static void free_frame(MemPool p, Frame* a) { |
|
54 |
LOOP_OPTIM |
||
55 |
✓✓ | 2672 |
for(vtype i = vector_size(&a->stack) + 1; --i;) |
56 |
✓✓ | 1046 |
if(vector_at(&a->stack, i - 1)) |
57 |
233 |
mp_free(p, Local, (Local*)vector_at(&a->stack, i - 1)); |
|
58 |
813 |
vector_release(&a->stack); |
|
59 |
813 |
mp_free(p, Frame, a); |
|
60 |
813 |
} |
|
61 |
|||
62 |
1014 |
ANN static Local* new_local(MemPool p, const Type type) { |
|
63 |
1014 |
Local* local = mp_calloc(p, Local); |
|
64 |
1014 |
local->type = type; |
|
65 |
1014 |
return local; |
|
66 |
} |
||
67 |
|||
68 |
1014 |
ANN static m_uint frame_local(MemPool p, Frame* frame, const Type t) { |
|
69 |
1014 |
Local* local = new_local(p, t); |
|
70 |
1014 |
local->offset = frame->curr_offset; |
|
71 |
1014 |
frame->curr_offset += t->size; |
|
72 |
1014 |
vector_add(&frame->stack, (vtype)local); |
|
73 |
1014 |
return local->offset; |
|
74 |
} |
||
75 |
|||
76 |
1070 |
ANN static inline void frame_push(Frame* frame) { |
|
77 |
1070 |
vector_add(&frame->stack, (vtype)NULL); |
|
78 |
1070 |
} |
|
79 |
|||
80 |
9 |
ANN static void struct_pop(const Emitter emit, const Type type, const m_uint offset) { |
|
81 |
✓✓ | 25 |
for(m_uint i = 0; i < vector_size(&type->e->tuple->types); ++i) { |
82 |
16 |
const Type t = (Type)vector_at(&type->e->tuple->types, i); |
|
83 |
✓✓ | 16 |
if(isa(t, emit->gwion->type[et_object]) > 0) { |
84 |
1 |
const Instr instr = emit_add_instr(emit, ObjectRelease); |
|
85 |
1 |
instr->m_val = offset + vector_at(&type->e->tuple->offset, i); |
|
86 |
✗✓ | 15 |
} else if(GET_FLAG(t, struct)) |
87 |
struct_pop(emit, t, offset + vector_at(&type->e->tuple->offset, i)); |
||
88 |
} |
||
89 |
9 |
} |
|
90 |
|||
91 |
1851 |
ANN static m_int frame_pop(const Emitter emit) { |
|
92 |
1851 |
Frame *frame = emit->code->frame; |
|
93 |
✓✓ | 1851 |
DECL_OB(const Local*, l, = (Local*)vector_pop(&frame->stack)) |
94 |
781 |
frame->curr_offset -= l->type->size; |
|
95 |
✓✓ | 781 |
if(GET_FLAG(l->type, struct)) { |
96 |
9 |
struct_pop(emit, l->type, l->offset); |
|
97 |
9 |
return frame_pop(emit); |
|
98 |
} |
||
99 |
✓✓ | 772 |
return isa(l->type, emit->gwion->type[et_object]) > 0 ? (m_int)l->offset : frame_pop(emit); |
100 |
} |
||
101 |
|||
102 |
ANN /*static */m_bool emit_exp(const Emitter emit, Exp exp); |
||
103 |
ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop); |
||
104 |
ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List list); |
||
105 |
ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member); |
||
106 |
ANN static m_bool emit_func_def(const Emitter emit, const Func_Def func_def); |
||
107 |
|||
108 |
813 |
ANEW static Code* new_code(const Emitter emit, const m_str name) { |
|
109 |
813 |
Code* code = mp_calloc(emit->gwion->mp, Code); |
|
110 |
813 |
code->name = code_name_set(emit->gwion->mp, name, emit->env->name); |
|
111 |
813 |
vector_init(&code->instr); |
|
112 |
813 |
vector_init(&code->stack_break); |
|
113 |
813 |
vector_init(&code->stack_cont); |
|
114 |
813 |
vector_init(&code->stack_return); |
|
115 |
813 |
code->frame = new_frame(emit->gwion->mp); |
|
116 |
813 |
return code; |
|
117 |
} |
||
118 |
|||
119 |
813 |
ANN static void free_code(MemPool p, Code* code) { |
|
120 |
813 |
vector_release(&code->instr); |
|
121 |
813 |
vector_release(&code->stack_break); |
|
122 |
813 |
vector_release(&code->stack_cont); |
|
123 |
813 |
vector_release(&code->stack_return); |
|
124 |
813 |
free_frame(p, code->frame); |
|
125 |
813 |
free_mstr(p, code->name); |
|
126 |
813 |
mp_free(p, Code, code); |
|
127 |
813 |
} |
|
128 |
|||
129 |
1070 |
ANN static void emit_pop_scope(const Emitter emit) { |
|
130 |
m_int offset; |
||
131 |
✓✓ | 2386 |
while((offset = frame_pop(emit)) > -1) { |
132 |
246 |
Instr instr = emit_add_instr(emit, ObjectRelease); |
|
133 |
246 |
instr->m_val = (m_uint)offset; |
|
134 |
} |
||
135 |
1070 |
vector_pop(&emit->info->pure); |
|
136 |
1070 |
} |
|
137 |
|||
138 |
412 |
ANN static inline void emit_push_code(const Emitter emit, const m_str name) { |
|
139 |
412 |
vector_add(&emit->stack, (vtype)emit->code); |
|
140 |
412 |
emit->code = new_code(emit, name); |
|
141 |
412 |
} |
|
142 |
|||
143 |
ANN static inline void emit_pop_code(const Emitter emit) { |
||
144 |
emit->code = (Code*)vector_pop(&emit->stack); |
||
145 |
} |
||
146 |
|||
147 |
1070 |
ANN static inline void emit_push_scope(const Emitter emit) { |
|
148 |
1070 |
frame_push(emit->code->frame); |
|
149 |
1070 |
vector_add(&emit->info->pure, 0); |
|
150 |
1070 |
} |
|
151 |
|||
152 |
530 |
ANN static inline m_uint emit_code_size(const Emitter emit) { |
|
153 |
530 |
return vector_size(&emit->code->instr); |
|
154 |
} |
||
155 |
|||
156 |
1742 |
ANN m_uint emit_code_offset(const Emitter emit) { |
|
157 |
1742 |
return emit->code->frame->curr_offset; |
|
158 |
} |
||
159 |
|||
160 |
1014 |
ANN m_uint emit_local(const Emitter emit, const Type t) { |
|
161 |
1014 |
return frame_local(emit->gwion->mp, emit->code->frame, t); |
|
162 |
} |
||
163 |
|||
164 |
ANN void emit_ext_ctor(const Emitter emit, const Type t); |
||
165 |
|||
166 |
626 |
ANN static inline void maybe_ctor(const Emitter emit, const Type t) { |
|
167 |
✓✓✓✓ |
626 |
if(!GET_FLAG(t, nonnull) && GET_FLAG(t, ctor)) |
168 |
151 |
emit_ext_ctor(emit, t); |
|
169 |
626 |
} |
|
170 |
|||
171 |
626 |
ANN static void emit_pre_ctor(const Emitter emit, const Type type) { |
|
172 |
✓✓ | 626 |
if(type->e->parent) |
173 |
428 |
emit_pre_ctor(emit, type->e->parent); |
|
174 |
626 |
maybe_ctor(emit, type); |
|
175 |
✓✓✓✓ |
626 |
if(GET_FLAG(type, typedef) && type->e->parent->array_depth) |
176 |
8 |
emit_array_extend(emit, type->e->parent, type->e->def->base.ext->array->exp); |
|
177 |
626 |
} |
|
178 |
|||
179 |
#define regxxx(name, instr) \ |
||
180 |
ANN static inline Instr reg##name(const Emitter emit, const m_uint sz) { \ |
||
181 |
const Instr instr = emit_add_instr(emit, Reg##instr); \ |
||
182 |
instr->m_val = sz; \ |
||
183 |
return instr; \ |
||
184 |
} |
||
185 |
1896 |
regxxx(pop, Pop) |
|
186 |
27 |
regxxx(push, Push) |
|
187 |
1799 |
regxxx(pushi, PushImm) |
|
188 |
3051 |
regxxx(seti, SetImm) |
|
189 |
|||
190 |
12 |
ANN static void struct_expand(const Emitter emit, const Type t) { |
|
191 |
12 |
const Instr instr = emit_add_instr(emit, Reg2RegDeref); |
|
192 |
12 |
instr->m_val = -SZ_INT; |
|
193 |
12 |
instr->m_val2 = t->size; |
|
194 |
// regpush(emit, t->size - SZ_INT); |
||
195 |
12 |
} |
|
196 |
|||
197 |
|||
198 |
INSTR(ArrayStruct); |
||
199 |
|||
200 |
12 |
ANN static void emit_pre_constructor_array(const Emitter emit, const Type type) { |
|
201 |
12 |
const m_uint start_index = emit_code_size(emit); |
|
202 |
12 |
const Instr top = emit_add_instr(emit, ArrayTop); |
|
203 |
12 |
top->m_val2 = (m_uint)type; |
|
204 |
✗✓ | 12 |
if(GET_FLAG(type, struct)) { |
205 |
const Instr instr = emit_add_instr(emit, ArrayStruct); |
||
206 |
instr->m_val = type->size; |
||
207 |
} |
||
208 |
12 |
emit_pre_ctor(emit, type); |
|
209 |
✓✗ | 12 |
if(!GET_FLAG(type, struct)) |
210 |
12 |
emit_add_instr(emit, ArrayBottom); |
|
211 |
else |
||
212 |
regpop(emit, SZ_INT); |
||
213 |
12 |
regpop(emit, SZ_INT); |
|
214 |
12 |
const Instr pc = emit_add_instr(emit, Goto); |
|
215 |
12 |
pc->m_val = start_index; |
|
216 |
12 |
top->m_val = emit_code_size(emit); |
|
217 |
12 |
regpop(emit, SZ_INT*3); |
|
218 |
12 |
emit_add_instr(emit, ArrayPost); |
|
219 |
12 |
} |
|
220 |
|||
221 |
41 |
ANN2(1) static m_bool extend_indices(const Emitter emit, Exp e, const m_uint depth) { |
|
222 |
✓✓ | 41 |
if(e) |
223 |
✗✓ | 37 |
CHECK_BB(emit_exp(emit, e)) |
224 |
41 |
m_uint count = 0; |
|
225 |
✓✓ | 140 |
while(e) { |
226 |
58 |
++count; |
|
227 |
58 |
e = e->next; |
|
228 |
} |
||
229 |
✓✓ | 47 |
for(m_uint i = count; i < depth; ++i) |
230 |
6 |
regpushi(emit, 0); |
|
231 |
41 |
return GW_OK; |
|
232 |
} |
||
233 |
|||
234 |
41 |
ANEW ANN static ArrayInfo* new_arrayinfo(const Emitter emit, const Type t) { |
|
235 |
41 |
const Type base = array_base(t); |
|
236 |
41 |
ArrayInfo* info = mp_calloc(emit->gwion->mp, ArrayInfo); |
|
237 |
41 |
vector_init(&info->type); |
|
238 |
✓✓ | 64 |
for(m_uint i = 1; i < t->array_depth; ++i) |
239 |
23 |
vector_add(&info->type, (vtype)array_type(emit->env, base, i)); |
|
240 |
41 |
vector_add(&info->type, (vtype)t); |
|
241 |
41 |
info->depth = (m_int)t->array_depth; |
|
242 |
41 |
info->base = base; |
|
243 |
41 |
return info; |
|
244 |
} |
||
245 |
|||
246 |
41 |
ANN static inline void arrayinfo_ctor(const Emitter emit, ArrayInfo *info) { |
|
247 |
41 |
const Type base = info->base; |
|
248 |
✓✓✓✗ |
41 |
if(isa(base, emit->gwion->type[et_compound]) > 0 && !GET_FLAG(base, abstract)) { |
249 |
12 |
emit_pre_constructor_array(emit, base); |
|
250 |
// if(isa(base, emit->gwion->type[et_object]) > 0) |
||
251 |
12 |
info->is_obj = 1; |
|
252 |
} |
||
253 |
41 |
} |
|
254 |
|||
255 |
41 |
ANN2(1,2) static ArrayInfo* emit_array_extend_inner(const Emitter emit, const Type t, const Exp e) { |
|
256 |
✗✓ | 41 |
CHECK_BO(extend_indices(emit, e, t->array_depth)) |
257 |
41 |
ArrayInfo* info = new_arrayinfo(emit, t); |
|
258 |
41 |
const Instr alloc = emit_add_instr(emit, ArrayAlloc); |
|
259 |
41 |
alloc->m_val = (m_uint)info; |
|
260 |
41 |
arrayinfo_ctor(emit, info); |
|
261 |
41 |
return info; |
|
262 |
} |
||
263 |
|||
264 |
163 |
ANN void emit_ext_ctor(const Emitter emit, const Type t) { |
|
265 |
163 |
const Instr cpy = emit_add_instr(emit, Reg2Reg); |
|
266 |
163 |
cpy->m_val2 = -SZ_INT; |
|
267 |
✓✓ | 163 |
if(t->nspc->pre_ctor) { |
268 |
161 |
const Instr set_code = regseti(emit, (m_uint)t->nspc->pre_ctor); |
|
269 |
161 |
set_code->m_val2 = SZ_INT; |
|
270 |
} else { |
||
271 |
2 |
const Instr instr = emit_add_instr(emit, SetCtor); |
|
272 |
2 |
instr->m_val = (m_uint)t; |
|
273 |
} |
||
274 |
163 |
const m_uint offset = emit_code_offset(emit); |
|
275 |
163 |
const Instr regset = regseti(emit, offset); |
|
276 |
163 |
regset->m_val2 = SZ_INT *2; |
|
277 |
163 |
const Instr push = emit_add_instr(emit, RegPush); |
|
278 |
163 |
push->m_val = SZ_INT *2; |
|
279 |
163 |
const Instr prelude = emit_add_instr(emit, SetCode); |
|
280 |
163 |
prelude->m_val2 = 2; |
|
281 |
163 |
prelude->m_val = SZ_INT; |
|
282 |
163 |
emit_add_instr(emit, Reg2Mem); |
|
283 |
163 |
const Instr next = emit_add_instr(emit, Overflow); |
|
284 |
163 |
next->m_val2 = offset; |
|
285 |
163 |
} |
|
286 |
|||
287 |
8 |
ANN m_bool emit_array_extend(const Emitter emit, const Type t, const Exp e) { |
|
288 |
✗✓ | 8 |
CHECK_OB(emit_array_extend_inner(emit, t, e)) |
289 |
8 |
emit_add_instr(emit, PopArrayClass); |
|
290 |
8 |
emit_add_instr(emit, RegAddRef); |
|
291 |
8 |
return GW_OK; |
|
292 |
} |
||
293 |
|||
294 |
231 |
ANN static inline void emit_notpure(const Emitter emit) { |
|
295 |
231 |
++VPTR(&emit->info->pure, VLEN(&emit->info->pure) - 1); |
|
296 |
231 |
} |
|
297 |
|||
298 |
219 |
ANN2(1,2) m_bool emit_instantiate_object(const Emitter emit, const Type type, |
|
299 |
const Array_Sub array, const m_bool is_ref) { |
||
300 |
219 |
emit_notpure(emit); |
|
301 |
✓✓ | 219 |
if(type->array_depth) { |
302 |
✓✓ | 33 |
ArrayInfo* info = emit_array_extend_inner(emit, type, array ? array->exp : NULL); |
303 |
✓✗ | 33 |
if(info) |
304 |
33 |
info->is_ref = is_ref; |
|
305 |
✓✗ | 33 |
return info ? GW_OK : GW_ERROR; |
306 |
✓✗ | 186 |
} else if(!is_ref) { |
307 |
186 |
const Instr instr = emit_add_instr(emit, ObjectInstantiate); |
|
308 |
186 |
instr->m_val2 = (m_uint)type; |
|
309 |
186 |
emit_pre_ctor(emit, type); |
|
310 |
} |
||
311 |
186 |
return GW_OK; |
|
312 |
} |
||
313 |
|||
314 |
2168 |
static inline enum Kind kindof(const m_uint size, const uint emit_var) { |
|
315 |
✓✓ | 2168 |
if(emit_var) |
316 |
470 |
return KIND_ADDR; |
|
317 |
✓✓✓✓ |
1698 |
return size == SZ_INT ? KIND_INT : size == SZ_FLOAT ? KIND_FLOAT : KIND_OTHER; |
318 |
} |
||
319 |
|||
320 |
2168 |
ANN /*static */Instr emit_kind(Emitter emit, const m_uint size, const uint addr, const f_instr func[]) { |
|
321 |
2168 |
const enum Kind kind = kindof(size, addr); |
|
322 |
2168 |
const Instr instr = emit_add_instr(emit, func[kind]); |
|
323 |
2168 |
instr->m_val2 = size; |
|
324 |
2168 |
return instr; |
|
325 |
} |
||
326 |
|||
327 |
static const f_instr regpushimm[] = { RegPushImm, RegPushImm2, RegPushImm3, RegPushImm4 }; |
||
328 |
static const f_instr regpushmem[] = { RegPushMem, RegPushMem2, RegPushMem3, RegPushMem4 }; |
||
329 |
static const f_instr regpushbase[] = { RegPushBase, RegPushBase2, RegPushBase3, RegPushBase4 }; |
||
330 |
static const f_instr dotstatic[] = { DotStatic, DotStatic2, DotStatic3, RegPushImm }; |
||
331 |
static const f_instr allocmember[] = { RegPushImm, RegPushImm2, RegPushImm3, AllocMember4 }; |
||
332 |
static const f_instr allocword[] = { AllocWord, AllocWord2, AllocWord3, RegPushMem4 }; |
||
333 |
static const f_instr structmember[] = { StructMember, StructMemberFloat, StructMemberOther, StructMemberAddr }; |
||
334 |
|||
335 |
ANN Exp symbol_owned_exp(const Gwion gwion, const Symbol *data); |
||
336 |
142 |
ANN static m_bool emit_symbol_owned(const Emitter emit, const Symbol *data) { |
|
337 |
142 |
const Exp dot = symbol_owned_exp(emit->gwion, data); |
|
338 |
142 |
dot->info->nspc = prim_exp(data)->info->nspc; |
|
339 |
142 |
const m_bool ret = emit_exp_dot(emit, &dot->d.exp_dot); |
|
340 |
142 |
free_exp(emit->gwion->mp, dot); |
|
341 |
142 |
return ret; |
|
342 |
} |
||
343 |
|||
344 |
164 |
ANN static m_bool emit_symbol_builtin(const Emitter emit, const Symbol *data) { |
|
345 |
164 |
const Value v = prim_self(data)->value; |
|
346 |
✓✓ | 164 |
if(GET_FLAG(v, union)) { |
347 |
7 |
const m_uint size = v->type->size; |
|
348 |
7 |
const Instr instr = emit_kind(emit, size, exp_getvar(prim_exp(data)), dotstatic); |
|
349 |
7 |
instr->m_val = (m_uint)v->d.ptr; |
|
350 |
} else { |
||
351 |
157 |
const m_uint size = v->type->size; |
|
352 |
157 |
const Instr instr = emit_kind(emit, size, exp_getvar(prim_exp(data)), regpushimm); |
|
353 |
✓✓✓✓ |
157 |
if(!exp_getvar(prim_exp(data)) && size == SZ_INT) { |
354 |
✓✓ | 160 |
if(isa(v->type, emit->gwion->type[et_object]) > 0) |
355 |
46 |
instr->m_val = (m_uint)v->d.ptr; |
|
356 |
✓✗ | 34 |
else if(v->d.ptr) |
357 |
34 |
instr->m_val = *(m_uint*)v->d.ptr; |
|
358 |
} else { |
||
359 |
assert(v->d.ptr); // instr->m_val = v->d.ptr; |
||
360 |
77 |
memcpy(&instr->m_val, v->d.ptr, v->type->size); |
|
361 |
} |
||
362 |
157 |
instr->m_val2 = size; |
|
363 |
} |
||
364 |
164 |
return GW_OK; |
|
365 |
} |
||
366 |
|||
367 |
1383 |
ANN static m_bool _emit_symbol(const Emitter emit, const Symbol *data) { |
|
368 |
1383 |
const Value v = prim_self(data)->value; |
|
369 |
✓✓ | 1383 |
if(is_class(emit->gwion, v->type)) { |
370 |
11 |
regpushi(emit, (m_uint)actual_type(emit->gwion, v->type)); |
|
371 |
11 |
return GW_OK; |
|
372 |
} |
||
373 |
✓✓ | 1372 |
if(v->from->owner_class) |
374 |
142 |
return emit_symbol_owned(emit, data); |
|
375 |
✓✓✓✓ ✓✓ |
1230 |
if(GET_FLAG(v, builtin) || GET_FLAG(v, union) || GET_FLAG(v, enum)) |
376 |
164 |
return emit_symbol_builtin(emit, data); |
|
377 |
1066 |
const m_uint size = v->type->size; |
|
378 |
✓✓ | 1066 |
const Instr instr = emit_kind(emit, size, exp_getvar(prim_exp(data)), !GET_FLAG(v, global) ? regpushmem : regpushbase); |
379 |
1066 |
instr->m_val = v->from->offset; |
|
380 |
1066 |
return GW_OK; |
|
381 |
} |
||
382 |
|||
383 |
1383 |
ANN static m_bool emit_symbol(const Emitter emit, const Exp_Primary* prim) { |
|
384 |
1383 |
return _emit_symbol(emit, &prim->d.var); |
|
385 |
} |
||
386 |
|||
387 |
809 |
ANN static VM_Code finalyze(const Emitter emit, const f_instr exec) { |
|
388 |
809 |
emit_add_instr(emit, exec); |
|
389 |
809 |
const VM_Code code = emit->info->emit_code(emit); |
|
390 |
809 |
free_code(emit->gwion->mp, emit->code); |
|
391 |
809 |
emit->code = (Code*)vector_pop(&emit->stack); |
|
392 |
809 |
return code; |
|
393 |
} |
||
394 |
|||
395 |
12 |
ANN static m_bool emit_prim_array(const Emitter emit, const Array_Sub *data) { |
|
396 |
12 |
Exp e = (*data)->exp; |
|
397 |
✗✓ | 12 |
CHECK_BB(emit_exp(emit, e)) |
398 |
12 |
m_uint count = 0; |
|
399 |
39 |
do ++count; |
|
400 |
✓✓ | 39 |
while((e = e->next)); |
401 |
12 |
const Type type = (*data)->type; |
|
402 |
12 |
regseti(emit, count); |
|
403 |
12 |
const Instr instr = emit_add_instr(emit, ArrayInit); |
|
404 |
12 |
instr->m_val = (m_uint)type; |
|
405 |
✓✓ | 12 |
instr->m_val2 = type->array_depth == 1 ? array_base(type)->size : SZ_INT; |
406 |
12 |
emit_add_instr(emit, GcAdd); |
|
407 |
12 |
emit_notpure(emit); |
|
408 |
12 |
return GW_OK; |
|
409 |
} |
||
410 |
|||
411 |
ANN static inline m_bool emit_exp_pop_next(const Emitter emit, Exp e); |
||
412 |
|||
413 |
9 |
ANN static m_bool emit_range(const Emitter emit, Range *range) { |
|
414 |
✓✓ | 9 |
if(range->start) |
415 |
✗✓ | 8 |
CHECK_BB(emit_exp_pop_next(emit, range->start)) |
416 |
else |
||
417 |
1 |
regpushi(emit, 0); |
|
418 |
✓✓ | 9 |
if(range->end) |
419 |
✗✓ | 7 |
CHECK_BB(emit_exp_pop_next(emit, range->end)) |
420 |
else |
||
421 |
2 |
regpushi(emit, -1); |
|
422 |
9 |
return GW_OK; |
|
423 |
} |
||
424 |
|||
425 |
2 |
ANN static m_bool emit_prim_range(const Emitter emit, Range **data) { |
|
426 |
2 |
Range *range = *data; |
|
427 |
✗✓ | 2 |
CHECK_BB(emit_range(emit, range)) |
428 |
✓✗ | 2 |
const Exp e = range->start ?: range->end; |
429 |
2 |
const Symbol sym = insert_symbol("@range"); |
|
430 |
6 |
struct Op_Import opi = { .op=sym, .rhs=e->info->type, |
|
431 |
4 |
.pos=e->pos, .data=(uintptr_t)prim_exp(data), .op_type=op_exp }; |
|
432 |
✗✓ | 2 |
CHECK_OB(op_emit(emit, &opi)) |
433 |
2 |
emit_add_instr(emit, GcAdd); |
|
434 |
2 |
return GW_OK; |
|
435 |
} |
||
436 |
|||
437 |
25 |
ANN m_bool emit_array_access(const Emitter emit, struct ArrayAccessInfo *const info) { |
|
438 |
✗✓ | 25 |
if(GET_FLAG(info->array.type, typedef)) { |
439 |
info->array.type = info->array.type->e->parent; |
||
440 |
return emit_array_access(emit, info); |
||
441 |
} |
||
442 |
// look mum no pos |
||
443 |
50 |
struct Op_Import opi = { .op=insert_symbol("@array"), .lhs=info->array.exp->info->type, .rhs=info->array.type, |
|
444 |
25 |
.data=(uintptr_t)info, .op_type=op_array }; |
|
445 |
✓✗ | 25 |
return op_emit(emit, &opi) != (Instr)GW_ERROR ? GW_OK : GW_ERROR; |
446 |
} |
||
447 |
|||
448 |
25 |
ANN static m_bool emit_exp_array(const Emitter emit, const Exp_Array* array) { |
|
449 |
✗✓ | 25 |
CHECK_BB(emit_exp(emit, array->base)) |
450 |
25 |
const Exp e = exp_self(array); |
|
451 |
25 |
struct ArrayAccessInfo info = { *array->array, e->info->type, exp_getvar(e) }; |
|
452 |
25 |
return emit_array_access(emit, &info); |
|
453 |
} |
||
454 |
|||
455 |
7 |
ANN static m_bool emit_exp_slice(const Emitter emit, const Exp_Slice* range) { |
|
456 |
✗✓ | 7 |
CHECK_BB(emit_exp(emit, range->base)) |
457 |
✗✓ | 7 |
CHECK_BB(emit_range(emit, range->range)) |
458 |
7 |
const Symbol sym = insert_symbol("@slice"); |
|
459 |
✓✓ | 7 |
const Exp e = range->range->start ?: range->range->end; |
460 |
21 |
struct Op_Import opi = { .op=sym, .lhs=e->info->type, .rhs=range->base->info->type, |
|
461 |
14 |
.pos=e->pos, .data=(uintptr_t)exp_self(range), .op_type=op_exp }; |
|
462 |
✗✓ | 7 |
CHECK_OB(op_emit(emit, &opi)) |
463 |
7 |
return GW_OK; |
|
464 |
} |
||
465 |
|||
466 |
1739 |
ANN static m_bool emit_prim_id(const Emitter emit, const Symbol *data) { |
|
467 |
1739 |
struct SpecialId_ * spid = specialid_get(emit->gwion, *data); |
|
468 |
✓✓ | 1739 |
if(spid) |
469 |
✓✗ | 356 |
return specialid_instr(emit, spid, prim_self(data)) ? GW_OK : GW_ERROR; |
470 |
1383 |
return emit_symbol(emit, prim_self(data)); |
|
471 |
} |
||
472 |
|||
473 |
537 |
ANN static m_bool emit_prim_num(const Emitter emit, const m_uint *num) { |
|
474 |
537 |
regpushi(emit, *num); |
|
475 |
537 |
return GW_OK; |
|
476 |
} |
||
477 |
|||
478 |
118 |
ANN static m_bool emit_prim_float(const Emitter emit, const m_float *fnum) { |
|
479 |
118 |
const Instr instr = emit_add_instr(emit, RegPushImm2); |
|
480 |
118 |
instr->f = *fnum; |
|
481 |
118 |
return GW_OK; |
|
482 |
} |
||
483 |
|||
484 |
15 |
ANN static m_bool emit_prim_char(const Emitter emit, const m_str *str) { |
|
485 |
15 |
const char c = str2char(emit, *str, prim_pos(str)); |
|
486 |
15 |
regpushi(emit, c); |
|
487 |
15 |
return GW_OK; |
|
488 |
} |
||
489 |
|||
490 |
523 |
ANN static Instr emit_addref(const Emitter emit, const m_bool emit_var) { |
|
491 |
✓✓ | 523 |
const f_instr exec = !emit_var ? RegAddRef : RegAddRefAddr; |
492 |
523 |
const Instr instr = emit_add_instr(emit, exec); |
|
493 |
523 |
instr->m_val = -SZ_INT; |
|
494 |
523 |
return instr; |
|
495 |
} |
||
496 |
|||
497 |
302 |
ANN static m_bool emit_prim_str(const Emitter emit, const m_str *str) { |
|
498 |
302 |
char c[strlen(*str) + 1]; |
|
499 |
✓✓ | 302 |
if(strlen(*str)) { |
500 |
296 |
strcpy(c, *str); |
|
501 |
✓✓ | 296 |
CHECK_BB(escape_str(emit, c, prim_pos(str))); |
502 |
6 |
} else c[0] = '\0'; |
|
503 |
300 |
const Value v = prim_self(str)->value; |
|
504 |
300 |
const Symbol sym = insert_symbol(c); |
|
505 |
✓✓ | 300 |
if(!v->d.ptr) |
506 |
240 |
v->d.ptr = (m_uint*)new_string2(emit->gwion, NULL, s_name(sym)); |
|
507 |
300 |
regpushi(emit, (m_uint)v->d.ptr); |
|
508 |
300 |
emit_addref(emit, 0); |
|
509 |
300 |
return GW_OK; |
|
510 |
} |
||
511 |
|||
512 |
#define emit_prim_nil (void*)dummy_func |
||
513 |
|||
514 |
23 |
ANN static m_bool emit_prim_typeof(const Emitter emit, const Exp *exp) { |
|
515 |
23 |
const Exp e = *exp; |
|
516 |
✓✓ | 23 |
if(!e->info->type->array_depth) |
517 |
22 |
regpushi(emit, (m_uint)(actual_type(emit->gwion, e->info->type))); |
|
518 |
else |
||
519 |
1 |
regpushi(emit, (m_uint)e->info->type); |
|
520 |
23 |
return GW_OK; |
|
521 |
} |
||
522 |
|||
523 |
23 |
ANN static void interp_multi(const Emitter emit, const Exp e) { |
|
524 |
23 |
Var_Decl_List list = e->d.exp_decl.list; |
|
525 |
23 |
const int emit_var = exp_getvar(e); |
|
526 |
23 |
m_uint offset = 0; |
|
527 |
✗✓ | 46 |
while((list = list->next)) |
528 |
offset += !emit_var ? list->self->value->type->size : SZ_INT; |
||
529 |
✗✓ | 23 |
if(offset) |
530 |
regpop(emit, offset); |
||
531 |
23 |
} |
|
532 |
|||
533 |
1136 |
ANN static inline void interp_size(const Emitter emit, const Type t) { |
|
534 |
1136 |
const Instr instr = regseti(emit, t->size); |
|
535 |
1136 |
instr->m_val2 = SZ_INT; |
|
536 |
1136 |
} |
|
537 |
|||
538 |
880 |
ANN static m_bool emit_interp(const Emitter emit, const Exp exp) { |
|
539 |
880 |
regpushi(emit, 0); |
|
540 |
880 |
Exp e = exp, next = NULL; |
|
541 |
do { |
||
542 |
1138 |
next = e->next; |
|
543 |
1138 |
e->next = NULL; |
|
544 |
✓✓ | 1138 |
if(emit_exp(emit, e) < 0) { |
545 |
2 |
e->next = next; |
|
546 |
2 |
return GW_ERROR; |
|
547 |
} |
||
548 |
✓✓ | 1136 |
if(e->exp_type == ae_exp_decl) // why only objects? |
549 |
23 |
interp_multi(emit, e); |
|
550 |
1136 |
regseti(emit, (m_uint)e->info->type); |
|
551 |
1136 |
interp_size(emit, e->info->type); |
|
552 |
1136 |
const m_bool isobj = isa(e->info->type, emit->gwion->type[et_object]) > 0; |
|
553 |
✓✓✓✓ |
1136 |
if(isobj && !GET_FLAG(e->info->type, force)) |
554 |
485 |
emit_add_instr(emit, GackType); |
|
555 |
1136 |
const Instr instr = emit_add_instr(emit, Gack); |
|
556 |
1136 |
instr->m_val = emit_code_offset(emit); |
|
557 |
✓✓ | 1136 |
} while((e = e->next = next)); |
558 |
878 |
return GW_OK; |
|
559 |
} |
||
560 |
|||
561 |
875 |
ANN static m_bool emit_prim_hack(const Emitter emit, const Exp *exp) { |
|
562 |
✓✓ | 875 |
CHECK_BB(emit_interp(emit, *exp)) |
563 |
✓✓✓✓ |
873 |
if(!(emit->env->func && emit->env->func->def->base->xid == insert_symbol("@gack"))) |
564 |
871 |
emit_add_instr(emit, GackEnd); |
|
565 |
else { |
||
566 |
2 |
const Instr instr = emit_add_instr(emit, Reg2Mem); |
|
567 |
2 |
instr->m_val = SZ_INT; |
|
568 |
2 |
instr->m_val2 = -SZ_INT; |
|
569 |
} |
||
570 |
873 |
return GW_OK; |
|
571 |
} |
||
572 |
|||
573 |
5 |
ANN static m_bool emit_prim_interp(const Emitter emit, const Exp *exp) { |
|
574 |
5 |
const Exp e = *exp; |
|
575 |
✗✓ | 5 |
CHECK_BB(emit_interp(emit, e)) |
576 |
5 |
const Instr instr = emit_add_instr(emit, GackEnd); |
|
577 |
5 |
instr->m_val = 1; |
|
578 |
5 |
return GW_OK; |
|
579 |
} |
||
580 |
|||
581 |
DECL_PRIM_FUNC(emit, m_bool , Emitter); |
||
582 |
3635 |
ANN static m_bool emit_prim(const Emitter emit, Exp_Primary *const prim) { |
|
583 |
3635 |
return emit_prim_func[prim->prim_type](emit, &prim->d); |
|
584 |
} |
||
585 |
|||
586 |
19 |
ANN static m_bool emit_dot_static_data(const Emitter emit, const Value v, const uint emit_var) { |
|
587 |
19 |
const m_uint size = v->type->size; |
|
588 |
19 |
const Instr instr = emit_kind(emit, size, emit_var, dotstatic); |
|
589 |
19 |
instr->m_val = (m_uint)(v->from->owner->info->class_data + v->from->offset); |
|
590 |
19 |
instr->m_val2 = size; |
|
591 |
19 |
return GW_OK; |
|
592 |
} |
||
593 |
|||
594 |
5 |
ANN static m_bool decl_static(const Emitter emit, const Var_Decl var_decl, const uint is_ref) { |
|
595 |
5 |
const Value v = var_decl->value; |
|
596 |
5 |
Code* code = emit->code; |
|
597 |
5 |
emit->code = (Code*)vector_back(&emit->stack); |
|
598 |
✗✓ | 5 |
CHECK_BB(emit_instantiate_object(emit, v->type, var_decl->array, is_ref)) |
599 |
✗✓ | 5 |
CHECK_BB(emit_dot_static_data(emit, v, 1)) |
600 |
5 |
emit_add_instr(emit, Assign); |
|
601 |
5 |
(void)emit_addref(emit, 0); |
|
602 |
5 |
regpop(emit, SZ_INT); |
|
603 |
5 |
emit->code = code; |
|
604 |
5 |
return GW_OK; |
|
605 |
} |
||
606 |
|||
607 |
1057 |
ANN static inline int struct_ctor(const Value v) { |
|
608 |
✓✓✓✗ |
1057 |
return GET_FLAG(v->type, struct) && v->type->nspc->pre_ctor; |
609 |
} |
||
610 |
|||
611 |
12 |
ANN static void decl_expand(const Emitter emit, const Type t) { |
|
612 |
12 |
struct_expand(emit, t); |
|
613 |
12 |
regpush(emit, t->size - SZ_INT); |
|
614 |
12 |
} |
|
615 |
|||
616 |
12 |
ANN static void emit_struct_decl_finish(const Emitter emit, const Type t, const uint emit_addr) { |
|
617 |
12 |
emit->code->frame->curr_offset += t->size + SZ_INT; |
|
618 |
12 |
emit_ext_ctor(emit, t); |
|
619 |
✓✗ | 12 |
if(!emit_addr) |
620 |
12 |
decl_expand(emit, t); |
|
621 |
12 |
emit->code->frame->curr_offset -= t->size + SZ_INT; |
|
622 |
12 |
} |
|
623 |
|||
624 |
14 |
ANN static m_bool emit_exp_decl_static(const Emitter emit, const Var_Decl var_decl, const uint is_ref, const uint emit_addr) { |
|
625 |
14 |
const Value v = var_decl->value; |
|
626 |
✓✓✓✗ |
14 |
if(isa(v->type, emit->gwion->type[et_object]) > 0 && !is_ref) |
627 |
✗✓ | 5 |
CHECK_BB(decl_static(emit, var_decl, 0)) |
628 |
✓✓✗✓ |
14 |
CHECK_BB(emit_dot_static_data(emit, v, !struct_ctor(v) ? emit_addr : 1)) |
629 |
✓✓ | 14 |
if(struct_ctor(v) /* && !GET_FLAG(decl->td, ref) */) |
630 |
1 |
emit_struct_decl_finish(emit, v->type, emit_addr); |
|
631 |
14 |
return GW_OK; |
|
632 |
} |
||
633 |
|||
634 |
26 |
ANN static Instr emit_struct_decl(const Emitter emit, const Value v, const m_bool emit_addr) { |
|
635 |
26 |
emit_add_instr(emit, RegPushMem); |
|
636 |
26 |
const Instr instr = emit_kind(emit, v->type->size, emit_addr, structmember); |
|
637 |
✓✓ | 26 |
if(!emit_addr) |
638 |
15 |
regpush(emit, v->type->size - SZ_INT); |
|
639 |
26 |
return instr; |
|
640 |
} |
||
641 |
|||
642 |
606 |
ANN static m_bool emit_exp_decl_non_static(const Emitter emit, const Exp_Decl *decl, const Var_Decl var_decl, |
|
643 |
const uint is_ref, const uint emit_var) { |
||
644 |
606 |
const Value v = var_decl->value; |
|
645 |
606 |
const Type type = v->type; |
|
646 |
606 |
const Array_Sub array = var_decl->array; |
|
647 |
✓✓✓✓ |
606 |
const m_bool is_array = (array && array->exp) /*|| GET_FLAG(decl->td, force)*/; |
648 |
606 |
const m_bool is_obj = isa(type, emit->gwion->type[et_object]) > 0; |
|
649 |
✓✓✓✓ ✓✗ |
606 |
const uint emit_addr = (!is_obj || (is_ref && !is_array)) ? emit_var : 1; |
650 |
✓✓✓✓ ✓✓✓✗ |
606 |
if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) |
651 |
✗✓ | 193 |
CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) |
652 |
606 |
f_instr *exec = (f_instr*)allocmember; |
|
653 |
✓✓ | 606 |
if(!GET_FLAG(v, member)) { |
654 |
487 |
v->from->offset = emit_local(emit, type); |
|
655 |
487 |
exec = (f_instr*)(allocword); |
|
656 |
✓✓ | 487 |
if(GET_FLAG(v, ref)) { // ref or emit_var ? |
657 |
46 |
const Instr clean = emit_add_instr(emit, MemSetImm); |
|
658 |
46 |
clean->m_val = v->from->offset; |
|
659 |
} |
||
660 |
} |
||
661 |
✓✓✗✓ |
1338 |
const Instr instr = !(SAFE_FLAG(emit->env->class_def, struct) && !emit->env->scope->depth) ? |
662 |
✓✓✓✓ ✓✗ |
1186 |
emit_kind(emit, v->type->size, !struct_ctor(v) ? emit_addr : 1, exec) : emit_struct_decl(emit, v, !struct_ctor(v) ? emit_addr : 1); |
663 |
606 |
instr->m_val = v->from->offset; |
|
664 |
✓✓✓✓ ✓✓✓✗ |
799 |
if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) { |
665 |
✓✗ | 193 |
if(!emit_var) |
666 |
193 |
emit_add_instr(emit, Assign); |
|
667 |
else { |
||
668 |
regpop(emit, SZ_INT); |
||
669 |
const Instr instr = emit_add_instr(emit, Reg2Reg); |
||
670 |
instr->m_val = -SZ_INT; |
||
671 |
} |
||
672 |
✓✓ | 193 |
const size_t missing_depth = type->array_depth - (array ? array->depth : 0); |
673 |
✓✓✓✓ |
193 |
if(missing_depth && !GET_FLAG(decl->td, force)) { |
674 |
2 |
const Instr push = emit_add_instr(emit, Reg2Reg); |
|
675 |
2 |
push->m_val = -(missing_depth) * SZ_INT; |
|
676 |
} |
||
677 |
✓✓ | 413 |
} else if(struct_ctor(v) /* && !GET_FLAG(decl->td, ref) */) |
678 |
10 |
emit_struct_decl_finish(emit, v->type, emit_addr); |
|
679 |
606 |
return GW_OK; |
|
680 |
} |
||
681 |
|||
682 |
6 |
ANN static m_bool emit_exp_decl_global(const Emitter emit, const Exp_Decl *decl, const Var_Decl var_decl, |
|
683 |
const uint is_ref, const uint emit_var) { |
||
684 |
6 |
const Value v = var_decl->value; |
|
685 |
6 |
const Type type = v->type; |
|
686 |
6 |
const Array_Sub array = var_decl->array; |
|
687 |
✗✓✗✗ |
6 |
const m_bool is_array = array && array->exp; |
688 |
6 |
const m_bool is_obj = isa(type, emit->gwion->type[et_object]) > 0; |
|
689 |
✓✓✗✓ ✗✗ |
6 |
const uint emit_addr = (!is_obj || (is_ref && !is_array)) ? emit_var : 1; |
690 |
✓✓✓✗ ✓✗✓✗ |
6 |
if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) |
691 |
✗✓ | 2 |
CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) |
692 |
✓✓ | 6 |
const Instr instr = emit_kind(emit, v->type->size, !struct_ctor(v) ? emit_addr : 1, dotstatic); |
693 |
6 |
v->d.ptr = mp_calloc2(emit->gwion->mp, v->type->size); |
|
694 |
6 |
SET_FLAG(v, union); |
|
695 |
6 |
instr->m_val = (m_uint)v->d.ptr; |
|
696 |
6 |
instr->m_val2 = v->type->size; |
|
697 |
✓✓✓✗ ✓✗✓✗ |
8 |
if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) { |
698 |
2 |
const Instr assign = emit_add_instr(emit, Assign); |
|
699 |
✗✓ | 2 |
const size_t missing_depth = type->array_depth - (array ? array->depth : 0); |
700 |
✗✓✗✗ |
2 |
if(missing_depth && !GET_FLAG(decl->td, force)) { |
701 |
const Instr push = emit_add_instr(emit, Reg2Reg); |
||
702 |
push->m_val = -(missing_depth) * SZ_INT; |
||
703 |
} |
||
704 |
2 |
assign->m_val = emit_var; |
|
705 |
2 |
(void)emit_addref(emit, emit_var); |
|
706 |
✓✓ | 4 |
} else if(struct_ctor(v) /* && !GET_FLAG(decl->td, ref) */) |
707 |
1 |
emit_struct_decl_finish(emit, v->type, emit_addr); |
|
708 |
6 |
return GW_OK; |
|
709 |
} |
||
710 |
|||
711 |
ANN static m_bool emit_class_def(const Emitter, const Class_Def); |
||
712 |
ANN static m_bool emit_cdef(const Emitter, const Class_Def); |
||
713 |
|||
714 |
30 |
ANN static inline m_bool ensure_emit(const Emitter emit, const Type t) { |
|
715 |
60 |
struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, |
|
716 |
30 |
.scope=emit->env->scope->depth, .flag=ae_flag_emit }; |
|
717 |
30 |
return envset_run(&es, t); |
|
718 |
} |
||
719 |
|||
720 |
619 |
ANN static m_bool emit_decl(const Emitter emit, const Exp_Decl* decl) { |
|
721 |
619 |
const m_bool global = GET_FLAG(decl->td, global); |
|
722 |
619 |
const uint var = exp_getvar(exp_self(decl)); |
|
723 |
✓✓✗✓ |
619 |
const uint ref = GET_FLAG(decl->td, ref) || type_ref(decl->type); |
724 |
619 |
Var_Decl_List list = decl->list; |
|
725 |
do { |
||
726 |
626 |
const uint r = GET_FLAG(list->self->value, ref) + ref; |
|
727 |
✓✓ | 626 |
if(GET_FLAG(decl->td, static)) |
728 |
✗✓ | 14 |
CHECK_BB(emit_exp_decl_static(emit, list->self, r, var)) |
729 |
✓✓ | 612 |
else if(!global) |
730 |
✗✓ | 606 |
CHECK_BB(emit_exp_decl_non_static(emit, decl, list->self, r, var)) |
731 |
else |
||
732 |
✗✓ | 6 |
CHECK_BB(emit_exp_decl_global(emit, decl, list->self, r, var)) |
733 |
✓✓ | 626 |
if(GET_FLAG(list->self->value->type, nonnull)) |
734 |
14 |
emit_add_instr(emit, GWOP_EXCEPT); |
|
735 |
✓✓ | 626 |
} while((list = list->next)); |
736 |
619 |
return GW_OK; |
|
737 |
} |
||
738 |
|||
739 |
619 |
ANN /*static */m_bool emit_exp_decl(const Emitter emit, const Exp_Decl* decl) { |
|
740 |
619 |
const Type t = get_type(decl->type); |
|
741 |
✓✓✓✓ |
619 |
if(!GET_FLAG(t, emit) && t->e->def) |
742 |
✗✓ | 24 |
CHECK_BB(ensure_emit(emit, t)) |
743 |
619 |
const m_bool global = GET_FLAG(decl->td, global); |
|
744 |
✓✓ | 619 |
const m_uint scope = !global ? emit->env->scope->depth : emit_push_global(emit); |
745 |
619 |
const m_bool ret = emit_decl(emit, decl); |
|
746 |
✓✓ | 619 |
if(global) |
747 |
6 |
emit_pop(emit, scope); |
|
748 |
619 |
return ret; |
|
749 |
} |
||
750 |
|||
751 |
18 |
ANN static m_uint vararg_size(const Exp_Call* exp_call, const Vector kinds) { |
|
752 |
18 |
Exp e = exp_call->args; |
|
753 |
18 |
Arg_List l = exp_call->m_func->def->base->args; |
|
754 |
18 |
m_uint size = 0; |
|
755 |
✓✓ | 84 |
while(e) { |
756 |
✓✓ | 48 |
if(!l) { |
757 |
41 |
size += e->info->type->size; |
|
758 |
41 |
vector_add(kinds, (vtype)e->info->type); // ->size |
|
759 |
} else |
||
760 |
7 |
l = l->next; |
|
761 |
48 |
e = e->next; |
|
762 |
} |
||
763 |
18 |
return size; |
|
764 |
} |
||
765 |
|||
766 |
18 |
ANN static void emit_func_arg_vararg(const Emitter emit, const Exp_Call* exp_call) { |
|
767 |
18 |
const Instr instr = emit_add_instr(emit, VarargIni); |
|
768 |
18 |
const Vector kinds = new_vector(emit->gwion->mp); |
|
769 |
✓✓ | 18 |
if((instr->m_val = vararg_size(exp_call, kinds))) |
770 |
15 |
instr->m_val2 = (m_uint)kinds; |
|
771 |
else |
||
772 |
3 |
free_vector(emit->gwion->mp, kinds); |
|
773 |
18 |
} |
|
774 |
|||
775 |
ANN static inline m_uint exp_size(Exp e); |
||
776 |
260 |
ANN static inline m_uint exp_totalsize(Exp e) { |
|
777 |
260 |
m_uint size = 0; |
|
778 |
335 |
do size += exp_size(e); |
|
779 |
✓✓ | 335 |
while((e = e->next)); |
780 |
260 |
return size; |
|
781 |
} |
||
782 |
ANN static /*inline */void emit_exp_addref1(const Emitter emit, Exp, const m_int size); |
||
783 |
ANN static /*inline */void emit_exp_addref(const Emitter emit, Exp, const m_int size); |
||
784 |
|||
785 |
435 |
ANN static m_bool emit_func_args(const Emitter emit, const Exp_Call* exp_call) { |
|
786 |
✓✓ | 435 |
if(exp_call->args) { |
787 |
✗✓ | 217 |
CHECK_BB(emit_exp(emit, exp_call->args)) |
788 |
217 |
emit_exp_addref(emit, exp_call->args, -exp_totalsize(exp_call->args)); |
|
789 |
} |
||
790 |
✓✗✓✓ |
435 |
if(exp_call->m_func && GET_FLAG(exp_call->m_func->def, variadic)) |
791 |
18 |
emit_func_arg_vararg(emit, exp_call); |
|
792 |
435 |
return GW_OK; |
|
793 |
} |
||
794 |
|||
795 |
434 |
ANN static m_bool prepare_call(const Emitter emit, const Exp_Call* exp_call) { |
|
796 |
✗✓ | 434 |
CHECK_BB(emit_func_args(emit, exp_call)) |
797 |
434 |
return emit_exp(emit, exp_call->func); |
|
798 |
} |
||
799 |
|||
800 |
407 |
ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { |
|
801 |
✗✓ | 407 |
CHECK_BB(prepare_call(emit, exp_call)) |
802 |
✓✗ | 407 |
if(exp_call->m_func) |
803 |
✗✓ | 407 |
CHECK_OB(emit_exp_call1(emit, exp_call->m_func)) |
804 |
else { |
||
805 |
struct Op_Import opi = { .op=insert_symbol("@ctor"), .rhs=exp_call->func->info->type->e->d.base_type, |
||
806 |
.data=(uintptr_t)exp_call, .pos=exp_self(exp_call)->pos, .op_type=op_exp }; |
||
807 |
CHECK_OB(op_emit(emit, &opi)) |
||
808 |
} |
||
809 |
407 |
const Exp e = exp_self(exp_call); |
|
810 |
✓✓ | 407 |
if(exp_getvar(e)) { |
811 |
2 |
regpop(emit, exp_self(exp_call)->info->type->size - SZ_INT); |
|
812 |
2 |
const Instr instr = emit_add_instr(emit, Reg2RegAddr); |
|
813 |
2 |
instr->m_val = -SZ_INT; |
|
814 |
2 |
instr->m_val2 = -SZ_INT; |
|
815 |
✗✓✗✗ |
405 |
} else if(!exp_call->m_func && GET_FLAG(e->info->type, struct)) |
816 |
regpop(emit, SZ_INT); |
||
817 |
407 |
return GW_OK; |
|
818 |
} |
||
819 |
|||
820 |
462 |
ANN static m_uint get_decl_size(Var_Decl_List a, uint emit_addr) { |
|
821 |
462 |
m_uint size = 0; |
|
822 |
do //if(GET_FLAG(a->self->value, used)) |
||
823 |
✓✗ | 469 |
size += !emit_addr ? a->self->value->type->size : SZ_INT; |
824 |
✓✓ | 469 |
while((a = a->next)); |
825 |
462 |
return size; |
|
826 |
} |
||
827 |
|||
828 |
1984 |
ANN static m_uint pop_exp_size(Exp e) { |
|
829 |
1984 |
const uint emit_addr = exp_getvar(e); |
|
830 |
1984 |
m_uint size = 0; |
|
831 |
do { // account for emit_var ? |
||
832 |
3968 |
size += (e->exp_type == ae_exp_decl ? |
|
833 |
✓✓ | 1984 |
get_decl_size(e->d.exp_decl.list, emit_addr) : e->info->type->size); |
834 |
✗✓ | 1984 |
} while((e = e->next)); |
835 |
1984 |
return size; |
|
836 |
} |
||
837 |
|||
838 |
1984 |
ANN static inline void pop_exp(const Emitter emit, Exp e) { |
|
839 |
1984 |
const m_uint size = pop_exp_size(e); |
|
840 |
✓✓ | 1984 |
if(size) |
841 |
1796 |
regpop(emit, size); |
|
842 |
1984 |
} |
|
843 |
|||
844 |
1250 |
ANN static inline m_bool emit_exp_pop_next(const Emitter emit, Exp e) { |
|
845 |
✗✓ | 1250 |
CHECK_BB(emit_exp(emit, e)) |
846 |
✓✓ | 1250 |
if(e->exp_type == ae_exp_decl) { |
847 |
119 |
Var_Decl_List list = e->d.exp_decl.list->next; |
|
848 |
✗✓ | 238 |
while(list) { |
849 |
regpop(emit, !exp_getvar(e) ? list->self->value->type->size : SZ_INT); |
||
850 |
list = list->next; |
||
851 |
} |
||
852 |
} |
||
853 |
✓✓ | 1250 |
if(e->next) |
854 |
1 |
pop_exp(emit, e->next); |
|
855 |
1250 |
return GW_OK; |
|
856 |
} |
||
857 |
|||
858 |
1246 |
ANN static inline m_bool op_emit_bool(const Emitter emit, const struct Op_Import* opi) { |
|
859 |
✗✓ | 1246 |
DECL_OB(const Instr, instr, = op_emit(emit, opi)) |
860 |
1246 |
return GW_OK; |
|
861 |
} |
||
862 |
|||
863 |
519 |
ANN static m_bool emit_exp_binary(const Emitter emit, const Exp_Binary* bin) { |
|
864 |
519 |
const Exp lhs = bin->lhs; |
|
865 |
519 |
const Exp rhs = bin->rhs; |
|
866 |
1557 |
struct Op_Import opi = { .op=bin->op, .lhs=lhs->info->type, .rhs=rhs->info->type, |
|
867 |
1038 |
.pos=exp_self(bin)->pos, .data=(uintptr_t)bin, .op_type=op_binary }; |
|
868 |
✗✓ | 519 |
CHECK_BB(emit_exp_pop_next(emit, lhs)) |
869 |
✗✓ | 519 |
CHECK_BB(emit_exp_pop_next(emit, rhs)) |
870 |
519 |
const m_int size = exp_size(rhs); |
|
871 |
519 |
emit_exp_addref1(emit, lhs, -exp_size(lhs) - size); |
|
872 |
519 |
emit_exp_addref1(emit, rhs, -size); |
|
873 |
519 |
return op_emit_bool(emit, &opi); |
|
874 |
} |
||
875 |
|||
876 |
30 |
ANN static m_bool emit_exp_cast(const Emitter emit, const Exp_Cast* cast) { |
|
877 |
// no pos ? |
||
878 |
60 |
struct Op_Import opi = { .op=insert_symbol("$"), .lhs=cast->exp->info->type, .rhs=exp_self(cast)->info->type, |
|
879 |
30 |
.data=(uintptr_t)cast, .op_type=op_cast}; |
|
880 |
✗✓ | 30 |
CHECK_BB(emit_exp(emit, cast->exp)) |
881 |
30 |
(void)op_emit(emit, &opi); |
|
882 |
30 |
return GW_OK; |
|
883 |
} |
||
884 |
|||
885 |
35 |
ANN static m_bool emit_exp_post(const Emitter emit, const Exp_Postfix* post) { |
|
886 |
// no pos ? |
||
887 |
70 |
struct Op_Import opi = { .op=post->op, .lhs=post->exp->info->type, |
|
888 |
35 |
.data=(uintptr_t)post, .op_type=op_postfix }; |
|
889 |
✗✓ | 35 |
CHECK_BB(emit_exp(emit, post->exp)) |
890 |
35 |
emit_exp_addref(emit, post->exp, -exp_totalsize(post->exp)); |
|
891 |
35 |
return op_emit_bool(emit, &opi); |
|
892 |
} |
||
893 |
|||
894 |
222 |
ANN static inline m_bool is_special(const Emitter emit, const Type t) { |
|
895 |
✓✗ | 227 |
return isa(t, emit->gwion->type[et_object]) < 0 && |
896 |
5 |
isa(t, emit->gwion->type[et_class]) < 0 ? |
|
897 |
✓✓ | 227 |
GW_OK : GW_ERROR; |
898 |
} |
||
899 |
|||
900 |
20 |
ANN static inline m_bool traverse_emit_func_def(const Emitter emit, const Func_Def fdef) { |
|
901 |
✓✗ | 20 |
if(!fdef->base->ret_type) |
902 |
✓✓ | 20 |
CHECK_BB(traverse_func_def(emit->env, fdef)) |
903 |
18 |
return emit_func_def(emit, fdef); |
|
904 |
} |
||
905 |
|||
906 |
20 |
ANN m_bool traverse_dot_tmpl(const Emitter emit, const struct dottmpl_ *dt) { |
|
907 |
20 |
const m_uint scope = emit->env->scope->depth; |
|
908 |
20 |
struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, |
|
909 |
.scope=scope, .flag=ae_flag_emit }; |
||
910 |
✗✓ | 20 |
CHECK_BB(envset_push(&es, dt->owner_class, dt->owner)) |
911 |
20 |
(void)emit_push(emit, dt->owner_class, dt->owner); |
|
912 |
20 |
const m_bool ret = traverse_emit_func_def(emit, dt->def); |
|
913 |
✓✓ | 20 |
if(es.run) |
914 |
4 |
envset_pop(&es, dt->owner_class); |
|
915 |
20 |
emit_pop(emit, scope); |
|
916 |
20 |
return ret; |
|
917 |
} |
||
918 |
|||
919 |
170 |
static inline m_bool push_func_code(const Emitter emit, const Func f) { |
|
920 |
✓✓ | 170 |
if(!vector_size(&emit->code->instr)) |
921 |
10 |
return GW_OK; |
|
922 |
160 |
const Instr instr = (Instr)vector_back(&emit->code->instr); |
|
923 |
✓✓ | 160 |
if(instr->opcode == eDotTmplVal) { |
924 |
31 |
size_t len = strlen(f->name); |
|
925 |
31 |
size_t sz = len - strlen(f->value_ref->from->owner_class->name); |
|
926 |
31 |
char c[sz + 1]; |
|
927 |
31 |
memcpy(c, f->name, sz); |
|
928 |
31 |
c[sz] = '\0'; |
|
929 |
31 |
struct dottmpl_ *dt = mp_calloc(emit->gwion->mp, dottmpl); |
|
930 |
31 |
dt->name = s_name(insert_symbol(c)); |
|
931 |
31 |
dt->vt_index = f->def->base->tmpl->base; |
|
932 |
31 |
dt->tl = cpy_type_list(emit->gwion->mp, f->def->base->tmpl->call); |
|
933 |
31 |
dt->base = f->def; |
|
934 |
31 |
instr->opcode = eOP_MAX; |
|
935 |
31 |
instr->m_val = (m_uint)dt; |
|
936 |
31 |
instr->m_val2 = strlen(c); |
|
937 |
31 |
instr->execute = DotTmpl; |
|
938 |
31 |
return GW_OK; |
|
939 |
} |
||
940 |
129 |
instr->opcode = eRegPushImm; |
|
941 |
129 |
instr->m_val = (m_uint)f->code; |
|
942 |
129 |
return GW_OK; |
|
943 |
} |
||
944 |
|||
945 |
33 |
ANN static m_bool emit_template_code(const Emitter emit, const Func f) { |
|
946 |
33 |
const Value v = f->value_ref; |
|
947 |
33 |
const size_t scope = emit->env->scope->depth; |
|
948 |
33 |
struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, |
|
949 |
.scope=scope, .flag=ae_flag_emit }; |
||
950 |
✗✓ | 33 |
CHECK_BB(envset_push(&es, v->from->owner_class, v->from->owner)) |
951 |
33 |
(void)emit_push(emit, v->from->owner_class, v->from->owner); |
|
952 |
33 |
const m_bool ret = emit_func_def(emit, f->def); |
|
953 |
✓✓ | 33 |
if(es.run) |
954 |
18 |
envset_pop(&es, v->from->owner_class); |
|
955 |
33 |
emit_pop(emit, scope); |
|
956 |
✓✗ | 33 |
return ret > 0 ? push_func_code(emit, f) : GW_ERROR; |
957 |
} |
||
958 |
|||
959 |
18 |
ANN static void tmpl_prelude(const Emitter emit, const Func f) { |
|
960 |
18 |
struct dottmpl_ *dt = (struct dottmpl_*)mp_calloc(emit->gwion->mp, dottmpl); |
|
961 |
18 |
size_t len = strlen(f->name); |
|
962 |
18 |
size_t slen = strlen(f->value_ref->from->owner->name); |
|
963 |
assert(len > slen); |
||
964 |
18 |
size_t sz = len - slen; |
|
965 |
18 |
char c[sz + 1]; |
|
966 |
18 |
memcpy(c, f->name, sz); |
|
967 |
18 |
c[sz] = '\0'; |
|
968 |
18 |
dt->tl = cpy_type_list(emit->gwion->mp, f->def->base->tmpl->call); |
|
969 |
18 |
dt->name = s_name(insert_symbol(c)); |
|
970 |
18 |
dt->vt_index = f->def->base->tmpl->base; |
|
971 |
18 |
dt->base = f->def; |
|
972 |
18 |
dt->owner = f->value_ref->from->owner; |
|
973 |
18 |
dt->owner_class = f->value_ref->from->owner_class; |
|
974 |
18 |
const Instr gtmpl = emit_add_instr(emit, GTmpl); |
|
975 |
18 |
gtmpl->m_val = (m_uint)dt; |
|
976 |
18 |
gtmpl->m_val2 = strlen(c); |
|
977 |
18 |
} |
|
978 |
|||
979 |
443 |
ANN static Instr get_prelude(const Emitter emit, const Func f) { |
|
980 |
443 |
const Type t = actual_type(emit->gwion, f->value_ref->type); |
|
981 |
✓✓ | 443 |
if(is_fptr(emit->gwion, t)) { |
982 |
56 |
emit_except(emit, t); |
|
983 |
✓✓ | 56 |
if(f->def->base->tmpl) |
984 |
18 |
tmpl_prelude(emit, f); |
|
985 |
} |
||
986 |
443 |
const Instr instr = emit_add_instr(emit, SetCode); |
|
987 |
443 |
instr->m_val2 = 1; |
|
988 |
443 |
return instr; |
|
989 |
} |
||
990 |
|||
991 |
223 |
ANN static void emit_args(const Emitter emit, const Func f) { |
|
992 |
223 |
const m_uint member = GET_FLAG(f, member) ? SZ_INT : 0; |
|
993 |
✓✓ | 223 |
if((f->def->stack_depth - member) == SZ_INT) { |
994 |
150 |
const Instr instr = emit_add_instr(emit, Reg2Mem); |
|
995 |
150 |
instr->m_val = member; |
|
996 |
} else { |
||
997 |
73 |
const Instr instr = emit_add_instr(emit, Reg2Mem4); |
|
998 |
73 |
instr->m_val = member; |
|
999 |
73 |
instr->m_val2 = f->def->stack_depth - member; |
|
1000 |
} |
||
1001 |
223 |
} |
|
1002 |
|||
1003 |
typedef struct { |
||
1004 |
const Emitter emit; |
||
1005 |
const Func_Def fdef; |
||
1006 |
struct Vector_ branch; |
||
1007 |
const m_uint offset; |
||
1008 |
m_uint arg_offset; |
||
1009 |
} MemoizeEmitter; |
||
1010 |
|||
1011 |
2 |
ANN static Instr me_push(const MemoizeEmitter *me, const m_uint sz) { |
|
1012 |
2 |
const Instr instr = emit_kind(me->emit, sz, 0, regpushmem); |
|
1013 |
2 |
instr->m_val = me->arg_offset; |
|
1014 |
2 |
return instr; |
|
1015 |
} |
||
1016 |
|||
1017 |
1 |
static m_bool me_cmp(MemoizeEmitter *me, const Arg_List arg) { |
|
1018 |
1 |
const Emitter emit = me->emit; |
|
1019 |
1 |
const Symbol sym = insert_symbol("=="); |
|
1020 |
1 |
struct ExpInfo_ info = { .nspc=me->fdef->base->func->value_ref->from->owner }; |
|
1021 |
1 |
struct Exp_ exp = { .info=&info }; |
|
1022 |
3 |
struct Op_Import opi = { .op=sym, .lhs=arg->type, .rhs=arg->type, |
|
1023 |
2 |
.pos=me->fdef->pos, .data=(uintptr_t)&exp.d, .op_type=op_binary }; |
|
1024 |
✗✓ | 1 |
CHECK_BB(op_emit_bool(emit, &opi)) |
1025 |
1 |
const Instr instr = emit_add_instr(emit, BranchEqInt); |
|
1026 |
1 |
vector_add(&me->branch, (vtype)instr); |
|
1027 |
1 |
return GW_OK; |
|
1028 |
} |
||
1029 |
|||
1030 |
1 |
ANN static m_bool me_arg(MemoizeEmitter *me) { |
|
1031 |
1 |
Arg_List arg = me->fdef->base->args; |
|
1032 |
do { |
||
1033 |
1 |
const m_uint sz = arg->type->size; |
|
1034 |
1 |
(void)me_push(me, sz); |
|
1035 |
1 |
const Instr instr = me_push(me, sz); |
|
1036 |
1 |
instr->m_val += me->offset + SZ_INT *2; |
|
1037 |
✗✓ | 1 |
CHECK_BB(me_cmp(me, arg)) |
1038 |
1 |
me->arg_offset += arg->type->size; |
|
1039 |
✗✓ | 1 |
} while((arg = arg->next)); |
1040 |
1 |
return GW_OK; |
|
1041 |
} |
||
1042 |
|||
1043 |
443 |
ANN static Instr emit_call(const Emitter emit, const Func f) { |
|
1044 |
443 |
const Instr prelude = get_prelude(emit, f); |
|
1045 |
443 |
prelude->m_val = f->def->stack_depth; |
|
1046 |
443 |
const m_uint member = GET_FLAG(f, member) ? SZ_INT : 0; |
|
1047 |
✓✓ | 443 |
if(member) { |
1048 |
241 |
const Instr instr = emit_add_instr(emit, Reg2Mem); |
|
1049 |
241 |
instr->m_val2 = f->def->stack_depth - SZ_INT; |
|
1050 |
241 |
++prelude->m_val2; |
|
1051 |
} |
||
1052 |
✓✓ | 443 |
if(f->def->stack_depth - member) { |
1053 |
222 |
emit_args(emit, f); |
|
1054 |
222 |
++prelude->m_val2; |
|
1055 |
} |
||
1056 |
443 |
return emit_add_instr(emit, Overflow); |
|
1057 |
} |
||
1058 |
|||
1059 |
443 |
ANN Instr emit_exp_call1(const Emitter emit, const Func f) { |
|
1060 |
✓✓✓✓ ✓✗ |
443 |
if(!f->code || (GET_FLAG(f, ref) && !GET_FLAG(f, builtin))) { |
1061 |
✓✓✓✗ |
216 |
if(GET_FLAG(f, template) && !is_fptr(emit->gwion, f->value_ref->type)) { |
1062 |
✓✓ | 76 |
if(emit->env->func != f) |
1063 |
✗✓ | 33 |
CHECK_BO(emit_template_code(emit, f)) |
1064 |
else { // recursive function. (maybe should be used only for global funcs) |
||
1065 |
10 |
const Instr back = (Instr) vector_size(&emit->code->instr) ? |
|
1066 |
✓✗ | 5 |
(Instr)vector_back(&emit->code->instr) : emit_add_instr(emit, RegPushImm); |
1067 |
5 |
back->opcode = eOP_MAX; |
|
1068 |
5 |
back->execute = SetRecurs; |
|
1069 |
5 |
back->m_val = 0; |
|
1070 |
} |
||
1071 |
✓✓✓✓ ✓✗✓✓ |
70 |
} else if(emit->env->func != f && !f->value_ref->from->owner_class && !f->code && !is_fptr(emit->gwion, f->value_ref->type)) { |
1072 |
✗✓ | 1 |
if(GET_FLAG(f->def, op)) { |
1073 |
const Instr back = (Instr)vector_back(&emit->code->instr); |
||
1074 |
back->m_val = (m_uint)f; |
||
1075 |
} else { |
||
1076 |
// ensure env? |
||
1077 |
✗✓ | 1 |
CHECK_BO(emit_func_def(emit, f->def)) |
1078 |
1 |
const Instr instr = emit_add_instr(emit, RegSetImm); |
|
1079 |
1 |
instr->m_val = (m_uint)f->code; |
|
1080 |
1 |
instr->m_val2 = -SZ_INT; |
|
1081 |
} |
||
1082 |
} |
||
1083 |
✓✓✓✓ ✓✓ |
665 |
} else if((f->value_ref->from->owner_class && is_special(emit, f->value_ref->from->owner_class) > 0) || |
1084 |
✓✓✓✗ |
566 |
!f->value_ref->from->owner_class || (GET_FLAG(f, template) && |
1085 |
19 |
!is_fptr(emit->gwion, f->value_ref->type))) |
|
1086 |
137 |
push_func_code(emit, f); |
|
1087 |
✓✓ | 198 |
else if(vector_size(&emit->code->instr)) { |
1088 |
187 |
const Instr back = (Instr)vector_back(&emit->code->instr); |
|
1089 |
✓✓✓✓ |
187 |
if((f_instr)(m_uint)back->opcode == DotFunc || (f_instr)(m_uint)back->opcode == DotStaticFunc) |
1090 |
169 |
back->m_val = f->vt_index; |
|
1091 |
} |
||
1092 |
✓✓✓✓ ✓✓ |
670 |
if(vector_size(&emit->code->instr) && GET_FLAG(f, member) && |
1093 |
251 |
is_fptr(emit->gwion, f->value_ref->type)) { |
|
1094 |
24 |
const Instr back = (Instr)vector_back(&emit->code->instr); |
|
1095 |
24 |
m_bit exec = back->opcode; |
|
1096 |
24 |
m_uint val = back->m_val; |
|
1097 |
24 |
m_uint val2 = back->m_val2; |
|
1098 |
24 |
back->opcode = eRegPushMem; |
|
1099 |
24 |
back->m_val = back->m_val2 = 0; |
|
1100 |
24 |
const Instr instr = emit_add_instr(emit, (f_instr)(m_uint)exec); |
|
1101 |
24 |
instr->m_val = val; |
|
1102 |
24 |
instr->m_val2 = val2; |
|
1103 |
✓✓✓✓ ✓✓ |
419 |
} else if(f != emit->env->func && !f->code && !is_fptr(emit->gwion, f->value_ref->type)){ |
1104 |
// not yet emitted static func |
||
1105 |
✓✗ | 2 |
if(f->value_ref->from->owner_class) { |
1106 |
4 |
const Instr instr = vector_size(&emit->code->instr) ? |
|
1107 |
✓✗ | 2 |
(Instr)vector_back(&emit->code->instr) : emit_add_instr(emit, SetFunc); |
1108 |
2 |
instr->opcode = eOP_MAX; |
|
1109 |
2 |
instr->execute = SetFunc; |
|
1110 |
2 |
instr->m_val = (m_uint)f; |
|
1111 |
} else { |
||
1112 |
const Instr instr = emit_add_instr(emit, SetFunc); |
||
1113 |
instr->m_val = (m_uint)f; |
||
1114 |
} |
||
1115 |
} |
||
1116 |
443 |
const m_uint offset = emit_code_offset(emit); |
|
1117 |
443 |
regseti(emit, offset); |
|
1118 |
443 |
const Instr instr = emit_call(emit, f); |
|
1119 |
443 |
instr->m_val = f->def->base->ret_type->size; |
|
1120 |
443 |
instr->m_val2 = offset; |
|
1121 |
443 |
return instr; |
|
1122 |
} |
||
1123 |
|||
1124 |
24 |
ANN static void emit_exp_spork_finish(const Emitter emit, const m_uint depth) { |
|
1125 |
24 |
regpop(emit, depth); |
|
1126 |
24 |
const Instr spork = emit_add_instr(emit, SporkFunc); |
|
1127 |
24 |
spork->m_val = depth + SZ_INT; |
|
1128 |
24 |
spork->m_val2 = -SZ_INT; |
|
1129 |
24 |
} |
|
1130 |
|||
1131 |
241 |
static inline void stack_alloc(const Emitter emit) { // maybe vararg could use t_vararg instead |
|
1132 |
241 |
emit_local(emit, emit->gwion->type[et_int]); // hiding the fact it is an object |
|
1133 |
241 |
emit->code->stack_depth += SZ_INT; |
|
1134 |
241 |
} |
|
1135 |
|||
1136 |
233 |
static inline void stack_alloc_this(const Emitter emit) { |
|
1137 |
233 |
SET_FLAG(emit->code, member); |
|
1138 |
233 |
stack_alloc(emit); |
|
1139 |
233 |
} |
|
1140 |
|||
1141 |
345 |
static m_bool scoped_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { |
|
1142 |
345 |
++emit->env->scope->depth; |
|
1143 |
345 |
emit_push_scope(emit); |
|
1144 |
345 |
const Instr gc = emit_add_instr(emit, NoOp); |
|
1145 |
345 |
const m_bool ret = emit_stmt(emit, stmt, pop); |
|
1146 |
✓✗ | 345 |
if(ret > 0) { |
1147 |
345 |
const m_bool pure = !vector_back(&emit->info->pure); |
|
1148 |
✓✓ | 345 |
if(!pure) { |
1149 |
7 |
gc->opcode = eGcIni; |
|
1150 |
7 |
emit_add_instr(emit, GcEnd); |
|
1151 |
} |
||
1152 |
} |
||
1153 |
345 |
emit_pop_scope(emit); |
|
1154 |
345 |
--emit->env->scope->depth; |
|
1155 |
345 |
return ret; |
|
1156 |
} |
||
1157 |
|||
1158 |
#define SPORK_FUNC_PREFIX "spork~func:%i" |
||
1159 |
#define FORK_FUNC_PREFIX "fork~func:%i" |
||
1160 |
#define SPORK_CODE_PREFIX "spork~code:%i" |
||
1161 |
#define FORK_CODE_PREFIX "fork~code:%i" |
||
1162 |
|||
1163 |
52 |
static void push_spork_code(const Emitter emit, const m_str prefix, const loc_t pos) { |
|
1164 |
52 |
char c[strlen(SPORK_FUNC_PREFIX) + num_digit(pos->first.line) + 1]; |
|
1165 |
52 |
sprintf(c, prefix, pos->first.line); |
|
1166 |
52 |
emit_push_code(emit, c); |
|
1167 |
52 |
} |
|
1168 |
|||
1169 |
27 |
ANN static m_bool call_spork_func(const Emitter emit, const Exp_Call *exp) { |
|
1170 |
✓✓ | 27 |
if(GET_FLAG(exp->m_func, member)) |
1171 |
14 |
SET_FLAG(emit->code, member); |
|
1172 |
✓✗ | 27 |
return emit_exp_call1(emit, exp->m_func) ? GW_OK : GW_ERROR; |
1173 |
} |
||
1174 |
|||
1175 |
struct Sporker { |
||
1176 |
const Stmt code; |
||
1177 |
const Exp exp; |
||
1178 |
VM_Code vm_code; |
||
1179 |
const m_bool emit_var; |
||
1180 |
const m_bool is_spork; |
||
1181 |
}; |
||
1182 |
|||
1183 |
25 |
ANN static m_bool spork_prepare_code(const Emitter emit, const struct Sporker *sp) { |
|
1184 |
25 |
emit_add_instr(emit, RegPushImm); |
|
1185 |
✓✓ | 25 |
push_spork_code(emit, sp->is_spork ? SPORK_CODE_PREFIX : FORK_CODE_PREFIX, sp->code->pos); |
1186 |
✓✓✓✓ |
25 |
if(SAFE_FLAG(emit->env->func, member)) |
1187 |
2 |
stack_alloc_this(emit); |
|
1188 |
25 |
return scoped_stmt(emit, sp->code, 0); |
|
1189 |
} |
||
1190 |
|||
1191 |
27 |
ANN static m_bool spork_prepare_func(const Emitter emit, const struct Sporker *sp) { |
|
1192 |
✓✗ | 27 |
push_spork_code(emit, sp->is_spork ? SPORK_FUNC_PREFIX : FORK_CODE_PREFIX, sp->exp->pos); |
1193 |
27 |
return call_spork_func(emit, &sp->exp->d.exp_call); |
|
1194 |
} |
||
1195 |
|||
1196 |
52 |
ANN static VM_Code spork_prepare(const Emitter emit, const struct Sporker *sp) { |
|
1197 |
✓✓ | 52 |
if(!sp->code) |
1198 |
✗✓ | 27 |
CHECK_BO(prepare_call(emit, &sp->exp->d.exp_call)) |
1199 |
✓✓✓✗ |
52 |
if((sp->code ? spork_prepare_code : spork_prepare_func)(emit, sp) > 0) |
1200 |
52 |
return finalyze(emit, EOC); |
|
1201 |
emit_pop_code(emit); |
||
1202 |
return NULL; |
||
1203 |
} |
||
1204 |
|||
1205 |
25 |
ANN void spork_code(const Emitter emit, const struct Sporker *sp) { |
|
1206 |
25 |
const Instr args = emit_add_instr(emit, SporkExp); |
|
1207 |
25 |
args->m_val = emit->code->stack_depth; |
|
1208 |
25 |
const Instr instr = emit_add_instr(emit, SporkEnd); |
|
1209 |
25 |
instr->m_val = sp->emit_var; |
|
1210 |
25 |
} |
|
1211 |
|||
1212 |
27 |
ANN void spork_func(const Emitter emit, const struct Sporker *sp) { |
|
1213 |
27 |
const Func f = sp->exp->d.exp_call.m_func; |
|
1214 |
✓✓✓✓ |
30 |
if(GET_FLAG(f, member) && is_fptr(emit->gwion, f->value_ref->type)) { |
1215 |
3 |
const m_uint depth = f->def->stack_depth; |
|
1216 |
3 |
regpop(emit, depth -SZ_INT); |
|
1217 |
3 |
const Instr spork = emit_add_instr(emit, SporkMemberFptr); |
|
1218 |
3 |
spork->m_val = depth; |
|
1219 |
} else |
||
1220 |
24 |
emit_exp_spork_finish(emit, f->def->stack_depth); |
|
1221 |
27 |
(void)emit_add_instr(emit, SporkEnd); |
|
1222 |
27 |
} |
|
1223 |
|||
1224 |
52 |
ANN static Instr spork_ini(const Emitter emit, const struct Sporker *sp) { |
|
1225 |
✓✓ | 52 |
if(sp->is_spork) { |
1226 |
45 |
const Instr instr = emit_add_instr(emit, SporkIni); |
|
1227 |
45 |
instr->m_val = (m_uint)sp->vm_code; |
|
1228 |
45 |
instr->m_val2 = sp->is_spork; |
|
1229 |
45 |
return instr; |
|
1230 |
} |
||
1231 |
✗✓ | 7 |
const Func f = !sp->code ? sp->exp->d.exp_call.m_func : NULL; |
1232 |
7 |
const Instr instr = emit_add_instr(emit, ForkIni); |
|
1233 |
7 |
instr->m_val = (m_uint)sp->vm_code; |
|
1234 |
✗✓ | 7 |
instr->m_val2 = f ? f->def->base->ret_type->size : 0; |
1235 |
7 |
return instr; |
|
1236 |
} |
||
1237 |
|||
1238 |
52 |
ANN Instr emit_exp_spork(const Emitter emit, const Exp_Unary* unary) { |
|
1239 |
260 |
struct Sporker sporker = { |
|
1240 |
52 |
.exp=unary->exp, |
|
1241 |
52 |
.code=unary->code, |
|
1242 |
52 |
.is_spork=(unary->op == insert_symbol("spork")), |
|
1243 |
52 |
.emit_var=exp_getvar(exp_self(unary)) |
|
1244 |
}; |
||
1245 |
✗✓ | 52 |
CHECK_OO((sporker.vm_code = spork_prepare(emit, &sporker))) |
1246 |
52 |
const Instr ini = spork_ini(emit, &sporker); |
|
1247 |
✓✓ | 52 |
(unary->code ? spork_code : spork_func)(emit, &sporker); |
1248 |
52 |
return ini; |
|
1249 |
} |
||
1250 |
|||
1251 |
124 |
ANN static m_bool emit_exp_unary(const Emitter emit, const Exp_Unary* unary) { |
|
1252 |
124 |
const Type t = exp_self(unary)->info->type; |
|
1253 |
124 |
const Type base = get_type(actual_type(emit->gwion, t)); |
|
1254 |
✓✓✗✓ |
124 |
if(base->e->def && !GET_FLAG(base, emit)) |
1255 |
CHECK_BB(ensure_emit(emit, base)) |
||
1256 |
// no pos ? |
||
1257 |
124 |
struct Op_Import opi = { .op=unary->op, .data=(uintptr_t)unary, .op_type=op_unary }; |
|
1258 |
✓✓✓✓ ✓✓ |
124 |
if(unary->op != insert_symbol("spork") && unary->op != insert_symbol("fork") && unary->exp) { |
1259 |
✗✓ | 53 |
CHECK_BB(emit_exp_pop_next(emit, unary->exp)) |
1260 |
53 |
emit_exp_addref1(emit, unary->exp, -exp_size(unary->exp)); |
|
1261 |
53 |
opi.rhs = unary->exp->info->type; |
|
1262 |
} |
||
1263 |
124 |
return op_emit_bool(emit, &opi); |
|
1264 |
} |
||
1265 |
|||
1266 |
34 |
ANN static m_bool emit_implicit_cast(const Emitter emit, |
|
1267 |
const restrict Exp from, const restrict Type to) { |
||
1268 |
34 |
const struct Implicit imp = { from, to, from->pos }; |
|
1269 |
// no pos |
||
1270 |
68 |
struct Op_Import opi = { .op=insert_symbol("@implicit"), .lhs=from->info->type, .rhs=to, |
|
1271 |
34 |
.data=(m_uint)&imp, .op_type=op_implicit }; |
|
1272 |
34 |
return op_emit_bool(emit, &opi); |
|
1273 |
} |
||
1274 |
|||
1275 |
81 |
ANN static Instr _flow(const Emitter emit, const Exp e, const m_bool b) { |
|
1276 |
✗✓ | 81 |
CHECK_BO(emit_exp_pop_next(emit, e)) |
1277 |
81 |
emit_exp_addref1(emit, e, -exp_size(e)); |
|
1278 |
✓✓ | 324 |
struct Op_Import opi = { .op=insert_symbol(b ? "@conditionnal" : "@unconditionnal"), |
1279 |
243 |
.rhs=e->info->type, .pos=e->pos, .data=(uintptr_t)e, .op_type=op_exp }; |
|
1280 |
81 |
const Instr instr = op_emit(emit, &opi); |
|
1281 |
assert(instr != (Instr)GW_OK); |
||
1282 |
81 |
return instr; |
|
1283 |
} |
||
1284 |
#define emit_flow(emit,b) _flow(emit, b, 1) |
||
1285 |
|||
1286 |
7 |
ANN static m_bool emit_exp_if(const Emitter emit, const Exp_If* exp_if) { |
|
1287 |
✗✓ | 7 |
DECL_OB(const Instr, op, = emit_flow(emit, exp_if->cond)) |
1288 |
✓✓✗✓ |
7 |
CHECK_BB(emit_exp_pop_next(emit, exp_if->if_exp ?: exp_if->cond)) |
1289 |
7 |
const Instr op2 = emit_add_instr(emit, Goto); |
|
1290 |
7 |
op->m_val = emit_code_size(emit); |
|
1291 |
7 |
const m_bool ret = emit_exp_pop_next(emit, exp_if->else_exp); |
|
1292 |
7 |
op2->m_val = emit_code_size(emit); |
|
1293 |
7 |
return ret; |
|
1294 |
} |
||
1295 |
|||
1296 |
13 |
ANN static m_bool emit_lambda(const Emitter emit, const Exp_Lambda * lambda) { |
|
1297 |
✗✓ | 13 |
CHECK_BB(emit_func_def(emit, lambda->def)) |
1298 |
✓✓✓✓ |
13 |
if(GET_FLAG(lambda->def, member) && !exp_getvar(exp_self(lambda))) |
1299 |
7 |
emit_add_instr(emit, RegPushMem); |
|
1300 |
13 |
regpushi(emit, (m_uint)lambda->def->base->func->code); |
|
1301 |
13 |
return GW_OK; |
|
1302 |
} |
||
1303 |
|||
1304 |
14 |
ANN static m_bool emit_exp_lambda(const Emitter emit, const Exp_Lambda * lambda) { |
|
1305 |
✓✓ | 14 |
if(!lambda->def->base->func) { |
1306 |
1 |
regpushi(emit, SZ_INT); |
|
1307 |
1 |
return GW_OK; |
|
1308 |
} |
||
1309 |
26 |
struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, |
|
1310 |
13 |
.scope=emit->env->scope->depth, .flag=ae_flag_emit }; |
|
1311 |
✗✓ | 13 |
CHECK_BB(envset_push(&es, lambda->owner, lambda->def->base->func->value_ref->from->owner)) |
1312 |
13 |
const m_bool ret = emit_lambda(emit, lambda); |
|
1313 |
✓✓ | 13 |
if(es.run) |
1314 |
5 |
envset_pop(&es, lambda->owner); |
|
1315 |
13 |
return ret; |
|
1316 |
} |
||
1317 |
|||
1318 |
DECL_EXP_FUNC(emit, m_bool, Emitter) |
||
1319 |
|||
1320 |
|||
1321 |
ANN static void struct_addref(const Emitter emit, const Type type, |
||
1322 |
const m_int size, const m_bool offset, const m_bool emit_var) { |
||
1323 |
for(m_uint i = 0; i < vector_size(&type->e->tuple->types); ++i) { |
||
1324 |
const Type t = (Type)vector_at(&type->e->tuple->types, i); |
||
1325 |
if(isa(t, emit->gwion->type[et_object]) > 0) { |
||
1326 |
const Instr instr = emit_addref(emit, emit_var); |
||
1327 |
instr->m_val = size; |
||
1328 |
instr->m_val2 = vector_at(&type->e->tuple->offset, i); |
||
1329 |
} else if(GET_FLAG(t, struct)) |
||
1330 |
struct_addref(emit, t, size, offset + vector_at(&type->e->tuple->offset, i), emit_var); |
||
1331 |
} |
||
1332 |
} |
||
1333 |
|||
1334 |
1849 |
ANN static inline m_uint exp_size(const Exp e) { |
|
1335 |
✓✓ | 1849 |
if(exp_getvar(e)) |
1336 |
354 |
return SZ_INT; |
|
1337 |
✓✓ | 1495 |
const Type type = e->info->cast_to ?: e->info->type; |
1338 |
1495 |
return type->size; |
|
1339 |
} |
||
1340 |
|||
1341 |
1514 |
ANN2(1) static void emit_exp_addref1(const Emitter emit, /* const */Exp exp, m_int size) { |
|
1342 |
✓✓✓✓ ✓✓ |
1740 |
if(isa(exp->info->type, emit->gwion->type[et_object]) > 0 && |
1343 |
438 |
(exp->info->cast_to ? isa(exp->info->cast_to, emit->gwion->type[et_object]) > 0 : 1)) { |
|
1344 |
212 |
const Instr instr = emit_addref(emit, exp_getvar(exp)); |
|
1345 |
212 |
instr->m_val = size; |
|
1346 |
✗✓ | 1302 |
} else if(GET_FLAG(exp->info->type, struct)) // check cast_to ? |
1347 |
struct_addref(emit, exp->info->type, size, 0, exp_getvar(exp)); |
||
1348 |
1514 |
} |
|
1349 |
|||
1350 |
335 |
ANN2(1) static void emit_exp_addref(const Emitter emit, /* const */Exp exp, m_int size) { |
|
1351 |
do { |
||
1352 |
335 |
emit_exp_addref1(emit, exp, size); |
|
1353 |
335 |
size += exp_size(exp); |
|
1354 |
✓✓ | 335 |
} while((exp = exp->next)); |
1355 |
260 |
} |
|
1356 |
|||
1357 |
5664 |
ANN2(1) /*static */m_bool emit_exp(const Emitter emit, /* const */Exp e) { |
|
1358 |
5664 |
Exp exp = e; |
|
1359 |
do { |
||
1360 |
✓✓ | 5800 |
CHECK_BB(emit_exp_func[exp->exp_type](emit, &exp->d)) |
1361 |
✓✓ | 5796 |
if(exp_getnonnull(exp)) |
1362 |
87 |
emit_except(emit, exp->info->type); |
|
1363 |
✓✓ | 5796 |
if(exp->info->cast_to) |
1364 |
✗✓ | 34 |
CHECK_BB(emit_implicit_cast(emit, exp, exp->info->cast_to)) |
1365 |
✓✓ | 5796 |
} while((exp = exp->next)); |
1366 |
5660 |
return GW_OK; |
|
1367 |
} |
||
1368 |
|||
1369 |
34 |
ANN static m_bool emit_if(const Emitter emit, const Stmt_If stmt) { |
|
1370 |
✗✓ | 34 |
DECL_OB(const Instr, op, = emit_flow(emit, stmt->cond)) |
1371 |
✗✓ | 34 |
CHECK_BB(scoped_stmt(emit, stmt->if_body, 1)) |
1372 |
34 |
const Instr op2 = emit_add_instr(emit, Goto); |
|
1373 |
34 |
op->m_val = emit_code_size(emit); |
|
1374 |
✓✓ | 34 |
if(stmt->else_body) |
1375 |
✗✓ | 12 |
CHECK_BB(scoped_stmt(emit, stmt->else_body, 1)) |
1376 |
34 |
op2->m_val = emit_code_size(emit); |
|
1377 |
34 |
return GW_OK; |
|
1378 |
} |
||
1379 |
|||
1380 |
34 |
ANN static m_bool emit_stmt_if(const Emitter emit, const Stmt_If stmt) { |
|
1381 |
34 |
emit_push_scope(emit); |
|
1382 |
34 |
const m_bool ret = emit_if(emit, stmt); |
|
1383 |
34 |
emit_pop_scope(emit); |
|
1384 |
34 |
return ret; |
|
1385 |
} |
||
1386 |
|||
1387 |
371 |
ANN static m_bool emit_stmt_code(const Emitter emit, const Stmt_Code stmt) { |
|
1388 |
371 |
++emit->env->scope->depth; |
|
1389 |
✓✓ | 371 |
const m_bool ret = stmt->stmt_list ? emit_stmt_list(emit, stmt->stmt_list) : 1; |
1390 |
371 |
--emit->env->scope->depth; |
|
1391 |
371 |
return ret; |
|
1392 |
} |
||
1393 |
|||
1394 |
1 |
ANN static m_bool optimize_taill_call(const Emitter emit, const Exp_Call* e) { |
|
1395 |
✓✗ | 1 |
if(e->args) { |
1396 |
1 |
emit_func_args(emit, e); |
|
1397 |
1 |
regpop(emit, e->m_func->def->stack_depth); |
|
1398 |
1 |
emit_args(emit, e->m_func); |
|
1399 |
} |
||
1400 |
1 |
emit_add_instr(emit, Goto); |
|
1401 |
1 |
return GW_OK; |
|
1402 |
} |
||
1403 |
|||
1404 |
38 |
ANN static m_bool emit_stmt_return(const Emitter emit, const Stmt_Exp stmt) { |
|
1405 |
✓✓ | 38 |
if(stmt->val) { |
1406 |
✓✓✓✗ |
36 |
if(stmt->val->exp_type == ae_exp_call && emit->env->func == stmt->val->d.exp_call.m_func) |
1407 |
1 |
return optimize_taill_call(emit, &stmt->val->d.exp_call); |
|
1408 |
✗✓ | 35 |
CHECK_BB(emit_exp_pop_next(emit, stmt->val)) |
1409 |
} |
||
1410 |
37 |
vector_add(&emit->code->stack_return, (vtype)emit_add_instr(emit, Goto)); |
|
1411 |
37 |
return GW_OK; |
|
1412 |
} |
||
1413 |
|||
1414 |
9 |
ANN static inline m_bool emit_stmt_continue(const Emitter emit, const Stmt stmt NUSED) { |
|
1415 |
9 |
vector_add(&emit->code->stack_cont, (vtype)emit_add_instr(emit, Goto)); |
|
1416 |
9 |
return GW_OK; |
|
1417 |
} |
||
1418 |
|||
1419 |
8 |
ANN static inline m_bool emit_stmt_break(const Emitter emit, const Stmt stmt NUSED) { |
|
1420 |
8 |
vector_add(&emit->code->stack_break, (vtype)emit_add_instr(emit, Goto)); |
|
1421 |
8 |
return GW_OK; |
|
1422 |
} |
||
1423 |
|||
1424 |
53 |
ANN static inline void emit_push_stack(const Emitter emit) { |
|
1425 |
53 |
emit_push_scope(emit); |
|
1426 |
53 |
vector_add(&emit->code->stack_cont, (vtype)NULL); |
|
1427 |
53 |
vector_add(&emit->code->stack_break, (vtype)NULL); |
|
1428 |
53 |
} |
|
1429 |
|||
1430 |
106 |
ANN static void pop_vector(Vector v, const m_uint pc) { |
|
1431 |
Instr instr; |
||
1432 |
✓✓ | 229 |
while((instr = (Instr)vector_pop(v))) |
1433 |
17 |
instr->m_val = pc; |
|
1434 |
106 |
} |
|
1435 |
|||
1436 |
53 |
ANN static void emit_pop_stack(const Emitter emit, const m_uint index) { |
|
1437 |
53 |
pop_vector(&emit->code->stack_cont, index); |
|
1438 |
53 |
pop_vector(&emit->code->stack_break, emit_code_size(emit)); |
|
1439 |
53 |
emit_pop_scope(emit); |
|
1440 |
53 |
} |
|
1441 |
|||
1442 |
26 |
ANN static m_bool _emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt, const m_uint index) { |
|
1443 |
26 |
Instr op = NULL; |
|
1444 |
✓✓ | 26 |
if(!stmt->is_do) |
1445 |
12 |
op = _flow(emit, stmt->cond, stmt_self(stmt)->stmt_type == ae_stmt_while); |
|
1446 |
✗✓ | 26 |
CHECK_BB(scoped_stmt(emit, stmt->body, 1)) |
1447 |
✓✓ | 26 |
if(stmt->is_do) { |
1448 |
✗✓ | 14 |
CHECK_OB((op = _flow(emit, stmt->cond, stmt_self(stmt)->stmt_type != ae_stmt_while))) |
1449 |
14 |
op->m_val = index; |
|
1450 |
} else { |
||
1451 |
12 |
const Instr goto_ = emit_add_instr(emit, Goto); |
|
1452 |
12 |
goto_->m_val = index; |
|
1453 |
12 |
op->m_val = emit_code_size(emit); |
|
1454 |
} |
||
1455 |
26 |
return GW_OK; |
|
1456 |
} |
||
1457 |
|||
1458 |
26 |
ANN static m_bool emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt) { |
|
1459 |
26 |
const m_uint index = emit_code_size(emit); |
|
1460 |
26 |
emit_push_stack(emit); |
|
1461 |
26 |
const m_bool ret = _emit_stmt_flow(emit, stmt, index); |
|
1462 |
26 |
emit_pop_stack(emit, index); |
|
1463 |
26 |
return ret; |
|
1464 |
} |
||
1465 |
|||
1466 |
10 |
ANN static m_bool variadic_state(const Emitter emit, const Stmt_VarLoop stmt, const m_uint status) { |
|
1467 |
10 |
regpushi(emit, status); |
|
1468 |
✗✓ | 10 |
CHECK_BB(emit_exp(emit, stmt->exp)) |
1469 |
10 |
emit_add_instr(emit, SetObj); |
|
1470 |
10 |
const Instr member = emit_add_instr(emit, DotMember4); |
|
1471 |
10 |
member->m_val = SZ_INT; |
|
1472 |
10 |
emit_add_instr(emit, int_r_assign); |
|
1473 |
10 |
regpop(emit, SZ_INT); |
|
1474 |
10 |
return GW_OK; |
|
1475 |
} |
||
1476 |
|||
1477 |
5 |
ANN static m_bool emit_stmt_varloop(const Emitter emit, const Stmt_VarLoop stmt) { |
|
1478 |
✗✓ | 5 |
CHECK_BB(variadic_state(emit, stmt, 1)) |
1479 |
✗✓ | 5 |
CHECK_BB(emit_exp(emit, stmt->exp)) |
1480 |
5 |
const Instr member = emit_add_instr(emit, DotMember4); |
|
1481 |
5 |
member->m_val = SZ_INT*2; |
|
1482 |
5 |
const Instr instr = emit_add_instr(emit, BranchEqInt); |
|
1483 |
5 |
const m_uint pc = emit_code_size(emit); |
|
1484 |
5 |
emit_stmt(emit, stmt->body, 1); |
|
1485 |
✗✓ | 5 |
CHECK_BB(emit_exp(emit, stmt->exp)) |
1486 |
5 |
emit_vararg_end(emit, pc); |
|
1487 |
5 |
instr->m_val = emit_code_size(emit); |
|
1488 |
✗✓ | 5 |
CHECK_BB(variadic_state(emit, stmt, 0)) |
1489 |
5 |
instr->m_val = emit_code_size(emit); |
|
1490 |
5 |
return GW_OK; |
|
1491 |
} |
||
1492 |
|||
1493 |
10 |
ANN static m_bool _emit_stmt_for(const Emitter emit, const Stmt_For stmt, m_uint *action_index) { |
|
1494 |
✗✓ | 10 |
CHECK_BB(emit_stmt(emit, stmt->c1, 1)) |
1495 |
10 |
const m_uint index = emit_code_size(emit); |
|
1496 |
✗✓ | 10 |
DECL_OB(const Instr, op, = emit_flow(emit, stmt->c2->d.stmt_exp.val)) |
1497 |
✗✓ | 10 |
CHECK_BB(scoped_stmt(emit, stmt->body, 1)) |
1498 |
10 |
*action_index = emit_code_size(emit); |
|
1499 |
✓✓ | 10 |
if(stmt->c3) { |
1500 |
✗✓ | 9 |
CHECK_BB(emit_exp(emit, stmt->c3)) |
1501 |
9 |
pop_exp(emit, stmt->c3); |
|
1502 |
} |
||
1503 |
10 |
const Instr _goto = emit_add_instr(emit, Goto); |
|
1504 |
10 |
_goto->m_val = index; |
|
1505 |
10 |
op->m_val = emit_code_size(emit); |
|
1506 |
10 |
return GW_OK; |
|
1507 |
} |
||
1508 |
|||
1509 |
10 |
ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) { |
|
1510 |
10 |
emit_push_stack(emit); |
|
1511 |
10 |
m_uint action_index = 0; |
|
1512 |
10 |
const m_bool ret = _emit_stmt_for(emit, stmt, &action_index); |
|
1513 |
10 |
emit_pop_stack(emit, action_index); |
|
1514 |
10 |
return ret; |
|
1515 |
} |
||
1516 |
|||
1517 |
4 |
ANN static Instr emit_stmt_autoptr_init(const Emitter emit, const Type type) { |
|
1518 |
4 |
const Instr new_obj = emit_add_instr(emit, ObjectInstantiate); |
|
1519 |
4 |
new_obj->m_val2 = (m_uint)type; |
|
1520 |
4 |
(void)emit_addref(emit, 0); |
|
1521 |
4 |
regpop(emit, SZ_INT); |
|
1522 |
4 |
return emit_add_instr(emit, Reg2Mem); |
|
1523 |
} |
||
1524 |
|||
1525 |
10 |
ANN static m_bool _emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt, m_uint *end_pc) { |
|
1526 |
10 |
const Instr s1 = emit_add_instr(emit, MemSetImm); |
|
1527 |
✓✓ | 10 |
Instr cpy = stmt->is_ptr ? emit_stmt_autoptr_init(emit, stmt->v->type) : NULL; |
1528 |
10 |
emit_local(emit, emit->gwion->type[et_int]); |
|
1529 |
10 |
const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); |
|
1530 |
10 |
emit_local(emit, emit->gwion->type[et_int]); |
|
1531 |
10 |
stmt->v->from->offset = offset + SZ_INT; |
|
1532 |
10 |
const m_uint ini_pc = emit_code_size(emit); |
|
1533 |
10 |
emit_except(emit, stmt->exp->info->type); |
|
1534 |
✓✓ | 10 |
const Instr loop = emit_add_instr(emit, stmt->is_ptr ? AutoLoopPtr : AutoLoop); |
1535 |
10 |
const Instr end = emit_add_instr(emit, BranchEqInt); |
|
1536 |
10 |
const m_bool ret = scoped_stmt(emit, stmt->body, 1); |
|
1537 |
10 |
*end_pc = emit_code_size(emit); |
|
1538 |
✓✓ | 10 |
if(stmt->is_ptr) { |
1539 |
4 |
loop->m_val2 = (m_uint)stmt->v->type; |
|
1540 |
4 |
cpy->m_val = stmt->v->from->offset; |
|
1541 |
} |
||
1542 |
10 |
const Instr tgt = emit_add_instr(emit, Goto); |
|
1543 |
10 |
end->m_val = emit_code_size(emit); |
|
1544 |
10 |
tgt->m_val = ini_pc; |
|
1545 |
10 |
s1->m_val = loop->m_val = offset; |
|
1546 |
10 |
return ret; |
|
1547 |
} |
||
1548 |
|||
1549 |
10 |
ANN static m_bool emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt) { |
|
1550 |
✗✓ | 10 |
CHECK_BB(emit_exp(emit, stmt->exp)) |
1551 |
10 |
emit_push_stack(emit); |
|
1552 |
10 |
m_uint end_pc = 0; |
|
1553 |
10 |
const m_bool ret = _emit_stmt_auto(emit, stmt, &end_pc); |
|
1554 |
10 |
emit_pop_stack(emit, end_pc); |
|
1555 |
10 |
regpop(emit, SZ_INT); |
|
1556 |
10 |
return ret; |
|
1557 |
} |
||
1558 |
|||
1559 |
7 |
ANN static m_bool _emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt, m_uint *index) { |
|
1560 |
✗✓ | 7 |
CHECK_BB(emit_exp_pop_next(emit, stmt->cond)) |
1561 |
7 |
const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); |
|
1562 |
7 |
const Instr tomem = emit_add_instr(emit, Reg2Mem); |
|
1563 |
7 |
tomem->m_val = offset; |
|
1564 |
7 |
tomem->m_val2 = -SZ_INT; |
|
1565 |
7 |
regpop(emit, SZ_INT); |
|
1566 |
7 |
*index = emit_code_size(emit); |
|
1567 |
7 |
const Instr cpy = emit_add_instr(emit, RegPushMem4); |
|
1568 |
7 |
cpy->m_val = offset; |
|
1569 |
7 |
emit_add_instr(emit, int_post_dec); |
|
1570 |
7 |
const Instr op = emit_add_instr(emit, BranchEqInt); |
|
1571 |
✗✓ | 7 |
CHECK_BB(scoped_stmt(emit, stmt->body, 1)) |
1572 |
7 |
const Instr _goto = emit_add_instr(emit, Goto); |
|
1573 |
7 |
_goto->m_val = *index; |
|
1574 |
7 |
op->m_val = emit_code_size(emit); |
|
1575 |
7 |
return GW_OK; |
|
1576 |
} |
||
1577 |
|||
1578 |
7 |
ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { |
|
1579 |
7 |
emit_push_stack(emit); |
|
1580 |
7 |
m_uint index = 0; |
|
1581 |
7 |
const m_bool ret = _emit_stmt_loop(emit, stmt, &index); |
|
1582 |
7 |
emit_pop_stack(emit, index); |
|
1583 |
7 |
return ret; |
|
1584 |
} |
||
1585 |
|||
1586 |
8 |
ANN static m_bool emit_stmt_jump(const Emitter emit, const Stmt_Jump stmt) { |
|
1587 |
✓✓ | 8 |
if(!stmt->is_label) |
1588 |
3 |
stmt->data.instr = emit_add_instr(emit, Goto); |
|
1589 |
else { |
||
1590 |
assert(stmt->data.v.ptr); |
||
1591 |
5 |
const m_uint size = vector_size(&stmt->data.v); |
|
1592 |
✓✓ | 5 |
if(!size) |
1593 |
//return GW_OK; |
||
1594 |
1 |
ERR_B(stmt_self(stmt)->pos, _("label '%s' defined but not used."), s_name(stmt->name)) |
|
1595 |
LOOP_OPTIM |
||
1596 |
✓✓ | 11 |
for(m_uint i = size + 1; --i;) { |
1597 |
4 |
const Stmt_Jump label = (Stmt_Jump)vector_at(&stmt->data.v, i - 1); |
|
1598 |
✓✓ | 4 |
if(!label->data.instr) |
1599 |
1 |
ERR_B(stmt_self(label)->pos, _("you are trying to use a upper label.")) |
|
1600 |
3 |
label->data.instr->m_val = emit_code_size(emit); |
|
1601 |
} |
||
1602 |
} |
||
1603 |
6 |
return GW_OK; |
|
1604 |
} |
||
1605 |
|||
1606 |
15 |
ANN static m_bool emit_type_def(const Emitter emit, const Type_Def tdef) { |
|
1607 |
✓✓ | 15 |
return tdef->type->e->def ? emit_class_def(emit, tdef->type->e->def) : GW_OK; |
1608 |
} |
||
1609 |
|||
1610 |
5 |
ANN static m_bool emit_enum_def(const Emitter emit, const Enum_Def edef) { |
|
1611 |
LOOP_OPTIM |
||
1612 |
✓✓ | 18 |
for(m_uint i = 0; i < vector_size(&edef->values); ++i) { |
1613 |
13 |
const Value v = (Value)vector_at(&edef->values, i); |
|
1614 |
✓✓ | 13 |
if(!emit->env->class_def) { |
1615 |
7 |
ALLOC_PTR(emit->gwion->mp, addr, m_uint, i); |
|
1616 |
7 |
v->from->offset = emit_local(emit, emit->gwion->type[et_int]); |
|
1617 |
7 |
v->d.ptr = addr; |
|
1618 |
} else |
||
1619 |
6 |
*(m_bit*)(emit->env->class_def->nspc->info->class_data + v->from->offset) = i; |
|
1620 |
} |
||
1621 |
5 |
return GW_OK; |
|
1622 |
} |
||
1623 |
|||
1624 |
34 |
ANN void emit_union_offset(Decl_List l, const m_uint o) { |
|
1625 |
do { |
||
1626 |
34 |
Var_Decl_List v = l->self->d.exp_decl.list; |
|
1627 |
34 |
do v->self->value->from->offset = o; |
|
1628 |
✗✓ | 34 |
while((v = v->next)); |
1629 |
✓✓ | 34 |
} while((l = l->next)); |
1630 |
18 |
} |
|
1631 |
|||
1632 |
10 |
ANN static inline void union_allocdata(MemPool mp, const Union_Def udef) { |
|
1633 |
✓✓ | 10 |
const Nspc nspc = (udef->xid ? udef->value->type : udef->type)->nspc; |
1634 |
10 |
nspc_allocdata(mp, nspc); |
|
1635 |
10 |
nspc->info->offset = udef->s; |
|
1636 |
10 |
} |
|
1637 |
|||
1638 |
18 |
ANN static m_bool emit_union_def(const Emitter emit, const Union_Def udef) { |
|
1639 |
✓✓ | 18 |
if(tmpl_base(udef->tmpl)) |
1640 |
3 |
return GW_OK; |
|
1641 |
15 |
Decl_List l = udef->l; |
|
1642 |
15 |
m_uint scope = emit->env->scope->depth; |
|
1643 |
15 |
const m_bool global = GET_FLAG(udef, global); |
|
1644 |
✓✓ | 15 |
if(udef->xid) { |
1645 |
6 |
union_allocdata(emit->gwion->mp, udef); |
|
1646 |
12 |
Type_Decl *type_decl = new_type_decl(emit->gwion->mp, |
|
1647 |
6 |
udef->xid, loc_cpy(emit->gwion->mp, udef->pos)); |
|
1648 |
6 |
type_decl->flag = udef->flag; |
|
1649 |
6 |
const Var_Decl var_decl = new_var_decl(emit->gwion->mp, udef->xid, NULL, loc_cpy(emit->gwion->mp, udef->pos)); |
|
1650 |
6 |
const Var_Decl_List var_decl_list = new_var_decl_list(emit->gwion->mp, var_decl, NULL); |
|
1651 |
6 |
const Exp exp = new_exp_decl(emit->gwion->mp, type_decl, var_decl_list); |
|
1652 |
6 |
exp->d.exp_decl.type = udef->value->type; |
|
1653 |
6 |
var_decl->value = udef->value; |
|
1654 |
6 |
const m_bool ret = emit_exp_decl(emit, &exp->d.exp_decl); |
|
1655 |
6 |
free_exp(emit->gwion->mp, exp); |
|
1656 |
✗✓ | 6 |
CHECK_BB(ret) |
1657 |
✓✓ | 6 |
if(global) { |
1658 |
1 |
const M_Object o = new_object(emit->gwion->mp, NULL, udef->value->type); |
|
1659 |
1 |
udef->value->d.ptr = (m_uint*)o; |
|
1660 |
1 |
SET_FLAG(udef->value, builtin); |
|
1661 |
1 |
UNSET_FLAG(udef->value, union); |
|
1662 |
} |
||
1663 |
6 |
scope = emit_push_type(emit, udef->value->type); |
|
1664 |
✓✓ | 9 |
} else if(udef->type_xid) { |
1665 |
4 |
union_allocdata(emit->gwion->mp, udef); |
|
1666 |
4 |
scope = emit_push_type(emit, udef->type); |
|
1667 |
✓✓ | 5 |
} else if(global) { |
1668 |
// TODO: use mpool allocation |
||
1669 |
1 |
void* ptr = (void*)xcalloc(1, udef->s); |
|
1670 |
1 |
l = udef->l; |
|
1671 |
1 |
udef->value->d.ptr = ptr; |
|
1672 |
1 |
SET_FLAG(udef->value, enum); |
|
1673 |
1 |
SET_FLAG(udef->value, dtor); |
|
1674 |
do { |
||
1675 |
2 |
Var_Decl_List list = l->self->d.exp_decl.list; |
|
1676 |
2 |
list->self->value->d.ptr = ptr; |
|
1677 |
2 |
SET_FLAG(list->self->value, union); |
|
1678 |
✓✓ | 2 |
} while((l = l->next)); |
1679 |
1 |
SET_FLAG(udef->l->self->d.exp_decl.list->self->value, enum); |
|
1680 |
1 |
SET_FLAG(udef->l->self->d.exp_decl.list->self->value, dtor); |
|
1681 |
} |
||
1682 |
✓✓ | 15 |
if(udef->xid) |
1683 |
6 |
regpop(emit, SZ_INT); |
|
1684 |
15 |
emit_union_offset(udef->l, udef->o); |
|
1685 |
✓✓✓✓ ✓✓ |
15 |
if(udef->xid || udef->type_xid || global) |
1686 |
11 |
emit_pop(emit, scope); |
|
1687 |
15 |
union_flag(udef, ae_flag_emit); |
|
1688 |
15 |
return GW_OK; |
|
1689 |
} |
||
1690 |
|||
1691 |
1991 |
ANN static m_bool emit_stmt_exp(const Emitter emit, const struct Stmt_Exp_* exp) { |
|
1692 |
✓✓ | 1991 |
return exp->val ? emit_exp(emit, exp->val) : GW_OK; |
1693 |
} |
||
1694 |
|||
1695 |
7 |
ANN static m_bool emit_case_head(const Emitter emit, const Exp base, |
|
1696 |
const Exp e, const Symbol op, const Vector v) { |
||
1697 |
✗✓ | 7 |
CHECK_BB(emit_exp(emit, base)) |
1698 |
✗✓ | 7 |
CHECK_BB(emit_exp_pop_next(emit, e)) |
1699 |
7 |
const m_int size = -exp_size(e); |
|
1700 |
7 |
emit_exp_addref(emit, base, -exp_totalsize(base) - size); |
|
1701 |
7 |
emit_exp_addref1(emit, e, -size); |
|
1702 |
7 |
const Exp_Binary bin = { .lhs=base, .rhs=e, .op=op }; |
|
1703 |
7 |
struct ExpInfo_ info = { .nspc=e->info->nspc }; |
|
1704 |
7 |
struct Exp_ ebin = { .d={.exp_binary=bin}, .info=&info }; |
|
1705 |
21 |
struct Op_Import opi = { .op=op, .lhs=base->info->type, .rhs=e->info->type, |
|
1706 |
14 |
.data=(uintptr_t)&ebin.d.exp_binary, .pos=e->pos, .op_type=op_binary }; |
|
1707 |
✗✓ | 7 |
CHECK_BB(op_emit_bool(emit, &opi)) |
1708 |
7 |
const Instr instr = emit_add_instr(emit, BranchEqInt); |
|
1709 |
7 |
vector_add(v, (vtype)instr); |
|
1710 |
7 |
return GW_OK; |
|
1711 |
} |
||
1712 |
|||
1713 |
10 |
ANN static m_bool emit_case_body(const Emitter emit, const struct Stmt_Match_* stmt) { |
|
1714 |
✓✓ | 10 |
const Instr when = stmt->when ? emit_flow(emit, stmt->when) : NULL; |
1715 |
✓✓ | 10 |
if(stmt->when) |
1716 |
✗✓ | 4 |
CHECK_OB(when) |
1717 |
✗✓ | 10 |
CHECK_BB(emit_stmt_list(emit, stmt->list)) |
1718 |
10 |
const Instr instr = emit_add_instr(emit, Goto); |
|
1719 |
10 |
vector_add(&emit->env->scope->match->vec, (vtype)instr); |
|
1720 |
✓✓ | 10 |
if(when) |
1721 |
4 |
when->m_val = emit_code_size(emit); |
|
1722 |
10 |
return GW_OK; |
|
1723 |
} |
||
1724 |
|||
1725 |
1 |
ANN static m_bool case_value(const Emitter emit, const Exp base, const Exp e) { |
|
1726 |
1 |
const Value v = e->d.prim.value; |
|
1727 |
1 |
v->from->offset = emit_local(emit, base->info->type); |
|
1728 |
✗✓ | 1 |
CHECK_BB(emit_exp(emit, base)) |
1729 |
1 |
emit_exp_addref(emit, base, -exp_totalsize(base)); |
|
1730 |
1 |
regpop(emit, base->info->type->size); |
|
1731 |
1 |
const Instr instr = emit_add_instr(emit, Reg2Mem4); |
|
1732 |
1 |
instr->m_val = v->from->offset; |
|
1733 |
1 |
instr->m_val2 = base->info->type->size; |
|
1734 |
1 |
return GW_OK; |
|
1735 |
} |
||
1736 |
|||
1737 |
|||
1738 |
#define CASE_PASS (Symbol)1 |
||
1739 |
10 |
ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e) { |
|
1740 |
✓✗ | 10 |
if(e->exp_type == ae_exp_primary) { |
1741 |
✓✓ | 10 |
if(e->d.prim.prim_type == ae_prim_id) { |
1742 |
✓✓ | 3 |
if(e->d.prim.d.var == insert_symbol("_")) |
1743 |
2 |
return CASE_PASS; |
|
1744 |
✓✗ | 1 |
if(!nspc_lookup_value1(emit->env->curr, e->d.prim.d.var)) { |
1745 |
✗✓ | 1 |
CHECK_BO(case_value(emit, base, e)) |
1746 |
1 |
return CASE_PASS; |
|
1747 |
} |
||
1748 |
} |
||
1749 |
} |
||
1750 |
7 |
return insert_symbol("=="); |
|
1751 |
} |
||
1752 |
|||
1753 |
10 |
ANN static m_bool _emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt, |
|
1754 |
const Vector v) { |
||
1755 |
10 |
Exp e = stmt->cond; |
|
1756 |
10 |
const Map map = &emit->env->scope->match->map; |
|
1757 |
✓✓✓✗ |
20 |
for(m_uint i = 0; i < map_size(map) && e; e = e->next, ++i) { |
1758 |
10 |
const Exp base = (Exp)VKEY(map, i); |
|
1759 |
10 |
const Symbol op = case_op(emit, base, e); |
|
1760 |
✓✓ | 10 |
if(op != CASE_PASS) |
1761 |
✗✓ | 7 |
CHECK_BB(emit_case_head(emit, base, e, op, v)) |
1762 |
} |
||
1763 |
✗✓ | 10 |
CHECK_BB(emit_case_body(emit, stmt)) |
1764 |
10 |
return GW_OK; |
|
1765 |
} |
||
1766 |
|||
1767 |
10 |
ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt) { |
|
1768 |
10 |
emit_push_scope(emit); |
|
1769 |
struct Vector_ v; |
||
1770 |
10 |
vector_init(&v); |
|
1771 |
10 |
const m_bool ret = _emit_stmt_match_case(emit, stmt, &v); |
|
1772 |
10 |
emit_pop_scope(emit); |
|
1773 |
✓✓ | 17 |
for(m_uint i = 0; i < vector_size(&v); ++i) { |
1774 |
7 |
const Instr instr = (Instr)vector_at(&v, i); |
|
1775 |
7 |
instr->m_val = emit_code_size(emit); |
|
1776 |
} |
||
1777 |
10 |
vector_release(&v); |
|
1778 |
10 |
return ret; |
|
1779 |
} |
||
1780 |
|||
1781 |
6 |
ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) { |
|
1782 |
6 |
const Vector vec = &match->vec; |
|
1783 |
✓✓ | 16 |
for(m_uint i = 0; i < vector_size(vec); ++i) { |
1784 |
10 |
const Instr instr = (Instr)VPTR(vec, i); |
|
1785 |
10 |
instr->m_val = pc; |
|
1786 |
} |
||
1787 |
6 |
vector_release(vec); |
|
1788 |
6 |
} |
|
1789 |
|||
1790 |
10 |
ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list) { |
|
1791 |
✗✓ | 10 |
do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match)) |
1792 |
✓✓ | 10 |
while((list = list->next)); |
1793 |
6 |
return GW_OK; |
|
1794 |
} |
||
1795 |
|||
1796 |
6 |
ANN static m_bool emit_match(const Emitter emit, const struct Stmt_Match_* stmt) { |
|
1797 |
✓✓ | 6 |
if(stmt->where) |
1798 |
✗✓ | 2 |
CHECK_BB(emit_stmt(emit, stmt->where, 1)) |
1799 |
6 |
MATCH_INI(emit->env->scope) |
|
1800 |
6 |
vector_init(&m.vec); |
|
1801 |
6 |
const m_bool ret = emit_stmt_cases(emit, stmt->list); |
|
1802 |
6 |
match_unvec(&m, emit_code_size(emit)); |
|
1803 |
6 |
MATCH_END(emit->env->scope) |
|
1804 |
6 |
return ret; |
|
1805 |
} |
||
1806 |
|||
1807 |
6 |
ANN static m_bool emit_stmt_match(const Emitter emit, const struct Stmt_Match_* stmt) { |
|
1808 |
6 |
emit_push_scope(emit); |
|
1809 |
6 |
const m_bool ret = emit_match(emit, stmt); |
|
1810 |
6 |
emit_pop_scope(emit); |
|
1811 |
6 |
return ret; |
|
1812 |
} |
||
1813 |
|||
1814 |
1 |
ANN static m_bool emit_stmt_pp(const Emitter emit, const struct Stmt_PP_* stmt) { |
|
1815 |
✓✗ | 1 |
if(stmt->pp_type == ae_pp_pragma) { |
1816 |
✓✗ | 1 |
if(!strncmp(stmt->data, "memoize", strlen("memoize"))) |
1817 |
1 |
emit->info->memoize = strtol(stmt->data + 7, NULL, 10); |
|
1818 |
} |
||
1819 |
1 |
return GW_OK; |
|
1820 |
} |
||
1821 |
|||
1822 |
#define emit_stmt_while emit_stmt_flow |
||
1823 |
#define emit_stmt_until emit_stmt_flow |
||
1824 |
DECL_STMT_FUNC(emit, m_bool , Emitter) |
||
1825 |
|||
1826 |
2524 |
ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { |
|
1827 |
✓✓ | 2524 |
CHECK_BB(emit_stmt_func[stmt->stmt_type](emit, &stmt->d)) |
1828 |
✓✓✓✓ ✓✓ |
2520 |
if(pop && stmt->stmt_type == ae_stmt_exp && stmt->d.stmt_exp.val) { |
1829 |
1974 |
pop_exp(emit, stmt->d.stmt_exp.val); |
|
1830 |
} |
||
1831 |
2520 |
return GW_OK; |
|
1832 |
} |
||
1833 |
|||
1834 |
2162 |
ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List l) { |
|
1835 |
✓✓ | 2162 |
do CHECK_BB(emit_stmt(emit, l->stmt, 1)) |
1836 |
✓✓ | 2158 |
while((l = l->next)); |
1837 |
858 |
return GW_OK; |
|
1838 |
} |
||
1839 |
|||
1840 |
526 |
ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member) { |
|
1841 |
2104 |
struct Op_Import opi = { .op=insert_symbol("@dot"), .lhs=member->t_base, |
|
1842 |
1578 |
.rhs=exp_self(member)->info->type, .data=(uintptr_t)member, .pos=exp_self(member)->pos, .op_type=op_dot }; |
|
1843 |
526 |
return op_emit_bool(emit, &opi); |
|
1844 |
} |
||
1845 |
|||
1846 |
82 |
ANN static inline void emit_func_def_global(const Emitter emit, const Value value) { |
|
1847 |
82 |
const Instr set_mem = emit_add_instr(emit, MemSetImm); |
|
1848 |
82 |
set_mem->m_val = value->from->offset; |
|
1849 |
82 |
set_mem->m_val2 = (m_uint)value->d.func_ref->code; |
|
1850 |
82 |
} |
|
1851 |
|||
1852 |
221 |
ANN static void emit_func_def_init(const Emitter emit, const Func func) { |
|
1853 |
221 |
const Type t = emit->env->class_def; |
|
1854 |
✓✓ | 221 |
char c[(t ? strlen(t->name) + 1 : 0) + strlen(func->name) + 6]; |
1855 |
✓✓✓✓ |
221 |
sprintf(c, "%s%s%s(...)", t ? t->name : "", t ? "." : "", func->name); |
1856 |
221 |
emit_push_code(emit, c); |
|
1857 |
221 |
} |
|
1858 |
|||
1859 |
157 |
ANN static void emit_func_def_args(const Emitter emit, Arg_List a) { |
|
1860 |
do { |
||
1861 |
157 |
const Type type = a->var_decl->value->type; |
|
1862 |
157 |
emit->code->stack_depth += type->size; |
|
1863 |
157 |
a->var_decl->value->from->offset = emit_local(emit, type); |
|
1864 |
✓✓ | 157 |
} while((a = a->next)); |
1865 |
122 |
} |
|
1866 |
|||
1867 |
221 |
ANN static void emit_func_def_ensure(const Emitter emit, const Func_Def fdef) { |
|
1868 |
221 |
const m_uint size = fdef->base->ret_type->size; |
|
1869 |
✓✓ | 221 |
if(size) { |
1870 |
68 |
const Instr instr = emit_kind(emit, size, 0, regpushimm); |
|
1871 |
68 |
instr->m_val2 = size; |
|
1872 |
} |
||
1873 |
221 |
vector_add(&emit->code->stack_return, (vtype)emit_add_instr(emit, Goto)); |
|
1874 |
221 |
} |
|
1875 |
|||
1876 |
221 |
ANN static void emit_func_def_return(const Emitter emit) { |
|
1877 |
221 |
const m_uint val = emit_code_size(emit); |
|
1878 |
LOOP_OPTIM |
||
1879 |
✓✓ | 700 |
for(m_uint i = vector_size(&emit->code->stack_return) + 1; --i; ) { |
1880 |
258 |
const Instr instr = (Instr)vector_at(&emit->code->stack_return, i-1); |
|
1881 |
258 |
instr->m_val = val; |
|
1882 |
} |
||
1883 |
221 |
vector_clear(&emit->code->stack_return); |
|
1884 |
✓✓✓✗ |
221 |
if(emit->info->memoize && GET_FLAG(emit->env->func, pure)) { |
1885 |
1 |
const Instr instr = emit_add_instr(emit, MemoizeStore); |
|
1886 |
1 |
instr->m_val = emit->env->func->def->stack_depth; |
|
1887 |
} |
||
1888 |
221 |
} |
|
1889 |
|||
1890 |
11 |
ANN static VM_Code emit_internal(const Emitter emit, const Func f) { |
|
1891 |
✓✓ | 11 |
if(f->def->base->xid == insert_symbol("@dtor")) { |
1892 |
6 |
emit->env->class_def->nspc->dtor = f->code = finalyze(emit, DTOR_EOC); |
|
1893 |
6 |
ADD_REF(f->code) |
|
1894 |
6 |
return f->code; |
|
1895 |
✓✓ | 5 |
} else if(f->def->base->xid == insert_symbol("@gack")) { |
1896 |
2 |
regpop(emit, SZ_INT + f->value_ref->from->owner_class->size); |
|
1897 |
2 |
const Instr instr = emit_add_instr(emit, RegPushMem); |
|
1898 |
2 |
instr->m_val = SZ_INT; |
|
1899 |
2 |
f->code = finalyze(emit, FuncReturn); |
|
1900 |
2 |
return emit->env->class_def->e->gack = f->code; |
|
1901 |
} |
||
1902 |
3 |
return finalyze(emit, FuncReturn); |
|
1903 |
} |
||
1904 |
|||
1905 |
221 |
ANN static VM_Code emit_func_def_code(const Emitter emit, const Func func) { |
|
1906 |
✓✓ | 221 |
if(GET_FLAG(func->def, typedef)) |
1907 |
11 |
return emit_internal(emit, func); |
|
1908 |
else |
||
1909 |
210 |
return finalyze(emit, FuncReturn); |
|
1910 |
} |
||
1911 |
|||
1912 |
221 |
ANN static m_bool emit_func_def_body(const Emitter emit, const Func_Def fdef) { |
|
1913 |
✓✓ | 221 |
if(fdef->base->args) |
1914 |
122 |
emit_func_def_args(emit, fdef->base->args); |
|
1915 |
✓✓ | 221 |
if(GET_FLAG(fdef, variadic)) |
1916 |
8 |
stack_alloc(emit); |
|
1917 |
✓✗ | 221 |
if(fdef->d.code) |
1918 |
✗✓ | 221 |
CHECK_BB(scoped_stmt(emit, fdef->d.code, 1)) |
1919 |
221 |
emit_func_def_ensure(emit, fdef); |
|
1920 |
221 |
return GW_OK; |
|
1921 |
} |
||
1922 |
|||
1923 |
1 |
ANN static Instr me_top(MemoizeEmitter *me) { |
|
1924 |
1 |
const Instr idx = emit_add_instr(me->emit, MemSetImm); |
|
1925 |
1 |
idx->m_val = me->offset; |
|
1926 |
1 |
const Instr pc = emit_add_instr(me->emit, MemSetImm); |
|
1927 |
1 |
pc->m_val = me->offset + SZ_INT; |
|
1928 |
1 |
return pc; |
|
1929 |
} |
||
1930 |
|||
1931 |
1 |
ANN static void me_ini(MemoizeEmitter *me) { |
|
1932 |
1 |
const Instr ini = emit_add_instr(me->emit, MemoizeIni); |
|
1933 |
1 |
ini->m_val = me->offset; |
|
1934 |
1 |
ini->m_val2 = me->fdef->stack_depth + me->fdef->base->ret_type->size; |
|
1935 |
1 |
} |
|
1936 |
|||
1937 |
1 |
ANN static void me_end(MemoizeEmitter *me, const m_uint pc) { |
|
1938 |
✓✓ | 2 |
for(m_uint i = 0; i < vector_size(&me->branch); ++i) |
1939 |
1 |
((Instr)vector_at(&me->branch, i))->m_val = pc; |
|
1940 |
1 |
} |
|
1941 |
|||
1942 |
1 |
ANN static void me_bottom(MemoizeEmitter *me, const m_uint pc) { |
|
1943 |
1 |
const Instr idx = emit_add_instr(me->emit, RegPushMem4); |
|
1944 |
1 |
idx->m_val = me->offset; |
|
1945 |
1 |
emit_add_instr(me->emit, int_pre_inc); |
|
1946 |
1 |
regpop(me->emit, SZ_INT); |
|
1947 |
1 |
const Instr loop = emit_add_instr(me->emit, Goto); |
|
1948 |
1 |
loop->m_val = pc; |
|
1949 |
1 |
} |
|
1950 |
|||
1951 |
1 |
ANN static void me_ret(MemoizeEmitter *me) { |
|
1952 |
1 |
const Instr instr = emit_kind(me->emit, me->fdef->base->ret_type->size, 0, regpushmem); |
|
1953 |
1 |
instr->m_val = (me->offset + SZ_INT)*2; |
|
1954 |
1 |
emit_add_instr(me->emit, FuncReturn); |
|
1955 |
1 |
} |
|
1956 |
|||
1957 |
1 |
ANN static m_bool me_run(MemoizeEmitter *me, const m_uint pc) { |
|
1958 |
1 |
me_ini(me); |
|
1959 |
✓✗ | 1 |
if(me->fdef->base->args) |
1960 |
✗✓ | 1 |
CHECK_BB(me_arg(me)) |
1961 |
1 |
me_ret(me); |
|
1962 |
1 |
me_end(me, emit_code_size(me->emit)); |
|
1963 |
1 |
me_bottom(me, pc); |
|
1964 |
1 |
return GW_OK; |
|
1965 |
} |
||
1966 |
|||
1967 |
1 |
ANN static m_bool emit_memoize(const Emitter emit, const Func_Def fdef) { |
|
1968 |
1 |
MemoizeEmitter me = { .emit=emit, .fdef=fdef, .offset=fdef->stack_depth }; |
|
1969 |
1 |
const Instr pc = me_top(&me); |
|
1970 |
1 |
const m_uint top = emit_code_size(emit); |
|
1971 |
1 |
vector_init(&me.branch); |
|
1972 |
1 |
const m_bool ret = me_run(&me, top); |
|
1973 |
1 |
vector_release(&me.branch); |
|
1974 |
1 |
pc->m_val2 = emit_code_size(emit); |
|
1975 |
1 |
return ret; |
|
1976 |
} |
||
1977 |
|||
1978 |
221 |
ANN static m_bool emit_fdef(const Emitter emit, const Func_Def fdef) { |
|
1979 |
✓✓✓✗ |
221 |
if(emit->info->memoize && GET_FLAG(fdef->base->func, pure)) |
1980 |
✗✓ | 1 |
CHECK_BB(emit_memoize(emit, fdef)) |
1981 |
✗✓ | 221 |
CHECK_BB(emit_func_def_body(emit, fdef)) |
1982 |
221 |
emit_func_def_return(emit); |
|
1983 |
221 |
return GW_OK; |
|
1984 |
} |
||
1985 |
|||
1986 |
442 |
static ANN int fdef_is_file_global(const Emitter emit, const Func_Def fdef) { |
|
1987 |
✓✓ | 868 |
return isa(fdef->base->func->value_ref->type, emit->gwion->type[et_lambda]) < 0 && |
1988 |
✓✓✓✓ ✓✓✓✓ |
826 |
!emit->env->class_def && !GET_FLAG(fdef, global) && !fdef->base->tmpl && |
1989 |
166 |
!emit->env->scope->depth; |
|
1990 |
} |
||
1991 |
|||
1992 |
221 |
ANN static void emit_fdef_finish(const Emitter emit, const Func_Def fdef) { |
|
1993 |
221 |
const Func func = fdef->base->func; |
|
1994 |
221 |
func->code = emit_func_def_code(emit, func); |
|
1995 |
✓✓ | 221 |
if(fdef_is_file_global(emit, fdef)) |
1996 |
82 |
emit_func_def_global(emit, func->value_ref); |
|
1997 |
✓✓✓✗ |
221 |
if(emit->info->memoize && GET_FLAG(func, pure)) |
1998 |
1 |
func->code->memoize = memoize_ini(emit, func); |
|
1999 |
221 |
} |
|
2000 |
|||
2001 |
264 |
ANN static m_bool emit_func_def(const Emitter emit, const Func_Def f) { |
|
2002 |
264 |
const Func func = f->base->func; |
|
2003 |
264 |
const Func_Def fdef = func->def; |
|
2004 |
264 |
const Func former = emit->env->func; |
|
2005 |
✓✓✓✓ |
264 |
if(func->code || tmpl_base(fdef->base->tmpl)) |
2006 |
43 |
return GW_OK; |
|
2007 |
✓✓✗✓ ✗✗ |
221 |
if(SAFE_FLAG(emit->env->class_def, builtin) && GET_FLAG(emit->env->class_def, template)) |
2008 |
return GW_OK; |
||
2009 |
✓✓ | 221 |
if(fdef_is_file_global(emit, fdef)) |
2010 |
82 |
func->value_ref->from->offset = emit_local(emit, emit->gwion->type[et_int]); |
|
2011 |
221 |
emit_func_def_init(emit, func); |
|
2012 |
✓✓ | 221 |
if(GET_FLAG(func, member)) |
2013 |
92 |
stack_alloc_this(emit); |
|
2014 |
221 |
emit->env->func = func; |
|
2015 |
221 |
emit_push_scope(emit); |
|
2016 |
✓✓ | 221 |
if(!strcmp(s_name(fdef->base->xid), "@gack")) { |
2017 |
2 |
emit_local(emit, emit->gwion->type[et_int]); |
|
2018 |
2 |
const Instr instr = emit_add_instr(emit, MemSetImm); |
|
2019 |
2 |
instr->m_val = SZ_INT; |
|
2020 |
} |
||
2021 |
221 |
const m_bool ret = scanx_fdef(emit->env, emit, fdef, (_exp_func)emit_fdef); |
|
2022 |
221 |
emit_pop_scope(emit); |
|
2023 |
221 |
emit->env->func = former; |
|
2024 |
✓✗ | 221 |
if(ret > 0) |
2025 |
221 |
emit_fdef_finish(emit, fdef); |
|
2026 |
else |
||
2027 |
emit_pop_code(emit); |
||
2028 |
221 |
return ret; |
|
2029 |
} |
||
2030 |
|||
2031 |
#define emit_fptr_def dummy_func |
||
2032 |
932 |
HANDLE_SECTION_FUNC(emit, m_bool, Emitter) |
|
2033 |
|||
2034 |
139 |
ANN Code* emit_class_code(const Emitter emit, const m_str name) { |
|
2035 |
139 |
const m_uint len = strlen(name) + 7; |
|
2036 |
139 |
char c[len]; |
|
2037 |
139 |
snprintf(c, len, "class %s", name); |
|
2038 |
139 |
emit_push_code(emit, c); |
|
2039 |
139 |
stack_alloc_this(emit); |
|
2040 |
139 |
return emit->code; |
|
2041 |
} |
||
2042 |
|||
2043 |
6 |
ANN static m_bool emit_parent(const Emitter emit, const Class_Def cdef) { |
|
2044 |
6 |
const Type parent = cdef->base.type->e->parent; |
|
2045 |
✓✗ | 6 |
return !GET_FLAG(parent, emit) ? ensure_emit(emit, parent) : GW_OK; |
2046 |
} |
||
2047 |
|||
2048 |
30 |
ANN static inline m_bool emit_cdef(const Emitter emit, const Class_Def cdef) { |
|
2049 |
30 |
return scanx_cdef(emit->env, emit, cdef, |
|
2050 |
(_exp_func)emit_class_def, (_exp_func)emit_union_def); |
||
2051 |
} |
||
2052 |
|||
2053 |
139 |
ANN void emit_class_finish(const Emitter emit, const Nspc nspc) { |
|
2054 |
139 |
nspc->pre_ctor = finalyze(emit, FuncReturn); |
|
2055 |
139 |
SET_FLAG(nspc->pre_ctor, ctor); |
|
2056 |
139 |
} |
|
2057 |
|||
2058 |
6 |
ANN static m_bool cdef_parent(const Emitter emit, const Class_Def cdef) { |
|
2059 |
✓✓✓✗ |
6 |
if(cdef->base.tmpl && cdef->base.tmpl->list) |
2060 |
✗✓ | 4 |
CHECK_BB(template_push_types(emit->env, cdef->base.tmpl)) |
2061 |
6 |
const m_bool ret = emit_parent(emit, cdef); |
|
2062 |
✓✓✓✗ |
6 |
if(cdef->base.tmpl && cdef->base.tmpl->list) |
2063 |
4 |
nspc_pop_type(emit->gwion->mp, emit->env->curr); |
|
2064 |
6 |
return ret; |
|
2065 |
} |
||
2066 |
|||
2067 |
182 |
ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { |
|
2068 |
✓✓ | 182 |
if(tmpl_base(cdef->base.tmpl)) |
2069 |
19 |
return GW_OK; |
|
2070 |
163 |
const Type t = cdef->base.type; |
|
2071 |
✗✓ | 163 |
if(GET_FLAG(t, emit)) |
2072 |
return GW_OK; |
||
2073 |
163 |
SET_FLAG(t, emit); |
|
2074 |
✓✓✗✓ |
163 |
if(t->e->owner_class && !GET_FLAG(t->e->owner_class, emit)) |
2075 |
CHECK_BB(ensure_emit(emit, t->e->owner_class)) |
||
2076 |
✓✓✓✓ ✓✓ |
163 |
if(cdef->base.ext && t->e->parent->e->def && !GET_FLAG(t->e->parent, emit)) |
2077 |
✗✓ | 6 |
CHECK_BB(cdef_parent(emit, cdef)) |
2078 |
163 |
nspc_allocdata(emit->gwion->mp, t->nspc); |
|
2079 |
✓✓ | 163 |
if(cdef->body) { |
2080 |
139 |
emit_class_code(emit, t->name); |
|
2081 |
✓✗ | 139 |
if(scanx_body(emit->env, cdef, (_exp_func)emit_section, emit) > 0) |
2082 |
139 |
emit_class_finish(emit, t->nspc); |
|
2083 |
else { |
||
2084 |
free_code(emit->gwion->mp, emit->code); |
||
2085 |
emit_pop_code(emit); |
||
2086 |
return GW_ERROR; |
||
2087 |
} |
||
2088 |
} |
||
2089 |
163 |
return GW_OK; |
|
2090 |
} |
||
2091 |
|||
2092 |
4 |
ANN static inline void emit_free_code(const Emitter emit, Code* code) { |
|
2093 |
✓✓ | 4 |
if(vector_size(&code->instr)) |
2094 |
2 |
free_code_instr(&code->instr, emit->gwion); |
|
2095 |
4 |
free_code(emit->gwion->mp, code); |
|
2096 |
4 |
} |
|
2097 |
|||
2098 |
4 |
ANN static VM_Code emit_free_stack(const Emitter emit) { |
|
2099 |
LOOP_OPTIM |
||
2100 |
✗✓ | 8 |
for(m_uint i = vector_size(&emit->stack) + 1; --i;) |
2101 |
emit_free_code(emit, (Code*)vector_at(&emit->stack, i - 1)); |
||
2102 |
4 |
vector_clear(&emit->stack); |
|
2103 |
4 |
vector_clear(&emit->info->pure); |
|
2104 |
4 |
emit_free_code(emit, emit->code); |
|
2105 |
4 |
return NULL; |
|
2106 |
} |
||
2107 |
|||
2108 |
667 |
ANN static inline m_bool emit_ast_inner(const Emitter emit, Ast ast) { |
|
2109 |
✓✓ | 667 |
do CHECK_BB(emit_section(emit, ast->section)) |
2110 |
✓✓ | 663 |
while((ast = ast->next)); |
2111 |
397 |
return GW_OK; |
|
2112 |
} |
||
2113 |
|||
2114 |
401 |
ANN m_bool emit_ast(const Env env, Ast ast) { |
|
2115 |
401 |
const Emitter emit = env->gwion->emit; |
|
2116 |
401 |
emit->info->memoize = 0; |
|
2117 |
401 |
emit->code = new_code(emit, emit->env->name); |
|
2118 |
401 |
emit_push_scope(emit); |
|
2119 |
401 |
const m_bool ret = emit_ast_inner(emit, ast); |
|
2120 |
401 |
emit_pop_scope(emit); |
|
2121 |
✓✓ | 401 |
if(ret > 0) |
2122 |
397 |
emit->info->code = finalyze(emit, emit->info->finalyzer); |
|
2123 |
else |
||
2124 |
4 |
emit_free_stack(emit); |
|
2125 |
401 |
return ret; |
|
2126 |
} |
Generated by: GCOVR (Version 4.2) |