GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/vm/vm.c Lines: 534 574 93.0 %
Date: 2020-08-07 19:15:19 Branches: 89 126 70.6 %

Line Branch Exec Source
1
#include <time.h>
2
#include "gwion_util.h"
3
#include "gwion_ast.h"
4
#include "gwion_env.h"
5
#include "vm.h"
6
#include "instr.h"
7
#include "object.h"
8
#include "ugen.h"
9
#include "shreduler_private.h"
10
#include "emit.h"
11
#include "gwion.h"
12
#include "operator.h"
13
#include "import.h"
14
#include "map_private.h"
15
#include "gack.h"
16
#include "array.h"
17
18
740
static inline uint64_t splitmix64_stateless(uint64_t index) {
19
740
  uint64_t z = (index + UINT64_C(0x9E3779B97F4A7C15));
20
740
  z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
21
740
  z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
22
740
  return z ^ (z >> 31);
23
}
24
25
93
static inline uint32_t rotl(const uint32_t x, int k) {
26
93
  return (x << k) | (x >> (32 -k));
27
}
28
29
740
void gw_seed(uint32_t rnd[2], const uint64_t s) {
30
740
  uint64_t seed = splitmix64_stateless(s);
31
740
  memcpy(rnd, &seed, sizeof(uint64_t));
32
740
}
33
34
/*xoroshiro32** */
35
31
uint32_t gw_rand(uint32_t s[2]) {
36
31
  const uint32_t s0 = s[0];
37
31
  const uint32_t s1 = s[1] ^ s0;
38
31
  const uint32_t ret = rotl(s0 * 0x9E3779BB, 5) * 5;
39
31
  s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9);
40
31
  s[1] = rotl(s1, 13);
41
31
  return ret;
42
}
43
44
2
void vm_remove(const VM* vm, const m_uint index) {
45
2
  const Vector v = (Vector)&vm->shreduler->shreds;
46
  LOOP_OPTIM
47
5
  for(m_uint i = vector_size(v) + 1; --i;) {
48
2
    const VM_Shred sh = (VM_Shred)vector_at(v, i - 1);
49

2
    if(sh && sh->tick->xid == index)
50
1
       Except(sh, "MsgRemove");
51
  }
52
}
53
54
736
ANN void free_vm(VM* vm) {
55
736
  vector_release(&vm->shreduler->shreds);
56
736
  vector_release(&vm->ugen);
57
736
  if(vm->bbq)
58
736
    free_driver(vm->bbq, vm);
59
736
  MUTEX_CLEANUP(vm->shreduler->mutex);
60
736
  mp_free(vm->gwion->mp, Shreduler, vm->shreduler);
61
736
  mp_free(vm->gwion->mp, VM, vm);
62
736
}
63
64
479
ANN void vm_add_shred(const VM* vm, const VM_Shred shred) {
65
479
  shred->info->vm = (VM*)vm;
66
479
  shred->info->me = new_shred(shred, 1);
67
479
  shreduler_add(vm->shreduler, shred);
68
479
}
69
70
730
ANN void vm_ini_shred(const VM* vm, const VM_Shred shred) {
71
730
  shred->info->vm = (VM*)vm;
72
730
  shred->info->me = new_shred(shred, 1);
73
730
  shreduler_ini(vm->shreduler, shred);
74
730
}
75
76
ANN void vm_lock(VM const *vm) {
77
  if(vm->parent)
78
    vm_lock(vm->parent);
79
  MUTEX_LOCK(vm->shreduler->mutex);
80
}
81
82
ANN void vm_unlock(VM const *vm) {
83
  do MUTEX_UNLOCK(vm->shreduler->mutex);
84
  while((vm = vm->parent));
85
}
86
87
ANN m_bool vm_running(VM const *vm) {
88
  if(!vm->shreduler->bbq->is_running)
89
    return 0;
90
  if(!vm->parent)
91
    return 1;
92
  return vm->shreduler->bbq->is_running = vm_running(vm->parent);
93
}
94
95
__attribute__((hot))
96
3150579
ANN static inline void vm_ugen_init(const VM* vm) {
97
3150579
  const Vector v = (Vector)&vm->ugen;
98
  LOOP_OPTIM
99
16232920
  for(m_uint i = vector_size(v) + 1; --i;) {
100
9931762
    const UGen u = (UGen)vector_at(v, i - 1);
101
9931762
    u->done = 0;
102
9931762
    if(u->multi) {
103
6301159
      struct ugen_multi_* m = u->connect.multi;
104
      LOOP_OPTIM
105
25204636
      for(m_uint j = m->n_chan + 1; --j;)
106
12602318
        UGEN(m->channel[j - 1])->done = 0;
107
    }
108
  }
109
3150579
  const UGen hole = (UGen)vector_at(v, 0);
110
3150579
  hole->compute(hole);
111
3150578
}
112
113
#ifdef DEBUG_STACK
114
#define VM_INFO                                                              \
115
  gw_err("shred[%" UINT_F "] mem[%" INT_F"] reg[%" INT_F"]\n", \
116
  shred->tick->xid, \
117
  mem - ((m_bit*)shred + sizeof(struct VM_Shred_) + SIZEOF_REG), reg - ((m_bit*)shred + sizeof(struct VM_Shred_)));
