~ubuntu-branches/ubuntu/vivid/nqp/vivid-proposed

« back to all changes in this revision

Viewing changes to src/vm/parrot/6model/reprs/P6opaque.c

  • Committer: Package Import Robot
  • Author(s): Alessandro Ghedini
  • Date: 2013-11-01 12:09:18 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20131101120918-kx51sl0sxl3exsxi
Tags: 2013.10-1
* New upstream release
* Bump versioned (Build-)Depends on parrot
* Update patches
* Install new README.pod
* Fix vcs-field-not-canonical
* Do not install rubyish examples
* Do not Depends on parrot-devel anymore
* Add 07_disable-serialization-tests.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* A mostly complete implementation of P6opaque, which supports inlining native
 
2
 * types, box/unbox of native types where it's declared possible and doing just
 
3
 * a single memory allocation in addition to the PMC header per object. For
 
4
 * single inheritance, memory is laid out parent to child, so that the slot
 
5
 * given to an attribute with be valid in all SI subclasses. For MI we just
 
6
 * go with the MRO to do slot allocations, but we never allow an actual index
 
7
 * lookup with a hint to take place and always slow-path it. */
 
8
 
 
9
#define PARROT_IN_EXTENSION
 
10
#include "parrot/parrot.h"
 
11
#include "parrot/extend.h"
 
12
#include "../sixmodelobject.h"
 
13
#include "P6opaque.h"
 
14
 
 
15
#define MAX(x, y) ((y) > (x) ? (y) : (x))
 
16
 
 
17
/* This representation's function pointer table. */
 
18
static REPROps *this_repr;
 
19
 
 
20
/* 6model object ID. */
 
21
static INTVAL smo_id = 0;
 
22
 
 
23
/* How do we go from type-object to a hash value? For now, we make an integer
 
24
 * that is the address of the STable struct, which not being subject to GC will
 
25
 * never move, and is unique per type object too. */
 
26
#define CLASS_KEY(c) ((INTVAL)PMC_data(STABLE_PMC(c)))
 
27
 
 
28
/* Helper to make an introspection call, possibly with :local. */
 
29
static PMC * introspection_call(PARROT_INTERP, PMC *WHAT, PMC *HOW, STRING *name, INTVAL local) {
 
30
    PMC *old_ctx, *cappy;
 
31
    
 
32
    /* Look up method; if there is none hand back a null. */
 
33
    PMC *meth = VTABLE_find_method(interp, HOW, name);
 
34
    if (PMC_IS_NULL(meth))
 
35
        return meth;
 
36
 
 
37
    /* Set up call capture. */
 
38
    old_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
 
39
    cappy   = Parrot_pmc_new(interp, enum_class_CallContext);
 
40
    VTABLE_push_pmc(interp, cappy, HOW);
 
41
    VTABLE_push_pmc(interp, cappy, WHAT);
 
42
    if (local)
 
43
        VTABLE_set_integer_keyed_str(interp, cappy, Parrot_str_new_constant(interp, "local"), 1);
 
44
 
 
45
    /* Call. */
 
46
    Parrot_pcc_invoke_from_sig_object(interp, meth, cappy);
 
47
 
 
48
    /* Grab result. */
 
49
    cappy = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
 
50
    Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx);
 
51
    return VTABLE_get_pmc_keyed_int(interp, cappy, 0);
 
52
}
 
53
 
 
54
/* Locates all of the attributes. Puts them onto a flattened, ordered
 
55
 * list of attributes (populating the passed flat_list). Also builds
 
56
 * the index mapping for doing named lookups. Note index is not related
 
57
 * to the storage position. */
 
58
static PMC * index_mapping_and_flat_list(PARROT_INTERP, PMC *mro, P6opaqueREPRData *repr_data) {
 
59
    PMC    *flat_list      = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
 
60
    PMC    *class_list     = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
 
61
    PMC    *attr_map_list  = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
 
62
    STRING *name_str       = Parrot_str_new_constant(interp, "name");
 
63
    INTVAL  current_slot   = 0;
 
64
    
 
65
    INTVAL num_classes, i;
 
66
    P6opaqueNameMap * result = NULL;
 
67
 
 
68
    /* Walk through the MRO backwards. */
 
69
    INTVAL mro_idx = VTABLE_elements(interp, mro);
 
70
    while (mro_idx)
 
71
    {
 
72
        /* Get current type in MRO. */
 
73
        PMC    *type_info     = VTABLE_get_pmc_keyed_int(interp, mro, --mro_idx);
 
74
        PMC    *current_class = decontainerize(interp, VTABLE_get_pmc_keyed_int(interp, type_info, 0));
 
75
        
 
76
        /* Get its local parents. */
 
77
        PMC    *parents     = VTABLE_get_pmc_keyed_int(interp, type_info, 2);
 
78
        INTVAL  num_parents = VTABLE_elements(interp, parents);
 
79
 
 
80
        /* Get attributes and iterate over them. */
 
81
        PMC *attributes = VTABLE_get_pmc_keyed_int(interp, type_info, 1);
 
82
        PMC *attr_map   = PMCNULL;
 
83
        PMC *attr_iter  = VTABLE_get_iter(interp, attributes);
 
84
        while (VTABLE_get_bool(interp, attr_iter)) {
 
85
            /* Get attribute. */
 
86
            PMC * attr_hash = VTABLE_shift_pmc(interp, attr_iter);
 
87
 
 
88
            /* Get its name. */
 
89
            PMC    *name_pmc = VTABLE_get_pmc_keyed_str(interp, attr_hash, name_str);
 
90
            STRING *name     = VTABLE_get_string(interp, name_pmc);
 
91
 
 
92
            /* Allocate a slot. */
 
93
            if (PMC_IS_NULL(attr_map))
 
94
                attr_map = Parrot_pmc_new(interp, enum_class_Hash);
 
95
            VTABLE_set_pmc_keyed_str(interp, attr_map, name,
 
96
                Parrot_pmc_new_init_int(interp, enum_class_Integer, current_slot));
 
97
            current_slot++;
 
98
 
 
99
            /* Push attr onto the flat list. */
 
100
            VTABLE_push_pmc(interp, flat_list, attr_hash);
 
101
        }
 
102
 
 
103
        /* Add to class list and map list. */
 
104
        VTABLE_push_pmc(interp, class_list, current_class);
 
105
        VTABLE_push_pmc(interp, attr_map_list, attr_map);
 
106
 
 
107
        /* If there's more than one parent, flag that we in an MI
 
108
         * situation. */
 
109
        if (num_parents > 1)
 
110
            repr_data->mi = 1;
 
111
    }
 
112
 
 
113
    /* We can now form the name map. */
 
114
    num_classes = VTABLE_elements(interp, class_list);
 
115
    result = (P6opaqueNameMap *) mem_sys_allocate_zeroed(sizeof(P6opaqueNameMap) * (1 + num_classes));
 
116
    for (i = 0; i < num_classes; i++) {
 
117
        result[i].class_key = VTABLE_get_pmc_keyed_int(interp, class_list, i);
 
118
        result[i].name_map  = VTABLE_get_pmc_keyed_int(interp, attr_map_list, i);
 
119
    }
 
120
    repr_data->name_to_index_mapping = result;
 
121
 
 
122
    return flat_list;
 
123
}
 
124
 
 
125
/* This works out an allocation strategy for the object. It takes care of
 
126
 * "inlining" storage of attributes that are natively typed, as well as
 
127
 * noting unbox targets. */
 
