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

nickg / nvc / 14685578009

26 Apr 2025 08:04PM UTC coverage: 92.344% (-0.004%) from 92.348%
14685578009

push

github

nickg
Optimise iteration over object fields

112 of 121 new or added lines in 1 file covered. (92.56%)

42 existing lines in 2 files now uncovered.

69223 of 74962 relevant lines covered (92.34%)

392751.34 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)
143,192,942✔
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;
143,192,942✔
130
#endif
131

132
   return &local;
143,192,942✔
133
}
134

135
jit_thread_local_t *jit_thread_local(void)
95,056,456✔
136
{
137
   jit_thread_local_t **ptr = jit_thread_local_ptr();
95,056,456✔
138

139
   if (unlikely(*ptr == NULL)) {
95,056,456✔
140
      *ptr = xcalloc(sizeof(jit_thread_local_t));
4,156✔
141
      (*ptr)->state = JIT_IDLE;
4,156✔
142
   }
143

144
   return *ptr;
95,056,456✔
145
}
146

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

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

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

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

165
   return j;
8,938✔
166
}
167

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

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

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

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

195
   for (int i = 0; i < j->next_handle; i++)
80,749✔
196
      jit_free_func(j->funcs->items[i]);
71,825✔
197
   free(j->funcs);
8,924✔
198

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

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

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

212
bool jit_is_shutdown(jit_t *j)
15,890✔
213
{
214
   return load_acquire(&j->shutdown);
15,890✔
215
}
216

217
mspace_t *jit_get_mspace(jit_t *j)
498,420✔
218
{
219
   return j->mspace;
498,420✔
220
}
221

222
void *jit_mspace_alloc(size_t size)
39,575,628✔
223
{
224
   jit_thread_local_t *thread = jit_thread_local();
39,575,628✔
225
   assert(thread->state == JIT_RUNNING);
39,575,628✔
226
   return mspace_alloc(thread->jit->mspace, size);
39,575,628✔
227
}
228

229
static void jit_install(jit_t *j, jit_func_t *f)
71,839✔
230
{
231
   assert_lock_held(&(j->lock));
71,839✔
232

233
   func_array_t *list = j->funcs;
71,839✔
234
   if (f->handle >= list->length) {
71,839✔
235
      const size_t newlen = MAX(f->handle + 1, list->length * 2);
12✔
236
      func_array_t *new = xcalloc_flex(sizeof(func_array_t),
12✔
237
                                       newlen, sizeof(jit_func_t *));
238
      new->length = newlen;
12✔
239
      for (size_t i = 0; i < list->length; i++)
10,764✔
240
         new->items[i] = list->items[i];
10,752✔
241

242
      // Synchronises with load_acquire in jit_get_func
243
      store_release(&(j->funcs), new);
12✔
244

245
      async_free(list);
12✔
246
      list = new;
12✔
247
   }
248

249
   // Synchronises with load_acquire in jit_get_func
250
   store_release(&(list->items[f->handle]), f);
71,839✔
251

252
   chash_put(j->index, f->name, f);
71,839✔
253
}
71,839✔
254

