/home/travis/build/MoarVM/MoarVM/src/6model/reprs/VMArray.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | #include "limits.h" |
3 | | |
4 | | /* This representation's function pointer table. */ |
5 | | static const MVMREPROps VMArray_this_repr; |
6 | | |
7 | 26.2M | MVM_STATIC_INLINE void enter_single_user(MVMThreadContext *tc, MVMArrayBody *arr) { |
8 | 26.2M | #if MVM_ARRAY_CONC_DEBUG |
9 | | if (!MVM_trycas(&(arr->in_use), 0, 1)) { |
10 | | MVM_dump_backtrace(tc); |
11 | | MVM_exception_throw_adhoc(tc, "Array may not be used concurrently"); |
12 | | } |
13 | | #endif |
14 | 26.2M | } |
15 | 26.2M | static void exit_single_user(MVMThreadContext *tc, MVMArrayBody *arr) { |
16 | 26.2M | #if MVM_ARRAY_CONC_DEBUG |
17 | | arr->in_use = 0; |
18 | | #endif |
19 | 26.2M | } |
20 | | |
21 | | /* Creates a new type object of this representation, and associates it with |
22 | | * the given HOW. */ |
23 | 743 | static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) { |
24 | 743 | MVMSTable *st = MVM_gc_allocate_stable(tc, &VMArray_this_repr, HOW); |
25 | 743 | |
26 | 743 | MVMROOT(tc, st, { |
27 | 743 | MVMObject *obj = MVM_gc_allocate_type_object(tc, st); |
28 | 743 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)MVM_malloc(sizeof(MVMArrayREPRData)); |
29 | 743 | |
30 | 743 | repr_data->slot_type = MVM_ARRAY_OBJ; |
31 | 743 | repr_data->elem_size = sizeof(MVMObject *); |
32 | 743 | repr_data->elem_type = NULL; |
33 | 743 | |
34 | 743 | MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj); |
35 | 743 | st->size = sizeof(MVMArray); |
36 | 743 | st->REPR_data = repr_data; |
37 | 743 | }); |
38 | 743 | |
39 | 743 | return st->WHAT; |
40 | 743 | } |
41 | | |
42 | | /* Copies the body of one object to another. The result has the space |
43 | | * needed for the current number of elements, which may not be the |
44 | | * entire allocated slot size. */ |
45 | 5.87k | static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) { |
46 | 5.87k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
47 | 5.87k | MVMArrayBody *src_body = (MVMArrayBody *)src; |
48 | 5.87k | MVMArrayBody *dest_body = (MVMArrayBody *)dest; |
49 | 5.87k | dest_body->elems = src_body->elems; |
50 | 5.87k | dest_body->ssize = src_body->elems; |
51 | 5.87k | dest_body->start = 0; |
52 | 5.87k | if (dest_body->elems > 0) { |
53 | 5.85k | size_t mem_size = dest_body->ssize * repr_data->elem_size; |
54 | 5.85k | size_t start_pos = src_body->start * repr_data->elem_size; |
55 | 5.85k | char *copy_start = ((char *)src_body->slots.any) + start_pos; |
56 | 5.85k | dest_body->slots.any = MVM_malloc(mem_size); |
57 | 5.85k | memcpy(dest_body->slots.any, copy_start, mem_size); |
58 | 5.85k | } |
59 | 24 | else { |
60 | 24 | dest_body->slots.any = NULL; |
61 | 24 | } |
62 | 5.87k | } |
63 | | |
64 | | /* Adds held objects to the GC worklist. */ |
65 | 469k | static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) { |
66 | 469k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
67 | 469k | MVMArrayBody *body = (MVMArrayBody *)data; |
68 | 469k | MVMuint64 elems = body->elems; |
69 | 469k | MVMuint64 start = body->start; |
70 | 469k | MVMuint64 i = 0; |
71 | 469k | switch (repr_data->slot_type) { |
72 | 448k | case MVM_ARRAY_OBJ: { |
73 | 448k | MVMObject **slots = body->slots.o; |
74 | 448k | slots += start; |
75 | 1.50M | while (i < elems) { |
76 | 1.05M | MVM_gc_worklist_add(tc, worklist, &slots[i]); |
77 | 1.05M | i++; |
78 | 1.05M | } |
79 | 448k | break; |
80 | 448k | } |
81 | 8.57k | case MVM_ARRAY_STR: { |
82 | 8.57k | MVMString **slots = body->slots.s; |
83 | 8.57k | slots += start; |
84 | 80.2k | while (i < elems) { |
85 | 71.6k | MVM_gc_worklist_add(tc, worklist, &slots[i]); |
86 | 71.6k | i++; |
87 | 71.6k | } |
88 | 8.57k | break; |
89 | 448k | } |
90 | 469k | } |
91 | 469k | } |
92 | | |
93 | | /* Called by the VM in order to free memory associated with this object. */ |
94 | 1.96M | static void gc_free(MVMThreadContext *tc, MVMObject *obj) { |
95 | 1.96M | MVMArray *arr = (MVMArray *)obj; |
96 | 1.96M | MVM_free(arr->body.slots.any); |
97 | 1.96M | } |
98 | | |
99 | | /* Marks the representation data in an STable.*/ |
100 | 358 | static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMGCWorklist *worklist) { |
101 | 358 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
102 | 358 | if (repr_data == NULL) |
103 | 0 | return; |
104 | 358 | MVM_gc_worklist_add(tc, worklist, &repr_data->elem_type); |
105 | 358 | } |
106 | | |
107 | | /* Frees the representation data in an STable.*/ |
108 | 0 | static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) { |
109 | 0 | MVM_free(st->REPR_data); |
110 | 0 | } |
111 | | |
112 | | |
113 | | static const MVMStorageSpec storage_spec = { |
114 | | MVM_STORAGE_SPEC_REFERENCE, /* inlineable */ |
115 | | 0, /* bits */ |
116 | | 0, /* align */ |
117 | | MVM_STORAGE_SPEC_BP_NONE, /* boxed_primitive */ |
118 | | 0, /* can_box */ |
119 | | 0, /* is_unsigned */ |
120 | | }; |
121 | | |
122 | | |
123 | | /* Gets the storage specification for this representation. */ |
124 | 245k | static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) { |
125 | 245k | return &storage_spec; |
126 | 245k | } |
127 | | |
128 | 22.0M | static void at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) { |
129 | 22.0M | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
130 | 22.0M | MVMArrayBody *body = (MVMArrayBody *)data; |
131 | 22.0M | |
132 | 22.0M | /* Handle negative indexes. */ |
133 | 22.0M | if (index < 0) { |
134 | 68.9k | index += body->elems; |
135 | 68.9k | if (index < 0) |
136 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Index out of bounds"); |
137 | 68.9k | } |
138 | 22.0M | |
139 | 22.0M | /* Go by type. */ |
140 | 22.0M | switch (repr_data->slot_type) { |
141 | 12.4M | case MVM_ARRAY_OBJ: |
142 | 12.4M | if (kind != MVM_reg_obj) |
143 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected object register"); |
144 | 12.4M | if (index >= body->elems) { |
145 | 41.5k | value->o = tc->instance->VMNull; |
146 | 41.5k | } |
147 | 12.4M | else { |
148 | 12.4M | MVMObject *found = body->slots.o[body->start + index]; |
149 | 12.4M | value->o = found ? found : tc->instance->VMNull; |
150 | 12.4M | } |
151 | 12.4M | break; |
152 | 62.6k | case MVM_ARRAY_STR: |
153 | 62.6k | if (kind != MVM_reg_str) |
154 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected string register"); |
155 | 62.6k | if (index >= body->elems) |
156 | 1 | value->s = NULL; |
157 | 62.6k | else |
158 | 62.6k | value->s = body->slots.s[body->start + index]; |
159 | 62.6k | break; |
160 | 9.51M | case MVM_ARRAY_I64: |
161 | 9.51M | if (kind != MVM_reg_int64) |
162 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
163 | 9.51M | if (index >= body->elems) |
164 | 1.63M | value->i64 = 0; |
165 | 9.51M | else |
166 | 7.87M | value->i64 = (MVMint64)body->slots.i64[body->start + index]; |
167 | 9.51M | break; |
168 | 0 | case MVM_ARRAY_I32: |
169 | 0 | if (kind != MVM_reg_int64) |
170 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
171 | 0 | if (index >= body->elems) |
172 | 0 | value->i64 = 0; |
173 | 0 | else |
174 | 0 | value->i64 = (MVMint64)body->slots.i32[body->start + index]; |
175 | 0 | break; |
176 | 0 | case MVM_ARRAY_I16: |
177 | 0 | if (kind != MVM_reg_int64) |
178 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
179 | 0 | if (index >= body->elems) |
180 | 0 | value->i64 = 0; |
181 | 0 | else |
182 | 0 | value->i64 = (MVMint64)body->slots.i16[body->start + index]; |
183 | 0 | break; |
184 | 9 | case MVM_ARRAY_I8: |
185 | 9 | if (kind != MVM_reg_int64) |
186 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
187 | 9 | if (index >= body->elems) |
188 | 0 | value->i64 = 0; |
189 | 9 | else |
190 | 9 | value->i64 = (MVMint64)body->slots.i8[body->start + index]; |
191 | 9 | break; |
192 | 17 | case MVM_ARRAY_N64: |
193 | 17 | if (kind != MVM_reg_num64) |
194 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected num register"); |
195 | 17 | if (index >= body->elems) |
196 | 1 | value->n64 = 0.0; |
197 | 17 | else |
198 | 16 | value->n64 = (MVMnum64)body->slots.n64[body->start + index]; |
199 | 17 | break; |
200 | 0 | case MVM_ARRAY_N32: |
201 | 0 | if (kind != MVM_reg_num64) |
202 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected num register"); |
203 | 0 | if (index >= body->elems) |
204 | 0 | value->n64 = 0.0; |
205 | 0 | else |
206 | 0 | value->n64 = (MVMnum64)body->slots.n32[body->start + index]; |
207 | 0 | break; |
208 | 0 | case MVM_ARRAY_U64: |
209 | 0 | if (kind != MVM_reg_int64) |
210 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
211 | 0 | if (index >= body->elems) |
212 | 0 | value->i64 = 0; |
213 | 0 | else |
214 | 0 | value->i64 = (MVMint64)body->slots.u64[body->start + index]; |
215 | 0 | break; |
216 | 6 | case MVM_ARRAY_U32: |
217 | 6 | if (kind != MVM_reg_int64) |
218 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
219 | 6 | if (index >= body->elems) |
220 | 0 | value->i64 = 0; |
221 | 6 | else |
222 | 6 | value->i64 = (MVMint64)body->slots.u32[body->start + index]; |
223 | 6 | break; |
224 | 0 | case MVM_ARRAY_U16: |
225 | 0 | if (kind != MVM_reg_int64) |
226 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
227 | 0 | if (index >= body->elems) |
228 | 0 | value->i64 = 0; |
229 | 0 | else |
230 | 0 | value->i64 = (MVMint64)body->slots.u16[body->start + index]; |
231 | 0 | break; |
232 | 75 | case MVM_ARRAY_U8: |
233 | 75 | if (kind != MVM_reg_int64) |
234 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: atpos expected int register"); |
235 | 75 | if (index >= body->elems) |
236 | 0 | value->i64 = 0; |
237 | 75 | else |
238 | 75 | value->i64 = (MVMint64)body->slots.u8[body->start + index]; |
239 | 75 | break; |
240 | 0 | default: |
241 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type, got '%s'", MVM_reg_get_debug_name(tc, repr_data->slot_type)); |
242 | 22.0M | } |
243 | 22.0M | } |
244 | 9.85M | void MVM_VMArray_at_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister *value, MVMuint16 kind) { |
245 | 9.85M | return at_pos(tc, st, root, data, index, value, kind); |
246 | 9.85M | } |
247 | | |
248 | | static MVMuint64 zero_slots(MVMThreadContext *tc, MVMArrayBody *body, |
249 | 7.54M | MVMuint64 elems, MVMuint64 ssize, MVMuint8 slot_type) { |
250 | 7.54M | switch (slot_type) { |
251 | 1.49M | case MVM_ARRAY_OBJ: |
252 | 14.1M | while (elems < ssize) |
253 | 12.6M | body->slots.o[elems++] = NULL; |
254 | 1.49M | break; |
255 | 20.5k | case MVM_ARRAY_STR: |
256 | 345k | while (elems < ssize) |
257 | 324k | body->slots.s[elems++] = NULL; |
258 | 20.5k | break; |
259 | 6.03M | case MVM_ARRAY_I64: |
260 | 27.2M | while (elems < ssize) |
261 | 21.1M | body->slots.i64[elems++] = 0; |
262 | 6.03M | break; |
263 | 0 | case MVM_ARRAY_I32: |
264 | 0 | while (elems < ssize) |
265 | 0 | body->slots.i32[elems++] = 0; |
266 | 0 | break; |
267 | 0 | case MVM_ARRAY_I16: |
268 | 0 | while (elems < ssize) |
269 | 0 | body->slots.i16[elems++] = 0; |
270 | 0 | break; |
271 | 1 | case MVM_ARRAY_I8: |
272 | 9 | while (elems < ssize) |
273 | 8 | body->slots.i8[elems++] = 0; |
274 | 1 | break; |
275 | 14 | case MVM_ARRAY_N64: |
276 | 96 | while (elems < ssize) |
277 | 82 | body->slots.n64[elems++] = 0.0; |
278 | 14 | break; |
279 | 0 | case MVM_ARRAY_N32: |
280 | 0 | while (elems < ssize) |
281 | 0 | body->slots.n32[elems++] = 0.0; |
282 | 0 | break; |
283 | 0 | case MVM_ARRAY_U64: |
284 | 0 | while (elems < ssize) |
285 | 0 | body->slots.u64[elems++] = 0; |
286 | 0 | break; |
287 | 4 | case MVM_ARRAY_U32: |
288 | 36 | while (elems < ssize) |
289 | 32 | body->slots.u32[elems++] = 0; |
290 | 4 | break; |
291 | 0 | case MVM_ARRAY_U16: |
292 | 0 | while (elems < ssize) |
293 | 0 | body->slots.u16[elems++] = 0; |
294 | 0 | break; |
295 | 7 | case MVM_ARRAY_U8: |
296 | 63 | while (elems < ssize) |
297 | 56 | body->slots.u8[elems++] = 0; |
298 | 7 | break; |
299 | 0 | default: |
300 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
301 | 7.54M | } |
302 | 7.54M | return elems; |
303 | 7.54M | } |
304 | | |
305 | 19.9M | static void set_size_internal(MVMThreadContext *tc, MVMArrayBody *body, MVMuint64 n, MVMArrayREPRData *repr_data) { |
306 | 19.9M | MVMuint64 elems = body->elems; |
307 | 19.9M | MVMuint64 start = body->start; |
308 | 19.9M | MVMuint64 ssize = body->ssize; |
309 | 19.9M | void *slots = body->slots.any; |
310 | 19.9M | |
311 | 19.9M | if (n == elems) |
312 | 149k | return; |
313 | 19.9M | |
314 | 19.7M | if (start > 0 && n + start > ssize) { |
315 | 40 | /* if there aren't enough slots at the end, shift off empty slots |
316 | 40 | * from the beginning first */ |
317 | 40 | if (elems > 0) |
318 | 40 | memmove(slots, |
319 | 40 | (char *)slots + start * repr_data->elem_size, |
320 | 40 | elems * repr_data->elem_size); |
321 | 40 | body->start = 0; |
322 | 40 | /* fill out any unused slots with NULL pointers or zero values */ |
323 | 40 | zero_slots(tc, body, elems, start+elems, repr_data->slot_type); |
324 | 40 | elems = ssize; /* we'll use this as a point to clear from later */ |
325 | 40 | } |
326 | 19.7M | else if (n < elems) { |
327 | 815k | /* we're downsizing; clear off extra slots */ |
328 | 815k | zero_slots(tc, body, n+start, start+elems, repr_data->slot_type); |
329 | 815k | } |
330 | 19.7M | |
331 | 19.7M | if (n <= ssize) { |
332 | 17.4M | /* we already have n slots available, we can just return */ |
333 | 17.4M | body->elems = n; |
334 | 17.4M | return; |
335 | 17.4M | } |
336 | 19.7M | |
337 | 19.7M | /* We need more slots. If the current slot size is less |
338 | 19.7M | * than 8K, use the larger of twice the current slot size |
339 | 19.7M | * or the actual number of elements needed. Otherwise, |
340 | 19.7M | * grow the slots to the next multiple of 4096 (0x1000). */ |
341 | 2.28M | if (ssize < 8192) { |
342 | 2.28M | ssize *= 2; |
343 | 2.28M | if (n > ssize) ssize = n; |
344 | 2.28M | if (ssize < 8) ssize = 8; |
345 | 2.28M | } |
346 | 18.4E | else { |
347 | 18.4E | ssize = (n + 0x1000) & ~0xfffUL; |
348 | 18.4E | } |
349 | 2.28M | { |
350 | 2.28M | /* Our budget is 2^( |
351 | 2.28M | * <number of bits in an array index> |
352 | 2.28M | * - <number of bits to address individual bytes in an array element> |
353 | 2.28M | * ) */ |
354 | 2.28M | size_t const elem_addr_size = repr_data->elem_size == 8 ? 4 : |
355 | 18.4E | repr_data->elem_size == 4 ? 3 : |
356 | 18.4E | repr_data->elem_size == 2 ? 2 : |
357 | 18.4E | 1; |
358 | 2.28M | if (ssize > (1ULL << (CHAR_BIT * sizeof(size_t) - elem_addr_size))) |
359 | 0 | MVM_exception_throw_adhoc(tc, |
360 | 0 | "Unable to allocate an array of %"PRIu64" elements", |
361 | 0 | ssize); |
362 | 2.28M | } |
363 | 2.28M | |
364 | 2.28M | /* now allocate the new slot buffer */ |
365 | 2.28M | slots = (slots) |
366 | 453k | ? MVM_realloc(slots, ssize * repr_data->elem_size) |
367 | 1.83M | : MVM_malloc(ssize * repr_data->elem_size); |
368 | 2.28M | |
369 | 2.28M | /* fill out any unused slots with NULL pointers or zero values */ |
370 | 2.28M | body->slots.any = slots; |
371 | 2.28M | zero_slots(tc, body, elems, ssize, repr_data->slot_type); |
372 | 2.28M | |
373 | 2.28M | body->ssize = ssize; |
374 | 2.28M | /* set elems last so no thread tries to access slots before they are available */ |
375 | 2.28M | body->elems = n; |
376 | 2.28M | } |
377 | | |
378 | 2.84M | static void bind_pos(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 index, MVMRegister value, MVMuint16 kind) { |
379 | 2.84M | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
380 | 2.84M | MVMArrayBody *body = (MVMArrayBody *)data; |
381 | 2.84M | |
382 | 2.84M | /* Handle negative indexes and resizing if needed. */ |
383 | 2.84M | enter_single_user(tc, body); |
384 | 2.84M | if (index < 0) { |
385 | 45.2k | index += body->elems; |
386 | 45.2k | if (index < 0) |
387 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Index out of bounds"); |
388 | 45.2k | } |
389 | 2.80M | else if (index >= body->elems) |
390 | 978k | set_size_internal(tc, body, index + 1, repr_data); |
391 | 2.84M | |
392 | 2.84M | /* Go by type. */ |
393 | 2.84M | switch (repr_data->slot_type) { |
394 | 2.00M | case MVM_ARRAY_OBJ: |
395 | 2.00M | if (kind != MVM_reg_obj) |
396 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected object register"); |
397 | 2.00M | MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[body->start + index], value.o); |
398 | 2.00M | break; |
399 | 161k | case MVM_ARRAY_STR: |
400 | 161k | if (kind != MVM_reg_str) |
401 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected string register"); |
402 | 161k | MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[body->start + index], value.s); |
403 | 161k | break; |
404 | 684k | case MVM_ARRAY_I64: |
405 | 684k | if (kind != MVM_reg_int64) |
406 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
407 | 684k | body->slots.i64[body->start + index] = value.i64; |
408 | 684k | break; |
409 | 0 | case MVM_ARRAY_I32: |
410 | 0 | if (kind != MVM_reg_int64) |
411 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
412 | 0 | body->slots.i32[body->start + index] = (MVMint32)value.i64; |
413 | 0 | break; |
414 | 0 | case MVM_ARRAY_I16: |
415 | 0 | if (kind != MVM_reg_int64) |
416 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
417 | 0 | body->slots.i16[body->start + index] = (MVMint16)value.i64; |
418 | 0 | break; |
419 | 0 | case MVM_ARRAY_I8: |
420 | 0 | if (kind != MVM_reg_int64) |
421 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
422 | 0 | body->slots.i8[body->start + index] = (MVMint8)value.i64; |
423 | 0 | break; |
424 | 10 | case MVM_ARRAY_N64: |
425 | 10 | if (kind != MVM_reg_num64) |
426 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected num register"); |
427 | 10 | body->slots.n64[body->start + index] = value.n64; |
428 | 10 | break; |
429 | 0 | case MVM_ARRAY_N32: |
430 | 0 | if (kind != MVM_reg_num64) |
431 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected num register"); |
432 | 0 | body->slots.n32[body->start + index] = (MVMnum32)value.n64; |
433 | 0 | break; |
434 | 0 | case MVM_ARRAY_U64: |
435 | 0 | if (kind != MVM_reg_int64) |
436 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
437 | 0 | body->slots.u64[body->start + index] = value.i64; |
438 | 0 | break; |
439 | 0 | case MVM_ARRAY_U32: |
440 | 0 | if (kind != MVM_reg_int64) |
441 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
442 | 0 | body->slots.u32[body->start + index] = (MVMuint32)value.i64; |
443 | 0 | break; |
444 | 0 | case MVM_ARRAY_U16: |
445 | 0 | if (kind != MVM_reg_int64) |
446 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
447 | 0 | body->slots.u16[body->start + index] = (MVMuint16)value.i64; |
448 | 0 | break; |
449 | 0 | case MVM_ARRAY_U8: |
450 | 0 | if (kind != MVM_reg_int64) |
451 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: bindpos expected int register"); |
452 | 0 | body->slots.u8[body->start + index] = (MVMuint8)value.i64; |
453 | 0 | break; |
454 | 0 | default: |
455 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
456 | 2.84M | } |
457 | 2.84M | exit_single_user(tc, body); |
458 | 2.84M | } |
459 | | |
460 | 11.7M | static MVMuint64 elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data) { |
461 | 11.7M | MVMArrayBody *body = (MVMArrayBody *)data; |
462 | 11.7M | return body->elems; |
463 | 11.7M | } |
464 | | |
465 | 1.08M | static void set_elems(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMuint64 count) { |
466 | 1.08M | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
467 | 1.08M | MVMArrayBody *body = (MVMArrayBody *)data; |
468 | 1.08M | enter_single_user(tc, body); |
469 | 1.08M | set_size_internal(tc, body, count, repr_data); |
470 | 1.08M | exit_single_user(tc, body); |
471 | 1.08M | } |
472 | | |
473 | 17.7M | static void push(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) { |
474 | 17.7M | MVMArrayBody *body = (MVMArrayBody *)data; |
475 | 17.7M | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
476 | 17.7M | enter_single_user(tc, body); |
477 | 17.7M | set_size_internal(tc, body, body->elems + 1, repr_data); |
478 | 17.7M | switch (repr_data->slot_type) { |
479 | 3.08M | case MVM_ARRAY_OBJ: |
480 | 3.08M | if (kind != MVM_reg_obj) |
481 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected object register"); |
482 | 3.08M | MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[body->start + body->elems - 1], value.o); |
483 | 3.08M | break; |
484 | 34.3k | case MVM_ARRAY_STR: |
485 | 34.3k | if (kind != MVM_reg_str) |
486 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected string register"); |
487 | 34.3k | MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[body->start + body->elems - 1], value.s); |
488 | 34.3k | break; |
489 | 14.6M | case MVM_ARRAY_I64: |
490 | 14.6M | if (kind != MVM_reg_int64) |
491 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
492 | 14.6M | body->slots.i64[body->start + body->elems - 1] = value.i64; |
493 | 14.6M | break; |
494 | 0 | case MVM_ARRAY_I32: |
495 | 0 | if (kind != MVM_reg_int64) |
496 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
497 | 0 | body->slots.i32[body->start + body->elems - 1] = (MVMint32)value.i64; |
498 | 0 | break; |
499 | 0 | case MVM_ARRAY_I16: |
500 | 0 | if (kind != MVM_reg_int64) |
501 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
502 | 0 | body->slots.i16[body->start + body->elems - 1] = (MVMint16)value.i64; |
503 | 0 | break; |
504 | 2 | case MVM_ARRAY_I8: |
505 | 2 | if (kind != MVM_reg_int64) |
506 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
507 | 2 | body->slots.i8[body->start + body->elems - 1] = (MVMint8)value.i64; |
508 | 2 | break; |
509 | 12 | case MVM_ARRAY_N64: |
510 | 12 | if (kind != MVM_reg_num64) |
511 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected num register"); |
512 | 12 | body->slots.n64[body->start + body->elems - 1] = value.n64; |
513 | 12 | break; |
514 | 0 | case MVM_ARRAY_N32: |
515 | 0 | if (kind != MVM_reg_num64) |
516 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected num register"); |
517 | 0 | body->slots.n32[body->start + body->elems - 1] = (MVMnum32)value.n64; |
518 | 0 | break; |
519 | 0 | case MVM_ARRAY_U64: |
520 | 0 | if (kind != MVM_reg_int64) |
521 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
522 | 0 | body->slots.u64[body->start + body->elems - 1] = (MVMuint64)value.i64; |
523 | 0 | break; |
524 | 9 | case MVM_ARRAY_U32: |
525 | 9 | if (kind != MVM_reg_int64) |
526 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
527 | 9 | body->slots.u32[body->start + body->elems - 1] = (MVMuint32)value.i64; |
528 | 9 | break; |
529 | 0 | case MVM_ARRAY_U16: |
530 | 0 | if (kind != MVM_reg_int64) |
531 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
532 | 0 | body->slots.u16[body->start + body->elems - 1] = (MVMuint16)value.i64; |
533 | 0 | break; |
534 | 18 | case MVM_ARRAY_U8: |
535 | 18 | if (kind != MVM_reg_int64) |
536 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: push expected int register"); |
537 | 18 | body->slots.u8[body->start + body->elems - 1] = (MVMuint8)value.i64; |
538 | 18 | break; |
539 | 0 | default: |
540 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
541 | 17.7M | } |
542 | 17.7M | exit_single_user(tc, body); |
543 | 17.7M | } |
544 | | |
545 | 4.42M | static void pop(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) { |
546 | 4.42M | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
547 | 4.42M | MVMArrayBody *body = (MVMArrayBody *)data; |
548 | 4.42M | const MVMuint64 slot = body->start + body->elems - 1; |
549 | 4.42M | |
550 | 4.42M | if (body->elems < 1) |
551 | 0 | MVM_exception_throw_adhoc(tc, |
552 | 0 | "MVMArray: Can't pop from an empty array"); |
553 | 4.42M | |
554 | 4.42M | enter_single_user(tc, body); |
555 | 4.42M | body->elems--; |
556 | 4.42M | switch (repr_data->slot_type) { |
557 | 166k | case MVM_ARRAY_OBJ: |
558 | 166k | if (kind != MVM_reg_obj) |
559 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected object register"); |
560 | 166k | value->o = body->slots.o[slot]; |
561 | 166k | break; |
562 | 1 | case MVM_ARRAY_STR: |
563 | 1 | if (kind != MVM_reg_str) |
564 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected string register"); |
565 | 1 | value->s = body->slots.s[slot]; |
566 | 1 | break; |
567 | 4.25M | case MVM_ARRAY_I64: |
568 | 4.25M | if (kind != MVM_reg_int64) |
569 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
570 | 4.25M | value->i64 = (MVMint64)body->slots.i64[slot]; |
571 | 4.25M | break; |
572 | 0 | case MVM_ARRAY_I32: |
573 | 0 | if (kind != MVM_reg_int64) |
574 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
575 | 0 | value->i64 = (MVMint64)body->slots.i32[slot]; |
576 | 0 | break; |
577 | 0 | case MVM_ARRAY_I16: |
578 | 0 | if (kind != MVM_reg_int64) |
579 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
580 | 0 | value->i64 = (MVMint64)body->slots.i16[slot]; |
581 | 0 | break; |
582 | 0 | case MVM_ARRAY_I8: |
583 | 0 | if (kind != MVM_reg_int64) |
584 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
585 | 0 | value->i64 = (MVMint64)body->slots.i8[slot]; |
586 | 0 | break; |
587 | 1 | case MVM_ARRAY_N64: |
588 | 1 | if (kind != MVM_reg_num64) |
589 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected num register"); |
590 | 1 | value->n64 = (MVMnum64)body->slots.n64[slot]; |
591 | 1 | break; |
592 | 0 | case MVM_ARRAY_N32: |
593 | 0 | if (kind != MVM_reg_num64) |
594 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected num register"); |
595 | 0 | value->n64 = (MVMnum64)body->slots.n32[slot]; |
596 | 0 | break; |
597 | 0 | case MVM_ARRAY_U64: |
598 | 0 | if (kind != MVM_reg_int64) |
599 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
600 | 0 | value->i64 = (MVMint64)body->slots.u64[slot]; |
601 | 0 | break; |
602 | 0 | case MVM_ARRAY_U32: |
603 | 0 | if (kind != MVM_reg_int64) |
604 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
605 | 0 | value->i64 = (MVMint64)body->slots.u32[slot]; |
606 | 0 | break; |
607 | 0 | case MVM_ARRAY_U16: |
608 | 0 | if (kind != MVM_reg_int64) |
609 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
610 | 0 | value->i64 = (MVMint64)body->slots.u16[slot]; |
611 | 0 | break; |
612 | 0 | case MVM_ARRAY_U8: |
613 | 0 | if (kind != MVM_reg_int64) |
614 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: pop expected int register"); |
615 | 0 | value->i64 = (MVMint64)body->slots.u8[slot]; |
616 | 0 | break; |
617 | 0 | default: |
618 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
619 | 4.42M | } |
620 | 4.42M | zero_slots(tc, body, slot, slot + 1, repr_data->slot_type); |
621 | 4.42M | exit_single_user(tc, body); |
622 | 4.42M | } |
623 | | |
624 | 39.0k | static void unshift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister value, MVMuint16 kind) { |
625 | 39.0k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
626 | 39.0k | MVMArrayBody *body = (MVMArrayBody *)data; |
627 | 39.0k | |
628 | 39.0k | /* If we don't have room at the beginning of the slots, |
629 | 39.0k | * make some room (8 slots) for unshifting */ |
630 | 39.0k | enter_single_user(tc, body); |
631 | 39.0k | if (body->start < 1) { |
632 | 24.4k | MVMuint64 n = 8; |
633 | 24.4k | MVMuint64 elems = body->elems; |
634 | 24.4k | |
635 | 24.4k | /* grow the array */ |
636 | 24.4k | set_size_internal(tc, body, elems + n, repr_data); |
637 | 24.4k | |
638 | 24.4k | /* move elements and set start */ |
639 | 24.4k | memmove( |
640 | 24.4k | (char *)body->slots.any + n * repr_data->elem_size, |
641 | 24.4k | body->slots.any, |
642 | 24.4k | elems * repr_data->elem_size); |
643 | 24.4k | body->start = n; |
644 | 24.4k | body->elems = elems; |
645 | 24.4k | |
646 | 24.4k | /* clear out beginning elements */ |
647 | 24.4k | zero_slots(tc, body, 0, n, repr_data->slot_type); |
648 | 24.4k | } |
649 | 39.0k | |
650 | 39.0k | /* Now do the unshift */ |
651 | 39.0k | body->start--; |
652 | 39.0k | switch (repr_data->slot_type) { |
653 | 39.0k | case MVM_ARRAY_OBJ: |
654 | 39.0k | if (kind != MVM_reg_obj) |
655 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected object register"); |
656 | 39.0k | MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[body->start], value.o); |
657 | 39.0k | break; |
658 | 1 | case MVM_ARRAY_STR: |
659 | 1 | if (kind != MVM_reg_str) |
660 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected string register"); |
661 | 1 | MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[body->start], value.s); |
662 | 1 | break; |
663 | 1 | case MVM_ARRAY_I64: |
664 | 1 | if (kind != MVM_reg_int64) |
665 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
666 | 1 | body->slots.i64[body->start] = value.i64; |
667 | 1 | break; |
668 | 0 | case MVM_ARRAY_I32: |
669 | 0 | if (kind != MVM_reg_int64) |
670 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
671 | 0 | body->slots.i32[body->start] = (MVMint32)value.i64; |
672 | 0 | break; |
673 | 0 | case MVM_ARRAY_I16: |
674 | 0 | if (kind != MVM_reg_int64) |
675 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
676 | 0 | body->slots.i16[body->start] = (MVMint16)value.i64; |
677 | 0 | break; |
678 | 0 | case MVM_ARRAY_I8: |
679 | 0 | if (kind != MVM_reg_int64) |
680 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
681 | 0 | body->slots.i8[body->start] = (MVMint8)value.i64; |
682 | 0 | break; |
683 | 0 | case MVM_ARRAY_N64: |
684 | 0 | if (kind != MVM_reg_num64) |
685 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected num register"); |
686 | 0 | body->slots.n64[body->start] = value.n64; |
687 | 0 | break; |
688 | 0 | case MVM_ARRAY_N32: |
689 | 0 | if (kind != MVM_reg_num64) |
690 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected num register"); |
691 | 0 | body->slots.n32[body->start] = (MVMnum32)value.n64; |
692 | 0 | break; |
693 | 0 | case MVM_ARRAY_U64: |
694 | 0 | if (kind != MVM_reg_int64) |
695 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
696 | 0 | body->slots.u64[body->start] = (MVMuint64)value.i64; |
697 | 0 | break; |
698 | 0 | case MVM_ARRAY_U32: |
699 | 0 | if (kind != MVM_reg_int64) |
700 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
701 | 0 | body->slots.u32[body->start] = (MVMuint32)value.i64; |
702 | 0 | break; |
703 | 0 | case MVM_ARRAY_U16: |
704 | 0 | if (kind != MVM_reg_int64) |
705 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
706 | 0 | body->slots.u16[body->start] = (MVMuint16)value.i64; |
707 | 0 | break; |
708 | 0 | case MVM_ARRAY_U8: |
709 | 0 | if (kind != MVM_reg_int64) |
710 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: unshift expected int register"); |
711 | 0 | body->slots.u8[body->start] = (MVMuint8)value.i64; |
712 | 0 | break; |
713 | 0 | default: |
714 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
715 | 39.0k | } |
716 | 39.0k | body->elems++; |
717 | 39.0k | exit_single_user(tc, body); |
718 | 39.0k | } |
719 | | |
720 | 15.9k | static void shift(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMRegister *value, MVMuint16 kind) { |
721 | 15.9k | MVMArrayBody *body = (MVMArrayBody *)data; |
722 | 15.9k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
723 | 15.9k | |
724 | 15.9k | if (body->elems < 1) |
725 | 0 | MVM_exception_throw_adhoc(tc, |
726 | 0 | "MVMArray: Can't shift from an empty array"); |
727 | 15.9k | |
728 | 15.9k | enter_single_user(tc, body); |
729 | 15.9k | switch (repr_data->slot_type) { |
730 | 15.9k | case MVM_ARRAY_OBJ: |
731 | 15.9k | if (kind != MVM_reg_obj) |
732 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected object register"); |
733 | 15.9k | value->o = body->slots.o[body->start]; |
734 | 15.9k | break; |
735 | 2 | case MVM_ARRAY_STR: |
736 | 2 | if (kind != MVM_reg_str) |
737 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected string register"); |
738 | 2 | value->s = body->slots.s[body->start]; |
739 | 2 | break; |
740 | 2 | case MVM_ARRAY_I64: |
741 | 2 | if (kind != MVM_reg_int64) |
742 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
743 | 2 | value->i64 = (MVMint64)body->slots.i64[body->start]; |
744 | 2 | break; |
745 | 0 | case MVM_ARRAY_I32: |
746 | 0 | if (kind != MVM_reg_int64) |
747 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
748 | 0 | value->i64 = (MVMint64)body->slots.i32[body->start]; |
749 | 0 | break; |
750 | 0 | case MVM_ARRAY_I16: |
751 | 0 | if (kind != MVM_reg_int64) |
752 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
753 | 0 | value->i64 = (MVMint64)body->slots.i16[body->start]; |
754 | 0 | break; |
755 | 0 | case MVM_ARRAY_I8: |
756 | 0 | if (kind != MVM_reg_int64) |
757 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
758 | 0 | value->i64 = (MVMint64)body->slots.i8[body->start]; |
759 | 0 | break; |
760 | 0 | case MVM_ARRAY_N64: |
761 | 0 | if (kind != MVM_reg_num64) |
762 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected num register"); |
763 | 0 | value->n64 = (MVMnum64)body->slots.n64[body->start]; |
764 | 0 | break; |
765 | 0 | case MVM_ARRAY_N32: |
766 | 0 | if (kind != MVM_reg_num64) |
767 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected num register"); |
768 | 0 | value->n64 = (MVMnum64)body->slots.n32[body->start]; |
769 | 0 | break; |
770 | 0 | case MVM_ARRAY_U64: |
771 | 0 | if (kind != MVM_reg_int64) |
772 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
773 | 0 | value->i64 = (MVMint64)body->slots.u64[body->start]; |
774 | 0 | break; |
775 | 0 | case MVM_ARRAY_U32: |
776 | 0 | if (kind != MVM_reg_int64) |
777 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
778 | 0 | value->i64 = (MVMint64)body->slots.u32[body->start]; |
779 | 0 | break; |
780 | 0 | case MVM_ARRAY_U16: |
781 | 0 | if (kind != MVM_reg_int64) |
782 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
783 | 0 | value->i64 = (MVMint64)body->slots.u16[body->start]; |
784 | 0 | break; |
785 | 0 | case MVM_ARRAY_U8: |
786 | 0 | if (kind != MVM_reg_int64) |
787 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: shift expected int register"); |
788 | 0 | value->i64 = (MVMint64)body->slots.u8[body->start]; |
789 | 0 | break; |
790 | 0 | default: |
791 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
792 | 15.9k | } |
793 | 15.9k | body->start++; |
794 | 15.9k | body->elems--; |
795 | 15.9k | exit_single_user(tc, body); |
796 | 15.9k | } |
797 | | |
798 | 108k | static void copy_elements(MVMThreadContext *tc, MVMObject *src, MVMObject *dest, MVMint64 s_offset, MVMint64 d_offset, MVMint64 elems) { |
799 | 108k | MVMArrayBody *s_body = (MVMArrayBody *)OBJECT_BODY(src); |
800 | 108k | MVMArrayBody *d_body = (MVMArrayBody *)OBJECT_BODY(dest); |
801 | 108k | MVMArrayREPRData *s_repr_data = REPR(src)->ID == MVM_REPR_ID_VMArray |
802 | 108k | ? (MVMArrayREPRData *)STABLE(src)->REPR_data : NULL; |
803 | 108k | MVMArrayREPRData *d_repr_data = REPR(src)->ID == MVM_REPR_ID_VMArray |
804 | 108k | ? (MVMArrayREPRData *)STABLE(dest)->REPR_data : NULL; |
805 | 108k | |
806 | 108k | if (elems > 0) { |
807 | 108k | MVMint64 i; |
808 | 108k | MVMuint16 kind; |
809 | 108k | MVMuint8 d_needs_barrier = dest->header.flags & MVM_CF_SECOND_GEN; |
810 | 108k | if (s_repr_data && d_repr_data |
811 | 108k | && s_repr_data->slot_type == d_repr_data->slot_type |
812 | 108k | && s_repr_data->elem_size == d_repr_data->elem_size |
813 | 108k | && (d_repr_data->slot_type != MVM_ARRAY_OBJ || !d_needs_barrier) |
814 | 108k | && d_repr_data->slot_type != MVM_ARRAY_STR) { |
815 | 108k | /* Optimized for copying from a VMArray with same slot type */ |
816 | 108k | MVMint64 s_start = s_body->start; |
817 | 108k | MVMint64 d_start = d_body->start; |
818 | 108k | memcpy( d_body->slots.u8 + (d_start + d_offset) * d_repr_data->elem_size, |
819 | 108k | s_body->slots.u8 + (s_start + s_offset) * s_repr_data->elem_size, |
820 | 108k | d_repr_data->elem_size * elems |
821 | 108k | ); |
822 | 108k | } |
823 | 172 | else { |
824 | 172 | switch (s_repr_data->slot_type) { |
825 | 172 | case MVM_ARRAY_OBJ: |
826 | 172 | kind = MVM_reg_obj; |
827 | 172 | break; |
828 | 0 | case MVM_ARRAY_STR: |
829 | 0 | kind = MVM_reg_str; |
830 | 0 | break; |
831 | 0 | case MVM_ARRAY_I64: |
832 | 0 | case MVM_ARRAY_I32: |
833 | 0 | case MVM_ARRAY_I16: |
834 | 0 | case MVM_ARRAY_I8: |
835 | 0 | kind = MVM_reg_int64; |
836 | 0 | break; |
837 | 0 | case MVM_ARRAY_N64: |
838 | 0 | case MVM_ARRAY_N32: |
839 | 0 | kind = MVM_reg_num64; |
840 | 0 | break; |
841 | 0 | case MVM_ARRAY_U64: |
842 | 0 | case MVM_ARRAY_U32: |
843 | 0 | case MVM_ARRAY_U16: |
844 | 0 | case MVM_ARRAY_U8: |
845 | 0 | kind = MVM_reg_int64; |
846 | 0 | break; |
847 | 0 | default: |
848 | 0 | abort(); /* never reached, silence compiler warnings */ |
849 | 172 | } |
850 | 643 | for (i = 0; i < elems; i++) { |
851 | 471 | MVMRegister to_copy; |
852 | 471 | REPR(src)->pos_funcs.at_pos(tc, STABLE(src), src, s_body, s_offset + i, &to_copy, kind); |
853 | 471 | bind_pos(tc, STABLE(dest), dest, d_body, d_offset + i, to_copy, kind); |
854 | 471 | } |
855 | 172 | } |
856 | 108k | } |
857 | 108k | } |
858 | | |
859 | 18 | static void aslice(MVMThreadContext *tc, MVMSTable *st, MVMObject *src, void *data, MVMObject *dest, MVMint64 start, MVMint64 end) { |
860 | 18 | MVMArrayBody *s_body = (MVMArrayBody *)data; |
861 | 18 | MVMArrayBody *d_body = (MVMArrayBody *)OBJECT_BODY(dest); |
862 | 18 | MVMArrayREPRData *d_repr_data = REPR(dest)->ID == MVM_REPR_ID_VMArray |
863 | 18 | ? STABLE(dest)->REPR_data : NULL; |
864 | 18 | |
865 | 18 | MVMint64 total_elems = REPR(src)->elems(tc, st, src, s_body); |
866 | 18 | MVMint64 elems; |
867 | 18 | |
868 | 13 | start = start < 0 ? total_elems + start : start; |
869 | 10 | end = end < 0 ? total_elems + end : end; |
870 | 18 | if ( end < start || start < 0 || end < 0 || total_elems <= start || total_elems <= end ) { |
871 | 8 | MVM_exception_throw_adhoc(tc, "MVMArray: Slice index out of bounds"); |
872 | 8 | } |
873 | 18 | |
874 | 18 | elems = end - start + 1; |
875 | 18 | if (d_repr_data) { |
876 | 10 | set_size_internal(tc, d_body, elems, d_repr_data); |
877 | 10 | } |
878 | 18 | |
879 | 18 | copy_elements(tc, src, dest, start, 0, elems); |
880 | 18 | } |
881 | | |
882 | | /* This whole splice optimization can be optimized for the case we have two |
883 | | * MVMArray representation objects. */ |
884 | 135k | static void asplice(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMObject *from, MVMint64 offset, MVMuint64 count) { |
885 | 135k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
886 | 135k | MVMArrayBody *body = (MVMArrayBody *)data; |
887 | 135k | |
888 | 135k | MVMint64 elems0 = body->elems; |
889 | 135k | MVMint64 elems1 = REPR(from)->elems(tc, STABLE(from), from, OBJECT_BODY(from)); |
890 | 135k | MVMint64 start; |
891 | 135k | MVMint64 tail; |
892 | 135k | |
893 | 135k | /* start from end? */ |
894 | 135k | if (offset < 0) { |
895 | 0 | offset += elems0; |
896 | 0 |
|
897 | 0 | if (offset < 0) |
898 | 0 | MVM_exception_throw_adhoc(tc, |
899 | 0 | "MVMArray: Illegal splice offset"); |
900 | 0 | } |
901 | 135k | |
902 | 135k | enter_single_user(tc, body); |
903 | 135k | |
904 | 135k | /* When offset == 0, then we may be able to reduce the memmove |
905 | 135k | * calls and reallocs by adjusting SELF's start, elems0, and |
906 | 135k | * count to better match the incoming splice. In particular, |
907 | 135k | * we're seeking to adjust C<count> to as close to C<elems1> |
908 | 135k | * as we can. */ |
909 | 135k | if (offset == 0) { |
910 | 61.2k | MVMint64 n = elems1 - count; |
911 | 61.2k | start = body->start; |
912 | 61.2k | if (n > start) |
913 | 48.9k | n = start; |
914 | 61.2k | if (n <= -elems0) { |
915 | 56.7k | elems0 = 0; |
916 | 56.7k | count = 0; |
917 | 56.7k | body->start = 0; |
918 | 56.7k | body->elems = elems0; |
919 | 56.7k | } |
920 | 4.52k | else if (n != 0) { |
921 | 0 | elems0 += n; |
922 | 0 | count += n; |
923 | 0 | body->start = start - n; |
924 | 0 | body->elems = elems0; |
925 | 0 | } |
926 | 61.2k | } |
927 | 135k | |
928 | 135k | /* if count == 0 and elems1 == 0, there's nothing left |
929 | 135k | * to copy or remove, so the splice is done! */ |
930 | 135k | if (count == 0 && elems1 == 0) { |
931 | 26.8k | exit_single_user(tc, body); |
932 | 26.8k | return; |
933 | 26.8k | } |
934 | 135k | |
935 | 135k | /* number of elements to right of splice (the "tail") */ |
936 | 108k | tail = elems0 - offset - count; |
937 | 108k | if (tail < 0) |
938 | 1 | tail = 0; |
939 | 108k | |
940 | 108k | else if (tail > 0 && count > elems1) { |
941 | 2 | /* We're shrinking the array, so first move the tail left */ |
942 | 2 | start = body->start; |
943 | 2 | memmove( |
944 | 2 | (char *)body->slots.any + (start + offset + elems1) * repr_data->elem_size, |
945 | 2 | (char *)body->slots.any + (start + offset + count) * repr_data->elem_size, |
946 | 2 | tail * repr_data->elem_size); |
947 | 2 | } |
948 | 108k | |
949 | 108k | /* now resize the array */ |
950 | 108k | set_size_internal(tc, body, offset + elems1 + tail, repr_data); |
951 | 108k | |
952 | 108k | start = body->start; |
953 | 108k | if (tail > 0 && count < elems1) { |
954 | 4.53k | /* The array grew, so move the tail to the right */ |
955 | 4.53k | memmove( |
956 | 4.53k | (char *)body->slots.any + (start + offset + elems1) * repr_data->elem_size, |
957 | 4.53k | (char *)body->slots.any + (start + offset + count) * repr_data->elem_size, |
958 | 4.53k | tail * repr_data->elem_size); |
959 | 4.53k | } |
960 | 108k | exit_single_user(tc, body); |
961 | 108k | |
962 | 108k | |
963 | 108k | /* now copy C<from>'s elements into SELF */ |
964 | 108k | copy_elements(tc, from, root, 0, offset, elems1); |
965 | 108k | } |
966 | | |
967 | 19 | static void at_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister *result, MVMuint16 kind) { |
968 | 19 | if (num_indices != 1) |
969 | 10 | MVM_exception_throw_adhoc(tc, "A dynamic array can only be indexed with a single dimension"); |
970 | 19 | at_pos(tc, st, root, data, indices[0], result, kind); |
971 | 19 | } |
972 | | |
973 | 19 | static void bind_pos_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_indices, MVMint64 *indices, MVMRegister value, MVMuint16 kind) { |
974 | 19 | if (num_indices != 1) |
975 | 10 | MVM_exception_throw_adhoc(tc, "A dynamic array can only be indexed with a single dimension"); |
976 | 19 | bind_pos(tc, st, root, data, indices[0], value, kind); |
977 | 19 | } |
978 | | |
979 | 6 | static void dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 *num_dimensions, MVMint64 **dimensions) { |
980 | 6 | MVMArrayBody *body = (MVMArrayBody *)data; |
981 | 6 | *num_dimensions = 1; |
982 | 6 | *dimensions = (MVMint64 *) &(body->elems); |
983 | 6 | } |
984 | | |
985 | 4 | static void set_dimensions(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMint64 num_dimensions, MVMint64 *dimensions) { |
986 | 4 | if (num_dimensions != 1) |
987 | 3 | MVM_exception_throw_adhoc(tc, "A dynamic array can only have a single dimension"); |
988 | 4 | set_elems(tc, st, root, data, dimensions[0]); |
989 | 4 | } |
990 | | |
991 | 343k | static MVMStorageSpec get_elem_storage_spec(MVMThreadContext *tc, MVMSTable *st) { |
992 | 343k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
993 | 343k | MVMStorageSpec spec; |
994 | 343k | |
995 | 343k | /* initialise storage spec to default values */ |
996 | 343k | spec.bits = 0; |
997 | 343k | spec.align = 0; |
998 | 343k | spec.is_unsigned = 0; |
999 | 343k | |
1000 | 343k | switch (repr_data->slot_type) { |
1001 | 14.6k | case MVM_ARRAY_STR: |
1002 | 14.6k | spec.inlineable = MVM_STORAGE_SPEC_INLINED; |
1003 | 14.6k | spec.boxed_primitive = MVM_STORAGE_SPEC_BP_STR; |
1004 | 14.6k | spec.can_box = MVM_STORAGE_SPEC_CAN_BOX_STR; |
1005 | 14.6k | break; |
1006 | 3 | case MVM_ARRAY_I64: |
1007 | 3 | case MVM_ARRAY_I32: |
1008 | 3 | case MVM_ARRAY_I16: |
1009 | 3 | case MVM_ARRAY_I8: |
1010 | 3 | spec.inlineable = MVM_STORAGE_SPEC_INLINED; |
1011 | 3 | spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT; |
1012 | 3 | spec.can_box = MVM_STORAGE_SPEC_CAN_BOX_INT; |
1013 | 3 | break; |
1014 | 2 | case MVM_ARRAY_N64: |
1015 | 2 | case MVM_ARRAY_N32: |
1016 | 2 | spec.inlineable = MVM_STORAGE_SPEC_INLINED; |
1017 | 2 | spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NUM; |
1018 | 2 | spec.can_box = MVM_STORAGE_SPEC_CAN_BOX_NUM; |
1019 | 2 | break; |
1020 | 0 | case MVM_ARRAY_U64: |
1021 | 0 | case MVM_ARRAY_U32: |
1022 | 0 | case MVM_ARRAY_U16: |
1023 | 0 | case MVM_ARRAY_U8: |
1024 | 0 | spec.inlineable = MVM_STORAGE_SPEC_INLINED; |
1025 | 0 | spec.boxed_primitive = MVM_STORAGE_SPEC_BP_INT; |
1026 | 0 | spec.can_box = MVM_STORAGE_SPEC_CAN_BOX_INT; |
1027 | 0 | spec.is_unsigned = 1; |
1028 | 0 | break; |
1029 | 328k | default: |
1030 | 328k | spec.inlineable = MVM_STORAGE_SPEC_REFERENCE; |
1031 | 328k | spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE; |
1032 | 328k | spec.can_box = 0; |
1033 | 328k | break; |
1034 | 343k | } |
1035 | 343k | return spec; |
1036 | 343k | } |
1037 | | |
1038 | | static AO_t * pos_as_atomic(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, |
1039 | 0 | void *data, MVMint64 index) { |
1040 | 0 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
1041 | 0 | MVMArrayBody *body = (MVMArrayBody *)data; |
1042 | 0 |
|
1043 | 0 | /* Handle negative indexes and require in bounds. */ |
1044 | 0 | if (index < 0) |
1045 | 0 | index += body->elems; |
1046 | 0 | if (index < 0 || index >= body->elems) |
1047 | 0 | MVM_exception_throw_adhoc(tc, "Index out of bounds in atomic operation on array"); |
1048 | 0 |
|
1049 | 0 | if (sizeof(AO_t) == 8 && (repr_data->slot_type == MVM_ARRAY_I64 || |
1050 | 0 | repr_data->slot_type == MVM_ARRAY_U64)) |
1051 | 0 | return (AO_t *)&(body->slots.i64[body->start + index]); |
1052 | 0 | if (sizeof(AO_t) == 4 && (repr_data->slot_type == MVM_ARRAY_I32 || |
1053 | 0 | repr_data->slot_type == MVM_ARRAY_U32)) |
1054 | 0 | return (AO_t *)&(body->slots.i32[body->start + index]); |
1055 | 0 | MVM_exception_throw_adhoc(tc, |
1056 | 0 | "Can only do integer atomic operation on native integer array element of atomic size"); |
1057 | 0 | } |
1058 | | |
1059 | | static AO_t * pos_as_atomic_multidim(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, |
1060 | 0 | void *data, MVMint64 num_indices, MVMint64 *indices) { |
1061 | 0 | if (num_indices != 1) |
1062 | 0 | MVM_exception_throw_adhoc(tc, |
1063 | 0 | "A dynamic array can only be indexed with a single dimension"); |
1064 | 0 | return pos_as_atomic(tc, st, root, data, indices[0]); |
1065 | 0 | } |
1066 | | |
1067 | | /* Compose the representation. */ |
1068 | 904 | static void spec_to_repr_data(MVMThreadContext *tc, MVMArrayREPRData *repr_data, const MVMStorageSpec *spec) { |
1069 | 904 | switch (spec->boxed_primitive) { |
1070 | 615 | case MVM_STORAGE_SPEC_BP_INT: |
1071 | 615 | if (spec->is_unsigned) { |
1072 | 164 | switch (spec->bits) { |
1073 | 0 | case 64: |
1074 | 0 | repr_data->slot_type = MVM_ARRAY_U64; |
1075 | 0 | repr_data->elem_size = sizeof(MVMuint64); |
1076 | 0 | break; |
1077 | 6 | case 32: |
1078 | 6 | repr_data->slot_type = MVM_ARRAY_U32; |
1079 | 6 | repr_data->elem_size = sizeof(MVMuint32); |
1080 | 6 | break; |
1081 | 1 | case 16: |
1082 | 1 | repr_data->slot_type = MVM_ARRAY_U16; |
1083 | 1 | repr_data->elem_size = sizeof(MVMuint16); |
1084 | 1 | break; |
1085 | 157 | case 8: |
1086 | 157 | repr_data->slot_type = MVM_ARRAY_U8; |
1087 | 157 | repr_data->elem_size = sizeof(MVMuint8); |
1088 | 157 | break; |
1089 | 0 | case 4: |
1090 | 0 | repr_data->slot_type = MVM_ARRAY_U4; |
1091 | 0 | repr_data->elem_size = 0; |
1092 | 0 | break; |
1093 | 0 | case 2: |
1094 | 0 | repr_data->slot_type = MVM_ARRAY_U2; |
1095 | 0 | repr_data->elem_size = 0; |
1096 | 0 | break; |
1097 | 0 | case 1: |
1098 | 0 | repr_data->slot_type = MVM_ARRAY_U1; |
1099 | 0 | repr_data->elem_size = 0; |
1100 | 0 | break; |
1101 | 0 | default: |
1102 | 0 | MVM_exception_throw_adhoc(tc, |
1103 | 0 | "MVMArray: Unsupported uint size"); |
1104 | 164 | } |
1105 | 164 | } |
1106 | 451 | else { |
1107 | 451 | switch (spec->bits) { |
1108 | 449 | case 64: |
1109 | 449 | repr_data->slot_type = MVM_ARRAY_I64; |
1110 | 449 | repr_data->elem_size = sizeof(MVMint64); |
1111 | 449 | break; |
1112 | 0 | case 32: |
1113 | 0 | repr_data->slot_type = MVM_ARRAY_I32; |
1114 | 0 | repr_data->elem_size = sizeof(MVMint32); |
1115 | 0 | break; |
1116 | 0 | case 16: |
1117 | 0 | repr_data->slot_type = MVM_ARRAY_I16; |
1118 | 0 | repr_data->elem_size = sizeof(MVMint16); |
1119 | 0 | break; |
1120 | 2 | case 8: |
1121 | 2 | repr_data->slot_type = MVM_ARRAY_I8; |
1122 | 2 | repr_data->elem_size = sizeof(MVMint8); |
1123 | 2 | break; |
1124 | 0 | case 4: |
1125 | 0 | repr_data->slot_type = MVM_ARRAY_I4; |
1126 | 0 | repr_data->elem_size = 0; |
1127 | 0 | break; |
1128 | 0 | case 2: |
1129 | 0 | repr_data->slot_type = MVM_ARRAY_I2; |
1130 | 0 | repr_data->elem_size = 0; |
1131 | 0 | break; |
1132 | 0 | case 1: |
1133 | 0 | repr_data->slot_type = MVM_ARRAY_I1; |
1134 | 0 | repr_data->elem_size = 0; |
1135 | 0 | break; |
1136 | 0 | default: |
1137 | 0 | MVM_exception_throw_adhoc(tc, |
1138 | 0 | "MVMArray: Unsupported int size"); |
1139 | 451 | } |
1140 | 451 | } |
1141 | 615 | break; |
1142 | 145 | case MVM_STORAGE_SPEC_BP_NUM: |
1143 | 145 | switch (spec->bits) { |
1144 | 145 | case 64: |
1145 | 145 | repr_data->slot_type = MVM_ARRAY_N64; |
1146 | 145 | repr_data->elem_size = sizeof(MVMnum64); |
1147 | 145 | break; |
1148 | 0 | case 32: |
1149 | 0 | repr_data->slot_type = MVM_ARRAY_N32; |
1150 | 0 | repr_data->elem_size = sizeof(MVMnum32); |
1151 | 0 | break; |
1152 | 0 | default: |
1153 | 0 | MVM_exception_throw_adhoc(tc, |
1154 | 0 | "MVMArray: Unsupported num size"); |
1155 | 145 | } |
1156 | 145 | break; |
1157 | 144 | case MVM_STORAGE_SPEC_BP_STR: |
1158 | 144 | repr_data->slot_type = MVM_ARRAY_STR; |
1159 | 144 | repr_data->elem_size = sizeof(MVMString *); |
1160 | 144 | break; |
1161 | 904 | } |
1162 | 904 | } |
1163 | 599 | static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { |
1164 | 599 | MVMStringConsts str_consts = tc->instance->str_consts; |
1165 | 599 | MVMArrayREPRData * const repr_data = (MVMArrayREPRData *)st->REPR_data; |
1166 | 599 | |
1167 | 599 | MVMObject *info = MVM_repr_at_key_o(tc, info_hash, str_consts.array); |
1168 | 599 | if (!MVM_is_null(tc, info)) { |
1169 | 598 | MVMObject *type = MVM_repr_at_key_o(tc, info, str_consts.type); |
1170 | 598 | if (!MVM_is_null(tc, type)) { |
1171 | 598 | const MVMStorageSpec *spec = REPR(type)->get_storage_spec(tc, STABLE(type)); |
1172 | 598 | MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type); |
1173 | 598 | spec_to_repr_data(tc, repr_data, spec); |
1174 | 598 | } |
1175 | 598 | } |
1176 | 599 | } |
1177 | | |
1178 | | /* Set the size of the STable. */ |
1179 | 450 | static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) { |
1180 | 450 | st->size = sizeof(MVMArray); |
1181 | 450 | } |
1182 | | |
1183 | | /* Serializes the REPR data. */ |
1184 | 1 | static void serialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationWriter *writer) { |
1185 | 1 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)st->REPR_data; |
1186 | 1 | MVM_serialization_write_ref(tc, writer, repr_data->elem_type); |
1187 | 1 | } |
1188 | | |
1189 | | /* Deserializes representation data. */ |
1190 | 450 | static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerializationReader *reader) { |
1191 | 450 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *)MVM_malloc(sizeof(MVMArrayREPRData)); |
1192 | 450 | |
1193 | 450 | MVMObject *type = MVM_serialization_read_ref(tc, reader); |
1194 | 450 | MVM_ASSIGN_REF(tc, &(st->header), repr_data->elem_type, type); |
1195 | 450 | repr_data->slot_type = MVM_ARRAY_OBJ; |
1196 | 450 | repr_data->elem_size = sizeof(MVMObject *); |
1197 | 450 | st->REPR_data = repr_data; |
1198 | 450 | |
1199 | 450 | if (type) { |
1200 | 306 | const MVMStorageSpec *spec; |
1201 | 306 | MVM_serialization_force_stable(tc, reader, STABLE(type)); |
1202 | 306 | spec = REPR(type)->get_storage_spec(tc, STABLE(type)); |
1203 | 306 | spec_to_repr_data(tc, repr_data, spec); |
1204 | 306 | } |
1205 | 450 | } |
1206 | | |
1207 | 665k | static void deserialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, void *data, MVMSerializationReader *reader) { |
1208 | 665k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data; |
1209 | 665k | MVMArrayBody *body = (MVMArrayBody *)data; |
1210 | 665k | MVMint64 i; |
1211 | 665k | |
1212 | 665k | body->elems = MVM_serialization_read_int(tc, reader); |
1213 | 665k | body->ssize = body->elems; |
1214 | 665k | if (body->ssize) |
1215 | 601k | body->slots.any = MVM_malloc(body->ssize * repr_data->elem_size); |
1216 | 665k | |
1217 | 3.58M | for (i = 0; i < body->elems; i++) { |
1218 | 2.92M | switch (repr_data->slot_type) { |
1219 | 2.91M | case MVM_ARRAY_OBJ: |
1220 | 2.91M | MVM_ASSIGN_REF(tc, &(root->header), body->slots.o[i], MVM_serialization_read_ref(tc, reader)); |
1221 | 2.91M | break; |
1222 | 0 | case MVM_ARRAY_STR: |
1223 | 0 | MVM_ASSIGN_REF(tc, &(root->header), body->slots.s[i], MVM_serialization_read_str(tc, reader)); |
1224 | 0 | break; |
1225 | 8.11k | case MVM_ARRAY_I64: |
1226 | 8.11k | body->slots.i64[i] = MVM_serialization_read_int(tc, reader); |
1227 | 8.11k | break; |
1228 | 0 | case MVM_ARRAY_I32: |
1229 | 0 | body->slots.i32[i] = (MVMint32)MVM_serialization_read_int(tc, reader); |
1230 | 0 | break; |
1231 | 0 | case MVM_ARRAY_I16: |
1232 | 0 | body->slots.i16[i] = (MVMint16)MVM_serialization_read_int(tc, reader); |
1233 | 0 | break; |
1234 | 0 | case MVM_ARRAY_I8: |
1235 | 0 | body->slots.i8[i] = (MVMint8)MVM_serialization_read_int(tc, reader); |
1236 | 0 | break; |
1237 | 0 | case MVM_ARRAY_U64: |
1238 | 0 | body->slots.i64[i] = MVM_serialization_read_int(tc, reader); |
1239 | 0 | break; |
1240 | 0 | case MVM_ARRAY_U32: |
1241 | 0 | body->slots.i32[i] = (MVMuint32)MVM_serialization_read_int(tc, reader); |
1242 | 0 | break; |
1243 | 0 | case MVM_ARRAY_U16: |
1244 | 0 | body->slots.i16[i] = (MVMuint16)MVM_serialization_read_int(tc, reader); |
1245 | 0 | break; |
1246 | 0 | case MVM_ARRAY_U8: |
1247 | 0 | body->slots.i8[i] = (MVMuint8)MVM_serialization_read_int(tc, reader); |
1248 | 0 | break; |
1249 | 3 | case MVM_ARRAY_N64: |
1250 | 3 | body->slots.n64[i] = MVM_serialization_read_num(tc, reader); |
1251 | 3 | break; |
1252 | 0 | case MVM_ARRAY_N32: |
1253 | 0 | body->slots.n32[i] = (MVMnum32)MVM_serialization_read_num(tc, reader); |
1254 | 0 | break; |
1255 | 0 | default: |
1256 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
1257 | 2.92M | } |
1258 | 2.92M | } |
1259 | 665k | } |
1260 | | |
1261 | 188 | static void serialize(MVMThreadContext *tc, MVMSTable *st, void *data, MVMSerializationWriter *writer) { |
1262 | 188 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data; |
1263 | 188 | MVMArrayBody *body = (MVMArrayBody *)data; |
1264 | 188 | MVMint64 i; |
1265 | 188 | |
1266 | 188 | MVM_serialization_write_int(tc, writer, body->elems); |
1267 | 1.54k | for (i = 0; i < body->elems; i++) { |
1268 | 1.35k | switch (repr_data->slot_type) { |
1269 | 1.35k | case MVM_ARRAY_OBJ: |
1270 | 1.35k | MVM_serialization_write_ref(tc, writer, body->slots.o[body->start + i]); |
1271 | 1.35k | break; |
1272 | 0 | case MVM_ARRAY_STR: |
1273 | 0 | MVM_serialization_write_str(tc, writer, body->slots.s[body->start + i]); |
1274 | 0 | break; |
1275 | 0 | case MVM_ARRAY_I64: |
1276 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i64[body->start + i]); |
1277 | 0 | break; |
1278 | 0 | case MVM_ARRAY_I32: |
1279 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i32[body->start + i]); |
1280 | 0 | break; |
1281 | 0 | case MVM_ARRAY_I16: |
1282 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i16[body->start + i]); |
1283 | 0 | break; |
1284 | 0 | case MVM_ARRAY_I8: |
1285 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.i8[body->start + i]); |
1286 | 0 | break; |
1287 | 0 | case MVM_ARRAY_U64: |
1288 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u64[body->start + i]); |
1289 | 0 | break; |
1290 | 0 | case MVM_ARRAY_U32: |
1291 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u32[body->start + i]); |
1292 | 0 | break; |
1293 | 0 | case MVM_ARRAY_U16: |
1294 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u16[body->start + i]); |
1295 | 0 | break; |
1296 | 0 | case MVM_ARRAY_U8: |
1297 | 0 | MVM_serialization_write_int(tc, writer, (MVMint64)body->slots.u8[body->start + i]); |
1298 | 0 | break; |
1299 | 3 | case MVM_ARRAY_N64: |
1300 | 3 | MVM_serialization_write_num(tc, writer, (MVMnum64)body->slots.n64[body->start + i]); |
1301 | 3 | break; |
1302 | 0 | case MVM_ARRAY_N32: |
1303 | 0 | MVM_serialization_write_num(tc, writer, (MVMnum64)body->slots.n32[body->start + i]); |
1304 | 0 | break; |
1305 | 0 | default: |
1306 | 0 | MVM_exception_throw_adhoc(tc, "MVMArray: Unhandled slot type"); |
1307 | 1.35k | } |
1308 | 1.35k | } |
1309 | 188 | } |
1310 | | |
1311 | | /* Bytecode specialization for this REPR. */ |
1312 | 21.6k | static void spesh(MVMThreadContext *tc, MVMSTable *st, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) { |
1313 | 21.6k | switch (ins->info->opcode) { |
1314 | 3.63k | case MVM_OP_create: { |
1315 | 3.63k | if (!(st->mode_flags & MVM_FINALIZE_TYPE)) { |
1316 | 3.63k | MVMSpeshOperand target = ins->operands[0]; |
1317 | 3.63k | MVMSpeshOperand type = ins->operands[1]; |
1318 | 3.63k | ins->info = MVM_op_get_op(MVM_OP_sp_fastcreate); |
1319 | 3.63k | ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand)); |
1320 | 3.63k | ins->operands[0] = target; |
1321 | 3.63k | ins->operands[1].lit_i16 = sizeof(MVMArray); |
1322 | 3.63k | ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)st); |
1323 | 3.63k | MVM_spesh_get_facts(tc, g, type)->usages--; |
1324 | 3.63k | } |
1325 | 3.63k | break; |
1326 | 3.63k | } |
1327 | 21.6k | } |
1328 | 21.6k | } |
1329 | | |
1330 | | /* Calculates the non-GC-managed memory we hold on to. */ |
1331 | 144k | static MVMuint64 unmanaged_size(MVMThreadContext *tc, MVMSTable *st, void *data) { |
1332 | 144k | MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data; |
1333 | 144k | MVMArrayBody *body = (MVMArrayBody *)data; |
1334 | 144k | return body->ssize * repr_data->elem_size; |
1335 | 144k | } |
1336 | | |
1337 | 0 | static void describe_refs (MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSTable *st, void *data) { |
1338 | 0 | MVMArrayREPRData *repr_data = (MVMArrayREPRData *) st->REPR_data; |
1339 | 0 | MVMArrayBody *body = (MVMArrayBody *)data; |
1340 | 0 | MVMuint64 elems = body->elems; |
1341 | 0 | MVMuint64 start = body->start; |
1342 | 0 | MVMuint64 i = 0; |
1343 | 0 |
|
1344 | 0 | switch (repr_data->slot_type) { |
1345 | 0 | case MVM_ARRAY_OBJ: { |
1346 | 0 | MVMObject **slots = body->slots.o; |
1347 | 0 | slots += start; |
1348 | 0 | while (i < elems) { |
1349 | 0 | MVM_profile_heap_add_collectable_rel_idx(tc, ss, |
1350 | 0 | (MVMCollectable *)slots[i], i); |
1351 | 0 | i++; |
1352 | 0 | } |
1353 | 0 | break; |
1354 | 0 | } |
1355 | 0 | case MVM_ARRAY_STR: { |
1356 | 0 | MVMString **slots = body->slots.s; |
1357 | 0 | slots += start; |
1358 | 0 | while (i < elems) { |
1359 | 0 | MVM_profile_heap_add_collectable_rel_idx(tc, ss, |
1360 | 0 | (MVMCollectable *)slots[i], i); |
1361 | 0 | i++; |
1362 | 0 | } |
1363 | 0 | break; |
1364 | 0 | } |
1365 | 0 | } |
1366 | 0 | } |
1367 | | |
1368 | | /* Initializes the representation. */ |
1369 | 144 | const MVMREPROps * MVMArray_initialize(MVMThreadContext *tc) { |
1370 | 144 | return &VMArray_this_repr; |
1371 | 144 | } |
1372 | | |
1373 | | static const MVMREPROps VMArray_this_repr = { |
1374 | | type_object_for, |
1375 | | MVM_gc_allocate_object, |
1376 | | NULL, /* initialize */ |
1377 | | copy_to, |
1378 | | MVM_REPR_DEFAULT_ATTR_FUNCS, |
1379 | | MVM_REPR_DEFAULT_BOX_FUNCS, |
1380 | | { |
1381 | | at_pos, |
1382 | | bind_pos, |
1383 | | set_elems, |
1384 | | push, |
1385 | | pop, |
1386 | | unshift, |
1387 | | shift, |
1388 | | aslice, |
1389 | | asplice, |
1390 | | at_pos_multidim, |
1391 | | bind_pos_multidim, |
1392 | | dimensions, |
1393 | | set_dimensions, |
1394 | | get_elem_storage_spec, |
1395 | | pos_as_atomic, |
1396 | | pos_as_atomic_multidim |
1397 | | }, /* pos_funcs */ |
1398 | | MVM_REPR_DEFAULT_ASS_FUNCS, |
1399 | | elems, |
1400 | | get_storage_spec, |
1401 | | NULL, /* change_type */ |
1402 | | serialize, |
1403 | | deserialize, |
1404 | | serialize_repr_data, |
1405 | | deserialize_repr_data, |
1406 | | deserialize_stable_size, |
1407 | | gc_mark, |
1408 | | gc_free, |
1409 | | NULL, /* gc_cleanup */ |
1410 | | gc_mark_repr_data, |
1411 | | gc_free_repr_data, |
1412 | | compose, |
1413 | | spesh, |
1414 | | "VMArray", /* name */ |
1415 | | MVM_REPR_ID_VMArray, |
1416 | | unmanaged_size, |
1417 | | describe_refs, |
1418 | | }; |