• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nickg / nvc / 13738584171

08 Mar 2025 12:57PM UTC coverage: 92.236% (-0.05%) from 92.281%
13738584171

push

github

nickg
Add a simple pointer provenance tracking scheme

52 of 53 new or added lines in 3 files covered. (98.11%)

230 existing lines in 7 files now uncovered.

68028 of 73754 relevant lines covered (92.24%)

433200.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.04
/src/jit/jit-core.c
1
//
2
//  Copyright (C) 2022-2024  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "array.h"
20
#include "common.h"
21
#include "debug.h"
22
#include "diag.h"
23
#include "hash.h"
24
#include "jit/jit-priv.h"
25
#include "jit/jit.h"
26
#include "lib.h"
27
#include "lower.h"
28
#include "mir/mir-unit.h"
29
#include "object.h"
30
#include "option.h"
31
#include "rt/model.h"
32
#include "rt/mspace.h"
33
#include "rt/structs.h"
34
#include "thread.h"
35
#include "tree.h"
36
#include "type.h"
37
#include "vcode.h"
38

39
#include <assert.h>
40
#include <ctype.h>
41
#include <errno.h>
42
#include <inttypes.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <unistd.h>
46

47
#define FUNC_HASH_SZ    1024
48
#define FUNC_LIST_SZ    512
49
#define COMPILE_TIMEOUT 10000
50

51
typedef struct _jit_tier {
52
   jit_tier_t    *next;
53
   int            threshold;
54
   jit_plugin_t   plugin;
55
   void          *context;
56
} jit_tier_t;
57

58
typedef struct {
59
   size_t      length;
60
   jit_func_t *items[0];
61
} func_array_t;
62

63
typedef struct _aot_dll {
64
   jit_dll_t  *dll;
65
   jit_pack_t *pack;
66
} aot_dll_t;
67

68
typedef struct {
69
   reloc_kind_t  kind;
70
   union {
71
      uintptr_t  off;
72
      void      *ptr;
73
   };
74
} aot_reloc_t;
75

76
// The code generator knows the layout of this struct
77
typedef struct {
78
   jit_entry_fn_t  entry;
79
   const char     *strtab;
80
   const uint8_t  *debug;
81
   const uint8_t  *cpool;
82
   aot_reloc_t     relocs[0];
83
} aot_descr_t;
84

85
typedef struct _jit {
86
   chash_t         *index;
87
   mspace_t        *mspace;
88
   void            *lower_ctx;
89
   bool             silent;
90
   bool             shutdown;
91
   int              exit_status;
92
   jit_tier_t      *tiers;
93
   aot_dll_t       *aotlib;
94
   aot_dll_t       *preloadlib;
95
   jit_pack_t      *pack;
96
   func_array_t    *funcs;
97
   unsigned         next_handle;
98
   nvc_lock_t       lock;
99
   int32_t         *cover_mem;
100
   unsigned         cover_ntags;
101
   jit_irq_fn_t     interrupt;
102
   void            *interrupt_ctx;
103
   unit_registry_t *registry;
104
   mir_context_t   *mir;
105
} jit_t;
106

107
static void jit_transition(jit_t *j, jit_state_t from, jit_state_t to);
108

109
static void jit_oom_cb(mspace_t *m, size_t size)
4✔
110
{
111
   diag_t *d = diag_new(DIAG_FATAL, NULL);
4✔
112
   diag_printf(d, "out of memory attempting to allocate %zu byte object", size);
4✔
113

114
   const size_t heapsize = opt_get_size(OPT_HEAP_SIZE);
4✔
115
   diag_hint(d, NULL, "the current heap size is %zu bytes which you can "
4✔
116
             "increase with the $bold$-H$$ option, for example $bold$-H %zum$$",
117
             heapsize, MAX(1, (heapsize * 2) / 1024 / 1024));
4✔
118

119
   diag_emit(d);
4✔
120
   jit_abort_with_status(EXIT_FAILURE);
4✔
121
}
122

123
static inline jit_thread_local_t **jit_thread_local_ptr(void)
142,887,216✔
124
{
125
#ifdef USE_EMUTLS
126
   static jit_thread_local_t *local = NULL;
127
   assert(thread_id() == 0);
128
#else
129
   static __thread jit_thread_local_t *local = NULL;
142,887,216✔
130
#endif
131

132
   return &local;
142,887,216✔
133
}
134

135
jit_thread_local_t *jit_thread_local(void)
94,751,259✔
136
{
137
   jit_thread_local_t **ptr = jit_thread_local_ptr();
94,751,259✔
138

139
   if (unlikely(*ptr == NULL)) {
94,751,259✔
140
      *ptr = xcalloc(sizeof(jit_thread_local_t));
4,112✔
141
      (*ptr)->state = JIT_IDLE;
4,112✔
142
   }
143

144
   return *ptr;
94,751,259✔
145
}
146

147
jit_t *jit_new(unit_registry_t *ur)
8,856✔
148
{
149
   jit_t *j = xcalloc(sizeof(jit_t));
8,856✔
150
   j->registry    = ur;
8,856✔
151
   j->index       = chash_new(FUNC_HASH_SZ);
8,856✔
152
   j->mspace      = mspace_new(opt_get_size(OPT_HEAP_SIZE));
8,856✔
153
   j->exit_status = INT_MIN;
8,856✔
154
   j->mir         = mir_context_new();
8,856✔
155

156
   j->funcs = xcalloc_flex(sizeof(func_array_t),
8,856✔
157
                           FUNC_LIST_SZ, sizeof(jit_func_t *));
158
   j->funcs->length = FUNC_LIST_SZ;
8,856✔
159

160
   mspace_set_oom_handler(j->mspace, jit_oom_cb);
8,856✔
161

162
   // Ensure we can resolve symbols from the executable
163
   ffi_load_dll(NULL);
8,856✔
164

165
   return j;
8,856✔
166
}
167

168
static void jit_free_func(jit_func_t *f)
76,142✔
169
{
170
   jit_free_cfg(f);
76,142✔
171
   mptr_free(f->jit->mspace, &(f->privdata));
76,142✔
172
   free(f->irbuf);
76,142✔
173
   free(f->linktab);
76,142✔
174
   if (f->owns_cpool) free(f->cpool);
76,142✔
175
   free(f);
76,142✔
176
}
76,142✔
177

178
void jit_free(jit_t *j)
8,836✔
179
{
180
   store_release(&j->shutdown, true);
8,836✔
181
   async_barrier();
8,836✔
182

183
   aot_dll_t *libs[] = { j->aotlib, j->preloadlib };
8,836✔
184
   for (int i = 0; i < ARRAY_LEN(libs); i++) {
26,508✔
185
      if (libs[i] != NULL) {
17,672✔
186
         ffi_unload_dll(libs[i]->dll);
5,999✔
187
         jit_pack_free(libs[i]->pack);
5,999✔
188
         free(libs[i]);
5,999✔
189
      }
190
   }
191

192
   if (j->pack != NULL)
8,836✔
193
      jit_pack_free(j->pack);
235✔
194

195
   for (int i = 0; i < j->next_handle; i++)
73,696✔
196
      jit_free_func(j->funcs->items[i]);
64,860✔
197
   free(j->funcs);
8,836✔
198

199
   free(j->cover_mem);
8,836✔
200

201
   for (jit_tier_t *it = j->tiers, *tmp; it; it = tmp) {
12,385✔
202
      tmp = it->next;
3,549✔
203
      (*it->plugin.cleanup)(it->context);
3,549✔
204
      free(it);
3,549✔
205
   }
206

207
   mir_context_free(j->mir);
8,836✔
208
   mspace_destroy(j->mspace);
8,836✔
209
   chash_free(j->index);
8,836✔
210
   free(j);
8,836✔
211
}
8,836✔
212

213
mspace_t *jit_get_mspace(jit_t *j)
492,352✔
214
{
215
   return j->mspace;
492,352✔
216
}
217

218
void *jit_mspace_alloc(size_t size)
39,575,903✔
219
{
220
   jit_thread_local_t *thread = jit_thread_local();
39,575,903✔
221
   assert(thread->state == JIT_RUNNING);
39,575,903✔
222
   return mspace_alloc(thread->jit->mspace, size);
39,575,903✔
223
}
224

