Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/moar.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include <platform/threads.h>
3
#include "platform/random.h"
4
#include "platform/time.h"
5
#if defined(_MSC_VER)
6
#define snprintf _snprintf
7
#endif
8
9
#ifndef _WIN32
10
#  include <unistd.h>
11
#else
12
#  include <process.h>
13
#endif
14
15
3.02k
#define init_mutex(loc, name) do { \
16
3.02k
    if ((init_stat = uv_mutex_init(&loc)) < 0) { \
17
0
        fprintf(stderr, "MoarVM: Initialization of " name " mutex failed\n    %s\n", \
18
0
            uv_strerror(init_stat)); \
19
0
        exit(1); \
20
0
    } \
21
3.02k
} while (0)
22
720
#define init_cond(loc, name) do { \
23
720
    if ((init_stat = uv_cond_init(&loc)) < 0) { \
24
0
        fprintf(stderr, "MoarVM: Initialization of " name " condition variable failed\n    %s\n", \
25
0
            uv_strerror(init_stat)); \
26
0
        exit(1); \
27
0
    } \
28
720
} while (0)
29
30
static void setup_std_handles(MVMThreadContext *tc);
31
32
0
static FILE *fopen_perhaps_with_pid(char *env_var, char *path, const char *mode) {
33
0
    FILE *result;
34
0
    if (strstr(path, "%d")) {
35
0
        MVMuint64 path_length = strlen(path);
36
0
        MVMuint64 found_percents = 0;
37
0
        MVMuint64 i;
38
0
39
0
        /* Let's sanitize the format string a bit. Must only have
40
0
         * a single printf-recognized directive. */
41
0
        for (i = 0; i < path_length; i++) {
42
0
            if (path[i] == '%') {
43
0
                /* %% is all right. */
44
0
                if (i + 1 < path_length && path[i + 1] == '%') {
45
0
                    i++; continue;
46
0
                }
47
0
                found_percents++;
48
0
            }
49
0
        }
50
0
        /* We expect to pass only a single argument to snprintf here;
51
0
         * just bail out if there's more than one directive. */
52
0
        if (found_percents > 1) {
53
0
            result = fopen(path, mode);
54
0
        } else {
55
0
            char *fixed_path = malloc(path_length + 16);
56
0
            MVMint64 pid;
57
0
#ifdef _WIN32
58
            pid = _getpid();
59
#else
60
0
            pid = getpid();
61
0
#endif
62
0
            /* We make the brave assumption that
63
0
             * pids only go up to 16 characters. */
64
0
            snprintf(fixed_path, path_length + 16, path, pid);
65
0
            result = fopen(fixed_path, mode);
66
0
            free(fixed_path);
67
0
        }
68
0
    } else {
69
0
        result = fopen(path, mode);
70
0
    }
71
0
72
0
    if (result)
73
0
        return result;
74
0
    fprintf(stderr, "MoarVM: Failed to open file `%s` given via `%s`: %s\n",
75
0
        path, env_var, strerror(errno));
76
0
    exit(1);
77
0
}
78
79
/* Create a new instance of the VM. */
80
144
MVMInstance * MVM_vm_create_instance(void) {
81
144
    MVMInstance *instance;
82
144
83
144
    char *spesh_log, *spesh_nodelay, *spesh_disable, *spesh_inline_disable,
84
144
         *spesh_osr_disable, *spesh_limit, *spesh_blocking;
85
144
    char *jit_log, *jit_expr_disable, *jit_disable, *jit_bytecode_dir, *jit_last_frame, *jit_last_bb;
86
144
    char *dynvar_log;
87
144
    int init_stat;
88
144
    MVMuint32 hashSecret;
89
144
    MVMuint64 now = MVM_platform_now();
90
144
91
144
    /* Set up instance data structure. */
92
144
    instance = MVM_calloc(1, sizeof(MVMInstance));
93
144
94
144
    /* Create the main thread's ThreadContext and stash it. */
95
144
    instance->main_thread = MVM_tc_create(NULL, instance);
96
144
    MVM_getrandom(instance->main_thread, &hashSecret, sizeof(MVMuint32));
97
144
    instance->hashSecret ^= now;
98
144
    instance->hashSecret ^= MVM_proc_getpid(instance->main_thread) * now;
99
144
    instance->main_thread->thread_id = 1;
100
144
101
144
    /* Next thread to be created gets ID 2 (the main thread got ID 1). */
102
144
    MVM_store(&instance->next_user_thread_id, 2);
103
144
104
144
    /* Set up the permanent roots storage. */
105
144
    instance->num_permroots         = 0;
106
144
    instance->alloc_permroots       = 16;
107
144
    instance->permroots             = MVM_malloc(sizeof(MVMCollectable **) * instance->alloc_permroots);
108
144
    instance->permroot_descriptions = MVM_malloc(sizeof(char *) * instance->alloc_permroots);
109
144
    init_mutex(instance->mutex_permroots, "permanent roots");
110
144
111
144
    /* GC orchestration state. */
112
144
    init_mutex(instance->mutex_gc_orchestrate, "GC orchestration");
113
144
    init_cond(instance->cond_gc_start, "GC start");
114
144
    init_cond(instance->cond_gc_finish, "GC finish");
115
144
    init_cond(instance->cond_gc_intrays_clearing, "GC intrays clearing");
116
144
    init_cond(instance->cond_blocked_can_continue, "GC thread unblock");
117
144
118
144
    /* Create fixed size allocator. */
119
144
    instance->fsa = MVM_fixed_size_create(instance->main_thread);
120
144
121
144
    /* Set up REPR registry mutex. */
122
144
    init_mutex(instance->mutex_repr_registry, "REPR registry");
123
144
124
144
    /* Set up HLL config mutex. */
125
144
    init_mutex(instance->mutex_hllconfigs, "hll configs");
126
144
127
144
    /* Set up DLL registry mutex. */
128
144
    init_mutex(instance->mutex_dll_registry, "REPR registry");
129
144
130
144
    /* Set up extension registry mutex. */
131
144
    init_mutex(instance->mutex_ext_registry, "extension registry");
132
144
133
144
    /* Set up extension op registry mutex. */
134
144
    init_mutex(instance->mutex_extop_registry, "extension op registry");
135
144
136
144
    /* Set up SC registry mutex. */
137
144
    init_mutex(instance->mutex_sc_registry, "sc registry");
138
144
139
144
    /* Set up loaded compunits hash mutex. */
140
144
    init_mutex(instance->mutex_loaded_compunits, "loaded compunits");
141
144
142
144
    /* Set up container registry mutex. */
143
144
    init_mutex(instance->mutex_container_registry, "container registry");
144
144
145
144
    /* Set up persistent object ID hash mutex. */
146
144
    init_mutex(instance->mutex_object_ids, "object ID hash");
147
144
148
144
    /* Allocate all things during following setup steps directly in gen2, as
149
144
     * they will have program lifetime. */
150
144
    MVM_gc_allocate_gen2_default_set(instance->main_thread);
151
144
152
144
    /* Set up integer constant and string cache. */
153
144
    init_mutex(instance->mutex_int_const_cache, "int constant cache");
154
144
    instance->int_const_cache = MVM_calloc(1, sizeof(MVMIntConstCache));
155
144
    instance->int_to_str_cache = MVM_calloc(MVM_INT_TO_STR_CACHE_SIZE, sizeof(MVMString *));
156
144
157
144
    /* Initialize Unicode database and NFG. */
158
144
    MVM_unicode_init(instance->main_thread);
159
144
    MVM_nfg_init(instance->main_thread);
160
144
161
144
    /* Bootstrap 6model. It is assumed the GC will not be called during this. */
162
144
    MVM_6model_bootstrap(instance->main_thread);
163
144
164
144
    /* Set up main thread's last_payload. */
165
144
    instance->main_thread->last_payload = instance->VMNull;
166
144
167
144
    /* Initialize event loop thread starting mutex. */
168
144
    init_mutex(instance->mutex_event_loop_start, "event loop thread start");
169
144
170
144
    /* Create main thread object, and also make it the start of the all threads
171
144
     * linked list. Set up the mutex to protect it. */
172
144
    instance->threads = instance->main_thread->thread_obj = (MVMThread *)
173
144
        REPR(instance->boot_types.BOOTThread)->allocate(
174
144
            instance->main_thread, STABLE(instance->boot_types.BOOTThread));
175
144
    instance->threads->body.stage = MVM_thread_stage_started;
176
144
    instance->threads->body.tc = instance->main_thread;
177
144
    instance->threads->body.native_thread_id = MVM_platform_thread_id();
178
144
    instance->threads->body.thread_id = instance->main_thread->thread_id;
179
144
    init_mutex(instance->mutex_threads, "threads list");
180
144
181
144
    /* Create compiler registry */
182
144
    instance->compiler_registry = MVM_repr_alloc_init(instance->main_thread, instance->boot_types.BOOTHash);
183
144
184
144
    /* Set up compiler registr mutex. */
185
144
    init_mutex(instance->mutex_compiler_registry, "compiler registry");
186
144
187
144
    /* Create hll symbol tables */
188
144
    instance->hll_syms = MVM_repr_alloc_init(instance->main_thread, instance->boot_types.BOOTHash);
189
144
190
144
    /* Set up hll symbol tables mutex. */
191
144
    init_mutex(instance->mutex_hll_syms, "hll syms");
192
144
193
144
    /* Create callsite intern pool. */
194
144
    instance->callsite_interns = MVM_calloc(1, sizeof(MVMCallsiteInterns));
195
144
    init_mutex(instance->mutex_callsite_interns, "callsite interns");
196
144
197
144
    /* There's some callsites we statically use all over the place. Intern
198
144
     * them, so that spesh may end up optimizing more "internal" stuff. */
199
144
    MVM_callsite_initialize_common(instance->main_thread);
200
144
201
144
    /* Multi-cache additions mutex. */
202
144
    init_mutex(instance->mutex_multi_cache_add, "multi-cache addition");
203
144
204
144
    /* Current instrumentation level starts at 1; used to trigger all frames
205
144
     * to be verified before their first run. */
206
144
    instance->instrumentation_level = 1;
207
144
208
144
    /* Mutex for spesh installations, and check if we've a file we
209
144
     * should log specializations to. */
210
144
    init_mutex(instance->mutex_spesh_install, "spesh installations");
211
144
    spesh_log = getenv("MVM_SPESH_LOG");
212
144
    if (spesh_log && spesh_log[0])
213
0
        instance->spesh_log_fh
214
0
            = fopen_perhaps_with_pid("MVM_SPESH_LOG", spesh_log, "w");
215
144
    spesh_disable = getenv("MVM_SPESH_DISABLE");
216
144
    if (!spesh_disable || !spesh_disable[0]) {
217
144
        instance->spesh_enabled = 1;
218
144
        spesh_inline_disable = getenv("MVM_SPESH_INLINE_DISABLE");
219
144
        if (!spesh_inline_disable || !spesh_inline_disable[0])
220
144
            instance->spesh_inline_enabled = 1;
221
144
        spesh_osr_disable = getenv("MVM_SPESH_OSR_DISABLE");
222
144
        if (!spesh_osr_disable || !spesh_osr_disable[0])
223
144
            instance->spesh_osr_enabled = 1;
224
144
    }
225
144
226
144
    init_mutex(instance->mutex_parameterization_add, "parameterization");
227
144
228
144
    /* Should we specialize without warm up delays? Used to find bugs in the
229
144
     * specializer and JIT. */
230
144
    spesh_nodelay = getenv("MVM_SPESH_NODELAY");
231
144
    if (spesh_nodelay && spesh_nodelay[0]) {
232
0
        instance->spesh_nodelay = 1;
233
0
    }
234
144
235
144
    /* Should we limit the number of specialized frames produced? (This is
236
144
     * mostly useful for building spesh bug bisect tools.) */
237
144
    spesh_limit = getenv("MVM_SPESH_LIMIT");
238
144
    if (spesh_limit && spesh_limit[0])
239
0
        instance->spesh_limit = atoi(spesh_limit);
240
144
241
144
    /* Should we enforce that a thread, when sending work to the specialzation
242
144
     * worker, block until the specialization worker is done? This is useful
243
144
     * for getting more predictable behavior when debugging. */
244
144
    spesh_blocking = getenv("MVM_SPESH_BLOCKING");
245
144
    if (spesh_blocking && spesh_blocking[0])
246
0
        instance->spesh_blocking = 1;
247
144
248
144
    /* JIT environment/logging setup. */
249
144
    jit_disable = getenv("MVM_JIT_DISABLE");
250
144
    if (!jit_disable || !jit_disable[0])
251
144
        instance->jit_enabled = 1;
252
144
253
144
    jit_expr_disable = getenv("MVM_JIT_EXPR_DISABLE");
254
144
    if (!jit_expr_disable || strlen(jit_expr_disable) == 0)
255
144
        instance->jit_expr_enabled = 1;
256
144
257
144
258
144
    jit_log = getenv("MVM_JIT_LOG");
259
144
    if (jit_log && jit_log[0])
260
0
        instance->jit_log_fh = fopen_perhaps_with_pid("MVM_JIT_LOG", jit_log, "w");
261
144
    jit_bytecode_dir = getenv("MVM_JIT_BYTECODE_DIR");
262
144
    if (jit_bytecode_dir && jit_bytecode_dir[0]) {
263
0
        size_t bytecode_map_name_size = strlen(jit_bytecode_dir) + strlen("/jit-map.txt") + 1;
264
0
        char *bytecode_map_name = MVM_malloc(bytecode_map_name_size);
265
0
        snprintf(bytecode_map_name, bytecode_map_name_size, "%s/jit-map.txt", jit_bytecode_dir);
266
0
        instance->jit_bytecode_map = fopen(bytecode_map_name, "w");
267
0
        instance->jit_bytecode_dir = jit_bytecode_dir;
268
0
        MVM_free(bytecode_map_name);
269
0
    }
270
144
    jit_last_frame = getenv("MVM_JIT_EXPR_LAST_FRAME");
271
144
    jit_last_bb    = getenv("MVM_JIT_EXPR_LAST_BB");
272
144
273
144
    /* what could possibly go wrong in integer formats? */
274
144
    instance->jit_expr_last_frame = jit_last_frame != NULL ? atoi(jit_last_frame) : -1;
275
144
    instance->jit_expr_last_bb    =    jit_last_bb != NULL ? atoi(jit_last_bb) : -1;
276
144
    instance->jit_seq_nr = 0;
277
144
278
144
    /* add JIT debugging breakpoints */
279
144
    {
280
144
        char *jit_breakpoints_str = getenv("MVM_JIT_BREAKPOINTS");
281
144
        if (jit_breakpoints_str != NULL) {
282
0
            MVM_VECTOR_INIT(instance->jit_breakpoints, 4);
283
144
        } else {
284
144
            instance->jit_breakpoints_num = 0;
285
144
            instance->jit_breakpoints     = NULL;
286
144
        }
287
144
        while (jit_breakpoints_str != NULL && *jit_breakpoints_str) {
288
0
            MVMint32 frame_nr, block_nr, nchars;
289
0
            MVMint32 result = sscanf(jit_breakpoints_str, "%d/%d%n",
290
0
                                     &frame_nr, &block_nr, &nchars);
291
0
            if (result < 2)
292
0
                break;
293
0
294
0
            MVM_VECTOR_ENSURE_SPACE(instance->jit_breakpoints, 1);
295
0
            instance->jit_breakpoints[instance->jit_breakpoints_num].frame_nr = frame_nr;
296
0
            instance->jit_breakpoints[instance->jit_breakpoints_num].block_nr = block_nr;
297
0
            instance->jit_breakpoints_num++;
298
0
299
0
            jit_breakpoints_str += nchars;
300
0
            if (*jit_breakpoints_str == ':') {
301
0
                jit_breakpoints_str++;
302
0
            }
303
0
        }
304
144
    }
305
144
306
144
    /* Spesh thread syncing. */
307
144
    init_mutex(instance->mutex_spesh_sync, "spesh sync");
308
144
    init_cond(instance->cond_spesh_sync, "spesh sync");
309
144
310
144
    /* Various kinds of debugging that can be enabled. */
311
144
    dynvar_log = getenv("MVM_DYNVAR_LOG");
312
144
    if (dynvar_log && dynvar_log[0]) {
313
0
        instance->dynvar_log_fh = fopen_perhaps_with_pid("MVM_DYNVAR_LOG", dynvar_log, "w");
314
0
        fprintf(instance->dynvar_log_fh, "+ x 0 0 0 0 0 %"PRIu64"\n", uv_hrtime());
315
0
        fflush(instance->dynvar_log_fh);
316
0
        instance->dynvar_log_lasttime = uv_hrtime();
317
0
    }
318
144
    else
319
144
        instance->dynvar_log_fh = NULL;
320
144
    instance->nfa_debug_enabled = getenv("MVM_NFA_DEB") ? 1 : 0;
321
144
    if (getenv("MVM_CROSS_THREAD_WRITE_LOG")) {
322
0
        instance->cross_thread_write_logging = 1;
323
0
        instance->cross_thread_write_logging_include_locked =
324
0
            getenv("MVM_CROSS_THREAD_WRITE_LOG_INCLUDE_LOCKED") ? 1 : 0;
325
0
        instance->instrumentation_level++;
326
0
        init_mutex(instance->mutex_cross_thread_write_logging,
327
0
            "cross thread write logging output");
328
0
    }
329
144
    else {
330
144
        instance->cross_thread_write_logging = 0;
331
144
    }
332
144
333
144
    if (getenv("MVM_COVERAGE_LOG")) {
334
0
        char *coverage_log = getenv("MVM_COVERAGE_LOG");
335
0
        instance->coverage_logging = 1;
336
0
        instance->instrumentation_level++;
337
0
        if (coverage_log[0])
338
0
            instance->coverage_log_fh = fopen_perhaps_with_pid("MVM_COVERAGE_LOG", coverage_log, "a");
339
0
        else
340
0
            instance->coverage_log_fh = stderr;
341
0
342
0
        instance->coverage_control = 0;
343
0
        if (getenv("MVM_COVERAGE_CONTROL")) {
344
0
            char *coverage_control = getenv("MVM_COVERAGE_CONTROL");
345
0
            if (coverage_control && coverage_control[0])
346
0
                instance->coverage_control = atoi(coverage_control);
347
0
        }
348
0
    }
349
144
    else {
350
144
        instance->coverage_logging = 0;
351
144
    }
352
144
353
144
    /* Create std[in/out/err]. */
354
144
    setup_std_handles(instance->main_thread);
355
144
356
144
    /* Set up the specialization worker thread and a log for the main thread. */
357
144
    MVM_spesh_worker_setup(instance->main_thread);
358
144
    MVM_spesh_log_initialize_thread(instance->main_thread, 1);
359
144
360
144
    /* Back to nursery allocation, now we're set up. */
361
144
    MVM_gc_allocate_gen2_default_clear(instance->main_thread);
362
144
363
144
    return instance;
364
144
}
365
366
/* Set up some standard file handles. */
367
144
static void setup_std_handles(MVMThreadContext *tc) {
368
144
    tc->instance->stdin_handle  = MVM_file_get_stdstream(tc, 0);
369
144
    MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&tc->instance->stdin_handle,
370
144
        "stdin handle");