128
static void compute_allocation_strategy(PARROT_INTERP, PMC *repr_info, P6opaqueREPRData *repr_data) {
 
129
    STRING *type_str       = Parrot_str_new_constant(interp, "type");
 
130
    STRING *box_target_str = Parrot_str_new_constant(interp, "box_target");
 
131
    STRING *avcont_str     = Parrot_str_new_constant(interp, "auto_viv_container");
 
132
    STRING *pos_del_str    = Parrot_str_new_constant(interp, "positional_delegate");
 
133
    STRING *ass_del_str    = Parrot_str_new_constant(interp, "associative_delegate");
 
134
    PMC    *flat_list;
 
135
 
 
136
    /*
 
137
     * We have to block GC mark here. Because "repr" is assotiated with some
 
138
     * PMC which is not accessible in this function. And we have to write
 
139
     * barrier this PMC because we are poking inside it guts directly. We
 
140
     * do have WB in caller function, but it can be triggered too late is
 
141
     * any of allocation will cause GC run.
 
142
     *
 
143
     * This is kind of minor evil until after I'll find better solution.
 
144
     */
 
145
    Parrot_block_GC_mark(interp);
 
146
 
 
147
    /* Compute index mapping table and get flat list of attributes. */
 
148
    flat_list = index_mapping_and_flat_list(interp, repr_info, repr_data);
 
149
    
 
150
    /* If we have no attributes in the index mapping, then just the header. */
 
151
    if (repr_data->name_to_index_mapping[0].class_key == NULL) {
 
152
        repr_data->allocation_size = sizeof(P6opaqueInstance);
 
153
    }
 
154
 
 
155
    /* Otherwise, we need to compute the allocation strategy.  */
 
156
    else {
 
157
        /* We track the size of the body part, since that's what we want offsets into. */
 
158
        INTVAL cur_size = 0;
 
159
        
 
160
        /* Get number of attributes and set up various counters. */
 
161
        INTVAL num_attrs        = VTABLE_elements(interp, flat_list);
 
162
        INTVAL info_alloc       = num_attrs == 0 ? 1 : num_attrs;
 
163
        INTVAL cur_pmc_attr     = 0;
 
164
        INTVAL cur_init_slot    = 0;
 
165
        INTVAL cur_mark_slot    = 0;
 
166
        INTVAL cur_cleanup_slot = 0;
 
167
        INTVAL cur_unbox_slot   = 0;
 
168
        INTVAL i;
 
169
 
 
170
        /* Allocate offset array and GC mark info arrays. */
 
171
        repr_data->num_attributes      = num_attrs;
 
172
        repr_data->attribute_offsets   = (INTVAL *) mem_sys_allocate(info_alloc * sizeof(INTVAL));
 
173
        repr_data->flattened_stables   = (STable **) mem_sys_allocate_zeroed(info_alloc * sizeof(PMC *));
 
174
        repr_data->unbox_int_slot      = -1;
 
175
        repr_data->unbox_num_slot      = -1;
 
176
        repr_data->unbox_str_slot      = -1;
 
177
        repr_data->pos_del_slot        = -1;
 
178
        repr_data->ass_del_slot        = -1;
 
179
 
 
180
        /* Go over the attributes and arrange their allocation. */
 
181
        for (i = 0; i < num_attrs; i++) {
 
182
            PMC *attr_hash = VTABLE_get_pmc_keyed_int(interp, flat_list, i);
 
183
 
 
184
            /* Fetch its type and box target flag, if available. */
 
185
            PMC *type       = VTABLE_get_pmc_keyed_str(interp, attr_hash, type_str);
 
186
            PMC *box_target = VTABLE_get_pmc_keyed_str(interp, attr_hash, box_target_str);
 
187
            PMC *av_cont    = VTABLE_get_pmc_keyed_str(interp, attr_hash, avcont_str);
 
188
 
 
189
            /* Work out what unboxed type it is, if any. Default to a boxed. */
 
190
            INTVAL unboxed_type = STORAGE_SPEC_BP_NONE;
 
191
            INTVAL bits         = sizeof(PMC *) * 8;
 
192
            INTVAL align        = ALIGNOF1(PMC *);
 
193
 
 
194
            /* True if this member is flattened into the object body. */
 
195
            INTVAL inlined      = 0;
 
196
 
 
197
            if (!PMC_IS_NULL(type)) {
 
198
                /* Get the storage spec of the type and see what it wants. */
 
199
                storage_spec spec = REPR(type)->get_storage_spec(interp, STABLE(type));
 
200
                if (spec.inlineable == STORAGE_SPEC_INLINED) {
 
201
                    /* Yes, it's something we'll flatten. */
 
202
                    unboxed_type = spec.boxed_primitive;
 
203
                    bits = spec.bits;
 
204
                    align = spec.align;
 
205
                    repr_data->flattened_stables[i] = STABLE(type);
 
206
                    inlined = 1;
 
207
                    
 
208
                    if (bits % 8) bits += 8 - bits%8;
 
209
 
 
210
                    /* Does it need special initialization? */
 
211
                    if (REPR(type)->initialize) {
 
212
                        if (!repr_data->initialize_slots)
 
213
                            repr_data->initialize_slots = (INTVAL *) mem_sys_allocate_zeroed((info_alloc + 1) * sizeof(INTVAL));
 
214
                        repr_data->initialize_slots[cur_init_slot] = i;
 
215
                        cur_init_slot++;
 
216
                    }
 
217
                    
 
218
                    /* Does it have special GC needs? */
 
219
                    if (REPR(type)->gc_mark) {
 
220
                        if (!repr_data->gc_mark_slots)
 
221
                            repr_data->gc_mark_slots = (INTVAL *) mem_sys_allocate_zeroed((info_alloc + 1) * sizeof(INTVAL));
 
222
                        repr_data->gc_mark_slots[cur_mark_slot] = i;
 
223
                        cur_mark_slot++;
 
224
                    }
 
225
                    if (REPR(type)->gc_cleanup) {
 
226
                        if (!repr_data->gc_cleanup_slots)
 
227
                            repr_data->gc_cleanup_slots = (INTVAL *) mem_sys_allocate_zeroed((info_alloc + 1) * sizeof(INTVAL));
 
228
                        repr_data->gc_cleanup_slots[cur_cleanup_slot] = i;
 
229
                        cur_cleanup_slot++;
 
230
                    }
 
231
 
 
232
                    /* Is it a target for box/unbox operations? */
 
233
                    if (!PMC_IS_NULL(box_target) && VTABLE_get_bool(interp, box_target)) {
 
234
                        /* If it boxes a primitive, note that. */
 
235
                        switch (unboxed_type) {
 
236
                        case STORAGE_SPEC_BP_INT:
 
237
                            if (repr_data->unbox_int_slot >= 0)
 
238
                                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
239
                                        "Duplicate box_target for native int");
 
240
                            repr_data->unbox_int_slot = i;
 
241
                            break;
 
242
                        case STORAGE_SPEC_BP_NUM:
 
243
                            if (repr_data->unbox_num_slot >= 0)
 
244
                                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
245
                                        "Duplicate box_target for native num");
 
246
                            repr_data->unbox_num_slot = i;
 
247
                            break;
 
248
                        case STORAGE_SPEC_BP_STR:
 
249
                            if (repr_data->unbox_str_slot >= 0)
 
250
                                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
251
                                        "Duplicate box_target for native str");
 
252
                            repr_data->unbox_str_slot = i;
 
253
                            break;
 
254
                        default:
 
255
                            /* nothing, just suppress 'missing default' warning */
 
256
                            break;
 
257
                        }
 
258
                        
 
259
                        /* Also list in the by-repr unbox list. */
 
260
                        if (repr_data->unbox_slots == NULL)
 
261
                            repr_data->unbox_slots = (P6opaqueBoxedTypeMap *) mem_sys_allocate_zeroed(info_alloc * sizeof(P6opaqueBoxedTypeMap));
 
262
                        repr_data->unbox_slots[cur_unbox_slot].repr_id = REPR(type)->ID;
 
263
                        repr_data->unbox_slots[cur_unbox_slot].slot = i;
 
264
                        cur_unbox_slot++;
 
265
                    }
 
266
                }
 
267
            }
 
268
            
 
269
            /* Do allocation. Before updating the size of the structure, we
 
270
             * make sure the object will be aligned appropriately. */
 
271
            if (cur_size % align) {
 
272
                cur_size += align - cur_size % align;
 
273
            }
 
274
            repr_data->attribute_offsets[i] = cur_size;
 
275
 
 
276
            /* Handle PMC attributes, which need marking and may have auto-viv needs. */
 
277
            if (!inlined) {
 
278
                if (!repr_data->gc_pmc_mark_offsets)
 
279
                    repr_data->gc_pmc_mark_offsets = (INTVAL *) mem_sys_allocate_zeroed(info_alloc * sizeof(INTVAL));
 
280
                repr_data->gc_pmc_mark_offsets[cur_pmc_attr] = cur_size;
 
281
                cur_pmc_attr++;
 
282
                if (!PMC_IS_NULL(av_cont)) {
 
283
                    if (!repr_data->auto_viv_values)
 
284
                        repr_data->auto_viv_values = (PMC **) mem_sys_allocate_zeroed(info_alloc * sizeof(PMC *));
 
285
                    repr_data->auto_viv_values[i] = av_cont;
 
286
                }
 
287
            }
 
288
            
 
289
            /* Is it a positional or associative delegate? */
 
290
            if (VTABLE_exists_keyed_str(interp, attr_hash, pos_del_str)) {
 
291
                if (repr_data->pos_del_slot != -1)
 
292
                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
293
                        "Duplicate positional delegate attribute");
 
294
                if (unboxed_type == STORAGE_SPEC_BP_NONE)
 
295
                    repr_data->pos_del_slot = i;
 
296
                else
 
297
                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
298
                        "Positional delegate attribute must be a reference type");
 
299
            }
 