225
static void jit_install(jit_t *j, jit_func_t *f)
64,873✔
226
{
227
   assert_lock_held(&(j->lock));
64,873✔
228

229
   func_array_t *list = j->funcs;
64,873✔
230
   if (f->handle >= list->length) {
64,873✔
231
      const size_t newlen = MAX(f->handle + 1, list->length * 2);
12✔
232
      func_array_t *new = xcalloc_flex(sizeof(func_array_t),
12✔
233
                                       newlen, sizeof(jit_func_t *));
234
      new->length = newlen;
12✔
235
      for (size_t i = 0; i < list->length; i++)
10,764✔
236
         new->items[i] = list->items[i];
10,752✔
237

238
      // Synchronises with load_acquire in jit_get_func
239
      store_release(&(j->funcs), new);
12✔
240

241
      async_free(list);
12✔
242
      list = new;
12✔
243
   }
244

245
   // Synchronises with load_acquire in jit_get_func
246
   store_release(&(list->items[f->handle]), f);
64,873✔
247

248
   chash_put(j->index, f->name, f);
64,873✔
249
}
64,873✔
250

251
static jit_handle_t jit_lazy_compile_locked(jit_t *j, ident_t name)
98,315✔
252
{
253
   assert_lock_held(&j->lock);
98,315✔
254

255
   jit_func_t *f = chash_get(j->index, name);
98,315✔
256
   if (f != NULL)
98,315✔
257
      return f->handle;
33,534✔
258

259
   aot_descr_t *descr = NULL;
64,781✔
260
   if (j->aotlib != NULL || j->preloadlib != NULL) {
64,781✔
261
      LOCAL_TEXT_BUF tb = safe_symbol(name);
113,664✔
262
      tb_cat(tb, ".descr");
56,832✔
263

264
      aot_dll_t *try[] = { j->aotlib, j->preloadlib };
56,832✔
265
      for (int i = 0; i < ARRAY_LEN(try); i++) {
130,017✔
266
         if (try[i] == NULL)
105,511✔
267
            continue;
42,091✔
268
         else if ((descr = ffi_find_symbol(try[i]->dll, tb_get(tb)))) {
63,420✔
269
            jit_pack_put(try[i]->pack, name, descr->cpool,
32,326✔
270
                         descr->strtab, descr->debug);
271
            break;
32,326✔
272
         }
273
      }
274
   }
275

276
   jit_entry_fn_t entry =
129,562✔
277
      jit_bind_intrinsic(name) ?: (descr ? descr->entry : jit_interp);
64,781✔
278

279
   f = xcalloc(sizeof(jit_func_t));
64,781✔
280
   f->name      = name;
64,781✔
281
   f->state     = descr ? JIT_FUNC_COMPILING : JIT_FUNC_PLACEHOLDER;
64,781✔
282
   f->jit       = j;
64,781✔
283
   f->handle    = j->next_handle++;
64,781✔
284
   f->next_tier = j->tiers;
64,781✔
285
   f->hotness   = f->next_tier ? f->next_tier->threshold : 0;
64,781✔
286
   f->entry     = entry;
64,781✔
287

288
   // Install now to allow circular references in relocations
289
   jit_install(j, f);
64,781✔
290

291
   if (descr != NULL) {
64,781✔
292
      for (aot_reloc_t *r = descr->relocs; r->kind != RELOC_NULL; r++) {
82,213✔
293
         const char *str = descr->strtab + r->off;
49,887✔
294
         if (r->kind == RELOC_COVER) {
49,887✔
295
            // TODO: get rid of the double indirection here by
296
            //       allocating coverage memory earlier
297
            r->ptr = &(j->cover_mem);
217✔
298
         }
299
         else if (r->kind == RELOC_PROCESSED) {
49,670✔
300
            // Detect musl libc brokenness
UNCOV
301
            diag_t *d = diag_new(DIAG_FATAL, NULL);
×
302
            diag_printf(d, "shared library containing %s was not properly "
×
303
                        "unloaded", istr(f->name));
UNCOV
304
            diag_hint(d, NULL, "this is probably because your libc does not "
×
305
                      "implement dlclose(3) correctly");
UNCOV
306
            diag_hint(d, NULL, "run the $bold$-e$$ and $bold$-r$$ steps in "
×
307
                      "separate commands as a workaround");
UNCOV
308
            diag_emit(d);
×
309
            fatal_exit(1);
×
310
         }
311
         else {
312
            jit_handle_t h = jit_lazy_compile_locked(j, ident_new(str));
49,670✔
313
            if (h == JIT_HANDLE_INVALID)
49,670✔
314
               fatal_trace("relocation against invalid function %s", str);
315

316
            switch (r->kind) {
49,670✔
317
            case RELOC_FUNC:
31,417✔
318
               r->ptr = jit_get_func(j, h);
31,417✔
319
               break;
31,417✔
320
            case RELOC_HANDLE:
622✔
321
               r->ptr = (void *)(uintptr_t)h;
622✔
322
               break;
622✔
323
            case RELOC_PRIVDATA:
17,631✔
324
               r->ptr = jit_get_privdata_ptr(j, jit_get_func(j, h));
17,631✔
325
               break;
17,631✔
UNCOV
326
            default:
×
327
               fatal_trace("unhandled relocation kind %d", r->kind);
328
            }
329
         }
330

331
         r->kind = RELOC_PROCESSED;
49,887✔
332
      }
333

334
      store_release(&f->state, JIT_FUNC_READY);
32,326✔
335
   }
336

337
   return f->handle;
64,781✔
338
}
339

340
jit_handle_t jit_lazy_compile(jit_t *j, ident_t name)
165,021✔
341
{
342
   jit_func_t *f = chash_get(j->index, name);
165,021✔
343
   if (f != NULL)
165,021✔
344
      return f->handle;
116,376✔
345

346
   SCOPED_LOCK(j->lock);
97,290✔
347
   return jit_lazy_compile_locked(j, name);
48,645✔
348
}
349

350
jit_func_t *jit_get_func(jit_t *j, jit_handle_t handle)
22,076,758✔
351
{
352
   assert(handle != JIT_HANDLE_INVALID);
22,076,758✔
353

354
   // Synchronises with store_release in jit_install
355
   func_array_t *list = load_acquire(&(j->funcs));
22,076,758✔
356
   assert(handle < list->length);
22,076,758✔
357

358
   // Synchronises with store_release in jit_install
359
   jit_func_t *f = load_acquire(&(list->items[handle]));
22,076,758✔
360
   assert(f != NULL);
22,076,758✔
361
   return f;
22,076,758✔
362
}
363

364
static inline bool jit_fill_from_aot(jit_func_t *f, aot_dll_t *lib)
68,213✔
365
{
366
   return lib != NULL && jit_pack_fill(lib->pack, f->jit, f);
68,213✔
367
}
368

369
__attribute__((noreturn))
370
static void jit_missing_unit(jit_func_t *f)
1✔
371
{
372
   tree_t unit = lib_get_qualified(f->name);
1✔
373
   if (unit != NULL && tree_kind(unit) == T_PACKAGE)
1✔
374
      jit_msg(tree_loc(unit), DIAG_FATAL, "missing body for package %s",
1✔
375
              istr(f->name));
376
   else
UNCOV
377
      jit_msg(NULL, DIAG_FATAL, "missing body for %s", istr(f->name));
×
378

UNCOV
379
   __builtin_unreachable();
×
380
}
381