118
#else
119
#define VM_INFO
120
#endif
121
122
2947
ANN static inline m_bool overflow_(const m_bit* mem, const VM_Shred c) {
123
2947
  return mem > (((m_bit*)c + sizeof(struct VM_Shred_) + SIZEOF_REG) + (SIZEOF_MEM) - (MEM_STEP*16));
124
}
125
126
75
ANN static inline VM_Shred init_spork_shred(const VM_Shred shred, const VM_Code code) {
127
75
  const VM_Shred sh = new_shred_base(shred, code);
128
75
  vm_add_shred(shred->info->vm, sh);
129
75
  sh->tick->parent = shred->tick;
130
75
  if(!shred->tick->child.ptr)
131
32
    vector_init(&shred->tick->child);
132
75
  vector_add(&shred->tick->child, (vtype)sh);
133
75
  return sh;
134
}
135
136
7
ANN static VM_Shred init_fork_shred(const VM_Shred shred, const VM_Code code, const m_uint retsz) {
137
7
  VM* parent = shred->info->vm;
138
7
  const VM_Shred sh = new_shred_base(shred, code);
139
7
  VM* vm = (sh->info->vm = gwion_cpy(parent));
140
7
  vm->parent = parent;
141
7
  const M_Object o = sh->info->me = new_shred(sh, 0);
142
7
  ++sh->info->me->ref;
143
7
  if(!parent->gwion->data->child.ptr)
144
7
    vector_init(&parent->gwion->data->child);
145
7
  vector_add(&parent->gwion->data->child, (vtype)o);
146
7
  shreduler_add(vm->shreduler, sh);
147
7
  fork_launch(sh->info->me, retsz);
148
7
  return sh;
149
}
150
151
#define TEST0(t, pos) if(!*(t*)(reg-pos)){ shred->pc = PC; exception(shred, "ZeroDivideException"); break; }
152
153
#define ADVANCE() byte += BYTECODE_SZ;
154
155
#define SDISPATCH() goto *dispatch[*(m_bit*)byte];
156
#define IDISPATCH() { VM_INFO; SDISPATCH(); }
157
158
#define SET_BYTE(pc)	(byte = bytecode + (pc) * BYTECODE_SZ)
159
160
#define PC_DISPATCH(pc)\
161
  SET_BYTE((pc));\
162
  IDISPATCH();
163
164
#define DISPATCH()\
165
  ADVANCE();\
166
  IDISPATCH();
167
168
169
#define ADVANCE() byte += BYTECODE_SZ;
170
171
#define ADISPATCH() { ADVANCE(); SDISPATCH(); }
172
173
#define PC ((*(unsigned short*)(byte + 2)) + 1)
174
175
#define OP(t, sz, op, ...) \
176
  reg -= sz;\
177
  __VA_ARGS__\
178
  *(t*)(reg - sz) op##= *(t*)reg;\
179
  DISPATCH();
180
181
#define INT_OP(op, ...) OP(m_int, SZ_INT, op, __VA_ARGS__)
182
#define FLOAT_OP(op, ...) OP(m_float, SZ_FLOAT, op, __VA_ARGS__)
183
184
#define LOGICAL(t, sz0, sz, op)\
185
reg -= sz0;\
186
*(m_int*)(reg-SZ_INT) = (*(t*)(reg - SZ_INT) op *(t*)(reg+sz));\
187
DISPATCH()
188
189
#define INT_LOGICAL(op) LOGICAL(m_int, SZ_INT, 0, op)
190
191
#define FLOAT_LOGICAL(op) LOGICAL(m_float, SZ_FLOAT * 2 - SZ_INT, \
192
  SZ_FLOAT - SZ_INT, op)
193
194
#define SELF(t, sz,op) \
195
  *(t*)(reg - sz) = op*(t*)(reg - sz);\
196
  DISPATCH();