371
144
372
144
    tc->instance->stdout_handle = MVM_file_get_stdstream(tc, 1);
373
144
    MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&tc->instance->stdout_handle,
374
144
        "stdout handle");
375
144
376
144
    tc->instance->stderr_handle = MVM_file_get_stdstream(tc, 2);
377
144
    MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&tc->instance->stderr_handle,
378
144
        "stderr handle");
379
144
}
380
381
/* This callback is passed to the interpreter code. It takes care of making
382
 * the initial invocation. */
383
288
static void toplevel_initial_invoke(MVMThreadContext *tc, void *data) {
384
288
    /* Create initial frame, which sets up all of the interpreter state also. */
385
288
    MVM_frame_invoke(tc, (MVMStaticFrame *)data, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS), NULL, NULL, NULL, -1);
386
288
}
387
388
/* Loads bytecode from the specified file name and runs it. */
389
144
void MVM_vm_run_file(MVMInstance *instance, const char *filename) {
390
144
    /* Map the compilation unit into memory and dissect it. */
391
144
    MVMThreadContext *tc = instance->main_thread;
392
144
    MVMCompUnit      *cu = MVM_cu_map_from_file(tc, filename);
393
144
394
144
    MVMROOT(tc, cu, {
395
144
        /* The call to MVM_string_utf8_decode() may allocate, invalidating the
396
144
           location cu->body.filename */
397
144
        MVMString *const str = MVM_string_utf8_c8_decode(tc, instance->VMString, filename, strlen(filename));
398
144
        cu->body.filename = str;
399
144
400
144
        /* Run deserialization frame, if there is one. Disable specialization
401
144
         * during this time, so we don't waste time logging one-shot setup
402
144
         * code. */
403
144
        if (cu->body.deserialize_frame) {
404
144
            MVMint8 spesh_enabled_orig = tc->instance->spesh_enabled;
405
144
            tc->instance->spesh_enabled = 0;
406
144
            MVM_interp_run(tc, toplevel_initial_invoke, cu->body.deserialize_frame);
407
144
            tc->instance->spesh_enabled = spesh_enabled_orig;
408
144
        }
409
144
    });
410
144
411
144
    /* Run the entry-point frame. */
412
144
    MVM_interp_run(tc, toplevel_initial_invoke, cu->body.main_frame);
413
144
}
414
415
/* Loads bytecode from the specified file name and dumps it. */
416
0
void MVM_vm_dump_file(MVMInstance *instance, const char *filename) {
417
0
    /* Map the compilation unit into memory and dissect it. */
418
0
    MVMThreadContext *tc = instance->main_thread;
419
0
    MVMCompUnit      *cu = MVM_cu_map_from_file(tc, filename);
420
0
    char *dump = MVM_bytecode_dump(tc, cu);
421
0
    size_t dumplen = strlen(dump);
422
0
    int position = 0;
423
0
424
0
    /* libuv already set up stdout to be nonblocking, but it can very well be
425
0
     * we encounter EAGAIN (Resource temporarily unavailable), so we need to
426
0
     * loop over our buffer, which can be quite big.
427
0
     *
428
0
     * The CORE.setting.moarvm has - as of writing this - about 32 megs of
429
0
     * output from dumping.
430
0
     */
431
0
    while (position < dumplen) {
432
0
        size_t written = write(1, dump + position, dumplen - position);
433
0
        if (written > 0)
434
0
            position += written;
435
0
    }
436
0
437
0
    MVM_free(dump);
438
0
}
439
440
/* Exits the process as quickly as is gracefully possible, respecting that
441
 * foreground threads should join first. Leaves all cleanup to the OS, as it
442
 * will be able to do it much more swiftly than we could. This is typically
443
 * not the right thing for embedding; see MVM_vm_destroy_instance for that. */