382
void jit_fill_irbuf(jit_func_t *f)
589,350✔
383
{
384
   const func_state_t state = load_acquire(&(f->state));
589,350✔
385
   switch (state) {
589,350✔
386
   case JIT_FUNC_READY:
557,060✔
387
      if (f->irbuf != NULL)
557,060✔
388
         return;
389
      // Fall-through
390
   case JIT_FUNC_PLACEHOLDER:
391
      if (atomic_cas(&(f->state), state, JIT_FUNC_COMPILING))
34,623✔
392
         break;
393
      // Fall-through
394
   case JIT_FUNC_COMPILING:
395
      // Another thread is compiling this function
UNCOV
396
      for (int timeout = 0; load_acquire(&(f->state)) != JIT_FUNC_READY; ) {
×
397
         if (++timeout % COMPILE_TIMEOUT == 0)
×
398
            warnf("waiting for %s to finish compiling", istr(f->name));
×
399
         thread_sleep(100);
×
400
      }
401
      return;
UNCOV
402
   case JIT_FUNC_ERROR:
×
403
      jit_missing_unit(f);
×
404
      break;
×
405
   default:
×
406
      fatal_trace("illegal function state for %s", istr(f->name));
407
   }
408

409
   assert(f->irbuf == NULL);
34,623✔
410

411
#ifndef USE_EMUTLS
412
   const jit_state_t oldstate = jit_thread_local()->state;
34,623✔
413
   jit_transition(f->jit, oldstate, JIT_COMPILING);
34,623✔
414
#endif
415

416
   if (jit_fill_from_aot(f, f->jit->aotlib))
34,623✔
417
      goto done;
1,033✔
418

419
   if (jit_fill_from_aot(f, f->jit->preloadlib))
33,590✔
420
      goto done;
1,300✔
421

422
   if (f->jit->pack != NULL && jit_pack_fill(f->jit->pack, f->jit, f))
32,290✔
423
      goto done;
840✔
424

425
   vcode_unit_t unit = NULL;
31,450✔
426
   if (f->jit->registry != NULL) {
31,450✔
427
      // Unit registry is not thread-safe
428
      SCOPED_LOCK(f->jit->lock);
31,450✔
429
      unit = unit_registry_get(f->jit->registry, f->name);
31,450✔
430
   }
431

432
   if (unit == NULL) {
31,447✔
433
      store_release(&(f->state), JIT_FUNC_ERROR);
1✔
434
      jit_missing_unit(f);
1✔
435
   }
436

437
   mir_unit_t *mu;
31,446✔
438
   {
439
      // MIR import is not thread-safe
440
      SCOPED_LOCK(f->jit->lock);
62,892✔
441

442
      mu = mir_get_unit(f->jit->mir, f->name);
31,446✔
443
      if (mu == NULL) {
31,446✔
444
         mu = mir_import(f->jit->mir, unit);
31,365✔
445
         mir_put_unit(f->jit->mir, mu);
31,365✔
446
      }
447
   }
448

449
   jit_irgen(f, mu);
31,446✔
450

451
   {
452
      SCOPED_LOCK(f->jit->lock);
62,892✔
453
      mir_unit_free(mu);
31,446✔
454
   }
455

456
 done:
34,619✔
457
#ifndef USE_EMUTLS
458
   jit_transition(f->jit, JIT_COMPILING, oldstate);
34,619✔
459
#endif
460
}
461

462
jit_handle_t jit_compile(jit_t *j, ident_t name)
999✔
463
{
464
   jit_handle_t handle = jit_lazy_compile(j, name);
999✔
465
   if (handle == JIT_HANDLE_INVALID)
999✔
466
      return handle;
467

468
   jit_func_t *f = jit_get_func(j, handle);
999✔
469
   jit_fill_irbuf(f);
999✔
470

471
   return handle;
999✔
472
}
473

474
void *jit_link(jit_t *j, jit_handle_t handle)
148✔
475
{
476
   if (handle == JIT_HANDLE_INVALID)
148✔
477
      return NULL;
478

479
   jit_func_t *f = jit_get_func(j, handle);
148✔
480
   if (f->privdata != MPTR_INVALID)
148✔
481
      return *mptr_get(f->privdata);
133✔
482

483
   f->privdata = mptr_new(j->mspace, "privdata");
15✔
484

485
   jit_fill_irbuf(f);
15✔
486

487
   tlab_t tlab = jit_null_tlab(j);
15✔
488
   jit_scalar_t p1 = { .pointer = NULL }, p2 = p1, result;
15✔
489
   if (!jit_fastcall(j, f->handle, &result, p1, p2, &tlab)) {
15✔
UNCOV
490
      error_at(&(f->object->loc), "failed to initialise %s", istr(f->name));
×
UNCOV
491
      result.pointer = NULL;
×
492
   }
493
   else if (result.pointer == NULL)
15✔
494
      fatal_trace("link %s returned NULL", istr(f->name));
495
   else if (f->privdata == MPTR_INVALID)
15✔
496
      fatal_trace("cannot link unit %s", istr(f->name));
497

498
   // Initialisation should save the context pointer
499
   assert(result.pointer == *mptr_get(f->privdata));
15✔
500

501
   return result.pointer;
15✔
502
}
503

504
void **jit_get_privdata_ptr(jit_t *j, jit_func_t *f)
4,357,833✔
505
{
506
   if (f->privdata == MPTR_INVALID)
4,357,833✔
507
      f->privdata = mptr_new(j->mspace, "privdata");
25,716✔
508

509
   return mptr_get(f->privdata);
4,357,833✔
510
}
511

512
void *jit_get_frame_var(jit_t *j, jit_handle_t handle, ident_t name)
364✔
513
{
514
   jit_func_t *f = jit_get_func(j, handle);
364✔
515
   if (f->privdata == MPTR_INVALID)
364✔
516
      fatal_trace("%s not linked", istr(f->name));
517

518
   jit_fill_irbuf(f);
364✔
519

520
   for (int i = 0; i < f->nvars; i++) {
958✔
521
      if (f->linktab[i].name == name)
958✔
522
         return *mptr_get(f->privdata) + f->linktab[i].offset;
364✔
523
   }
524

525
   fatal_trace("%s has no variable %s", istr(f->name), istr(name));
526
}
527

528
static void jit_emit_trace(diag_t *d, const loc_t *loc, object_t *enclosing,
7,364✔
529
                           const char *symbol)
530
{
531
   tree_t tree = tree_from_object(enclosing);
7,364✔
532
   if (tree != NULL) {
7,364✔
533
      switch (tree_kind(tree)) {
7,106✔
534
      case T_PROCESS:
4,591✔
535
         {
536
            rt_proc_t *proc = get_active_proc();
4,591✔
537
            const char *name = istr(proc ? proc->name : tree_ident(tree));
4,591✔
538
            diag_trace(d, loc, "Process$$ %s", name);
4,591✔
539
         }
540
         break;
4,591✔
541
      case T_ATTR_SPEC:
1✔
542
         assert(ident_casecmp(tree_ident(tree), well_known(W_FOREIGN)));
1✔
543
         diag_trace(d, loc, "Subprogram$$ %s",
1✔
544
                    type_pp(tree_type(tree_ref(tree))));
545
         break;
1✔
546
      case T_FUNC_BODY:
1,318✔
547
      case T_FUNC_DECL:
548
         diag_trace(d, loc, "Function$$ %s", type_pp(tree_type(tree)));
1,318✔
549
         break;
1,318✔
550
      case T_PROC_BODY:
1,026✔
551
      case T_PROC_DECL:
552
         diag_trace(d, loc, "Procedure$$ %s", type_pp(tree_type(tree)));
1,026✔
553
         break;
1,026✔
554
      case T_TYPE_DECL:
16✔
555
         if (strstr(symbol, "$value"))
16✔
556
            diag_trace(d, loc, "Attribute$$ %s'VALUE", istr(tree_ident(tree)));
13✔
557
         else
558
            diag_trace(d, loc, "Type$$ %s", istr(tree_ident(tree)));
3✔
559
         break;
560
      case T_BLOCK:
29✔
561
         diag_trace(d, loc, "Process$$ (init)");
29✔
562
         break;
29✔
563
      case T_PACKAGE:
4✔
564
      case T_PACK_BODY:
565
      case T_PACK_INST:
566
         diag_trace(d, loc, "Package$$ %s", istr(tree_ident(tree)));
4✔
567
         break;
4✔
568
      case T_INERTIAL:
6✔
569
         diag_trace(d, loc, "Equivalent process");
6✔
570
         break;
6✔
UNCOV
571
      case T_TYPE_CONV:
×
UNCOV
572
         diag_trace(d, loc, "Type conversion %s", type_pp(tree_type(tree)));
×
UNCOV
573
         break;
×
574
      default:
115✔
575
         {
576
            const char *class = class_str(class_of(tree));
115✔
577
            diag_trace(d, loc, "%c%s %s", toupper_iso88591(class[0]),
115✔
578
                       class + 1, istr(tree_ident(tree)));
579
         }
580
         break;
115✔
581
      }
582
   }
583
}
7,364✔
584

