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

nickg / nvc / 13887457702

16 Mar 2025 09:12PM UTC coverage: 92.285% (-0.04%) from 92.324%
13887457702

push

github

nickg
Tag Docker images on releases. Fixes #1165

68273 of 73981 relevant lines covered (92.28%)

423265.54 hits per line

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

94.02
/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)
140,817,008✔
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;
140,817,008✔
130
#endif
131

132
   return &local;
140,817,008✔
133
}
134

135
jit_thread_local_t *jit_thread_local(void)
92,680,887✔
136
{
137
   jit_thread_local_t **ptr = jit_thread_local_ptr();
92,680,887✔
138

139
   if (unlikely(*ptr == NULL)) {
92,680,887✔
140
      *ptr = xcalloc(sizeof(jit_thread_local_t));
4,121✔
141
      (*ptr)->state = JIT_IDLE;
4,121✔
142
   }
143

144
   return *ptr;
92,680,887✔
145
}
146

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

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

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

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

165
   return j;
8,855✔
166
}
167

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

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

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

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

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

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

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

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

212
mspace_t *jit_get_mspace(jit_t *j)
491,763✔
213
{
214
   return j->mspace;
491,763✔
215
}
216

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

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

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

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

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

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

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

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

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

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

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

275
   jit_entry_fn_t entry =
129,770✔
276
      jit_bind_intrinsic(name) ?: (descr ? descr->entry : jit_interp);
64,885✔
277

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

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

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

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

330
         r->kind = RELOC_PROCESSED;
49,959✔
331
      }
332

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

336
   return f->handle;
64,885✔
337
}
338

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

345
   SCOPED_LOCK(j->lock);
97,432✔
346
   return jit_lazy_compile_locked(j, name);
48,716✔
347
}
348

349
jit_func_t *jit_get_func(jit_t *j, jit_handle_t handle)
21,387,936✔
350
{
351
   assert(handle != JIT_HANDLE_INVALID);
21,387,936✔
352

353
   // Synchronises with store_release in jit_install
354
   func_array_t *list = load_acquire(&(j->funcs));
21,387,936✔
355
   assert(handle < list->length);
21,387,936✔
356

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

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

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

378
   __builtin_unreachable();
×
379
}
380

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

408
   assert(f->irbuf == NULL);
34,665✔
409

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

415
   if (jit_fill_from_aot(f, f->jit->aotlib))
34,665✔
416
      goto done;
1,034✔
417

418
   if (jit_fill_from_aot(f, f->jit->preloadlib))
33,631✔
419
      goto done;
1,303✔
420

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

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

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

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

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

448
   jit_irgen(f, mu);
31,484✔
449

450
 done:
34,661✔
451
#ifndef USE_EMUTLS
452
   jit_transition(f->jit, JIT_COMPILING, oldstate);
34,661✔
453
#endif
454
}
455

456
jit_handle_t jit_compile(jit_t *j, ident_t name)
999✔
457
{
458
   jit_handle_t handle = jit_lazy_compile(j, name);
999✔
459
   if (handle == JIT_HANDLE_INVALID)
999✔
460
      return handle;
461

462
   jit_func_t *f = jit_get_func(j, handle);
999✔
463
   jit_fill_irbuf(f);
999✔
464

465
   return handle;
999✔
466
}
467

468
void *jit_link(jit_t *j, jit_handle_t handle)
148✔
469
{
470
   if (handle == JIT_HANDLE_INVALID)
148✔
471
      return NULL;
472

473
   jit_func_t *f = jit_get_func(j, handle);
148✔
474
   if (f->privdata != MPTR_INVALID)
148✔
475
      return *mptr_get(f->privdata);
134✔
476

477
   f->privdata = mptr_new(j->mspace, "privdata");
14✔
478

479
   jit_fill_irbuf(f);
14✔
480

481
   tlab_t tlab = jit_null_tlab(j);
14✔
482
   jit_scalar_t p1 = { .pointer = NULL }, p2 = p1, result;
14✔
483
   if (!jit_fastcall(j, f->handle, &result, p1, p2, &tlab)) {
14✔
484
      error_at(&(f->object->loc), "failed to initialise %s", istr(f->name));
×
485
      result.pointer = NULL;
×
486
   }
487
   else if (result.pointer == NULL)
14✔
488
      fatal_trace("link %s returned NULL", istr(f->name));
489
   else if (f->privdata == MPTR_INVALID)
14✔
490
      fatal_trace("cannot link unit %s", istr(f->name));
491

492
   // Initialisation should save the context pointer
493
   assert(result.pointer == *mptr_get(f->privdata));
14✔
494

495
   return result.pointer;
14✔
496
}
497

