/home/travis/build/MoarVM/MoarVM/src/core/ext.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | 0 | int MVM_ext_load(MVMThreadContext *tc, MVMString *lib, MVMString *ext) { |
4 | 0 | MVMString *colon, *prefix, *name; |
5 | 0 | MVMExtRegistry *entry; |
6 | 0 | MVMDLLSym *sym; |
7 | 0 | void (*init)(MVMThreadContext *); |
8 | 0 |
|
9 | 0 | MVMROOT2(tc, lib, ext, { |
10 | 0 | colon = MVM_string_ascii_decode_nt( |
11 | 0 | tc, tc->instance->VMString, ":"); |
12 | 0 | prefix = MVM_string_concatenate(tc, lib, colon); |
13 | 0 | name = MVM_string_concatenate(tc, prefix, ext); |
14 | 0 | }); |
15 | 0 |
|
16 | 0 | uv_mutex_lock(&tc->instance->mutex_ext_registry); |
17 | 0 |
|
18 | 0 | MVM_HASH_GET(tc, tc->instance->ext_registry, name, entry); |
19 | 0 |
|
20 | 0 | /* Extension already loaded. */ |
21 | 0 | if (entry) { |
22 | 0 | uv_mutex_unlock(&tc->instance->mutex_ext_registry); |
23 | 0 | return 0; |
24 | 0 | } |
25 | 0 |
|
26 | 0 | MVMROOT(tc, name, { |
27 | 0 | sym = (MVMDLLSym *)MVM_dll_find_symbol(tc, lib, ext); |
28 | 0 | }); |
29 | 0 | if (!sym) { |
30 | 0 | uv_mutex_unlock(&tc->instance->mutex_ext_registry); |
31 | 0 | MVM_exception_throw_adhoc(tc, "extension symbol not found"); |
32 | 0 | } |
33 | 0 |
|
34 | 0 | entry = MVM_malloc(sizeof *entry); |
35 | 0 | entry->sym = sym; |
36 | 0 | entry->name = name; |
37 | 0 |
|
38 | 0 | MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->name, |
39 | 0 | "Extension name"); |
40 | 0 | MVM_HASH_BIND(tc, tc->instance->ext_registry, name, entry); |
41 | 0 | MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->hash_handle.key, |
42 | 0 | "Extension name hash key"); |
43 | 0 |
|
44 | 0 | uv_mutex_unlock(&tc->instance->mutex_ext_registry); |
45 | 0 |
|
46 | 0 | /* Call extension's initializer */ |
47 | 0 | init = (void (*)(MVMThreadContext *))sym->body.address; |
48 | 0 | init(tc); |
49 | 0 |
|
50 | 0 | return 1; |
51 | 0 | } |
52 | | |
53 | | int MVM_ext_register_extop(MVMThreadContext *tc, const char *cname, |
54 | | MVMExtOpFunc func, MVMuint8 num_operands, MVMuint8 operands[], |
55 | 0 | MVMExtOpSpesh *spesh, MVMExtOpFactDiscover *discover, MVMuint32 flags) { |
56 | 0 | MVMExtOpRegistry *entry; |
57 | 0 | MVMString *name = MVM_string_ascii_decode_nt( |
58 | 0 | tc, tc->instance->VMString, cname); |
59 | 0 |
|
60 | 0 | uv_mutex_lock(&tc->instance->mutex_extop_registry); |
61 | 0 |
|
62 | 0 | MVM_HASH_GET(tc, tc->instance->extop_registry, name, entry); |
63 | 0 |
|
64 | 0 | /* Op already registered, so just verify its signature. */ |
65 | 0 | if (entry) { |
66 | 0 | uv_mutex_unlock(&tc->instance->mutex_extop_registry); |
67 | 0 | if (num_operands != entry->info.num_operands |
68 | 0 | || memcmp(operands, entry->info.operands, num_operands) != 0) |
69 | 0 | MVM_exception_throw_adhoc(tc, |
70 | 0 | "signature mismatch when re-registering extension op %s", |
71 | 0 | cname); |
72 | 0 | return 0; |
73 | 0 | } |
74 | 0 |
|
75 | 0 | /* Sanity-check signature. */ |
76 | 0 | if (num_operands > MVM_MAX_OPERANDS) { |
77 | 0 | uv_mutex_unlock(&tc->instance->mutex_extop_registry); |
78 | 0 | MVM_exception_throw_adhoc(tc, |
79 | 0 | "cannot register extension op with more than %u operands", |
80 | 0 | MVM_MAX_OPERANDS); |
81 | 0 | } |
82 | 0 | { |
83 | 0 | MVMuint8 i = 0; |
84 | 0 |
|
85 | 0 | for(; i < num_operands; i++) { |
86 | 0 | MVMuint8 flags = operands[i]; |
87 | 0 |
|
88 | 0 | switch (flags & MVM_operand_rw_mask) { |
89 | 0 | case MVM_operand_literal: |
90 | 0 | goto check_literal; |
91 | 0 |
|
92 | 0 | case MVM_operand_read_reg: |
93 | 0 | case MVM_operand_write_reg: |
94 | 0 | case MVM_operand_read_lex: |
95 | 0 | case MVM_operand_write_lex: |
96 | 0 | goto check_reg; |
97 | 0 |
|
98 | 0 | default: |
99 | 0 | goto fail; |
100 | 0 | } |
101 | 0 |
|
102 | 0 | check_literal: |
103 | 0 | switch (flags & MVM_operand_type_mask) { |
104 | 0 | case MVM_operand_int8: |
105 | 0 | case MVM_operand_int16: |
106 | 0 | case MVM_operand_int32: |
107 | 0 | case MVM_operand_int64: |
108 | 0 | case MVM_operand_num32: |
109 | 0 | case MVM_operand_num64: |
110 | 0 | case MVM_operand_str: |
111 | 0 | case MVM_operand_coderef: |
112 | 0 | continue; |
113 | 0 |
|
114 | 0 | case MVM_operand_ins: |
115 | 0 | case MVM_operand_callsite: |
116 | 0 | default: |
117 | 0 | goto fail; |
118 | 0 | } |
119 | 0 |
|
120 | 0 | check_reg: |
121 | 0 | switch (flags & MVM_operand_type_mask) { |
122 | 0 | case MVM_operand_int8: |
123 | 0 | case MVM_operand_int16: |
124 | 0 | case MVM_operand_int32: |
125 | 0 | case MVM_operand_int64: |
126 | 0 | case MVM_operand_num32: |
127 | 0 | case MVM_operand_num64: |
128 | 0 | case MVM_operand_str: |
129 | 0 | case MVM_operand_obj: |
130 | 0 | case MVM_operand_type_var: |
131 | 0 | case MVM_operand_uint8: |
132 | 0 | case MVM_operand_uint16: |
133 | 0 | case MVM_operand_uint32: |
134 | 0 | case MVM_operand_uint64: |
135 | 0 | continue; |
136 | 0 |
|
137 | 0 | default: |
138 | 0 | goto fail; |
139 | 0 | } |
140 | 0 |
|
141 | 0 | fail: |
142 | 0 | uv_mutex_unlock(&tc->instance->mutex_extop_registry); |
143 | 0 | MVM_exception_throw_adhoc(tc, |
144 | 0 | "extension op %s has illegal signature", cname); |
145 | 0 | } |
146 | 0 | } |
147 | 0 |
|
148 | 0 | entry = MVM_malloc(sizeof *entry); |
149 | 0 | entry->name = name; |
150 | 0 | entry->func = func; |
151 | 0 | entry->info.name = cname; |
152 | 0 | entry->info.opcode = (MVMuint16)-1; |
153 | 0 | entry->info.mark[0] = '.'; |
154 | 0 | entry->info.mark[1] = 'x'; |
155 | 0 | entry->info.num_operands = num_operands; |
156 | 0 | entry->info.pure = flags & MVM_EXTOP_PURE; |
157 | 0 | entry->info.deopt_point = 0; |
158 | 0 | entry->info.logged = 0; |
159 | 0 | entry->info.no_inline = flags & MVM_EXTOP_NOINLINE; |
160 | 0 | entry->info.jittivity = (flags & MVM_EXTOP_INVOKISH) ? MVM_JIT_INFO_INVOKISH : 0; |
161 | 0 | entry->info.uses_hll = 0; |
162 | 0 | memcpy(entry->info.operands, operands, num_operands); |
163 | 0 | memset(entry->info.operands + num_operands, 0, |
164 | 0 | MVM_MAX_OPERANDS - num_operands); |
165 | 0 | entry->spesh = spesh; |
166 | 0 | entry->discover = discover; |
167 | 0 | entry->no_jit = flags & MVM_EXTOP_NO_JIT; |
168 | 0 | entry->allocating = flags & MVM_EXTOP_ALLOCATING; |
169 | 0 |
|
170 | 0 | MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->name, |
171 | 0 | "Extension op name"); |
172 | 0 | MVM_HASH_BIND(tc, tc->instance->extop_registry, name, entry); |
173 | 0 | MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&entry->hash_handle.key, |
174 | 0 | "Extension op name hash key"); |
175 | 0 |
|
176 | 0 | uv_mutex_unlock(&tc->instance->mutex_extop_registry); |
177 | 0 |
|
178 | 0 | return 1; |
179 | 0 | } |
180 | | |
181 | | const MVMOpInfo * MVM_ext_resolve_extop_record(MVMThreadContext *tc, |
182 | 0 | MVMExtOpRecord *record) { |
183 | 0 | MVMExtOpRegistry *entry; |
184 | 0 |
|
185 | 0 | /* Already resolved. */ |
186 | 0 | if (record->info) |
187 | 0 | return record->info; |
188 | 0 |
|
189 | 0 | uv_mutex_lock(&tc->instance->mutex_extop_registry); |
190 | 0 |
|
191 | 0 | MVM_HASH_GET(tc, tc->instance->extop_registry, record->name, entry); |
192 | 0 |
|
193 | 0 | if (!entry) { |
194 | 0 | uv_mutex_unlock(&tc->instance->mutex_extop_registry); |
195 | 0 | return NULL; |
196 | 0 | } |
197 | 0 |
|
198 | 0 | /* Resolve record. */ |
199 | 0 | record->info = &entry->info; |
200 | 0 | record->func = entry->func; |
201 | 0 | record->spesh = entry->spesh; |
202 | 0 | record->discover = entry->discover; |
203 | 0 | record->no_jit = entry->no_jit; |
204 | 0 | record->allocating = entry->allocating; |
205 | 0 |
|
206 | 0 | uv_mutex_unlock(&tc->instance->mutex_extop_registry); |
207 | 0 |
|
208 | 0 | return record->info; |
209 | 0 | } |