444
143
void MVM_vm_exit(MVMInstance *instance) {
445
143
    /* Join any foreground threads and flush standard handles. */
446
143
    MVM_thread_join_foreground(instance->main_thread);
447
143
    MVM_io_flush_standard_handles(instance->main_thread);
448
143
449
143
    /* Close any spesh or jit log. */
450
143
    if (instance->spesh_log_fh)
451
0
        fclose(instance->spesh_log_fh);
452
143
    if (instance->jit_log_fh)
453
0
        fclose(instance->jit_log_fh);
454
143
    if (instance->jit_bytecode_map)
455
0
        fclose(instance->jit_bytecode_map);
456
143
    if (instance->dynvar_log_fh) {
457
0
        fprintf(instance->dynvar_log_fh, "- x 0 0 0 0 %"PRId64" %"PRIu64" %"PRIu64"\n", instance->dynvar_log_lasttime, uv_hrtime(), uv_hrtime());
458
0
        fclose(instance->dynvar_log_fh);
459
0
    }
460
143
461
143
    /* And, we're done. */
462
143
    exit(0);
463
143
}
464
465
0
static void cleanup_callsite_interns(MVMInstance *instance) {
466
0
    int i;
467
0
468
0
    for (i = 0; i < MVM_INTERN_ARITY_LIMIT; i++) {
469
0
        int callsite_count = instance->callsite_interns->num_by_arity[i];
470
0
        int j;
471
0
472
0
        if (callsite_count) {
473
0
            MVMCallsite **callsites = instance->callsite_interns->by_arity[i];
474
0
475
0
            for (j = 0; j < callsite_count; j++) {
476
0
                MVMCallsite *callsite = callsites[j];
477
0
478
0
                if (MVM_callsite_is_common(callsite)) {
479
0
                    continue;
480
0
                }
481
0
482
0
                MVM_callsite_destroy(callsite);
483
0
            }
484
0
485
0
            MVM_free(callsites);
486
0
        }
487
0
    }
488
0
    MVM_free(instance->callsite_interns);
489
0
}
490
491
/* Destroys a VM instance. This must be called only from the main thread. It
492
 * should clear up all resources and free all memory; in practice, it falls
493
 * short of this goal at the moment. */
