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. */
9
#define PARROT_IN_EXTENSION
10
#include "parrot/parrot.h"
11
#include "parrot/extend.h"
12
#include "../sixmodelobject.h"
15
#define MAX(x, y) ((y) > (x) ? (y) : (x))
17
/* This representation's function pointer table. */
18
static REPROps *this_repr;
20
/* 6model object ID. */
21
static INTVAL smo_id = 0;
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)))
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) {
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))
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);
43
VTABLE_set_integer_keyed_str(interp, cappy, Parrot_str_new_constant(interp, "local"), 1);
46
Parrot_pcc_invoke_from_sig_object(interp, meth, cappy);
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);
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;
65
INTVAL num_classes, i;
66
P6opaqueNameMap * result = NULL;
68
/* Walk through the MRO backwards. */
69
INTVAL mro_idx = VTABLE_elements(interp, mro);
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));
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);
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)) {
86
PMC * attr_hash = VTABLE_shift_pmc(interp, attr_iter);
89
PMC *name_pmc = VTABLE_get_pmc_keyed_str(interp, attr_hash, name_str);
90
STRING *name = VTABLE_get_string(interp, name_pmc);
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));
99
/* Push attr onto the flat list. */
100
VTABLE_push_pmc(interp, flat_list, attr_hash);
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);
107
/* If there's more than one parent, flag that we in an MI
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);
120
repr_data->name_to_index_mapping = result;
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");
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.
143
* This is kind of minor evil until after I'll find better solution.
145
Parrot_block_GC_mark(interp);
147
/* Compute index mapping table and get flat list of attributes. */
148
flat_list = index_mapping_and_flat_list(interp, repr_info, repr_data);
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);
155
/* Otherwise, we need to compute the allocation strategy. */
157
/* We track the size of the body part, since that's what we want offsets into. */
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;
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;
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);
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);
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 *);
194
/* True if this member is flattened into the object body. */
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;
205
repr_data->flattened_stables[i] = STABLE(type);
208
if (bits % 8) bits += 8 - bits%8;
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;
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;
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;
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;
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;
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;
255
/* nothing, just suppress 'missing default' warning */
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;
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;
274
repr_data->attribute_offsets[i] = cur_size;
276
/* Handle PMC attributes, which need marking and may have auto-viv needs. */
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;
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;
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;
297
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
298
"Positional delegate attribute must be a reference type");
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;
307
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
308
"Associative delegate attribute must be a reference type");
311
/* Increment object size by the allocated bytes. */
312
cur_size += bits / 8;
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;
327
Parrot_unblock_GC_mark(interp);
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);
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;
342
/* Helper for finding a slot number. */
343
static INTVAL try_get_slot(PARROT_INTERP, P6opaqueREPRData *repr_data, PMC *class_key, STRING *name) {
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);
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)));
369
/* Creates a new type object of this representation, and associates it with
371
static PMC * type_object_for(PARROT_INTERP, PMC *HOW) {
372
/* Create new object instance. */
373
P6opaqueInstance *obj = mem_allocate_zeroed_typed(P6opaqueInstance);
375
/* Build an STable. */
376
PMC *st_pmc = create_stable(interp, this_repr, HOW);
377
STable *st = STABLE_STRUCT(st_pmc);
379
/* Create REPR data structure and hand it off the STable. */
380
st->REPR_data = mem_allocate_zeroed_typed(P6opaqueREPRData);
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);
387
/* Flag it as a type object. */
388
MARK_AS_TYPE_OBJECT(st->WHAT);
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);
402
/* Creates a new instance based on the type object. */
403
static PMC * allocate(PARROT_INTERP, STable *st) {
404
P6opaqueInstance * obj;
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");
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;
417
return wrap_object(interp, obj);
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) {
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);
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;
438
/* Copy main body. */
439
memcpy(dest, src, repr_data->allocation_size - sizeof(P6opaqueInstance));
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];
445
INTVAL offset = repr_data->attribute_offsets[i];
446
st_copy->REPR->copy_to(interp, st_copy, (char*)src + offset, (char*)dest + offset);
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)));
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;
466
/* Try the slot allocation first. */
467
slot = hint >= 0 && !(repr_data->mi) ? hint :
468
try_get_slot(interp, repr_data, class_handle, name);
470
if (!repr_data->flattened_stables[slot]) {
471
PMC *result = get_pmc_at_offset(data, repr_data->attribute_offsets[slot]);
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];
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);
488
set_pmc_at_offset(data, repr_data->attribute_offsets[slot], value);
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);
508
/* Otherwise, complain that the attribute doesn't exist. */
509
no_such_attribute(interp, "get", class_handle, name);
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;
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);
520
STable *st = repr_data->flattened_stables[slot];
521
void *ptr = ((char *)data) + repr_data->attribute_offsets[slot];
523
switch (value->type) {
524
case NATIVE_VALUE_INT:
525
value->value.intval = st->REPR->box_funcs->get_int(interp, st, ptr);
527
case NATIVE_VALUE_FLOAT:
528
value->value.floatval = st->REPR->box_funcs->get_num(interp, st, ptr);
530
case NATIVE_VALUE_STRING:
531
value->value.stringval = st->REPR->box_funcs->get_str(interp, st, ptr);
534
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
535
"Bad value of NativeValue.type: %d", value->type);
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)));
548
/* Otherwise, complain that the attribute doesn't exist. */
549
no_such_attribute(interp, "get", class_handle, name);
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;
557
/* Try the slot allocation first. */
558
slot = hint >= 0 && !(repr_data->mi) ? hint :
559
try_get_slot(interp, repr_data, class_handle, name);
561
STable *st = repr_data->flattened_stables[slot];
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]);
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)));
574
set_pmc_at_offset(data, repr_data->attribute_offsets[slot], value);
578
/* Otherwise, complain that the attribute doesn't exist. */
579
no_such_attribute(interp, "bind", class_handle, name);
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;
586
/* Try to find the slot. */
587
slot = hint >= 0 && !(repr_data->mi) ? hint :
588
try_get_slot(interp, repr_data, class_handle, name);
590
STable *st = repr_data->flattened_stables[slot];
591
void *ptr = (char *)data + repr_data->attribute_offsets[slot];
593
switch (value->type) {
594
case NATIVE_VALUE_INT:
595
st->REPR->box_funcs->set_int(interp, st, ptr, value->value.intval);
597
case NATIVE_VALUE_FLOAT:
598
st->REPR->box_funcs->set_num(interp, st, ptr, value->value.floatval);
600
case NATIVE_VALUE_STRING:
601
st->REPR->box_funcs->set_str(interp, st, ptr, value->value.stringval);
604
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
605
"Bad value of NativeValue.type: %d", value->type);
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)));
617
/* Otherwise, complain that the attribute doesn't exist. */
618
no_such_attribute(interp, "bind", class_handle, name);
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);
627
return NULL != get_pmc_at_offset(data, repr_data->attribute_offsets[slot]);
629
no_such_attribute(interp, "initializedness check", class_handle, name);
632
/* Gets the hint for the given attribute ID. */
633
static INTVAL hint_for(PARROT_INTERP, STable *st, PMC *class_key, STRING *name) {
635
P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data;
636
if (!repr_data->allocation_size)
638
slot = try_get_slot(interp, repr_data, class_key, name);
639
return slot >= 0 ? slot : NO_HINT;
642
/* Used with boxing. Sets an integer value, for representations that can hold
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);
651
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
652
"This type cannot box a native integer");
656
/* Used with boxing. Gets an integer value, for representations that can
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]);
665
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
666
"This type cannot unbox to a native integer");
670
/* Used with boxing. Sets a floating point value, for representations that can
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);
679
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
680
"This type cannot box a native number");
684
/* Used with boxing. Gets a floating point value, for representations that can
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]);
693
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
694
"This type cannot unbox to a native number");
698
/* Used with boxing. Sets a string value, for representations that can hold
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);
707
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
708
"This type cannot box a native string");
712
/* Used with boxing. Gets a string value, for representations that can hold
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]);
721
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
722
"This type cannot unbox to a native string");
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
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) {
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)
739
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
740
"get_boxed_ref could not unbox for the given representation");
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");
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");
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]),
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");
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]),
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]),
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]));
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]),
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]));
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");
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");
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]),
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]),
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]),
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]),
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]));
863
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
864
"This type does not support elems");
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;
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);
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);
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;
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);
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));
908
mem_sys_free(PMC_data(obj));
909
PMC_data(obj) = NULL;
912
/* This Parrot-specific addition to the API is used to mark a repr's
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);
923
if (repr_data->auto_viv_values) {
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);
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;
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;
956
spec.inlineable = STORAGE_SPEC_REFERENCE;
957
spec.boxed_primitive = STORAGE_SPEC_BP_NONE;
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;
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;
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");
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");
989
/* Ensure that MRO of new type has current type's MRO as a suffix. */
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;
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)) {
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");
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");
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
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;
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);
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;
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");
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];
1051
if (a_st->REPR->serialize)
1052
a_st->REPR->serialize(interp, a_st, (char *)data + a_offset, writer);
1054
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
1055
"Missing serialize REPR function");
1058
writer->write_ref(interp, writer, get_pmc_at_offset(data, a_offset));
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;
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];
1071
a_st->REPR->deserialize(interp, a_st, (char *)data + a_offset, reader);
1073
set_pmc_at_offset(data, a_offset, reader->read_ref(interp, reader));
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;
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");
1086
writer->write_int(interp, writer, repr_data->num_attributes);
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]);
1094
writer->write_int(interp, writer, repr_data->mi);
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]);
1102
writer->write_int(interp, writer, 0);
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);
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);
1117
writer->write_int(interp, writer, 0);
1120
num_classes = i = 0;
1121
while (repr_data->name_to_index_mapping[i].class_key)
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);
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);
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;
1140
repr_data->num_attributes = reader->read_int(interp, reader);
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);
1147
repr_data->flattened_stables[i] = NULL;
1149
repr_data->mi = reader->read_int(interp, reader);
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);
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);
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);
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);
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);
1181
repr_data->pos_del_slot = -1;
1182
repr_data->ass_del_slot = -1;
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;
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;
1204
repr_data->attribute_offsets[i] = cur_offset;
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++;
1210
/* Increment by pointer size. */
1211
cur_offset += sizeof(PMC *);
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;
1220
repr_data->attribute_offsets[i] = cur_offset;
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;
1230
/* Increment by size reported by representation. */
1231
cur_offset += cur_st->REPR->get_storage_spec(interp, cur_st).bits / 8;
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;
1238
repr_data->allocation_size = sizeof(P6opaqueInstance) + cur_offset;
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));