585
jit_stack_trace_t *jit_stack_trace(void)
6,602✔
586
{
587
   jit_thread_local_t *thread = jit_thread_local();
6,602✔
588

589
   int count = 0;
6,602✔
590
   for (jit_anchor_t *a = thread->anchor; a; a = a->caller)
15,845✔
591
      count++;
9,243✔
592

593
   jit_stack_trace_t *stack =
6,602✔
594
      xmalloc_flex(sizeof(jit_stack_trace_t), count, sizeof(jit_frame_t));
6,602✔
595
   stack->count = count;
6,602✔
596

597
   jit_frame_t *frame = stack->frames;
6,602✔
598
   for (jit_anchor_t *a = thread->anchor; a; a = a->caller, frame++) {
15,845✔
599
      frame->loc    = LOC_INVALID;
9,243✔
600
      frame->symbol = a->func->name;
9,243✔
601
      frame->object = NULL;
9,243✔
602

603
#ifdef USE_EMUTLS
604
      if (load_acquire(&a->func->state) == JIT_FUNC_COMPILING)
605
         continue;   // Cannot use jit_transition in jit_fill_irbuf
606
#endif
607

608
      jit_fill_irbuf(a->func);
9,243✔
609

610
      frame->object = a->func->object;
9,243✔
611

612
      // Scan backwards to find the last debug info
613
      assert(a->irpos < a->func->nirs);
9,243✔
614
      frame->loc = frame->object ? frame->object->loc : LOC_INVALID;
9,243✔
615
      for (jit_ir_t *ir = &(a->func->irbuf[a->irpos]);
9,243✔
616
           ir >= a->func->irbuf; ir--) {
52,150✔
617
         if (ir->op == J_DEBUG) {
51,873✔
618
            frame->loc = ir->arg1.loc;
8,949✔
619
            break;
8,949✔
620
         }
621
         else if (ir->target)
42,924✔
622
            break;
623
      }
624
   }
625

626
   return stack;
6,602✔
627
}
628

629
static void jit_diag_cb(diag_t *d, void *arg)
6,311✔
630
{
631
   jit_t *j = arg;
6,311✔
632

633
   if (j->silent) {
6,311✔
634
      diag_suppress(d, true);
1,052✔
635
      return;
1,052✔
636
   }
637
   else if (unlikely(jit_thread_local()->state != JIT_RUNNING))
5,259✔
638
      fatal_trace("JIT diag callback called when not running");
639

640
   jit_stack_trace_t *stack LOCAL = jit_stack_trace();
10,518✔
641

642
   for (int i = 0; i < stack->count; i++) {
12,628✔
643
      jit_frame_t *frame = &(stack->frames[i]);
7,369✔
644

645
      if (frame->object != NULL)
7,369✔
646
         jit_emit_trace(d, &(frame->loc), frame->object, istr(frame->symbol));
7,364✔
647
      else
648
         diag_trace(d, &(frame->loc), "%s", istr(frame->symbol));
5✔
649
   }
650
}
651

652
static void jit_transition(jit_t *j, jit_state_t from, jit_state_t to)
36,519,544✔
653
{
654
   jit_thread_local_t *thread = jit_thread_local();
36,519,544✔
655

656
#ifdef DEBUG
657
   if (thread->state != from)
36,519,544✔
658
      fatal_trace("expected thread state %d but have %d", from, thread->state);
659
#endif
660

661
   thread->state = to;
36,519,544✔
662

663
   switch (to) {
36,519,544✔
664
   case JIT_RUNNING:
18,303,849✔
665
      if (from != JIT_RUNNING) {
18,303,849✔
666
         diag_add_hint_fn(jit_diag_cb, j);
18,191,911✔
667
         thread->jit = j;
18,191,911✔
668
      }
669
      else
670
         assert(thread->jit == j);
111,938✔
671
      break;
672
   case JIT_IDLE:
18,180,851✔
673
      if (from == JIT_RUNNING) {
18,180,851✔
674
         diag_remove_hint_fn(jit_diag_cb);
18,169,180✔
675
         thread->jit = NULL;
18,169,180✔
676
      }
677
      break;
678
   case JIT_COMPILING:
34,844✔
679
      if (from == JIT_RUNNING) {
34,844✔
680
         diag_remove_hint_fn(jit_diag_cb);
22,731✔
681
         thread->jit = NULL;
22,731✔
682
      }
683
      break;
684
   }
685
}
36,519,544✔
686

687
static bool jit_try_vcall(jit_t *j, jit_func_t *f, jit_scalar_t *args,
18,225,153✔
688
                          tlab_t *tlab)
689
{
690
   jit_thread_local_t *volatile thread = jit_thread_local();
18,225,153✔
691
   volatile const jit_state_t oldstate = thread->state;
18,225,153✔
692

693
   const int rc = jit_setjmp(thread->abort_env);
18,225,153✔
694
   if (rc == 0) {
18,226,608✔
695
      thread->jmp_buf_valid = 1;
18,225,153✔
696
      jit_transition(j, oldstate, JIT_RUNNING);
18,225,153✔
697

698
      (*f->entry)(f, NULL, args, tlab);
18,225,153✔
699

700
      jit_transition(j, JIT_RUNNING, oldstate);
18,223,694✔
701
      thread->jmp_buf_valid = 0;
18,223,694✔
702
      thread->anchor = NULL;
18,223,694✔
703
      return true;
18,223,694✔
704
   }
705
   else {
706
      jit_transition(j, JIT_RUNNING, oldstate);
1,455✔
707
      thread->jmp_buf_valid = 0;
1,455✔
708
      thread->anchor = NULL;
1,455✔
709
      return false;
1,455✔
710
   }
711
}
712

713
static void jit_unpack_args(jit_func_t *f, jit_scalar_t *args, va_list ap)
59,006✔
714
{
715
   jit_fill_irbuf(f);  // Ensure FFI spec is set
59,006✔
716

717
   int wptr = 0;
59,006✔
718
   for (int i = 1; ffi_spec_has(f->spec, i); i++) {
176,800✔
719
      switch (ffi_spec_get(f->spec, i)) {
117,794✔
720
      case FFI_POINTER:
58,818✔
721
         args[wptr++].pointer = va_arg(ap, void *);
58,818✔
722
         break;
58,818✔
723
      case FFI_FLOAT:
77✔
724
         args[wptr++].real = va_arg(ap, double);
77✔
725
         break;
77✔
726
      case FFI_UARRAY:
58,356✔
727
         args[wptr++].pointer = va_arg(ap, void *);
58,356✔
728
         args[wptr++].integer = va_arg(ap, int32_t);
58,356✔
729
         args[wptr++].integer = va_arg(ap, int32_t);
58,356✔
730
         break;
58,356✔
731
      case FFI_INT8:
359✔
732
      case FFI_INT16:
733
      case FFI_INT32:
734
         args[wptr++].integer = va_arg(ap, int32_t);
359✔
735
         break;
359✔
736
      case FFI_UINT8:
94✔
737
      case FFI_UINT16:
738
      case FFI_UINT32:
739
         args[wptr++].integer = va_arg(ap, uint32_t);
94✔
740
         break;
94✔
741
      default:
90✔
742
         args[wptr++].integer = va_arg(ap, int64_t);
90✔
743
         break;
90✔
744
      }
745
   }
746
}
59,006✔
747

748
bool jit_try_call(jit_t *j, jit_handle_t handle, jit_scalar_t *result, ...)
58,649✔
749
{
750
   va_list ap;
58,649✔
751
   va_start(ap, result);
58,649✔
752

753
   jit_func_t *f = jit_get_func(j, handle);
58,649✔
754

755
   jit_scalar_t args[JIT_MAX_ARGS];
58,649✔
756
   jit_unpack_args(f, args, ap);
58,649✔
757

758
   va_end(ap);
58,649✔
759

760
   tlab_t tlab = jit_null_tlab(j);
58,649✔
761
   if (!jit_try_vcall(j, f, args, &tlab))
58,649✔
762
      return false;
763

764
   *result = args[0];
58,041✔
765
   return true;
58,041✔
766
}
767