494
0
void MVM_vm_destroy_instance(MVMInstance *instance) {
495
0
    /* Join any foreground threads and flush standard handles. */
496
0
    MVM_thread_join_foreground(instance->main_thread);
497
0
    MVM_io_flush_standard_handles(instance->main_thread);
498
0
499
0
    /* Run the GC global destruction phase. After this,
500
0
     * no 6model object pointers should be accessed. */
501
0
    MVM_gc_global_destruction(instance->main_thread);
502
0
503
0
    /* Cleanup REPR registry */
504
0
    uv_mutex_destroy(&instance->mutex_repr_registry);
505
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMReprRegistry, instance->repr_hash);
506
0
    MVM_free(instance->repr_list);
507
0
508
0
    /* Clean up GC related resources. */
509
0
    uv_mutex_destroy(&instance->mutex_permroots);
510
0
    MVM_free(instance->permroots);
511
0
    MVM_free(instance->permroot_descriptions);
512
0
    uv_cond_destroy(&instance->cond_gc_start);
513
0
    uv_cond_destroy(&instance->cond_gc_finish);
514
0
    uv_cond_destroy(&instance->cond_gc_intrays_clearing);
515
0
    uv_cond_destroy(&instance->cond_blocked_can_continue);
516
0
    uv_mutex_destroy(&instance->mutex_gc_orchestrate);