197
198
// check me
199
#define R(t, sz, op, ...) \
200
reg -= SZ_INT;\
201
__VA_ARGS__\
202
*(t*)(reg-sz) = (**(t**)reg op##= (*(t*)(reg-sz)));\
203
DISPATCH()
204
#define INT_R(op, ...) R(m_int, SZ_INT, op, __VA_ARGS__)
205
#define FLOAT_R(op, ...) R(m_float, SZ_FLOAT, op)
206
207
#define INT_PRE(op) \
208
/*assert(*(m_int**)(reg-SZ_INT));*/\
209
*(m_int*)(reg- SZ_INT) = op(**(m_int**)(reg-SZ_INT));\
210
DISPATCH()
211
212
#define INT_POST(op) \
213
/*assert(*(m_int**)(reg-SZ_INT));*/\
214
*(m_int*)(reg- SZ_INT) = (**(m_int**)(reg-SZ_INT))op;\
215
DISPATCH()
216
217
#define IF_OP(op) \
218
  reg -=SZ_INT;\
219
    *(m_float*)(reg-SZ_FLOAT) = (m_float)*(m_int*)(reg-SZ_FLOAT) op \
220
    *(m_float*)(reg + SZ_INT - SZ_FLOAT); \
221
  DISPATCH()
222
223
#define IF_LOGICAL(op)\
224
  reg -= SZ_FLOAT; \
225
  *(m_int*)(reg-SZ_INT) = (m_int)(*(m_int*)(reg-SZ_INT) op *(m_float*)reg); \
226
  DISPATCH()
227
__attribute__((hot))
228
229
#define IF_R(op) \
230
  reg -= SZ_INT * 2 - SZ_FLOAT; \
231
  *(m_float*)(reg-SZ_FLOAT) = (**(m_float**)(reg +SZ_INT - SZ_FLOAT) op##= \
232
    (m_float)*(m_int*)(reg-SZ_FLOAT)); \
233
  DISPATCH()
234
235
#define FI_OP(op)\
236
  reg -= SZ_INT; \
237
  *(m_float*)(reg-SZ_FLOAT) op##= (m_float)*(m_int*)reg; \
238
  DISPATCH()
239
240
#define FI_LOGICAL(op) \
241
  reg -= SZ_FLOAT; \
242
  *(m_int*)(reg-SZ_INT) = (m_int)(*(m_float*)(reg-SZ_INT) op\
243
    *(m_int*)(reg + SZ_FLOAT-SZ_INT)); \
244
  DISPATCH()
245
246
#define FI_R(op, ...) \
247
  reg -= SZ_FLOAT; \
248
  __VA_ARGS__ \
249
  *(m_int*)(reg-SZ_INT) = (**(m_int**)(reg+SZ_FLOAT -SZ_INT) op##= \
250
    /*(m_int)*/(*(m_float*)(reg-SZ_INT))); \
251
  DISPATCH()
252
253
254
#define STRINGIFY_NX(a) #a
255
#define STRINGIFY(a) STRINGIFY_NX(a)
256
#define PPCAT_NX(A, B) A ## B
257
#define PPCAT(A, B) PPCAT_NX(A, B)
258
259
#if defined(__clang__)
260
#define COMPILER clang
261
#define UNINITIALIZED "-Wuninitialized")
262
#elif defined(__GNUC__) || defined(__GNUG__)
263
#define COMPILER GCC
264
#define UNINITIALIZED "-Wmaybe-uninitialized")
265
#endif
266
267
#define PRAGMA_PUSH() \
268
_Pragma(STRINGIFY(COMPILER diagnostic push)) \
269
_Pragma(STRINGIFY(COMPILER diagnostic ignored UNINITIALIZED)
270
#define PRAGMA_POP() _Pragma(STRINGIFY(COMPILER diagnostic pop)) \
271
272
#define VAL (*(m_uint*)(byte + SZ_INT))
273
#define FVAL (*(m_float*)(byte + SZ_INT))
274
#define VAL2 (*(m_uint*)(byte + SZ_INT*2))
275
276
#define BRANCH_DISPATCH(check) \
277
  if(check) SET_BYTE(VAL);\
278
  else ADVANCE(); \
279
  IDISPATCH();
280
281
#define VM_OUT shred->code = code; shred->reg = reg; shred->mem = mem; shred->pc = PC;
282
283
__attribute__ ((hot, optimize("-O2")))
284
5049186
ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto]
285
  static const void* dispatch[] = {
286
    &&regsetimm,
287
    &&regpushimm, &&regpushfloat, &&regpushother, &&regpushaddr,
288
    &&regpushmem, &&regpushmemfloat, &&regpushmemother, &&regpushmemaddr, &&regpushmemderef,
289
    &&pushnow,
290
    &&baseint, &&basefloat, &&baseother, &&baseaddr,
291
    &&regtoreg, &&regtoregaddr, &&regtoregderef,
292
    &&structmember, &&structmemberfloat, &&structmemberother, &&structmemberaddr,
293
    &&memsetimm,
294
    &&regpushme, &&regpushmaybe,
295
    &&funcreturn,
296
    &&_goto,
297
    &&allocint, &&allocfloat, &&allocother,
298
    &&intplus, &&intminus, && intmul, &&intdiv, &&intmod,
299
    // int relationnal
300
    &&inteq, &&intne, &&intand, &&intor,
301
    &&intgt, &&intge, &&intlt, &&intle,
302
    &&intsl, &&intsr, &&intsand, &&intsor, &&intxor,
303
    &&intnegate, &&intnot, &&intcmp,
304
    &&intrassign,
305
    &&intradd, &&intrsub, &&intrmul, &&intrdiv, &&intrmod,
306
    &&intrsl, &&intrsr, &&intrsand, &&intrsor, &&intrxor,
307
    &&preinc, &&predec,
308
    &&postinc, &&postdec,
309
    &&floatadd, &&floatsub, &&floatmul, &&floatdiv,
310
// logical
311
    &&floatand, &&floator, &&floateq, &&floatne,
312
    &&floatgt, &&floatge, &&floatlt, &&floatle,
313
    &&floatneg, &&floatnot,
314
    &&floatrassign, &&floatradd, &&floatrsub, &&floatrmul, &&floatrdiv,
315
    &&ifadd, &&ifsub, &&ifmul, &&ifdiv,
316
    &&ifand, &&ifor, &&ifeq, &&ifne, &&ifgt, &&ifge, &&iflt, &&ifle,
317
    &&ifrassign, &&ifradd, &&ifrsub, &&ifrmul, &&ifrdiv,
318
    &&fiadd, &&fisub, &&fimul, &&fidiv,
319
    &&fiand, &&fior, &&fieq, &&fine, &&figt, &&fige, &&filt, &&file,
320
    &&firassign, &&firadd, &&firsub, &&firmul, &&firdiv,
321
    &&itof, &&ftoi,
322
    &&timeadv,
323
    &&setcode,
324
    &&regpop, &&regpush, &&regtomem, &&regtomemother, &&overflow, &&funcusrend, &&funcmemberend,
325
    &&sporkini, &&forkini, &&sporkfunc, &&sporkmemberfptr, &&sporkexp, &&sporkend,
326
    &&brancheqint, &&branchneint, &&brancheqfloat, &&branchnefloat,
327
    &&arrayappend, &&autoloop, &&autoloopptr, &&autoloopcount, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid,
328
    &&newobj, &&addref, &&addrefaddr, &&objassign, &&assign, &&remref,
329
    &&setobj, &&except, &&allocmemberaddr, &&dotmember, &&dotfloat, &&dotother, &&dotaddr,
330
    &&staticint, &&staticfloat, &&staticother,
331
    &&dotfunc, &&dotstaticfunc,
332
    &&gcini, &&gcadd, &&gcend,
333
    &&gacktype, &&gackend, &&gack, &&noop, &&eoc, &&other, &&regpushimm
334
  };
335
5049186
  const Shreduler s = vm->shreduler;
336
  register VM_Shred shred;
337
  register m_bit next;
338
339
10098998
  while((shred = shreduler_get(s))) {
340
626
    register VM_Code code = shred->code;
341
626
    register m_bit* bytecode = code->bytecode;
342
626
    register m_bit* byte = bytecode + shred->pc * BYTECODE_SZ;
343
626
    register m_bit* reg = shred->reg;
344
626
    register m_bit* mem = shred->mem;
345
    register union {
346
      M_Object obj;
347
      VM_Code code;
348
    } a;
349
PRAGMA_PUSH()
350
    register VM_Shred child;
351
PRAGMA_POP()
352
626
  MUTEX_LOCK(s->mutex);
353
  do {
354
626
    SDISPATCH();
355
6090
regsetimm:
356
6090
  *(m_uint*)(reg + (m_int)VAL2) = VAL;
357
6090
  DISPATCH();
358
2889
regpushimm:
359
2889
  *(m_uint*)reg = VAL;
360
2889
  reg += SZ_INT;
361
2889
  DISPATCH();
362
497
regpushfloat:
363
497
  *(m_float*)reg = FVAL;
364
497
  reg += SZ_FLOAT;
365
497
  DISPATCH();
366
regpushother:
367
//  LOOP_OPTIM
368
  for(m_uint i = 0; i <= VAL2; i+= SZ_INT)
369
    *(m_bit**)(reg+i) = (m_bit*)(VAL + i);
370
  reg += VAL2;
371
  DISPATCH();
372
1
regpushaddr:
373
1
  *(m_uint**)reg =  &VAL;
374
1
  reg += SZ_INT;
375
1
  DISPATCH()
376
3455
regpushmem:
377
3455
  *(m_uint*)reg = *(m_uint*)(mem + (m_int)VAL);
378
3455
  reg += SZ_INT;
379
3455
  DISPATCH();
380
152
regpushmemfloat:
381
152
  *(m_float*)reg = *(m_float*)(mem + (m_int)VAL);
382
152
  reg += SZ_FLOAT;
383
152
  DISPATCH();
384
2
regpushmemother:
385
6
  for(m_uint i = 0; i <= VAL2; i+= SZ_INT)
386
4
    *(m_uint*)(reg+i) = *(m_uint*)((m_bit*)(mem + (m_int)VAL) + i);
387
2
  reg += VAL2;
388
2
  DISPATCH();
389
1573
regpushmemaddr:
390
1573
  *(m_bit**)reg = &*(m_bit*)(mem + (m_int)VAL);
391
1573
  reg += SZ_INT;
392
1573
  DISPATCH()
393
1
regpushmemderef:
394
1
  memcpy(reg, *(m_uint**)(mem+(m_int)VAL), VAL2);
395
1
  reg += VAL2;
396
1
  DISPATCH()
397
145
pushnow:
398
145
  *(m_float*)reg = vm->bbq->pos;
399
145
  reg += SZ_FLOAT;
400
145
  DISPATCH();
401
2798
baseint:
402
2798
  *(m_uint*)reg = *(m_uint*)(shred->base + VAL);
403
2798
  reg += SZ_INT;
404
2798
  DISPATCH();
405
44
basefloat:
406
44
  *(m_float*)reg = *(m_float*)(shred->base + VAL);
407
44
  reg += SZ_FLOAT;
408
44
  DISPATCH();
409
baseother:
410
//  LOOP_OPTIM
411
  for(m_uint i = 0; i <= VAL2; i+= SZ_INT)
412
    *(m_uint*)(reg+i) = *(m_uint*)((shred->base + VAL) + i);
413
  reg += VAL2;
414
  DISPATCH();
415
114
baseaddr:
416
114
  *(m_uint**)reg = &*(m_uint*)(shred->base + (m_int)VAL);
417
114
  reg += SZ_INT;
418
114
  DISPATCH();
419
205
regtoreg:
420
205
  *(m_uint*)(reg + (m_int)VAL) = *(m_uint*)(reg + (m_int)VAL2);
421
205
  DISPATCH()
422
2
regtoregaddr:
423
2
  *(m_uint**)(reg + (m_int)VAL) = &*(m_uint*)(reg + (m_int)VAL2);
424
2
  DISPATCH()
425
13
regtoregderef:
426
13
  memcpy(*(m_bit**)(reg - SZ_INT), *(m_bit**)(reg + (m_int)VAL), VAL2);
427
13
  DISPATCH()
428
18
structmember:
429
18
  *(m_bit**)(reg-SZ_INT) =  *(m_bit**)(*(m_bit**)(reg-SZ_INT) + (m_int)VAL);
430
18
  DISPATCH()
431
11
structmemberfloat:
432
11
  *(m_bit**)(reg-SZ_INT) =  *(m_bit**)(*(m_bit**)(reg-SZ_INT) + (m_int)VAL);
433
11
  DISPATCH()
434
structmemberother:
435
  *(m_bit**)(reg-SZ_INT) =  *(m_bit**)(*(m_bit**)(reg-SZ_INT) + (m_int)VAL);
436
  DISPATCH()
437
17
structmemberaddr:
438
17
  *(m_bit**)(reg-SZ_INT) =  &*(*(m_bit**)(reg-SZ_INT) + (m_int)VAL);
439
17
  DISPATCH()
440
294
memsetimm:
441
294
  *(m_uint*)(mem+VAL) = VAL2;
442
294
  DISPATCH();
443
72
regpushme:
444
72
  *(M_Object*)reg = shred->info->me;
445
72
  reg += SZ_INT;
446
72
  DISPATCH()
447
31
regpushmaybe:
448
31
  *(m_uint*)reg = gw_rand((uint32_t*)vm->rand) > (UINT32_MAX / 2);
449
31
  reg += SZ_INT;
450
31
  DISPATCH();
451
561
funcreturn:
452
{
453
561
  register const m_uint pc = *(m_uint*)(mem-SZ_INT*2);
454
561
  bytecode = (code = *(VM_Code*)(mem-SZ_INT*3))->bytecode;
455
561
  mem -= (*(m_uint*)(mem-SZ_INT*4) + SZ_INT*4);
456
561
  PC_DISPATCH(pc);
457
}
458
12
_goto:
459
3585
  PC_DISPATCH(VAL);
460
171
allocint:
461
171
  *(m_uint*)reg = *(m_uint*)(mem+VAL) = 0;
462
171
  reg += SZ_INT;
463
171
  DISPATCH()
464
90
allocfloat:
465
90
  *(m_float*)reg = *(m_float*)(mem+VAL) = 0;
466
90
  reg += SZ_FLOAT;
467
90
  DISPATCH()
468
allocother:
469
//  LOOP_OPTIM
470
  for(m_uint i = 0; i <= VAL2; i += SZ_INT)
471
    *(m_uint*)(reg+i) = (*(m_uint*)(mem+VAL+i) = 0);
472
  reg += VAL2;
473
  DISPATCH()
474
475
43
intplus:  INT_OP(+)
476
108
intminus: INT_OP(-)
477
2
intmul:   INT_OP(*)
478
2
intdiv:   INT_OP(/, TEST0(m_int, 0))
479
2
intmod:   INT_OP(%, TEST0(m_int, 0))
480
481
1287
inteq:   INT_LOGICAL(==)
482
2
intne:   INT_LOGICAL(!=)
483

1
intand:  INT_LOGICAL(&&)
484

1
intor:   INT_LOGICAL(||)
485
26
intgt:   INT_LOGICAL(>)
486
1
intge:   INT_LOGICAL(>=)
487
90
intlt:   INT_LOGICAL(<)
488
1
intle:   INT_LOGICAL(<=)
489
1
intsl:   INT_LOGICAL(<<)
490
1
intsr:   INT_LOGICAL(>>)
491
1
intsand: INT_LOGICAL(&)
492
1
intsor:  INT_LOGICAL(|)
493
1
intxor:  INT_LOGICAL(^)
494
495
23
intnegate:
496
23
  *(m_int*)(reg - SZ_INT) *= -1;
497
23
  DISPATCH()
498
27
intnot: SELF(m_int, SZ_INT, !)
499
1
intcmp: SELF(m_int, SZ_INT, ~)
500
501
101
intrassign:
502
101
  reg -= SZ_INT;
503
101
  **(m_int**)reg = *(m_int*)(reg-SZ_INT);
504
101
  DISPATCH()
505
506
3
intradd: INT_R(+)
507
1
intrsub: INT_R(-)
508
1
intrmul: INT_R(*)
509
//intrdiv: INT_R(/, TEST0(m_int, -SZ_INT))
510
//intrmod: INT_R(%, TEST0(m_int, -SZ_INT))
511
1
intrdiv: INT_R(/, TEST0(m_int, SZ_INT))
512
1
intrmod: INT_R(%, TEST0(m_int, SZ_INT))
513
1
intrsl: INT_R(<<)
514
1
intrsr: INT_R(>>)
515
1
intrsand: INT_R(&)
516
1
intrsor: INT_R(|)
517
1
intrxor: INT_R(^)
518
519
1247
preinc: INT_PRE(++)
520
26
predec: INT_PRE(--)
521
522
46
postinc: INT_POST(++)
523
42
postdec: INT_POST(--)
524
525
4
floatadd: FLOAT_OP(+)
526
2
floatsub: FLOAT_OP(-)
527
73
floatmul: FLOAT_OP(*)
528
2
floatdiv: FLOAT_OP(/)
529
530

2
floatand: FLOAT_LOGICAL(&&)
531

2
floator: FLOAT_LOGICAL(||)
532
69
floateq: FLOAT_LOGICAL(==)
533
2
floatne: FLOAT_LOGICAL(!=)
534
6
floatgt: FLOAT_LOGICAL(>)
535
3
floatge: FLOAT_LOGICAL(>=)
536
5
floatlt: FLOAT_LOGICAL(<)
537
1
floatle: FLOAT_LOGICAL(<=)
538
539
2
floatneg: SELF(m_float, SZ_FLOAT, -)
540
541
4
floatnot:
542
4
  reg -= SZ_FLOAT - SZ_INT;
543
4
  *(m_int*)(reg - SZ_INT) = !*(m_float*)(reg - SZ_INT);
544
4
  DISPATCH()
545
546
16
floatrassign:
547
16
  reg -= SZ_INT;
548
16
  **(m_float**)reg = *(m_float*)(reg-SZ_FLOAT);
549
16
  DISPATCH()
550
551
2
floatradd: FLOAT_R(+)
552
12
floatrsub: FLOAT_R(-)
553
2
floatrmul: FLOAT_R(*)
554
2
floatrdiv: FLOAT_R(/)
555
556
2
ifadd: IF_OP(+)
557
5
ifsub: IF_OP(-)
558
22
ifmul: IF_OP(*)
559
2
ifdiv: IF_OP(/)
560
561

2
ifand: IF_LOGICAL(&&)
562

2
ifor: IF_LOGICAL(||)
563
2
ifeq: IF_LOGICAL(==)
564
2
ifne: IF_LOGICAL(!=)
565
3
ifgt: IF_LOGICAL(>)
566
3
ifge: IF_LOGICAL(>=)
567
3
iflt: IF_LOGICAL(<)
568
3
ifle: IF_LOGICAL(<=)
569
570
17
ifrassign: IF_R()
571
7
ifradd: IF_R(+)
572
18
ifrsub: IF_R(-)
573
1
ifrmul: IF_R(*)
574
1
ifrdiv: IF_R(/)
575
576
2
fiadd: FI_OP(+)
577
2
fisub: FI_OP(-)
578
2
fimul: FI_OP(*)
579
2
fidiv: FI_OP(/)
580
581

3
fiand: FI_LOGICAL(&&)
582

3
fior: FI_LOGICAL(||)
583
6
fieq: FI_LOGICAL(==)
584
1
fine: FI_LOGICAL(!=)
585
26
figt: FI_LOGICAL( >)
586
2
fige: FI_LOGICAL(>=)
587
2
filt: FI_LOGICAL( <)
588
2
file: FI_LOGICAL(<=)
589
590
4
firassign:
591
4
  reg -=SZ_FLOAT;
592
8
  *(m_int*)(reg-SZ_INT) = **(m_int**)(reg + SZ_FLOAT-SZ_INT) =
593
8
    (m_int)*(m_float*)(reg-SZ_INT);
594
4
  DISPATCH()
595
596
3
firadd: FI_R(+)
597
4
firsub: FI_R(-)
598
3
firmul: FI_R(*)
599
3
firdiv: FI_R(/, TEST0(m_float, SZ_INT))
600
601
82
itof:
602
82
  reg -= SZ_INT - SZ_FLOAT;
603
82
  *(m_float*)(reg-SZ_FLOAT) = (m_float)*(m_int*)(reg-SZ_FLOAT);
604
82
  DISPATCH()
605
3
ftoi:
606
3
  reg -= SZ_FLOAT - SZ_INT;
607
3
  *(m_int*)(reg-SZ_INT) = (m_int)*(m_float*)(reg-SZ_INT);
608
3
  DISPATCH()
609
133
timeadv:
610
133
  reg -= SZ_FLOAT;
611
133
  shredule(s, shred, *(m_float*)(reg-SZ_FLOAT));
612
133
  *(m_float*)(reg-SZ_FLOAT) += vm->bbq->pos;
613
133
  VM_OUT
614
133
  break;
615
2947
setcode:
616
PRAGMA_PUSH()
617
2947
  reg -= SZ_INT;
618
2947
  a.code = *(VM_Code*)reg;
619
2947
  if(!GET_FLAG((VM_Code)a.code, builtin)) {
620
2603
    register const m_uint push = *(m_uint*)(reg + SZ_INT) + *(m_uint*)(mem-SZ_INT);
621
2603
    mem += push;
622
2603
    *(m_uint*)  mem = push;mem += SZ_INT;
623
2603
    *(VM_Code*) mem = code; mem += SZ_INT;
624
2603
    *(m_uint*)  mem = PC + VAL2; mem += SZ_INT;
625
2603
    *(m_uint*) mem = a.code->stack_depth; mem += SZ_INT;
626
    next = eFuncUsrEnd;
627
  } else {
628
344
    mem += *(m_uint*)(reg + SZ_INT);
629
    next = eFuncMemberEnd;
630
  }
631
PRAGMA_POP()
632
8198
regpop:
633
8198
  reg -= VAL;
634
8198
  DISPATCH();
635
251
regpush:
636
251
  reg += VAL;
637
251
  DISPATCH();
638
876
regtomem:
639
876
  *(m_uint*)(mem+VAL) = *(m_uint*)(reg+(m_int)VAL2);
640
876
  DISPATCH()
641
148
regtomemother:
642
148
  memcpy(mem+VAL, reg, VAL2);
643
148
  DISPATCH()
644
2947
overflow:
645
2947
  if(overflow_(mem + VAL2, shred)) {
646
1
    shred->pc = PC;
647
1
    exception(shred, "StackOverflow");
648
1
    continue;
649
  }
650
PRAGMA_PUSH()
651
2946
  goto *dispatch[next];
652
PRAGMA_POP()
653
2602
funcusrend:
654
PRAGMA_PUSH()
655
2602
  byte = bytecode = (code = a.code)->bytecode;
656
PRAGMA_POP()
657
2602
  SDISPATCH();
658
344
funcmemberend:
659
344
  VM_OUT
660
  {
661
344
    register const m_uint val = VAL;
662
344
    register const m_uint val2 = VAL2;
663
344
    ((f_mfun)a.code->native_func)((*(M_Object*)mem), reg, shred);
664
344
    reg += val;
665
344
    shred->mem = (mem -= val2);
666
344
    if(!s->curr)break;
667
  }
668
315
  PC_DISPATCH(shred->pc)
669
75
sporkini:
670
75
  child = init_spork_shred(shred, (VM_Code)VAL);
671
75
  DISPATCH()
672
7
forkini:
673
7
  child = init_fork_shred(shred, (VM_Code)VAL, VAL2),
674
7
  DISPATCH()
675
50
sporkfunc:
676
//  LOOP_OPTIM
677
PRAGMA_PUSH()
678
147
  for(m_uint i = 0; i < VAL; i+= SZ_INT)
679
97
    *(m_uint*)(child->reg + i) = *(m_uint*)(reg + i + (m_int)VAL2);
680
50
  child->reg += VAL;
681
50
  DISPATCH()
682
PRAGMA_POP()
683
3
sporkmemberfptr:
684
9
  for(m_uint i = 0; i < VAL; i+= SZ_INT)
685
6
    *(m_uint*)(child->reg + i) = *(m_uint*)(reg - VAL + i);
686
3
  *(M_Object*)(child->reg + VAL) = a.obj;
687
3
  *(m_uint*)(child->reg + VAL + SZ_INT) = *(m_uint*)(reg + VAL - SZ_INT*2);
688
3
  child->reg += VAL + SZ_INT*2;
689
3
  DISPATCH()
690
29
sporkexp:
691
//  LOOP_OPTIM
692
40
  for(m_uint i = 0; i < VAL; i+= SZ_INT)
693
11
    *(m_uint*)(child->mem + i) = *(m_uint*)(mem+i);
694
29
  DISPATCH()
695
82
sporkend:
696
  assert(!VAL); // spork are not mutable
697
82
  *(M_Object*)(reg-SZ_INT) = child->info->me;
698
82
  DISPATCH()
699
1613
brancheqint:
700
1613
  reg -= SZ_INT;
701
1613
  BRANCH_DISPATCH(!*(m_uint*)reg);
702
35
branchneint:
703
35
  reg -= SZ_INT;
704
35
  BRANCH_DISPATCH(*(m_uint*)reg);
705
74
brancheqfloat:
706
74
  reg -= SZ_FLOAT;
707
74
  BRANCH_DISPATCH(!*(m_float*)reg);
708
8
branchnefloat:
709
8
  reg -= SZ_FLOAT;
710
8
  BRANCH_DISPATCH(*(m_float*)reg);
711
2
arrayappend:
712
2
  m_vector_add(ARRAY(*(M_Object*)(reg-SZ_INT)), reg);
713
2
  release(*(M_Object*)(reg-SZ_INT), shred);
714
2
  DISPATCH()
715
20
autoloop:
716
20
  m_vector_get(ARRAY(*(M_Object*)(reg-SZ_INT)), *(m_uint*)(mem + VAL), mem + VAL + SZ_INT);
717
20
  goto autoloopcount;
718
14
autoloopptr:
719
14
  *(m_bit**)(*(M_Object*)(mem + VAL + SZ_INT))->data = m_vector_addr(ARRAY(*(M_Object*)(reg-SZ_INT)), *(m_uint*)(mem + VAL));
720
34
autoloopcount:
721
34
  *(m_uint*)reg = m_vector_size(ARRAY(*(M_Object*)(reg-SZ_INT))) - (*(m_uint*)(mem + VAL))++;
722
34
  reg += SZ_INT;
723
34
  DISPATCH()
724
1631
arraytop:
725
1631
  if(*(m_uint*)(reg - SZ_INT * 2) < *(m_uint*)(reg-SZ_INT))
726
    goto newobj;
727
  else
728
    goto _goto;
729
35
arrayaccess:
730
{
731
35
  register const m_int idx = *(m_int*)(reg + SZ_INT * VAL);
732

35
  if(idx < 0 || (m_uint)idx >= m_vector_size(ARRAY(a.obj))) {
733
4
    gw_err(_("  ... at index [%" INT_F "]\n"), idx);
734
4
    gw_err(_("  ... at dimension [%" INT_F "]\n"), VAL);
735
4
    VM_OUT
736
4
    exception(shred, "ArrayOutofBounds");
737
4
    continue; // or break ?
738
  }
739
31
  DISPATCH()
740
}
741
25
arrayget:
742
25
  m_vector_get(ARRAY(a.obj), *(m_int*)(reg + SZ_INT * VAL), (reg + (m_int)VAL2));
743
25
  DISPATCH()
744
6
arrayaddr:
745
6
  *(m_bit**)(reg + (m_int)VAL2) = m_vector_addr(ARRAY(a.obj), *(m_int*)(reg + SZ_INT * VAL));
746
6
  DISPATCH()
747
22
arrayvalid:
748
// are we sure it is the array ?
749
// rather increase ref
750
22
  vector_pop(&shred->gc);
751
22
  goto regpush;
752
1619
newobj:
753
1807
  *(M_Object*)reg = new_object(vm->gwion->mp, shred, (Type)VAL2);
754
1807
  reg += SZ_INT;
755
1807
  DISPATCH()
756
638
addref:
757
638
  a.obj = *((M_Object*)(reg+(m_int)VAL) + (m_int)VAL2);
758
638
  goto addrefcommon;
759
34
addrefaddr:
760
34
  a.obj = *(*(M_Object**)(reg+(m_int)VAL) + (m_int)VAL2);
761
672
addrefcommon:
762
672
  if(a.obj)
763
632
    ++a.obj->ref;
764
672
  DISPATCH()
765
31
objassign:
766
31
  a.obj = **(M_Object**)(reg -SZ_INT);
767
31
  if(a.obj) {
768
8
    --a.obj->ref;
769
8
    _release(a.obj, shred);
770
  }
771
228
assign:
772
228
  reg -= SZ_INT;
773
228
  **(M_Object**)reg = *(M_Object*)(reg-SZ_INT);
774
228
  DISPATCH()
775
233
remref:
776
233
  release(*(M_Object*)(mem + VAL), shred);
777
233
  DISPATCH()
778
28
setobj:
779
28
  a.obj  = *(M_Object*)(reg-SZ_INT-(m_int)VAL);
780
28
  DISPATCH();
781
846
except:
782
/* TODO: Refactor except instruction             *
783
 * so that                                       *
784
 *  VAL = offset (no default SZ_INT)             *
785
 *  VAL2 = error message                         *
786
 * grep for GWOP_EXCEPT and Except, exception... */
787
846
  if(!(a.obj  = *(M_Object*)(reg-SZ_INT-VAL))) {
788
20
    shred->pc = PC;
789
20
    exception(shred, "NullPtrException");
790
20
    continue;
791
  }
792
826
  DISPATCH();
793
37
allocmemberaddr:
794
37
  a.obj = *(M_Object*)mem;
795
37
  *(m_bit**)reg = a.obj->data + VAL;
796
37
  reg += SZ_INT;
797
37
  DISPATCH()
798
135
dotmember:
799
135
  *(m_uint*)(reg-SZ_INT) = *(m_uint*)(a.obj->data + VAL);
800
135
  DISPATCH()
801
12
dotfloat:
802
12
  *(m_float*)(reg-SZ_INT) = *(m_float*)(a.obj->data + VAL);
803
12
  reg += SZ_FLOAT - SZ_INT;
804
12
  DISPATCH()
805
dotother:
806
//  LOOP_OPTIM
807
PRAGMA_PUSH()
808
  for(m_uint i = 0; i <= VAL2; i += SZ_INT)
809
    *(m_uint*)(reg+i-SZ_INT) = *(m_uint*)((a.obj->data + VAL) + i);
810
PRAGMA_POP()
811
  reg += VAL2 - SZ_INT;
812
  DISPATCH()
813
65
dotaddr:
814
65
  *(m_bit**)(reg-SZ_INT) = (a.obj->data + VAL);
815
65
  DISPATCH()
816
39
staticint:
817
39
  *(m_uint*)reg = *(m_uint*)VAL;
818
39
  reg += SZ_INT;
819
39
  DISPATCH()
820
4
staticfloat:
821
4
  *(m_float*)reg = *(m_float*)VAL;
822
4
  reg += SZ_FLOAT;
823
4
  DISPATCH()
824
staticother:
825
//  LOOP_OPTIM
826
//  for(m_uint i = 0; i <= VAL2; i += SZ_INT)
827
//    *(m_uint*)(reg+i) = *(m_uint*)((m_bit*)VAL + i);
828
  memcpy(reg, (m_bit*)VAL, VAL2);
829
  reg += VAL2;
830
  DISPATCH()
831
370
dotfunc:
832
  assert(a.obj);
833
370
  reg += SZ_INT;
834
376
dotstaticfunc:
835
PRAGMA_PUSH()
836
376
  *(VM_Code*)(reg-SZ_INT) = ((Func)vector_at(a.obj->vtable, VAL))->code;
837
PRAGMA_POP()
838
376
  DISPATCH()
839
6
gcini:
840
6
  vector_add(&shred->gc, 0);
841
6
  DISPATCH();
842
70
gcadd:
843
70
  vector_add(&shred->gc, *(vtype*)(reg-SZ_INT));
844
70
  DISPATCH();
845
6
gcend:
846
6
  while((a.obj = (M_Object)vector_pop(&shred->gc)))
847
3
    _release(a.obj, shred);
848
3
  DISPATCH()
849
638
gacktype:
850
{
851
638
  const M_Object o = *(M_Object*)(reg - SZ_INT);
852
638
  if(o)
853
616
    *(Type*)reg = o->type_ref;
854
638
  DISPATCH()
855
}
856
1091
gackend:
857
{
858
1091
  m_str str = *(m_str*)(reg - SZ_INT);
859
1091
  if(!VAL)
860
1086
    gw_out("%s\n", str);
861
  else
862
5
    *(M_Object*)(reg - SZ_INT)= new_string(vm->gwion->mp, shred, str);
863
1091
  if(str)
864
1091
    mp_free2(vm->gwion->mp, strlen(str), str);
865
1091
  DISPATCH();
866
}
867
1468
gack:
868
1468
  VM_OUT
869
1468
  gack(shred, VAL);
870
1468
  goto in;
871
2806
noop:
872
2806
  DISPATCH();
873
3247
other:
874
3247
  VM_OUT
875
3247
  ((f_instr)VAL2)(shred, (Instr)VAL);
876
4715
in:
877
4715
  if(!s->curr)
878
    break;
879
4690
  bytecode = (code = shred->code)->bytecode;
880
4690
  reg = shred->reg;
881
4690
  mem = shred->mem;
882
4690
  PC_DISPATCH(shred->pc)
883
412
eoc:
884
412
  VM_OUT
885
412
  vm_shred_exit(shred);
886
437
    } while(s->curr);
887
626
  MUTEX_UNLOCK(s->mutex);
888
  }
889
4859533
}
890
891
3150579
static void vm_run_audio(const VM *vm) {
892
3150579
  vm_run(vm);
893
3150579
  vm_ugen_init(vm);
894
3150578
}
895
896
740
VM* new_vm(MemPool p, const m_bool audio) {
897
740
  VM* vm = (VM*)mp_calloc(p, VM);
898
740
  vector_init(&vm->ugen);
899
740
  vm->bbq = new_driver(p);
900
740
  vm->bbq->run = audio ? vm_run_audio : vm_run;
901
740
  vm->shreduler  = (Shreduler)mp_calloc(p, Shreduler);
902
740
  vector_init(&vm->shreduler->shreds);
903
740
  MUTEX_SETUP(vm->shreduler->mutex);
904
740
  vm->shreduler->bbq = vm->bbq;
905
#ifndef __AFL_COMPILER
906
740
  gw_seed(vm->rand, (uint64_t)time(NULL));
907
#else
908
  gw_seed(vm->rand, 0);
909
#endif
910
740
  return vm;
911
}