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 */
32 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
34 PARROT_WARN_UNUSED_RESULT
35 PARROT_CAN_RETURN_NULL
36 static PMC
* C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
37 __attribute__nonnull__(1)
38 __attribute__nonnull__(2);
40 static void debug_trace_find_meth(PARROT_INTERP
,
41 ARGIN(const PMC
*_class
),
42 ARGIN(const STRING
*name
),
43 ARGIN_NULLOK(const PMC
*sub
))
44 __attribute__nonnull__(1)
45 __attribute__nonnull__(2)
46 __attribute__nonnull__(3);
48 static void fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
49 __attribute__nonnull__(1)
50 __attribute__nonnull__(2);
52 PARROT_WARN_UNUSED_RESULT
53 PARROT_CAN_RETURN_NULL
54 static PMC
* find_method_direct_1(PARROT_INTERP
,
56 ARGIN(STRING
*method_name
))
57 __attribute__nonnull__(1)
58 __attribute__nonnull__(2)
59 __attribute__nonnull__(3);
61 PARROT_WARN_UNUSED_RESULT
62 PARROT_CAN_RETURN_NULL
63 static PMC
* find_vtable_meth_ns(PARROT_INTERP
,
66 __attribute__nonnull__(1)
67 __attribute__nonnull__(2);
69 PARROT_WARN_UNUSED_RESULT
70 PARROT_CAN_RETURN_NULL
71 static PMC
* get_init_meth(PARROT_INTERP
,
73 ARGIN(STRING
*prop_str
),
74 ARGOUT(STRING
**meth_str
))
75 __attribute__nonnull__(1)
76 __attribute__nonnull__(2)
77 __attribute__nonnull__(3)
78 __attribute__nonnull__(4)
79 FUNC_MODIFIES(*meth_str
);
81 static void invalidate_all_caches(PARROT_INTERP
)
82 __attribute__nonnull__(1);
84 static void invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
85 __attribute__nonnull__(1);
87 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
88 /* HEADERIZER END: static */
92 =item C<void Parrot_oo_extract_methods_from_namespace>
94 Extract methods and vtable overrides from the given namespace and insert them
102 Parrot_oo_extract_methods_from_namespace(PARROT_INTERP
, ARGIN(PMC
*self
), ARGIN(PMC
*ns
))
104 PMC
*methods
, *vtable_overrides
;
106 /* Pull in methods from the namespace, if any. */
110 /* Import any methods. */
111 Parrot_PCCINVOKE(interp
, ns
,
112 CONST_STRING(interp
, "get_associated_methods"), "->P", &methods
);
114 if (!PMC_IS_NULL(methods
)) {
115 PMC
* const iter
= VTABLE_get_iter(interp
, methods
);
117 while (VTABLE_get_bool(interp
, iter
)) {
118 STRING
* const meth_name
= VTABLE_shift_string(interp
, iter
);
119 PMC
* const meth_sub
= VTABLE_get_pmc_keyed_str(interp
, methods
,
121 VTABLE_add_method(interp
, self
, meth_name
, meth_sub
);
125 /* Import any vtable methods. */
126 Parrot_PCCINVOKE(interp
, ns
,
127 CONST_STRING(interp
, "get_associated_vtable_methods"), "->P", &vtable_overrides
);
129 if (!PMC_IS_NULL(vtable_overrides
)) {
130 PMC
* const iter
= VTABLE_get_iter(interp
, vtable_overrides
);
131 while (VTABLE_get_bool(interp
, iter
)) {
132 STRING
* const vtable_index_str
= VTABLE_shift_string(interp
, iter
);
133 PMC
* const vtable_sub
= VTABLE_get_pmc_keyed_str(interp
,
134 vtable_overrides
, vtable_index_str
);
136 /* Look up the name of the vtable function from the index. */
137 const INTVAL vtable_index
= string_to_int(interp
, vtable_index_str
);
138 const char * const meth_c
= Parrot_vtable_slot_names
[vtable_index
];
139 STRING
*vtable_name
= string_from_cstring(interp
, meth_c
, 0);
141 /* Strip leading underscores in the vtable name */
142 if (string_str_index(interp
, vtable_name
,
143 CONST_STRING(interp
, "__"), 0) == 0) {
144 vtable_name
= string_substr(interp
, vtable_name
, 2,
145 string_length(interp
, vtable_name
) - 2, NULL
, 0);
148 VTABLE_add_vtable_override(interp
, self
, vtable_name
, vtable_sub
);
156 =item C<PMC * Parrot_oo_get_namespace>
158 Lookup a namespace object from a class PMC.
164 PARROT_CAN_RETURN_NULL
165 PARROT_WARN_UNUSED_RESULT
167 Parrot_oo_get_namespace(SHIM_INTERP
, ARGIN(const PMC
*classobj
))
169 Parrot_Class_attributes
* const _class
= PARROT_CLASS(classobj
);
170 PMC
* const _namespace
= _class
->_namespace
;
172 if (PMC_IS_NULL(_namespace
))
181 =item C<PMC * Parrot_oo_get_class>
183 Lookup a class object from a namespace, string, or key PMC.
190 PARROT_CAN_RETURN_NULL
191 PARROT_WARN_UNUSED_RESULT
193 Parrot_oo_get_class(PARROT_INTERP
, ARGIN(PMC
*key
))
195 PMC
*classobj
= PMCNULL
;
197 if (PObj_is_class_TEST(key
))
200 /* Fast select of behavior based on type of the lookup key */
201 switch (key
->vtable
->base_type
) {
202 case enum_class_NameSpace
:
203 classobj
= VTABLE_get_class(interp
, key
);
206 case enum_class_String
:
208 case enum_class_ResizableStringArray
:
210 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
,
211 interp
->HLL_namespace
,
212 CONTEXT(interp
)->current_HLL
);
213 PMC
* const ns
= Parrot_get_namespace_keyed(interp
,
216 if (!PMC_IS_NULL(ns
))
217 classobj
= VTABLE_get_class(interp
, ns
);
224 if (PMC_IS_NULL(classobj
)) {
225 /* Look up a low-level class and create a proxy */
226 const INTVAL type
= pmc_type(interp
, VTABLE_get_string(interp
, key
));
228 /* Reject invalid type numbers */
229 if (type
> interp
->n_vtable_max
|| type
<= 0)
232 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
233 VTABLE_set_integer_native(interp
, type_num
, type
);
234 classobj
= pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
244 =item C<PMC * Parrot_oo_get_class_str>
246 Lookup a class object from a builtin string.
253 PARROT_CAN_RETURN_NULL
254 PARROT_WARN_UNUSED_RESULT
256 Parrot_oo_get_class_str(PARROT_INTERP
, ARGIN(STRING
*name
))
258 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
, interp
->HLL_namespace
,
259 CONTEXT(interp
)->current_HLL
);
260 PMC
* const ns
= Parrot_get_namespace_keyed_str(interp
, hll_ns
, name
);
261 PMC
* const _class
= PMC_IS_NULL(ns
)
262 ? PMCNULL
: VTABLE_get_class(interp
, ns
);
264 /* Look up a low-level class and create a proxy */
265 if (PMC_IS_NULL(_class
)) {
266 const INTVAL type
= pmc_type(interp
, name
);
268 /* Reject invalid type numbers */
269 if (type
> interp
->n_vtable_max
|| type
<= 0)
272 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
273 VTABLE_set_integer_native(interp
, type_num
, type
);
274 return pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
284 =item C<PMC * Parrot_oo_newclass_from_str>
286 Create a new class object from a string name.
292 PARROT_CAN_RETURN_NULL
293 PARROT_WARN_UNUSED_RESULT
295 Parrot_oo_newclass_from_str(PARROT_INTERP
, ARGIN(STRING
*name
))
297 PMC
* const namearg
= pmc_new(interp
, enum_class_String
);
298 PMC
*namehash
= pmc_new(interp
, enum_class_Hash
);
301 VTABLE_set_string_native(interp
, namearg
, name
);
302 VTABLE_set_pmc_keyed_str(interp
, namehash
, CONST_STRING(interp
, "name"), namearg
);
304 classobj
= pmc_new_init(interp
, enum_class_Class
, namehash
);
306 PARROT_ASSERT(classobj
);
313 =item C<PMC * Parrot_oo_find_vtable_override_for_class>
315 Lookup a vtable override in a specific class object.
321 PARROT_CAN_RETURN_NULL
322 PARROT_WARN_UNUSED_RESULT
324 Parrot_oo_find_vtable_override_for_class(PARROT_INTERP
,
325 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
327 Parrot_Class_attributes
*class_info
;
328 PARROT_ASSERT(PObj_is_class_TEST(classobj
));
330 class_info
= PARROT_CLASS(classobj
);
331 return VTABLE_get_pmc_keyed_str(interp
, class_info
->vtable_overrides
, name
);
337 =item C<PMC * Parrot_oo_find_vtable_override>
339 Lookup a vtable override in a class, including any vtable overrides inherited
346 PARROT_CAN_RETURN_NULL
347 PARROT_WARN_UNUSED_RESULT
349 Parrot_oo_find_vtable_override(PARROT_INTERP
,
350 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
352 Parrot_Class_attributes
* const _class
= PARROT_CLASS(classobj
);
354 if (VTABLE_exists_keyed_str(interp
, _class
->parent_overrides
, name
))
355 return VTABLE_get_pmc_keyed_str(interp
, _class
->parent_overrides
, name
);
357 /* Walk and search for the vtable method. */
358 const INTVAL num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
359 PMC
*result
= PMCNULL
;
362 for (i
= 0; i
< num_classes
; i
++) {
364 PMC
* const cur_class
=
365 VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, i
);
367 result
= Parrot_oo_find_vtable_override_for_class(interp
,
370 if (!PMC_IS_NULL(result
))
374 VTABLE_set_pmc_keyed_str(interp
, _class
->parent_overrides
, name
, result
);
383 =item C<INTVAL Parrot_get_vtable_index>
385 Return index if C<name> is a valid vtable slot name.
393 Parrot_get_vtable_index(PARROT_INTERP
, ARGIN(const STRING
*name
))
395 char * const name_c
= string_to_cstring(interp
, name
);
397 /* some of the first "slots" don't have names. skip 'em. */
398 INTVAL low
= PARROT_VTABLE_LOW
;
399 INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
402 const INTVAL mid
= (low
+ high
) / 2;
403 const char * const meth_c
= Parrot_vtable_slot_names
[mid
];
405 /* RT#45965 slot_names still have __ in front */
406 const INTVAL cmp
= strcmp(name_c
, meth_c
+ 2);
409 string_cstring_free(name_c
);
418 string_cstring_free(name_c
);
426 =item C<static PMC* find_vtable_meth_ns>
428 Return Sub PMC if a method with the vtable name exists in ns
434 PARROT_WARN_UNUSED_RESULT
435 PARROT_CAN_RETURN_NULL
437 find_vtable_meth_ns(PARROT_INTERP
, ARGIN(PMC
*ns
), INTVAL vtable_index
)
439 return VTABLE_get_pmc_keyed_int(interp
, ns
, vtable_index
);
445 =item C<STRING* readable_name>
447 Given a String or Key PMC return the STRING* representation
449 RT#45967 this function, key_set_to_string, and the key PMC get_repr should be
457 PARROT_WARN_UNUSED_RESULT
458 PARROT_CANNOT_RETURN_NULL
460 readable_name(PARROT_INTERP
, ARGIN(PMC
*name
))
464 if (name
->vtable
->base_type
== enum_class_String
)
465 return VTABLE_get_string(interp
, name
);
467 array
= pmc_new(interp
, enum_class_ResizableStringArray
);
469 PARROT_ASSERT(name
->vtable
->base_type
== enum_class_Key
);
472 VTABLE_push_string(interp
, array
, VTABLE_get_string(interp
, name
));
473 name
= key_next(interp
, name
);
476 return string_join(interp
, CONST_STRING(interp
, ";"), array
);
482 =item C<const char* Parrot_MMD_method_name>
484 Return the method name for the given MMD enum.
492 PARROT_CAN_RETURN_NULL
494 Parrot_MMD_method_name(SHIM_INTERP
, INTVAL idx
)
496 PARROT_ASSERT(idx
>= 0);
498 if (idx
>= MMD_USER_FIRST
)
501 return Parrot_mmd_func_names
[idx
];
507 =item C<INTVAL Parrot_MMD_method_idx>
509 Return the MMD function number for method name or -1 on failure.
511 RT#45973 allow dynamic expansion at runtime.
520 Parrot_MMD_method_idx(SHIM_INTERP
, ARGIN(const char *name
))
524 for (i
= 0; i
< MMD_USER_FIRST
; ++i
) {
525 if (STREQ(Parrot_mmd_func_names
[i
], name
))
535 =item C<PMC * Parrot_class_lookup>
537 Looks for the class named C<class_name> and returns it if it exists.
538 Otherwise it returns C<PMCNULL>.
545 PARROT_CAN_RETURN_NULL
546 PARROT_WARN_UNUSED_RESULT
548 Parrot_class_lookup(PARROT_INTERP
, ARGIN(STRING
*class_name
))
550 const INTVAL type
= pmc_type(interp
, class_name
);
556 pmc
= interp
->vtables
[type
]->pmc_class
;
564 =item C<PMC * Parrot_class_lookup_p>
566 Looks for the class named C<class_name> and returns it if it exists.
567 Otherwise it returns C<PMCNULL>.
573 PARROT_CAN_RETURN_NULL
574 PARROT_WARN_UNUSED_RESULT
576 Parrot_class_lookup_p(PARROT_INTERP
, ARGIN(PMC
*class_name
))
578 const INTVAL type
= pmc_type_p(interp
, class_name
);
584 pmc
= interp
->vtables
[type
]->pmc_class
;
592 =item C<static void fail_if_type_exists>
594 This function throws an exception if a PMC or class with the same name *
595 already exists in the global type registry. The global type registry
596 will go away eventually, but this allows the new object metamodel to
597 interact with the old one until it does.
604 fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
608 PMC
* const classname_hash
= interp
->class_hash
;
609 PMC
* const type_pmc
= (PMC
*)VTABLE_get_pointer_keyed(interp
,
610 classname_hash
, name
);
612 if (PMC_IS_NULL(type_pmc
)
613 || type_pmc
->vtable
->base_type
== enum_class_NameSpace
)
616 type
= VTABLE_get_integer(interp
, type_pmc
);
618 if (type
> enum_type_undef
)
619 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
620 "Class %Ss already registered!\n",
621 string_escape_string(interp
, VTABLE_get_string(interp
, name
)));
623 if (type
< enum_type_undef
)
624 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
625 "native type with name '%s' already exists - "
626 "can't register Class", data_types
[type
].name
);
632 =item C<INTVAL Parrot_oo_register_type>
634 This function registers a type in the global registry, first checking if it
635 already exists. The global type registry will go away eventually, but this
636 allows the new object metamodel to interact with the old one until it does.
642 PARROT_WARN_UNUSED_RESULT
644 Parrot_oo_register_type(PARROT_INTERP
, ARGIN(PMC
*name
))
647 PMC
*classname_hash
, *item
;
649 fail_if_type_exists(interp
, name
);
651 /* Type doesn't exist, so go ahead and register it. Lock interpreter so
652 * pt_shared_fixup() can safely do a type lookup. */
653 LOCK_INTERPRETER(interp
);
654 classname_hash
= interp
->class_hash
;
656 type
= interp
->n_vtable_max
++;
658 /* Have we overflowed the table? */
659 if (type
>= interp
->n_vtable_alloced
)
660 parrot_realloc_vtables(interp
);
662 /* set entry in name->type hash */
663 item
= pmc_new(interp
, enum_class_Integer
);
664 PMC_int_val(item
) = type
;
666 VTABLE_set_pmc_keyed(interp
, classname_hash
, name
, item
);
667 UNLOCK_INTERPRETER(interp
);
675 =item C<static PMC* get_init_meth>
677 RT#48260: Not yet documented!!!
683 PARROT_WARN_UNUSED_RESULT
684 PARROT_CAN_RETURN_NULL
686 get_init_meth(PARROT_INTERP
, ARGIN(PMC
*_class
),
687 ARGIN(STRING
*prop_str
), ARGOUT(STRING
**meth_str
))
691 PMC
*props
, *ns
, *method
;
695 PMC
* const prop
= VTABLE_getprop(interp
, _class
, prop_str
);
696 if (!VTABLE_defined(interp
, prop
))
698 meth
= VTABLE_get_string(interp
, prop
);
700 props
= PMC_metadata(_class
);
704 b
= parrot_hash_get_bucket(interp
,
705 (Hash
*) PMC_struct_val(props
), prop_str
);
709 meth
= PMC_str_val((PMC
*) b
->value
);
713 ns
= VTABLE_get_namespace(interp
, _class
);
714 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, meth
);
721 =item C<PMC * Parrot_remove_parent>
723 This currently does nothing but return C<PMCNULL>.
731 PARROT_IGNORABLE_RESULT
732 PARROT_CAN_RETURN_NULL
734 Parrot_remove_parent(PARROT_INTERP
, ARGIN(PMC
*removed_class
),
735 ARGIN(PMC
*existing_class
))
738 UNUSED(removed_class
);
739 UNUSED(existing_class
);
747 =item C<void mark_object_cache>
749 Marks all PMCs in the object method cache as live. This shouldn't strictly be
750 necessary, as they're likely all reachable from namespaces and classes, but
751 it's unlikely to hurt anything except mark phase performance.
757 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
758 #define TBL_SIZE (1 + TBL_SIZE_MASK)
761 mark_object_cache(PARROT_INTERP
)
763 Caches
* const mc
= interp
->caches
;
769 for (type
= 0; type
< mc
->mc_size
; type
++) {
773 for (entry
= 0; entry
< TBL_SIZE
; ++entry
) {
774 Meth_cache_entry
*e
= mc
->idx
[type
][entry
];
776 pobject_lives(interp
, (PObj
*)e
->pmc
);
786 =item C<void init_object_cache>
788 Allocate memory for object cache.
795 init_object_cache(PARROT_INTERP
)
797 Caches
* const mc
= interp
->caches
= mem_allocate_zeroed_typed(Caches
);
804 =item C<void destroy_object_cache>
806 RT#48260: Not yet documented!!!
813 destroy_object_cache(PARROT_INTERP
)
816 Caches
* const mc
= interp
->caches
;
818 /* mc->idx[type][bits] = e; */
819 for (i
= 0; i
< mc
->mc_size
; i
++) {
821 invalidate_type_caches(interp
, i
);
824 mem_sys_free(mc
->idx
);
831 =item C<static void invalidate_type_caches>
833 RT#48260: Not yet documented!!!
840 invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
842 Caches
* const mc
= interp
->caches
;
848 /* is it a valid entry */
849 if (type
>= mc
->mc_size
|| !mc
->idx
[type
])
852 for (i
= 0; i
< TBL_SIZE
; ++i
) {
853 Meth_cache_entry
*e
= mc
->idx
[type
][i
];
855 Meth_cache_entry
* const next
= e
->next
;
861 mem_sys_free(mc
->idx
[type
]);
862 mc
->idx
[type
] = NULL
;
868 =item C<static void invalidate_all_caches>
870 RT#48260: Not yet documented!!!
877 invalidate_all_caches(PARROT_INTERP
)
880 for (i
= 1; i
< (UINTVAL
)interp
->n_vtable_max
; ++i
)
881 invalidate_type_caches(interp
, i
);
887 =item C<void Parrot_invalidate_method_cache>
889 Clear method cache for the given class. If class is NULL, caches for
890 all classes are invalidated.
898 Parrot_invalidate_method_cache(PARROT_INTERP
, ARGIN_NULLOK(STRING
*_class
), ARGIN(STRING
*meth
))
902 /* during interp creation and NCI registration the class_hash
904 if (!interp
->class_hash
)
907 if (interp
->resume_flag
& RESUME_INITIAL
)
911 invalidate_all_caches(interp
);
915 type
= pmc_type(interp
, _class
);
918 invalidate_all_caches(interp
);
920 invalidate_type_caches(interp
, (UINTVAL
)type
);
925 * quick'n'dirty method cache
926 * RT#45987: use a hash if method_name is not constant
927 * i.e. from obj.$Sreg(args)
928 * If this hash is implemented mark it during DOD
933 =item C<PMC * Parrot_find_method_direct>
935 Find a method PMC for a named method, given the class PMC, current
936 interpreter, and name of the method. Don't use a possible method cache.
943 PARROT_CAN_RETURN_NULL
944 PARROT_WARN_UNUSED_RESULT
946 Parrot_find_method_direct(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
948 PMC
* const found
= find_method_direct_1(interp
, _class
, method_name
);
950 if (!PMC_IS_NULL(found
))
954 if (!string_equal(interp
, method_name
, CONST_STRING(interp
, "__get_string")))
955 return find_method_direct_1(interp
, _class
,
956 CONST_STRING(interp
, "__get_repr"));
964 =item C<PMC * Parrot_find_method_with_cache>
966 Find a method PMC for a named method, given the class PMC, current
967 interp, and name of the method.
969 This routine should use the current scope's method cache, if there is
970 one. If not, it creates a new method cache. Or, rather, it will when
971 we've got that bit working. For now it unconditionally goes and looks up
972 the name in the global stash.
979 PARROT_CAN_RETURN_NULL
980 PARROT_WARN_UNUSED_RESULT
982 Parrot_find_method_with_cache(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
987 Meth_cache_entry
*e
, *old
;
989 PARROT_ASSERT(method_name
!= 0);
991 #if DISABLE_METH_CACHE
992 return Parrot_find_method_direct(interp
, _class
, method_name
);
995 if (! PObj_constant_TEST(method_name
))
996 return Parrot_find_method_direct(interp
, _class
, method_name
);
999 type
= _class
->vtable
->base_type
;
1000 bits
= (((UINTVAL
) method_name
->strstart
) >> 2) & TBL_SIZE_MASK
;
1002 if (type
>= mc
->mc_size
) {
1004 mc
->idx
= (Meth_cache_entry
***)mem_sys_realloc_zeroed(mc
->idx
,
1005 sizeof (Meth_cache_entry
***) * (type
+ 1),
1006 sizeof (Meth_cache_entry
***) * mc
->mc_size
);
1009 mc
->idx
= (Meth_cache_entry
***)mem_sys_allocate_zeroed(
1010 sizeof (Meth_cache_entry
***) * (type
+ 1));
1012 mc
->mc_size
= type
+ 1;
1015 if (!mc
->idx
[type
]) {
1016 mc
->idx
[type
] = (Meth_cache_entry
**)mem_sys_allocate_zeroed(
1017 sizeof (Meth_cache_entry
*) * TBL_SIZE
);
1020 e
= mc
->idx
[type
][bits
];
1023 while (e
&& e
->strstart
!= method_name
->strstart
) {
1029 /* when here no or no correct entry was at [bits] */
1030 e
= mem_allocate_typed(Meth_cache_entry
);
1035 mc
->idx
[type
][bits
] = e
;
1037 e
->pmc
= Parrot_find_method_direct(interp
, _class
, method_name
);
1039 e
->strstart
= method_name
->strstart
;
1048 =item C<static void debug_trace_find_meth>
1050 RT#48260: Not yet documented!!!
1057 # define TRACE_FM(i, c, m, sub)
1059 # define TRACE_FM(i, c, m, sub) \
1060 debug_trace_find_meth((i), (c), (m), (sub))
1063 debug_trace_find_meth(PARROT_INTERP
, ARGIN(const PMC
*_class
),
1064 ARGIN(const STRING
*name
), ARGIN_NULLOK(const PMC
*sub
))
1070 if (!Interp_trace_TEST(interp
, PARROT_TRACE_FIND_METH_FLAG
))
1073 if (PObj_is_class_TEST(_class
)) {
1074 SLOTTYPE
* const class_array
= PMC_data_typed(_class
, SLOTTYPE
*);
1075 PMC
*const class_name_pmc
= get_attrib_num(class_array
, PCD_CLASS_NAME
);
1076 class_name
= PMC_str_val(class_name_pmc
);
1079 class_name
= _class
->vtable
->whoami
;
1082 if (sub
->vtable
->base_type
== enum_class_NCI
)
1090 tracer
= interp
->debugger
? interp
->debugger
: interp
;
1091 PIO_eprintf(tracer
, "# find_method class '%Ss' method '%Ss': %s\n",
1092 class_name
, name
, result
);
1100 =item C<static PMC * find_method_direct_1>
1102 RT#48260: Not yet documented!!!
1108 PARROT_WARN_UNUSED_RESULT
1109 PARROT_CAN_RETURN_NULL
1111 find_method_direct_1(PARROT_INTERP
, ARGIN(PMC
*_class
),
1112 ARGIN(STRING
*method_name
))
1116 PMC
* const mro
= _class
->vtable
->mro
;
1117 const INTVAL n
= VTABLE_elements(interp
, mro
);
1119 for (i
= 0; i
< n
; ++i
) {
1122 _class
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
1123 ns
= VTABLE_get_namespace(interp
, _class
);
1124 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, method_name
);
1126 TRACE_FM(interp
, _class
, method_name
, method
);
1128 if (!PMC_IS_NULL(method
))
1132 TRACE_FM(interp
, _class
, method_name
, NULL
);
1137 /* ************************************************************************ */
1138 /* ********* BELOW HERE IS NEW PPD15 IMPLEMENTATION RELATED STUFF ********* */
1139 /* ************************************************************************ */
1143 =item C<static PMC* C3_merge>
1145 RT#48260: Not yet documented!!!
1151 PARROT_WARN_UNUSED_RESULT
1152 PARROT_CAN_RETURN_NULL
1154 C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
1156 PMC
*accepted
= PMCNULL
;
1157 PMC
*result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1158 const int list_count
= VTABLE_elements(interp
, merge_list
);
1162 /* Try and find something appropriate to add to the MRO - basically, the
1163 * first list head that is not in the tail of all the other lists. */
1164 for (i
= 0; i
< list_count
; i
++) {
1165 PMC
* const cand_list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1171 if (VTABLE_elements(interp
, cand_list
) == 0)
1174 cand_class
= VTABLE_get_pmc_keyed_int(interp
, cand_list
, 0);
1177 for (j
= 0; j
< list_count
; j
++) {
1178 /* Skip the current list. */
1180 /* Is it in the tail? If so, reject. */
1181 PMC
* const check_list
=
1182 VTABLE_get_pmc_keyed_int(interp
, merge_list
, j
);
1184 const int check_length
= VTABLE_elements(interp
, check_list
);
1187 for (k
= 1; k
< check_length
; k
++) {
1188 if (VTABLE_get_pmc_keyed_int(interp
, check_list
, k
) ==
1197 /* If we didn't reject it, this candidate will do. */
1199 accepted
= cand_class
;
1204 /* If we never found any candidates, return an empty list. */
1205 if (cand_count
== 0)
1206 return pmc_new(interp
, enum_class_ResizablePMCArray
);
1208 /* If we didn't find anything to accept, error. */
1209 if (PMC_IS_NULL(accepted
))
1210 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_ILL_INHERIT
,
1211 "Could not build C3 linearization: ambiguous hierarchy");
1213 /* Otherwise, remove what was accepted from the merge lists. */
1214 for (i
= 0; i
< list_count
; i
++) {
1217 PMC
* const list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1218 const int list_count
= VTABLE_elements(interp
, list
);
1220 for (j
= 0; j
< list_count
; j
++) {
1221 if (VTABLE_get_pmc_keyed_int(interp
, list
, j
) == accepted
) {
1222 VTABLE_delete_keyed_int(interp
, list
, j
);
1228 /* Need to merge what remains of the list, then put what was accepted on
1229 * the start of the list, and we're done. */
1230 result
= C3_merge(interp
, merge_list
);
1231 VTABLE_unshift_pmc(interp
, result
, accepted
);
1239 =item C<PMC* Parrot_ComputeMRO_C3>
1241 Computes the C3 linearization for the given class.
1248 PARROT_WARN_UNUSED_RESULT
1249 PARROT_CAN_RETURN_NULL
1251 Parrot_ComputeMRO_C3(PARROT_INTERP
, ARGIN(PMC
*_class
))
1254 PMC
* const merge_list
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1255 PMC
*immediate_parents
;
1256 int i
, parent_count
;
1258 /* Now get immediate parents list. */
1259 Parrot_PCCINVOKE(interp
, _class
, CONST_STRING(interp
, "parents"),
1260 "->P", &immediate_parents
);
1262 if (!immediate_parents
)
1263 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_METH_NOT_FOUND
,
1264 "Failed to get parents list from class!");
1266 parent_count
= VTABLE_elements(interp
, immediate_parents
);
1268 if (parent_count
== 0) {
1269 /* No parents - MRO just contains this class. */
1270 result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1271 VTABLE_push_pmc(interp
, result
, _class
);
1275 /* Otherwise, need to do merge. For that, need linearizations of all of
1276 * our parents added to the merge list. */
1277 for (i
= 0; i
< parent_count
; i
++) {
1278 PMC
* const lin
= Parrot_ComputeMRO_C3(interp
,
1279 VTABLE_get_pmc_keyed_int(interp
, immediate_parents
, i
));
1281 if (PMC_IS_NULL(lin
))
1284 VTABLE_push_pmc(interp
, merge_list
, lin
);
1287 /* Finally, need list of direct parents on the end of the merge list, then
1289 VTABLE_push_pmc(interp
, merge_list
, immediate_parents
);
1290 result
= C3_merge(interp
, merge_list
);
1292 if (PMC_IS_NULL(result
))
1295 /* Merged result needs this class on the start, and then we're done. */
1296 VTABLE_unshift_pmc(interp
, result
, _class
);
1304 =item C<void Parrot_ComposeRole>
1306 Used by the Class and Object PMCs internally to compose a role into either of
1307 them. The C<role> parameter is the role that we are composing into the class
1308 or role. C<methods_hash> is the hash of method names to invokable PMCs that
1309 contains the methods the class or role has. C<roles_list> is the list of roles
1310 the the class or method does.
1312 The C<role> parameter is only dealt with by its external interface. Whether
1313 this routine is usable by any other object system implemented in Parrot very
1314 much depends on how closely the role composition semantics they want are to
1315 the default implementation.
1323 Parrot_ComposeRole(PARROT_INTERP
, ARGIN(PMC
*role
),
1324 ARGIN(PMC
*exclude
), int got_exclude
,
1325 ARGIN(PMC
*alias
), int got_alias
,
1326 ARGIN(PMC
*methods_hash
), ARGIN(PMC
*roles_list
))
1331 PMC
*proposed_add_methods
;
1333 int i
, roles_of_role_count
;
1335 /* Check we have not already composed the role; if so, just ignore it. */
1336 int roles_count
= VTABLE_elements(interp
, roles_list
);
1338 for (i
= 0; i
< roles_count
; i
++)
1339 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, i
) == role
)
1342 /* Get the methods from the role. */
1343 Parrot_PCCINVOKE(interp
, role
,
1344 CONST_STRING(interp
, "methods"), "->P", &methods
);
1346 if (PMC_IS_NULL(methods
))
1349 /* We need to check for conflicts before we do the composition. We
1350 * put each method that would be OK to add into a proposal list, and
1351 * bail out right away if we find a problem. */
1352 proposed_add_methods
= pmc_new(interp
, enum_class_Hash
);
1353 methods_iter
= VTABLE_get_iter(interp
, methods
);
1355 while (VTABLE_get_bool(interp
, methods_iter
)) {
1356 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1357 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
, methods
,
1360 /* Need to find the name we'll check for a conflict on. */
1363 /* Check if it's in the exclude list. */
1365 const int exclude_count
= VTABLE_elements(interp
, exclude
);
1367 for (i
= 0; i
< exclude_count
; i
++) {
1368 const STRING
* const check
=
1369 VTABLE_get_string_keyed_int(interp
, exclude
, i
);
1371 if (string_equal(interp
, check
, method_name
) == 0) {
1378 /* If we weren't excluded... */
1380 /* Is there a method with this name already in the class?
1381 * RT#45999 multi-method handling. */
1383 if (VTABLE_exists_keyed_str(interp
, methods_hash
, method_name
))
1384 /* Conflicts with something already in the class. */
1385 Parrot_ex_throw_from_c_args(interp
, NULL
,
1386 EXCEPTION_ROLE_COMPOSITION_METH_CONFLICT
,
1387 "A conflict occurred during role composition "
1388 "due to method '%S'.", method_name
);
1390 /* What about a conflict with ourslef? */
1391 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1393 /* Something very weird is going on. */
1394 Parrot_ex_throw_from_c_args(interp
, NULL
,
1395 EXCEPTION_ROLE_COMPOSITION_METH_CONFLICT
,
1396 "A conflict occurred during role composition;"
1397 " the method '%S' from the role managed to conflict "
1398 "with itself somehow.", method_name
);
1400 /* If we got here, no conflicts! Add method to the "to compose"
1402 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1403 method_name
, cur_method
);
1406 /* Now see if we've got an alias. */
1407 if (got_alias
&& VTABLE_exists_keyed_str(interp
, alias
, method_name
)) {
1408 /* Got one. Get name to alias it to. */
1409 STRING
* const alias_name
= VTABLE_get_string_keyed_str(interp
,
1410 alias
, method_name
);
1412 /* Is there a method with this name already in the class?
1413 * RT#45999: multi-method handling. */
1414 if (VTABLE_exists_keyed_str(interp
, methods_hash
, alias_name
))
1415 /* Conflicts with something already in the class. */
1416 Parrot_ex_throw_from_c_args(interp
, NULL
,
1417 EXCEPTION_ROLE_COMPOSITION_METH_CONFLICT
,
1418 "A conflict occurred during role composition"
1419 " due to the aliasing of '%S' to '%S'.",
1420 method_name
, alias_name
);
1422 /* What about a conflict with ourslef? */
1423 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1425 Parrot_ex_throw_from_c_args(interp
, NULL
,
1426 EXCEPTION_ROLE_COMPOSITION_METH_CONFLICT
,
1427 "A conflict occurred during role composition"
1428 " due to the aliasing of '%S' to '%S' (role already has"
1429 " a method '%S').", method_name
, alias_name
, alias_name
);
1431 /* If we get here, no conflicts! Add method to the "to compose"
1432 * list with its alias. */
1433 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1434 alias_name
, cur_method
);
1438 /* If we get here, we detected no conflicts. Go ahead and compose the
1440 methods_iter
= VTABLE_get_iter(interp
, proposed_add_methods
);
1442 while (VTABLE_get_bool(interp
, methods_iter
)) {
1443 /* Get current method and its name. */
1444 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1445 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
,
1446 proposed_add_methods
, method_name
);
1448 /* Add it to the methods of the class. */
1449 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
1452 /* Add this role to the roles list. */
1453 VTABLE_push_pmc(interp
, roles_list
, role
);
1456 /* As a result of composing this role, we will also now do the roles
1457 * that it did itself. Note that we already have the correct methods
1458 * as roles "flatten" the methods they get from other roles into their
1459 * own method list. */
1460 Parrot_PCCINVOKE(interp
, role
,
1461 CONST_STRING(interp
, "roles"), "->P", &roles_of_role
);
1462 roles_of_role_count
= VTABLE_elements(interp
, roles_of_role
);
1464 for (i
= 0; i
< roles_of_role_count
; i
++) {
1465 /* Only add if we don't already have it in the list. */
1466 PMC
* const cur_role
= VTABLE_get_pmc_keyed_int(interp
,
1470 for (j
= 0; j
< roles_count
; j
++) {
1471 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, j
) == cur_role
) {
1472 /* We ain't be havin' it. */
1473 VTABLE_push_pmc(interp
, roles_list
, cur_role
);
1486 F<include/parrot/oo.h>, F<include/parrot/oo_private.h>,
1487 F<docs/pdds/pdd15_objects.pod>.
1495 * c-file-style: "parrot"
1497 * vim: expandtab shiftwidth=4: