/home/travis/build/MoarVM/MoarVM/src/core/loadbytecode.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Handles loading of bytecode, including triggering the deserialize and load |
4 | | * special frames. Takes place in two steps, with a callback between them which |
5 | | * is triggered by the special_return mechanism. */ |
6 | | static void run_load(MVMThreadContext *tc, void *sr_data); |
7 | 0 | static void mark_sr_data(MVMThreadContext *tc, MVMFrame *frame, MVMGCWorklist *worklist) { |
8 | 0 | MVM_gc_worklist_add(tc, worklist, &frame->special_return_data); |
9 | 0 | } |
10 | 1.30k | static void run_comp_unit(MVMThreadContext *tc, MVMCompUnit *cu) { |
11 | 1.30k | /* If there's a deserialization frame, need to run that. */ |
12 | 1.30k | if (cu->body.deserialize_frame) { |
13 | 1.30k | /* Set up special return to delegate to running the load frame, |
14 | 1.30k | * if any. */ |
15 | 1.30k | tc->cur_frame->return_value = NULL; |
16 | 1.30k | tc->cur_frame->return_type = MVM_RETURN_VOID; |
17 | 1.30k | tc->cur_frame->special_return = run_load; |
18 | 1.30k | tc->cur_frame->special_return_data = cu; |
19 | 1.30k | tc->cur_frame->mark_special_return_data = mark_sr_data; |
20 | 1.30k | |
21 | 1.30k | /* Invoke the deserialization frame and return to the runloop. */ |
22 | 1.30k | MVM_frame_invoke(tc, cu->body.deserialize_frame, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS), |
23 | 1.30k | NULL, NULL, NULL, -1); |
24 | 1.30k | } |
25 | 0 | else { |
26 | 0 | /* No deserialize frame, so do load frame instead. */ |
27 | 0 | run_load(tc, cu); |
28 | 0 | } |
29 | 1.30k | } |
30 | 0 | void MVM_load_bytecode_buffer(MVMThreadContext *tc, MVMObject *buf) { |
31 | 0 | MVMCompUnit *cu; |
32 | 0 | MVMuint8 *data_start; |
33 | 0 | MVMuint32 data_size; |
34 | 0 |
|
35 | 0 | /* Ensure the source is in the correct form. */ |
36 | 0 | if ( |
37 | 0 | !IS_CONCRETE(buf) |
38 | 0 | || REPR(buf)->ID != MVM_REPR_ID_VMArray |
39 | 0 | || ( |
40 | 0 | ((MVMArrayREPRData *)STABLE(buf)->REPR_data)->slot_type != MVM_ARRAY_U8 |
41 | 0 | && ((MVMArrayREPRData *)STABLE(buf)->REPR_data)->slot_type != MVM_ARRAY_I8 |
42 | 0 | ) |
43 | 0 | ) |
44 | 0 | MVM_exception_throw_adhoc(tc, "loadbytecodebuffer requires a native int8 or uint8 array to read from"); |
45 | 0 |
|
46 | 0 | /* MVMCompUnit expects the data to be non-GC managed as it usually comes straight from a file */ |
47 | 0 | data_size = ((MVMArray *)buf)->body.elems; |
48 | 0 | data_start = MVM_malloc(data_size); |
49 | 0 | memcpy(data_start, (MVMuint8 *)(((MVMArray *)buf)->body.slots.i8 + ((MVMArray *)buf)->body.start), data_size); |
50 | 0 |
|
51 | 0 | cu = MVM_cu_from_bytes(tc, data_start, data_size); |
52 | 0 | run_comp_unit(tc, cu); |
53 | 0 | } |
54 | 4.29k | void MVM_load_bytecode(MVMThreadContext *tc, MVMString *filename) { |
55 | 4.29k | MVMCompUnit *cu; |
56 | 4.29k | MVMLoadedCompUnitName *loaded_name; |
57 | 4.29k | |
58 | 4.29k | /* Work out actual filename to use, taking --libpath into account. */ |
59 | 4.29k | filename = MVM_file_in_libpath(tc, filename); |
60 | 4.29k | |
61 | 4.29k | /* See if we already loaded this. */ |
62 | 4.29k | uv_mutex_lock(&tc->instance->mutex_loaded_compunits); |
63 | 4.29k | MVM_tc_set_ex_release_mutex(tc, &tc->instance->mutex_loaded_compunits); |
64 | 4.29k | MVM_HASH_GET(tc, tc->instance->loaded_compunits, filename, loaded_name); |
65 | 4.29k | if (loaded_name) { |
66 | 2.99k | /* already loaded */ |
67 | 2.99k | goto LEAVE; |
68 | 2.99k | } |
69 | 4.29k | |
70 | 4.29k | /* Otherwise, load from disk. */ |
71 | 1.30k | MVMROOT(tc, filename, { |
72 | 1.30k | char *c_filename = MVM_string_utf8_c8_encode_C_string(tc, filename); |
73 | 1.30k | /* XXX any exception from MVM_cu_map_from_file needs to be handled |
74 | 1.30k | * and c_filename needs to be freed */ |
75 | 1.30k | cu = MVM_cu_map_from_file(tc, c_filename); |
76 | 1.30k | MVM_free(c_filename); |
77 | 1.30k | cu->body.filename = filename; |
78 | 1.30k | |
79 | 1.30k | run_comp_unit(tc, cu); |
80 | 1.30k | |
81 | 1.30k | loaded_name = MVM_calloc(1, sizeof(MVMLoadedCompUnitName)); |
82 | 1.30k | loaded_name->filename = filename; |
83 | 1.30k | MVM_HASH_BIND(tc, tc->instance->loaded_compunits, filename, loaded_name); |
84 | 1.30k | }); |
85 | 1.30k | |
86 | 4.29k | LEAVE: |
87 | 4.29k | MVM_tc_clear_ex_release_mutex(tc); |
88 | 4.29k | uv_mutex_unlock(&tc->instance->mutex_loaded_compunits); |
89 | 4.29k | } |
90 | 0 | void MVM_load_bytecode_fh(MVMThreadContext *tc, MVMObject *oshandle, MVMString *filename) { |
91 | 0 | MVMCompUnit *cu; |
92 | 0 |
|
93 | 0 | if (REPR(oshandle)->ID != MVM_REPR_ID_MVMOSHandle) |
94 | 0 | MVM_exception_throw_adhoc(tc, "loadbytecodefh requires an object with REPR MVMOSHandle"); |
95 | 0 |
|
96 | 0 | MVMROOT(tc, filename, { |
97 | 0 | MVMuint64 pos = MVM_io_tell(tc, oshandle); |
98 | 0 | cu = MVM_cu_map_from_file_handle(tc, MVM_io_fileno(tc, oshandle), pos); |
99 | 0 | cu->body.filename = filename; |
100 | 0 |
|
101 | 0 | run_comp_unit(tc, cu); |
102 | 0 | }); |
103 | 0 | } |
104 | | |
105 | | /* Callback after running deserialize code to run the load code. */ |
106 | 1.30k | static void run_load(MVMThreadContext *tc, void *sr_data) { |
107 | 1.30k | MVMCompUnit *cu = (MVMCompUnit *)sr_data; |
108 | 1.30k | |
109 | 1.30k | /* If there's a load frame, need to run that. If not, we're done. */ |
110 | 1.30k | if (cu->body.load_frame) { |
111 | 1.30k | /* Make sure the call happens in void context. No special return |
112 | 1.30k | * handler here; we want to go back to the place that used the |
113 | 1.30k | * loadbytecode op in the first place. */ |
114 | 1.30k | tc->cur_frame->return_value = NULL; |
115 | 1.30k | tc->cur_frame->return_type = MVM_RETURN_VOID; |
116 | 1.30k | |
117 | 1.30k | /* Invoke the load frame and return to the runloop. */ |
118 | 1.30k | MVM_frame_invoke(tc, cu->body.load_frame, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS), |
119 | 1.30k | NULL, NULL, NULL, -1); |
120 | 1.30k | } |
121 | 1.30k | } |