Coverage Report

Created: 2017-04-15 07:07

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