498
void **jit_get_privdata_ptr(jit_t *j, jit_func_t *f)
4,357,845✔
499
{
500
   if (f->privdata == MPTR_INVALID)
4,357,845✔
501
      f->privdata = mptr_new(j->mspace, "privdata");
25,724✔
502

503
   return mptr_get(f->privdata);
4,357,845✔
504
}
505

506
void *jit_get_frame_var(jit_t *j, jit_handle_t handle, ident_t name)
364✔
507
{
508
   jit_func_t *f = jit_get_func(j, handle);
364✔
509
   if (f->privdata == MPTR_INVALID)
364✔
510
      fatal_trace("%s not linked", istr(f->name));
511

512
   jit_fill_irbuf(f);
364✔
513

514
   for (int i = 0; i < f->nvars; i++) {
958✔
515
      if (f->linktab[i].name == name)
958✔
516
         return *mptr_get(f->privdata) + f->linktab[i].offset;
364✔
517
   }
518

519
   fatal_trace("%s has no variable %s", istr(f->name), istr(name));
520
}
521

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

579
jit_stack_trace_t *jit_stack_trace(void)
6,605✔
580
{
581
   jit_thread_local_t *thread = jit_thread_local();
6,605✔
582

583
   int count = 0;
6,605✔
584
   for (jit_anchor_t *a = thread->anchor; a; a = a->caller)
15,854✔
585
      count++;
9,249✔
586

587
   jit_stack_trace_t *stack =
6,605✔
588
      xmalloc_flex(sizeof(jit_stack_trace_t), count, sizeof(jit_frame_t));
6,605✔
589
   stack->count = count;
6,605✔
590

591
   jit_frame_t *frame = stack->frames;
6,605✔
592
   for (jit_anchor_t *a = thread->anchor; a; a = a->caller, frame++) {
15,854✔
593
      frame->loc    = LOC_INVALID;
9,249✔
594
      frame->symbol = a->func->name;
9,249✔
595
      frame->object = NULL;
9,249✔
596

597
#ifdef USE_EMUTLS
598
      if (load_acquire(&a->func->state) == JIT_FUNC_COMPILING)
599
         continue;   // Cannot use jit_transition in jit_fill_irbuf
600
#endif
601

602
      jit_fill_irbuf(a->func);
9,249✔
603

604
      frame->object = a->func->object;
9,249✔
605

606
      // Scan backwards to find the last debug info
607
      assert(a->irpos < a->func->nirs);
9,249✔
608
      frame->loc = frame->object ? frame->object->loc : LOC_INVALID;
9,249✔
609
      for (jit_ir_t *ir = &(a->func->irbuf[a->irpos]);
9,249✔
610
           ir >= a->func->irbuf; ir--) {
52,180✔
611
         if (ir->op == J_DEBUG) {
51,903✔
612
            frame->loc = ir->arg1.loc;
8,955✔
613
            break;
8,955✔
614
         }
615
         else if (ir->target)
42,948✔
616
            break;
617
      }
618
   }
619

620
   return stack;
6,605✔
621
}
622

623
static void jit_diag_cb(diag_t *d, void *arg)
6,314✔
624
{
625
   jit_t *j = arg;
6,314✔
626

627
   if (j->silent) {
6,314✔
628
      diag_suppress(d, true);
1,052✔
629
      return;
1,052✔
630
   }
631
   else if (unlikely(jit_thread_local()->state != JIT_RUNNING))
5,262✔
632
      fatal_trace("JIT diag callback called when not running");
633

634
   jit_stack_trace_t *stack LOCAL = jit_stack_trace();
10,524✔
635

636
   for (int i = 0; i < stack->count; i++) {
12,637✔
637
      jit_frame_t *frame = &(stack->frames[i]);
7,375✔
638

639
      if (frame->object != NULL)
7,375✔
640
         jit_emit_trace(d, &(frame->loc), frame->object, istr(frame->symbol));
7,370✔
641
      else
642
         diag_trace(d, &(frame->loc), "%s", istr(frame->symbol));
5✔
643
   }
644
}
645