768
jit_scalar_t jit_call(jit_t *j, jit_handle_t handle, ...)
357✔
769
{
770
   va_list ap;
357✔
771
   va_start(ap, handle);
357✔
772

773
   jit_func_t *f = jit_get_func(j, handle);
357✔
774

775
   jit_scalar_t args[JIT_MAX_ARGS];
357✔
776
   jit_unpack_args(f, args, ap);
357✔
777

778
   va_end(ap);
357✔
779

780
   tlab_t tlab = jit_null_tlab(j);
357✔
781

782
   if (!jit_try_vcall(j, f, args, &tlab))
357✔
783
      fatal_trace("call to %s failed", istr(jit_get_func(j, handle)->name));
784

785
   return args[0];
357✔
786
}
787

788
bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result,
18,138,897✔
789
                  jit_scalar_t p1, jit_scalar_t p2, tlab_t *tlab)
790
{
791
   jit_func_t *f = jit_get_func(j, handle);
18,138,897✔
792

793
   jit_scalar_t args[JIT_MAX_ARGS];
18,138,897✔
794
   args[0] = p1;
18,138,897✔
795
   args[1] = p2;
18,138,897✔
796

797
   if (!jit_try_vcall(j, f, args, tlab))
18,138,897✔
798
      return false;
799

800
   *result = args[0];
18,138,465✔
801
   return true;
18,138,465✔
802
}
803

804
bool jit_vfastcall(jit_t *j, jit_handle_t handle, const jit_scalar_t *inargs,
15,964✔
805
                   unsigned nargs, jit_scalar_t *results, unsigned nresults,
806
                   tlab_t *tlab)
807
{
808
   jit_func_t *f = jit_get_func(j, handle);
15,964✔
809

810
   jit_scalar_t args[JIT_MAX_ARGS];
15,964✔
811
   memcpy(args, inargs, nargs * sizeof(jit_scalar_t));
15,964✔
812

813
   if (!jit_try_vcall(j, f, args, tlab))
15,964✔
814
      return false;
815

816
   memcpy(results, args, nresults * sizeof(jit_scalar_t));
15,964✔
817
   return true;
15,964✔
818
}
819

820
void *jit_call_thunk(jit_t *j, vcode_unit_t unit, void *context,
11,286✔
821
                     thunk_result_fn_t fn, void *arg)
822
{
823
   assert(vcode_unit_kind(unit) == VCODE_UNIT_THUNK);
11,286✔
824

825
   jit_func_t *f = xcalloc(sizeof(jit_func_t));
11,286✔
826
   f->state  = JIT_FUNC_COMPILING;
11,286✔
827
   f->jit    = j;
11,286✔
828
   f->handle = JIT_HANDLE_INVALID;
11,286✔
829
   f->entry  = jit_interp;
11,286✔
830
   f->object = vcode_unit_object(unit);
11,286✔
831

832
   mir_unit_t *mu = mir_import(f->jit->mir, unit);
11,286✔
833
   jit_irgen(f, mu);
11,286✔
834
   mir_unit_free(mu);
11,286✔
835

836
   jit_scalar_t args[JIT_MAX_ARGS];
11,286✔
837
   args[0].pointer = context;
11,286✔
838

839
   tlab_t tlab = jit_null_tlab(j);
11,286✔
840

841
   void *user = NULL;
11,286✔
842
   if (jit_try_vcall(j, f, args, &tlab))
11,286✔
843
      user = (*fn)(args, arg);
10,867✔
844

845
   jit_free_func(f);
11,282✔
846
   return user;
11,282✔
847
}
848

849
tlab_t jit_null_tlab(jit_t *j)
105,075✔
850
{
851
   tlab_t t = { .mspace = j->mspace };
105,075✔
852
   return t;
105,075✔
853
}
854

855
void jit_set_silent(jit_t *j, bool silent)
25,798✔
856
{
857
   j->silent = silent;
25,798✔
858
}
25,798✔
859

860
static aot_dll_t *load_dll_internal(jit_t *j, const char *path)
6,005✔
861
{
862
   uint32_t abi_version = 0;
6,005✔
863

864
   aot_dll_t *lib = xcalloc(sizeof(aot_dll_t));
6,005✔
865
   lib->pack = jit_pack_new();
6,005✔
866
   lib->dll  = ffi_load_dll(path);
6,005✔
867

868
   uint32_t *p = ffi_find_symbol(lib->dll, "__nvc_abi_version");
6,005✔
869
   if (p == NULL)
6,005✔
UNCOV
870
      warnf("%s: cannot find symbol __nvc_abi_version", path);
×
871
   else
872
      abi_version = *p;
6,005✔
873

874
   if (abi_version != RT_ABI_VERSION)
6,005✔
UNCOV
875
      fatal("%s: ABI version %d does not match current version %d",
×
876
            path, abi_version, RT_ABI_VERSION);
877

878
   if (opt_get_int(OPT_JIT_LOG))
6,005✔
UNCOV
879
      debugf("loaded AOT library from %s", path);
×
880

881
   return lib;
6,005✔
882
}
883

884
void jit_preload(jit_t *j)
4,811✔
885
{
886
#ifdef HAVE_LLVM
887
   if (j->preloadlib != NULL)
4,811✔
888
      fatal_trace("Preload library already loaded");
889

890
   lib_t std = lib_find(well_known(W_STD));
4,811✔
891
   if (std == NULL)
4,811✔
UNCOV
892
      fatal("cannot find STD library");
×
893

894
   LOCAL_TEXT_BUF tb = tb_new();
4,811✔
895
   tb_cat(tb, lib_path(std));
4,811✔
896
   tb_cat(tb, DIR_SEP "..");
4,811✔
897

898
   const char *preload_vers[] = { "93", "93", "93", "93", "08", "19" };
4,811✔
899
   tb_printf(tb, DIR_SEP "preload%s." DLL_EXT, preload_vers[standard()]);
4,811✔
900

901
   const char *path = tb_get(tb);
4,811✔
902
   file_info_t info;
4,811✔
903
   if (!get_file_info(path, &info) || info.type != FILE_REGULAR)
4,811✔
UNCOV
904
      fatal("missing preload library at %s", path);
×
905

906
   j->preloadlib = load_dll_internal(j, path);
4,811✔
907
#endif  // HAVE_LLVM
908
}
4,811✔
909

910
void jit_load_dll(jit_t *j, ident_t name)
3,316✔
911
{
912
   lib_t lib = lib_require(ident_until(name, '.'));
3,316✔
913

914
   LOCAL_TEXT_BUF tb = tb_new();
3,316✔
915
   tb_printf(tb, "_%s", istr(name));
3,316✔
916
   if (opt_get_int(OPT_NO_SAVE))
3,316✔
917
      tb_printf(tb, ".%d", getpid());
2,848✔
918
   tb_cat(tb, "." DLL_EXT);
3,316✔
919

920
   char so_path[PATH_MAX];
3,316✔
921
   lib_realpath(lib, tb_get(tb), so_path, sizeof(so_path));
3,316✔
922

923
   if (access(so_path, F_OK) != 0)
3,316✔
924
      return;
2,122✔
925

926
   if (j->aotlib != NULL)
1,194✔
927
      fatal_trace("AOT library already loaded");
928

929
   j->aotlib = load_dll_internal(j, so_path);
1,194✔
930
}
931

932
void jit_load_pack(jit_t *j, FILE *f)
235✔
933
{
934
   assert(j->pack == NULL);
235✔
935
   j->pack = jit_read_pack(f);
235✔
936
}
235✔
937

938
void jit_msg(const loc_t *where, diag_level_t level, const char *fmt, ...)
706✔
939
{
940
   diag_t *d = diag_new(level, where);
706✔
941

942
   va_list ap;
706✔
943
   va_start(ap, fmt);
706✔
944
   diag_vprintf(d, fmt, ap);
706✔
945
   va_end(ap);
706✔
946

947
   diag_emit(d);
706✔
948

949
   if (level == DIAG_FATAL)
706✔
950
      jit_abort_with_status(EXIT_FAILURE);
706✔
UNCOV
951
}
×
952

