/* Composes the representation. */ static void compose(PARROT_INTERP, STable *st, PMC *repr_info) { /* Compute allocation strategy. */ CStructREPRData *repr_data = (CStructREPRData *) st->REPR_data; PMC *attr_info = VTABLE_get_pmc_keyed_str(interp, repr_info, Parrot_str_new_constant(interp, "attribute")); compute_allocation_strategy(interp, attr_info, repr_data); PARROT_GC_WRITE_BARRIER(interp, st->stable_pmc); }
/* Gets the hint for the given attribute ID. */ static INTVAL hint_for(PARROT_INTERP, STable *st, PMC *class_key, STRING *name) { INTVAL slot; P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data; if (!repr_data->allocation_size) { compute_allocation_strategy(interp, st->WHAT, repr_data); PARROT_GC_WRITE_BARRIER(interp, st->stable_pmc); } slot = try_get_slot(interp, repr_data, class_key, name); return slot >= 0 ? slot : NO_HINT; }
/* Serializes the REPR data. */ static void serialize_repr_data(PARROT_INTERP, STable *st, SerializationWriter *writer) { P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data; INTVAL i, num_classes; if (!repr_data->allocation_size) { compute_allocation_strategy(interp, st->WHAT, repr_data); PARROT_GC_WRITE_BARRIER(interp, st->stable_pmc); } writer->write_int(interp, writer, repr_data->num_attributes); for (i = 0; i < repr_data->num_attributes; i++) { writer->write_int(interp, writer, repr_data->flattened_stables[i] != NULL); if (repr_data->flattened_stables[i]) writer->write_stable_ref(interp, writer, repr_data->flattened_stables[i]); } writer->write_int(interp, writer, repr_data->mi); if (repr_data->auto_viv_values) { writer->write_int(interp, writer, 1); for (i = 0; i < repr_data->num_attributes; i++) writer->write_ref(interp, writer, repr_data->auto_viv_values[i]); } else { writer->write_int(interp, writer, 0); } writer->write_int(interp, writer, repr_data->unbox_int_slot); writer->write_int(interp, writer, repr_data->unbox_num_slot); writer->write_int(interp, writer, repr_data->unbox_str_slot); if (repr_data->unbox_slots) { writer->write_int(interp, writer, 1); for (i = 0; i < repr_data->num_attributes; i++) { writer->write_int(interp, writer, repr_data->unbox_slots[i].repr_id); writer->write_int(interp, writer, repr_data->unbox_slots[i].slot); } } else { writer->write_int(interp, writer, 0); } num_classes = i = 0; while (repr_data->name_to_index_mapping[i].class_key) num_classes++, i++; writer->write_int(interp, writer, num_classes); for (i = 0; i < num_classes; i++) { writer->write_ref(interp, writer, repr_data->name_to_index_mapping[i].class_key); writer->write_ref(interp, writer, repr_data->name_to_index_mapping[i].name_map); } }
/* Creates a new instance based on the type object. */ static PMC * allocate(PARROT_INTERP, STable *st) { P6opaqueInstance * obj; /* Compute allocation strategy if we've not already done so. */ P6opaqueREPRData * repr_data = (P6opaqueREPRData *) st->REPR_data; if (!repr_data->allocation_size) { compute_allocation_strategy(interp, st->WHAT, repr_data); PARROT_GC_WRITE_BARRIER(interp, st->stable_pmc); } /* Allocate and set up object instance. */ obj = (P6opaqueInstance *) Parrot_gc_allocate_fixed_size_storage(interp, repr_data->allocation_size); memset(obj, 0, repr_data->allocation_size); obj->common.stable = st->stable_pmc; return wrap_object(interp, obj); }
/* Creates a new instance based on the type object. */ static PMC * instance_of(PARROT_INTERP, PMC *WHAT) { P6opaqueInstance * obj; /* Compute allocation strategy if we've not already done so. */ P6opaqueREPRData * repr_data = (P6opaqueREPRData *) STABLE(WHAT)->REPR_data; if (!repr_data->allocation_size) { compute_allocation_strategy(interp, WHAT, repr_data); PARROT_GC_WRITE_BARRIER(interp, STABLE_PMC(WHAT)); } /* Allocate and set up object instance. */ obj = (P6opaqueInstance *) Parrot_gc_allocate_fixed_size_storage(interp, repr_data->allocation_size); memset(obj, 0, repr_data->allocation_size); obj->common.stable = STABLE_PMC(WHAT); /* The spill slot gets set to PMCNULL; it not being (C) NULL is what * lets us know it's actually a real instance, not a type object. */ obj->spill = PMCNULL; return wrap_object(interp, obj); }
/* Serializes the data. */ static void serialize(PARROT_INTERP, STable *st, void *data, SerializationWriter *writer) { P6opaqueREPRData *repr_data = (P6opaqueREPRData *)st->REPR_data; INTVAL num_attributes, i; if (!repr_data->allocation_size) { compute_allocation_strategy(interp, st->WHAT, repr_data); PARROT_GC_WRITE_BARRIER(interp, st->stable_pmc); } num_attributes = repr_data->num_attributes; for (i = 0; i < num_attributes; i++) { INTVAL a_offset = repr_data->attribute_offsets[i]; STable *a_st = repr_data->flattened_stables[i]; if (a_st) { if (a_st->REPR->serialize) a_st->REPR->serialize(interp, a_st, (char *)data + a_offset, writer); else Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "Missing serialize REPR function"); } else writer->write_ref(interp, writer, get_pmc_at_offset(data, a_offset)); } }
/* Performs a change of type, where possible. */ static void change_type(PARROT_INTERP, PMC *obj, PMC *new_type) { P6opaqueInstance *instance = (P6opaqueInstance *)PMC_data(obj); P6opaqueREPRData *cur_repr_data = (P6opaqueREPRData *)STABLE(obj)->REPR_data; P6opaqueREPRData *new_repr_data = (P6opaqueREPRData *)STABLE(new_type)->REPR_data; STRING *mro_str = Parrot_str_new_constant(interp, "mro"); PMC *cur_mro, *new_mro; INTVAL cur_mro_elems, new_mro_elems, mro_is_suffix; /* Ensure we're not trying to change the type of a type object. */ if (PObj_flag_TEST(private0, obj)) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "Cannot change the type of a type object"); /* Ensure that the destination type REPR is P6opaque also. */ if (REPR(obj) != REPR(new_type)) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "P6opaque can only change type to another type with P6opaque REPR"); /* Ensure that MRO of new type has current type's MRO as a suffix. */ mro_is_suffix = 1; cur_mro = introspection_call(interp, STABLE(obj)->WHAT, STABLE(obj)->HOW, mro_str, 0); new_mro = introspection_call(interp, STABLE(new_type)->WHAT, STABLE(new_type)->HOW, mro_str, 0); cur_mro_elems = VTABLE_elements(interp, cur_mro); new_mro_elems = VTABLE_elements(interp, new_mro); if (new_mro_elems >= cur_mro_elems) { INTVAL start = new_mro_elems - cur_mro_elems; INTVAL i; for (i = 0; i < cur_mro_elems; i++) { PMC *cur_elem = VTABLE_get_pmc_keyed_int(interp, cur_mro, i); PMC *new_elem = VTABLE_get_pmc_keyed_int(interp, new_mro, i + start); if (decontainerize(interp, cur_elem) != decontainerize(interp, new_elem)) { mro_is_suffix = 0; break; } } } else { mro_is_suffix = 0; } if (!mro_is_suffix) Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, "P6opaque only supports type changes where the MRO of the original type is a suffix of the MRO of the new type"); /* If the new REPR never calculated it's object layout, do so now. */ if (!new_repr_data->allocation_size) { compute_allocation_strategy(interp, new_type, new_repr_data); PARROT_GC_WRITE_BARRIER(interp, STABLE_PMC(new_type)); } /* Reallocate ourself to the new allocation size, if needed, and * ensure new chunk of the memory is zeroed. Note that we can't * really re-alloc, we need to go deal with the fixed size pool * allocator. */ if (new_repr_data->allocation_size > cur_repr_data->allocation_size) { P6opaqueInstance *new_body = (P6opaqueInstance *) Parrot_gc_allocate_fixed_size_storage(interp, new_repr_data->allocation_size); memset(new_body, 0, new_repr_data->allocation_size); memcpy(new_body, instance, cur_repr_data->allocation_size); PMC_data(obj) = new_body; Parrot_gc_free_fixed_size_storage(interp, cur_repr_data->allocation_size, instance); instance = new_body; } /* Finally, we're ready to switch the S-Table pointer. */ instance->common.stable = STABLE_PMC(new_type); PARROT_GC_WRITE_BARRIER(interp, obj); }