GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/array.c Lines: 373 416 89.7 %
Date: 2020-09-14 20:46:08 Branches: 104 134 77.6 %

Line Branch Exec Source
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