646
static void jit_transition(jit_t *j, jit_state_t from, jit_state_t to)
35,139,266✔
647
{
648
   jit_thread_local_t *thread = jit_thread_local();
35,139,266✔
649

650
#ifdef DEBUG
651
   if (thread->state != from)
35,139,266✔
652
      fatal_trace("expected thread state %d but have %d", from, thread->state);
653
#endif
654

655
   thread->state = to;
35,139,266✔
656

657
   switch (to) {
35,139,266✔
658
   case JIT_RUNNING:
17,613,647✔
659
      if (from != JIT_RUNNING) {
17,613,647✔
660
         diag_add_hint_fn(jit_diag_cb, j);
17,501,709✔
661
         thread->jit = j;
17,501,709✔
662
      }
663
      else
664
         assert(thread->jit == j);
111,938✔
665
      break;
666
   case JIT_IDLE:
17,490,733✔
667
      if (from == JIT_RUNNING) {
17,490,733✔
668
         diag_remove_hint_fn(jit_diag_cb);
17,478,999✔
669
         thread->jit = NULL;
17,478,999✔
670
      }
671
      break;
672
   case JIT_COMPILING:
34,886✔
673
      if (from == JIT_RUNNING) {
34,886✔
674
         diag_remove_hint_fn(jit_diag_cb);
22,710✔
675
         thread->jit = NULL;
22,710✔
676
      }
677
      break;
678
   }
679
}
35,139,266✔
680

681
static bool jit_try_vcall(jit_t *j, jit_func_t *f, jit_scalar_t *args,
17,534,972✔
682
                          tlab_t *tlab)
683
{
684
   jit_thread_local_t *volatile thread = jit_thread_local();
17,534,972✔
685
   volatile const jit_state_t oldstate = thread->state;
17,534,972✔
686

687
   const int rc = jit_setjmp(thread->abort_env);
17,534,972✔
688
   if (rc == 0) {
17,536,430✔
689
      thread->jmp_buf_valid = 1;
17,534,972✔
690
      jit_transition(j, oldstate, JIT_RUNNING);
17,534,972✔
691

692
      jit_entry_fn_t entry = load_acquire(&f->entry);
17,534,972✔
693
      (*entry)(f, NULL, args, tlab);
17,534,972✔
694

695
      jit_transition(j, JIT_RUNNING, oldstate);
17,533,510✔
696
      thread->jmp_buf_valid = 0;
17,533,510✔
697
      thread->anchor = NULL;
17,533,510✔
698
      return true;
17,533,510✔
699
   }
700
   else {
701
      jit_transition(j, JIT_RUNNING, oldstate);
1,458✔
702
      thread->jmp_buf_valid = 0;
1,458✔
703
      thread->anchor = NULL;
1,458✔
704
      return false;
1,458✔
705
   }
706
}
707

708
static void jit_unpack_args(jit_func_t *f, jit_scalar_t *args, va_list ap)
59,006✔
709
{
710
   jit_fill_irbuf(f);  // Ensure FFI spec is set
59,006✔
711

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

743
bool jit_try_call(jit_t *j, jit_handle_t handle, jit_scalar_t *result, ...)
58,649✔
744
{
745
   va_list ap;
58,649✔
746
   va_start(ap, result);
58,649✔
747

748
   jit_func_t *f = jit_get_func(j, handle);
58,649✔
749

750
   jit_scalar_t args[JIT_MAX_ARGS];
58,649✔
751
   jit_unpack_args(f, args, ap);
58,649✔
752

753
   va_end(ap);
58,649✔
754

755
   tlab_t tlab = jit_null_tlab(j);
58,649✔
756
   if (!jit_try_vcall(j, f, args, &tlab))
58,649✔
757
      return false;
758

759
   *result = args[0];
58,041✔
760
   return true;
58,041✔
761
}
762

763
jit_scalar_t jit_call(jit_t *j, jit_handle_t handle, ...)
357✔
764
{
765
   va_list ap;
357✔
766
   va_start(ap, handle);
357✔
767

768
   jit_func_t *f = jit_get_func(j, handle);
357✔
769

770
   jit_scalar_t args[JIT_MAX_ARGS];
357✔
771
   jit_unpack_args(f, args, ap);
357✔
772

773
   va_end(ap);
357✔
774

775
   tlab_t tlab = jit_null_tlab(j);
357✔
776

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

780
   return args[0];
357✔
781
}
782

783
bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result,
17,448,716✔
784
                  jit_scalar_t p1, jit_scalar_t p2, tlab_t *tlab)