953
void jit_abort(void)
1,456✔
954
{
955
   jit_thread_local_t *thread = jit_thread_local();
1,456✔
956

957
   switch (thread->state) {
1,456✔
958
   case JIT_IDLE:
1✔
959
   case JIT_COMPILING:
960
      fatal_exit(1);
1✔
961
      break;
1,455✔
962
   case JIT_RUNNING:
1,455✔
963
      if (thread->jmp_buf_valid)
1,455✔
964
         jit_longjmp(thread->abort_env, 1);
1,455✔
965
      else {
UNCOV
966
         const int code = atomic_load(&thread->jit->exit_status);
×
UNCOV
967
         fatal_exit(code);
×
968
      }
UNCOV
969
      break;
×
970
   }
971

UNCOV
972
   __builtin_unreachable();
×
973
}
974

975
void jit_abort_with_status(int code)
1,345✔
976
{
977
   assert(code != INT_MIN);
1,345✔
978

979
   jit_thread_local_t *thread = jit_thread_local();
1,345✔
980
   if (thread->jit != NULL)
1,345✔
981
      atomic_store(&(thread->jit->exit_status), code);
1,344✔
982

983
   jit_abort();
1,345✔
984
}
985

986
void jit_reset_exit_status(jit_t *j)
12,918✔
987
{
988
   atomic_store(&(j->exit_status), INT_MIN);
12,918✔
989
}
12,918✔
990

991
bool jit_exit_status(jit_t *j, int *status)
3,971✔
992
{
993
   if (j->exit_status != INT_MIN) {
3,971✔
994
      *status = j->exit_status;
320✔
995
      return true;
320✔
996
   }
997
   else
998
      return false;
999
}
1000

1001
static void jit_async_cgen(void *context, void *arg)
3✔
1002
{
1003
   jit_func_t *f = context;
3✔
1004
   jit_tier_t *tier = arg;
3✔
1005

1006
   if (!load_acquire(&f->jit->shutdown))
3✔
1007
      (*tier->plugin.cgen)(f->jit, f->handle, tier->context);
2✔
1008
}
3✔
1009

1010
void jit_tier_up(jit_func_t *f)
7,902✔
1011
{
1012
   assert(f->hotness <= 0);
7,902✔
1013
   assert(f->next_tier != NULL);
7,902✔
1014

1015
   if (opt_get_int(OPT_JIT_ASYNC))
7,902✔
1016
      async_do(jit_async_cgen, f, f->next_tier);
3✔
1017
   else
1018
      (f->next_tier->plugin.cgen)(f->jit, f->handle, f->next_tier->context);
7,899✔
1019

1020
   f->hotness   = 0;
7,902✔
1021
   f->next_tier = NULL;
7,902✔
1022
}
7,902✔
1023

1024
void jit_add_tier(jit_t *j, int threshold, const jit_plugin_t *plugin)
3,553✔
1025
{
1026
   assert(threshold > 0);
3,553✔
1027

1028
   jit_tier_t *t = xcalloc(sizeof(jit_tier_t));
3,553✔
1029
   t->next      = j->tiers;
3,553✔
1030
   t->threshold = threshold;
3,553✔
1031
   t->plugin    = *plugin;
3,553✔
1032
   t->context   = (*plugin->init)(j);
3,553✔
1033

1034
   j->tiers = t;
3,553✔
1035
}
3,553✔
1036

1037
ident_t jit_get_name(jit_t *j, jit_handle_t handle)
2,541✔
1038
{
1039
   return jit_get_func(j, handle)->name;
2,541✔
1040
}
1041

1042
object_t *jit_get_object(jit_t *j, jit_handle_t handle)
241✔
1043
{
1044
   jit_func_t *f = jit_get_func(j, handle);
241✔
1045
   jit_fill_irbuf(f);
241✔
1046
   return f->object;
241✔
1047
}
1048

1049
bool jit_writes_flags(jit_ir_t *ir)
8,571,987✔
1050
{
1051
   return ir->op == J_CMP || ir->op == J_FCMP
8,571,987✔
1052
      || ir->op == J_CCMP || ir->op == J_FCCMP
8,253,292✔
1053
      || (ir->op == J_ADD && ir->cc != JIT_CC_NONE)
8,240,835✔
1054
      || (ir->op == J_SUB && ir->cc != JIT_CC_NONE)
8,235,539✔
1055
      || (ir->op == J_MUL && ir->cc != JIT_CC_NONE)
8,229,642✔
1056
      || (ir->op == MACRO_EXP && ir->cc != JIT_CC_NONE);
16,800,741✔
1057
}
1058

1059
bool jit_reads_flags(jit_ir_t *ir)
5,716,324✔
1060
{
1061
   return (ir->op == J_JUMP && ir->cc != JIT_CC_NONE)
250,661✔
1062
      || ir->op == J_CSET || ir->op == J_CSEL || ir->op == J_CCMP
1063
      || ir->op == J_FCCMP;
5,716,324✔
1064
}
1065