300
            if (VTABLE_exists_keyed_str(interp, attr_hash, ass_del_str)) {
 
301
                if (repr_data->ass_del_slot != -1)
 
302
                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
303
                        "Duplicate associative delegate attribute");
 
304
                if (unboxed_type == STORAGE_SPEC_BP_NONE)
 
305
                    repr_data->ass_del_slot = i;
 
306
                else
 
307
                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
308
                        "Associative delegate attribute must be a reference type");
 
309
            }
 
310
            
 
311
            /* Increment object size by the allocated bytes. */
 
312
            cur_size += bits / 8;
 
313
        }
 
314
 
 
315
        /* Finally, put computed allocation size in place; it's body size plus
 
316
         * header size. Also number of markables and sentinels. */
 
317
        repr_data->allocation_size = cur_size + sizeof(P6opaqueInstance);
 
318
        repr_data->gc_pmc_mark_offsets_count = cur_pmc_attr;
 
319
        if (repr_data->initialize_slots)
 
320
            repr_data->initialize_slots[cur_init_slot] = -1;
 
321
        if (repr_data->gc_mark_slots)
 
322
            repr_data->gc_mark_slots[cur_mark_slot] = -1;
 
323
        if (repr_data->gc_cleanup_slots)
 
324
            repr_data->gc_cleanup_slots[cur_cleanup_slot] = -1;
 
325
    }
 
326
 
 
327
    Parrot_unblock_GC_mark(interp);
 
328
}
 
329
 
 
330
/* Helper for reading a PMC at the specified offset. */
 
331
static PMC * get_pmc_at_offset(void *data, INTVAL offset) {
 
332
    void *location = (char *)data + offset;
 
333
    return *((PMC **)location);
 
334
}
 
335
 
 
336
/* Helper for writing a PMC at the specified offset. */
 
337
static void set_pmc_at_offset(void *data, INTVAL offset, PMC *value) {
 
338
    void *location = (char *)data + offset;
 
339
    *((PMC **)location) = value;
 
340
}
 
341
 
 
342
/* Helper for finding a slot number. */
 
343
static INTVAL try_get_slot(PARROT_INTERP, P6opaqueREPRData *repr_data, PMC *class_key, STRING *name) {
 
344
    INTVAL slot = -1;
 
345
    if (repr_data->name_to_index_mapping) {
 
346
        P6opaqueNameMap *cur_map_entry = repr_data->name_to_index_mapping;
 
347
        while (cur_map_entry->class_key != NULL) {
 
348
            if (cur_map_entry->class_key == class_key) {
 
349
                if (!PMC_IS_NULL(cur_map_entry->name_map)) {
 
350
                    PMC *slot_pmc = VTABLE_get_pmc_keyed_str(interp, cur_map_entry->name_map, name);
 
351
                    if (!PMC_IS_NULL(slot_pmc))
 
352
                        slot = VTABLE_get_integer(interp, slot_pmc);
 
353
                    break;
 
354
                }
 
355
                else {
 
356
                    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
357
                        "Null attribute map for P6opaque in class '%Ss'",
 
358
                        VTABLE_get_string(interp, introspection_call(interp,
 
359
                            class_key, STABLE(class_key)->HOW,
 
360
                            Parrot_str_new_constant(interp, "name"), 0)));
 
361
                }
 
362
            }
 
363
            cur_map_entry++;
 
364
        }
 
365
    }
 
366
    return slot;
 
367
}
 
368
 
 
369
/* Creates a new type object of this representation, and associates it with
 
370
 * the given HOW. */
 
371
static PMC * type_object_for(PARROT_INTERP, PMC *HOW) {
 
372
    /* Create new object instance. */
 
373
    P6opaqueInstance *obj = mem_allocate_zeroed_typed(P6opaqueInstance);
 
374
 
 
375
    /* Build an STable. */
 
376
    PMC *st_pmc = create_stable(interp, this_repr, HOW);
 
377
    STable *st  = STABLE_STRUCT(st_pmc);
 
378
    
 
379
    /* Create REPR data structure and hand it off the STable. */
 
380
    st->REPR_data = mem_allocate_zeroed_typed(P6opaqueREPRData);
 
381
 
 
382
    /* Create type object and point it back at the STable. */
 
383
    obj->common.stable = st_pmc;
 
384
    st->WHAT = wrap_object(interp, obj);
 
385
    PARROT_GC_WRITE_BARRIER(interp, st_pmc);
 
386
 
 
387
    /* Flag it as a type object. */
 
388
    MARK_AS_TYPE_OBJECT(st->WHAT);
 
389
 
 
390
    return st->WHAT;
 
391
}
 
392
 
 
393
/* Composes the representation. */
 
394
static void compose(PARROT_INTERP, STable *st, PMC *repr_info) {
 
395
    P6opaqueREPRData * repr_data = (P6opaqueREPRData *) st->REPR_data;
 
396
    PMC *attr_info = VTABLE_get_pmc_keyed_str(interp, repr_info,
 
397
        Parrot_str_new_constant(interp, "attribute"));
 
398
    compute_allocation_strategy(interp, attr_info, repr_data);
 
399
    PARROT_GC_WRITE_BARRIER(interp, st->stable_pmc);
 
400
}
 
401
 
 
402
/* Creates a new instance based on the type object. */
 
403
static PMC * allocate(PARROT_INTERP, STable *st) {
 
404
    P6opaqueInstance * obj;
 
405
 
 
406
    /* Compute allocation strategy if we've not already done so. */
 
407
    P6opaqueREPRData * repr_data = (P6opaqueREPRData *) st->REPR_data;
 
408
    if (!repr_data->allocation_size)
 
409
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
410
            "Representation must be composed before it can be allocated");
 
411
 
 
412
    /* Allocate and set up object instance. */
 
413
    obj = (P6opaqueInstance *) Parrot_gc_allocate_fixed_size_storage(interp, repr_data->allocation_size);
 
414
    memset(obj, 0, repr_data->allocation_size);
 
415
    obj->common.stable = st->stable_pmc;
 
416
 
 
417
    return wrap_object(interp, obj);
 
418
}
 
419
 
 
420
/* Initialize a new instance. */
 
421
static void initialize(PARROT_INTERP, STable *st, void *data) {
 
422
    P6opaqueREPRData * repr_data = (P6opaqueREPRData *) st->REPR_data;
 
423
    if (repr_data->initialize_slots) {
 
424
        INTVAL i;
 
425
        for (i = 0; repr_data->initialize_slots[i] >= 0; i++) {
 
426
            INTVAL  offset = repr_data->attribute_offsets[repr_data->initialize_slots[i]];
 
427
            STable *st     = repr_data->flattened_stables[repr_data->initialize_slots[i]];
 
428
            st->REPR->initialize(interp, st, (char *)data + offset);
 
429
        }
 
430
    }
 
431
}
 
432
 
 
433
/* Copies to the body of one object to another. */
 
434
static void copy_to(PARROT_INTERP, STable *st, void *src, void *dest) {
 
435
    P6opaqueREPRData * repr_data = (P6opaqueREPRData *) st->REPR_data;
 
436
    INTVAL i;
 
437
 
 
438
    /* Copy main body. */
 
439
    memcpy(dest, src, repr_data->allocation_size - sizeof(P6opaqueInstance));
 
440
 
 
441
    /* Flattened in REPRs need a chance to copy 'emselves. */
 
442
    for (i = 0; i < repr_data->num_attributes; i++) {
 
443
        STable *st_copy = repr_data->flattened_stables[i];
 
444
        if (st_copy) {
 
445
            INTVAL offset = repr_data->attribute_offsets[i];
 
446
            st_copy->REPR->copy_to(interp, st_copy, (char*)src + offset, (char*)dest + offset);
 
447
        }
 
448
    }
 
449
}
 
450
 
 
451
/* Helper for complaining about attribute access errors. */
 
452
PARROT_DOES_NOT_RETURN
 
453
static void no_such_attribute(PARROT_INTERP, const char *action, PMC *class_handle, STRING *name) {
 
454
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
455
            "Can not %s attribute '%Ss' declared in class '%Ss' with this object",
 
456
            action, name, VTABLE_get_string(interp, introspection_call(interp,
 
457
                class_handle, STABLE(class_handle)->HOW,
 
458
                Parrot_str_new_constant(interp, "name"), 0)));
 
459
}
 
460
 
 
461
/* Gets the current value for an attribute. */
 