785
{
786
   jit_func_t *f = jit_get_func(j, handle);
17,448,716✔
787

788
   jit_scalar_t args[JIT_MAX_ARGS];
17,448,716✔
789
   args[0] = p1;
17,448,716✔
790
   args[1] = p2;
17,448,716✔
791

792
   if (!jit_try_vcall(j, f, args, tlab))
17,448,716✔
793
      return false;
794

795
   *result = args[0];
17,448,281✔
796
   return true;
17,448,281✔
797
}
798

799
bool jit_vfastcall(jit_t *j, jit_handle_t handle, const jit_scalar_t *inargs,
15,964✔
800
                   unsigned nargs, jit_scalar_t *results, unsigned nresults,
801
                   tlab_t *tlab)
802
{
803
   jit_func_t *f = jit_get_func(j, handle);
15,964✔
804

805
   jit_scalar_t args[JIT_MAX_ARGS];
15,964✔
806
   memcpy(args, inargs, nargs * sizeof(jit_scalar_t));
15,964✔
807

808
   if (!jit_try_vcall(j, f, args, tlab))
15,964✔
809
      return false;
810

811
   memcpy(results, args, nresults * sizeof(jit_scalar_t));
15,964✔
812
   return true;
15,964✔
813
}
814

815
void *jit_call_thunk(jit_t *j, vcode_unit_t unit, void *context,
11,286✔
816
                     thunk_result_fn_t fn, void *arg)
817
{
818
   assert(vcode_unit_kind(unit) == VCODE_UNIT_THUNK);
11,286✔
819

820
   jit_func_t *f = xcalloc(sizeof(jit_func_t));
11,286✔
821
   f->state  = JIT_FUNC_COMPILING;
11,286✔
822
   f->jit    = j;
11,286✔
823
   f->handle = JIT_HANDLE_INVALID;
11,286✔
824
   f->entry  = jit_interp;
11,286✔
825
   f->object = vcode_unit_object(unit);
11,286✔
826

827
   mir_unit_t *mu = mir_import(f->jit->mir, unit);
11,286✔
828
   jit_irgen(f, mu);
11,286✔
829
   mir_unit_free(mu);
11,286✔
830

831
   jit_scalar_t args[JIT_MAX_ARGS];
11,286✔
832
   args[0].pointer = context;
11,286✔
833

834
   tlab_t tlab = jit_null_tlab(j);
11,286✔
835

836
   void *user = NULL;
11,286✔
837
   if (jit_try_vcall(j, f, args, &tlab))
11,286✔
838
      user = (*fn)(args, arg);
10,867✔
839

840
   jit_free_func(f);
11,282✔
841
   return user;
11,282✔
842
}
843

844
tlab_t jit_null_tlab(jit_t *j)
105,083✔
845
{
846
   tlab_t t = { .mspace = j->mspace };
105,083✔
847
   return t;
105,083✔
848
}
849

850
void jit_set_silent(jit_t *j, bool silent)
25,798✔
851
{
852
   j->silent = silent;
25,798✔
853
}
25,798✔
854

855
static aot_dll_t *load_dll_internal(jit_t *j, const char *path)
6,025✔
856
{
857
   uint32_t abi_version = 0;
6,025✔
858

859
   aot_dll_t *lib = xcalloc(sizeof(aot_dll_t));
6,025✔
860
   lib->pack = jit_pack_new();
6,025✔
861
   lib->dll  = ffi_load_dll(path);
6,025✔
862

863
   uint32_t *p = ffi_find_symbol(lib->dll, "__nvc_abi_version");
6,025✔
864
   if (p == NULL)
6,025✔
865
      warnf("%s: cannot find symbol __nvc_abi_version", path);
×
866
   else
867
      abi_version = *p;
6,025✔
868

869
   if (abi_version != RT_ABI_VERSION)
6,025✔
870
      fatal("%s: ABI version %d does not match current version %d",
×
871
            path, abi_version, RT_ABI_VERSION);
872

873
   if (opt_get_int(OPT_JIT_LOG))
6,025✔
874
      debugf("loaded AOT library from %s", path);
×
875

876
   return lib;
6,025✔
877
}
878

879
void jit_preload(jit_t *j)
4,818✔
880
{
881
#ifdef HAVE_LLVM
882
   if (j->preloadlib != NULL)
4,818✔
883
      fatal_trace("Preload library already loaded");
884

885
   lib_t std = lib_find(well_known(W_STD));
4,818✔
886
   if (std == NULL)
4,818✔
887
      fatal("cannot find STD library");
×
888

889
   LOCAL_TEXT_BUF tb = tb_new();
4,818✔
890
   tb_cat(tb, lib_path(std));
4,818✔
891
   tb_cat(tb, DIR_SEP "..");
4,818✔
892

893
   const char *preload_vers[] = { "93", "93", "93", "93", "08", "19" };
4,818✔
894
   tb_printf(tb, DIR_SEP "preload%s." DLL_EXT, preload_vers[standard()]);
4,818✔
895

896
   const char *path = tb_get(tb);
4,818✔
897
   file_info_t info;
4,818✔
898
   if (!get_file_info(path, &info) || info.type != FILE_REGULAR)
4,818✔
899
      fatal("missing preload library at %s", path);
×
900

901
   j->preloadlib = load_dll_internal(j, path);
4,818✔
902
#endif  // HAVE_LLVM
903
}
4,818✔
904

905
void jit_load_dll(jit_t *j, ident_t name)
3,331✔
906
{
907
   lib_t lib = lib_require(ident_until(name, '.'));
3,331✔
908

909
   LOCAL_TEXT_BUF tb = tb_new();
3,331✔
910
   tb_printf(tb, "_%s", istr(name));
3,331✔
911
   if (opt_get_int(OPT_NO_SAVE))
3,331✔
912
      tb_printf(tb, ".%d", getpid());
2,851✔
913
   tb_cat(tb, "." DLL_EXT);
3,331✔
914

915
   char so_path[PATH_MAX];
3,331✔
916
   lib_realpath(lib, tb_get(tb), so_path, sizeof(so_path));
3,331✔
917

918
   if (access(so_path, F_OK) != 0)
3,331✔
919
      return;
2,124✔
920

921
   if (j->aotlib != NULL)
1,207✔
922
      fatal_trace("AOT library already loaded");
923

924
   j->aotlib = load_dll_internal(j, so_path);
1,207✔
925
}
926

927
void jit_load_pack(jit_t *j, FILE *f)
235✔
928
{
929
   assert(j->pack == NULL);
235✔
930
   j->pack = jit_read_pack(f);
235✔
931
}
235✔
932

933
void jit_msg(const loc_t *where, diag_level_t level, const char *fmt, ...)
706✔
934
{
935
   diag_t *d = diag_new(level, where);
706✔
936

937
   va_list ap;
706✔
938
   va_start(ap, fmt);
706✔
939
   diag_vprintf(d, fmt, ap);
706✔
940
   va_end(ap);
706✔
941

942
   diag_emit(d);
706✔
943

944
   if (level == DIAG_FATAL)
706✔
945
      jit_abort_with_status(EXIT_FAILURE);
706✔
946
}
×
947

948
void jit_abort(void)
1,459✔
949
{
950
   jit_thread_local_t *thread = jit_thread_local();
1,459✔
951

952
   switch (thread->state) {
1,459✔
953
   case JIT_IDLE:
1✔
954
   case JIT_COMPILING:
955
      fatal_exit(1);
1✔
956
      break;
1,458✔
957
   case JIT_RUNNING:
1,458✔
958
      if (thread->jmp_buf_valid)
1,458✔
959
         jit_longjmp(thread->abort_env, 1);
1,458✔
960
      else {
961
         const int code = atomic_load(&thread->jit->exit_status);
×
962
         fatal_exit(code);
×
963
      }
964
      break;
×
965
   }
966

967
   __builtin_unreachable();
×
968
}
969

970
void jit_abort_with_status(int code)
1,345✔
971
{
972
   assert(code != INT_MIN);
1,345✔
973

974
   jit_thread_local_t *thread = jit_thread_local();
1,345✔
975
   if (thread->jit != NULL)
1,345✔
976
      atomic_store(&(thread->jit->exit_status), code);
1,344✔
977

978
   jit_abort();
1,345✔
979
}
980

981
void jit_reset_exit_status(jit_t *j)
12,926✔
982
{
983
   atomic_store(&(j->exit_status), INT_MIN);
12,926✔
984
}
12,926✔
985

986
bool jit_exit_status(jit_t *j, int *status)
3,974✔
987
{
988
   if (j->exit_status != INT_MIN) {
3,974✔
989
      *status = j->exit_status;
320✔
990
      return true;
320✔
991
   }
992
   else
993
      return false;
994
}
995