255
static jit_handle_t jit_lazy_compile_locked(jit_t *j, ident_t name)
109,127✔
256
{
257
   assert_lock_held(&j->lock);
109,127✔
258

259
   jit_func_t *f = chash_get(j->index, name);
109,127✔
260
   if (f != NULL)
109,127✔
261
      return f->handle;
37,380✔
262

263
   aot_descr_t *descr = NULL;
71,747✔
264
   if (j->aotlib != NULL || j->preloadlib != NULL) {
71,747✔
265
      LOCAL_TEXT_BUF tb = safe_symbol(name);
126,840✔
266
      tb_cat(tb, ".descr");
63,420✔
267

268
      aot_dll_t *try[] = { j->aotlib, j->preloadlib };
63,420✔
269
      for (int i = 0; i < ARRAY_LEN(try); i++) {
143,389✔
270
         if (try[i] == NULL)
118,373✔
271
            continue;
46,878✔
272
         else if ((descr = ffi_find_symbol(try[i]->dll, tb_get(tb)))) {
71,495✔
273
            jit_pack_put(try[i]->pack, name, descr->cpool,
38,404✔
274
                         descr->strtab, descr->debug);
275
            break;
38,404✔
276
         }
277
      }
278
   }
279

280
   jit_entry_fn_t entry =
143,494✔
281
      jit_bind_intrinsic(name) ?: (descr ? descr->entry : jit_interp);
71,747✔
282

283
   f = xcalloc(sizeof(jit_func_t));
71,747✔
284
   f->name      = name;
71,747✔
285
   f->state     = descr ? JIT_FUNC_COMPILING : JIT_FUNC_PLACEHOLDER;
71,747✔
286
   f->jit       = j;
71,747✔
287
   f->handle    = j->next_handle++;
71,747✔
288
   f->next_tier = j->tiers;
71,747✔
289
   f->hotness   = f->next_tier ? f->next_tier->threshold : 0;
71,747✔
290
   f->entry     = entry;
71,747✔
291

292
   // Install now to allow circular references in relocations
293
   jit_install(j, f);
71,747✔
294

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

320
            switch (r->kind) {
59,898✔
321
            case RELOC_FUNC:
36,216✔
322
               r->ptr = jit_get_func(j, h);
36,216✔
323
               break;
36,216✔
324
            case RELOC_HANDLE:
5,969✔
325
               r->ptr = (void *)(uintptr_t)h;
5,969✔
326
               break;
5,969✔
327
            case RELOC_PRIVDATA:
17,713✔
328
               r->ptr = jit_get_privdata_ptr(j, jit_get_func(j, h));
17,713✔
329
               break;
17,713✔
UNCOV
330
            default:
×
331
               fatal_trace("unhandled relocation kind %d", r->kind);
332
            }
333
         }
334

335
         r->kind = RELOC_PROCESSED;
60,115✔
336
      }
337

338
      store_release(&f->state, JIT_FUNC_READY);
38,404✔
339
   }
340

341
   return f->handle;
71,747✔
342
}
343

344
jit_handle_t jit_lazy_compile(jit_t *j, ident_t name)
174,825✔
345
{
346
   jit_func_t *f = chash_get(j->index, name);
174,825✔
347
   if (f != NULL)
174,825✔
348
      return f->handle;
125,596✔
349

350
   SCOPED_LOCK(j->lock);
98,458✔
351
   return jit_lazy_compile_locked(j, name);
49,229✔
352
}
353

354
jit_func_t *jit_get_func(jit_t *j, jit_handle_t handle)
22,193,471✔
355
{
356
   assert(handle != JIT_HANDLE_INVALID);
22,193,471✔
357

358
   // Synchronises with store_release in jit_install
359
   func_array_t *list = load_acquire(&(j->funcs));
22,193,471✔
360
   assert(handle < list->length);
22,193,471✔
361

362
   // Synchronises with store_release in jit_install
363
   jit_func_t *f = load_acquire(&(list->items[handle]));
22,193,471✔
364
   assert(f != NULL);
22,193,471✔
365
   return f;
22,193,471✔
366
}
367

368
static inline bool jit_fill_from_aot(jit_func_t *f, aot_dll_t *lib)
70,347✔
369
{
370
   return lib != NULL && jit_pack_fill(lib->pack, f->jit, f);
70,347✔
371
}
372

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

UNCOV
383
   __builtin_unreachable();
×
384
}
385

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

413
   assert(f->irbuf == NULL);
35,706✔
414

415
#ifndef USE_EMUTLS
416
   const jit_state_t oldstate = jit_thread_local()->state;
35,706✔
417
   jit_transition(f->jit, oldstate, JIT_COMPILING);
35,706✔
418
#endif
419