462
static PMC * get_attribute_boxed(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint) {
 
463
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
464
    INTVAL            slot;
 
465
 
 
466
    /* Try the slot allocation first. */
 
467
    slot = hint >= 0 && !(repr_data->mi) ? hint :
 
468
        try_get_slot(interp, repr_data, class_handle, name);
 
469
    if (slot >= 0) {
 
470
        if (!repr_data->flattened_stables[slot]) {
 
471
            PMC *result = get_pmc_at_offset(data, repr_data->attribute_offsets[slot]);
 
472
            if (result) {
 
473
                return result;
 
474
            }
 
475
            else {
 
476
                /* Maybe we know how to auto-viv it to a container. */
 
477
                if (repr_data->auto_viv_values) {
 
478
                    PMC *value = repr_data->auto_viv_values[slot];
 
479
                    if (value != NULL) {
 
480
                        if (IS_CONCRETE(value)) {
 
481
                            PMC *cloned = REPR(value)->allocate(interp, STABLE(value));
 
482
                            REPR(value)->copy_to(interp, STABLE(value), OBJECT_BODY(value), OBJECT_BODY(cloned));
 
483
                            PARROT_GC_WRITE_BARRIER(interp, cloned);
 
484
                            set_pmc_at_offset(data, repr_data->attribute_offsets[slot], cloned);
 
485
                            return cloned;
 
486
                        }
 
487
                        else {
 
488
                            set_pmc_at_offset(data, repr_data->attribute_offsets[slot], value);
 
489
                            return value;
 
490
                        }
 
491
                    }
 
492
                }
 
493
                return PMCNULL;
 
494
            }
 
495
        }
 
496
        else {
 
497
            /* Need to produce a boxed version of this attribute. */
 
498
            STable *st  = repr_data->flattened_stables[slot];
 
499
            PMC *result = st->REPR->allocate(interp, st);
 
500
            st->REPR->copy_to(interp, st, (char *)data + repr_data->attribute_offsets[slot],
 
501
                OBJECT_BODY(result));
 
502
            PARROT_GC_WRITE_BARRIER(interp, result);
 
503
 
 
504
            return result;
 
505
        }
 
506
    }
 
507
    
 
508
    /* Otherwise, complain that the attribute doesn't exist. */
 
509
    no_such_attribute(interp, "get", class_handle, name);
 
510
}
 
511
 
 
512
static void get_attribute_native(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint, NativeValue *value) {
 
513
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
514
    INTVAL            slot;
 
515
 
 
516
    /* Look up slot, then offset and compute address. */
 
517
    slot = hint >= 0 && !(repr_data->mi) ? hint :
 
518
        try_get_slot(interp, repr_data, class_handle, name);
 
519
    if (slot >= 0) {
 
520
        STable *st = repr_data->flattened_stables[slot];
 
521
        void *ptr = ((char *)data) + repr_data->attribute_offsets[slot];
 
522
        if (st) {
 
523
            switch (value->type) {
 
524
            case NATIVE_VALUE_INT:
 
525
                value->value.intval = st->REPR->box_funcs->get_int(interp, st, ptr);
 
526
                break;
 
527
            case NATIVE_VALUE_FLOAT:
 
528
                value->value.floatval = st->REPR->box_funcs->get_num(interp, st, ptr);
 
529
                break;
 
530
            case NATIVE_VALUE_STRING:
 
531
                value->value.stringval = st->REPR->box_funcs->get_str(interp, st, ptr);
 
532
                break;
 
533
            default:
 
534
                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
535
                    "Bad value of NativeValue.type: %d", value->type);
 
536
            }
 
537
            return;
 
538
        }
 
539
        else {
 
540
            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
541
                "Cannot read by reference from non-flattened attribute '%Ss' on class '%Ss'",
 
542
                name, VTABLE_get_string(interp, introspection_call(interp,
 
543
                    class_handle, STABLE(class_handle)->HOW,
 
544
                    Parrot_str_new_constant(interp, "name"), 0)));
 
545
        }
 
546
    }
 
547
    
 
548
    /* Otherwise, complain that the attribute doesn't exist. */
 
549
    no_such_attribute(interp, "get", class_handle, name);
 
550
}
 
551
 
 
552
/* Binds the given value to the specified attribute. */
 
553
static void bind_attribute_boxed(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint, PMC *value) {
 
554
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
555
    INTVAL            slot;
 
556
 
 
557
    /* Try the slot allocation first. */
 
558
    slot = hint >= 0 && !(repr_data->mi) ? hint :
 
559
        try_get_slot(interp, repr_data, class_handle, name);
 
560
    if (slot >= 0) {
 
561
        STable *st = repr_data->flattened_stables[slot];
 
562
        if (st) {
 
563
            if (value->vtable->base_type == smo_id && st == STABLE(value))
 
564
                st->REPR->copy_to(interp, st, OBJECT_BODY(value),
 
565
                    (char *)data + repr_data->attribute_offsets[slot]);
 
566
            else
 
567
                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
568
                    "Type mismatch when storing value to attribute '%Ss' on class '%Ss'",
 
569
                    name, VTABLE_get_string(interp, introspection_call(interp,
 
570
                        class_handle, STABLE(class_handle)->HOW,
 
571
                        Parrot_str_new_constant(interp, "name"), 0)));
 
572
        }
 
573
        else {
 
574
            set_pmc_at_offset(data, repr_data->attribute_offsets[slot], value);
 
575
        }
 
576
    }
 
577
    else {
 
578
        /* Otherwise, complain that the attribute doesn't exist. */
 
579
        no_such_attribute(interp, "bind", class_handle, name);
 
580
    }
 
581
}
 
582
static void bind_attribute_native(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint, NativeValue *value) {
 
583
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
584
    INTVAL            slot;
 
585
 
 
586
    /* Try to find the slot. */
 
587
    slot = hint >= 0 && !(repr_data->mi) ? hint :
 
588
        try_get_slot(interp, repr_data, class_handle, name);
 
589
    if (slot >= 0) {
 
590
        STable *st = repr_data->flattened_stables[slot];
 
591
        void *ptr = (char *)data + repr_data->attribute_offsets[slot];
 
592
        if (st) {
 
593
            switch (value->type) {
 
594
            case NATIVE_VALUE_INT:
 
595
                st->REPR->box_funcs->set_int(interp, st, ptr, value->value.intval);
 
596
                break;
 
597
            case NATIVE_VALUE_FLOAT:
 
598
                st->REPR->box_funcs->set_num(interp, st, ptr, value->value.floatval);
 
599
                break;
 
600
            case NATIVE_VALUE_STRING:
 
601
                st->REPR->box_funcs->set_str(interp, st, ptr, value->value.stringval);
 
602
                break;
 
603
            default:
 
604
                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
605
                    "Bad value of NativeValue.type: %d", value->type);
 
606
            }
 
607
            return;
 
608
        }
 
609
        else
 
610
            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
611
                "Cannot bind by reference to non-flattened attribute '%Ss' on class '%Ss'",
 
612
                name, VTABLE_get_string(interp, introspection_call(interp,
 
613
                    class_handle, STABLE(class_handle)->HOW,
 
614
                    Parrot_str_new_constant(interp, "name"), 0)));
 
615
    }
 
616
    else {
 
617
        /* Otherwise, complain that the attribute doesn't exist. */
 
618
        no_such_attribute(interp, "bind", class_handle, name);
 
619
    }
 
620
}
 
621
 
 
622
/* Checks if an attribute has been initialized. */
 
623
static INTVAL is_attribute_initialized(PARROT_INTERP, STable *st, void *data, PMC *class_handle, STRING *name, INTVAL hint) {
 
624
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
625
    INTVAL slot = try_get_slot(interp, repr_data, class_handle, name);
 
626
    if (slot >= 0)
 
627
        return NULL != get_pmc_at_offset(data, repr_data->attribute_offsets[slot]);
 
628
    else
 
629
        no_such_attribute(interp, "initializedness check", class_handle, name);
 
630
}
 
631
 
 
632
/* Gets the hint for the given attribute ID. */
 
633
static INTVAL hint_for(PARROT_INTERP, STable *st, PMC *class_key, STRING *name) {
 
634
    INTVAL slot;
 
635
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
636
    if (!repr_data->allocation_size)
 
637
        return NO_HINT;
 
638
    slot = try_get_slot(interp, repr_data, class_key, name);
 
639
    return slot >= 0 ? slot : NO_HINT;
 
640
}
 
641
 
 
642
/* Used with boxing. Sets an integer value, for representations that can hold
 
643
 * one. */
 
644
static void set_int(PARROT_INTERP, STable *st, void *data, INTVAL value) {
 
645
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
646
    if (repr_data->unbox_int_slot >= 0) {
 
647
        STable *st = repr_data->flattened_stables[repr_data->unbox_int_slot];
 
648
        st->REPR->box_funcs->set_int(interp, st, (char *)data + repr_data->attribute_offsets[repr_data->unbox_int_slot], value);
 
649
    }
 
650
    else {
 
651
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
652
            "This type cannot box a native integer");
 
653
    }
 
654
}
 
655
 
 
656
/* Used with boxing. Gets an integer value, for representations that can
 
657
 * hold one. */
 