517
0
518
0
    /* Clean up Hash of HLLConfig. */
519
0
    uv_mutex_destroy(&instance->mutex_hllconfigs);
520
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMHLLConfig, instance->compiler_hll_configs);
521
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMHLLConfig, instance->compilee_hll_configs);
522
0
523
0
    /* Clean up Hash of DLLs. */
524
0
    uv_mutex_destroy(&instance->mutex_dll_registry);
525
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMDLLRegistry, instance->dll_registry);
526
0
527
0
    /* Clean up Hash of extensions. */
528
0
    uv_mutex_destroy(&instance->mutex_ext_registry);
529
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMExtRegistry, instance->ext_registry);
530
0
531
0
    /* Clean up Hash of extension ops. */
532
0
    uv_mutex_destroy(&instance->mutex_extop_registry);
533
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMExtOpRegistry, instance->extop_registry);
534
0
535
0
    /* Clean up Hash of all known serialization contexts; all SCs list is in
536
0
     * FSA space and so cleaned up with that. */
537
0
    uv_mutex_destroy(&instance->mutex_sc_registry);
538
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMSerializationContextBody, instance->sc_weakhash);
539
0
540
0
    /* Clean up Hash of filenames of compunits loaded from disk. */
541
0
    uv_mutex_destroy(&instance->mutex_loaded_compunits);
