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