658
static INTVAL get_int(PARROT_INTERP, STable *st, void *data) {
 
659
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
660
    if (repr_data->unbox_int_slot >= 0) {
 
661
        STable *st = repr_data->flattened_stables[repr_data->unbox_int_slot];
 
662
        return st->REPR->box_funcs->get_int(interp, st, (char *)data + repr_data->attribute_offsets[repr_data->unbox_int_slot]);
 
663
    }
 
664
    else {
 
665
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
666
            "This type cannot unbox to a native integer");
 
667
    }
 
668
}
 
669
 
 
670
/* Used with boxing. Sets a floating point value, for representations that can
 
671
 * hold one. */
 
672
static void set_num(PARROT_INTERP, STable *st, void *data, FLOATVAL value) {
 
673
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
674
    if (repr_data->unbox_num_slot >= 0) {
 
675
        STable *st = repr_data->flattened_stables[repr_data->unbox_num_slot];
 
676
        st->REPR->box_funcs->set_num(interp, st, (char *)data + repr_data->attribute_offsets[repr_data->unbox_num_slot], value);
 
677
    }
 
678
    else {
 
679
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
680
            "This type cannot box a native number");
 
681
    }
 
682
}
 
683
 
 
684
/* Used with boxing. Gets a floating point value, for representations that can
 
685
 * hold one. */
 
686
static FLOATVAL get_num(PARROT_INTERP, STable *st, void *data) {
 
687
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
688
    if (repr_data->unbox_num_slot >= 0) {
 
689
        STable *st = repr_data->flattened_stables[repr_data->unbox_num_slot];
 
690
        return st->REPR->box_funcs->get_num(interp, st, (char *)data + repr_data->attribute_offsets[repr_data->unbox_num_slot]);
 
691
    }
 
692
    else {
 
693
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
694
            "This type cannot unbox to a native number");
 
695
    }
 
696
}
 
697
 
 
698
/* Used with boxing. Sets a string value, for representations that can hold
 
699
 * one. */
 
700
static void set_str(PARROT_INTERP, STable *st, void *data, STRING *value) {
 
701
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
702
    if (repr_data->unbox_str_slot >= 0) {
 
703
        STable *st = repr_data->flattened_stables[repr_data->unbox_str_slot];
 
704
        st->REPR->box_funcs->set_str(interp, st, (char *)data + repr_data->attribute_offsets[repr_data->unbox_str_slot], value);
 
705
    }
 
706
    else {
 
707
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
708
            "This type cannot box a native string");
 
709
    }
 
710
}
 
711
 
 
712
/* Used with boxing. Gets a string value, for representations that can hold
 
713
 * one. */
 
714
static STRING * get_str(PARROT_INTERP, STable *st, void *data) {
 
715
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
716
    if (repr_data->unbox_str_slot >= 0) {
 
717
        STable *st = repr_data->flattened_stables[repr_data->unbox_str_slot];
 
718
        return st->REPR->box_funcs->get_str(interp, st, (char *)data + repr_data->attribute_offsets[repr_data->unbox_str_slot]);
 
719
    }
 
720
    else {
 
721
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
722
            "This type cannot unbox to a native string");
 
723
    }
 
724
}
 
725
 
 
726
/* Some objects serve primarily as boxes of others, inlining them. This gets
 
727
 * gets the reference to such things, using the representation ID to distinguish
 
728
 * them. */
 
729
static void * get_boxed_ref(PARROT_INTERP, STable *st, void *data, INTVAL repr_id) {
 
730
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
731
    if (repr_data->unbox_slots) {
 
732
        INTVAL i;
 
733
        for (i = 0; i < repr_data->num_attributes; i++)
 
734
            if (repr_data->unbox_slots[i].repr_id == repr_id)
 
735
                return (char *)data + repr_data->attribute_offsets[repr_data->unbox_slots[i].slot];
 
736
            else if (repr_data->unbox_slots[i].repr_id == 0)
 
737
                break;
 
738
    }
 
739
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
740
            "get_boxed_ref could not unbox for the given representation");
 
741
    return NULL;
 
742
}
 
743
 
 
744
/* Positional delegation. */
 
745
PARROT_DOES_NOT_RETURN
 
746
static void die_no_pos_del(PARROT_INTERP) {
 
747
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
748
        "This type does not support positional operations");
 
749
}
 
750
static void at_pos_native(PARROT_INTERP, STable *st, void *data, INTVAL index, NativeValue *value) {
 
751
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
752
    if (repr_data->pos_del_slot == -1)
 
753
        die_no_pos_del(interp);
 
754
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
755
        "This type does not support at_pos_native");
 
756
}
 
757
static PMC * at_pos_boxed(PARROT_INTERP, STable *st, void *data, INTVAL index) {
 
758
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
759
    if (repr_data->pos_del_slot == -1)
 
760
        die_no_pos_del(interp);
 
761
    return VTABLE_get_pmc_keyed_int(interp,
 
762
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]),
 
763
        index);
 
764
}
 
765
static void bind_pos_native(PARROT_INTERP, STable *st, void *data, INTVAL index, NativeValue *value) {
 
766
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
767
    if (repr_data->pos_del_slot == -1)
 
768
        die_no_pos_del(interp);
 
769
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
770
        "This type does not support bind_pos_native");
 
771
}
 
772
static void bind_pos_boxed(PARROT_INTERP, STable *st, void *data, INTVAL index, PMC *obj) {
 
773
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
774
    if (repr_data->pos_del_slot == -1)
 
775
        die_no_pos_del(interp);
 
776
    VTABLE_set_pmc_keyed_int(interp,
 
777
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]),
 
778
        index, obj);
 
779
}
 
780
static void push_boxed(PARROT_INTERP, STable *st, void *data, PMC *obj) {
 
781
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
782
    if (repr_data->pos_del_slot == -1)
 
783
        die_no_pos_del(interp);
 
784
    VTABLE_push_pmc(interp,
 
785
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]),
 
786
        obj);
 
787
}
 
788
static PMC * pop_boxed(PARROT_INTERP, STable *st, void *data) {
 
789
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
790
    if (repr_data->pos_del_slot == -1)
 
791
        die_no_pos_del(interp);
 
792
    return VTABLE_pop_pmc(interp,
 
793
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]));
 
794
}
 
795
static void unshift_boxed(PARROT_INTERP, STable *st, void *data, PMC *obj) {
 
796
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
797
    if (repr_data->pos_del_slot == -1)
 
798
        die_no_pos_del(interp);
 
799
    VTABLE_unshift_pmc(interp,
 
800
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]),
 
801
        obj);
 
802
}
 
803
static PMC * shift_boxed(PARROT_INTERP, STable *st, void *data) {
 
804
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
805
    if (repr_data->pos_del_slot == -1)
 
806
        die_no_pos_del(interp);
 
807
    return VTABLE_shift_pmc(interp,
 
808
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]));
 
809
}
 
810
static STable * get_elem_stable(PARROT_INTERP, STable *st) {
 
811
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
812
    if (repr_data->pos_del_slot == -1)
 
813
        die_no_pos_del(interp);
 
814
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
815
        "This type does not support get_elem_stable");
 
816
}
 
817
PARROT_DOES_NOT_RETURN
 
818
static void die_no_ass_del(PARROT_INTERP) {
 
819
    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
820
        "This type does not support associative operations");
 
821
}
 
822
static PMC * at_key_boxed(PARROT_INTERP, STable *st, void *data, STRING *key) {
 
823
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
824
    if (repr_data->ass_del_slot == -1)
 
825
        die_no_ass_del(interp);
 
826
    return VTABLE_get_pmc_keyed_str(interp,
 
827
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]),
 
828
        key);
 
829
}
 
830
static void bind_key_boxed(PARROT_INTERP, STable *st, void *data, STRING *key, PMC *value) {
 
831
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
832
    if (repr_data->ass_del_slot == -1)
 
833
        die_no_ass_del(interp);
 
834
    VTABLE_set_pmc_keyed_str(interp,
 
835
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]),
 
836
        key, value);
 
837
}
 
838
static INTVAL exists_key(PARROT_INTERP, STable *st, void *data, STRING *key) {
 
839
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
840
    if (repr_data->ass_del_slot == -1)
 
841
        die_no_ass_del(interp);
 
842
    return VTABLE_exists_keyed_str(interp,
 
843
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]),
 
844
        key);
 
845
}
 
846
static void delete_key(PARROT_INTERP, STable *st, void *data, STRING *key) {
 
847
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
848
    if (repr_data->ass_del_slot == -1)
 
849
        die_no_ass_del(interp);
 
850
    VTABLE_delete_keyed_str(interp,
 
851
        get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]),
 
852
        key);
 
853
}
 
