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