GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/array.c Lines: 318 343 92.7 %
Date: 2020-07-24 14:14:26 Branches: 94 118 79.7 %

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
68
ANN m_uint m_vector_size(const M_Vector v) {
29
68
  return ARRAY_LEN(v);
30
}
31
32
508
M_Vector new_m_vector(MemPool p, const m_uint size, const m_uint len) {
33
508
  const M_Vector array = mp_calloc(p, M_Vector);
34
508
  const size_t sz = (ARRAY_OFFSET*SZ_INT) + (len*size);
35
508
  array->ptr   = (m_bit*)xcalloc(1, sz);
36
508
  m_uint cap = 1;
37
2290
  while(cap < len)
38
1274
    cap *= 2;
39
508
  ARRAY_CAP(array)   = cap;
40
508
  ARRAY_SIZE(array)  = size;
41
508
  ARRAY_LEN(array) = len;
42
508
  return array;
43
}
44
45
508
void free_m_vector(MemPool p, M_Vector a) {
46
508
  xfree(a->ptr);
47
508
  mp_free(p, M_Vector, a);
48
508
}
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
508
static DTOR(array_dtor) {
56
508
  const Type t = unflag_type(o->type_ref);
57
508
  if(*(void**)(o->data + SZ_INT))
58
    xfree(*(void**)(o->data + SZ_INT));
59
508
  struct M_Vector_* a = ARRAY(o);
60
508
  if(!a)
61
    return;
62
508
  if(t->nspc->info->class_data_size) {
63
2527
    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
508
  free_m_vector(shred->info->mp, a);
67
}
68
69
508
ANN M_Object new_array(MemPool p, const Type t, const m_uint length) {
70
508
  const M_Object a = new_object(p, NULL, t);
71
508
  const m_uint depth = t->array_depth;
72
508
  const m_uint size = depth > 1 ? SZ_INT : array_base(t)->size;
73
508
  ARRAY(a) = new_m_vector(p, size,length);
74
508
  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
3
static OP_CHECK(opck_array_cast) {
187
3
  const Exp_Cast* cast = (Exp_Cast*)data;
188
3
  Type l = cast->exp->info->type;
189
3
  Type r = exp_self(cast)->info->type;
190
8
  while(!l->e->d.base_type)
191
2
    l = l->e->parent;
192
7
  while(!r->e->d.base_type)
193
1
    r = r->e->parent;
194

3
  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
2
    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
41
static FREEARG(freearg_array) {
238
41
  ArrayInfo* info = (ArrayInfo*)instr->m_val;
239
41
  vector_release(&info->type);
240
41
  mp_free(((Gwion)gwion)->mp, ArrayInfo, info);
241
41
}
242
243
2
static OP_CHECK(opck_not_array) {
244
2
  const Array_Sub array = (Array_Sub)data;
245
2
    ERR_O(array->exp->pos, _("array subscripts (%"UINT_F") exceeds defined dimension (%"UINT_F")"),
246
        array->depth, get_depth(array->type))
247
}
248
249
ANN Type check_array_access(const Env env, const Array_Sub array);
250
251
27
static OP_CHECK(opck_array) {
252
27
  const Array_Sub array = (Array_Sub)data;
253
27
  const Type t_int = env->gwion->type[et_int];
254
27
  Exp e = array->exp;
255
40
  do CHECK_BO(check_implicit(env, e, t_int))
256
40
  while((e = e->next));
257
27
  const Type t = array->type;
258
27
  if(t->array_depth >= array->depth)
259
26
    return array_type(env, array_base(t), t->array_depth - array->depth);
260
1
  const Exp curr = take_exp(array->exp, array->type->array_depth);
261
1
  struct Array_Sub_ next = { curr->next, array_base(array->type), array->depth - array->type->array_depth };
262
1
  return check_array_access(env, &next);
263
}
264
265
25
ANN static void array_loop(const Emitter emit, const m_uint depth) {
266
25
  const Instr pre_pop = emit_add_instr(emit, RegPop);
267
25
  pre_pop->m_val = depth * SZ_INT;
268
25
  emit_add_instr(emit, GWOP_EXCEPT);
269
37
  for(m_uint i = 0; i < depth - 1; ++i) {
270
12
    const Instr access = emit_add_instr(emit, ArrayAccess);
271
12
    access->m_val = i;
272
12
    const Instr get = emit_add_instr(emit, ArrayGet);
273
12
    get->m_val = i;
274
12
    get->m_val2 = -SZ_INT;
275
12
    emit_add_instr(emit, GWOP_EXCEPT);
276
  }
277
25
  const Instr post_pop = emit_add_instr(emit, RegPop);
278
25
  post_pop->m_val = SZ_INT;
279
25
  const Instr access = emit_add_instr(emit, ArrayAccess);
280
25
  access->m_val = depth;
281
25
}
282
283
25
ANN static void array_finish(const Emitter emit, const m_uint depth,
284
		const m_uint size, const m_bool is_var) {
285
25
  const Instr get = emit_add_instr(emit, is_var ? ArrayAddr : ArrayGet);
286
25
  get->m_val = depth;
287
25
  const Instr push = emit_add_instr(emit, ArrayValid);
288
25
  push->m_val = is_var ? SZ_INT : size;
289
25
}
290
291
25
ANN static inline m_bool array_do(const  Emitter emit, const Array_Sub array, const m_bool is_var) {
292
25
  emit_add_instr(emit, GcAdd);
293
25
  CHECK_BB(emit_exp(emit, array->exp))
294
25
  array_loop(emit, array->depth);
295
25
  array_finish(emit, array->depth, array->type->size, is_var);
296
25
  return GW_OK;
297
}
298
ANN static inline Exp emit_n_exp(const Emitter emit,  struct ArrayAccessInfo *const info) {
299
  const Exp e = take_exp(info->array.exp, info->array.depth);
300
  const Exp next = e->next;
301
  e->next = NULL;
302
  struct Array_Sub_ partial = { info->array.exp, info->array.type, info->array.depth };
303
  const m_bool ret = array_do(emit, &partial, 0);
304
  e->next = next;
305
  return ret > 0 ? next : NULL;
306
}
307
308
25
static OP_EMIT(opem_array_access) {
309
25
  struct ArrayAccessInfo *const info = (struct ArrayAccessInfo*)data;
310
25
  if(info->array.type->array_depth >= info->array.depth) {
311
25
    struct Array_Sub_ next = { .exp=info->array.exp, .type=info->type, .depth=info->array.depth };
312
25
    return (Instr)(m_uint)array_do(emit, &next, info->is_var);
313
  }
314
  struct Array_Sub_ partial = { info->array.exp, info->array.type, info->array.type->array_depth };
315
  struct Array_Sub_ next = { info->array.exp, array_base(info->array.type), info->array.depth - info->array.type->array_depth };
316
  info->array = partial;
317
  const Exp exp = emit_n_exp(emit, info);
318
  next.exp = exp;
319
  info->array = next;
320
  return (Instr)(m_uint)(exp ? emit_array_access(emit, info) : GW_ERROR);
321
}
322
323
730
GWION_IMPORT(array) {
324
730
  const Type t_array  = gwi_class_ini(gwi, "@Array", NULL);
325
730
  gwi->gwion->type[et_array] = t_array;
326
730
  gwi_class_xtor(gwi, NULL, array_dtor);
327
730
  GWI_BB(gwi_item_ini(gwi, "@internal", "@array"))
328
730
  GWI_BB(gwi_item_end(gwi, 0, NULL))
329
730
  GWI_BB(gwi_item_ini(gwi, "@internal", "@ctor_data"))
330
730
  GWI_BB(gwi_item_end(gwi, 0, NULL))
331
332
730
  GWI_BB(gwi_func_ini(gwi, "int", "size"))
333
730
  GWI_BB(gwi_func_end(gwi, vm_vector_size, ae_flag_none))
334
730
  GWI_BB(gwi_func_ini(gwi, "int", "depth"))
335
730
  GWI_BB(gwi_func_end(gwi, vm_vector_depth, ae_flag_none))
336
337
730
  GWI_BB(gwi_func_ini(gwi, "int", "cap"))
338
730
  GWI_BB(gwi_func_end(gwi, vm_vector_cap, ae_flag_none))
339
340
730
  GWI_BB(gwi_func_ini(gwi, "int", "remove"))
341
730
  GWI_BB(gwi_func_arg(gwi, "int", "index"))
342
730
  GWI_BB(gwi_func_end(gwi, vm_vector_rem, ae_flag_none))
343
344
730
  GWI_BB(gwi_class_end(gwi))
345
730
  GWI_BB(gwi_oper_ini(gwi, "@Array", "@Array", NULL))
346
730
  GWI_BB(gwi_oper_add(gwi, opck_array_at))
347
730
  GWI_BB(gwi_oper_end(gwi, "@=>", ObjectAssign))
348
730
  GWI_BB(gwi_oper_ini(gwi, "@null", "@Array", NULL))
349
730
  GWI_BB(gwi_oper_add(gwi, opck_array_at))
350
730
  GWI_BB(gwi_oper_end(gwi, "@=>", ObjectAssign))
351
730
  GWI_BB(gwi_oper_ini(gwi, "nonnull @Array", (m_str)OP_ANY_TYPE, NULL))
352
730
  GWI_BB(gwi_oper_add(gwi, opck_array_shift))
353
730
  GWI_BB(gwi_oper_emi(gwi, opem_array_shift))
354
730
  GWI_BB(gwi_oper_end(gwi, "<<", NULL))
355
730
  GWI_BB(gwi_oper_ini(gwi, "@Array", "@Array", NULL))
356
730
  GWI_BB(gwi_oper_add(gwi, opck_array_cast))
357
730
  GWI_BB(gwi_oper_end(gwi, "$", NULL))
358
730
  GWI_BB(gwi_oper_ini(gwi, "int", "nonnull @Array", "int"))
359
730
  GWI_BB(gwi_oper_add(gwi, opck_array_slice))
360
730
  GWI_BB(gwi_oper_emi(gwi, opem_array_slice))
361
730
  GWI_BB(gwi_oper_end(gwi, "@slice", NULL))
362
730
  GWI_BB(gwi_oper_ini(gwi, "int", (m_str)OP_ANY_TYPE, NULL))
363
730
  GWI_BB(gwi_oper_add(gwi, opck_not_array))
364
730
  GWI_BB(gwi_oper_end(gwi, "@array", NULL))
365
730
  GWI_BB(gwi_oper_ini(gwi, "int", "@Array", NULL))
366
730
  GWI_BB(gwi_oper_add(gwi, opck_array))
367
730
  GWI_BB(gwi_oper_emi(gwi, opem_array_access))
368
730
  GWI_BB(gwi_oper_end(gwi, "@array", NULL))
369
730
  gwi_register_freearg(gwi, ArrayAlloc, freearg_array);
370
730
  return GW_OK;
371
}
372
373
INSTR(ArrayStruct) {
374
  const M_Object ref = *(M_Object*)(REG(-SZ_INT * 5));
375
  const m_int idx = (*(m_int*)((shred->reg -SZ_INT * 3)))++;
376
  *(m_bit**)(shred->reg) = m_vector_addr(ARRAY(ref), idx);
377
  shred->reg += SZ_INT; // regpush
378
}
379
380
1619
INSTR(ArrayBottom) {
381
1619
  *(M_Object*)(*(m_uint**)REG(-SZ_INT * 4))[(*(m_int*)REG(-SZ_INT * 3))++] = *(M_Object*)REG(-SZ_INT);
382
1619
}
383
384
12
INSTR(ArrayPost) {
385
12
  xfree(*(m_uint**)REG(0));
386
12
  const M_Object o = *(M_Object*)(REG(-SZ_INT));
387
12
  *(m_uint*)(o->data + SZ_INT) = 0;
388
12
}
389
390
10
INSTR(ArrayInit) {// for litteral array
391
10
  const Type t = (Type)instr->m_val;
392
10
  const m_uint sz = *(m_uint*)REG(0);
393
10
  const m_uint off = instr->m_val2 * sz;
394
10
  POP_REG(shred, off - SZ_INT);
395
10
  const M_Object obj = new_array(shred->info->mp, t, sz);
396
10
  memcpy(ARRAY(obj)->ptr + ARRAY_OFFSET, REG(-SZ_INT), off);
397
10
  *(M_Object*)REG(-SZ_INT) = obj;
398
10
}
399
400
#define TOP -1
401
402
493
ANN static inline M_Object do_alloc_array_object(MemPool p, const ArrayInfo* info, const m_int cap) {
403
493
  struct Vector_ v = info->type;
404
493
  const Type t = (Type)vector_at(&v, (vtype)(-info->depth - 1));
405
493
  return new_array(p, t, (m_uint)cap);
406
}
407
408
331
ANN static inline M_Object do_alloc_array_init(ArrayInfo* info, const m_uint cap,
409
    const M_Object base) {
410
1950
  for(m_uint i = 0; i < cap; ++i)
411
1619
    info->data[(*info->d.idx)++] = (M_Object)m_vector_addr(ARRAY(base), i);
412
331
  return base;
413
}
414
415
ANN static M_Object do_alloc_array(const VM_Shred shred, ArrayInfo* info);
416
124
ANN static M_Object do_alloc_array_loop(const VM_Shred shred, ArrayInfo* info,
417
    const m_uint cap, const M_Object base) {
418
577
  for(m_uint i = 0; i < cap; ++i) {
419
2270
    struct ArrayInfo_ aai = { info->depth + 1, info->type,
420
1816
      info->base, info->data, { info->d.idx } , 0, info->is_obj };
421
454
    const M_Object next = do_alloc_array(shred, &aai);
422
454
    if(!next) {
423
1
      _release(base, shred);
424
1
      return NULL;
425
    }
426
453
    m_vector_set(ARRAY(base), i, &next);
427
  }
428
123
  return base;
429
}
430
431
495
ANN static M_Object do_alloc_array(const VM_Shred shred, ArrayInfo* info) {
432
495
  const m_int cap = *(m_int*)REG(info->depth * SZ_INT);
433
495
  if(cap < 0) {
434
2
    gw_err("[gwion](VM): NegativeArraySize: while allocating arrays...\n");
435
2
    return NULL;
436
  }
437
493
  const M_Object base = do_alloc_array_object(shred->info->mp, info, cap);
438

1193
  return info->depth < TOP ? do_alloc_array_loop(shred, info, (m_uint)cap, base) :
439
700
    info->data ? do_alloc_array_init(info, (m_uint)cap, base) : base;
440
}
441
442
12
ANN static M_Object* init_array(const VM_Shred shred, const ArrayInfo* info, m_uint* num_obj) {
443
12
  m_int curr = -info->depth;
444
49
  while(curr <= TOP) {
445
25
    *num_obj *= *(m_uint*)REG(SZ_INT * curr);
446
25
    ++curr;
447
  }
448
12
  return *num_obj > 0 ? (M_Object*)xcalloc(*num_obj, info->base->size) : NULL;
449
}
450
451
41
INSTR(ArrayAlloc) {
452
41
  const ArrayInfo* info = (ArrayInfo*)instr->m_val;
453
41
  m_uint num_obj = 1;
454
41
  m_int idx = 0;
455

41
  const m_bool is_obj = info->is_obj && !info->is_ref;
456
82
  struct ArrayInfo_ aai = { -info->depth, info->type, info->base,
457
41
         NULL, { &idx }, 0, info->is_obj};
458
41
  if(is_obj)
459
12
    aai.data = init_array(shred, info, &num_obj);
460
41
  const M_Object ref = do_alloc_array(shred, &aai);
461
41
  if(!ref) {
462
2
    gw_err("[Gwion](VM): (note: in shred[id=%" UINT_F ":%s])\n", shred->tick->xid, shred->info->name);
463
2
    vm_shred_exit(shred);
464
2
    return; // TODO make exception vararg
465
  }
466
39
  *(void**)(ref->data + SZ_INT) = aai.data;
467
39
  vector_add(&shred->gc, (m_uint)ref);
468
39
  if(!is_obj) {
469
27
    POP_REG(shred, SZ_INT * (info->depth - 1));
470
27
    *(M_Object*)REG(-SZ_INT) = ref;
471
  } else {
472
12
    POP_REG(shred, SZ_INT * (info->depth - 4));
473
12
    *(M_Object*)REG(-SZ_INT*4) = ref;
474
12
    *(M_Object**)REG(-SZ_INT*3) = aai.data;
475
12
    *(m_uint*) REG(-SZ_INT*2) = 0;
476
12
    *(m_uint*) REG(-SZ_INT) = num_obj;
477
  }
478
}
479