854
static INTVAL elems(PARROT_INTERP, STable *st, void *data) {
 
855
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
856
    if (repr_data->pos_del_slot >= 0)
 
857
        return VTABLE_elements(interp,
 
858
            get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->pos_del_slot]));
 
859
    else if (repr_data->ass_del_slot >= 0)
 
860
        return VTABLE_elements(interp,
 
861
            get_pmc_at_offset(data, repr_data->attribute_offsets[repr_data->ass_del_slot]));
 
862
    else
 
863
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
864
            "This type does not support elems");
 
865
}
 
866
 
 
867
/* This Parrot-specific addition to the API is used to mark an object. */
 
868
static void gc_mark(PARROT_INTERP, STable *st, void *data) {
 
869
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
870
    INTVAL i;
 
871
 
 
872
    /* Mark PMCs. */
 
873
    if (repr_data->gc_pmc_mark_offsets) {
 
874
        for (i = 0; i < repr_data->gc_pmc_mark_offsets_count; i++) {
 
875
            INTVAL offset = repr_data->gc_pmc_mark_offsets[i];
 
876
            PMC *to_mark  = get_pmc_at_offset(data, offset);
 
877
            if (!PMC_IS_NULL(to_mark))
 
878
                Parrot_gc_mark_PMC_alive(interp, to_mark);
 
879
        }
 
880
    }
 
881
 
 
882
    /* Mark any nested reprs that need it. */
 
883
    if (repr_data->gc_mark_slots) {
 
884
        for (i = 0; repr_data->gc_mark_slots[i] >= 0; i++) {
 
885
            INTVAL  offset = repr_data->attribute_offsets[repr_data->gc_mark_slots[i]];
 
886
            STable *st     = repr_data->flattened_stables[repr_data->gc_mark_slots[i]];
 
887
            st->REPR->gc_mark(interp, st, (char *)data + offset);
 
888
        }
 
889
    }
 
890
}
 
891
 
 
892
/* This Parrot-specific addition to the API is used to free an object. */
 
893
static void gc_free(PARROT_INTERP, PMC *obj) {
 
894
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)STABLE(obj)->REPR_data;
 
895
    INTVAL i;
 
896
 
 
897
    /* Cleanup any nested reprs that need it. */
 
898
    if (repr_data->gc_cleanup_slots) {
 
899
        for (i = 0; repr_data->gc_cleanup_slots[i] >= 0; i++) {
 
900
            INTVAL  offset = repr_data->attribute_offsets[repr_data->gc_cleanup_slots[i]];
 
901
            STable *st     = repr_data->flattened_stables[repr_data->gc_cleanup_slots[i]];
 
902
            st->REPR->gc_cleanup(interp, st, (char *)OBJECT_BODY(obj) + offset);
 
903
        }
 
904
    }
 
905
    if (repr_data->allocation_size && !PObj_flag_TEST(private0, obj))
 
906
        Parrot_gc_free_fixed_size_storage(interp, repr_data->allocation_size, PMC_data(obj));
 
907
    else
 
908
        mem_sys_free(PMC_data(obj));
 
909
    PMC_data(obj) = NULL;
 
910
}
 
911
 
 
912
/* This Parrot-specific addition to the API is used to mark a repr's
 
913
 * per-type data. */
 
914
static void gc_mark_repr_data(PARROT_INTERP, STable *st) {
 
915
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
916
    if (repr_data->name_to_index_mapping) {
 
917
        P6opaqueNameMap *cur_map_entry = repr_data->name_to_index_mapping;
 
918
        while (cur_map_entry->class_key != NULL) {
 
919
            Parrot_gc_mark_PMC_alive(interp, cur_map_entry->name_map);
 
920
            cur_map_entry++;
 
921
        }
 
922
    }
 
923
    if (repr_data->auto_viv_values) {
 
924
        int i;
 
925
        for (i = 0; i < repr_data->num_attributes; i++) {
 
926
            PMC *to_mark = repr_data->auto_viv_values[i];
 
927
            if (to_mark != NULL && !PMC_IS_NULL(to_mark))
 
928
                Parrot_gc_mark_PMC_alive(interp, to_mark);
 
929
        }
 
930
    }
 
931
}
 
932
 
 
933
/* This Parrot-specific addition to the API is used to free a repr instance. */
 
934
static void gc_free_repr_data(PARROT_INTERP, STable *st) {
 
935
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
936
    if (repr_data->name_to_index_mapping)
 
937
        mem_sys_free(repr_data->name_to_index_mapping);
 
938
    if (repr_data->gc_pmc_mark_offsets)
 
939
        mem_sys_free(repr_data->gc_pmc_mark_offsets);
 
940
    if (repr_data->auto_viv_values)
 
941
        mem_sys_free(repr_data->auto_viv_values);
 
942
    if (repr_data->initialize_slots)
 
943
        mem_sys_free(repr_data->initialize_slots);
 
944
    if (repr_data->gc_mark_slots)
 
945
        mem_sys_free(repr_data->gc_mark_slots);
 
946
    if (repr_data->gc_cleanup_slots)
 
947
        mem_sys_free(repr_data->gc_cleanup_slots);
 
948
    mem_sys_free(st->REPR_data);
 
949
    st->REPR_data = NULL;
 
950
}
 
951
 
 
952
/* Gets the storage specification for this representation. */
 
953
static storage_spec get_storage_spec(PARROT_INTERP, STable *st) {
 
954
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
955
    storage_spec spec;
 
956
    spec.inlineable = STORAGE_SPEC_REFERENCE;
 
957
    spec.boxed_primitive = STORAGE_SPEC_BP_NONE;
 
958
    spec.can_box = 0;
 
959
    spec.bits = sizeof(void *);
 
960
    spec.align = ALIGNOF1(void *);
 
961
    if (repr_data->unbox_int_slot >= 0)
 
962
        spec.can_box += STORAGE_SPEC_CAN_BOX_INT;
 
963
    if (repr_data->unbox_num_slot >= 0)
 
964
        spec.can_box += STORAGE_SPEC_CAN_BOX_NUM;
 
965
    if (repr_data->unbox_str_slot >= 0)
 
966
        spec.can_box += STORAGE_SPEC_CAN_BOX_STR;
 
967
    return spec;
 
968
}
 
969
 
 
970
/* Performs a change of type, where possible. */
 
971
static void change_type(PARROT_INTERP, PMC *obj, PMC *new_type) {
 
972
    P6opaqueInstance *instance      = (P6opaqueInstance *)PMC_data(obj);
 
973
    P6opaqueREPRData *cur_repr_data = (P6opaqueREPRData *)STABLE(obj)->REPR_data;
 
974
    P6opaqueREPRData *new_repr_data = (P6opaqueREPRData *)STABLE(new_type)->REPR_data;
 
975
    STRING           *mro_str       = Parrot_str_new_constant(interp, "mro");
 
976
    PMC              *cur_mro, *new_mro;
 
977
    INTVAL            cur_mro_elems, new_mro_elems, mro_is_suffix;
 
978
    
 
979
    /* Ensure we're not trying to change the type of a type object. */
 
980
    if (PObj_flag_TEST(private0, obj))
 
981
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
982
            "Cannot change the type of a type object");
 
983
    
 
984
    /* Ensure that the destination type REPR is P6opaque also. */
 
985
    if (REPR(obj) != REPR(new_type))
 
986
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
987
            "P6opaque can only change type to another type with P6opaque REPR");
 
988
 
 
989
    /* Ensure that MRO of new type has current type's MRO as a suffix. */
 
990
    mro_is_suffix = 1;
 
991
    cur_mro = introspection_call(interp, STABLE(obj)->WHAT, STABLE(obj)->HOW, mro_str, 0);
 
992
    new_mro = introspection_call(interp, STABLE(new_type)->WHAT, STABLE(new_type)->HOW, mro_str, 0);
 
993
    cur_mro_elems = VTABLE_elements(interp, cur_mro);
 
994
    new_mro_elems = VTABLE_elements(interp, new_mro);
 
995
    if (new_mro_elems >= cur_mro_elems) {
 
996
        INTVAL start = new_mro_elems - cur_mro_elems;
 
997
        INTVAL i;
 
998
        for (i = 0; i < cur_mro_elems; i++) {
 
999
            PMC *cur_elem = VTABLE_get_pmc_keyed_int(interp, cur_mro, i);
 
1000
            PMC *new_elem = VTABLE_get_pmc_keyed_int(interp, new_mro, i + start);
 
1001
            if (decontainerize(interp, cur_elem) != decontainerize(interp, new_elem)) {
 
1002
                mro_is_suffix = 0;
 
1003
                break;
 
1004
            }
 
1005
        }
 
1006
    }
 
1007
    else {
 
1008
        mro_is_suffix = 0;
 
1009
    }
 
