1 |
|
|
#include <stdlib.h> |
2 |
|
|
#include <string.h> |
3 |
|
|
#include "gwion_util.h" |
4 |
|
|
#include "gwion_ast.h" |
5 |
|
|
#include "gwion_env.h" |
6 |
|
|
#include "vm.h" |
7 |
|
|
#include "gwion.h" |
8 |
|
|
#include "instr.h" |
9 |
|
|
#include "object.h" |
10 |
|
|
#include "array.h" |
11 |
|
|
#include "emit.h" |
12 |
|
|
#include "operator.h" |
13 |
|
|
#include "import.h" |
14 |
|
|
#include "traverse.h" |
15 |
|
|
#include "parse.h" |
16 |
|
|
#include "gwi.h" |
17 |
|
|
#include "emit.h" |
18 |
|
|
|
19 |
|
|
struct M_Vector_ { |
20 |
|
|
m_bit* ptr; |
21 |
|
|
}; |
22 |
|
|
#define ARRAY_OFFSET SZ_INT * 4 |
23 |
|
|
#define ARRAY_PTR(array) (array->ptr + ARRAY_OFFSET) |
24 |
|
|
#define ARRAY_LEN(array) *(m_uint*)(array->ptr) |
25 |
|
|
#define ARRAY_SIZE(array) *(m_uint*)(array->ptr + SZ_INT) |
26 |
|
|
#define ARRAY_CAP(array) *(m_uint*)(array->ptr + SZ_INT*2) |
27 |
|
|
|
28 |
|
72 |
ANN m_uint m_vector_size(const M_Vector v) { |
29 |
|
72 |
return ARRAY_LEN(v); |
30 |
|
|
} |
31 |
|
|
|
32 |
|
505 |
M_Vector new_m_vector(MemPool p, const m_uint size, const m_uint len) { |
33 |
|
505 |
const M_Vector array = mp_calloc(p, M_Vector); |
34 |
|
505 |
const size_t sz = (ARRAY_OFFSET*SZ_INT) + (len*size); |
35 |
|
505 |
array->ptr = (m_bit*)xcalloc(1, sz); |
36 |
|
505 |
m_uint cap = 1; |
37 |
✓✓ |
2283 |
while(cap < len) |
38 |
|
1273 |
cap *= 2; |
39 |
|
505 |
ARRAY_CAP(array) = cap; |
40 |
|
505 |
ARRAY_SIZE(array) = size; |
41 |
|
505 |
ARRAY_LEN(array) = len; |
42 |
|
505 |
return array; |
43 |
|
|
} |
44 |
|
|
|
45 |
|
505 |
void free_m_vector(MemPool p, M_Vector a) { |
46 |
|
505 |
xfree(a->ptr); |
47 |
|
505 |
mp_free(p, M_Vector, a); |
48 |
|
505 |
} |
49 |
|
|
|
50 |
|
505 |
static DTOR(array_dtor) { |
51 |
|
505 |
const Type t = unflag_type(o->type_ref); |
52 |
✗✓ |
505 |
if(*(void**)(o->data + SZ_INT)) |
53 |
|
|
xfree(*(void**)(o->data + SZ_INT)); |
54 |
|
505 |
struct M_Vector_* a = ARRAY(o); |
55 |
✗✓ |
505 |
if(!a) |
56 |
|
|
return; |
57 |
✓✓ |
505 |
if(t->nspc->info->class_data_size) { |
58 |
✓✓ |
2526 |
for(m_uint i = 0; i < ARRAY_LEN(a); ++i) |
59 |
|
2072 |
(*(f_release**)t->nspc->info->class_data)(shred, array_base(t), ARRAY_PTR(a) + i * ARRAY_SIZE(a)); |
60 |
|
|
} |
61 |
|
505 |
free_m_vector(shred->info->mp, a); |
62 |
|
|
} |
63 |
|
|
|
64 |
|
505 |
ANN M_Object new_array(MemPool p, const Type t, const m_uint length) { |
65 |
|
505 |
const M_Object a = new_object(p, NULL, t); |
66 |
|
505 |
const m_uint depth = t->array_depth; |
67 |
✓✓ |
505 |
const m_uint size = depth > 1 ? SZ_INT : array_base(t)->size; |
68 |
|
505 |
ARRAY(a) = new_m_vector(p, size,length); |
69 |
|
505 |
return a; |
70 |
|
|
} |
71 |
|
|
|
72 |
|
52 |
ANN void m_vector_get(const M_Vector v, const m_uint i, void* c) { |
73 |
|
52 |
const m_uint size = ARRAY_SIZE(v); |
74 |
|
52 |
memcpy(c, ARRAY_PTR(v) + i * size, size); |
75 |
|
52 |
} |
76 |
|
|
|
77 |
|
4 |
ANN void m_vector_add(const M_Vector v, const void* data) { |
78 |
|
4 |
const m_uint size = ARRAY_SIZE(v); |
79 |
✓✗ |
4 |
if(++ARRAY_LEN(v) >= ARRAY_CAP(v)) { |
80 |
|
4 |
const m_uint cap = ARRAY_CAP(v) *=2; |
81 |
|
4 |
v->ptr = (m_bit*)xrealloc(v->ptr, ARRAY_OFFSET + cap * size); |
82 |
|
|
} |
83 |
|
4 |
memcpy(ARRAY_PTR(v) + (ARRAY_LEN(v) - 1) * size, data, size); |
84 |
|
4 |
} |
85 |
|
|
|
86 |
|
1 |
ANN void m_vector_add_front(const M_Vector v, const void* data) { |
87 |
|
1 |
const m_uint size = ARRAY_SIZE(v); |
88 |
✗✓ |
1 |
if(++ARRAY_LEN(v) >= ARRAY_CAP(v)) { |
89 |
|
|
const m_uint cap = ARRAY_CAP(v) *=2; |
90 |
|
|
v->ptr = (m_bit*)xrealloc(v->ptr, ARRAY_OFFSET + cap * size); |
91 |
|
|
} |
92 |
|
1 |
memmove(ARRAY_PTR(v) + size, ARRAY_PTR(v), ARRAY_LEN(v) * size); |
93 |
|
1 |
memmove(ARRAY_PTR(v), data, size); |
94 |
|
1 |
} |
95 |
|
|
|
96 |
|
463 |
ANN void m_vector_set(const M_Vector v, const m_uint i, const void* data) { |
97 |
|
463 |
const m_uint size = ARRAY_SIZE(v); |
98 |
|
463 |
memcpy(ARRAY_PTR(v) + i * size, data, size); |
99 |
|
463 |
} |
100 |
|
|
|
101 |
|
2 |
ANN void m_vector_rem(const M_Vector v, m_uint index) { |
102 |
|
2 |
const m_uint size = ARRAY_SIZE(v); |
103 |
✓✗ |
2 |
if(index < ARRAY_LEN(v) - 1) |
104 |
|
2 |
memmove(ARRAY_PTR(v) + index * size, ARRAY_PTR(v) + (index + 1) * size, |
105 |
|
2 |
(ARRAY_SIZE(v) - index - 1) *size); |
106 |
|
2 |
--ARRAY_LEN(v); |
107 |
✓✓ |
2 |
if(ARRAY_LEN(v) < ARRAY_CAP(v) / 2) { |
108 |
|
1 |
const m_uint cap = ARRAY_CAP(v) /= 2; |
109 |
|
1 |
v->ptr = (m_bit*)xrealloc(v->ptr, ARRAY_OFFSET + cap * size); |
110 |
|
|
} |
111 |
|
2 |
} |
112 |
|
|
|
113 |
|
2 |
static MFUN(vm_vector_rem) { |
114 |
|
2 |
const m_int index = *(m_int*)(shred->mem + SZ_INT); |
115 |
|
2 |
const M_Vector v = ARRAY(o); |
116 |
✓✗✗✓
|
2 |
if(index < 0 || (m_uint)index >= ARRAY_LEN(v)) |
117 |
|
|
return; |
118 |
|
2 |
const Type t = unflag_type(o->type_ref); |
119 |
✓✗ |
2 |
if(t->nspc->info->class_data_size) |
120 |
|
2 |
(*(f_release**)t->nspc->info->class_data)(shred, array_base(t), ARRAY_PTR(v) + index * ARRAY_SIZE(v)); |
121 |
|
2 |
m_vector_rem(v, (vtype)index); |
122 |
|
|
} |
123 |
|
|
|
124 |
|
1639 |
ANN m_bit* m_vector_addr(const M_Vector v, const m_uint i) { |
125 |
|
1639 |
return &*(m_bit*)(ARRAY_PTR(v) + i * ARRAY_SIZE(v)); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
14 |
static MFUN(vm_vector_size) { |
129 |
|
14 |
*(m_uint*)RETURN = ARRAY_LEN(ARRAY(o)); |
130 |
|
14 |
} |
131 |
|
|
|
132 |
|
2 |
static MFUN(vm_vector_depth) { |
133 |
|
2 |
*(m_uint*)RETURN = o->type_ref->array_depth; |
134 |
|
2 |
} |
135 |
|
|
|
136 |
|
2 |
static MFUN(vm_vector_cap) { |
137 |
|
2 |
*(m_uint*)RETURN = ARRAY_CAP(ARRAY(o)); |
138 |
|
2 |
} |
139 |
|
|
|
140 |
|
26 |
ANN static Type get_array_type(Type t) { |
141 |
✓✓ |
72 |
while(t->e->d.base_type) |
142 |
|
20 |
t = t->e->d.base_type; |
143 |
|
26 |
return t; |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
#define ARRAY_OPCK(a, b, pos) \ |
147 |
|
|
const Type l = get_array_type(a->info->type); \ |
148 |
|
|
const Type r = get_array_type(b->info->type); \ |
149 |
|
|
if(isa(l, r) < 0) \ |
150 |
|
|
ERR_N(pos, _("array types do not match.")) |
151 |
|
|
|
152 |
|
8 |
static OP_CHECK(opck_array_at) { |
153 |
|
8 |
const Exp_Binary* bin = (Exp_Binary*)data; |
154 |
✓✓ |
8 |
if(opck_const_rhs(env, data, mut) == env->gwion->type[et_null]) |
155 |
|
1 |
return env->gwion->type[et_null]; |
156 |
✓✓ |
7 |
if(bin->lhs->info->type != env->gwion->type[et_null]) { |
157 |
✓✓ |
6 |
ARRAY_OPCK(bin->lhs, bin->rhs, exp_self(bin)->pos) |
158 |
✓✓ |
5 |
if(bin->lhs->info->type->array_depth != bin->rhs->info->type->array_depth) |
159 |
|
1 |
ERR_N(exp_self(bin)->pos, _("array depths do not match.")) |
160 |
|
|
} |
161 |
✓✓ |
5 |
if(bin->rhs->exp_type == ae_exp_decl) { |
162 |
|
3 |
SET_FLAG(bin->rhs->d.exp_decl.td, ref); |
163 |
✓✓✓✗
|
4 |
if(bin->rhs->d.exp_decl.list->self->array && |
164 |
|
1 |
bin->rhs->d.exp_decl.list->self->array->exp) |
165 |
|
1 |
ERR_N(exp_self(bin)->pos, _("do not provide array for 'xxx @=> declaration'.")) |
166 |
|
|
} |
167 |
|
4 |
exp_setvar(bin->rhs, 1); |
168 |
|
4 |
return bin->rhs->info->type; |
169 |
|
|
} |
170 |
|
|
|
171 |
|
7 |
ANN static Type check_array_shift(const Env env, |
172 |
|
|
const Exp a, const Exp b, const m_str str, const loc_t pos) { |
173 |
✗✓✗✗
|
7 |
if(a->info->type == env->gwion->type[et_null] && |
174 |
|
|
b->info->type->array_depth > 1) |
175 |
|
|
return a->info->type; |
176 |
✗✓ |
7 |
ARRAY_OPCK(a, b, pos) |
177 |
✓✓ |
7 |
if(a->info->type->array_depth == b->info->type->array_depth + 1) |
178 |
|
5 |
return a->info->type; |
179 |
✓✓ |
2 |
else if(a->info->type->array_depth == b->info->type->array_depth) |
180 |
|
1 |
return a->info->type; |
181 |
|
1 |
ERR_N(pos, "array depths do not match for '%s'.", str); |
182 |
|
|
} |
183 |
|
|
|
184 |
|
5 |
static OP_CHECK(opck_array_sl) { |
185 |
|
5 |
const Exp_Binary* bin = (Exp_Binary*)data; |
186 |
|
5 |
return check_array_shift(env, bin->lhs, bin->rhs, "<<", exp_self(bin)->pos); |
187 |
|
|
} |
188 |
|
|
|
189 |
|
2 |
static OP_CHECK(opck_array_sr) { |
190 |
|
2 |
const Exp_Binary* bin = (Exp_Binary*)data; |
191 |
|
2 |
return check_array_shift(env, bin->rhs, bin->lhs, ">>", exp_self(bin)->pos); |
192 |
|
|
} |
193 |
|
|
|
194 |
|
1 |
ANN static Instr emit_array_shift(const Emitter emit, const f_instr exec) { |
195 |
|
1 |
const Instr pop = emit_add_instr(emit, RegPop); |
196 |
|
1 |
pop->m_val = SZ_INT; |
197 |
|
1 |
return emit_add_instr(emit, exec); |
198 |
|
|
} |
199 |
|
|
|
200 |
|
1 |
static INSTR(ArrayAppendFront) { |
201 |
|
1 |
const M_Object o = *(M_Object*)(shred->reg); |
202 |
|
1 |
const M_Vector a = ARRAY(o); |
203 |
|
1 |
m_vector_add_front(a, shred->reg - ARRAY_SIZE(a)); |
204 |
|
1 |
} |
205 |
|
|
|
206 |
|
|
static INSTR(ArrayConcatLeft) { |
207 |
|
|
const M_Object obase = *(M_Object*)(shred->reg - SZ_INT); |
208 |
|
|
const M_Object omore = *(M_Object*)(shred->reg); |
209 |
|
|
const M_Vector base = ARRAY(obase); |
210 |
|
|
const M_Vector more = ARRAY(omore); |
211 |
|
|
const m_uint len = ARRAY_LEN(base); |
212 |
|
|
const m_uint sz = ARRAY_SIZE(base); |
213 |
|
|
if((ARRAY_LEN(base) += ARRAY_LEN(more)) >= ARRAY_CAP(base)) { |
214 |
|
|
ARRAY_CAP(base) += ARRAY_CAP(more); |
215 |
|
|
m_bit *ptr = (m_bit*)xrealloc(base->ptr, ARRAY_OFFSET + ARRAY_CAP(base) * sz); |
216 |
|
|
base->ptr = ptr; |
217 |
|
|
} |
218 |
|
|
m_bit *data = more->ptr + ARRAY_OFFSET; |
219 |
|
|
memmove(ARRAY_PTR(base) + (len - 1) * sz, data, sz); |
220 |
|
|
release(obase, shred); |
221 |
|
|
release(omore, shred); |
222 |
|
|
} |
223 |
|
|
|
224 |
|
1 |
static INSTR(ArrayConcatRight) { |
225 |
|
1 |
const M_Object obase = *(M_Object*)(shred->reg); |
226 |
|
1 |
const M_Object omore = *(M_Object*)(shred->reg - SZ_INT); |
227 |
|
1 |
const M_Vector base = ARRAY(obase); |
228 |
|
1 |
const M_Vector more = ARRAY(omore); |
229 |
|
1 |
const m_uint len = ARRAY_LEN(base); |
230 |
|
1 |
const m_uint sz = ARRAY_SIZE(base); |
231 |
✓✗ |
1 |
if((ARRAY_LEN(base) += ARRAY_LEN(more)) >= ARRAY_CAP(base)) { |
232 |
|
1 |
ARRAY_CAP(base) += ARRAY_CAP(more); |
233 |
|
1 |
m_bit *ptr = (m_bit*)xrealloc(base->ptr, ARRAY_OFFSET + ARRAY_CAP(base) * sz); |
234 |
|
1 |
base->ptr = ptr; |
235 |
|
|
} |
236 |
|
1 |
memmove(ARRAY_PTR(base) + (ARRAY_LEN(more) + len - 1) * sz, ARRAY_PTR(base), len * sz); |
237 |
|
1 |
memmove(ARRAY_PTR(base), ARRAY_PTR(more), ARRAY_LEN(more) * sz); |
238 |
|
1 |
release(obase, shred); |
239 |
|
1 |
release(omore, shred); |
240 |
|
1 |
} |
241 |
|
|
|
242 |
|
2 |
static OP_EMIT(opem_array_sr) { |
243 |
|
2 |
const Exp_Binary* bin = (Exp_Binary*)data; |
244 |
✓✓ |
2 |
if(bin->rhs->info->type->array_depth == bin->lhs->info->type->array_depth) |
245 |
|
1 |
return emit_array_shift(emit, ArrayConcatRight); |
246 |
|
1 |
const Instr pop = emit_add_instr(emit, RegPop); |
247 |
|
1 |
pop->m_val = SZ_INT; |
248 |
|
1 |
(void)emit_gc(emit, 0); |
249 |
|
1 |
return emit_add_instr(emit, ArrayAppendFront); |
250 |
|
|
} |
251 |
|
|
|
252 |
|
4 |
static OP_EMIT(opem_array_sl) { |
253 |
|
4 |
const Exp_Binary* bin = (Exp_Binary*)data; |
254 |
✗✓ |
4 |
if(bin->lhs->info->type->array_depth == bin->rhs->info->type->array_depth) |
255 |
|
|
return emit_array_shift(emit, ArrayConcatLeft); |
256 |
|
4 |
const Instr pop = emit_add_instr(emit, RegPop); |
257 |
|
4 |
pop->m_val = bin->rhs->info->type->size; |
258 |
|
4 |
(void)emit_gc(emit, -SZ_INT); |
259 |
|
4 |
return emit_add_instr(emit, ArrayAppend); |
260 |
|
|
} |
261 |
|
|
|
262 |
|
|
// check me. use common ancestor maybe |
263 |
|
2 |
static OP_CHECK(opck_array_cast) { |
264 |
|
2 |
const Exp_Cast* cast = (Exp_Cast*)data; |
265 |
|
2 |
Type l = cast->exp->info->type; |
266 |
|
2 |
Type r = exp_self(cast)->info->type; |
267 |
✓✓ |
5 |
while(!l->e->d.base_type) |
268 |
|
1 |
l = l->e->parent; |
269 |
✓✓ |
5 |
while(!r->e->d.base_type) |
270 |
|
1 |
r = r->e->parent; |
271 |
✓✓✓✗
|
2 |
if(get_depth(cast->exp->info->type) == get_depth(exp_self(cast)->info->type) && isa(l->e->d.base_type, r->e->d.base_type) > 0) |
272 |
|
1 |
return l; |
273 |
|
1 |
return env->gwion->type[et_null]; |
274 |
|
|
} |
275 |
|
|
|
276 |
|
4 |
static OP_CHECK(opck_array_slice) { |
277 |
|
4 |
const Exp e = (Exp)data; |
278 |
|
4 |
exp_setmeta(exp_self(e), 1); |
279 |
|
4 |
exp_setnonnull(e->d.exp_slice.base, 1); |
280 |
|
4 |
return e->d.exp_slice.base->info->type; |
281 |
|
|
} |
282 |
|
|
|
283 |
|
7 |
static inline m_bool bounds(const M_Vector v, const m_int i) { |
284 |
✗✓ |
7 |
CHECK_BB(i) |
285 |
✓✓ |
7 |
return (m_uint)i < ARRAY_LEN(v) ? GW_OK : GW_ERROR; |
286 |
|
|
} |
287 |
|
|
|
288 |
|
4 |
static INSTR(ArraySlice) { |
289 |
|
4 |
shred->reg -= SZ_INT *2; |
290 |
|
4 |
const M_Object array = *(M_Object*)REG(-SZ_INT); |
291 |
|
4 |
const M_Vector in = ARRAY(array); |
292 |
|
4 |
const m_int start = *(m_uint*)REG(0); |
293 |
|
4 |
m_int end = *(m_uint*)REG(SZ_INT); |
294 |
✓✓ |
4 |
if(end < 0) |
295 |
|
2 |
end = ARRAY_LEN(in) + end; |
296 |
✓✓ |
4 |
const m_int op = start < end ? 1 : -1; |
297 |
✓✓ |
4 |
const m_uint sz = op > 0 ? end - start : start - end; |
298 |
✓✓✗✓
|
4 |
if(bounds(in, start) < 0 || bounds(in, end) < 0) |
299 |
|
1 |
Except(shred, "OutOfBoundsArraySliceException"); |
300 |
|
3 |
const M_Object out = new_array(shred->info->vm->gwion->mp, array->type_ref, sz); |
301 |
✓✓ |
6 |
for(m_int i = start, j = 0; i != end; i += op, ++j) { |
302 |
|
3 |
m_bit buf[ARRAY_SIZE(in)]; |
303 |
|
3 |
m_vector_get(in, i, &buf); |
304 |
|
3 |
m_vector_set(ARRAY(out), j, buf); |
305 |
|
|
} |
306 |
|
3 |
*(M_Object*)REG(-SZ_INT) = out; |
307 |
|
|
} |
308 |
|
|
|
309 |
|
4 |
static OP_EMIT(opem_array_slice) { |
310 |
|
4 |
emit_add_instr(emit, ArraySlice); |
311 |
|
4 |
return emit_gc(emit, -SZ_INT); |
312 |
|
|
} |
313 |
|
|
|
314 |
|
38 |
static FREEARG(freearg_array) { |
315 |
|
38 |
ArrayInfo* info = (ArrayInfo*)instr->m_val; |
316 |
|
38 |
vector_release(&info->type); |
317 |
|
38 |
mp_free(((Gwion)gwion)->mp, ArrayInfo, info); |
318 |
|
38 |
} |
319 |
|
|
|
320 |
|
4 |
static OP_CHECK(opck_not_array) { |
321 |
|
4 |
const Array_Sub array = (Array_Sub)data; |
322 |
✓✓ |
4 |
if(get_depth(array->type)) { |
323 |
|
2 |
struct Array_Sub_ next = { array->exp, array->type->e->parent, array->depth }; |
324 |
|
2 |
return check_array_access(env, &next); |
325 |
|
|
} |
326 |
|
2 |
ERR_O(array->exp->pos, _("array subscripts (%"UINT_F") exceeds defined dimension (%"UINT_F")"), |
327 |
|
|
array->depth, get_depth(array->type)) |
328 |
|
|
} |
329 |
|
|
|
330 |
|
|
ANN Type check_array_access(const Env env, const Array_Sub array); |
331 |
|
|
|
332 |
|
29 |
static OP_CHECK(opck_array) { |
333 |
|
29 |
const Array_Sub array = (Array_Sub)data; |
334 |
|
29 |
const Type t_int = env->gwion->type[et_int]; |
335 |
|
29 |
Exp e = array->exp; |
336 |
✗✓ |
43 |
do CHECK_BO(check_implicit(env, e, t_int)) |
337 |
✓✓ |
43 |
while((e = e->next)); |
338 |
|
29 |
const Type t = array->type; |
339 |
✓✓ |
29 |
if(t->array_depth >= array->depth) |
340 |
|
27 |
return array_type(env, array_base(t), t->array_depth - array->depth); |
341 |
|
2 |
const Exp curr = take_exp(array->exp, array->type->array_depth); |
342 |
|
2 |
struct Array_Sub_ next = { curr->next, array_base(array->type), array->depth - array->type->array_depth }; |
343 |
|
2 |
return check_array_access(env, &next); |
344 |
|
|
} |
345 |
|
|
|
346 |
|
25 |
ANN static void array_loop(const Emitter emit, const m_uint depth) { |
347 |
|
25 |
const Instr pre_pop = emit_add_instr(emit, RegPop); |
348 |
|
25 |
pre_pop->m_val = depth * SZ_INT; |
349 |
|
25 |
emit_add_instr(emit, GWOP_EXCEPT); |
350 |
✓✓ |
37 |
for(m_uint i = 0; i < depth - 1; ++i) { |
351 |
|
12 |
const Instr access = emit_add_instr(emit, ArrayAccess); |
352 |
|
12 |
access->m_val = i * SZ_INT; |
353 |
✓✗ |
12 |
access->m_val2 = !i ? SZ_INT : 0; |
354 |
|
12 |
const Instr get = emit_add_instr(emit, ArrayGet); |
355 |
|
12 |
get->m_val = i * SZ_INT; |
356 |
|
12 |
get->m_val2 = -SZ_INT; |
357 |
|
12 |
emit_add_instr(emit, GWOP_EXCEPT); |
358 |
|
|
} |
359 |
|
25 |
const Instr post_pop = emit_add_instr(emit, RegPop); |
360 |
|
25 |
post_pop->m_val = SZ_INT; |
361 |
|
25 |
const Instr access = emit_add_instr(emit, ArrayAccess); |
362 |
|
25 |
access->m_val = depth * SZ_INT; |
363 |
|
25 |
} |
364 |
|
|
|
365 |
|
25 |
ANN static void array_finish(const Emitter emit, const m_uint depth, |
366 |
|
|
const m_uint size, const m_bool is_var) { |
367 |
✓✓ |
25 |
const Instr get = emit_add_instr(emit, is_var ? ArrayAddr : ArrayGet); |
368 |
|
25 |
get->m_val = depth * SZ_INT; |
369 |
|
25 |
const Instr push = emit_add_instr(emit, ArrayValid); |
370 |
✓✓ |
25 |
push->m_val = is_var ? SZ_INT : size; |
371 |
|
25 |
} |
372 |
|
|
|
373 |
|
25 |
ANN static inline m_bool array_do(const Emitter emit, const Array_Sub array, const m_bool is_var) { |
374 |
|
25 |
emit_gc(emit, -SZ_INT); |
375 |
✗✓ |
25 |
CHECK_BB(emit_exp(emit, array->exp)) |
376 |
|
25 |
array_loop(emit, array->depth); |
377 |
|
25 |
array_finish(emit, array->depth, array->type->size, is_var); |
378 |
|
25 |
return GW_OK; |
379 |
|
|
} |
380 |
|
|
ANN static inline Exp emit_n_exp(const Emitter emit, struct ArrayAccessInfo *const info) { |
381 |
|
|
const Exp e = take_exp(info->array.exp, info->array.depth); |
382 |
|
|
const Exp next = e->next; |
383 |
|
|
e->next = NULL; |
384 |
|
|
struct Array_Sub_ partial = { info->array.exp, info->array.type, info->array.depth }; |
385 |
|
|
const m_bool ret = array_do(emit, &partial, 0); |
386 |
|
|
e->next = next; |
387 |
|
|
return ret > 0 ? next : NULL; |
388 |
|
|
} |
389 |
|
|
|
390 |
|
25 |
static OP_EMIT(opem_array_access) { |
391 |
|
25 |
struct ArrayAccessInfo *const info = (struct ArrayAccessInfo*)data; |
392 |
✓✗ |
25 |
if(info->array.type->array_depth >= info->array.depth) { |
393 |
|
25 |
struct Array_Sub_ next = { .exp=info->array.exp, .type=info->type, .depth=info->array.depth }; |
394 |
|
25 |
return (Instr)(m_uint)array_do(emit, &next, info->is_var); |
395 |
|
|
} |
396 |
|
|
struct Array_Sub_ partial = { info->array.exp, info->array.type, info->array.type->array_depth }; |
397 |
|
|
struct Array_Sub_ next = { info->array.exp, array_base(info->array.type), info->array.depth - info->array.type->array_depth }; |
398 |
|
|
info->array = partial; |
399 |
|
|
const Exp exp = emit_n_exp(emit, info); |
400 |
|
|
next.exp = exp; |
401 |
|
|
info->array = next; |
402 |
|
|
return (Instr)(m_uint)(exp ? emit_array_access(emit, info) : GW_ERROR); |
403 |
|
|
} |
404 |
|
|
|
405 |
|
712 |
GWION_IMPORT(array) { |
406 |
|
712 |
const Type t_array = gwi_class_ini(gwi, "@Array", NULL); |
407 |
|
712 |
gwi->gwion->type[et_array] = t_array; |
408 |
|
712 |
gwi_class_xtor(gwi, NULL, array_dtor); |
409 |
|
712 |
GWI_BB(gwi_item_ini(gwi, "@internal", "@array")) |
410 |
|
712 |
GWI_BB(gwi_item_end(gwi, 0, NULL)) |
411 |
|
712 |
GWI_BB(gwi_item_ini(gwi, "@internal", "@ctor_data")) |
412 |
|
712 |
GWI_BB(gwi_item_end(gwi, 0, NULL)) |
413 |
|
|
|
414 |
|
712 |
GWI_BB(gwi_func_ini(gwi, "int", "size")) |
415 |
|
712 |
GWI_BB(gwi_func_end(gwi, vm_vector_size, ae_flag_none)) |
416 |
|
712 |
GWI_BB(gwi_func_ini(gwi, "int", "depth")) |
417 |
|
712 |
GWI_BB(gwi_func_end(gwi, vm_vector_depth, ae_flag_none)) |
418 |
|
|
|
419 |
|
712 |
GWI_BB(gwi_func_ini(gwi, "int", "cap")) |
420 |
|
712 |
GWI_BB(gwi_func_end(gwi, vm_vector_cap, ae_flag_none)) |
421 |
|
|
|
422 |
|
712 |
GWI_BB(gwi_func_ini(gwi, "int", "remove")) |
423 |
|
712 |
GWI_BB(gwi_func_arg(gwi, "int", "index")) |
424 |
|
712 |
GWI_BB(gwi_func_end(gwi, vm_vector_rem, ae_flag_none)) |
425 |
|
|
|
426 |
|
712 |
GWI_BB(gwi_class_end(gwi)) |
427 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@Array", "@Array", NULL)) |
428 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array_at)) |
429 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@=>", ObjectAssign)) |
430 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@null", "@Array", NULL)) |
431 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array_at)) |
432 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@=>", ObjectAssign)) |
433 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "nonnull @Array", (m_str)OP_ANY_TYPE, NULL)) |
434 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array_sl)) |
435 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_array_sl)) |
436 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "<<", NULL)) |
437 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "nonnull @Array", NULL)) |
438 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array_sr)) |
439 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_array_sr)) |
440 |
|
712 |
GWI_BB(gwi_oper_end(gwi, ">>", NULL)) |
441 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@Array", "@Array", NULL)) |
442 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array_cast)) |
443 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "$", NULL)) |
444 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "int", "nonnull @Array", "int")) |
445 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array_slice)) |
446 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_array_slice)) |
447 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@slice", NULL)) |
448 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "int", (m_str)OP_ANY_TYPE, NULL)) |
449 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_not_array)) |
450 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@array", NULL)) |
451 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "int", "@Array", NULL)) |
452 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_array)) |
453 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_array_access)) |
454 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@array", NULL)) |
455 |
|
712 |
gwi_register_freearg(gwi, ArrayAlloc, freearg_array); |
456 |
|
712 |
return GW_OK; |
457 |
|
|
} |
458 |
|
|
|
459 |
|
|
INSTR(ArrayStruct) { |
460 |
|
|
const M_Object ref = *(M_Object*)(REG(-SZ_INT * 5)); |
461 |
|
|
const m_int idx = (*(m_int*)((shred->reg -SZ_INT * 3)))++; |
462 |
|
|
*(m_bit**)(shred->reg) = m_vector_addr(ARRAY(ref), idx); |
463 |
|
|
shred->reg += SZ_INT; // regpush |
464 |
|
|
} |
465 |
|
|
|
466 |
|
1619 |
INSTR(ArrayBottom) { |
467 |
|
1619 |
*(M_Object*)(*(m_uint**)REG(-SZ_INT * 4))[(*(m_int*)REG(-SZ_INT * 3))++] = *(M_Object*)REG(-SZ_INT); |
468 |
|
1619 |
} |
469 |
|
|
|
470 |
|
12 |
INSTR(ArrayPost) { |
471 |
|
12 |
xfree(*(m_uint**)REG(0)); |
472 |
|
12 |
const M_Object o = *(M_Object*)(REG(-SZ_INT)); |
473 |
|
12 |
*(m_uint*)(o->data + SZ_INT) = 0; |
474 |
|
12 |
} |
475 |
|
|
|
476 |
|
10 |
INSTR(ArrayInit) {// for litteral array |
477 |
|
10 |
const Type t = (Type)instr->m_val; |
478 |
|
10 |
const m_uint sz = *(m_uint*)REG(0); |
479 |
|
10 |
const m_uint off = instr->m_val2 * sz; |
480 |
|
10 |
POP_REG(shred, off - SZ_INT); |
481 |
|
10 |
const M_Object obj = new_array(shred->info->mp, t, sz); |
482 |
|
10 |
memcpy(ARRAY(obj)->ptr + ARRAY_OFFSET, REG(-SZ_INT), off); |
483 |
|
10 |
*(M_Object*)REG(-SZ_INT) = obj; |
484 |
|
10 |
} |
485 |
|
|
|
486 |
|
|
#define TOP -1 |
487 |
|
|
|
488 |
|
490 |
ANN static inline M_Object do_alloc_array_object(MemPool p, const ArrayInfo* info, const m_int cap) { |
489 |
|
490 |
struct Vector_ v = info->type; |
490 |
|
490 |
const Type t = (Type)vector_at(&v, (vtype)(-info->depth - 1)); |
491 |
|
490 |
return new_array(p, t, (m_uint)cap); |
492 |
|
|
} |
493 |
|
|
|
494 |
|
331 |
ANN static inline M_Object do_alloc_array_init(ArrayInfo* info, const m_uint cap, |
495 |
|
|
const M_Object base) { |
496 |
✓✓ |
1950 |
for(m_uint i = 0; i < cap; ++i) |
497 |
|
1619 |
info->data[(*info->d.idx)++] = (M_Object)m_vector_addr(ARRAY(base), i); |
498 |
|
331 |
return base; |
499 |
|
|
} |
500 |
|
|
|
501 |
|
|
ANN static M_Object do_alloc_array(const VM_Shred shred, ArrayInfo* info); |
502 |
|
123 |
ANN static M_Object do_alloc_array_loop(const VM_Shred shred, ArrayInfo* info, |
503 |
|
|
const m_uint cap, const M_Object base) { |
504 |
✓✓ |
576 |
for(m_uint i = 0; i < cap; ++i) { |
505 |
|
2270 |
struct ArrayInfo_ aai = { info->depth + 1, info->type, |
506 |
|
1816 |
info->base, info->data, { info->d.idx } , 0, info->is_obj }; |
507 |
|
454 |
const M_Object next = do_alloc_array(shred, &aai); |
508 |
✓✓ |
454 |
if(!next) { |
509 |
|
1 |
_release(base, shred); |
510 |
|
1 |
return NULL; |
511 |
|
|
} |
512 |
|
453 |
m_vector_set(ARRAY(base), i, &next); |
513 |
|
|
} |
514 |
|
122 |
return base; |
515 |
|
|
} |
516 |
|
|
|
517 |
|
492 |
ANN static M_Object do_alloc_array(const VM_Shred shred, ArrayInfo* info) { |
518 |
|
492 |
const m_int cap = *(m_int*)REG(info->depth * SZ_INT); |
519 |
✓✓ |
492 |
if(cap < 0) { |
520 |
|
2 |
gw_err("[gwion](VM): NegativeArraySize: while allocating arrays...\n"); |
521 |
|
2 |
return NULL; |
522 |
|
|
} |
523 |
|
490 |
const M_Object base = do_alloc_array_object(shred->info->mp, info, cap); |
524 |
✓✓✓✓
|
1188 |
return info->depth < TOP ? do_alloc_array_loop(shred, info, (m_uint)cap, base) : |
525 |
|
698 |
info->data ? do_alloc_array_init(info, (m_uint)cap, base) : base; |
526 |
|
|
} |
527 |
|
|
|
528 |
|
12 |
ANN static M_Object* init_array(const VM_Shred shred, const ArrayInfo* info, m_uint* num_obj) { |
529 |
|
12 |
m_int curr = -info->depth; |
530 |
✓✓ |
49 |
while(curr <= TOP) { |
531 |
|
25 |
*num_obj *= *(m_uint*)REG(SZ_INT * curr); |
532 |
|
25 |
++curr; |
533 |
|
|
} |
534 |
✓✗ |
12 |
return *num_obj > 0 ? (M_Object*)xcalloc(*num_obj, info->base->size) : NULL; |
535 |
|
|
} |
536 |
|
|
|
537 |
|
38 |
INSTR(ArrayAlloc) { |
538 |
|
38 |
const ArrayInfo* info = (ArrayInfo*)instr->m_val; |
539 |
|
38 |
m_uint num_obj = 1; |
540 |
|
38 |
m_int idx = 0; |
541 |
✓✓✓✗
|
38 |
const m_bool is_obj = info->is_obj && !info->is_ref; |
542 |
|
76 |
struct ArrayInfo_ aai = { -info->depth, info->type, info->base, |
543 |
|
38 |
NULL, { &idx }, 0, info->is_obj}; |
544 |
✓✓ |
38 |
if(is_obj) |
545 |
|
12 |
aai.data = init_array(shred, info, &num_obj); |
546 |
|
38 |
const M_Object ref = do_alloc_array(shred, &aai); |
547 |
✓✓ |
38 |
if(!ref) { |
548 |
|
2 |
gw_err("[Gwion](VM): (note: in shred[id=%" UINT_F ":%s])\n", shred->tick->xid, shred->info->name); |
549 |
|
2 |
vm_shred_exit(shred); |
550 |
|
2 |
return; // TODO make exception vararg |
551 |
|
|
} |
552 |
|
36 |
*(void**)(ref->data + SZ_INT) = aai.data; |
553 |
|
36 |
vector_add(&shred->gc, (m_uint)ref); |
554 |
✓✓ |
36 |
if(!is_obj) { |
555 |
|
24 |
POP_REG(shred, SZ_INT * (info->depth - 1)); |
556 |
|
24 |
*(M_Object*)REG(-SZ_INT) = ref; |
557 |
|
|
} else { |
558 |
|
12 |
POP_REG(shred, SZ_INT * (info->depth - 4)); |
559 |
|
12 |
*(M_Object*)REG(-SZ_INT*4) = ref; |
560 |
|
12 |
*(M_Object**)REG(-SZ_INT*3) = aai.data; |
561 |
|
12 |
*(m_uint*) REG(-SZ_INT*2) = 0; |
562 |
|
12 |
*(m_uint*) REG(-SZ_INT) = num_obj; |
563 |
|
|
} |
564 |
|
|
} |
565 |
|
|
|