996
static void jit_async_cgen(void *context, void *arg)
3✔
997
{
998
   jit_func_t *f = context;
3✔
999
   jit_tier_t *tier = arg;
3✔
1000

1001
   if (!load_acquire(&f->jit->shutdown))
3✔
1002
      (*tier->plugin.cgen)(f->jit, f->handle, tier->context);
3✔
1003
}
3✔
1004

1005
void jit_tier_up(jit_func_t *f)
7,904✔
1006
{
1007
   assert(f->hotness <= 0);
7,904✔
1008
   assert(f->next_tier != NULL);
7,904✔
1009

1010
   if (opt_get_int(OPT_JIT_ASYNC))
7,904✔
1011
      async_do(jit_async_cgen, f, f->next_tier);
3✔
1012
   else
1013
      (f->next_tier->plugin.cgen)(f->jit, f->handle, f->next_tier->context);
7,901✔
1014

1015
   f->hotness   = 0;
7,904✔
1016
   f->next_tier = NULL;
7,904✔
1017
}
7,904✔
1018

1019
void jit_add_tier(jit_t *j, int threshold, const jit_plugin_t *plugin)
3,558✔
1020
{
1021
   assert(threshold > 0);
3,558✔
1022

1023
   jit_tier_t *t = xcalloc(sizeof(jit_tier_t));
3,558✔
1024
   t->next      = j->tiers;
3,558✔
1025
   t->threshold = threshold;
3,558✔
1026
   t->plugin    = *plugin;
3,558✔
1027
   t->context   = (*plugin->init)(j);
3,558✔
1028

1029
   j->tiers = t;
3,558✔
1030
}
3,558✔
1031

1032
ident_t jit_get_name(jit_t *j, jit_handle_t handle)
2,545✔
1033
{
1034
   return jit_get_func(j, handle)->name;
2,545✔
1035
}
1036

1037
object_t *jit_get_object(jit_t *j, jit_handle_t handle)
241✔
1038
{
1039
   jit_func_t *f = jit_get_func(j, handle);
241✔
1040
   jit_fill_irbuf(f);
241✔
1041
   return f->object;
241✔
1042
}
1043

1044
bool jit_writes_flags(jit_ir_t *ir)
8,585,508✔
1045
{
1046
   return ir->op == J_CMP || ir->op == J_FCMP
8,585,508✔
1047
      || ir->op == J_CCMP || ir->op == J_FCCMP
8,266,371✔
1048
      || (ir->op == J_ADD && ir->cc != JIT_CC_NONE)
8,253,906✔
1049
      || (ir->op == J_SUB && ir->cc != JIT_CC_NONE)
8,248,623✔
1050
      || (ir->op == J_MUL && ir->cc != JIT_CC_NONE)
8,242,710✔
1051
      || (ir->op == MACRO_EXP && ir->cc != JIT_CC_NONE);
16,827,322✔
1052
}
1053

1054
bool jit_reads_flags(jit_ir_t *ir)
5,724,984✔
1055
{
1056
   return (ir->op == J_JUMP && ir->cc != JIT_CC_NONE)
250,771✔
1057
      || ir->op == J_CSET || ir->op == J_CSEL || ir->op == J_CCMP
1058
      || ir->op == J_FCCMP;
5,724,984✔
1059
}
1060