1010
    if (!mro_is_suffix)
 
1011
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
1012
            "P6opaque only supports type changes where the MRO of the original type is a suffix of the MRO of the new type");
 
1013
    
 
1014
    /* If the new REPR never calculated it's object layout, do so now. */
 
1015
    if (!new_repr_data->allocation_size)
 
1016
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
1017
            "Representation must be composed before change_type");
 
1018
    
 
1019
    /* Reallocate ourself to the new allocation size, if needed, and
 
1020
     * ensure new chunk of the memory is zeroed. Note that we can't
 
1021
     * really re-alloc, we need to go deal with the fixed size pool
 
1022
     * allocator. */
 
1023
    if (new_repr_data->allocation_size > cur_repr_data->allocation_size) {
 
1024
        P6opaqueInstance *new_body = (P6opaqueInstance *) Parrot_gc_allocate_fixed_size_storage(interp, new_repr_data->allocation_size);
 
1025
        memset(new_body, 0, new_repr_data->allocation_size);
 
1026
        memcpy(new_body, instance, cur_repr_data->allocation_size);
 
1027
        PMC_data(obj) = new_body;
 
1028
        Parrot_gc_free_fixed_size_storage(interp, cur_repr_data->allocation_size, instance);
 
1029
        instance = new_body;
 
1030
    }
 
1031
    
 
1032
    /* Finally, we're ready to switch the S-Table pointer. */
 
1033
    instance->common.stable = STABLE_PMC(new_type);
 
1034
    PARROT_GC_WRITE_BARRIER(interp, obj);
 
1035
}
 
1036
 
 
1037
/* Serializes the data. */
 
1038
static void serialize(PARROT_INTERP, STable *st, void *data, SerializationWriter *writer) {
 
1039
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
1040
    INTVAL num_attributes, i;
 
1041
    
 
1042
    if (!repr_data->allocation_size)
 
1043
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
1044
            "Representation must be composed before it can be serialized");
 
1045
    
 
1046
    num_attributes = repr_data->num_attributes;
 
1047
    for (i = 0; i < num_attributes; i++) {
 
1048
        INTVAL a_offset = repr_data->attribute_offsets[i];
 
1049
        STable *a_st = repr_data->flattened_stables[i];
 
1050
        if (a_st) {
 
1051
            if (a_st->REPR->serialize)
 
1052
                a_st->REPR->serialize(interp, a_st, (char *)data + a_offset, writer);
 
1053
            else
 
1054
                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
1055
                    "Missing serialize REPR function");
 
1056
        }
 
1057
        else
 
1058
            writer->write_ref(interp, writer, get_pmc_at_offset(data, a_offset));
 
1059
    }
 
1060
}
 
1061
 
 
1062
/* Deserializes the data. */
 
1063
static void deserialize(PARROT_INTERP, STable *st, void *data, SerializationReader *reader) {
 
1064
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
1065
    INTVAL num_attributes = repr_data->num_attributes;
 
1066
    INTVAL i;
 
1067
    for (i = 0; i < num_attributes; i++) {
 
1068
        INTVAL a_offset = repr_data->attribute_offsets[i];
 
1069
        STable *a_st = repr_data->flattened_stables[i];
 
1070
        if (a_st)
 
1071
            a_st->REPR->deserialize(interp, a_st, (char *)data + a_offset, reader);
 
1072
        else
 
1073
            set_pmc_at_offset(data, a_offset, reader->read_ref(interp, reader));
 
1074
    }
 
1075
}
 
1076
 
 
1077
/* Serializes the REPR data. */
 
1078
static void serialize_repr_data(PARROT_INTERP, STable *st, SerializationWriter *writer) {
 
1079
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
 
1080
    INTVAL i, num_classes;
 
1081
    
 
1082
    if (!repr_data->allocation_size)
 
1083
        Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
 
1084
            "Representation must be composed before it can be serialized");
 
1085
    
 
1086
    writer->write_int(interp, writer, repr_data->num_attributes);
 
1087
 
 
1088
    for (i = 0; i < repr_data->num_attributes; i++) {
 
1089
        writer->write_int(interp, writer, repr_data->flattened_stables[i] != NULL);
 
1090
        if (repr_data->flattened_stables[i])
 
1091
            writer->write_stable_ref(interp, writer, repr_data->flattened_stables[i]);
 
1092
    }
 
1093
    
 
1094
    writer->write_int(interp, writer, repr_data->mi);
 
1095
    
 
1096
    if (repr_data->auto_viv_values) {
 
1097
        writer->write_int(interp, writer, 1);
 
1098
        for (i = 0; i < repr_data->num_attributes; i++)
 
1099
            writer->write_ref(interp, writer, repr_data->auto_viv_values[i]);
 
1100
    }
 
1101
    else {
 
1102
        writer->write_int(interp, writer, 0);
 
1103
    }
 
1104
    
 
1105
    writer->write_int(interp, writer, repr_data->unbox_int_slot);
 
1106
    writer->write_int(interp, writer, repr_data->unbox_num_slot);
 
1107
    writer->write_int(interp, writer, repr_data->unbox_str_slot);
 
1108
    
 
1109
    if (repr_data->unbox_slots) {
 
1110
        writer->write_int(interp, writer, 1);
 
1111
        for (i = 0; i < repr_data->num_attributes; i++) {
 
1112
            writer->write_int(interp, writer, repr_data->unbox_slots[i].repr_id);
 
1113
            writer->write_int(interp, writer, repr_data->unbox_slots[i].slot);
 
1114
        }
 
1115
    }
 
1116
    else {
 
1117
        writer->write_int(interp, writer, 0);
 
1118
    }
 
1119
    
 
1120
    num_classes = i = 0;
 
1121
    while (repr_data->name_to_index_mapping[i].class_key)
 
1122
        num_classes++, i++;
 
1123
    writer->write_int(interp, writer, num_classes);
 
1124
    for (i = 0; i < num_classes; i++) {
 
1125
        writer->write_ref(interp, writer, repr_data->name_to_index_mapping[i].class_key);
 
1126
        writer->write_ref(interp, writer, repr_data->name_to_index_mapping[i].name_map);
 
1127
    }
 
1128
    
 
1129
    if (writer->root.version >= 3) {
 
1130
        writer->write_int(interp, writer, repr_data->pos_del_slot);
 
1131
        writer->write_int(interp, writer, repr_data->ass_del_slot);
 
1132
    }
 
1133
}
 
1134
 
 
1135
/* Deserializes the data. */
 