420
   if (jit_fill_from_aot(f, f->jit->aotlib))
35,706✔
421
      goto done;
1,065✔
422

423
   if (jit_fill_from_aot(f, f->jit->preloadlib))
34,641✔
424
      goto done;
1,831✔
425

426
   if (f->jit->pack != NULL && jit_pack_fill(f->jit->pack, f->jit, f))
32,810✔
427
      goto done;
870✔
428

429
   mir_unit_t *mu = mir_get_unit(f->jit->mir, f->name);
31,940✔
430

431
   if (mu == NULL && f->jit->registry != NULL) {
31,940✔
432
      // Unit registry and MIR import is not thread-safe
433
      SCOPED_LOCK(f->jit->lock);
40,167✔
434
      vcode_unit_t unit = unit_registry_get(f->jit->registry, f->name);
20,085✔
435
      if (unit != NULL) {
20,082✔
436
         mu = mir_import(f->jit->mir, unit);
20,081✔
437
         mir_put_unit(f->jit->mir, mu);
20,081✔
438
      }
439
   }
440

441
   if (mu == NULL) {
31,937✔
442
      store_release(&(f->state), JIT_FUNC_ERROR);
1✔
443
      jit_missing_unit(f);
1✔
444
   }
445

446
   jit_irgen(f, mu);
31,936✔
447

448
 done:
35,702✔
449
#ifndef USE_EMUTLS
450
   jit_transition(f->jit, JIT_COMPILING, oldstate);
35,702✔
451
#endif
452
}
453

454
jit_handle_t jit_compile(jit_t *j, ident_t name)
1,035✔
455
{
456
   jit_handle_t handle = jit_lazy_compile(j, name);
1,035✔
457
   if (handle == JIT_HANDLE_INVALID)
1,035✔
458
      return handle;
459

460
   jit_func_t *f = jit_get_func(j, handle);
1,035✔
461
   jit_fill_irbuf(f);
1,035✔
462

463
   return handle;
1,035✔
464
}
465

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

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

475
   f->privdata = mptr_new(j->mspace, "privdata");
14✔
476

477
   jit_fill_irbuf(f);
14✔
478

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

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

493
   return result.pointer;
14✔
494
}
495

496
void **jit_get_privdata_ptr(jit_t *j, jit_func_t *f)
4,357,176✔
497
{
498
   if (f->privdata == MPTR_INVALID)
4,357,176✔
499
      f->privdata = mptr_new(j->mspace, "privdata");
25,410✔
500

501
   return mptr_get(f->privdata);
4,357,176✔
502
}
503

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

510
   jit_fill_irbuf(f);
361✔
511

512
   for (int i = 0; i < f->nvars; i++) {
952✔
513
      if (f->linktab[i].name == name)
952✔
514
         return *mptr_get(f->privdata) + f->linktab[i].offset;
361✔
515
   }
516

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

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

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

584
   int count = 0;
6,748✔
585
   for (jit_anchor_t *a = thread->anchor; a; a = a->caller)
16,427✔
586
      count++;
9,679✔
587

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

592
   jit_frame_t *frame = stack->frames;
6,748✔
593
   for (jit_anchor_t *a = thread->anchor; a; a = a->caller, frame++) {
16,427✔
594
      frame->loc    = LOC_INVALID;
9,679✔
595
      frame->symbol = a->func->name;
9,679✔
596
      frame->object = NULL;
9,679✔
597

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

603
      jit_fill_irbuf(a->func);
9,679✔
604

605
      frame->object = a->func->object;
9,679✔
606

607
      // Scan backwards to find the last debug info
608
      assert(a->irpos < a->func->nirs);
9,679✔
609
      frame->loc = frame->object ? frame->object->loc : LOC_INVALID;
9,679✔
610
      for (jit_ir_t *ir = &(a->func->irbuf[a->irpos]);
9,679✔
611
           ir >= a->func->irbuf; ir--) {
54,042✔
612
         if (ir->op == J_DEBUG) {
53,765✔
613
            frame->loc = ir->arg1.loc;
9,385✔
614
            break;
9,385✔
615
         }
616
         else if (ir->target)
44,380✔
617
            break;
618
      }
619
   }