1061
jit_handle_t jit_assemble(jit_t *j, ident_t name, const char *text)
92✔
1062
{
1063
   jit_func_t *f = chash_get(j->index, name);
92✔
1064
   if (f != NULL)
92✔
1065
      return f->handle;
×
1066

1067
   SCOPED_LOCK(j->lock);
184✔
1068

1069
   f = xcalloc(sizeof(jit_func_t));
92✔
1070

1071
   f->name      = name;
92✔
1072
   f->state     = JIT_FUNC_READY;
92✔
1073
   f->jit       = j;
92✔
1074
   f->handle    = j->next_handle++;
92✔
1075
   f->next_tier = j->tiers;
92✔
1076
   f->hotness   = f->next_tier ? f->next_tier->threshold : 0;
92✔
1077
   f->entry     = jit_interp;
92✔
1078

1079
   jit_install(j, f);
92✔
1080

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

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

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

1152
   const unsigned bufsz = 128;
92✔
1153
   f->irbuf = xcalloc_array(bufsz, sizeof(jit_ir_t));
92✔
1154

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

1167
         if (tok[0] == 'L' && isdigit((int)tok[1])) {
537✔
1168
            char *eptr = NULL;
25✔
1169
            const int lab = strtol(tok + 1, &eptr, 10);
25✔
1170
            if (*eptr != ':')
25✔
1171
               fatal_trace("cannot parse label '%s'", tok);
1172

1173
            if (lab > maxlabel) {
25✔
1174
               maxlabel = next_power_of_2(lab);
24✔
1175
               labels = xrealloc_array(labels, maxlabel + 1, sizeof(int));
24✔
1176
            }
1177

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

1192
      case INS:
536✔
1193
         {
1194
            char *dot = strchr(tok, '.');
536✔
1195
            if (dot != NULL)
536✔
1196
               *dot++ = '\0';
76✔
1197

1198
            int ipos = 0;
536✔
1199
            for (; ipos < ARRAY_LEN(optab)
536✔
1200
                    && strcmp(optab[ipos].name, tok); ipos++)
6,165✔
1201
               ;
1202

1203
            if (ipos == ARRAY_LEN(optab))
536✔
1204
               fatal_trace("illegal instruction %s", tok);
1205

1206
            nargs = optab[ipos].nargs;
536✔
1207
            nresult = optab[ipos].nresult;
536✔
1208

1209
            ir->op = optab[ipos].op;
536✔
1210
            ir->size = JIT_SZ_UNSPEC;
536✔
1211
            ir->result = JIT_REG_INVALID;
536✔
1212

1213
            if (dot != NULL) {
536✔
1214
               tok = dot;
76✔
1215
               state = CCSIZE;
76✔
1216
               goto again;
76✔
1217
            }
1218

1219
            state = nresult > 0 ? RESULT : (nargs > 0 ? ARG1 : NEWLINE);
460✔
1220
         }
1221
         break;
1222

1223
      case CCSIZE:
90✔
1224
         {
1225
            char *dot = strchr(tok, '.');
90✔
1226
            if (dot != NULL)
90✔
1227
               *dot++ = '\0';
14✔
1228

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

1245
               if (cpos == ARRAY_LEN(cctab))
40✔
1246
                  fatal_trace("illegal condition code %s", tok);
1247

1248
               ir->cc = cctab[cpos].cc;
40✔
1249
            }
1250

1251
            if (dot != NULL) {
90✔
1252
               tok = dot;
14✔
1253
               state = CCSIZE;
14✔
1254
               goto again;
14✔
1255
            }
1256

1257
            state = nresult > 0 ? RESULT : (nargs > 0 ? ARG1 : NEWLINE);
76✔
1258
         }
1259
         break;
1260

1261
      case RESULT:
326✔
1262
         if (tok[0] != 'R')
326✔
1263
            fatal_trace("expected register name but got '%s'", tok);
1264

1265
         ir->result = atoi(tok + 1);
326✔
1266
         f->nregs = MAX(ir->result + 1, f->nregs);
326✔
1267
         state = nargs > 0 ? ARG1 : NEWLINE;
326✔
1268
         break;
1269

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

1322
            if (state == ARG1)
646✔
1323
               ir->arg1 = arg;
423✔
1324
            else
1325
               ir->arg2 = arg;
223✔
1326

1327
            state = state == ARG1 && nargs > 1 ? ARG2 : NEWLINE;
646✔
1328
         }
1329
         break;
1330

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

1341
      case CP:
9✔
1342
         {
1343
            if (*tok == '\n' && *++tok == '\0')
9✔
1344
               continue;
1✔
1345

1346
            char *eptr = NULL;
8✔
1347
            unsigned long byte = strtoul(tok, &eptr, 16);
8✔
1348
            if (*eptr != '\0' || byte >= 256)
8✔
1349
               fatal_trace("invalid constant pool value '%s'", tok);
1350

1351
            if (f->cpool == NULL)
8✔
1352
               f->cpool = xmalloc((f->cpoolsz = 64));
1✔
1353
            else if (cpoolptr == f->cpoolsz)
7✔
1354
               fatal_trace("constant pool overflow");
1355

1356
            f->cpool[cpoolptr++] = byte;
8✔
1357
         }
1358
         break;
8✔
1359
      }
1360
   }
1361

1362
   f->cpoolsz = cpoolptr;
92✔
1363

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

1372
   return f->handle;
92✔
1373
}
1374