1066
jit_handle_t jit_assemble(jit_t *j, ident_t name, const char *text)
92✔
1067
{
1068
   jit_func_t *f = chash_get(j->index, name);
92✔
1069
   if (f != NULL)
92✔
UNCOV
1070
      return f->handle;
×
1071

1072
   SCOPED_LOCK(j->lock);
184✔
1073

1074
   f = xcalloc(sizeof(jit_func_t));
92✔
1075

1076
   f->name      = name;
92✔
1077
   f->state     = JIT_FUNC_READY;
92✔
1078
   f->jit       = j;
92✔
1079
   f->handle    = j->next_handle++;
92✔
1080
   f->next_tier = j->tiers;
92✔
1081
   f->hotness   = f->next_tier ? f->next_tier->threshold : 0;
92✔
1082
   f->entry     = jit_interp;
92✔
1083

1084
   jit_install(j, f);
92✔
1085

1086
   enum { LABEL, INS, CCSIZE, RESULT, ARG1, ARG2, NEWLINE, CP } state = LABEL;
92✔
1087

1088
   static const struct {
92✔
1089
      const char *name;
1090
      jit_op_t    op;
1091
      int         nresult;
1092
      int         nargs;
1093
   } optab[] = {
1094
      { "MOV",     J_MOV,        1, 1 },
1095
      { "ADD",     J_ADD,        1, 2 },
1096
      { "SUB",     J_SUB,        1, 2 },
1097
      { "MUL",     J_MUL,        1, 2 },
1098
      { "DIV",     J_DIV,        1, 2 },
1099
      { "REM",     J_REM,        1, 2 },
1100
      { "RECV",    J_RECV,       1, 1 },
1101
      { "SEND",    J_SEND,       0, 2 },
1102
      { "RET",     J_RET,        0, 0 },
1103
      { "CMP",     J_CMP,        0, 2 },
1104
      { "CCMP",    J_CCMP,       0, 2 },
1105
      { "JUMP",    J_JUMP,       0, 1 },
1106
      { "CSEL",    J_CSEL,       1, 2 },
1107
      { "CSET",    J_CSET,       1, 0 },
1108
      { "NOP",     J_NOP,        0, 0 },
1109
      { "CLAMP",   J_CLAMP,      1, 1 },
1110
      { "CALL",    J_CALL,       0, 1 },
1111
      { "STORE",   J_STORE,      0, 2 },
1112
      { "LOAD",    J_LOAD,       1, 1 },
1113
      { "ULOAD",   J_ULOAD,      1, 1 },
1114
      { "SHL",     J_SHL,        1, 2 },
1115
      { "ASR",     J_ASR,        1, 2 },
1116
      { "LEA",     J_LEA,        1, 1 },
1117
      { "AND",     J_AND,        1, 2 },
1118
      { "OR",      J_OR,         1, 2 },
1119
      { "XOR",     J_XOR,        1, 2 },
1120
      { "NOT",     J_NOT,        1, 1 },
1121
      { "NEG",     J_NEG,        1, 1 },
1122
      { "FADD",    J_FADD,       1, 2 },
1123
      { "FSUB",    J_FSUB,       1, 2 },
1124
      { "FMUL",    J_FMUL,       1, 2 },
1125
      { "FDIV",    J_FDIV,       1, 2 },
1126
      { "FNEG",    J_FNEG,       1, 1 },
1127
      { "FCMP",    J_FCMP,       0, 2 },
1128
      { "FCVTNS",  J_FCVTNS,     1, 1 },
1129
      { "SCVTF",   J_SCVTF,      1, 1 },
1130
      { "$EXIT",   MACRO_EXIT,   0, 1 },
1131
      { "$COPY",   MACRO_COPY,   1, 2 },
1132
      { "$MOVE",   MACRO_MOVE,   1, 2 },
1133
      { "$CASE",   MACRO_CASE,   1, 2 },
1134
      { "$SALLOC", MACRO_SALLOC, 1, 2 },
1135
      { "$LALLOC", MACRO_LALLOC, 1, 1 },
1136
      { "$BZERO",  MACRO_BZERO,  1, 1 },
1137
      { "$MEMSET", MACRO_MEMSET, 1, 2 },
1138
      { "$EXP",    MACRO_EXP,    1, 2 },
1139
      { "$FEXP",   MACRO_FEXP,   1, 2 },
1140
   };
1141

1142
   static const struct {
92✔
1143
      const char *name;
1144
      jit_cc_t    cc;
1145
   } cctab[] = {
1146
      { "T",  JIT_CC_T },
1147
      { "F",  JIT_CC_F },
1148
      { "EQ", JIT_CC_EQ },
1149
      { "O",  JIT_CC_O },
1150
      { "C",  JIT_CC_C },
1151
      { "LT", JIT_CC_LT },
1152
      { "LE", JIT_CC_LE },
1153
      { "GT", JIT_CC_GT },
1154
      { "GE", JIT_CC_GE },
1155
   };
1156

1157
   const unsigned bufsz = 128;
92✔
1158
   f->irbuf = xcalloc_array(bufsz, sizeof(jit_ir_t));
92✔
1159

1160
   SCOPED_A(int) lpatch = AINIT;
184✔
1161
   int *labels LOCAL = NULL, maxlabel = 0;
184✔
1162
   jit_ir_t *ir = NULL;
92✔
1163
   int nresult = 0, nargs = 0, cpoolptr = 0;
92✔
1164
   char *copy LOCAL = xstrdup(text);
92✔
1165
   for (char *tok = strtok(copy, " \r\t"); tok; tok = strtok(NULL, " \r\t")) {
2,141✔
1166
   again:
2,680✔
1167
      switch (state) {
2,680✔
1168
      case LABEL:
537✔
1169
         assert(f->nirs < bufsz);
537✔
1170
         ir = &(f->irbuf[f->nirs++]);
537✔
1171

1172
         if (tok[0] == 'L' && isdigit((int)tok[1])) {
537✔
1173
            char *eptr = NULL;
25✔
1174
            const int lab = strtol(tok + 1, &eptr, 10);
25✔
1175
            if (*eptr != ':')
25✔
1176
               fatal_trace("cannot parse label '%s'", tok);
1177

1178
            if (lab > maxlabel) {
25✔
1179
               maxlabel = next_power_of_2(lab);
24✔
1180
               labels = xrealloc_array(labels, maxlabel + 1, sizeof(int));
24✔
1181
            }
1182

1183
            ir->target = 1;
25✔
1184
            labels[lab] = ir - f->irbuf;
25✔
1185
            state = INS;
25✔
1186
         }
1187
         else if (isdigit((int)tok[1])) {
512✔
1188
            state = CP;
1✔
1189
            goto again;
1✔
1190
         }
1191
         else {
1192
            state = INS;
511✔
1193
            goto again;
511✔
1194
         }
1195
         break;
25✔
1196

1197
      case INS:
536✔
1198
         {
1199
            char *dot = strchr(tok, '.');
536✔
1200
            if (dot != NULL)
536✔
1201
               *dot++ = '\0';
76✔
1202

1203
            int ipos = 0;
536✔
1204
            for (; ipos < ARRAY_LEN(optab)
536✔
1205
                    && strcmp(optab[ipos].name, tok); ipos++)
6,165✔
1206
               ;
1207

1208
            if (ipos == ARRAY_LEN(optab))
536✔
1209
               fatal_trace("illegal instruction %s", tok);
1210

1211
            nargs = optab[ipos].nargs;
536✔
1212
            nresult = optab[ipos].nresult;
536✔
1213

1214
            ir->op = optab[ipos].op;
536✔
1215
            ir->size = JIT_SZ_UNSPEC;
536✔
1216
            ir->result = JIT_REG_INVALID;
536✔
1217

1218
            if (dot != NULL) {
536✔
1219
               tok = dot;
76✔
1220
               state = CCSIZE;
76✔
1221
               goto again;
76✔
1222
            }
1223

1224
            state = nresult > 0 ? RESULT : (nargs > 0 ? ARG1 : NEWLINE);
460✔
1225
         }
1226
         break;
1227

1228
      case CCSIZE:
90✔
1229
         {
1230
            char *dot = strchr(tok, '.');
90✔
1231
            if (dot != NULL)
90✔
1232
               *dot++ = '\0';
14✔
1233

1234
            if (isdigit((int)tok[0])) {
90✔
1235
               switch (atoi(tok)) {
50✔
1236
               case 8: ir->size = JIT_SZ_8; break;
13✔
1237
               case 16: ir->size = JIT_SZ_16; break;
16✔
1238
               case 32: ir->size = JIT_SZ_32; break;
18✔
1239
               case 64: ir->size = JIT_SZ_64; break;
3✔
UNCOV
1240
               default:
×
1241
                  fatal_trace("illegal operation size %s", tok);
1242
               }
1243
            }
1244
            else {
1245
               int cpos = 0;
1246
               for (; cpos < ARRAY_LEN(cctab)
148✔
1247
                       && strcmp(cctab[cpos].name, tok); cpos++)
148✔
1248
                  ;
1249

1250
               if (cpos == ARRAY_LEN(cctab))
40✔
1251
                  fatal_trace("illegal condition code %s", tok);
1252

1253
               ir->cc = cctab[cpos].cc;
40✔
1254
            }
1255

1256
            if (dot != NULL) {
90✔
1257
               tok = dot;
14✔
1258
               state = CCSIZE;
14✔
1259
               goto again;
14✔
1260
            }
1261

1262
            state = nresult > 0 ? RESULT : (nargs > 0 ? ARG1 : NEWLINE);
76✔
1263
         }
1264
         break;
1265

1266
      case RESULT:
326✔
1267
         if (tok[0] != 'R')
326✔
1268
            fatal_trace("expected register name but got '%s'", tok);
1269

1270
         ir->result = atoi(tok + 1);
326✔
1271
         f->nregs = MAX(ir->result + 1, f->nregs);
326✔
1272
         state = nargs > 0 ? ARG1 : NEWLINE;
326✔
1273
         break;
1274

1275
      case ARG1:
646✔
1276
      case ARG2:
1277
         {
1278
            jit_value_t arg;
646✔
1279
            size_t toklen = strlen(tok);
646✔
1280
            if (tok[0] == 'R') {
646✔
1281
               arg.kind = JIT_VALUE_REG;
237✔
1282
               arg.reg  = atoi(tok + 1);
237✔
1283
               f->nregs = MAX(arg.reg + 1, f->nregs);
237✔
1284
            }
1285
            else if (tok[0] == '#') {
409✔
1286
               arg.kind  = JIT_VALUE_INT64;
333✔
1287
               arg.int64 = strtoll(tok + 1, NULL, 0);
333✔
1288
            }
1289
            else if (tok[0] == '%') {
76✔
1290
               arg.kind  = JIT_VALUE_DOUBLE;
1✔
1291
               arg.dval = strtod(tok + 1, NULL);
1✔
1292
            }
1293
            else if (tok[0] == 'L') {
75✔
1294
               APUSH(lpatch, ir - f->irbuf);
27✔
1295
               arg.kind = JIT_VALUE_LABEL;
27✔
1296
               arg.label = atoi(tok + 1);
27✔
1297
            }
1298
            else if (tok[0] == '[' && tok[1] == 'R') {
92✔
1299
               char *eptr = NULL;
44✔
1300
               arg.kind = JIT_ADDR_REG;
44✔
1301
               arg.reg = strtol(tok + 2, &eptr, 0);
44✔
1302
               if (*eptr == '+' || *eptr == '-')
44✔
1303
                  arg.disp = strtol(eptr, &eptr, 0);
6✔
1304
               else
1305
                  arg.disp = 0;
1306
               if (*eptr != ']')
44✔
1307
                  fatal_trace("invalid address %s", tok);
1308
               f->nregs = MAX(arg.reg + 1, f->nregs);
44✔
1309
            }
1310
            else if (tok[0] == '[' && tok[1] == 'C' && tok[2] == 'P') {
4✔
1311
               char *eptr = NULL;
2✔
1312
               arg.int64 = strtol(tok + 4, &eptr, 0);
2✔
1313
               arg.kind = JIT_ADDR_CPOOL;
2✔
1314
               if (tok[3] != '+' || *eptr != ']')
2✔
1315
                  fatal_trace("invalid address %s", tok);
1316
            }
1317
            else if (tok[0] == '<' && tok[toklen - 1] == '>') {
2✔
1318
               tok[toklen - 1] = '\0';
2✔
1319
               arg.kind = JIT_VALUE_HANDLE;
2✔
1320
               arg.handle = jit_lazy_compile(j, ident_new(tok + 1));
2✔
1321
            }
UNCOV
1322
            else if (tok[0] == '\n')
×
1323
               fatal_trace("got newline, expecting argument");
1324
            else
1325
               fatal_trace("cannot parse argument '%s'", tok);
1326

1327
            if (state == ARG1)
646✔
1328
               ir->arg1 = arg;
423✔
1329
            else
1330
               ir->arg2 = arg;
223✔
1331

1332
            state = state == ARG1 && nargs > 1 ? ARG2 : NEWLINE;
646✔
1333
         }
1334
         break;
1335

1336
      case NEWLINE:
536✔
1337
         if (*tok != '\n')
536✔
1338
            fatal_trace("expected newline, got '%s'", tok);
1339
         if (ir->op == MACRO_SALLOC)
536✔
1340
            f->framesz += ALIGN_UP(ir->arg2.int64, 8);
7✔
1341
         state = LABEL;
536✔
1342
         if (*++tok != '\0')
536✔
1343
            goto again;
29✔
1344
         break;
1345

1346
      case CP:
9✔
1347
         {
1348
            if (*tok == '\n' && *++tok == '\0')
9✔
1349
               continue;
1✔
1350

1351
            char *eptr = NULL;
8✔
1352
            unsigned long byte = strtoul(tok, &eptr, 16);
8✔
1353
            if (*eptr != '\0' || byte >= 256)
8✔
1354
               fatal_trace("invalid constant pool value '%s'", tok);
1355

1356
            if (f->cpool == NULL)
8✔
1357
               f->cpool = xmalloc((f->cpoolsz = 64));
1✔
1358
            else if (cpoolptr == f->cpoolsz)
7✔
1359
               fatal_trace("constant pool overflow");
1360

1361
            f->cpool[cpoolptr++] = byte;
8✔
1362
         }
1363
         break;
8✔
1364
      }
1365
   }
1366

1367
   f->cpoolsz = cpoolptr;
92✔
1368

1369
   for (int i = 0; i < lpatch.count; i++) {
119✔
1370
      jit_ir_t *ir = &(f->irbuf[lpatch.items[i]]);
27✔
1371
      if (ir->arg1.kind == JIT_VALUE_LABEL)
27✔
1372
         ir->arg1.label = labels[ir->arg1.label];
19✔
1373
      else
1374
         ir->arg2.label = labels[ir->arg2.label];
8✔
1375
   }
1376

1377
   return f->handle;
92✔
1378
}
1379

