/home/travis/build/MoarVM/MoarVM/src/6model/reprs/NativeRef.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* This representation's function pointer table. */ |
4 | | static const MVMREPROps NativeRef_this_repr; |
5 | | |
6 | | /* Creates a new type object of this representation, and associates it with |
7 | | * the given HOW. */ |
8 | 19 | static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) { |
9 | 19 | MVMSTable *st = MVM_gc_allocate_stable(tc, &NativeRef_this_repr, HOW); |
10 | 19 | |
11 | 19 | MVMROOT(tc, st, { |
12 | 19 | MVMObject *obj = MVM_gc_allocate_type_object(tc, st); |
13 | 19 | MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj); |
14 | 19 | st->size = sizeof(MVMNativeRef); |
15 | 19 | }); |
16 | 19 | |
17 | 19 | return st->WHAT; |
18 | 19 | } |
19 | | |
20 | | /* Copies the body of one object to another. */ |
21 | 0 | static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) { |
22 | 0 | MVM_exception_throw_adhoc(tc, "Cannot copy object with repr MVMNativeRef"); |
23 | 0 | } |
24 | | |
25 | | /* Set the size of objects on the STable. */ |
26 | 0 | static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) { |
27 | 0 | st->size = sizeof(MVMNativeRef); |
28 | 0 | } |
29 | | |
30 | | /* Serializes the REPR data. */ |
31 | 0 | static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) { |
32 | 0 | MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)st->REPR_data; |
33 | 0 | if (repr_data) { |
34 | 0 | MVM_serialization_write_int(tc, writer, repr_data->primitive_type); |
35 | 0 | MVM_serialization_write_int(tc, writer, repr_data->ref_kind); |
36 | 0 | } |
37 | 0 | else { |
38 | 0 | MVM_serialization_write_int(tc, writer, 0); |
39 | 0 | MVM_serialization_write_int(tc, writer, 0); |
40 | 0 | } |
41 | 0 | } |
42 | | |
43 | | /* Deserializes REPR data. */ |
44 | 0 | static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) { |
45 | 0 | MVMNativeRefREPRData *repr_data = MVM_malloc(sizeof(MVMNativeRefREPRData)); |
46 | 0 | repr_data->primitive_type = MVM_serialization_read_int(tc, reader); |
47 | 0 | repr_data->ref_kind = MVM_serialization_read_int(tc, reader); |
48 | 0 | st->REPR_data = repr_data; |
49 | 0 | } |
50 | | |
51 | | /* Called by the VM to mark any GCable items. */ |
52 | 0 | static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) { |
53 | 0 | MVMNativeRefBody *ref = (MVMNativeRefBody *)data; |
54 | 0 | MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)st->REPR_data; |
55 | 0 | switch (repr_data->ref_kind) { |
56 | 0 | case MVM_NATIVEREF_LEX: |
57 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.lex.frame); |
58 | 0 | break; |
59 | 0 | case MVM_NATIVEREF_ATTRIBUTE: |
60 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.attribute.obj); |
61 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.attribute.class_handle); |
62 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.attribute.name); |
63 | 0 | break; |
64 | 0 | case MVM_NATIVEREF_POSITIONAL: |
65 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.positional.obj); |
66 | 0 | break; |
67 | 0 | case MVM_NATIVEREF_MULTIDIM: |
68 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.multidim.obj); |
69 | 0 | MVM_gc_worklist_add(tc, worklist, &ref->u.multidim.indices); |
70 | 0 | break; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | /* Frees the representation data, if any. */ |
75 | 0 | static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) { |
76 | 0 | MVM_free(st->REPR_data); |
77 | 0 | } |
78 | | |
79 | | /* Gets the storage specification for this representation. */ |
80 | | static const MVMStorageSpec storage_spec = { |
81 | | MVM_STORAGE_SPEC_REFERENCE, /* inlineable */ |
82 | | 0, /* bits */ |
83 | | 0, /* align */ |
84 | | MVM_STORAGE_SPEC_BP_NONE, /* boxed_primitive */ |
85 | | 0, /* can_box */ |
86 | | 0, /* is_unsigned */ |
87 | | }; |
88 | 0 | static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) { |
89 | 0 | return &storage_spec; |
90 | 0 | } |
91 | | |
92 | | /* Compose the representation. */ |
93 | 19 | static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { |
94 | 19 | MVMStringConsts *str_consts = &(tc->instance->str_consts); |
95 | 19 | MVMObject *info = MVM_repr_at_key_o(tc, info_hash, str_consts->nativeref); |
96 | 19 | if (IS_CONCRETE(info)) { |
97 | 19 | MVMObject *type = MVM_repr_at_key_o(tc, info, str_consts->type); |
98 | 19 | MVMuint16 prim = REPR(type)->get_storage_spec(tc, STABLE(type))->boxed_primitive; |
99 | 19 | if (prim != MVM_STORAGE_SPEC_BP_NONE) { |
100 | 19 | MVMObject *refkind = MVM_repr_at_key_o(tc, info, str_consts->refkind); |
101 | 19 | if (IS_CONCRETE(refkind)) { |
102 | 19 | MVMNativeRefREPRData *repr_data; |
103 | 19 | MVMuint16 kind; |
104 | 19 | MVMString *refkind_s = MVM_repr_get_str(tc, refkind); |
105 | 19 | if (MVM_string_equal(tc, refkind_s, str_consts->lexical)) { |
106 | 7 | kind = MVM_NATIVEREF_LEX; |
107 | 7 | } |
108 | 12 | else if (MVM_string_equal(tc, refkind_s, str_consts->attribute)) { |
109 | 6 | kind = MVM_NATIVEREF_ATTRIBUTE; |
110 | 6 | } |
111 | 6 | else if (MVM_string_equal(tc, refkind_s, str_consts->positional)) { |
112 | 3 | kind = MVM_NATIVEREF_POSITIONAL; |
113 | 3 | } |
114 | 3 | else if (MVM_string_equal(tc, refkind_s, str_consts->multidim)) { |
115 | 3 | kind = MVM_NATIVEREF_MULTIDIM; |
116 | 3 | } |
117 | 0 | else { |
118 | 0 | MVM_exception_throw_adhoc(tc, "NativeRef: invalid refkind in compose"); |
119 | 0 | } |
120 | 19 | |
121 | 19 | repr_data = MVM_malloc(sizeof(MVMNativeRefREPRData)); |
122 | 19 | repr_data->primitive_type = prim; |
123 | 19 | repr_data->ref_kind = kind; |
124 | 19 | st->REPR_data = repr_data; |
125 | 19 | } |
126 | 0 | else { |
127 | 0 | MVM_exception_throw_adhoc(tc, "NativeRef: missing refkind in compose"); |
128 | 0 | } |
129 | 19 | } |
130 | 0 | else { |
131 | 0 | MVM_exception_throw_adhoc(tc, "NativeRef: non-native type supplied in compose"); |
132 | 0 | } |
133 | 19 | } |
134 | 0 | else { |
135 | 0 | MVM_exception_throw_adhoc(tc, "NativeRef: missing nativeref protocol in compose"); |
136 | 0 | } |
137 | 19 | } |
138 | | |
139 | | /* Initializes the representation. */ |
140 | 144 | const MVMREPROps * MVMNativeRef_initialize(MVMThreadContext *tc) { |
141 | 144 | return &NativeRef_this_repr; |
142 | 144 | } |
143 | | |
144 | 0 | static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) { |
145 | 0 | MVMNativeRefREPRData * repr_data = (MVMNativeRefREPRData *)st->REPR_data; |
146 | 0 | MVMuint16 opcode = ins->info->opcode; |
147 | 0 |
|
148 | 0 | if (!repr_data) |
149 | 0 | return; |
150 | 0 | /* TODO re-implement spesh for this; lost due to native ref refactors */ |
151 | 0 | } |
152 | | |
153 | | static const MVMREPROps NativeRef_this_repr = { |
154 | | type_object_for, |
155 | | MVM_gc_allocate_object, |
156 | | NULL, /* initialize */ |
157 | | copy_to, |
158 | | MVM_REPR_DEFAULT_ATTR_FUNCS, |
159 | | MVM_REPR_DEFAULT_BOX_FUNCS, |
160 | | MVM_REPR_DEFAULT_POS_FUNCS, |
161 | | MVM_REPR_DEFAULT_ASS_FUNCS, |
162 | | MVM_REPR_DEFAULT_ELEMS, |
163 | | get_storage_spec, |
164 | | NULL, /* change_type */ |
165 | | NULL, /* serialize */ |
166 | | NULL, /* deserialize */ |
167 | | serialize_repr_data, |
168 | | deserialize_repr_data, |
169 | | deserialize_stable_size, |
170 | | gc_mark, |
171 | | NULL, /* gc_free */ |
172 | | NULL, /* gc_cleanup */ |
173 | | NULL, /* gc_mark_repr_data */ |
174 | | gc_free_repr_data, |
175 | | compose, |
176 | | spesh, /* spesh */ |
177 | | "NativeRef", /* name */ |
178 | | MVM_REPR_ID_NativeRef, |
179 | | NULL, /* unmanaged_size */ |
180 | | NULL, /* describe_refs */ |
181 | | }; |
182 | | |
183 | | /* Validates the given type is a native reference of the required primitive |
184 | | * type and reference kind. */ |
185 | 19 | void MVM_nativeref_ensure(MVMThreadContext *tc, MVMObject *type, MVMuint16 wantprim, MVMuint16 wantkind, char *guilty) { |
186 | 19 | if (REPR(type)->ID == MVM_REPR_ID_NativeRef) { |
187 | 19 | MVMNativeRefREPRData *repr_data = (MVMNativeRefREPRData *)STABLE(type)->REPR_data; |
188 | 19 | if (!repr_data) |
189 | 0 | MVM_exception_throw_adhoc(tc, "%s set to NativeRef that is not yet composed", guilty); |
190 | 19 | if (repr_data->primitive_type != wantprim) |
191 | 0 | MVM_exception_throw_adhoc(tc, "%s set to NativeRef of wrong primitive type", guilty); |
192 | 19 | if (repr_data->ref_kind != wantkind) |
193 | 0 | MVM_exception_throw_adhoc(tc, "%s set to NativeRef of wrong reference kind", guilty); |
194 | 19 | } |
195 | 0 | else { |
196 | 0 | MVM_exception_throw_adhoc(tc, "%s requires a type with REPR NativeRef", guilty); |
197 | 0 | } |
198 | 19 | } |
199 | | |
200 | | /* Creation of native references for lexicals. */ |
201 | | static MVMObject * lex_ref(MVMThreadContext *tc, MVMObject *type, MVMFrame *f, |
202 | 15 | MVMuint16 env_idx, MVMuint16 reg_type) { |
203 | 15 | MVMNativeRef *ref; |
204 | 15 | MVMROOT(tc, f, { |
205 | 15 | ref = (MVMNativeRef *)MVM_gc_allocate_object(tc, STABLE(type)); |
206 | 15 | }); |
207 | 15 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.lex.frame, f); |
208 | 15 | ref->body.u.lex.env_idx = env_idx; |
209 | 15 | ref->body.u.lex.type = reg_type; |
210 | 15 | return (MVMObject *)ref; |
211 | 15 | } |
212 | | |
213 | | /* Creation of native references for lexicals. */ |
214 | 15 | static MVMFrame * get_lexical_outer(MVMThreadContext *tc, MVMuint16 outers) { |
215 | 15 | MVMFrame *f = tc->cur_frame; |
216 | 15 | while (outers) { |
217 | 0 | if (!f) |
218 | 0 | MVM_exception_throw_adhoc(tc, "getlexref_*: outer index out of range"); |
219 | 0 | f = f->outer; |
220 | 0 | outers--; |
221 | 0 | } |
222 | 15 | return f; |
223 | 15 | } |
224 | 5 | MVMObject * MVM_nativeref_lex_i(MVMThreadContext *tc, MVMuint16 outers, MVMuint16 idx) { |
225 | 5 | MVMObject *ref_type; |
226 | 5 | MVM_frame_force_to_heap(tc, tc->cur_frame); |
227 | 5 | ref_type = MVM_hll_current(tc)->int_lex_ref; |
228 | 5 | if (ref_type) { |
229 | 5 | MVMFrame *f = get_lexical_outer(tc, outers); |
230 | 0 | MVMuint16 *lexical_types = f->spesh_cand && f->spesh_cand->lexical_types |
231 | 0 | ? f->spesh_cand->lexical_types |
232 | 5 | : f->static_info->body.lexical_types; |
233 | 5 | MVMuint16 type = lexical_types[idx]; |
234 | 5 | if (type != MVM_reg_int64 && type != MVM_reg_int32 && |
235 | 0 | type != MVM_reg_int16 && type != MVM_reg_int8 && |
236 | 0 | type != MVM_reg_uint64 && type != MVM_reg_uint32 && |
237 | 0 | type != MVM_reg_uint16 && type != MVM_reg_uint8) |
238 | 0 | MVM_exception_throw_adhoc(tc, "getlexref_i: lexical is not an int"); |
239 | 5 | return lex_ref(tc, ref_type, f, idx, type); |
240 | 5 | } |
241 | 0 | MVM_exception_throw_adhoc(tc, "No int lexical reference type registered for current HLL"); |
242 | 0 | } |
243 | 5 | MVMObject * MVM_nativeref_lex_n(MVMThreadContext *tc, MVMuint16 outers, MVMuint16 idx) { |
244 | 5 | MVMObject *ref_type; |
245 | 5 | MVM_frame_force_to_heap(tc, tc->cur_frame); |
246 | 5 | ref_type = MVM_hll_current(tc)->num_lex_ref; |
247 | 5 | if (ref_type) { |
248 | 5 | MVMFrame *f = get_lexical_outer(tc, outers); |
249 | 0 | MVMuint16 *lexical_types = f->spesh_cand && f->spesh_cand->lexical_types |
250 | 0 | ? f->spesh_cand->lexical_types |
251 | 5 | : f->static_info->body.lexical_types; |
252 | 5 | MVMuint16 type = lexical_types[idx]; |
253 | 5 | if (type != MVM_reg_num64 && type != MVM_reg_num32) |
254 | 0 | MVM_exception_throw_adhoc(tc, "getlexref_n: lexical is not a num"); |
255 | 5 | return lex_ref(tc, ref_type, f, idx, type); |
256 | 5 | } |
257 | 0 | MVM_exception_throw_adhoc(tc, "No num lexical reference type registered for current HLL"); |
258 | 0 | } |
259 | 5 | MVMObject * MVM_nativeref_lex_s(MVMThreadContext *tc, MVMuint16 outers, MVMuint16 idx) { |
260 | 5 | MVMObject *ref_type; |
261 | 5 | MVM_frame_force_to_heap(tc, tc->cur_frame); |
262 | 5 | ref_type = MVM_hll_current(tc)->str_lex_ref; |
263 | 5 | if (ref_type) { |
264 | 5 | MVMFrame *f = get_lexical_outer(tc, outers); |
265 | 0 | MVMuint16 *lexical_types = f->spesh_cand && f->spesh_cand->lexical_types |
266 | 0 | ? f->spesh_cand->lexical_types |
267 | 5 | : f->static_info->body.lexical_types; |
268 | 5 | if (lexical_types[idx] != MVM_reg_str) |
269 | 0 | MVM_exception_throw_adhoc(tc, "getlexref_s: lexical is not a str (%d, %d)", outers, idx); |
270 | 5 | return lex_ref(tc, ref_type, f, idx, MVM_reg_str); |
271 | 5 | } |
272 | 0 | MVM_exception_throw_adhoc(tc, "No str lexical reference type registered for current HLL"); |
273 | 0 | } |
274 | 0 | #define LEXREF_ANY_INT -1 |
275 | 0 | static MVMObject * lexref_by_name(MVMThreadContext *tc, MVMObject *type, MVMString *name, MVMint16 kind) { |
276 | 0 | MVMFrame *cur_frame = tc->cur_frame; |
277 | 0 | while (cur_frame != NULL) { |
278 | 0 | MVMLexicalRegistry *lexical_names = cur_frame->static_info->body.lexical_names; |
279 | 0 | if (lexical_names) { |
280 | 0 | MVMLexicalRegistry *entry; |
281 | 0 | MVM_HASH_GET(tc, lexical_names, name, entry) |
282 | 0 | if (entry) { |
283 | 0 | MVMint16 lex_kind = cur_frame->static_info->body.lexical_types[entry->value]; |
284 | 0 | if (lex_kind == kind) { |
285 | 0 | return lex_ref(tc, type, cur_frame, entry->value, kind); |
286 | 0 | } |
287 | 0 | /* If kind == LEXREF_ANY_INT we will allow any of the native int |
288 | 0 | * types so we don't need functions for every single type. */ |
289 | 0 | else if (kind == LEXREF_ANY_INT) { |
290 | 0 | switch (lex_kind) { |
291 | 0 | case MVM_reg_int8: |
292 | 0 | case MVM_reg_int16: |
293 | 0 | case MVM_reg_int32: |
294 | 0 | case MVM_reg_int64: |
295 | 0 | case MVM_reg_uint8: |
296 | 0 | case MVM_reg_uint16: |
297 | 0 | case MVM_reg_uint32: |
298 | 0 | case MVM_reg_uint64: |
299 | 0 | return lex_ref(tc, type, cur_frame, entry->value, lex_kind); |
300 | 0 | } |
301 | 0 | } |
302 | 0 | { |
303 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
304 | 0 | char *waste[] = { c_name, NULL }; |
305 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
306 | 0 | "Lexical with name '%s' has wrong type. real type %i wanted type %i", |
307 | 0 | c_name, cur_frame->static_info->body.lexical_types[entry->value], kind); |
308 | 0 | } |
309 | 0 | } |
310 | 0 | } |
311 | 0 | cur_frame = cur_frame->outer; |
312 | 0 | } |
313 | 0 | { |
314 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
315 | 0 | char *waste[] = { c_name, NULL }; |
316 | 0 | MVM_exception_throw_adhoc_free(tc, waste, "No lexical found with name '%s'", |
317 | 0 | c_name); |
318 | 0 | } |
319 | 0 | } |
320 | 0 | MVMObject * MVM_nativeref_lex_name_i(MVMThreadContext *tc, MVMString *name) { |
321 | 0 | MVMObject *ref_type; |
322 | 0 | MVMROOT(tc, name, { |
323 | 0 | MVM_frame_force_to_heap(tc, tc->cur_frame); |
324 | 0 | }); |
325 | 0 | ref_type = MVM_hll_current(tc)->int_lex_ref; |
326 | 0 | if (ref_type) |
327 | 0 | /* LEXREF_ANY_INT will allow int8..int64 as well as uint8..uint64 */ |
328 | 0 | return lexref_by_name(tc, ref_type, name, LEXREF_ANY_INT); |
329 | 0 | MVM_exception_throw_adhoc(tc, "No int lexical reference type registered for current HLL"); |
330 | 0 | } |
331 | 0 | MVMObject * MVM_nativeref_lex_name_n(MVMThreadContext *tc, MVMString *name) { |
332 | 0 | MVMObject *ref_type; |
333 | 0 | MVMROOT(tc, name, { |
334 | 0 | MVM_frame_force_to_heap(tc, tc->cur_frame); |
335 | 0 | }); |
336 | 0 | ref_type = MVM_hll_current(tc)->num_lex_ref; |
337 | 0 | if (ref_type) |
338 | 0 | return lexref_by_name(tc, ref_type, name, MVM_reg_num64); |
339 | 0 | MVM_exception_throw_adhoc(tc, "No num lexical reference type registered for current HLL"); |
340 | 0 | } |
341 | 0 | MVMObject * MVM_nativeref_lex_name_s(MVMThreadContext *tc, MVMString *name) { |
342 | 0 | MVMObject *ref_type; |
343 | 0 | MVMROOT(tc, name, { |
344 | 0 | MVM_frame_force_to_heap(tc, tc->cur_frame); |
345 | 0 | }); |
346 | 0 | ref_type = MVM_hll_current(tc)->str_lex_ref; |
347 | 0 | if (ref_type) |
348 | 0 | return lexref_by_name(tc, ref_type, name, MVM_reg_str); |
349 | 0 | MVM_exception_throw_adhoc(tc, "No str lexical reference type registered for current HLL"); |
350 | 0 | } |
351 | | |
352 | | /* Creation of native references for attributes. */ |
353 | 7 | static MVMObject * attrref(MVMThreadContext *tc, MVMObject *type, MVMObject *obj, MVMObject *class_handle, MVMString *name) { |
354 | 7 | MVMNativeRef *ref; |
355 | 7 | MVMROOT3(tc, obj, class_handle, name, { |
356 | 7 | ref = (MVMNativeRef *)MVM_gc_allocate_object(tc, STABLE(type)); |
357 | 7 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.attribute.obj, obj); |
358 | 7 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.attribute.class_handle, class_handle); |
359 | 7 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.attribute.name, name); |
360 | 7 | }); |
361 | 7 | return (MVMObject *)ref; |
362 | 7 | } |
363 | 3 | MVMObject * MVM_nativeref_attr_i(MVMThreadContext *tc, MVMObject *obj, MVMObject *class_handle, MVMString *name) { |
364 | 3 | MVMObject *ref_type = MVM_hll_current(tc)->int_attr_ref; |
365 | 3 | if (ref_type) |
366 | 3 | return attrref(tc, ref_type, obj, class_handle, name); |
367 | 0 | MVM_exception_throw_adhoc(tc, "No int attribute reference type registered for current HLL"); |
368 | 0 | } |
369 | 2 | MVMObject * MVM_nativeref_attr_n(MVMThreadContext *tc, MVMObject *obj, MVMObject *class_handle, MVMString *name) { |
370 | 2 | MVMObject *ref_type = MVM_hll_current(tc)->num_attr_ref; |
371 | 2 | if (ref_type) |
372 | 2 | return attrref(tc, ref_type, obj, class_handle, name); |
373 | 0 | MVM_exception_throw_adhoc(tc, "No num attribute reference type registered for current HLL"); |
374 | 0 | } |
375 | 2 | MVMObject * MVM_nativeref_attr_s(MVMThreadContext *tc, MVMObject *obj, MVMObject *class_handle, MVMString *name) { |
376 | 2 | MVMObject *ref_type = MVM_hll_current(tc)->str_attr_ref; |
377 | 2 | if (ref_type) |
378 | 2 | return attrref(tc, ref_type, obj, class_handle, name); |
379 | 0 | MVM_exception_throw_adhoc(tc, "No str attribute reference type registered for current HLL"); |
380 | 0 | } |
381 | | |
382 | | /* Creation of native references for positionals. */ |
383 | 3 | static MVMObject * posref(MVMThreadContext *tc, MVMObject *type, MVMObject *obj, MVMint64 idx) { |
384 | 3 | MVMNativeRef *ref; |
385 | 3 | MVMROOT(tc, obj, { |
386 | 3 | ref = (MVMNativeRef *)MVM_gc_allocate_object(tc, STABLE(type)); |
387 | 3 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.positional.obj, obj); |
388 | 3 | ref->body.u.positional.idx = idx; |
389 | 3 | }); |
390 | 3 | return (MVMObject *)ref; |
391 | 3 | } |
392 | 1 | MVMObject * MVM_nativeref_pos_i(MVMThreadContext *tc, MVMObject *obj, MVMint64 idx) { |
393 | 1 | MVMObject *ref_type = MVM_hll_current(tc)->int_pos_ref; |
394 | 1 | if (ref_type) |
395 | 1 | return posref(tc, ref_type, obj, idx); |
396 | 0 | MVM_exception_throw_adhoc(tc, "No int positional reference type registered for current HLL"); |
397 | 0 | } |
398 | 1 | MVMObject * MVM_nativeref_pos_n(MVMThreadContext *tc, MVMObject *obj, MVMint64 idx) { |
399 | 1 | MVMObject *ref_type = MVM_hll_current(tc)->num_pos_ref; |
400 | 1 | if (ref_type) |
401 | 1 | return posref(tc, ref_type, obj, idx); |
402 | 0 | MVM_exception_throw_adhoc(tc, "No num positional reference type registered for current HLL"); |
403 | 0 | } |
404 | 1 | MVMObject * MVM_nativeref_pos_s(MVMThreadContext *tc, MVMObject *obj, MVMint64 idx) { |
405 | 1 | MVMObject *ref_type = MVM_hll_current(tc)->str_pos_ref; |
406 | 1 | if (ref_type) |
407 | 1 | return posref(tc, ref_type, obj, idx); |
408 | 0 | MVM_exception_throw_adhoc(tc, "No str positional reference type registered for current HLL"); |
409 | 0 | } |
410 | | |
411 | | /* Creation of native references for multi-dimensional positionals. */ |
412 | 12 | static MVMObject * md_posref(MVMThreadContext *tc, MVMObject *type, MVMObject *obj, MVMObject *indices) { |
413 | 12 | MVMNativeRef *ref; |
414 | 12 | MVMROOT2(tc, obj, indices, { |
415 | 12 | ref = (MVMNativeRef *)MVM_gc_allocate_object(tc, STABLE(type)); |
416 | 12 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.multidim.obj, obj); |
417 | 12 | MVM_ASSIGN_REF(tc, &(ref->common.header), ref->body.u.multidim.indices, indices); |
418 | 12 | }); |
419 | 12 | return (MVMObject *)ref; |
420 | 12 | } |
421 | 4 | MVMObject * MVM_nativeref_multidim_i(MVMThreadContext *tc, MVMObject *obj, MVMObject *indices) { |
422 | 4 | MVMObject *ref_type = MVM_hll_current(tc)->int_multidim_ref; |
423 | 4 | if (ref_type) |
424 | 4 | return md_posref(tc, ref_type, obj, indices); |
425 | 0 | MVM_exception_throw_adhoc(tc, "No int multidim positional reference type registered for current HLL"); |
426 | 0 | } |
427 | 4 | MVMObject * MVM_nativeref_multidim_n(MVMThreadContext *tc, MVMObject *obj, MVMObject *indices) { |
428 | 4 | MVMObject *ref_type = MVM_hll_current(tc)->num_multidim_ref; |
429 | 4 | if (ref_type) |
430 | 4 | return md_posref(tc, ref_type, obj, indices); |
431 | 0 | MVM_exception_throw_adhoc(tc, "No num multidim positional reference type registered for current HLL"); |
432 | 0 | } |
433 | 4 | MVMObject * MVM_nativeref_multidim_s(MVMThreadContext *tc, MVMObject *obj, MVMObject *indices) { |
434 | 4 | MVMObject *ref_type = MVM_hll_current(tc)->str_multidim_ref; |
435 | 4 | if (ref_type) |
436 | 4 | return md_posref(tc, ref_type, obj, indices); |
437 | 0 | MVM_exception_throw_adhoc(tc, "No str multidim positional reference type registered for current HLL"); |
438 | 0 | } |
439 | | |
440 | | /* Reference read functions. These do no checks that the reference is of the |
441 | | * right kind and primitive type, they just go ahead and do the read. Thus |
442 | | * they are more suited to calling from optimized code. The checking path is |
443 | | * in the native ref container implementation, in containers.c; after checks, |
444 | | * they delegate here. */ |
445 | 5 | MVMint64 MVM_nativeref_read_lex_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
446 | 5 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
447 | 5 | MVMRegister *var = &(ref->body.u.lex.frame->env[ref->body.u.lex.env_idx]); |
448 | 5 | switch (ref->body.u.lex.type) { |
449 | 0 | case MVM_reg_int8: |
450 | 0 | return var->i8; |
451 | 0 | case MVM_reg_int16: |
452 | 0 | return var->i16; |
453 | 0 | case MVM_reg_int32: |
454 | 0 | return var->i32; |
455 | 5 | default: |
456 | 5 | return var->i64; |
457 | 5 | } |
458 | 5 | } |
459 | 5 | MVMnum64 MVM_nativeref_read_lex_n(MVMThreadContext *tc, MVMObject *ref_obj) { |
460 | 5 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
461 | 5 | MVMRegister *var = &(ref->body.u.lex.frame->env[ref->body.u.lex.env_idx]); |
462 | 5 | switch (ref->body.u.lex.type) { |
463 | 0 | case MVM_reg_num32: |
464 | 0 | return var->n32; |
465 | 5 | default: |
466 | 5 | return var->n64; |
467 | 5 | } |
468 | 5 | } |
469 | 5 | MVMString * MVM_nativeref_read_lex_s(MVMThreadContext *tc, MVMObject *ref_obj) { |
470 | 5 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
471 | 5 | return ref->body.u.lex.frame->env[ref->body.u.lex.env_idx].s; |
472 | 5 | } |
473 | 1 | MVMint64 MVM_nativeref_read_attribute_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
474 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
475 | 1 | return MVM_repr_get_attr_i(tc, ref->body.u.attribute.obj, |
476 | 1 | ref->body.u.attribute.class_handle, ref->body.u.attribute.name, MVM_NO_HINT); |
477 | 1 | } |
478 | 1 | MVMnum64 MVM_nativeref_read_attribute_n(MVMThreadContext *tc, MVMObject *ref_obj) { |
479 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
480 | 1 | return MVM_repr_get_attr_n(tc, ref->body.u.attribute.obj, |
481 | 1 | ref->body.u.attribute.class_handle, ref->body.u.attribute.name, MVM_NO_HINT); |
482 | 1 | } |
483 | 1 | MVMString * MVM_nativeref_read_attribute_s(MVMThreadContext *tc, MVMObject *ref_obj) { |
484 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
485 | 1 | return MVM_repr_get_attr_s(tc, ref->body.u.attribute.obj, |
486 | 1 | ref->body.u.attribute.class_handle, ref->body.u.attribute.name, MVM_NO_HINT); |
487 | 1 | } |
488 | 1 | MVMint64 MVM_nativeref_read_positional_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
489 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
490 | 1 | return MVM_repr_at_pos_i(tc, ref->body.u.positional.obj, ref->body.u.positional.idx); |
491 | 1 | } |
492 | 1 | MVMnum64 MVM_nativeref_read_positional_n(MVMThreadContext *tc, MVMObject *ref_obj) { |
493 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
494 | 1 | return MVM_repr_at_pos_n(tc, ref->body.u.positional.obj, ref->body.u.positional.idx); |
495 | 1 | } |
496 | 1 | MVMString * MVM_nativeref_read_positional_s(MVMThreadContext *tc, MVMObject *ref_obj) { |
497 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
498 | 1 | return MVM_repr_at_pos_s(tc, ref->body.u.positional.obj, ref->body.u.positional.idx); |
499 | 1 | } |
500 | 2 | MVMint64 MVM_nativeref_read_multidim_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
501 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
502 | 2 | return MVM_repr_at_pos_multidim_i(tc, ref->body.u.multidim.obj, ref->body.u.multidim.indices); |
503 | 2 | } |
504 | 2 | MVMnum64 MVM_nativeref_read_multidim_n(MVMThreadContext *tc, MVMObject *ref_obj) { |
505 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
506 | 2 | return MVM_repr_at_pos_multidim_n(tc, ref->body.u.multidim.obj, ref->body.u.multidim.indices); |
507 | 2 | } |
508 | 2 | MVMString * MVM_nativeref_read_multidim_s(MVMThreadContext *tc, MVMObject *ref_obj) { |
509 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
510 | 2 | return MVM_repr_at_pos_multidim_s(tc, ref->body.u.multidim.obj, ref->body.u.multidim.indices); |
511 | 2 | } |
512 | | |
513 | | /* Reference write functions. Same (non-checking) rules as the reads above. */ |
514 | 2 | void MVM_nativeref_write_lex_i(MVMThreadContext *tc, MVMObject *ref_obj, MVMint64 value) { |
515 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
516 | 2 | MVMRegister *var = &(ref->body.u.lex.frame->env[ref->body.u.lex.env_idx]); |
517 | 2 | switch (ref->body.u.lex.type) { |
518 | 0 | case MVM_reg_int8: |
519 | 0 | var->i8 = (MVMint8)value; |
520 | 0 | break; |
521 | 0 | case MVM_reg_int16: |
522 | 0 | var->i16 = (MVMint16)value; |
523 | 0 | break; |
524 | 0 | case MVM_reg_int32: |
525 | 0 | var->i32 = (MVMint32)value; |
526 | 0 | break; |
527 | 2 | default: |
528 | 2 | var->i64 = value; |
529 | 2 | break; |
530 | 2 | } |
531 | 2 | } |
532 | 2 | void MVM_nativeref_write_lex_n(MVMThreadContext *tc, MVMObject *ref_obj, MVMnum64 value) { |
533 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
534 | 2 | MVMRegister *var = &(ref->body.u.lex.frame->env[ref->body.u.lex.env_idx]); |
535 | 2 | switch (ref->body.u.lex.type) { |
536 | 0 | case MVM_reg_num32: |
537 | 0 | var->n32 = (MVMnum32)value; |
538 | 0 | break; |
539 | 2 | default: |
540 | 2 | var->n64 = value; |
541 | 2 | break; |
542 | 2 | } |
543 | 2 | } |
544 | 2 | void MVM_nativeref_write_lex_s(MVMThreadContext *tc, MVMObject *ref_obj, MVMString *value) { |
545 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
546 | 2 | MVM_ASSIGN_REF(tc, &(ref->body.u.lex.frame->header), |
547 | 2 | ref->body.u.lex.frame->env[ref->body.u.lex.env_idx].s, value); |
548 | 2 | } |
549 | 4 | void MVM_nativeref_write_attribute_i(MVMThreadContext *tc, MVMObject *ref_obj, MVMint64 value) { |
550 | 4 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
551 | 4 | MVMRegister r; |
552 | 4 | r.i64 = value; |
553 | 4 | MVM_repr_bind_attr_inso(tc, ref->body.u.attribute.obj, ref->body.u.attribute.class_handle, |
554 | 4 | ref->body.u.attribute.name, MVM_NO_HINT, r, MVM_reg_int64); |
555 | 4 | } |
556 | 2 | void MVM_nativeref_write_attribute_n(MVMThreadContext *tc, MVMObject *ref_obj, MVMnum64 value) { |
557 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
558 | 2 | MVMRegister r; |
559 | 2 | r.n64 = value; |
560 | 2 | MVM_repr_bind_attr_inso(tc, ref->body.u.attribute.obj, ref->body.u.attribute.class_handle, |
561 | 2 | ref->body.u.attribute.name, MVM_NO_HINT, r, MVM_reg_num64); |
562 | 2 | } |
563 | 2 | void MVM_nativeref_write_attribute_s(MVMThreadContext *tc, MVMObject *ref_obj, MVMString *value) { |
564 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
565 | 2 | MVMRegister r; |
566 | 2 | r.s = value; |
567 | 2 | MVM_repr_bind_attr_inso(tc, ref->body.u.attribute.obj, ref->body.u.attribute.class_handle, |
568 | 2 | ref->body.u.attribute.name, MVM_NO_HINT, r, MVM_reg_str); |
569 | 2 | } |
570 | 1 | void MVM_nativeref_write_positional_i(MVMThreadContext *tc, MVMObject *ref_obj, MVMint64 value) { |
571 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
572 | 1 | MVM_repr_bind_pos_i(tc, ref->body.u.positional.obj, ref->body.u.positional.idx, value); |
573 | 1 | } |
574 | 1 | void MVM_nativeref_write_positional_n(MVMThreadContext *tc, MVMObject *ref_obj, MVMnum64 value) { |
575 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
576 | 1 | MVM_repr_bind_pos_n(tc, ref->body.u.positional.obj, ref->body.u.positional.idx, value); |
577 | 1 | } |
578 | 1 | void MVM_nativeref_write_positional_s(MVMThreadContext *tc, MVMObject *ref_obj, MVMString *value) { |
579 | 1 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
580 | 1 | MVM_repr_bind_pos_s(tc, ref->body.u.positional.obj, ref->body.u.positional.idx, value); |
581 | 1 | } |
582 | | |
583 | 2 | void MVM_nativeref_write_multidim_i(MVMThreadContext *tc, MVMObject *ref_obj, MVMint64 value) { |
584 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
585 | 2 | MVM_repr_bind_pos_multidim_i(tc, ref->body.u.multidim.obj, ref->body.u.multidim.indices, value); |
586 | 2 | } |
587 | 2 | void MVM_nativeref_write_multidim_n(MVMThreadContext *tc, MVMObject *ref_obj, MVMnum64 value) { |
588 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
589 | 2 | MVM_repr_bind_pos_multidim_n(tc, ref->body.u.multidim.obj, ref->body.u.multidim.indices, value); |
590 | 2 | } |
591 | 2 | void MVM_nativeref_write_multidim_s(MVMThreadContext *tc, MVMObject *ref_obj, MVMString *value) { |
592 | 2 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
593 | 2 | MVM_repr_bind_pos_multidim_s(tc, ref->body.u.multidim.obj, ref->body.u.multidim.indices, value); |
594 | 2 | } |
595 | | |
596 | | /* Functions to turn native integer references into an AO_t * that can be used |
597 | | * in an atomic operation. The reference *must* be used and discarded *before* |
598 | | * the next safepoint, after which it could become invalidated. */ |
599 | 0 | AO_t * MVM_nativeref_as_atomic_lex_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
600 | 0 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
601 | 0 | MVMRegister *var = &(ref->body.u.lex.frame->env[ref->body.u.lex.env_idx]); |
602 | 0 | if (sizeof(AO_t) == 8 && ref->body.u.lex.type == MVM_reg_int64) |
603 | 0 | return (AO_t *)&(var->i64); |
604 | 0 | if (sizeof(AO_t) == 4 && ref->body.u.lex.type == MVM_reg_int32) |
605 | 0 | return (AO_t *)&(var->i32); |
606 | 0 | MVM_exception_throw_adhoc(tc, |
607 | 0 | "Cannot atomic load from an integer lexical not of the machine's native size"); |
608 | 0 | } |
609 | 0 | AO_t * MVM_nativeref_as_atomic_attribute_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
610 | 0 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
611 | 0 | MVMObject *obj = ref->body.u.attribute.obj; |
612 | 0 | return REPR(obj)->attr_funcs.attribute_as_atomic(tc, STABLE(obj), OBJECT_BODY(obj), |
613 | 0 | ref->body.u.attribute.class_handle, ref->body.u.attribute.name, MVM_reg_int64); |
614 | 0 | } |
615 | 0 | AO_t * MVM_nativeref_as_atomic_positional_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
616 | 0 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
617 | 0 | MVMObject *obj = ref->body.u.positional.obj; |
618 | 0 | return REPR(obj)->pos_funcs.pos_as_atomic(tc, STABLE(obj), obj, OBJECT_BODY(obj), |
619 | 0 | ref->body.u.positional.idx); |
620 | 0 | } |
621 | 0 | AO_t * MVM_nativeref_as_atomic_multidim_i(MVMThreadContext *tc, MVMObject *ref_obj) { |
622 | 0 | MVMNativeRef *ref = (MVMNativeRef *)ref_obj; |
623 | 0 | MVMObject *obj = ref->body.u.multidim.obj; |
624 | 0 | MVMint64 num_indices; |
625 | 0 | MVM_repr_populate_indices_array(tc, ref->body.u.multidim.indices, &num_indices); |
626 | 0 | return REPR(obj)->pos_funcs.pos_as_atomic_multidim(tc, STABLE(obj), obj, OBJECT_BODY(obj), |
627 | 0 | num_indices, tc->multi_dim_indices); |
628 | 0 | } |