/home/travis/build/MoarVM/MoarVM/src/6model/reprs/MVMStaticFrame.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 MVMStaticFrame_this_repr; |
5 | | |
6 | | /* Invocation protocol handler. */ |
7 | 0 | static void invoke_handler(MVMThreadContext *tc, MVMObject *invokee, MVMCallsite *callsite, MVMRegister *args) { |
8 | 0 | MVM_exception_throw_adhoc(tc, "Cannot invoke static frame object"); |
9 | 0 | } |
10 | | |
11 | | /* Creates a new type object of this representation, and associates it with |
12 | | * the given HOW. Also sets the invocation protocol handler in the STable. */ |
13 | 130 | static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) { |
14 | 130 | MVMSTable *st = MVM_gc_allocate_stable(tc, &MVMStaticFrame_this_repr, HOW); |
15 | 130 | |
16 | 130 | MVMROOT(tc, st, { |
17 | 130 | MVMObject *obj = MVM_gc_allocate_type_object(tc, st); |
18 | 130 | MVM_ASSIGN_REF(tc, &(st->header), st->WHAT, obj); |
19 | 130 | st->invoke = invoke_handler; |
20 | 130 | st->size = sizeof(MVMStaticFrame); |
21 | 130 | }); |
22 | 130 | |
23 | 130 | return st->WHAT; |
24 | 130 | } |
25 | | |
26 | | /* Copies the body of one object to another. */ |
27 | 1.50k | static void copy_to(MVMThreadContext *tc, MVMSTable *st, void *src, MVMObject *dest_root, void *dest) { |
28 | 1.50k | MVMStaticFrameBody *src_body = (MVMStaticFrameBody *)src; |
29 | 1.50k | MVMStaticFrameBody *dest_body = (MVMStaticFrameBody *)dest; |
30 | 1.50k | |
31 | 1.50k | if (!src_body->fully_deserialized) |
32 | 0 | MVM_exception_throw_adhoc(tc, "Can only clone a fully deserialized MVMFrame"); |
33 | 1.50k | |
34 | 1.50k | dest_body->orig_bytecode = src_body->orig_bytecode; |
35 | 1.50k | dest_body->bytecode_size = src_body->bytecode_size; |
36 | 1.50k | if (src_body->bytecode == src_body->orig_bytecode) { |
37 | 1.50k | /* Easy - the source MVMStaticFrameBody doesn't own the memory. */ |
38 | 1.50k | dest_body->bytecode = src_body->bytecode; |
39 | 1.50k | } |
40 | 0 | else { |
41 | 0 | /* We're going to need to make a copy, in case the source object gets |
42 | 0 | GC'd before we do, and so they free memory we point to. */ |
43 | 0 | /* If this gets to be a resource hog, then implement something more |
44 | 0 | sophisticated. The easiest thing would be to bump the allocated size |
45 | 0 | and value stored in bytecode by sizeof(MVMuint64), and use the extra |
46 | 0 | space to store a reference count. */ |
47 | 0 | dest_body->bytecode = MVM_malloc(src_body->bytecode_size); |
48 | 0 | memcpy(dest_body->bytecode, src_body->bytecode, src_body->bytecode_size); |
49 | 0 | } |
50 | 1.50k | |
51 | 1.50k | MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->cu, src_body->cu); |
52 | 1.50k | MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->cuuid, src_body->cuuid); |
53 | 1.50k | MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->name, src_body->name); |
54 | 1.50k | MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->static_code, src_body->static_code); |
55 | 1.50k | |
56 | 1.50k | dest_body->num_locals = src_body->num_locals; |
57 | 1.50k | dest_body->num_lexicals = src_body->num_lexicals; |
58 | 1.50k | { |
59 | 1.50k | MVMuint16 *local_types = MVM_malloc(sizeof(MVMuint16) * src_body->num_locals); |
60 | 1.50k | MVMuint16 *lexical_types = MVM_malloc(sizeof(MVMuint16) * src_body->num_lexicals); |
61 | 1.50k | memcpy(local_types, src_body->local_types, sizeof(MVMuint16) * src_body->num_locals); |
62 | 1.50k | memcpy(lexical_types, src_body->lexical_types, sizeof(MVMuint16) * src_body->num_lexicals); |
63 | 1.50k | dest_body->local_types = local_types; |
64 | 1.50k | dest_body->lexical_types = lexical_types; |
65 | 1.50k | } |
66 | 1.50k | { |
67 | 1.50k | MVMLexicalRegistry *current, *tmp; |
68 | 1.50k | unsigned bucket_tmp; |
69 | 1.50k | |
70 | 1.50k | /* NOTE: if we really wanted to, we could avoid rehashing... */ |
71 | 1.50k | HASH_ITER(hash_handle, src_body->lexical_names, current, tmp, bucket_tmp) { |
72 | 0 | MVMLexicalRegistry *new_entry = MVM_malloc(sizeof(MVMLexicalRegistry)); |
73 | 0 | /* don't need to clone the string */ |
74 | 0 | MVM_ASSIGN_REF(tc, &(dest_root->header), new_entry->key, current->key); |
75 | 0 | new_entry->value = current->value; |
76 | 0 | MVM_HASH_BIND(tc, dest_body->lexical_names, current->key, new_entry); |
77 | 0 | } |
78 | 1.50k | } |
79 | 1.50k | |
80 | 1.50k | /* Static environment needs to be copied, and any objects WB'd. */ |
81 | 1.50k | if (src_body->env_size) { |
82 | 0 | MVMuint16 *type_map = src_body->lexical_types; |
83 | 0 | MVMuint16 count = src_body->num_lexicals; |
84 | 0 | MVMuint16 i; |
85 | 0 |
|
86 | 0 | dest_body->static_env = MVM_malloc(src_body->env_size); |
87 | 0 | memcpy(dest_body->static_env, src_body->static_env, src_body->env_size); |
88 | 0 | dest_body->static_env_flags = MVM_malloc(src_body->num_lexicals); |
89 | 0 | memcpy(dest_body->static_env_flags, src_body->static_env_flags, src_body->num_lexicals); |
90 | 0 |
|
91 | 0 | for (i = 0; i < count; i++) { |
92 | 0 | if (type_map[i] == MVM_reg_str) { |
93 | 0 | MVM_gc_write_barrier(tc, (MVMCollectable *)dest_root, (MVMCollectable *)dest_body->static_env[i].s); |
94 | 0 | } |
95 | 0 | else if (type_map[i] == MVM_reg_obj) { |
96 | 0 | MVM_gc_write_barrier(tc, (MVMCollectable *)dest_root, (MVMCollectable *)dest_body->static_env[i].o); |
97 | 0 | } |
98 | 0 | } |
99 | 0 | } |
100 | 1.50k | dest_body->env_size = src_body->env_size; |
101 | 1.50k | dest_body->work_size = src_body->work_size; |
102 | 1.50k | |
103 | 1.50k | if (src_body->outer) |
104 | 1.50k | MVM_ASSIGN_REF(tc, &(dest_root->header), dest_body->outer, src_body->outer); |
105 | 1.50k | |
106 | 1.50k | dest_body->num_handlers = src_body->num_handlers; |
107 | 1.50k | dest_body->handlers = MVM_malloc(src_body->num_handlers * sizeof(MVMFrameHandler)); |
108 | 1.50k | memcpy(dest_body->handlers, src_body->handlers, src_body->num_handlers * sizeof(MVMFrameHandler)); |
109 | 1.50k | dest_body->instrumentation_level = 0; |
110 | 1.50k | dest_body->pool_index = src_body->pool_index; |
111 | 1.50k | dest_body->num_annotations = src_body->num_annotations; |
112 | 1.50k | dest_body->annotations_data = src_body->annotations_data; |
113 | 1.50k | dest_body->fully_deserialized = 1; |
114 | 1.50k | } |
115 | | |
116 | | /* Adds held objects to the GC worklist. */ |
117 | 8.73k | static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data, MVMGCWorklist *worklist) { |
118 | 8.73k | MVMStaticFrameBody *body = (MVMStaticFrameBody *)data; |
119 | 8.73k | MVMLexicalRegistry *current, *tmp; |
120 | 8.73k | unsigned bucket_tmp; |
121 | 8.73k | |
122 | 8.73k | /* mvmobjects */ |
123 | 8.73k | MVM_gc_worklist_add(tc, worklist, &body->cu); |
124 | 8.73k | MVM_gc_worklist_add(tc, worklist, &body->cuuid); |
125 | 8.73k | MVM_gc_worklist_add(tc, worklist, &body->name); |
126 | 8.73k | MVM_gc_worklist_add(tc, worklist, &body->outer); |
127 | 8.73k | MVM_gc_worklist_add(tc, worklist, &body->static_code); |
128 | 8.73k | |
129 | 8.73k | /* If it's not fully deserialized, none of the following can apply. */ |
130 | 8.73k | if (!body->fully_deserialized) |
131 | 0 | return; |
132 | 8.73k | |
133 | 8.73k | /* lexical names hash keys */ |
134 | 8.73k | HASH_ITER(hash_handle, body->lexical_names, current, tmp, bucket_tmp) { |
135 | 983 | MVM_gc_worklist_add(tc, worklist, ¤t->hash_handle.key); |
136 | 983 | MVM_gc_worklist_add(tc, worklist, ¤t->key); |
137 | 983 | } |
138 | 8.73k | |
139 | 8.73k | /* static env */ |
140 | 8.73k | if (body->static_env) { |
141 | 5.18k | MVMuint16 *type_map = body->lexical_types; |
142 | 5.18k | MVMuint16 count = body->num_lexicals; |
143 | 5.18k | MVMuint16 i; |
144 | 6.16k | for (i = 0; i < count; i++) |
145 | 983 | if (type_map[i] == MVM_reg_str || type_map[i] == MVM_reg_obj) |
146 | 908 | MVM_gc_worklist_add(tc, worklist, &body->static_env[i].o); |
147 | 5.18k | } |
148 | 8.73k | |
149 | 8.73k | /* Spesh slots. */ |
150 | 8.73k | if (body->num_spesh_candidates) { |
151 | 5.17k | MVMint32 i, j; |
152 | 15.0k | for (i = 0; i < body->num_spesh_candidates; i++) { |
153 | 25.3k | for (j = 0; j < body->spesh_candidates[i].num_guards; j++) |
154 | 15.4k | MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].guards[j].match); |
155 | 84.5k | for (j = 0; j < body->spesh_candidates[i].num_spesh_slots; j++) |
156 | 74.7k | MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].spesh_slots[j]); |
157 | 9.82k | if (body->spesh_candidates[i].log_slots) |
158 | 67.9k | for (j = 0; j < body->spesh_candidates[i].num_log_slots * MVM_SPESH_LOG_RUNS; j++) |
159 | 66.3k | MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].log_slots[j]); |
160 | 12.4k | for (j = 0; j < body->spesh_candidates[i].num_inlines; j++) |
161 | 2.67k | MVM_gc_worklist_add(tc, worklist, &body->spesh_candidates[i].inlines[j].code); |
162 | 9.82k | if (body->spesh_candidates[i].sg) |
163 | 1.97k | MVM_spesh_graph_mark(tc, body->spesh_candidates[i].sg, worklist); |
164 | 9.82k | } |
165 | 5.17k | } |
166 | 8.73k | } |
167 | | |
168 | | /* Called by the VM in order to free memory associated with this object. */ |
169 | 0 | static void gc_free(MVMThreadContext *tc, MVMObject *obj) { |
170 | 0 | MVMStaticFrame *sf = (MVMStaticFrame *)obj; |
171 | 0 | MVMStaticFrameBody *body = &sf->body; |
172 | 0 | MVMint32 i; |
173 | 0 | if (body->orig_bytecode != body->bytecode) { |
174 | 0 | MVM_free(body->bytecode); |
175 | 0 | body->bytecode = body->orig_bytecode; |
176 | 0 | } |
177 | 0 |
|
178 | 0 |
|
179 | 0 | /* If it's not fully deserialized, none of the following can apply. */ |
180 | 0 | if (!body->fully_deserialized) |
181 | 0 | return; |
182 | 0 | MVM_free(body->handlers); |
183 | 0 | MVM_free(body->work_initial); |
184 | 0 | MVM_free(body->static_env); |
185 | 0 | MVM_free(body->static_env_flags); |
186 | 0 | MVM_free(body->local_types); |
187 | 0 | MVM_free(body->lexical_types); |
188 | 0 | MVM_free(body->lexical_names_list); |
189 | 0 | MVM_HASH_DESTROY(hash_handle, MVMLexicalRegistry, body->lexical_names); |
190 | 0 |
|
191 | 0 | for (i = 0; i < body->num_spesh_candidates; i++) |
192 | 0 | MVM_spesh_candidate_destroy(tc, &body->spesh_candidates[i]); |
193 | 0 | MVM_free(body->spesh_candidates); |
194 | 0 | } |
195 | | |
196 | | static const MVMStorageSpec storage_spec = { |
197 | | MVM_STORAGE_SPEC_REFERENCE, /* inlineable */ |
198 | | 0, /* bits */ |
199 | | 0, /* align */ |
200 | | MVM_STORAGE_SPEC_BP_NONE, /* boxed_primitive */ |
201 | | 0, /* can_box */ |
202 | | 0, /* is_unsigned */ |
203 | | }; |
204 | | |
205 | | |
206 | | /* Gets the storage specification for this representation. */ |
207 | 0 | static const MVMStorageSpec * get_storage_spec(MVMThreadContext *tc, MVMSTable *st) { |
208 | 0 | /* XXX in the end we'll support inlining of this... */ |
209 | 0 | return &storage_spec; |
210 | 0 | } |
211 | | |
212 | | /* Compose the representation. */ |
213 | 0 | static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info) { |
214 | 0 | /* Nothing to do for this REPR. */ |
215 | 0 | } |
216 | | |
217 | | /* Calculates the non-GC-managed memory we hold on to. */ |
218 | 1.16k | static MVMuint64 unmanaged_size(MVMThreadContext *tc, MVMSTable *st, void *data) { |
219 | 1.16k | MVMStaticFrameBody *body = (MVMStaticFrameBody *)data; |
220 | 1.16k | MVMuint64 size = 0; |
221 | 1.16k | |
222 | 1.16k | if (body->fully_deserialized) { |
223 | 1.16k | MVMuint32 spesh_idx; |
224 | 1.16k | |
225 | 1.16k | size += sizeof(MVMuint16) * body->num_locals; |
226 | 1.16k | size += sizeof(MVMuint16) * body->num_lexicals; |
227 | 1.16k | |
228 | 1.16k | if (body->bytecode != body->orig_bytecode) |
229 | 0 | size += body->bytecode_size; |
230 | 1.16k | |
231 | 1.16k | size += sizeof(MVMLexicalRegistry *) * body->num_lexicals; |
232 | 1.16k | |
233 | 1.16k | size += sizeof(MVMLexicalRegistry) * HASH_CNT(hash_handle, body->lexical_names); |
234 | 1.16k | |
235 | 1.16k | size += sizeof(MVMFrameHandler) * body->num_handlers; |
236 | 1.16k | |
237 | 1.16k | /* XXX i *think* the annotations are just a pointer into the serialized |
238 | 1.16k | * blob, so don't actually count it towards the unmanaged size. */ |
239 | 1.16k | /* |
240 | 1.16k | size += sizeof(MVMuint8) * body->num_annotations |
241 | 1.16k | */ |
242 | 1.16k | size += body->env_size; /* static_env */ |
243 | 1.16k | size += body->num_lexicals; /* static_env_flags */ |
244 | 1.16k | |
245 | 1.16k | for (spesh_idx = 0; spesh_idx < body->num_spesh_candidates; spesh_idx++) { |
246 | 0 | MVMSpeshCandidate *cand = &body->spesh_candidates[spesh_idx]; |
247 | 0 | size += sizeof(MVMSpeshGuard) * cand->num_guards; |
248 | 0 |
|
249 | 0 | size += cand->bytecode_size; |
250 | 0 |
|
251 | 0 | size += sizeof(MVMFrameHandler) * cand->num_handlers; |
252 | 0 |
|
253 | 0 | size += sizeof(MVMCollectable *) * cand->num_spesh_slots; |
254 | 0 |
|
255 | 0 | size += sizeof(MVMint32) * cand->num_deopts; |
256 | 0 |
|
257 | 0 | if (cand->sg) |
258 | 0 | /* XXX we ought to descend into the speshgraph, too. */ |
259 | 0 | size += sizeof(MVMSpeshGraph); |
260 | 0 |
|
261 | 0 | size += sizeof(MVMCollectable *) * cand->num_log_slots; |
262 | 0 |
|
263 | 0 | size += sizeof(MVMSpeshInline) * cand->num_inlines; |
264 | 0 |
|
265 | 0 | size += sizeof(MVMuint16) * (cand->num_locals + cand->num_lexicals); |
266 | 0 |
|
267 | 0 | /* XXX probably don't need to measure the bytecode size here, |
268 | 0 | * as it's probably just a pointer to the same bytecode we have in |
269 | 0 | * the static frame anyway. */ |
270 | 0 |
|
271 | 0 | /* Dive into the jit code */ |
272 | 0 | if (cand->jitcode) { |
273 | 0 | MVMJitCode *code = cand->jitcode; |
274 | 0 |
|
275 | 0 | size += sizeof(MVMJitCode); |
276 | 0 |
|
277 | 0 | size += sizeof(void *) * code->num_labels; |
278 | 0 |
|
279 | 0 | size += sizeof(MVMint32) * code->num_bbs; |
280 | 0 | size += sizeof(MVMJitDeopt) * code->num_deopts; |
281 | 0 | size += sizeof(MVMJitInline) * code->num_inlines; |
282 | 0 | size += sizeof(MVMJitHandler) * code->num_handlers; |
283 | 0 | } |
284 | 0 | } |
285 | 1.16k | |
286 | 1.16k | if (body->instrumentation) { |
287 | 0 | size += body->instrumentation->uninstrumented_bytecode_size; |
288 | 0 | size += body->instrumentation->instrumented_bytecode_size; |
289 | 0 |
|
290 | 0 | /* XXX not 100% sure if num_handlers from the body is also the |
291 | 0 | * number of handlers in instrumented version. should be, though. */ |
292 | 0 | size += sizeof(MVMFrameHandler) * body->num_handlers * 2; |
293 | 0 | } |
294 | 1.16k | } |
295 | 1.16k | |
296 | 1.16k | return size; |
297 | 1.16k | } |
298 | | |
299 | 0 | static void describe_refs(MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSTable *st, void *data) { |
300 | 0 | MVMStaticFrameBody *body = (MVMStaticFrameBody *)data; |
301 | 0 | MVMLexicalRegistry *current, *tmp; |
302 | 0 | unsigned bucket_tmp; |
303 | 0 |
|
304 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
305 | 0 | (MVMCollectable *)body->cu, "Compilation Unit"); |
306 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
307 | 0 | (MVMCollectable *)body->cuuid, "Compilation Unit Unique ID"); |
308 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
309 | 0 | (MVMCollectable *)body->name, "Name"); |
310 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
311 | 0 | (MVMCollectable *)body->outer, "Outer static frame"); |
312 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
313 | 0 | (MVMCollectable *)body->static_code, "Static code object"); |
314 | 0 |
|
315 | 0 | /* If it's not fully deserialized, none of the following can apply. */ |
316 | 0 | if (!body->fully_deserialized) |
317 | 0 | return; |
318 | 0 |
|
319 | 0 | /* lexical names hash keys */ |
320 | 0 | HASH_ITER(hash_handle, body->lexical_names, current, tmp, bucket_tmp) { |
321 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
322 | 0 | (MVMCollectable *)current->key, "Lexical name"); |
323 | 0 | } |
324 | 0 |
|
325 | 0 | /* static env */ |
326 | 0 | if (body->static_env) { |
327 | 0 | MVMuint16 *type_map = body->lexical_types; |
328 | 0 | MVMuint16 count = body->num_lexicals; |
329 | 0 | MVMuint16 i; |
330 | 0 | for (i = 0; i < count; i++) |
331 | 0 | if (type_map[i] == MVM_reg_str || type_map[i] == MVM_reg_obj) |
332 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
333 | 0 | (MVMCollectable *)body->static_env[i].o, "Static Environment Entry"); |
334 | 0 | } |
335 | 0 |
|
336 | 0 | /* Spesh slots. */ |
337 | 0 | if (body->num_spesh_candidates) { |
338 | 0 | MVMint32 i, j; |
339 | 0 | for (i = 0; i < body->num_spesh_candidates; i++) { |
340 | 0 | for (j = 0; j < body->spesh_candidates[i].num_guards; j++) |
341 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
342 | 0 | (MVMCollectable *)body->spesh_candidates[i].guards[j].match, |
343 | 0 | "Spesh guard match"); |
344 | 0 | for (j = 0; j < body->spesh_candidates[i].num_spesh_slots; j++) |
345 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
346 | 0 | (MVMCollectable *)body->spesh_candidates[i].spesh_slots[j], |
347 | 0 | "Spesh slot entry"); |
348 | 0 | if (body->spesh_candidates[i].log_slots) |
349 | 0 | for (j = 0; j < body->spesh_candidates[i].num_log_slots * MVM_SPESH_LOG_RUNS; j++) |
350 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
351 | 0 | (MVMCollectable *)body->spesh_candidates[i].log_slots[j], |
352 | 0 | "Spesh log slots"); |
353 | 0 | for (j = 0; j < body->spesh_candidates[i].num_inlines; j++) |
354 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
355 | 0 | (MVMCollectable *)body->spesh_candidates[i].inlines[j].code, |
356 | 0 | "Spesh inlined code object"); |
357 | 0 | if (body->spesh_candidates[i].sg) { |
358 | 0 | MVMCollectable **c_ptr; |
359 | 0 | MVM_spesh_graph_mark(tc, body->spesh_candidates[i].sg, ss->gcwl); |
360 | 0 | while (( c_ptr = MVM_gc_worklist_get(tc, ss->gcwl) )) { |
361 | 0 | MVMCollectable *c = *c_ptr; |
362 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, c, |
363 | 0 | "Object held by spesh graph"); |
364 | 0 | } |
365 | 0 | } |
366 | 0 | } |
367 | 0 | } |
368 | 0 | } |
369 | | |
370 | | /* Initializes the representation. */ |
371 | 130 | const MVMREPROps * MVMStaticFrame_initialize(MVMThreadContext *tc) { |
372 | 130 | return &MVMStaticFrame_this_repr; |
373 | 130 | } |
374 | | |
375 | | static const MVMREPROps MVMStaticFrame_this_repr = { |
376 | | type_object_for, |
377 | | MVM_gc_allocate_object, |
378 | | NULL, /* initialize */ |
379 | | copy_to, |
380 | | MVM_REPR_DEFAULT_ATTR_FUNCS, |
381 | | MVM_REPR_DEFAULT_BOX_FUNCS, |
382 | | MVM_REPR_DEFAULT_POS_FUNCS, |
383 | | MVM_REPR_DEFAULT_ASS_FUNCS, |
384 | | MVM_REPR_DEFAULT_ELEMS, |
385 | | get_storage_spec, |
386 | | NULL, /* change_type */ |
387 | | NULL, /* serialize */ |
388 | | NULL, /* deserialize */ |
389 | | NULL, /* serialize_repr_data */ |
390 | | NULL, /* deserialize_repr_data */ |
391 | | NULL, /* deserialize_stable_size */ |
392 | | gc_mark, |
393 | | gc_free, |
394 | | NULL, /* gc_cleanup */ |
395 | | NULL, /* gc_mark_repr_data */ |
396 | | NULL, /* gc_free_repr_data */ |
397 | | compose, |
398 | | NULL, /* spesh */ |
399 | | "MVMStaticFrame", /* name */ |
400 | | MVM_REPR_ID_MVMStaticFrame, |
401 | | unmanaged_size, /* unmanaged_size */ |
402 | | describe_refs, |
403 | | }; |