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