1375
bool jit_will_abort(jit_ir_t *ir)
2,287,836✔
1376
{
1377
   if (ir->op == MACRO_EXIT) {
2,287,836✔
1378
      return ir->arg1.exit == JIT_EXIT_INDEX_FAIL
87,622✔
1379
         || ir->arg1.exit == JIT_EXIT_OVERFLOW
1380
         || ir->arg1.exit == JIT_EXIT_NULL_DEREF
1381
         || ir->arg1.exit == JIT_EXIT_UNREACHABLE
87,622✔
1382
         || ir->arg1.exit == JIT_EXIT_LENGTH_FAIL
1383
         || ir->arg1.exit == JIT_EXIT_DIV_ZERO
1384
         || ir->arg1.exit == JIT_EXIT_EXPONENT_FAIL
1385
         || ir->arg1.exit == JIT_EXIT_RANGE_FAIL;
160,534✔
1386
   }
1387
   else
1388
      return ir->op == J_TRAP;
2,200,214✔
1389
}
1390

1391
int32_t *jit_get_cover_mem(jit_t *j, int mintags)
3,609✔
1392
{
1393
   if (mintags > j->cover_ntags) {
3,609✔
1394
      j->cover_mem = xrealloc_array(j->cover_mem, mintags, sizeof(int32_t));
148✔
1395
      memset(j->cover_mem + j->cover_ntags, '\0',
148✔
1396
             (mintags - j->cover_ntags) * sizeof(int32_t));
148✔
1397
      j->cover_ntags = mintags;
148✔
1398
   }
1399

1400
   return j->cover_mem;
3,609✔
1401
}
1402

1403
int32_t *jit_get_cover_ptr(jit_t *j, jit_value_t addr)
1,077✔
1404
{
1405
   assert(addr.kind == JIT_ADDR_COVER);
1,077✔
1406
   int32_t *base = jit_get_cover_mem(j, addr.int64 + 1);
1,077✔
1407
   assert(base != NULL);
1,077✔
1408
   return base + addr.int64;
1,077✔
1409
}
1410

1411
void jit_interrupt(jit_t *j, jit_irq_fn_t fn, void *ctx)
×
1412
{
1413
   relaxed_store(&j->interrupt_ctx, ctx);
×
1414
   if (!atomic_cas(&j->interrupt, NULL, fn))
×
1415
      fatal_exit(1);
×
1416
}
×
1417

1418
__attribute__((cold, noinline))
1419
static void jit_handle_interrupt(jit_t *j)
×
1420
{
1421
   jit_irq_fn_t fn = load_acquire(&j->interrupt);
×
1422
   if (!atomic_cas(&j->interrupt, fn, NULL))
×
1423
      return;
1424

1425
   (*fn)(j, relaxed_load(&j->interrupt_ctx));
×
1426
}
1427

1428
void jit_check_interrupt(jit_t *j)
48,136,509✔
1429
{
1430
   if (unlikely(relaxed_load(&j->interrupt) != NULL))
48,136,509✔
1431
      jit_handle_interrupt(j);
×
1432
}
48,136,509✔
1433

1434
void jit_reset(jit_t *j)
29✔
1435
{
1436
   SCOPED_LOCK(j->lock);
58✔
1437

1438
   for (int i = 0; i < j->next_handle; i++) {
80✔
1439
      jit_func_t *f = j->funcs->items[i];
51✔
1440
      if (f->privdata != MPTR_INVALID)
51✔
1441
         *mptr_get(f->privdata) = NULL;
42✔
1442
   }
1443

1444
   jit_reset_exit_status(j);
29✔
1445
}
29✔
1446

1447
jit_t *jit_for_thread(void)
235✔
1448
{
1449
   jit_thread_local_t *thread = jit_thread_local();
235✔
1450

1451
   if (unlikely(thread->jit == NULL))
235✔
1452
      fatal_trace("thread not attached to JIT");
1453

1454
   return thread->jit;
235✔
1455
}
1456

1457
jit_thread_local_t *jit_attach_thread(jit_anchor_t *anchor)
48,136,121✔
1458
{
1459
   jit_thread_local_t *thread = *jit_thread_local_ptr();
48,136,121✔
1460
   assert(thread != NULL);
48,136,121✔
1461

1462
   thread->anchor = anchor;
48,136,121✔
1463

1464
   jit_check_interrupt(thread->jit);
48,136,121✔
1465

1466
   return thread;
48,136,121✔
1467
}
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