620

621
   return stack;
6,748✔
622
}
623

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

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

635
   jit_stack_trace_t *stack LOCAL = jit_stack_trace();
10,810✔
636

637
   for (int i = 0; i < stack->count; i++) {
13,210✔
638
      jit_frame_t *frame = &(stack->frames[i]);
7,805✔
639

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

647
static void jit_transition(jit_t *j, jit_state_t from, jit_state_t to)
36,722,942✔
648
{
649
   jit_thread_local_t *thread = jit_thread_local();
36,722,942✔
650

651
#ifdef DEBUG
652
   if (thread->state != from)
36,722,942✔
653
      fatal_trace("expected thread state %d but have %d", from, thread->state);
654
#endif
655

656
   thread->state = to;
36,722,942✔
657

658
   switch (to) {
36,722,942✔
659
   case JIT_RUNNING:
18,413,270✔
660
      if (from != JIT_RUNNING) {
18,413,270✔
661
         diag_add_hint_fn(jit_diag_cb, j);
18,284,172✔
662
         thread->jit = j;
18,284,172✔
663
      }
664
      else
665
         assert(thread->jit == j);
129,098✔
666
      break;
667
   case JIT_IDLE:
18,273,268✔
668
      if (from == JIT_RUNNING) {
18,273,268✔
669
         diag_remove_hint_fn(jit_diag_cb);
18,261,216✔
670
         thread->jit = NULL;
18,261,216✔
671
      }
672
      break;
673
   case JIT_COMPILING:
36,404✔
674
      if (from == JIT_RUNNING) {
36,404✔
675
         diag_remove_hint_fn(jit_diag_cb);
22,956✔
676
         thread->jit = NULL;
22,956✔
677
      }
678
      break;
679
   }
680
}
36,722,942✔
681

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

688
   const int rc = jit_setjmp(thread->abort_env);
18,325,769✔
689
   if (rc == 0) {
18,327,235✔
690
      thread->jmp_buf_valid = 1;
18,325,769✔
691
      jit_transition(j, oldstate, JIT_RUNNING);
18,325,769✔
692

693
      jit_entry_fn_t entry = load_acquire(&f->entry);
18,325,769✔
694
      (*entry)(f, NULL, args, tlab);
18,325,769✔
695

696
      jit_transition(j, JIT_RUNNING, oldstate);
18,324,299✔
697
      thread->jmp_buf_valid = 0;
18,324,299✔
698
      thread->anchor = NULL;
18,324,299✔
699
      return true;
18,324,299✔
700
   }
701
   else {
702
      jit_transition(j, JIT_RUNNING, oldstate);
1,466✔
703
      thread->jmp_buf_valid = 0;
1,466✔
704
      thread->anchor = NULL;
1,466✔
705
      return false;
1,466✔
706
   }
707
}
708

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

713
   int wptr = 0;
67,625✔
714
   for (int i = 1; ffi_spec_has(f->spec, i); i++) {
269,513✔
715
      switch (ffi_spec_get(f->spec, i)) {
201,888✔
716
      case FFI_POINTER:
134,335✔
717
         args[wptr++].pointer = va_arg(ap, void *);
134,335✔
718
         break;
134,335✔
719
      case FFI_FLOAT:
77✔
720
         args[wptr++].real = va_arg(ap, double);
77✔
721
         break;
77✔
722
      case FFI_UARRAY:
35✔
723
         args[wptr++].pointer = va_arg(ap, void *);
35✔
724
         args[wptr++].integer = va_arg(ap, int32_t);
35✔
725
         args[wptr++].integer = va_arg(ap, int32_t);
35✔
726
         break;
35✔
727
      case FFI_INT8:
359✔
728
      case FFI_INT16:
729
      case FFI_INT32:
730
         args[wptr++].integer = va_arg(ap, int32_t);
359✔
731
         break;
359✔
732
      case FFI_UINT8:
66,992✔
733
      case FFI_UINT16:
734
      case FFI_UINT32:
735
         args[wptr++].integer = va_arg(ap, uint32_t);
66,992✔
736
         break;
66,992✔
737
      default:
90✔
738
         args[wptr++].integer = va_arg(ap, int64_t);
90✔
739
         break;
90✔
740
      }
741
   }
742
}
67,625✔
743

744
bool jit_try_call(jit_t *j, jit_handle_t handle, jit_scalar_t *result, ...)
67,268✔
745
{
746
   va_list ap;
67,268✔
747
   va_start(ap, result);
67,268✔
748

749
   jit_func_t *f = jit_get_func(j, handle);
67,268✔
750

751
   jit_scalar_t args[JIT_MAX_ARGS];
67,268✔
752
   jit_unpack_args(f, args, ap);
67,268✔
753

754
   va_end(ap);
67,268✔
755

756
   tlab_t tlab = jit_null_tlab(j);
67,268✔
757
   if (!jit_try_vcall(j, f, args, &tlab))
67,268✔
758
      return false;
759

760
   *result = args[0];
66,660✔
761
   return true;
66,660✔
762
}
763

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

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

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

774
   va_end(ap);
357✔
775

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

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

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

784
bool jit_fastcall(jit_t *j, jit_handle_t handle, jit_scalar_t *result,
18,229,910✔
785
                  jit_scalar_t p1, jit_scalar_t p2, tlab_t *tlab)
786
{
787
   jit_func_t *f = jit_get_func(j, handle);
18,229,910✔
788

789
   jit_scalar_t args[JIT_MAX_ARGS];
18,229,910✔
790
   args[0] = p1;
18,229,910✔
791
   args[1] = p2;
18,229,910✔
792

793
   if (!jit_try_vcall(j, f, args, tlab))
18,229,910✔
794
      return false;
795

796
   *result = args[0];
18,229,475✔
797
   return true;
18,229,475✔
798
}
799

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

806
   jit_scalar_t args[JIT_MAX_ARGS];
16,138✔
807
   memcpy(args, inargs, nargs * sizeof(jit_scalar_t));
16,138✔
808

809
   if (!jit_try_vcall(j, f, args, tlab))
16,138✔
810
      return false;
811

812
   memcpy(results, args, nresults * sizeof(jit_scalar_t));
16,138✔
813
   return true;
16,138✔
814
}
815

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

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

828
   mir_unit_t *mu = mir_import(f->jit->mir, unit);
12,096✔
829
   jit_irgen(f, mu);
12,096✔
830
   mir_unit_free(mu);
12,096✔
831

832
   jit_scalar_t args[JIT_MAX_ARGS];
12,096✔
833
   args[0].pointer = context;
12,096✔
834

835
   tlab_t tlab = jit_null_tlab(j);
12,096✔
836

837
   void *user = NULL;
12,096✔
838
   if (jit_try_vcall(j, f, args, &tlab))
12,096✔
839
      user = (*fn)(args, arg);
11,669✔
840

841
   jit_free_func(f);
12,092✔
842
   return user;
12,092✔
843
}
844

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

851
void jit_set_silent(jit_t *j, bool silent)
26,046✔
852
{
853
   j->silent = silent;
26,046✔
854
}
26,046✔
855

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

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

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

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

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

877
   return lib;
6,078✔
878
}
879

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

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

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

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

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

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

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

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

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

919
   if (access(so_path, F_OK) != 0)
3,364✔
920
      return;
2,146✔
921

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

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

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

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

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

943
   diag_emit(d);
708✔
944

945
   if (level == DIAG_FATAL)
708✔
946
      jit_abort_with_status(EXIT_FAILURE);
708✔
UNCOV
947
}
×
948

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

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

UNCOV
968
   __builtin_unreachable();
×
969
}
970

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

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

979
   jit_abort();
1,350✔
980
}
981

982
void jit_reset_exit_status(jit_t *j)
13,050✔
983
{
984
   atomic_store(&(j->exit_status), INT_MIN);
13,050✔
985
}
13,050✔
986

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

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

1002
   if (!jit_is_shutdown(f->jit))
4✔
1003
      (*tier->plugin.cgen)(f->jit, f->handle, tier->context);
4✔
1004
}
4✔
1005

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

1011
   if (opt_get_int(OPT_JIT_ASYNC))
8,009✔
1012
      async_do(jit_async_cgen, f, f->next_tier);
4✔
1013
   else
1014
      (f->next_tier->plugin.cgen)(f->jit, f->handle, f->next_tier->context);
8,005✔
1015

1016
   f->hotness   = 0;
8,009✔
1017
   f->next_tier = NULL;
8,009✔
1018
}
8,009✔
1019

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

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

1030
   j->tiers = t;
3,590✔
1031
}
3,590✔
1032

1033
ident_t jit_get_name(jit_t *j, jit_handle_t handle)
1,233✔
1034
{
1035
   return jit_get_func(j, handle)->name;
1,233✔
1036
}
1037

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

1045
bool jit_writes_flags(jit_ir_t *ir)
8,700,122✔
1046
{
1047
   return ir->op == J_CMP || ir->op == J_FCMP
8,700,122✔
1048
      || ir->op == J_CCMP || ir->op == J_FCCMP
8,376,447✔
1049
      || (ir->op == J_ADD && ir->cc != JIT_CC_NONE)
8,363,400✔
1050
      || (ir->op == J_SUB && ir->cc != JIT_CC_NONE)
8,358,135✔
1051
      || (ir->op == J_MUL && ir->cc != JIT_CC_NONE)
8,354,865✔
1052
      || (ir->op == MACRO_EXP && ir->cc != JIT_CC_NONE);
17,054,107✔
1053
}
1054

1055
bool jit_reads_flags(jit_ir_t *ir)
5,793,267✔
1056
{
1057
   return (ir->op == J_JUMP && ir->cc != JIT_CC_NONE)
251,020✔
1058
      || ir->op == J_CSET || ir->op == J_CSEL || ir->op == J_CCMP
1059
      || ir->op == J_FCCMP;
5,793,267✔
1060
}
1061

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

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

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

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

1080
   jit_install(j, f);
92✔
1081

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1363
   f->cpoolsz = cpoolptr;
92✔
1364

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

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

1376
bool jit_will_abort(jit_ir_t *ir)
2,318,197✔
1377
{
1378
   if (ir->op == MACRO_EXIT) {
2,318,197✔
1379
      return ir->arg1.exit == JIT_EXIT_INDEX_FAIL
88,204✔
1380
         || ir->arg1.exit == JIT_EXIT_OVERFLOW
1381
         || ir->arg1.exit == JIT_EXIT_NULL_DEREF
1382
         || ir->arg1.exit == JIT_EXIT_UNREACHABLE
88,204✔
1383
         || ir->arg1.exit == JIT_EXIT_LENGTH_FAIL
1384
         || ir->arg1.exit == JIT_EXIT_DIV_ZERO
1385
         || ir->arg1.exit == JIT_EXIT_EXPONENT_FAIL
1386
         || ir->arg1.exit == JIT_EXIT_RANGE_FAIL;
161,470✔
1387
   }
1388
   else
1389
      return ir->op == J_TRAP;
2,229,993✔
1390
}
1391

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1463
   thread->anchor = anchor;
48,136,486✔
1464

1465
   jit_check_interrupt(thread->jit);
48,136,486✔
1466

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