542
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMLoadedCompUnitName, instance->loaded_compunits);
543
0
544
0
    /* Clean up Container registry. */
545
0
    uv_mutex_destroy(&instance->mutex_container_registry);
546
0
    MVM_HASH_DESTROY(instance->main_thread, hash_handle, MVMContainerRegistry, instance->container_registry);
547
0
548
0
    /* Clean up Hash of compiler objects keyed by name. */
549
0
    uv_mutex_destroy(&instance->mutex_compiler_registry);
550
0
551
0
    /* Clean up Hash of hashes of symbol tables per hll. */
552
0
    uv_mutex_destroy(&instance->mutex_hll_syms);
553
0
554
0
    /* Clean up multi cache addition mutex. */
555
0
    uv_mutex_destroy(&instance->mutex_multi_cache_add);
556
0
557
0
    /* Clean up parameterization addition mutex. */
558
0
    uv_mutex_destroy(&instance->mutex_parameterization_add);
559
0
560
0
    /* Clean up interned callsites */
561
0
    uv_mutex_destroy(&instance->mutex_callsite_interns);
562
0
    cleanup_callsite_interns(instance);
563
0
564
0
    /* Release this interpreter's hold on Unicode database */
565
0
    MVM_unicode_release(instance->main_thread);
566
0
567
0
    /* Clean up spesh mutexes and close any log. */
