GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/vararg.c Lines: 137 139 98.6 %
Date: 2020-09-14 00:22:58 Branches: 44 58 75.9 %

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 "instr.h"
6
#include "emit.h"
7
#include "object.h"
8
#include "vararg.h"
9
#include "gwion.h"
10
#include "operator.h"
11
#include "import.h"
12
#include "gwi.h"
13
#include "specialid.h"
14
#include "traverse.h"
15
#include "parse.h"
16
#include "gack.h"
17
18
25
void free_vararg(MemPool p, struct Vararg_* arg) {
19
25
  if(arg->t.ptr) {
20
19
    xfree(arg->d);
21
19
    vector_release(&arg->t);
22
  }
23
25
  mp_free(p, Vararg, arg);
24
25
}
25
26
25
static DTOR(vararg_dtor) {
27
25
  struct Vararg_ *arg = *(struct Vararg_**)o->data;
28
25
  if(*(m_uint*)(o->data + SZ_INT*2)) {
29
19
    m_uint offset = 0;
30
64
    for(m_uint i = 0; i < vector_size(&arg->t); ++i) {
31
45
      const Type t = (Type)vector_at(&arg->t, i);
32
45
      if(isa(t, shred->info->vm->gwion->type[et_object]) > 0)
33
2
        release(*(M_Object*)(arg->d + offset), shred);
34
43
      else if(GET_FLAG(t, struct))
35
        struct_release(shred, t, *(m_bit**)(arg->d + offset));
36
45
      offset += t->size;
37
    }
38
  }
39
25
  free_vararg(shred->info->vm->gwion->mp, arg);
40
25
}
41
42
1
static MFUN(mfun_vararg_cpy) {
43
1
  struct Vararg_ *src =  *(struct Vararg_**)o->data;
44
1
  struct Vararg_* arg = mp_calloc(shred->info->mp, Vararg);
45
1
  vector_copy2(&src->t, &arg->t);
46
1
  arg->d = (m_bit*)xmalloc(round2szint(*(m_uint*)(o->data + SZ_INT*2)));
47
1
  m_uint offset = 0;
48
2
  for(m_uint i = 0; i < vector_size(&arg->t); ++i) {
49
1
    const Type t = (Type)vector_at(&arg->t, arg->i);
50
1
    *(m_uint*)(arg->d + offset) = *(m_uint*)(src->d + offset);
51
1
    if(isa(t, shred->info->vm->gwion->type[et_object]) > 0)
52
      ++(*(M_Object*)(arg->d + offset))->ref;
53
1
    offset += t->size;
54
  }
55
1
  arg->s = vector_size(&arg->t);
56
1
  arg->i = src->i;
57
1
  arg->o = src->o;
58
1
  const M_Object obj = new_object(shred->info->mp, shred, o->type_ref);
59
1
  *(struct Vararg_**)obj->data = arg;
60
1
  *(m_uint*)(obj->data + SZ_INT*2) = *(m_uint*)(o->data + SZ_INT*2);
61
1
  *(M_Object*)RETURN = obj;
62
1
}
63
64
24
INSTR(VarargIni) {
65
24
  const M_Object o = new_object(shred->info->mp, shred, shred->info->vm->gwion->type[et_vararg]);
66
24
  struct Vararg_* arg = mp_calloc(shred->info->mp, Vararg);
67
24
  *(struct Vararg_**)o->data = arg;
68
24
  POP_REG(shred, instr->m_val - SZ_INT)
69
24
  if((*(m_uint*)(o->data + SZ_INT * 2) = instr->m_val)) {
70
18
    arg->d = (m_bit*)xmalloc(round2szint(instr->m_val));
71
18
    const Vector kinds = (Vector)instr->m_val2;
72
18
    vector_copy2(kinds, &arg->t);
73
18
    m_uint offset = 0;
74
62
    for(m_uint i = 0; i < vector_size(&arg->t); ++i) {
75
44
      const Type t = (Type)vector_at(&arg->t, i);
76
44
      *(m_uint*)(arg->d + offset) = *(m_uint*)(shred->reg - SZ_INT + offset);
77
44
      if(isa(t, shred->info->vm->gwion->type[et_object]) > 0) {
78
2
        const M_Object obj = *(M_Object*)(arg->d + offset);
79
2
        if(obj)
80
2
          ++obj->ref;
81
      }
82
44
      offset += t->size;
83
    }
84
18
    arg->s = vector_size(kinds);
85
  }
86
24
  *(M_Object*)REG(-SZ_INT) = o;
87
24
}
88
89
15
INSTR(VarargCheck) {
90
15
  const M_Object o = *(M_Object*)(shred->reg-SZ_INT);
91
15
  struct Vararg_ *arg = *(struct Vararg_**)o->data;
92
15
  if(arg->s)
93
9
    return;
94
6
  shred->reg -= SZ_INT;
95
6
  shred->pc = instr->m_val;
96
}
97
98
14
static INSTR(VarargEnd) {
99
14
  const M_Object o = *(M_Object*)REG(0);
100
14
  struct Vararg_* arg = *(struct Vararg_**)o->data;
101
14
  arg->o += arg->t.ptr ? ((Type)vector_at(&arg->t, arg->i))->size : 0;
102
14
  if(++arg->i < arg->s)
103
7
    shred->pc = instr->m_val;
104
  else
105
7
    arg->i = arg->o = 0;
106
14
}
107
108
10
static OP_CHECK(opck_vararg_cast) {
109
10
  const Exp_Cast* cast = (Exp_Cast*)data;
110
10
  return known_type(env, cast->td);
111
}
112
113
16
static INSTR(VarargCast) {
114
16
  const M_Object o = *(M_Object*)REG(-SZ_INT);
115
16
  if(!*(m_uint*)(o->data + SZ_INT))
116
1
	  Except(shred, "Using Vararg outside varloop");
117
15
  struct Vararg_* arg = *(struct Vararg_**)o->data;
118
15
  const Type t = (Type)instr->m_val;
119
15
  if(isa((Type)vector_at(&arg->t, arg->i), t) < 0)
120
2
	  Except(shred, "InvalidVariadicAccess");
121
26
  for(m_uint i = 0; i < t->size; i += SZ_INT)
122
13
    *(m_uint*)REG(i - SZ_INT) = *(m_uint*)(arg->d + arg->o + i);
123
}
124
125
10
static OP_EMIT(opem_vararg_cast) {
126
10
  const Exp_Cast* cast = (Exp_Cast*)data;
127
10
  const Instr instr = emit_add_instr(emit, VarargCast);
128
10
  instr->m_val = (m_uint)exp_self(cast)->info->type;
129
10
  const Instr push = emit_add_instr(emit, RegPush);
130
10
  push->m_val = exp_self(cast)->info->type->size - SZ_INT;
131
10
  return instr;
132
}
133
134
24
static FREEARG(freearg_vararg) {
135
24
  if(instr->m_val2)
136
18
    free_vector(((Gwion)gwion)->mp, (Vector)instr->m_val2);
137
24
}
138
139
22
static ID_CHECK(idck_vararg) {
140

22
  if(env->func && GET_FLAG(env->func->def, variadic))
141
21
    return nonnul_type(env, exp_self(prim)->info->type);
142
1
  ERR_O(exp_self(prim)->pos, _("'vararg' must be used inside variadic function"))
143
}
144
145
48
static ID_EMIT(idem_vararg) {
146
48
  const Instr instr = emit_add_instr(emit, RegPushMem);
147
48
  instr->m_val = emit->code->stack_depth - SZ_INT;
148
48
  return instr;
149
}
150
151
2
static GACK(gack_vararg) {
152
2
  INTERP_PRINTF("%p", *(M_Object*)VALUE);
153
2
}
154
155
9
ANN void emit_vararg_end(const Emitter emit, const m_uint pc) {
156
9
  const Instr pop = emit_add_instr(emit, RegPop);
157
9
  pop->m_val = SZ_INT;
158
9
  const Instr instr = emit_add_instr(emit, VarargEnd);
159
9
  instr->m_val = pc;
160
9
}
161
162
711
GWION_IMPORT(vararg) {
163
711
  const Type t_vararg  = gwi_class_ini(gwi, "Vararg", "Object");
164
711
  gwi_class_xtor(gwi, NULL, vararg_dtor);
165
711
  gwi_gack(gwi, t_vararg, gack_vararg);
166
711
  CHECK_BB(gwi_item_ini(gwi, "@internal", "@data"))
167
711
  CHECK_BB(gwi_item_end(gwi, ae_flag_none, NULL))
168
711
  CHECK_BB(gwi_item_ini(gwi, "int", "@inLoop"))
169
711
  CHECK_BB(gwi_item_end(gwi, ae_flag_none, NULL))
170
711
  CHECK_BB(gwi_item_ini(gwi, "int", "@len"))
171
711
  CHECK_BB(gwi_item_end(gwi, ae_flag_none, NULL))
172
711
  CHECK_BB(gwi_func_ini(gwi, "Vararg", "cpy"))
173
711
  CHECK_BB(gwi_func_end(gwi, mfun_vararg_cpy, ae_flag_none))
174
711
  GWI_BB(gwi_class_end(gwi))
175
711
  SET_FLAG(t_vararg, abstract);
176
711
  CHECK_BB(gwi_set_global_type(gwi, t_vararg, et_vararg))
177
711
  GWI_BB(gwi_oper_ini(gwi, "nonnull Vararg", (m_str)OP_ANY_TYPE, NULL))
178
711
  GWI_BB(gwi_oper_add(gwi, opck_vararg_cast))
179
711
  GWI_BB(gwi_oper_emi(gwi, opem_vararg_cast))
180
711
  GWI_BB(gwi_oper_end(gwi, "$", NULL))
181
711
  gwi_register_freearg(gwi, VarargIni, freearg_vararg);
182
711
  struct SpecialId_ spid = { .type=t_vararg, .is_const=1, .ck=idck_vararg, .em=idem_vararg};
183
711
  gwi_specialid(gwi, "vararg", &spid);
184
711
  return GW_OK;
185
}