1380
bool jit_will_abort(jit_ir_t *ir)
2,283,403✔
1381
{
1382
   if (ir->op == MACRO_EXIT) {
2,283,403✔
1383
      return ir->arg1.exit == JIT_EXIT_INDEX_FAIL
87,438✔
1384
         || ir->arg1.exit == JIT_EXIT_OVERFLOW
1385
         || ir->arg1.exit == JIT_EXIT_NULL_DEREF
1386
         || ir->arg1.exit == JIT_EXIT_UNREACHABLE
87,438✔
1387
         || ir->arg1.exit == JIT_EXIT_LENGTH_FAIL
1388
         || ir->arg1.exit == JIT_EXIT_DIV_ZERO
1389
         || ir->arg1.exit == JIT_EXIT_EXPONENT_FAIL
1390
         || ir->arg1.exit == JIT_EXIT_RANGE_FAIL;
160,179✔
1391
   }
1392
   else
1393
      return ir->op == J_TRAP;
2,195,965✔
1394
}
1395

1396
int32_t *jit_get_cover_mem(jit_t *j, int mintags)
3,609✔
1397
{
1398
   if (mintags > j->cover_ntags) {
3,609✔
1399
      j->cover_mem = xrealloc_array(j->cover_mem, mintags, sizeof(int32_t));
148✔
1400
      memset(j->cover_mem + j->cover_ntags, '\0',
148✔
1401
             (mintags - j->cover_ntags) * sizeof(int32_t));
148✔
1402
      j->cover_ntags = mintags;
148✔
1403
   }
1404

1405
   return j->cover_mem;
3,609✔
1406
}
1407

1408
int32_t *jit_get_cover_ptr(jit_t *j, jit_value_t addr)
1,077✔
1409
{
1410
   assert(addr.kind == JIT_ADDR_COVER);
1,077✔
1411
   int32_t *base = jit_get_cover_mem(j, addr.int64 + 1);
1,077✔
1412
   assert(base != NULL);
1,077✔
1413
   return base + addr.int64;
1,077✔
1414
}
1415

UNCOV
1416
void jit_interrupt(jit_t *j, jit_irq_fn_t fn, void *ctx)
×
1417
{
UNCOV
1418
   relaxed_store(&j->interrupt_ctx, ctx);
×
UNCOV
1419
   if (!atomic_cas(&j->interrupt, NULL, fn))
×
UNCOV
1420
      fatal_exit(1);
×
UNCOV
1421
}
×
1422

1423
__attribute__((cold, noinline))
UNCOV
1424
static void jit_handle_interrupt(jit_t *j)
×
1425
{
UNCOV
1426
   jit_irq_fn_t fn = load_acquire(&j->interrupt);
×
1427
   if (!atomic_cas(&j->interrupt, fn, NULL))
×
1428
      return;
1429

1430
   (*fn)(j, relaxed_load(&j->interrupt_ctx));
×
1431
}
1432

1433
void jit_check_interrupt(jit_t *j)
48,136,342✔
1434
{
1435
   if (unlikely(relaxed_load(&j->interrupt) != NULL))
48,136,342✔
UNCOV
1436
      jit_handle_interrupt(j);
×
1437
}
48,136,342✔
1438

1439
void jit_reset(jit_t *j)
21✔
1440
{
1441
   SCOPED_LOCK(j->lock);
42✔
1442

1443
   for (int i = 0; i < j->next_handle; i++) {
68✔
1444
      jit_func_t *f = j->funcs->items[i];
47✔
1445
      if (f->privdata != MPTR_INVALID)
47✔
1446
         *mptr_get(f->privdata) = NULL;
38✔
1447
   }
1448

1449
   jit_reset_exit_status(j);
21✔
1450
}
21✔
1451

1452
jit_t *jit_for_thread(void)
240✔
1453
{
1454
   jit_thread_local_t *thread = jit_thread_local();
240✔
1455

1456
   if (unlikely(thread->jit == NULL))
240✔
1457
      fatal_trace("thread not attached to JIT");
1458

1459
   return thread->jit;
240✔
1460
}
1461

1462
jit_thread_local_t *jit_attach_thread(jit_anchor_t *anchor)
48,135,957✔
1463
{
1464
   jit_thread_local_t *thread = *jit_thread_local_ptr();
48,135,957✔
1465
   assert(thread != NULL);
48,135,957✔
1466

1467
   thread->anchor = anchor;
48,135,957✔
1468

1469
   jit_check_interrupt(thread->jit);
48,135,957✔
1470

1471
   return thread;
48,135,957✔
1472
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc