/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 | } |