1136
static void deserialize_repr_data(PARROT_INTERP, STable *st, SerializationReader *reader) {
 
1137
    P6opaqueREPRData *repr_data = (P6opaqueREPRData *) (st->REPR_data = mem_sys_allocate_zeroed(sizeof(P6opaqueREPRData)));
 
1138
    INTVAL i, num_classes, cur_offset, cur_initialize_slot, cur_gc_mark_slot, cur_gc_cleanup_slot;
 
1139
    
 
1140
    repr_data->num_attributes = reader->read_int(interp, reader);
 
1141
        
 
1142
    repr_data->flattened_stables = (STable **)mem_sys_allocate(MAX(repr_data->num_attributes, 1) * sizeof(STable *));
 
1143
    for (i = 0; i < repr_data->num_attributes; i++)
 
1144
        if (reader->read_int(interp, reader))
 
1145
            repr_data->flattened_stables[i] = reader->read_stable_ref(interp, reader);
 
1146
        else
 
1147
            repr_data->flattened_stables[i] = NULL;
 
1148
 
 
1149
    repr_data->mi = reader->read_int(interp, reader);
 
1150
    
 
1151
    if (reader->read_int(interp, reader)) {
 
1152
        repr_data->auto_viv_values = (PMC **)mem_sys_allocate(MAX(repr_data->num_attributes, 1) * sizeof(PMC *));
 
1153
        for (i = 0; i < repr_data->num_attributes; i++)
 
1154
            repr_data->auto_viv_values[i] = reader->read_ref(interp, reader);
 
1155
    }
 
1156
    
 
1157
    repr_data->unbox_int_slot = reader->read_int(interp, reader);
 
1158
    repr_data->unbox_num_slot = reader->read_int(interp, reader);
 
1159
    repr_data->unbox_str_slot = reader->read_int(interp, reader);
 
1160
    
 
1161
    if (reader->read_int(interp, reader)) {
 
1162
        repr_data->unbox_slots = (P6opaqueBoxedTypeMap *)mem_sys_allocate(MAX(repr_data->num_attributes, 1) * sizeof(P6opaqueBoxedTypeMap));
 
1163
        for (i = 0; i < repr_data->num_attributes; i++) {
 
1164
            repr_data->unbox_slots[i].repr_id = reader->read_int(interp, reader);
 
1165
            repr_data->unbox_slots[i].slot = reader->read_int(interp, reader);
 
1166
        }
 
1167
    }
 
1168
    
 
1169
    num_classes = reader->read_int(interp, reader);
 
1170
    repr_data->name_to_index_mapping = (P6opaqueNameMap *)mem_sys_allocate_zeroed((num_classes + 1) * sizeof(P6opaqueNameMap));
 
1171
    for (i = 0; i < num_classes; i++) {
 
1172
        repr_data->name_to_index_mapping[i].class_key = reader->read_ref(interp, reader);
 
1173
        repr_data->name_to_index_mapping[i].name_map = reader->read_ref(interp, reader);
 
1174
    }
 
1175
    
 
1176
    if (reader->root.version >= 3) {
 
1177
        repr_data->pos_del_slot = reader->read_int(interp, reader);
 
1178
        repr_data->ass_del_slot = reader->read_int(interp, reader);
 
1179
    }
 
1180
    else {
 
1181
        repr_data->pos_del_slot = -1;
 
1182
        repr_data->ass_del_slot = -1;
 
1183
    }
 
1184
    
 
1185
    /* Re-calculate the remaining info, which is platform specific or
 
1186
     * derived information. */
 
1187
    repr_data->attribute_offsets   = (INTVAL *)mem_sys_allocate(MAX(repr_data->num_attributes, 1) * sizeof(INTVAL));
 
1188
    repr_data->gc_pmc_mark_offsets = (INTVAL *)mem_sys_allocate(MAX(repr_data->num_attributes, 1) * sizeof(INTVAL));
 
1189
    repr_data->initialize_slots    = (INTVAL *)mem_sys_allocate((repr_data->num_attributes + 1) * sizeof(INTVAL));
 
1190
    repr_data->gc_mark_slots       = (INTVAL *)mem_sys_allocate((repr_data->num_attributes + 1) * sizeof(INTVAL));
 
1191
    repr_data->gc_cleanup_slots    = (INTVAL *)mem_sys_allocate((repr_data->num_attributes + 1) * sizeof(INTVAL));
 
1192
    repr_data->gc_pmc_mark_offsets_count = 0;
 
1193
    cur_offset          = 0;
 
1194
    cur_initialize_slot = 0;
 
1195
    cur_gc_mark_slot    = 0;
 
1196
    cur_gc_cleanup_slot = 0;
 
1197
    for (i = 0; i < repr_data->num_attributes; i++) {
 
1198
        if (repr_data->flattened_stables[i] == NULL) {
 
1199
            /* Align and store position. */
 
1200
            INTVAL align = ALIGNOF1(PMC *);
 
1201
            if (cur_offset % align) {
 
1202
                cur_offset += align - cur_offset % align;
 
1203
            }
 
1204
            repr_data->attribute_offsets[i] = cur_offset;
 
1205
            
 
1206
            /* Reference type. Needs marking. */
 
1207
            repr_data->gc_pmc_mark_offsets[repr_data->gc_pmc_mark_offsets_count] = cur_offset;
 
1208
            repr_data->gc_pmc_mark_offsets_count++;
 
1209
            
 
1210
            /* Increment by pointer size. */
 
1211
            cur_offset += sizeof(PMC *);
 
1212
        }
 
1213
        else {
 
1214
            /* Align and store position. */
 
1215
            STable *cur_st = repr_data->flattened_stables[i];
 
1216
            INTVAL align = cur_st->REPR->get_storage_spec(interp, cur_st).align;
 
1217
            if (cur_offset % align) {
 
1218
                cur_offset += align - cur_offset % align;
 
1219
            }
 
1220
            repr_data->attribute_offsets[i] = cur_offset;
 
1221
 
 
1222
            /* Set up flags for initialization and GC. */
 
1223
            if (cur_st->REPR->initialize)
 
1224
                repr_data->initialize_slots[cur_initialize_slot++] = i;
 
1225
            if (cur_st->REPR->gc_mark)
 
1226
                repr_data->gc_mark_slots[cur_gc_mark_slot++] = i;
 
1227
            if (cur_st->REPR->gc_cleanup)
 
1228
                repr_data->gc_cleanup_slots[cur_gc_cleanup_slot++] = i;
 
1229
            
 
1230
            /* Increment by size reported by representation. */
 
1231
            cur_offset += cur_st->REPR->get_storage_spec(interp, cur_st).bits / 8;
 
1232
        }
 
1233
    }
 
1234
    repr_data->initialize_slots[cur_initialize_slot] = -1;
 
1235
    repr_data->gc_mark_slots[cur_gc_mark_slot] = -1;
 
1236
    repr_data->gc_cleanup_slots[cur_gc_cleanup_slot] = -1;
 
1237
    
 
1238
    repr_data->allocation_size = sizeof(P6opaqueInstance) + cur_offset;
 
1239
}
 
1240
 
 
1241
/* Initializes the P6opaque representation. */
 
1242
REPROps * P6opaque_initialize(PARROT_INTERP) {
 
1243
    /* Allocate and populate the representation function table. */
 
1244
    this_repr = mem_allocate_zeroed_typed(REPROps);
 
1245
    this_repr->type_object_for = type_object_for;
 
1246
    this_repr->compose = compose;
 
1247
    this_repr->allocate = allocate;
 
1248
    this_repr->initialize = initialize;
 
1249
    this_repr->copy_to = copy_to;
 
1250
    this_repr->attr_funcs = mem_allocate_typed(REPROps_Attribute);
 
1251
    this_repr->attr_funcs->get_attribute_boxed = get_attribute_boxed;
 
1252
    this_repr->attr_funcs->get_attribute_native = get_attribute_native;
 
1253
    this_repr->attr_funcs->bind_attribute_boxed = bind_attribute_boxed;
 
1254
    this_repr->attr_funcs->bind_attribute_native = bind_attribute_native;
 
1255
    this_repr->attr_funcs->is_attribute_initialized = is_attribute_initialized;
 
1256
    this_repr->attr_funcs->hint_for = hint_for;
 
1257
    this_repr->box_funcs = mem_allocate_typed(REPROps_Boxing);
 
1258
    this_repr->box_funcs->set_int = set_int;
 
1259
    this_repr->box_funcs->get_int = get_int;
 
1260
    this_repr->box_funcs->set_num = set_num;
 
1261
    this_repr->box_funcs->get_num = get_num;
 
1262
    this_repr->box_funcs->set_str = set_str;
 
1263
    this_repr->box_funcs->get_str = get_str;
 
1264
    this_repr->box_funcs->get_boxed_ref = get_boxed_ref;
 
1265
    this_repr->pos_funcs = mem_allocate_zeroed_typed(REPROps_Positional);
 
1266
    this_repr->pos_funcs->at_pos_native = at_pos_native;
 
1267
    this_repr->pos_funcs->at_pos_boxed = at_pos_boxed;
 
1268
    this_repr->pos_funcs->bind_pos_native = bind_pos_native;
 
1269
    this_repr->pos_funcs->bind_pos_boxed = bind_pos_boxed;
 
1270
    this_repr->pos_funcs->push_boxed = push_boxed;
 
1271
    this_repr->pos_funcs->pop_boxed = pop_boxed;
 
1272
    this_repr->pos_funcs->unshift_boxed = unshift_boxed;
 
1273
    this_repr->pos_funcs->shift_boxed = shift_boxed;
 
1274
    this_repr->pos_funcs->get_elem_stable = get_elem_stable;
 
1275
    this_repr->ass_funcs = mem_allocate_typed(REPROps_Associative);
 
1276
    this_repr->ass_funcs->at_key_boxed = at_key_boxed;
 
1277
    this_repr->ass_funcs->bind_key_boxed = bind_key_boxed;
 
1278
    this_repr->ass_funcs->exists_key = exists_key;
 
1279
    this_repr->ass_funcs->delete_key = delete_key;
 
1280
    this_repr->elems = elems;
 
1281
    this_repr->gc_mark = gc_mark;
 
1282
    this_repr->gc_free = gc_free;
 
1283
    this_repr->gc_mark_repr_data = gc_mark_repr_data;
 
1284
    this_repr->gc_free_repr_data = gc_free_repr_data;
 
1285
    this_repr->get_storage_spec = get_storage_spec;
 
1286
    this_repr->change_type = change_type;
 
1287
    this_repr->serialize = serialize;
 
1288
    this_repr->deserialize = deserialize;
 
1289
    this_repr->serialize_repr_data = serialize_repr_data;
 
1290
    this_repr->deserialize_repr_data = deserialize_repr_data;
 
1291
    smo_id = Parrot_pmc_get_type_str(interp, Parrot_str_new(interp, "SixModelObject", 0));
 
1292
    return this_repr;
 
1293
}