568
0
    uv_mutex_destroy(&instance->mutex_spesh_install);
569
0
    uv_cond_destroy(&instance->cond_spesh_sync);
570
0
    uv_mutex_destroy(&instance->mutex_spesh_sync);
571
0
    if (instance->spesh_log_fh)
572
0
        fclose(instance->spesh_log_fh);
573
0
    if (instance->jit_log_fh)
574
0
        fclose(instance->jit_log_fh);
575
0
    if (instance->dynvar_log_fh)
576
0
        fclose(instance->dynvar_log_fh);
577
0
    if (instance->jit_breakpoints) {
578
0
        MVM_VECTOR_DESTROY(instance->jit_breakpoints);
579
0
    }
580
0
581
0
582
0
    /* Clean up cross-thread-write-logging mutex */
583
0
    uv_mutex_destroy(&instance->mutex_cross_thread_write_logging);
584
0
585
0
    /* Clean up NFG. */
586
0
    uv_mutex_destroy(&instance->nfg->update_mutex);
587
0
    MVM_nfg_destroy(instance->main_thread);
588
0
589
0
    /* Clean up fixed size allocator */
590
0
    MVM_fixed_size_destroy(instance->fsa);
591
0
592
0
    /* Clean up integer constant and string cache. */
593
0
    uv_mutex_destroy(&instance->mutex_int_const_cache);
594
0
    MVM_free(instance->int_const_cache);
595
0
    MVM_free(instance->int_to_str_cache);
596
0
597
0
    /* Clean up event loop starting mutex. */
598
0
    uv_mutex_destroy(&instance->mutex_event_loop_start);
599
0
600
0
    /* Destroy main thread contexts and thread list mutex. */
601
0
    MVM_tc_destroy(instance->main_thread);
602
0
    uv_mutex_destroy(&instance->mutex_threads);
603
0
604
0
    /* Clear up VM instance memory. */
605
0
    MVM_free(instance);
606
0
}
607
608
144
void MVM_vm_set_clargs(MVMInstance *instance, int argc, char **argv) {
609
144
    instance->num_clargs = argc;
610
144
    instance->raw_clargs = argv;
611
144
}
612
613
144
void MVM_vm_set_exec_name(MVMInstance *instance, const char *exec_name) {
614
144
    instance->exec_name = exec_name;
615
144
}
616
617
144
void MVM_vm_set_prog_name(MVMInstance *instance, const char *prog_name) {
618
144
    instance->prog_name = prog_name;
619
144
}
620
621
144
void MVM_vm_set_lib_path(MVMInstance *instance, int count, const char **lib_path) {
622
144
    enum { MAX_COUNT = sizeof instance->lib_path / sizeof *instance->lib_path };
623
144
624
144
    int i = 0;
625
144
626
144
    if (count > MAX_COUNT)
627
0
        MVM_panic(1, "Cannot set more than %i library paths", MAX_COUNT);
628
144
629
144
    for (; i < count; ++i)
630
0
        instance->lib_path[i] = lib_path[i];
631
144
632
144
    /* Clear remainder to allow repeated calls */
633
1.29k
    for (; i < MAX_COUNT; ++i)
634
1.15k
        instance->lib_path[i] = NULL;
635
144
}