2 Copyright (C) 2007-2008, The Perl Foundation.
7 oo.c - Class and object
11 Handles class and object manipulation.
21 #define PARROT_IN_OO_C
22 #define PARROT_IN_OBJECTS_C /* To get the vtable.h imports we want. */
23 #include "parrot/parrot.h"
24 #include "parrot/oo_private.h"
25 #include "pmc/pmc_class.h"
29 /* HEADERIZER HFILE: include/parrot/oo.h */
31 /* HEADERIZER BEGIN: static */
33 PARROT_WARN_UNUSED_RESULT
34 PARROT_CAN_RETURN_NULL
35 static PMC
* C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
36 __attribute__nonnull__(1)
37 __attribute__nonnull__(2);
39 static void create_deleg_pmc_vtable(PARROT_INTERP
,
42 __attribute__nonnull__(1)
43 __attribute__nonnull__(2);
45 static void debug_trace_find_meth(PARROT_INTERP
,
46 ARGIN(const PMC
*_class
),
47 ARGIN(const STRING
*name
),
48 ARGIN_NULLOK(const PMC
*sub
))
49 __attribute__nonnull__(1)
50 __attribute__nonnull__(2)
51 __attribute__nonnull__(3);
53 static void do_initcall(PARROT_INTERP
,
54 ARGIN_NULLOK(PMC
* _class
),
55 ARGIN_NULLOK(PMC
*object
),
56 ARGIN_NULLOK(PMC
*init
))
57 __attribute__nonnull__(1);
59 static void fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
60 __attribute__nonnull__(1)
61 __attribute__nonnull__(2);
63 PARROT_WARN_UNUSED_RESULT
64 PARROT_CAN_RETURN_NULL
65 static PMC
* find_method_direct_1(PARROT_INTERP
,
67 ARGIN(STRING
*method_name
))
68 __attribute__nonnull__(1)
69 __attribute__nonnull__(2)
70 __attribute__nonnull__(3);
72 PARROT_WARN_UNUSED_RESULT
73 PARROT_CAN_RETURN_NULL
74 static PMC
* find_vtable_meth_ns(PARROT_INTERP
,
77 __attribute__nonnull__(1)
78 __attribute__nonnull__(2);
80 PARROT_WARN_UNUSED_RESULT
81 PARROT_CAN_RETURN_NULL
82 static PMC
* get_init_meth(PARROT_INTERP
,
84 ARGIN(STRING
*prop_str
),
85 ARGOUT(STRING
**meth_str
))
86 __attribute__nonnull__(1)
87 __attribute__nonnull__(2)
88 __attribute__nonnull__(3)
89 __attribute__nonnull__(4)
90 FUNC_MODIFIES(*meth_str
);
92 static void instantiate_object(PARROT_INTERP
,
94 ARGIN_NULLOK(PMC
*init
))
95 __attribute__nonnull__(1)
96 __attribute__nonnull__(2)
97 FUNC_MODIFIES(*object
);
99 static void invalidate_all_caches(PARROT_INTERP
)
100 __attribute__nonnull__(1);
102 static void invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
103 __attribute__nonnull__(1);
105 static void parrot_class_register(PARROT_INTERP
,
107 ARGIN(PMC
*new_class
),
108 ARGIN_NULLOK(PMC
*parent
),
110 __attribute__nonnull__(1)
111 __attribute__nonnull__(2)
112 __attribute__nonnull__(3)
113 __attribute__nonnull__(5);
115 static void rebuild_attrib_stuff(PARROT_INTERP
, ARGIN(PMC
*_class
))
116 __attribute__nonnull__(1)
117 __attribute__nonnull__(2);
119 /* HEADERIZER END: static */
123 =item C<void Parrot_oo_extract_methods_from_namespace>
125 Extract methods and vtable overrides from the given namespace and insert them
133 Parrot_oo_extract_methods_from_namespace(PARROT_INTERP
, ARGIN(PMC
*self
), ARGIN(PMC
*ns
))
135 PMC
*methods
, *vtable_overrides
;
137 /* Pull in methods from the namespace, if any. */
141 /* Import any methods. */
142 Parrot_PCCINVOKE(interp
, ns
,
143 CONST_STRING(interp
, "get_associated_methods"), "->P", &methods
);
145 if (!PMC_IS_NULL(methods
)) {
146 PMC
* const iter
= VTABLE_get_iter(interp
, methods
);
148 while (VTABLE_get_bool(interp
, iter
)) {
149 STRING
* const meth_name
= VTABLE_shift_string(interp
, iter
);
150 PMC
* const meth_sub
= VTABLE_get_pmc_keyed_str(interp
, methods
,
152 VTABLE_add_method(interp
, self
, meth_name
, meth_sub
);
156 /* Import any vtable methods. */
157 Parrot_PCCINVOKE(interp
, ns
,
158 CONST_STRING(interp
, "get_associated_vtable_methods"), "->P", &vtable_overrides
);
160 if (!PMC_IS_NULL(vtable_overrides
)) {
161 PMC
* const iter
= VTABLE_get_iter(interp
, vtable_overrides
);
162 while (VTABLE_get_bool(interp
, iter
)) {
163 STRING
* const vtable_index_str
= VTABLE_shift_string(interp
, iter
);
164 PMC
* const vtable_sub
= VTABLE_get_pmc_keyed_str(interp
,
165 vtable_overrides
, vtable_index_str
);
167 /* Look up the name of the vtable function from the index. */
168 const INTVAL vtable_index
= string_to_int(interp
, vtable_index_str
);
169 const char * const meth_c
= Parrot_vtable_slot_names
[vtable_index
];
170 STRING
*vtable_name
= string_from_cstring(interp
, meth_c
, 0);
172 /* Strip leading underscores in the vtable name */
173 if (string_str_index(interp
, vtable_name
,
174 CONST_STRING(interp
, "__"), 0) == 0) {
175 vtable_name
= string_substr(interp
, vtable_name
, 2,
176 string_length(interp
, vtable_name
) - 2, NULL
, 0);
179 VTABLE_add_vtable_override(interp
, self
, vtable_name
, vtable_sub
);
187 =item C<PMC * Parrot_oo_get_namespace>
189 Lookup a namespace object from a class PMC.
195 PARROT_CAN_RETURN_NULL
196 PARROT_WARN_UNUSED_RESULT
198 Parrot_oo_get_namespace(SHIM_INTERP
, ARGIN(const PMC
*classobj
))
200 Parrot_Class
* const _class
= PARROT_CLASS(classobj
);
201 PMC
* const _namespace
= _class
->_namespace
;
203 if (PMC_IS_NULL(_namespace
))
212 =item C<PMC * Parrot_oo_get_class>
214 Lookup a class object from a namespace, string, or key PMC.
221 PARROT_CAN_RETURN_NULL
222 PARROT_WARN_UNUSED_RESULT
224 Parrot_oo_get_class(PARROT_INTERP
, ARGIN(PMC
*key
))
226 PMC
*classobj
= PMCNULL
;
228 if (PObj_is_class_TEST(key
))
231 /* Fast select of behavior based on type of the lookup key */
232 switch (key
->vtable
->base_type
) {
233 case enum_class_NameSpace
:
234 classobj
= VTABLE_get_class(interp
, key
);
237 case enum_class_String
:
239 case enum_class_ResizableStringArray
:
241 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
,
242 interp
->HLL_namespace
,
243 CONTEXT(interp
)->current_HLL
);
244 PMC
* const ns
= Parrot_get_namespace_keyed(interp
,
247 if (!PMC_IS_NULL(ns
))
248 classobj
= VTABLE_get_class(interp
, ns
);
255 if (PMC_IS_NULL(classobj
)) {
256 /* Look up a low-level class and create a proxy */
257 const INTVAL type
= pmc_type(interp
, VTABLE_get_string(interp
, key
));
259 /* Reject invalid type numbers */
260 if (type
> interp
->n_vtable_max
|| type
<= 0)
263 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
264 VTABLE_set_integer_native(interp
, type_num
, type
);
265 return pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
275 =item C<PMC * Parrot_oo_get_class_str>
277 Lookup a class object from a builtin string.
284 PARROT_CAN_RETURN_NULL
285 PARROT_WARN_UNUSED_RESULT
287 Parrot_oo_get_class_str(PARROT_INTERP
, ARGIN(STRING
*name
))
289 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
, interp
->HLL_namespace
,
290 CONTEXT(interp
)->current_HLL
);
291 PMC
* const ns
= Parrot_get_namespace_keyed_str(interp
, hll_ns
, name
);
292 PMC
* const _class
= PMC_IS_NULL(ns
)
293 ? PMCNULL
: VTABLE_get_class(interp
, ns
);
295 /* Look up a low-level class and create a proxy */
296 if (PMC_IS_NULL(_class
)) {
297 const INTVAL type
= pmc_type(interp
, name
);
299 /* Reject invalid type numbers */
300 if (type
> interp
->n_vtable_max
|| type
<= 0)
303 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
304 VTABLE_set_integer_native(interp
, type_num
, type
);
305 return pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
315 =item C<PMC * Parrot_oo_newclass_from_str>
317 Create a new class object from a string name.
323 PARROT_CAN_RETURN_NULL
324 PARROT_WARN_UNUSED_RESULT
326 Parrot_oo_newclass_from_str(PARROT_INTERP
, ARGIN(STRING
*name
))
328 PMC
* const namearg
= pmc_new(interp
, enum_class_String
);
329 PMC
*namehash
= pmc_new(interp
, enum_class_Hash
);
332 VTABLE_set_string_native(interp
, namearg
, name
);
333 VTABLE_set_pmc_keyed_str(interp
, namehash
, CONST_STRING(interp
, "name"), namearg
);
335 classobj
= pmc_new_init(interp
, enum_class_Class
, namehash
);
337 PARROT_ASSERT(classobj
);
344 =item C<PMC * Parrot_oo_find_vtable_override_for_class>
346 Lookup a vtable override in a specific class object.
352 PARROT_CAN_RETURN_NULL
353 PARROT_WARN_UNUSED_RESULT
355 Parrot_oo_find_vtable_override_for_class(PARROT_INTERP
,
356 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
358 Parrot_Class
*class_info
;
359 PARROT_ASSERT(PObj_is_class_TEST(classobj
));
361 class_info
= PARROT_CLASS(classobj
);
362 return VTABLE_get_pmc_keyed_str(interp
, class_info
->vtable_overrides
, name
);
368 =item C<PMC * Parrot_oo_find_vtable_override>
370 Lookup a vtable override in a class, including any vtable overrides inherited
377 PARROT_CAN_RETURN_NULL
378 PARROT_WARN_UNUSED_RESULT
380 Parrot_oo_find_vtable_override(PARROT_INTERP
,
381 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
383 Parrot_Class
* const _class
= PARROT_CLASS(classobj
);
385 /* Walk and search for the vtable method. */
386 const INTVAL num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
389 for (i
= 0; i
< num_classes
; i
++) {
391 PMC
* const cur_class
=
392 VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, i
);
395 Parrot_oo_find_vtable_override_for_class(interp
, cur_class
, name
);
397 if (!PMC_IS_NULL(meth
))
407 =item C<INTVAL Parrot_get_vtable_index>
409 Return index if C<name> is a valid vtable slot name.
417 Parrot_get_vtable_index(PARROT_INTERP
, ARGIN(const STRING
*name
))
419 char * const name_c
= string_to_cstring(interp
, name
);
421 /* some of the first "slots" don't have names. skip 'em. */
422 INTVAL low
= PARROT_VTABLE_LOW
;
423 INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
426 const INTVAL mid
= (low
+ high
) / 2;
427 const char * const meth_c
= Parrot_vtable_slot_names
[mid
];
429 /* RT#45965 slot_names still have __ in front */
430 const INTVAL cmp
= strcmp(name_c
, meth_c
+ 2);
433 string_cstring_free(name_c
);
442 string_cstring_free(name_c
);
450 =item C<static PMC* find_vtable_meth_ns>
452 Return Sub PMC if a method with the vtable name exists in ns
458 PARROT_WARN_UNUSED_RESULT
459 PARROT_CAN_RETURN_NULL
461 find_vtable_meth_ns(PARROT_INTERP
, ARGIN(PMC
*ns
), INTVAL vtable_index
)
463 return VTABLE_get_pmc_keyed_int(interp
, ns
, vtable_index
);
469 =item C<PMC* Parrot_find_vtable_meth>
471 Given pmc, run through its mro looking for the meth vtable method.
472 Return the vtable method PMC if found.
479 PARROT_CAN_RETURN_NULL
481 Parrot_find_vtable_meth(PARROT_INTERP
, ARGIN(PMC
*pmc
), ARGIN(STRING
*meth
))
487 /* Get index in Parrot_vtable_slot_names[]. */
488 const INTVAL vtable_index
= Parrot_get_vtable_index(interp
, meth
);
490 if (vtable_index
== -1)
494 if (PObj_is_object_TEST(pmc
))
495 _class
= GET_CLASS(pmc
);
497 /* Get MRO and iterate over it to find method with a matching
498 vtable index or double-underscored name. */
499 mro
= _class
->vtable
->mro
;
500 n
= VTABLE_elements(interp
, mro
);
502 for (i
= 0; i
< n
; ++i
) {
503 PMC
*ns
= VTABLE_get_namespace(interp
, _class
);
504 PMC
*_class
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
506 if (!PMC_IS_NULL(ns
)) {
507 PMC
* const res
= find_vtable_meth_ns(interp
, ns
, vtable_index
);
509 if (!PMC_IS_NULL(res
))
514 /* If we get here, method is not overridden in the class. */
521 =item C<STRING* readable_name>
523 Given a String or Key PMC return the STRING* representation
525 RT#45967 this function, key_set_to_string, and the key PMC get_repr should be
533 PARROT_WARN_UNUSED_RESULT
534 PARROT_CANNOT_RETURN_NULL
536 readable_name(PARROT_INTERP
, ARGIN(PMC
*name
))
540 if (name
->vtable
->base_type
== enum_class_String
)
541 return VTABLE_get_string(interp
, name
);
543 array
= pmc_new(interp
, enum_class_ResizableStringArray
);
545 PARROT_ASSERT(name
->vtable
->base_type
== enum_class_Key
);
548 VTABLE_push_string(interp
, array
, key_string(interp
, name
));
549 name
= key_next(interp
, name
);
552 return string_join(interp
, CONST_STRING(interp
, ";"), array
);
558 =item C<static void rebuild_attrib_stuff>
560 Take the class and completely rebuild the attribute stuff for
561 it. Horribly destructive, and definitely not a good thing to do if
562 there are instantiated objects for the class
569 rebuild_attrib_stuff(PARROT_INTERP
, ARGIN(PMC
*_class
))
571 INTVAL attr_count
, cur_offset
, n_class
, n_mro
, offset
;
572 PMC
*attr_offset_hash
, *mro
, *attribs
;
573 SLOTTYPE
*class_slots
;
576 PMC
* const orig_class
= _class
;
579 /* attrib count isn't set yet, a GC caused by concat could
580 * corrupt data under construction */
581 Parrot_block_DOD(interp
);
583 class_slots
= PMC_data_typed(_class
, SLOTTYPE
*);
584 attr_offset_hash
= pmc_new(interp
, enum_class_Hash
);
585 set_attrib_num(_class
, class_slots
, PCD_ATTRIBUTES
, attr_offset_hash
);
587 mro
= _class
->vtable
->mro
;
588 n_mro
= VTABLE_elements(interp
, mro
);
590 /* walk from oldest parent down to n_class == 0 which is this class */
593 for (n_class
= n_mro
- 1; n_class
>= 0; --n_class
) {
596 _class
= VTABLE_get_pmc_keyed_int(interp
, mro
, n_class
);
598 /* this Class isa PMC - no attributes there */
599 if (!PObj_is_class_TEST(_class
))
602 class_slots
= PMC_data_typed(_class
, SLOTTYPE
*);
603 classname
= VTABLE_get_string(interp
,
604 get_attrib_num(class_slots
, PCD_CLASS_NAME
));
605 attribs
= get_attrib_num(class_slots
, PCD_CLASS_ATTRIBUTES
);
606 attr_count
= VTABLE_elements(interp
, attribs
);
609 STRING
* const partial_name
= string_concat(interp
, classname
,
610 CONST_STRING(interp
, "\0"), 0);
612 for (offset
= 0; offset
< attr_count
; offset
++) {
613 STRING
* const attr_name
=
614 VTABLE_get_string_keyed_int(interp
, attribs
, offset
);
615 STRING
* const full_name
=
616 string_concat(interp
, partial_name
, attr_name
, 0);
618 /* store this attribute with short and full name */
620 VTABLE_set_integer_keyed_str(interp
, attr_offset_hash
,
621 attr_name
, cur_offset
);
622 VTABLE_set_integer_keyed_str(interp
, attr_offset_hash
,
623 full_name
, cur_offset
);
630 PARROT_ASSERT(_class
== orig_class
);
633 /* And note the totals */
634 CLASS_ATTRIB_COUNT(_class
) = cur_offset
;
635 Parrot_unblock_DOD(interp
);
641 =item C<static void create_deleg_pmc_vtable>
643 Create a vtable that dispatches either to the contained PMC in the first
644 attribute (deleg_pmc) or to an overridden method (delegate), depending
645 on the existence of the method for this class.
652 create_deleg_pmc_vtable(PARROT_INTERP
, ARGIN(PMC
*_class
), int full
)
659 PMC
* const vtable_pmc
= get_attrib_num(PMC_data_typed(_class
,
660 SLOTTYPE
*), PCD_OBJECT_VTABLE
);
661 VTABLE
* const vtable
= (VTABLE
*)PMC_struct_val(vtable_pmc
);
662 VTABLE
* const ro_vtable
= vtable
->ro_variant_vtable
;
663 VTABLE
* const deleg_pmc_vtable
= interp
->vtables
[enum_class_deleg_pmc
];
664 VTABLE
* const object_vtable
= interp
->vtables
[enum_class_Object
];
665 VTABLE
* const ro_object_vtable
= object_vtable
->ro_variant_vtable
;
666 VTABLE
* const delegate_vtable
= interp
->vtables
[enum_class_delegate
];
668 memset(&meth_str
, 0, sizeof (meth_str
));
670 meth_str
.encoding
= Parrot_fixed_8_encoding_ptr
;
671 meth_str
.charset
= Parrot_default_charset_ptr
;
673 for (i
= 0; (meth
= Parrot_vtable_slot_names
[i
]) != NULL
; ++i
) {
677 /* strip underscores from method name */
678 meth_str
.strstart
= (char *)const_cast(meth
+ 2);
679 meth_str
.strlen
= meth_str
.bufused
= strlen(meth
) - 2;
680 meth_str
.hashval
= 0;
682 if (!PMC_IS_NULL(Parrot_find_vtable_meth(interp
, _class
, &meth_str
))) {
683 /* the method exists; keep the ParrotObject delegate vtable slot */
684 ((void **)vtable
)[i
] = ((void**)object_vtable
)[i
];
686 ((void **)ro_vtable
)[i
] = ((void**)ro_object_vtable
)[i
];
690 * the method doesn't exist; put in the deleg_pmc vtable,
691 * but only if ParrotObject hasn't overridden the method
693 if (((void **)delegate_vtable
)[i
] == ((void**)object_vtable
)[i
]) {
695 ((void **)ro_vtable
)[i
] = ((void**)deleg_pmc_vtable
)[i
];
696 ((void **)vtable
)[i
] = ((void**)deleg_pmc_vtable
)[i
];
699 ((void **)vtable
)[i
] = ((void**)object_vtable
)[i
];
701 ((void **)ro_vtable
)[i
] = ((void**)ro_object_vtable
)[i
];
711 =item C<const char* Parrot_MMD_method_name>
713 Return the method name for the given MMD enum.
721 PARROT_CAN_RETURN_NULL
723 Parrot_MMD_method_name(SHIM_INTERP
, INTVAL idx
)
725 PARROT_ASSERT(idx
>= 0);
727 if (idx
>= MMD_USER_FIRST
)
730 return Parrot_mmd_func_names
[idx
];
736 =item C<INTVAL Parrot_MMD_method_idx>
738 Return the MMD function number for method name or -1 on failure.
740 RT#45973 allow dynamic expansion at runtime.
749 Parrot_MMD_method_idx(SHIM_INTERP
, ARGIN(const char *name
))
753 for (i
= 0; i
< MMD_USER_FIRST
; ++i
) {
754 if (STREQ(Parrot_mmd_func_names
[i
], name
))
764 =item C<PMC * Parrot_single_subclass>
766 Subclass a class. Single parent class, nice and straightforward. If
767 C<child_class> is C<NULL>, this is an anonymous subclass we're creating,
775 PARROT_WARN_UNUSED_RESULT
776 PARROT_CANNOT_RETURN_NULL
778 Parrot_single_subclass(PARROT_INTERP
, ARGIN(PMC
*base_class
), ARGIN_NULLOK(PMC
*name
))
780 PMC
*child_class
, *parents
, *temp_pmc
, *mro
;
781 SLOTTYPE
*child_class_array
;
784 /* Set the classname, if we have one */
785 if (!PMC_IS_NULL(name
)) {
786 fail_if_type_exists(interp
, name
);
789 /* RT#45975 not really threadsafe but good enough for now */
790 static int anon_count
;
791 STRING
* const child_class_name
=
792 Parrot_sprintf_c(interp
, "%c%canon_%d", 0, 0, ++anon_count
);
793 name
= pmc_new(interp
, enum_class_String
);
794 VTABLE_set_string_native(interp
, name
, child_class_name
);
797 /* ParrotClass is the baseclass anyway, so build just a new class */
798 if (base_class
== interp
->vtables
[enum_class_Class
]->pmc_class
)
799 return pmc_new_init(interp
, enum_class_Class
, name
);
801 parent_is_class
= PObj_is_class_TEST(base_class
);
802 child_class
= pmc_new(interp
, enum_class_Class
);
804 /* Hang an array off the data pointer */
805 set_attrib_array_size(child_class
, PCD_MAX
);
806 child_class_array
= PMC_data_typed(child_class
, SLOTTYPE
*);
807 set_attrib_flags(child_class
);
809 /* We will have five entries in this array */
811 /* We have the same number of attributes as our parent */
812 CLASS_ATTRIB_COUNT(child_class
) = parent_is_class
?
813 CLASS_ATTRIB_COUNT(base_class
) : 0;
815 /* Our parent class array has a single member in it */
816 parents
= pmc_new(interp
, enum_class_ResizablePMCArray
);
818 VTABLE_set_integer_native(interp
, parents
, 1);
819 VTABLE_set_pmc_keyed_int(interp
, parents
, 0, base_class
);
821 set_attrib_num(child_class
, child_class_array
, PCD_PARENTS
, parents
);
822 set_attrib_num(child_class
, child_class_array
, PCD_CLASS_NAME
, name
);
824 /* Our mro list is a clone of our parent's mro list,
825 * with our self unshifted onto the beginning */
826 mro
= VTABLE_clone(interp
, base_class
->vtable
->mro
);
827 VTABLE_unshift_pmc(interp
, mro
, child_class
);
829 /* But we have no attributes of our own. Yet */
830 temp_pmc
= pmc_new(interp
, enum_class_ResizablePMCArray
);
831 set_attrib_num(child_class
, child_class_array
, PCD_CLASS_ATTRIBUTES
,
834 parrot_class_register(interp
, name
, child_class
, base_class
, mro
);
835 rebuild_attrib_stuff(interp
, child_class
);
837 if (!parent_is_class
) {
838 /* we append one attribute to hold the PMC */
839 Parrot_add_attribute(interp
, child_class
,
840 CONST_STRING(interp
, "__value"));
842 * then create a vtable derived from ParrotObject and
843 * deleg_pmc - the ParrotObject vtable is already built
845 create_deleg_pmc_vtable(interp
, child_class
, 1);
849 * if any parent isa PMC, then still individual vtables might
850 * be overridden in this subclass
853 int any_pmc_parent
= 0;
854 const int n
= VTABLE_elements(interp
, mro
);
856 /* 0 = this, 1 = parent (handled above), 2 = grandpa */
857 for (i
= 2; i
< n
; ++i
) {
858 const PMC
* const parent
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
859 if (!PObj_is_class_TEST(parent
)) {
865 create_deleg_pmc_vtable(interp
, child_class
, 0);
874 =item C<PMC * Parrot_class_lookup>
876 Looks for the class named C<class_name> and returns it if it exists.
877 Otherwise it returns C<PMCNULL>.
884 PARROT_CAN_RETURN_NULL
885 PARROT_WARN_UNUSED_RESULT
887 Parrot_class_lookup(PARROT_INTERP
, ARGIN(STRING
*class_name
))
889 const INTVAL type
= pmc_type(interp
, class_name
);
895 pmc
= interp
->vtables
[type
]->pmc_class
;
903 =item C<PMC * Parrot_class_lookup_p>
905 Looks for the class named C<class_name> and returns it if it exists.
906 Otherwise it returns C<PMCNULL>.
912 PARROT_CAN_RETURN_NULL
913 PARROT_WARN_UNUSED_RESULT
915 Parrot_class_lookup_p(PARROT_INTERP
, ARGIN(PMC
*class_name
))
917 const INTVAL type
= pmc_type_p(interp
, class_name
);
923 pmc
= interp
->vtables
[type
]->pmc_class
;
931 =item C<static void fail_if_type_exists>
933 This function throws an exception if a PMC or class with the same name *
934 already exists in the global type registry. The global type registry
935 will go away eventually, but this allows the new object metamodel to
936 interact with the old one until it does.
943 fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
947 PMC
* const classname_hash
= interp
->class_hash
;
948 PMC
* const type_pmc
= (PMC
*)VTABLE_get_pointer_keyed(interp
,
949 classname_hash
, name
);
951 if (PMC_IS_NULL(type_pmc
)
952 || type_pmc
->vtable
->base_type
== enum_class_NameSpace
)
955 type
= VTABLE_get_integer(interp
, type_pmc
);
957 if (type
> enum_type_undef
)
958 /* RT#46091 get printable name */
959 real_exception(interp
, NULL
, INVALID_OPERATION
,
960 "Class %Ss already registered!\n",
961 VTABLE_get_string(interp
, name
));
963 if (type
< enum_type_undef
)
964 real_exception(interp
, NULL
, INVALID_OPERATION
,
965 "native type with name '%s' already exists - "
966 "can't register Class", data_types
[type
].name
);
972 =item C<INTVAL Parrot_oo_register_type>
974 This function registers a type in the global registry, first checking if it
975 already exists. The global type registry will go away eventually, but this
976 allows the new object metamodel to interact with the old one until it does.
982 PARROT_WARN_UNUSED_RESULT
984 Parrot_oo_register_type(PARROT_INTERP
, ARGIN(PMC
*name
))
987 PMC
*classname_hash
, *item
;
989 fail_if_type_exists(interp
, name
);
991 /* Type doesn't exist, so go ahead and register it. Lock interpreter so
992 * pt_shared_fixup() can safely do a type lookup. */
993 LOCK_INTERPRETER(interp
);
994 classname_hash
= interp
->class_hash
;
996 type
= interp
->n_vtable_max
++;
998 /* Have we overflowed the table? */
999 if (type
>= interp
->n_vtable_alloced
)
1000 parrot_realloc_vtables(interp
);
1002 /* set entry in name->type hash */
1003 item
= pmc_new(interp
, enum_class_Integer
);
1004 PMC_int_val(item
) = type
;
1006 VTABLE_set_pmc_keyed(interp
, classname_hash
, name
, item
);
1007 UNLOCK_INTERPRETER(interp
);
1015 =item C<static void parrot_class_register>
1017 This is the way to register a new Parrot class as an instantiable
1018 type. Doing this involves putting it in the class hash, setting its
1019 vtable so that the C<init> method initializes objects of the class rather than
1020 the class itself, and adding it to the interpreter's base type table so
1021 you can create a new C<foo> in PASM like this: C<new Px, foo>.
1028 parrot_class_register(PARROT_INTERP
, ARGIN(PMC
*name
),
1029 ARGIN(PMC
*new_class
), ARGIN_NULLOK(PMC
*parent
), ARGIN(PMC
*mro
))
1032 const INTVAL new_type
= Parrot_oo_register_type(interp
, name
);
1034 /* check if we already have a NameSpace */
1035 PMC
*top
= CONTEXT(interp
)->current_namespace
;
1036 PMC
*ns
= VTABLE_get_pmc_keyed(interp
, top
, name
);
1038 /* Build a new vtable for this class
1039 * The child class PMC gets the vtable of its parent class or
1040 * a ParrotClass vtable
1042 VTABLE
*parent_vtable
=
1043 (parent
&& PObj_is_class_TEST(parent
))
1045 : new_class
->vtable
;
1047 VTABLE
*new_vtable
= Parrot_clone_vtable(interp
, parent_vtable
);
1049 /* Set the vtable's type to the newly allocated type */
1050 new_vtable
->base_type
= new_type
;
1052 /* And cache our class PMC in the vtable so we can find it later */
1053 new_vtable
->pmc_class
= new_class
;
1054 new_vtable
->mro
= mro
;
1056 if (parent_vtable
->ro_variant_vtable
)
1057 new_vtable
->ro_variant_vtable
=
1058 Parrot_clone_vtable(interp
, parent_vtable
->ro_variant_vtable
);
1060 /* Reset the init method to our instantiation method */
1061 new_vtable
->init
= Parrot_instantiate_object
;
1062 new_vtable
->init_pmc
= Parrot_instantiate_object_init
;
1063 new_class
->vtable
= new_vtable
;
1065 /* Put our new vtable in the global table */
1066 interp
->vtables
[new_type
] = new_vtable
;
1068 /* RT#45979 nested, use current as base ? */
1069 if (PMC_IS_NULL(ns
)) {
1070 /* RT#45983 try HLL namespace too */
1071 top
= Parrot_get_ctx_HLL_namespace(interp
);
1072 ns
= VTABLE_get_pmc_keyed(interp
, top
, name
);
1075 if (PMC_IS_NULL(ns
)) {
1076 ns
= pmc_new(interp
, enum_class_NameSpace
);
1077 VTABLE_set_pmc_keyed(interp
, top
, name
, ns
);
1080 /* attach namespace to vtable */
1081 new_vtable
->_namespace
= ns
;
1083 if (new_vtable
->ro_variant_vtable
) {
1084 VTABLE
* const ro_vt
= new_vtable
->ro_variant_vtable
;
1086 ro_vt
->base_type
= new_vtable
->base_type
;
1087 ro_vt
->pmc_class
= new_vtable
->pmc_class
;
1088 ro_vt
->mro
= new_vtable
->mro
;
1089 ro_vt
->_namespace
= new_vtable
->_namespace
;
1093 * prepare object vtable - again that of the parent or
1094 * a ParrotObject vtable
1096 if (parent
&& PObj_is_class_TEST(parent
)) {
1098 get_attrib_num((SLOTTYPE
*)PMC_data(parent
), PCD_OBJECT_VTABLE
);
1099 parent_vtable
= (VTABLE
*)PMC_struct_val(vtable_pmc
);
1102 parent_vtable
= interp
->vtables
[enum_class_Object
];
1104 new_vtable
= Parrot_clone_vtable(interp
, parent_vtable
);
1106 if (parent_vtable
->ro_variant_vtable
)
1107 new_vtable
->ro_variant_vtable
=
1108 Parrot_clone_vtable(interp
, parent_vtable
->ro_variant_vtable
);
1110 new_vtable
->base_type
= new_type
;
1111 new_vtable
->mro
= mro
;
1112 new_vtable
->pmc_class
= new_class
;
1114 set_attrib_num(new_class
, (SLOTTYPE
*)PMC_data(new_class
), PCD_OBJECT_VTABLE
,
1115 vtable_pmc
= constant_pmc_new(interp
, enum_class_VtableCache
));
1116 PMC_struct_val(vtable_pmc
) = new_vtable
;
1118 /* attach namespace to object vtable too */
1119 new_vtable
->_namespace
= ns
;
1121 if (new_vtable
->ro_variant_vtable
) {
1122 VTABLE
* const ro_vt
= new_vtable
->ro_variant_vtable
;
1124 ro_vt
->base_type
= new_vtable
->base_type
;
1125 ro_vt
->pmc_class
= new_vtable
->pmc_class
;
1126 ro_vt
->mro
= new_vtable
->mro
;
1127 ro_vt
->_namespace
= new_vtable
->_namespace
;
1134 =item C<static PMC* get_init_meth>
1136 RT#48260: Not yet documented!!!
1142 PARROT_WARN_UNUSED_RESULT
1143 PARROT_CAN_RETURN_NULL
1145 get_init_meth(PARROT_INTERP
, ARGIN(PMC
*_class
),
1146 ARGIN(STRING
*prop_str
), ARGOUT(STRING
**meth_str
))
1150 PMC
*props
, *ns
, *method
;
1154 PMC
* const prop
= VTABLE_getprop(interp
, _class
, prop_str
);
1155 if (!VTABLE_defined(interp
, prop
))
1157 meth
= VTABLE_get_string(interp
, prop
);
1159 props
= PMC_metadata(_class
);
1163 b
= parrot_hash_get_bucket(interp
,
1164 (Hash
*) PMC_struct_val(props
), prop_str
);
1168 meth
= PMC_str_val((PMC
*) b
->value
);
1172 ns
= VTABLE_get_namespace(interp
, _class
);
1173 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, meth
);
1181 =item C<static void do_initcall>
1183 RT#48260: Not yet documented!!!
1190 do_initcall(PARROT_INTERP
, ARGIN_NULLOK(PMC
* _class
), ARGIN_NULLOK(PMC
*object
),
1191 ARGIN_NULLOK(PMC
*init
))
1193 PMC
* const classsearch_array
= _class
->vtable
->mro
;
1197 * 1) if class has a CONSTRUCT property run it on the object
1200 * RT#45985 isn't CONSTRUCT for creating new objects?
1203 PMC
*meth
= get_init_meth(interp
, _class
,
1204 CONST_STRING(interp
, "CONSTRUCT"), &meth_str
);
1207 if (!PMC_IS_NULL(meth
)) {
1209 Parrot_run_meth_fromc_args(interp
, meth
,
1210 object
, meth_str
, "vP", init
);
1212 Parrot_run_meth_fromc_args(interp
, meth
,
1213 object
, meth_str
, "v");
1216 * 2. if class has a BUILD property call it for all classes
1217 * in reverse search order - this class last.
1219 * Note: mro contains this class as first element
1221 nparents
= VTABLE_elements(interp
, classsearch_array
);
1223 for (i
= nparents
- 1; i
>= 0; --i
) {
1224 PMC
* const parent_class
=
1225 VTABLE_get_pmc_keyed_int(interp
, classsearch_array
, i
);
1227 /* if it's a PMC, we put one PMC of that type into
1228 * the attribute slot #0 and call init() on that PMC */
1229 if (!PObj_is_class_TEST(parent_class
)) {
1230 PMC
*attr
, *next_parent
;
1233 /* but only if init isn't inherited
1234 * or rather just on the last non-class parent */
1235 PARROT_ASSERT(i
>= 1);
1236 next_parent
= VTABLE_get_pmc_keyed_int(interp
,
1237 classsearch_array
, i
- 1);
1239 if (!PObj_is_class_TEST(next_parent
))
1242 attr
= pmc_new_noinit(interp
, parent_class
->vtable
->base_type
);
1243 obj_data
= PMC_data_typed(object
, SLOTTYPE
*);
1244 set_attrib_num(object
, obj_data
, 0, attr
);
1245 VTABLE_init(interp
, attr
);
1249 meth
= get_init_meth(interp
, parent_class
,
1250 CONST_STRING(interp
, "BUILD"), &meth_str
);
1252 /* no method found and no BUILD property set? */
1253 if (PMC_IS_NULL(meth
) && meth_str
== NULL
) {
1255 INTVAL vtable_index
;
1257 /* use __init or __init_pmc (depending on if an argument was passed)
1258 * as fallback constructor method, if it exists */
1260 meth_str
= CONST_STRING(interp
, "init_pmc");
1262 meth_str
= CONST_STRING(interp
, "init");
1264 ns
= VTABLE_get_namespace(interp
, parent_class
);
1266 /* can't use find_method, it walks mro */
1267 vtable_index
= Parrot_get_vtable_index(interp
, meth_str
);
1268 meth
= find_vtable_meth_ns(interp
, ns
, vtable_index
);
1274 if (!PMC_IS_NULL(meth
)) {
1276 Parrot_run_meth_fromc_args(interp
, meth
,
1277 object
, meth_str
, "vP", init
);
1279 Parrot_run_meth_fromc_args(interp
, meth
,
1280 object
, meth_str
, "v");
1282 else if (meth_str
!= NULL
&&
1283 string_length(interp
, meth_str
) != 0 && !default_meth
) {
1284 real_exception(interp
, NULL
, METH_NOT_FOUND
,
1285 "Class BUILD method ('%Ss') not found", meth_str
);
1293 =item C<void Parrot_instantiate_object_init>
1295 Creates a Parrot object. Takes a passed-in class PMC that has sufficient
1296 information to describe the layout of the object and makes the object.
1304 Parrot_instantiate_object_init(PARROT_INTERP
, ARGIN(PMC
*object
), ARGIN(PMC
*init
))
1306 instantiate_object(interp
, object
, init
);
1312 =item C<void Parrot_instantiate_object>
1314 Wrapper for instantiate_object, passing NULL as initialization.
1315 Returns a new Parrot object.
1323 Parrot_instantiate_object(PARROT_INTERP
, ARGMOD(PMC
*object
))
1325 instantiate_object(interp
, object
, NULL
);
1331 =item C<static void instantiate_object>
1333 RT#48260: Not yet documented!!!
1340 instantiate_object(PARROT_INTERP
, ARGMOD(PMC
*object
), ARGIN_NULLOK(PMC
*init
))
1342 SLOTTYPE
*new_object_array
;
1343 INTVAL attrib_count
, i
;
1345 PMC
* const _class
= object
->vtable
->pmc_class
;
1347 /* put in the real vtable */
1348 PMC
* const vtable_pmc
= get_attrib_num((SLOTTYPE
*)PMC_data(_class
),
1350 object
->vtable
= (VTABLE
*)PMC_struct_val(vtable_pmc
);
1352 /* Grab the attribute count from the class */
1353 attrib_count
= CLASS_ATTRIB_COUNT(_class
);
1355 /* Build the array that hangs off the new object */
1356 /* First presize it */
1357 set_attrib_array_size(object
, attrib_count
);
1358 new_object_array
= PMC_data_typed(object
, SLOTTYPE
*);
1360 /* fill with PMCNULL, so that access doesn't segfault */
1361 for (i
= 0; i
< attrib_count
; ++i
)
1362 set_attrib_num(object
, new_object_array
, i
, PMCNULL
);
1364 /* turn marking on */
1365 set_attrib_flags(object
);
1367 /* We are an object now */
1368 PObj_is_object_SET(object
);
1370 /* We really ought to call the class init routines here...
1371 * this assumes that an object isa delegate */
1372 do_initcall(interp
, _class
, object
, init
);
1378 =item C<PMC * Parrot_remove_parent>
1380 This currently does nothing but return C<PMCNULL>.
1388 PARROT_IGNORABLE_RESULT
1389 PARROT_CAN_RETURN_NULL
1391 Parrot_remove_parent(PARROT_INTERP
, ARGIN(PMC
*removed_class
),
1392 ARGIN(PMC
*existing_class
))
1395 UNUSED(removed_class
);
1396 UNUSED(existing_class
);
1404 =item C<void mark_object_cache>
1406 Marks all PMCs in the object method cache as live. This shouldn't strictly be
1407 necessary, as they're likely all reachable from namespaces and classes, but
1408 it's unlikely to hurt anything except mark phase performance.
1414 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
1415 #define TBL_SIZE (1 + TBL_SIZE_MASK)
1418 mark_object_cache(PARROT_INTERP
)
1420 Caches
* const mc
= interp
->caches
;
1421 UINTVAL type
, entry
;
1426 for (type
= 0; type
< mc
->mc_size
; type
++) {
1430 for (entry
= 0; entry
< TBL_SIZE
; ++entry
) {
1431 Meth_cache_entry
*e
= mc
->idx
[type
][entry
];
1433 pobject_lives(interp
, (PObj
*)e
->pmc
);
1443 =item C<void init_object_cache>
1445 Allocate memory for object cache.
1452 init_object_cache(PARROT_INTERP
)
1454 Caches
* const mc
= interp
->caches
= mem_allocate_zeroed_typed(Caches
);
1461 =item C<void destroy_object_cache>
1463 RT#48260: Not yet documented!!!
1470 destroy_object_cache(PARROT_INTERP
)
1473 Caches
* const mc
= interp
->caches
;
1475 /* mc->idx[type][bits] = e; */
1476 for (i
= 0; i
< mc
->mc_size
; i
++) {
1478 invalidate_type_caches(interp
, i
);
1481 mem_sys_free(mc
->idx
);
1488 =item C<static void invalidate_type_caches>
1490 RT#48260: Not yet documented!!!
1497 invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
1499 Caches
* const mc
= interp
->caches
;
1505 /* is it a valid entry */
1506 if (type
>= mc
->mc_size
|| !mc
->idx
[type
])
1509 for (i
= 0; i
< TBL_SIZE
; ++i
) {
1510 Meth_cache_entry
*e
= mc
->idx
[type
][i
];
1512 Meth_cache_entry
* const next
= e
->next
;
1518 mem_sys_free(mc
->idx
[type
]);
1519 mc
->idx
[type
] = NULL
;
1525 =item C<static void invalidate_all_caches>
1527 RT#48260: Not yet documented!!!
1534 invalidate_all_caches(PARROT_INTERP
)
1537 for (i
= 1; i
< (UINTVAL
)interp
->n_vtable_max
; ++i
)
1538 invalidate_type_caches(interp
, i
);
1544 =item C<void Parrot_invalidate_method_cache>
1546 Clear method cache for the given class. If class is NULL, caches for
1547 all classes are invalidated.
1555 Parrot_invalidate_method_cache(PARROT_INTERP
, ARGIN_NULLOK(STRING
*_class
), ARGIN(STRING
*meth
))
1559 /* during interp creation and NCI registration the class_hash
1561 if (!interp
->class_hash
)
1564 if (interp
->resume_flag
& RESUME_INITIAL
)
1568 invalidate_all_caches(interp
);
1572 type
= pmc_type(interp
, _class
);
1575 invalidate_all_caches(interp
);
1577 invalidate_type_caches(interp
, (UINTVAL
)type
);
1582 * quick'n'dirty method cache
1583 * RT#45987: use a hash if method_name is not constant
1584 * i.e. from obj.$Sreg(args)
1585 * If this hash is implemented mark it during DOD
1590 =item C<PMC * Parrot_find_method_direct>
1592 Find a method PMC for a named method, given the class PMC, current
1593 interpreter, and name of the method. Don't use a possible method cache.
1600 PARROT_CAN_RETURN_NULL
1601 PARROT_WARN_UNUSED_RESULT
1603 Parrot_find_method_direct(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
1605 PMC
* const found
= find_method_direct_1(interp
, _class
, method_name
);
1607 if (!PMC_IS_NULL(found
))
1611 if (!string_equal(interp
, method_name
, CONST_STRING(interp
, "__get_string")))
1612 return find_method_direct_1(interp
, _class
,
1613 CONST_STRING(interp
, "__get_repr"));
1621 =item C<PMC * Parrot_find_method_with_cache>
1623 Find a method PMC for a named method, given the class PMC, current
1624 interp, and name of the method.
1626 This routine should use the current scope's method cache, if there is
1627 one. If not, it creates a new method cache. Or, rather, it will when
1628 we've got that bit working. For now it unconditionally goes and looks up
1629 the name in the global stash.
1636 PARROT_CAN_RETURN_NULL
1637 PARROT_WARN_UNUSED_RESULT
1639 Parrot_find_method_with_cache(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
1644 Meth_cache_entry
*e
, *old
;
1646 PARROT_ASSERT(method_name
!= 0);
1648 #if DISABLE_METH_CACHE
1649 return Parrot_find_method_direct(interp
, _class
, method_name
);
1652 if (! PObj_constant_TEST(method_name
))
1653 return Parrot_find_method_direct(interp
, _class
, method_name
);
1655 mc
= interp
->caches
;
1656 type
= _class
->vtable
->base_type
;
1657 bits
= (((UINTVAL
) method_name
->strstart
) >> 2) & TBL_SIZE_MASK
;
1659 if (type
>= mc
->mc_size
) {
1661 mc
->idx
= (Meth_cache_entry
***)mem_sys_realloc_zeroed(mc
->idx
,
1662 sizeof (Meth_cache_entry
***) * (type
+ 1),
1663 sizeof (Meth_cache_entry
***) * mc
->mc_size
);
1666 mc
->idx
= (Meth_cache_entry
***)mem_sys_allocate_zeroed(
1667 sizeof (Meth_cache_entry
***) * (type
+ 1));
1669 mc
->mc_size
= type
+ 1;
1672 if (!mc
->idx
[type
]) {
1673 mc
->idx
[type
] = (Meth_cache_entry
**)mem_sys_allocate_zeroed(
1674 sizeof (Meth_cache_entry
*) * TBL_SIZE
);
1677 e
= mc
->idx
[type
][bits
];
1680 while (e
&& e
->strstart
!= method_name
->strstart
) {
1686 /* when here no or no correct entry was at [bits] */
1687 e
= mem_allocate_typed(Meth_cache_entry
);
1692 mc
->idx
[type
][bits
] = e
;
1694 e
->pmc
= Parrot_find_method_direct(interp
, _class
, method_name
);
1696 e
->strstart
= method_name
->strstart
;
1705 =item C<static void debug_trace_find_meth>
1707 RT#48260: Not yet documented!!!
1714 # define TRACE_FM(i, c, m, sub)
1716 # define TRACE_FM(i, c, m, sub) \
1717 debug_trace_find_meth(i, c, m, sub)
1720 debug_trace_find_meth(PARROT_INTERP
, ARGIN(const PMC
*_class
),
1721 ARGIN(const STRING
*name
), ARGIN_NULLOK(const PMC
*sub
))
1727 if (!Interp_trace_TEST(interp
, PARROT_TRACE_FIND_METH_FLAG
))
1730 if (PObj_is_class_TEST(_class
)) {
1731 SLOTTYPE
* const class_array
= PMC_data_typed(_class
, SLOTTYPE
*);
1732 PMC
*const class_name_pmc
= get_attrib_num(class_array
, PCD_CLASS_NAME
);
1733 class_name
= PMC_str_val(class_name_pmc
);
1736 class_name
= _class
->vtable
->whoami
;
1739 if (sub
->vtable
->base_type
== enum_class_NCI
)
1747 tracer
= interp
->debugger
? interp
->debugger
: interp
;
1748 PIO_eprintf(tracer
, "# find_method class '%Ss' method '%Ss': %s\n",
1749 class_name
, name
, result
);
1757 =item C<static PMC * find_method_direct_1>
1759 RT#48260: Not yet documented!!!
1765 PARROT_WARN_UNUSED_RESULT
1766 PARROT_CAN_RETURN_NULL
1768 find_method_direct_1(PARROT_INTERP
, ARGIN(PMC
*_class
),
1769 ARGIN(STRING
*method_name
))
1773 PMC
* const mro
= _class
->vtable
->mro
;
1774 const INTVAL n
= VTABLE_elements(interp
, mro
);
1776 for (i
= 0; i
< n
; ++i
) {
1779 _class
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
1780 ns
= VTABLE_get_namespace(interp
, _class
);
1781 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, method_name
);
1783 TRACE_FM(interp
, _class
, method_name
, method
);
1785 if (!PMC_IS_NULL(method
))
1789 TRACE_FM(interp
, _class
, method_name
, NULL
);
1796 =item C<INTVAL Parrot_add_attribute>
1798 Adds the attribute C<attr> to the class.
1800 Life is ever so much easier if a class keeps its attributes at the
1801 end of the attribute array, since we don't have to insert and
1802 reorder attributes. Inserting's no big deal, especially since we're
1803 going to break horribly if you insert into a class that's been
1804 subclassed, but it'll do for now.
1812 Parrot_add_attribute(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*attr
))
1814 STRING
*full_attr_name
;
1815 SLOTTYPE
* const class_array
= (SLOTTYPE
*)PMC_data(_class
);
1816 STRING
* const class_name
= VTABLE_get_string(interp
,
1817 get_attrib_num(class_array
, PCD_CLASS_NAME
));
1818 PMC
* const attr_array
= get_attrib_num(class_array
, PCD_CLASS_ATTRIBUTES
);
1819 PMC
* const attr_hash
= get_attrib_num(class_array
, PCD_ATTRIBUTES
);
1820 INTVAL idx
= VTABLE_elements(interp
, attr_array
);
1822 VTABLE_set_integer_native(interp
, attr_array
, idx
+ 1);
1823 VTABLE_set_string_keyed_int(interp
, attr_array
, idx
, attr
);
1825 full_attr_name
= string_concat(interp
, class_name
,
1826 string_from_cstring(interp
, "\0", 1), 0);
1828 full_attr_name
= string_concat(interp
, full_attr_name
, attr
, 0);
1830 /* RT#45989 escape NUL char */
1831 if (VTABLE_exists_keyed_str(interp
, attr_hash
, full_attr_name
))
1832 real_exception(interp
, NULL
, 1,
1833 "Attribute '%Ss' already exists", full_attr_name
);
1836 * RT#45993 check if someone is trying to add attributes to a parent class
1837 * while there are already child class attrs
1839 idx
= CLASS_ATTRIB_COUNT(_class
)++;
1840 VTABLE_set_integer_keyed_str(interp
, attr_hash
, attr
, idx
);
1841 VTABLE_set_integer_keyed_str(interp
, attr_hash
, full_attr_name
, idx
);
1847 /* ************************************************************************ */
1848 /* ********* BELOW HERE IS NEW PPD15 IMPLEMENTATION RELATED STUFF ********* */
1849 /* ************************************************************************ */
1853 =item C<static PMC* C3_merge>
1855 RT#48260: Not yet documented!!!
1861 PARROT_WARN_UNUSED_RESULT
1862 PARROT_CAN_RETURN_NULL
1864 C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
1866 PMC
*accepted
= PMCNULL
;
1867 PMC
*result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1868 const int list_count
= VTABLE_elements(interp
, merge_list
);
1872 /* Try and find something appropriate to add to the MRO - basically, the
1873 * first list head that is not in the tail of all the other lists. */
1874 for (i
= 0; i
< list_count
; i
++) {
1875 PMC
* const cand_list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1881 if (VTABLE_elements(interp
, cand_list
) == 0)
1884 cand_class
= VTABLE_get_pmc_keyed_int(interp
, cand_list
, 0);
1887 for (j
= 0; j
< list_count
; j
++) {
1888 /* Skip the current list. */
1890 /* Is it in the tail? If so, reject. */
1891 PMC
* const check_list
=
1892 VTABLE_get_pmc_keyed_int(interp
, merge_list
, j
);
1894 const int check_length
= VTABLE_elements(interp
, check_list
);
1897 for (k
= 1; k
< check_length
; k
++) {
1898 if (VTABLE_get_pmc_keyed_int(interp
, check_list
, k
) ==
1907 /* If we didn't reject it, this candidate will do. */
1909 accepted
= cand_class
;
1914 /* If we never found any candidates, return an empty list. */
1915 if (cand_count
== 0)
1916 return pmc_new(interp
, enum_class_ResizablePMCArray
);
1918 /* If we didn't find anything to accept, error. */
1919 if (PMC_IS_NULL(accepted
))
1920 real_exception(interp
, NULL
, ILL_INHERIT
,
1921 "Could not build C3 linearization: ambiguous hierarchy");
1923 /* Otherwise, remove what was accepted from the merge lists. */
1924 for (i
= 0; i
< list_count
; i
++) {
1927 PMC
* const list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1928 const int list_count
= VTABLE_elements(interp
, list
);
1930 for (j
= 0; j
< list_count
; j
++) {
1931 if (VTABLE_get_pmc_keyed_int(interp
, list
, j
) == accepted
) {
1932 VTABLE_delete_keyed_int(interp
, list
, j
);
1938 /* Need to merge what remains of the list, then put what was accepted on
1939 * the start of the list, and we're done. */
1940 result
= C3_merge(interp
, merge_list
);
1941 VTABLE_unshift_pmc(interp
, result
, accepted
);
1949 =item C<PMC* Parrot_ComputeMRO_C3>
1951 Computes the C3 linearization for the given class.
1958 PARROT_WARN_UNUSED_RESULT
1959 PARROT_CAN_RETURN_NULL
1961 Parrot_ComputeMRO_C3(PARROT_INTERP
, ARGIN(PMC
*_class
))
1964 PMC
* const merge_list
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1965 PMC
*immediate_parents
;
1966 int i
, parent_count
;
1968 /* Now get immediate parents list. */
1969 Parrot_PCCINVOKE(interp
, _class
, CONST_STRING(interp
, "parents"),
1970 "->P", &immediate_parents
);
1972 if (!immediate_parents
)
1973 real_exception(interp
, NULL
, METH_NOT_FOUND
,
1974 "Failed to get parents list from class!");
1976 parent_count
= VTABLE_elements(interp
, immediate_parents
);
1978 if (parent_count
== 0) {
1979 /* No parents - MRO just contains this class. */
1980 result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1981 VTABLE_push_pmc(interp
, result
, _class
);
1985 /* Otherwise, need to do merge. For that, need linearizations of all of
1986 * our parents added to the merge list. */
1987 for (i
= 0; i
< parent_count
; i
++) {
1988 PMC
* const lin
= Parrot_ComputeMRO_C3(interp
,
1989 VTABLE_get_pmc_keyed_int(interp
, immediate_parents
, i
));
1991 if (PMC_IS_NULL(lin
))
1994 VTABLE_push_pmc(interp
, merge_list
, lin
);
1997 /* Finally, need list of direct parents on the end of the merge list, then
1999 VTABLE_push_pmc(interp
, merge_list
, immediate_parents
);
2000 result
= C3_merge(interp
, merge_list
);
2002 if (PMC_IS_NULL(result
))
2005 /* Merged result needs this class on the start, and then we're done. */
2006 VTABLE_unshift_pmc(interp
, result
, _class
);
2014 =item C<void Parrot_ComposeRole>
2016 Used by the Class and Object PMCs internally to compose a role into either of
2017 them. The C<role> parameter is the role that we are composing into the class
2018 or role. C<methods_hash> is the hash of method names to invokable PMCs that
2019 contains the methods the class or role has. C<roles_list> is the list of roles
2020 the the class or method does.
2022 The C<role> parameter is only dealt with by its external interface. Whether
2023 this routine is usable by any other object system implemented in Parrot very
2024 much depends on how closely the role composition semantics they want are to
2025 the default implementation.
2033 Parrot_ComposeRole(PARROT_INTERP
, ARGIN(PMC
*role
),
2034 ARGIN(PMC
*exclude
), int got_exclude
,
2035 ARGIN(PMC
*alias
), int got_alias
,
2036 ARGIN(PMC
*methods_hash
), ARGIN(PMC
*roles_list
))
2041 PMC
*proposed_add_methods
;
2043 int i
, roles_of_role_count
;
2045 /* Check we have not already composed the role; if so, just ignore it. */
2046 int roles_count
= VTABLE_elements(interp
, roles_list
);
2048 for (i
= 0; i
< roles_count
; i
++)
2049 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, i
) == role
)
2052 /* Get the methods from the role. */
2053 Parrot_PCCINVOKE(interp
, role
,
2054 CONST_STRING(interp
, "methods"), "->P", &methods
);
2056 if (PMC_IS_NULL(methods
))
2059 /* We need to check for conflicts before we do the composition. We
2060 * put each method that would be OK to add into a proposal list, and
2061 * bail out right away if we find a problem. */
2062 proposed_add_methods
= pmc_new(interp
, enum_class_Hash
);
2063 methods_iter
= VTABLE_get_iter(interp
, methods
);
2065 while (VTABLE_get_bool(interp
, methods_iter
)) {
2066 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
2067 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
, methods
,
2070 /* Need to find the name we'll check for a conflict on. */
2073 /* Check if it's in the exclude list. */
2075 const int exclude_count
= VTABLE_elements(interp
, exclude
);
2077 for (i
= 0; i
< exclude_count
; i
++) {
2078 const STRING
* const check
=
2079 VTABLE_get_string_keyed_int(interp
, exclude
, i
);
2081 if (string_equal(interp
, check
, method_name
) == 0) {
2088 /* If we weren't excluded... */
2090 /* Is there a method with this name already in the class?
2091 * RT#45999 multi-method handling. */
2093 if (VTABLE_exists_keyed_str(interp
, methods_hash
, method_name
))
2094 /* Conflicts with something already in the class. */
2095 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
2096 "A conflict occurred during role composition "
2097 "due to method '%S'.", method_name
);
2099 /* What about a conflict with ourslef? */
2100 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
2102 /* Something very weird is going on. */
2103 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
2104 "A conflict occurred during role composition;"
2105 " the method '%S' from the role managed to conflict "
2106 "with itself somehow.", method_name
);
2108 /* If we got here, no conflicts! Add method to the "to compose"
2110 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
2111 method_name
, cur_method
);
2114 /* Now see if we've got an alias. */
2115 if (got_alias
&& VTABLE_exists_keyed_str(interp
, alias
, method_name
)) {
2116 /* Got one. Get name to alias it to. */
2117 STRING
* const alias_name
= VTABLE_get_string_keyed_str(interp
,
2118 alias
, method_name
);
2120 /* Is there a method with this name already in the class?
2121 * RT#45999: multi-method handling. */
2122 if (VTABLE_exists_keyed_str(interp
, methods_hash
, alias_name
))
2123 /* Conflicts with something already in the class. */
2124 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
2125 "A conflict occurred during role composition"
2126 " due to the aliasing of '%S' to '%S'.",
2127 method_name
, alias_name
);
2129 /* What about a conflict with ourslef? */
2130 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
2132 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
2133 "A conflict occurred during role composition"
2134 " due to the aliasing of '%S' to '%S' (role already has"
2136 method_name
, alias_name
, alias_name
);
2138 /* If we get here, no conflicts! Add method to the "to compose"
2139 * list with its alias. */
2140 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
2141 alias_name
, cur_method
);
2145 /* If we get here, we detected no conflicts. Go ahead and compose the
2147 methods_iter
= VTABLE_get_iter(interp
, proposed_add_methods
);
2149 while (VTABLE_get_bool(interp
, methods_iter
)) {
2150 /* Get current method and its name. */
2151 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
2152 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
,
2153 proposed_add_methods
, method_name
);
2155 /* Add it to the methods of the class. */
2156 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
2159 /* Add this role to the roles list. */
2160 VTABLE_push_pmc(interp
, roles_list
, role
);
2163 /* As a result of composing this role, we will also now do the roles
2164 * that it did itself. Note that we already have the correct methods
2165 * as roles "flatten" the methods they get from other roles into their
2166 * own method list. */
2167 Parrot_PCCINVOKE(interp
, role
,
2168 CONST_STRING(interp
, "roles"), "->P", &roles_of_role
);
2169 roles_of_role_count
= VTABLE_elements(interp
, roles_of_role
);
2171 for (i
= 0; i
< roles_of_role_count
; i
++) {
2172 /* Only add if we don't already have it in the list. */
2173 PMC
* const cur_role
= VTABLE_get_pmc_keyed_int(interp
,
2177 for (j
= 0; j
< roles_count
; j
++) {
2178 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, j
) == cur_role
) {
2179 /* We ain't be havin' it. */
2180 VTABLE_push_pmc(interp
, roles_list
, cur_role
);
2193 F<include/parrot/oo.h>, F<include/parrot/oo_private.h>,
2194 F<docs/pdds/pdd15_objects.pod>.
2202 * c-file-style: "parrot"
2204 * vim: expandtab shiftwidth=4: