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 do_initcall(PARROT_INTERP
,
49 ARGIN_NULLOK(PMC
* _class
),
50 ARGIN_NULLOK(PMC
*object
),
51 ARGIN_NULLOK(PMC
*init
))
52 __attribute__nonnull__(1);
54 static void fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
55 __attribute__nonnull__(1)
56 __attribute__nonnull__(2);
58 PARROT_WARN_UNUSED_RESULT
59 PARROT_CAN_RETURN_NULL
60 static PMC
* find_method_direct_1(PARROT_INTERP
,
62 ARGIN(STRING
*method_name
))
63 __attribute__nonnull__(1)
64 __attribute__nonnull__(2)
65 __attribute__nonnull__(3);
67 PARROT_WARN_UNUSED_RESULT
68 PARROT_CAN_RETURN_NULL
69 static PMC
* find_vtable_meth_ns(PARROT_INTERP
,
72 __attribute__nonnull__(1)
73 __attribute__nonnull__(2);
75 PARROT_WARN_UNUSED_RESULT
76 PARROT_CAN_RETURN_NULL
77 static PMC
* get_init_meth(PARROT_INTERP
,
79 ARGIN(STRING
*prop_str
),
80 ARGOUT(STRING
**meth_str
))
81 __attribute__nonnull__(1)
82 __attribute__nonnull__(2)
83 __attribute__nonnull__(3)
84 __attribute__nonnull__(4)
85 FUNC_MODIFIES(*meth_str
);
87 static void instantiate_object(PARROT_INTERP
,
89 ARGIN_NULLOK(PMC
*init
))
90 __attribute__nonnull__(1)
91 __attribute__nonnull__(2)
92 FUNC_MODIFIES(*object
);
94 static void invalidate_all_caches(PARROT_INTERP
)
95 __attribute__nonnull__(1);
97 static void invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
98 __attribute__nonnull__(1);
100 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
101 /* HEADERIZER END: static */
105 =item C<void Parrot_oo_extract_methods_from_namespace>
107 Extract methods and vtable overrides from the given namespace and insert them
115 Parrot_oo_extract_methods_from_namespace(PARROT_INTERP
, ARGIN(PMC
*self
), ARGIN(PMC
*ns
))
117 PMC
*methods
, *vtable_overrides
;
119 /* Pull in methods from the namespace, if any. */
123 /* Import any methods. */
124 Parrot_PCCINVOKE(interp
, ns
,
125 CONST_STRING(interp
, "get_associated_methods"), "->P", &methods
);
127 if (!PMC_IS_NULL(methods
)) {
128 PMC
* const iter
= VTABLE_get_iter(interp
, methods
);
130 while (VTABLE_get_bool(interp
, iter
)) {
131 STRING
* const meth_name
= VTABLE_shift_string(interp
, iter
);
132 PMC
* const meth_sub
= VTABLE_get_pmc_keyed_str(interp
, methods
,
134 VTABLE_add_method(interp
, self
, meth_name
, meth_sub
);
138 /* Import any vtable methods. */
139 Parrot_PCCINVOKE(interp
, ns
,
140 CONST_STRING(interp
, "get_associated_vtable_methods"), "->P", &vtable_overrides
);
142 if (!PMC_IS_NULL(vtable_overrides
)) {
143 PMC
* const iter
= VTABLE_get_iter(interp
, vtable_overrides
);
144 while (VTABLE_get_bool(interp
, iter
)) {
145 STRING
* const vtable_index_str
= VTABLE_shift_string(interp
, iter
);
146 PMC
* const vtable_sub
= VTABLE_get_pmc_keyed_str(interp
,
147 vtable_overrides
, vtable_index_str
);
149 /* Look up the name of the vtable function from the index. */
150 const INTVAL vtable_index
= string_to_int(interp
, vtable_index_str
);
151 const char * const meth_c
= Parrot_vtable_slot_names
[vtable_index
];
152 STRING
*vtable_name
= string_from_cstring(interp
, meth_c
, 0);
154 /* Strip leading underscores in the vtable name */
155 if (string_str_index(interp
, vtable_name
,
156 CONST_STRING(interp
, "__"), 0) == 0) {
157 vtable_name
= string_substr(interp
, vtable_name
, 2,
158 string_length(interp
, vtable_name
) - 2, NULL
, 0);
161 VTABLE_add_vtable_override(interp
, self
, vtable_name
, vtable_sub
);
169 =item C<PMC * Parrot_oo_get_namespace>
171 Lookup a namespace object from a class PMC.
177 PARROT_CAN_RETURN_NULL
178 PARROT_WARN_UNUSED_RESULT
180 Parrot_oo_get_namespace(SHIM_INTERP
, ARGIN(const PMC
*classobj
))
182 Parrot_Class
* const _class
= PARROT_CLASS(classobj
);
183 PMC
* const _namespace
= _class
->_namespace
;
185 if (PMC_IS_NULL(_namespace
))
194 =item C<PMC * Parrot_oo_get_class>
196 Lookup a class object from a namespace, string, or key PMC.
203 PARROT_CAN_RETURN_NULL
204 PARROT_WARN_UNUSED_RESULT
206 Parrot_oo_get_class(PARROT_INTERP
, ARGIN(PMC
*key
))
208 PMC
*classobj
= PMCNULL
;
210 if (PObj_is_class_TEST(key
))
213 /* Fast select of behavior based on type of the lookup key */
214 switch (key
->vtable
->base_type
) {
215 case enum_class_NameSpace
:
216 classobj
= VTABLE_get_class(interp
, key
);
219 case enum_class_String
:
221 case enum_class_ResizableStringArray
:
223 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
,
224 interp
->HLL_namespace
,
225 CONTEXT(interp
)->current_HLL
);
226 PMC
* const ns
= Parrot_get_namespace_keyed(interp
,
229 if (!PMC_IS_NULL(ns
))
230 classobj
= VTABLE_get_class(interp
, ns
);
237 if (PMC_IS_NULL(classobj
)) {
238 /* Look up a low-level class and create a proxy */
239 const INTVAL type
= pmc_type(interp
, VTABLE_get_string(interp
, key
));
241 /* Reject invalid type numbers */
242 if (type
> interp
->n_vtable_max
|| type
<= 0)
245 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
246 VTABLE_set_integer_native(interp
, type_num
, type
);
247 classobj
= pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
257 =item C<PMC * Parrot_oo_get_class_str>
259 Lookup a class object from a builtin string.
266 PARROT_CAN_RETURN_NULL
267 PARROT_WARN_UNUSED_RESULT
269 Parrot_oo_get_class_str(PARROT_INTERP
, ARGIN(STRING
*name
))
271 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
, interp
->HLL_namespace
,
272 CONTEXT(interp
)->current_HLL
);
273 PMC
* const ns
= Parrot_get_namespace_keyed_str(interp
, hll_ns
, name
);
274 PMC
* const _class
= PMC_IS_NULL(ns
)
275 ? PMCNULL
: VTABLE_get_class(interp
, ns
);
277 /* Look up a low-level class and create a proxy */
278 if (PMC_IS_NULL(_class
)) {
279 const INTVAL type
= pmc_type(interp
, name
);
281 /* Reject invalid type numbers */
282 if (type
> interp
->n_vtable_max
|| type
<= 0)
285 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
286 VTABLE_set_integer_native(interp
, type_num
, type
);
287 return pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
297 =item C<PMC * Parrot_oo_newclass_from_str>
299 Create a new class object from a string name.
305 PARROT_CAN_RETURN_NULL
306 PARROT_WARN_UNUSED_RESULT
308 Parrot_oo_newclass_from_str(PARROT_INTERP
, ARGIN(STRING
*name
))
310 PMC
* const namearg
= pmc_new(interp
, enum_class_String
);
311 PMC
*namehash
= pmc_new(interp
, enum_class_Hash
);
314 VTABLE_set_string_native(interp
, namearg
, name
);
315 VTABLE_set_pmc_keyed_str(interp
, namehash
, CONST_STRING(interp
, "name"), namearg
);
317 classobj
= pmc_new_init(interp
, enum_class_Class
, namehash
);
319 PARROT_ASSERT(classobj
);
326 =item C<PMC * Parrot_oo_find_vtable_override_for_class>
328 Lookup a vtable override in a specific class object.
334 PARROT_CAN_RETURN_NULL
335 PARROT_WARN_UNUSED_RESULT
337 Parrot_oo_find_vtable_override_for_class(PARROT_INTERP
,
338 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
340 Parrot_Class
*class_info
;
341 PARROT_ASSERT(PObj_is_class_TEST(classobj
));
343 class_info
= PARROT_CLASS(classobj
);
344 return VTABLE_get_pmc_keyed_str(interp
, class_info
->vtable_overrides
, name
);
350 =item C<PMC * Parrot_oo_find_vtable_override>
352 Lookup a vtable override in a class, including any vtable overrides inherited
359 PARROT_CAN_RETURN_NULL
360 PARROT_WARN_UNUSED_RESULT
362 Parrot_oo_find_vtable_override(PARROT_INTERP
,
363 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
365 Parrot_Class
* const _class
= PARROT_CLASS(classobj
);
367 if (VTABLE_exists_keyed_str(interp
, _class
->parent_overrides
, name
))
368 return VTABLE_get_pmc_keyed_str(interp
, _class
->parent_overrides
, name
);
370 /* Walk and search for the vtable method. */
371 const INTVAL num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
372 PMC
*result
= PMCNULL
;
375 for (i
= 0; i
< num_classes
; i
++) {
377 PMC
* const cur_class
=
378 VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, i
);
380 result
= Parrot_oo_find_vtable_override_for_class(interp
,
383 if (!PMC_IS_NULL(result
))
387 VTABLE_set_pmc_keyed_str(interp
, _class
->parent_overrides
, name
, result
);
396 =item C<INTVAL Parrot_get_vtable_index>
398 Return index if C<name> is a valid vtable slot name.
406 Parrot_get_vtable_index(PARROT_INTERP
, ARGIN(const STRING
*name
))
408 char * const name_c
= string_to_cstring(interp
, name
);
410 /* some of the first "slots" don't have names. skip 'em. */
411 INTVAL low
= PARROT_VTABLE_LOW
;
412 INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
415 const INTVAL mid
= (low
+ high
) / 2;
416 const char * const meth_c
= Parrot_vtable_slot_names
[mid
];
418 /* RT#45965 slot_names still have __ in front */
419 const INTVAL cmp
= strcmp(name_c
, meth_c
+ 2);
422 string_cstring_free(name_c
);
431 string_cstring_free(name_c
);
439 =item C<static PMC* find_vtable_meth_ns>
441 Return Sub PMC if a method with the vtable name exists in ns
447 PARROT_WARN_UNUSED_RESULT
448 PARROT_CAN_RETURN_NULL
450 find_vtable_meth_ns(PARROT_INTERP
, ARGIN(PMC
*ns
), INTVAL vtable_index
)
452 return VTABLE_get_pmc_keyed_int(interp
, ns
, vtable_index
);
458 =item C<STRING* readable_name>
460 Given a String or Key PMC return the STRING* representation
462 RT#45967 this function, key_set_to_string, and the key PMC get_repr should be
470 PARROT_WARN_UNUSED_RESULT
471 PARROT_CANNOT_RETURN_NULL
473 readable_name(PARROT_INTERP
, ARGIN(PMC
*name
))
477 if (name
->vtable
->base_type
== enum_class_String
)
478 return VTABLE_get_string(interp
, name
);
480 array
= pmc_new(interp
, enum_class_ResizableStringArray
);
482 PARROT_ASSERT(name
->vtable
->base_type
== enum_class_Key
);
485 VTABLE_push_string(interp
, array
, key_string(interp
, name
));
486 name
= key_next(interp
, name
);
489 return string_join(interp
, CONST_STRING(interp
, ";"), array
);
495 =item C<const char* Parrot_MMD_method_name>
497 Return the method name for the given MMD enum.
505 PARROT_CAN_RETURN_NULL
507 Parrot_MMD_method_name(SHIM_INTERP
, INTVAL idx
)
509 PARROT_ASSERT(idx
>= 0);
511 if (idx
>= MMD_USER_FIRST
)
514 return Parrot_mmd_func_names
[idx
];
520 =item C<INTVAL Parrot_MMD_method_idx>
522 Return the MMD function number for method name or -1 on failure.
524 RT#45973 allow dynamic expansion at runtime.
533 Parrot_MMD_method_idx(SHIM_INTERP
, ARGIN(const char *name
))
537 for (i
= 0; i
< MMD_USER_FIRST
; ++i
) {
538 if (STREQ(Parrot_mmd_func_names
[i
], name
))
548 =item C<PMC * Parrot_class_lookup>
550 Looks for the class named C<class_name> and returns it if it exists.
551 Otherwise it returns C<PMCNULL>.
558 PARROT_CAN_RETURN_NULL
559 PARROT_WARN_UNUSED_RESULT
561 Parrot_class_lookup(PARROT_INTERP
, ARGIN(STRING
*class_name
))
563 const INTVAL type
= pmc_type(interp
, class_name
);
569 pmc
= interp
->vtables
[type
]->pmc_class
;
577 =item C<PMC * Parrot_class_lookup_p>
579 Looks for the class named C<class_name> and returns it if it exists.
580 Otherwise it returns C<PMCNULL>.
586 PARROT_CAN_RETURN_NULL
587 PARROT_WARN_UNUSED_RESULT
589 Parrot_class_lookup_p(PARROT_INTERP
, ARGIN(PMC
*class_name
))
591 const INTVAL type
= pmc_type_p(interp
, class_name
);
597 pmc
= interp
->vtables
[type
]->pmc_class
;
605 =item C<static void fail_if_type_exists>
607 This function throws an exception if a PMC or class with the same name *
608 already exists in the global type registry. The global type registry
609 will go away eventually, but this allows the new object metamodel to
610 interact with the old one until it does.
617 fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
621 PMC
* const classname_hash
= interp
->class_hash
;
622 PMC
* const type_pmc
= (PMC
*)VTABLE_get_pointer_keyed(interp
,
623 classname_hash
, name
);
625 if (PMC_IS_NULL(type_pmc
)
626 || type_pmc
->vtable
->base_type
== enum_class_NameSpace
)
629 type
= VTABLE_get_integer(interp
, type_pmc
);
631 if (type
> enum_type_undef
)
632 real_exception(interp
, NULL
, INVALID_OPERATION
,
633 "Class '%Ss' already registered!\n",
634 string_escape_string(interp
, VTABLE_get_string(interp
, name
)));
636 if (type
< enum_type_undef
)
637 real_exception(interp
, NULL
, INVALID_OPERATION
,
638 "native type with name '%s' already exists - "
639 "can't register Class", data_types
[type
].name
);
645 =item C<INTVAL Parrot_oo_register_type>
647 This function registers a type in the global registry, first checking if it
648 already exists. The global type registry will go away eventually, but this
649 allows the new object metamodel to interact with the old one until it does.
655 PARROT_WARN_UNUSED_RESULT
657 Parrot_oo_register_type(PARROT_INTERP
, ARGIN(PMC
*name
))
660 PMC
*classname_hash
, *item
;
662 fail_if_type_exists(interp
, name
);
664 /* Type doesn't exist, so go ahead and register it. Lock interpreter so
665 * pt_shared_fixup() can safely do a type lookup. */
666 LOCK_INTERPRETER(interp
);
667 classname_hash
= interp
->class_hash
;
669 type
= interp
->n_vtable_max
++;
671 /* Have we overflowed the table? */
672 if (type
>= interp
->n_vtable_alloced
)
673 parrot_realloc_vtables(interp
);
675 /* set entry in name->type hash */
676 item
= pmc_new(interp
, enum_class_Integer
);
677 PMC_int_val(item
) = type
;
679 VTABLE_set_pmc_keyed(interp
, classname_hash
, name
, item
);
680 UNLOCK_INTERPRETER(interp
);
688 =item C<static PMC* get_init_meth>
690 RT#48260: Not yet documented!!!
696 PARROT_WARN_UNUSED_RESULT
697 PARROT_CAN_RETURN_NULL
699 get_init_meth(PARROT_INTERP
, ARGIN(PMC
*_class
),
700 ARGIN(STRING
*prop_str
), ARGOUT(STRING
**meth_str
))
704 PMC
*props
, *ns
, *method
;
708 PMC
* const prop
= VTABLE_getprop(interp
, _class
, prop_str
);
709 if (!VTABLE_defined(interp
, prop
))
711 meth
= VTABLE_get_string(interp
, prop
);
713 props
= PMC_metadata(_class
);
717 b
= parrot_hash_get_bucket(interp
,
718 (Hash
*) PMC_struct_val(props
), prop_str
);
722 meth
= PMC_str_val((PMC
*) b
->value
);
726 ns
= VTABLE_get_namespace(interp
, _class
);
727 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, meth
);
735 =item C<static void do_initcall>
737 RT#48260: Not yet documented!!!
744 do_initcall(PARROT_INTERP
, ARGIN_NULLOK(PMC
* _class
), ARGIN_NULLOK(PMC
*object
),
745 ARGIN_NULLOK(PMC
*init
))
747 PMC
* const classsearch_array
= _class
->vtable
->mro
;
751 * 1) if class has a CONSTRUCT property run it on the object
754 * RT#45985 isn't CONSTRUCT for creating new objects?
757 PMC
*meth
= get_init_meth(interp
, _class
,
758 CONST_STRING(interp
, "CONSTRUCT"), &meth_str
);
761 if (!PMC_IS_NULL(meth
)) {
763 Parrot_run_meth_fromc_args(interp
, meth
,
764 object
, meth_str
, "vP", init
);
766 Parrot_run_meth_fromc_args(interp
, meth
,
767 object
, meth_str
, "v");
770 * 2. if class has a BUILD property call it for all classes
771 * in reverse search order - this class last.
773 * Note: mro contains this class as first element
775 nparents
= VTABLE_elements(interp
, classsearch_array
);
777 for (i
= nparents
- 1; i
>= 0; --i
) {
778 PMC
* const parent_class
=
779 VTABLE_get_pmc_keyed_int(interp
, classsearch_array
, i
);
781 /* if it's a PMC, we put one PMC of that type into
782 * the attribute slot #0 and call init() on that PMC */
783 if (!PObj_is_class_TEST(parent_class
)) {
784 PMC
*attr
, *next_parent
;
787 /* but only if init isn't inherited
788 * or rather just on the last non-class parent */
789 PARROT_ASSERT(i
>= 1);
790 next_parent
= VTABLE_get_pmc_keyed_int(interp
,
791 classsearch_array
, i
- 1);
793 if (!PObj_is_class_TEST(next_parent
))
796 attr
= pmc_new_noinit(interp
, parent_class
->vtable
->base_type
);
797 obj_data
= PMC_data_typed(object
, SLOTTYPE
*);
798 set_attrib_num(object
, obj_data
, 0, attr
);
799 VTABLE_init(interp
, attr
);
803 meth
= get_init_meth(interp
, parent_class
,
804 CONST_STRING(interp
, "BUILD"), &meth_str
);
806 /* no method found and no BUILD property set? */
807 if (PMC_IS_NULL(meth
) && meth_str
== NULL
) {
811 /* use __init or __init_pmc (depending on if an argument was passed)
812 * as fallback constructor method, if it exists */
814 meth_str
= CONST_STRING(interp
, "init_pmc");
816 meth_str
= CONST_STRING(interp
, "init");
818 ns
= VTABLE_get_namespace(interp
, parent_class
);
820 /* can't use find_method, it walks mro */
821 vtable_index
= Parrot_get_vtable_index(interp
, meth_str
);
822 meth
= find_vtable_meth_ns(interp
, ns
, vtable_index
);
828 if (!PMC_IS_NULL(meth
)) {
830 Parrot_run_meth_fromc_args(interp
, meth
,
831 object
, meth_str
, "vP", init
);
833 Parrot_run_meth_fromc_args(interp
, meth
,
834 object
, meth_str
, "v");
836 else if (meth_str
!= NULL
&&
837 string_length(interp
, meth_str
) != 0 && !default_meth
) {
838 real_exception(interp
, NULL
, METH_NOT_FOUND
,
839 "Class BUILD method ('%Ss') not found", meth_str
);
847 =item C<void Parrot_instantiate_object_init>
849 Creates a Parrot object. Takes a passed-in class PMC that has sufficient
850 information to describe the layout of the object and makes the object.
858 Parrot_instantiate_object_init(PARROT_INTERP
, ARGIN(PMC
*object
), ARGIN(PMC
*init
))
860 instantiate_object(interp
, object
, init
);
866 =item C<void Parrot_instantiate_object>
868 Wrapper for instantiate_object, passing NULL as initialization.
869 Returns a new Parrot object.
877 Parrot_instantiate_object(PARROT_INTERP
, ARGMOD(PMC
*object
))
879 instantiate_object(interp
, object
, NULL
);
885 =item C<static void instantiate_object>
887 RT#48260: Not yet documented!!!
894 instantiate_object(PARROT_INTERP
, ARGMOD(PMC
*object
), ARGIN_NULLOK(PMC
*init
))
896 SLOTTYPE
*new_object_array
;
897 INTVAL attrib_count
, i
;
899 PMC
* const _class
= object
->vtable
->pmc_class
;
901 /* put in the real vtable */
902 PMC
* const vtable_pmc
= get_attrib_num((SLOTTYPE
*)PMC_data(_class
),
904 object
->vtable
= (VTABLE
*)PMC_struct_val(vtable_pmc
);
906 /* Grab the attribute count from the class */
907 attrib_count
= CLASS_ATTRIB_COUNT(_class
);
909 /* Build the array that hangs off the new object */
910 /* First presize it */
911 set_attrib_array_size(object
, attrib_count
);
912 new_object_array
= PMC_data_typed(object
, SLOTTYPE
*);
914 /* fill with PMCNULL, so that access doesn't segfault */
915 for (i
= 0; i
< attrib_count
; ++i
)
916 set_attrib_num(object
, new_object_array
, i
, PMCNULL
);
918 /* turn marking on */
919 set_attrib_flags(object
);
921 /* We are an object now */
922 PObj_is_object_SET(object
);
924 /* We really ought to call the class init routines here...
925 * this assumes that an object isa delegate */
926 do_initcall(interp
, _class
, object
, init
);
932 =item C<PMC * Parrot_remove_parent>
934 This currently does nothing but return C<PMCNULL>.
942 PARROT_IGNORABLE_RESULT
943 PARROT_CAN_RETURN_NULL
945 Parrot_remove_parent(PARROT_INTERP
, ARGIN(PMC
*removed_class
),
946 ARGIN(PMC
*existing_class
))
949 UNUSED(removed_class
);
950 UNUSED(existing_class
);
958 =item C<void mark_object_cache>
960 Marks all PMCs in the object method cache as live. This shouldn't strictly be
961 necessary, as they're likely all reachable from namespaces and classes, but
962 it's unlikely to hurt anything except mark phase performance.
968 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
969 #define TBL_SIZE (1 + TBL_SIZE_MASK)
972 mark_object_cache(PARROT_INTERP
)
974 Caches
* const mc
= interp
->caches
;
980 for (type
= 0; type
< mc
->mc_size
; type
++) {
984 for (entry
= 0; entry
< TBL_SIZE
; ++entry
) {
985 Meth_cache_entry
*e
= mc
->idx
[type
][entry
];
987 pobject_lives(interp
, (PObj
*)e
->pmc
);
997 =item C<void init_object_cache>
999 Allocate memory for object cache.
1006 init_object_cache(PARROT_INTERP
)
1008 Caches
* const mc
= interp
->caches
= mem_allocate_zeroed_typed(Caches
);
1015 =item C<void destroy_object_cache>
1017 RT#48260: Not yet documented!!!
1024 destroy_object_cache(PARROT_INTERP
)
1027 Caches
* const mc
= interp
->caches
;
1029 /* mc->idx[type][bits] = e; */
1030 for (i
= 0; i
< mc
->mc_size
; i
++) {
1032 invalidate_type_caches(interp
, i
);
1035 mem_sys_free(mc
->idx
);
1042 =item C<static void invalidate_type_caches>
1044 RT#48260: Not yet documented!!!
1051 invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
1053 Caches
* const mc
= interp
->caches
;
1059 /* is it a valid entry */
1060 if (type
>= mc
->mc_size
|| !mc
->idx
[type
])
1063 for (i
= 0; i
< TBL_SIZE
; ++i
) {
1064 Meth_cache_entry
*e
= mc
->idx
[type
][i
];
1066 Meth_cache_entry
* const next
= e
->next
;
1072 mem_sys_free(mc
->idx
[type
]);
1073 mc
->idx
[type
] = NULL
;
1079 =item C<static void invalidate_all_caches>
1081 RT#48260: Not yet documented!!!
1088 invalidate_all_caches(PARROT_INTERP
)
1091 for (i
= 1; i
< (UINTVAL
)interp
->n_vtable_max
; ++i
)
1092 invalidate_type_caches(interp
, i
);
1098 =item C<void Parrot_invalidate_method_cache>
1100 Clear method cache for the given class. If class is NULL, caches for
1101 all classes are invalidated.
1109 Parrot_invalidate_method_cache(PARROT_INTERP
, ARGIN_NULLOK(STRING
*_class
), ARGIN(STRING
*meth
))
1113 /* during interp creation and NCI registration the class_hash
1115 if (!interp
->class_hash
)
1118 if (interp
->resume_flag
& RESUME_INITIAL
)
1122 invalidate_all_caches(interp
);
1126 type
= pmc_type(interp
, _class
);
1129 invalidate_all_caches(interp
);
1131 invalidate_type_caches(interp
, (UINTVAL
)type
);
1136 * quick'n'dirty method cache
1137 * RT#45987: use a hash if method_name is not constant
1138 * i.e. from obj.$Sreg(args)
1139 * If this hash is implemented mark it during DOD
1144 =item C<PMC * Parrot_find_method_direct>
1146 Find a method PMC for a named method, given the class PMC, current
1147 interpreter, and name of the method. Don't use a possible method cache.
1154 PARROT_CAN_RETURN_NULL
1155 PARROT_WARN_UNUSED_RESULT
1157 Parrot_find_method_direct(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
1159 PMC
* const found
= find_method_direct_1(interp
, _class
, method_name
);
1161 if (!PMC_IS_NULL(found
))
1165 if (!string_equal(interp
, method_name
, CONST_STRING(interp
, "__get_string")))
1166 return find_method_direct_1(interp
, _class
,
1167 CONST_STRING(interp
, "__get_repr"));
1175 =item C<PMC * Parrot_find_method_with_cache>
1177 Find a method PMC for a named method, given the class PMC, current
1178 interp, and name of the method.
1180 This routine should use the current scope's method cache, if there is
1181 one. If not, it creates a new method cache. Or, rather, it will when
1182 we've got that bit working. For now it unconditionally goes and looks up
1183 the name in the global stash.
1190 PARROT_CAN_RETURN_NULL
1191 PARROT_WARN_UNUSED_RESULT
1193 Parrot_find_method_with_cache(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
1198 Meth_cache_entry
*e
, *old
;
1200 PARROT_ASSERT(method_name
!= 0);
1202 #if DISABLE_METH_CACHE
1203 return Parrot_find_method_direct(interp
, _class
, method_name
);
1206 if (! PObj_constant_TEST(method_name
))
1207 return Parrot_find_method_direct(interp
, _class
, method_name
);
1209 mc
= interp
->caches
;
1210 type
= _class
->vtable
->base_type
;
1211 bits
= (((UINTVAL
) method_name
->strstart
) >> 2) & TBL_SIZE_MASK
;
1213 if (type
>= mc
->mc_size
) {
1215 mc
->idx
= (Meth_cache_entry
***)mem_sys_realloc_zeroed(mc
->idx
,
1216 sizeof (Meth_cache_entry
***) * (type
+ 1),
1217 sizeof (Meth_cache_entry
***) * mc
->mc_size
);
1220 mc
->idx
= (Meth_cache_entry
***)mem_sys_allocate_zeroed(
1221 sizeof (Meth_cache_entry
***) * (type
+ 1));
1223 mc
->mc_size
= type
+ 1;
1226 if (!mc
->idx
[type
]) {
1227 mc
->idx
[type
] = (Meth_cache_entry
**)mem_sys_allocate_zeroed(
1228 sizeof (Meth_cache_entry
*) * TBL_SIZE
);
1231 e
= mc
->idx
[type
][bits
];
1234 while (e
&& e
->strstart
!= method_name
->strstart
) {
1240 /* when here no or no correct entry was at [bits] */
1241 e
= mem_allocate_typed(Meth_cache_entry
);
1246 mc
->idx
[type
][bits
] = e
;
1248 e
->pmc
= Parrot_find_method_direct(interp
, _class
, method_name
);
1250 e
->strstart
= method_name
->strstart
;
1259 =item C<static void debug_trace_find_meth>
1261 RT#48260: Not yet documented!!!
1268 # define TRACE_FM(i, c, m, sub)
1270 # define TRACE_FM(i, c, m, sub) \
1271 debug_trace_find_meth((i), (c), (m), (sub))
1274 debug_trace_find_meth(PARROT_INTERP
, ARGIN(const PMC
*_class
),
1275 ARGIN(const STRING
*name
), ARGIN_NULLOK(const PMC
*sub
))
1281 if (!Interp_trace_TEST(interp
, PARROT_TRACE_FIND_METH_FLAG
))
1284 if (PObj_is_class_TEST(_class
)) {
1285 SLOTTYPE
* const class_array
= PMC_data_typed(_class
, SLOTTYPE
*);
1286 PMC
*const class_name_pmc
= get_attrib_num(class_array
, PCD_CLASS_NAME
);
1287 class_name
= PMC_str_val(class_name_pmc
);
1290 class_name
= _class
->vtable
->whoami
;
1293 if (sub
->vtable
->base_type
== enum_class_NCI
)
1301 tracer
= interp
->debugger
? interp
->debugger
: interp
;
1302 PIO_eprintf(tracer
, "# find_method class '%Ss' method '%Ss': %s\n",
1303 class_name
, name
, result
);
1311 =item C<static PMC * find_method_direct_1>
1313 RT#48260: Not yet documented!!!
1319 PARROT_WARN_UNUSED_RESULT
1320 PARROT_CAN_RETURN_NULL
1322 find_method_direct_1(PARROT_INTERP
, ARGIN(PMC
*_class
),
1323 ARGIN(STRING
*method_name
))
1327 PMC
* const mro
= _class
->vtable
->mro
;
1328 const INTVAL n
= VTABLE_elements(interp
, mro
);
1330 for (i
= 0; i
< n
; ++i
) {
1333 _class
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
1334 ns
= VTABLE_get_namespace(interp
, _class
);
1335 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, method_name
);
1337 TRACE_FM(interp
, _class
, method_name
, method
);
1339 if (!PMC_IS_NULL(method
))
1343 TRACE_FM(interp
, _class
, method_name
, NULL
);
1348 /* ************************************************************************ */
1349 /* ********* BELOW HERE IS NEW PPD15 IMPLEMENTATION RELATED STUFF ********* */
1350 /* ************************************************************************ */
1354 =item C<static PMC* C3_merge>
1356 RT#48260: Not yet documented!!!
1362 PARROT_WARN_UNUSED_RESULT
1363 PARROT_CAN_RETURN_NULL
1365 C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
1367 PMC
*accepted
= PMCNULL
;
1368 PMC
*result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1369 const int list_count
= VTABLE_elements(interp
, merge_list
);
1373 /* Try and find something appropriate to add to the MRO - basically, the
1374 * first list head that is not in the tail of all the other lists. */
1375 for (i
= 0; i
< list_count
; i
++) {
1376 PMC
* const cand_list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1382 if (VTABLE_elements(interp
, cand_list
) == 0)
1385 cand_class
= VTABLE_get_pmc_keyed_int(interp
, cand_list
, 0);
1388 for (j
= 0; j
< list_count
; j
++) {
1389 /* Skip the current list. */
1391 /* Is it in the tail? If so, reject. */
1392 PMC
* const check_list
=
1393 VTABLE_get_pmc_keyed_int(interp
, merge_list
, j
);
1395 const int check_length
= VTABLE_elements(interp
, check_list
);
1398 for (k
= 1; k
< check_length
; k
++) {
1399 if (VTABLE_get_pmc_keyed_int(interp
, check_list
, k
) ==
1408 /* If we didn't reject it, this candidate will do. */
1410 accepted
= cand_class
;
1415 /* If we never found any candidates, return an empty list. */
1416 if (cand_count
== 0)
1417 return pmc_new(interp
, enum_class_ResizablePMCArray
);
1419 /* If we didn't find anything to accept, error. */
1420 if (PMC_IS_NULL(accepted
))
1421 real_exception(interp
, NULL
, ILL_INHERIT
,
1422 "Could not build C3 linearization: ambiguous hierarchy");
1424 /* Otherwise, remove what was accepted from the merge lists. */
1425 for (i
= 0; i
< list_count
; i
++) {
1428 PMC
* const list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1429 const int list_count
= VTABLE_elements(interp
, list
);
1431 for (j
= 0; j
< list_count
; j
++) {
1432 if (VTABLE_get_pmc_keyed_int(interp
, list
, j
) == accepted
) {
1433 VTABLE_delete_keyed_int(interp
, list
, j
);
1439 /* Need to merge what remains of the list, then put what was accepted on
1440 * the start of the list, and we're done. */
1441 result
= C3_merge(interp
, merge_list
);
1442 VTABLE_unshift_pmc(interp
, result
, accepted
);
1450 =item C<PMC* Parrot_ComputeMRO_C3>
1452 Computes the C3 linearization for the given class.
1459 PARROT_WARN_UNUSED_RESULT
1460 PARROT_CAN_RETURN_NULL
1462 Parrot_ComputeMRO_C3(PARROT_INTERP
, ARGIN(PMC
*_class
))
1465 PMC
* const merge_list
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1466 PMC
*immediate_parents
;
1467 int i
, parent_count
;
1469 /* Now get immediate parents list. */
1470 Parrot_PCCINVOKE(interp
, _class
, CONST_STRING(interp
, "parents"),
1471 "->P", &immediate_parents
);
1473 if (!immediate_parents
)
1474 real_exception(interp
, NULL
, METH_NOT_FOUND
,
1475 "Failed to get parents list from class!");
1477 parent_count
= VTABLE_elements(interp
, immediate_parents
);
1479 if (parent_count
== 0) {
1480 /* No parents - MRO just contains this class. */
1481 result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1482 VTABLE_push_pmc(interp
, result
, _class
);
1486 /* Otherwise, need to do merge. For that, need linearizations of all of
1487 * our parents added to the merge list. */
1488 for (i
= 0; i
< parent_count
; i
++) {
1489 PMC
* const lin
= Parrot_ComputeMRO_C3(interp
,
1490 VTABLE_get_pmc_keyed_int(interp
, immediate_parents
, i
));
1492 if (PMC_IS_NULL(lin
))
1495 VTABLE_push_pmc(interp
, merge_list
, lin
);
1498 /* Finally, need list of direct parents on the end of the merge list, then
1500 VTABLE_push_pmc(interp
, merge_list
, immediate_parents
);
1501 result
= C3_merge(interp
, merge_list
);
1503 if (PMC_IS_NULL(result
))
1506 /* Merged result needs this class on the start, and then we're done. */
1507 VTABLE_unshift_pmc(interp
, result
, _class
);
1515 =item C<void Parrot_ComposeRole>
1517 Used by the Class and Object PMCs internally to compose a role into either of
1518 them. The C<role> parameter is the role that we are composing into the class
1519 or role. C<methods_hash> is the hash of method names to invokable PMCs that
1520 contains the methods the class or role has. C<roles_list> is the list of roles
1521 the the class or method does.
1523 The C<role> parameter is only dealt with by its external interface. Whether
1524 this routine is usable by any other object system implemented in Parrot very
1525 much depends on how closely the role composition semantics they want are to
1526 the default implementation.
1534 Parrot_ComposeRole(PARROT_INTERP
, ARGIN(PMC
*role
),
1535 ARGIN(PMC
*exclude
), int got_exclude
,
1536 ARGIN(PMC
*alias
), int got_alias
,
1537 ARGIN(PMC
*methods_hash
), ARGIN(PMC
*roles_list
))
1542 PMC
*proposed_add_methods
;
1544 int i
, roles_of_role_count
;
1546 /* Check we have not already composed the role; if so, just ignore it. */
1547 int roles_count
= VTABLE_elements(interp
, roles_list
);
1549 for (i
= 0; i
< roles_count
; i
++)
1550 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, i
) == role
)
1553 /* Get the methods from the role. */
1554 Parrot_PCCINVOKE(interp
, role
,
1555 CONST_STRING(interp
, "methods"), "->P", &methods
);
1557 if (PMC_IS_NULL(methods
))
1560 /* We need to check for conflicts before we do the composition. We
1561 * put each method that would be OK to add into a proposal list, and
1562 * bail out right away if we find a problem. */
1563 proposed_add_methods
= pmc_new(interp
, enum_class_Hash
);
1564 methods_iter
= VTABLE_get_iter(interp
, methods
);
1566 while (VTABLE_get_bool(interp
, methods_iter
)) {
1567 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1568 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
, methods
,
1571 /* Need to find the name we'll check for a conflict on. */
1574 /* Check if it's in the exclude list. */
1576 const int exclude_count
= VTABLE_elements(interp
, exclude
);
1578 for (i
= 0; i
< exclude_count
; i
++) {
1579 const STRING
* const check
=
1580 VTABLE_get_string_keyed_int(interp
, exclude
, i
);
1582 if (string_equal(interp
, check
, method_name
) == 0) {
1589 /* If we weren't excluded... */
1591 /* Is there a method with this name already in the class?
1592 * RT#45999 multi-method handling. */
1594 if (VTABLE_exists_keyed_str(interp
, methods_hash
, method_name
))
1595 /* Conflicts with something already in the class. */
1596 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
1597 "A conflict occurred during role composition "
1598 "due to method '%S'.", method_name
);
1600 /* What about a conflict with ourslef? */
1601 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1603 /* Something very weird is going on. */
1604 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
1605 "A conflict occurred during role composition;"
1606 " the method '%S' from the role managed to conflict "
1607 "with itself somehow.", method_name
);
1609 /* If we got here, no conflicts! Add method to the "to compose"
1611 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1612 method_name
, cur_method
);
1615 /* Now see if we've got an alias. */
1616 if (got_alias
&& VTABLE_exists_keyed_str(interp
, alias
, method_name
)) {
1617 /* Got one. Get name to alias it to. */
1618 STRING
* const alias_name
= VTABLE_get_string_keyed_str(interp
,
1619 alias
, method_name
);
1621 /* Is there a method with this name already in the class?
1622 * RT#45999: multi-method handling. */
1623 if (VTABLE_exists_keyed_str(interp
, methods_hash
, alias_name
))
1624 /* Conflicts with something already in the class. */
1625 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
1626 "A conflict occurred during role composition"
1627 " due to the aliasing of '%S' to '%S'.",
1628 method_name
, alias_name
);
1630 /* What about a conflict with ourslef? */
1631 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1633 real_exception(interp
, NULL
, ROLE_COMPOSITION_METH_CONFLICT
,
1634 "A conflict occurred during role composition"
1635 " due to the aliasing of '%S' to '%S' (role already has"
1637 method_name
, alias_name
, alias_name
);
1639 /* If we get here, no conflicts! Add method to the "to compose"
1640 * list with its alias. */
1641 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1642 alias_name
, cur_method
);
1646 /* If we get here, we detected no conflicts. Go ahead and compose the
1648 methods_iter
= VTABLE_get_iter(interp
, proposed_add_methods
);
1650 while (VTABLE_get_bool(interp
, methods_iter
)) {
1651 /* Get current method and its name. */
1652 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1653 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
,
1654 proposed_add_methods
, method_name
);
1656 /* Add it to the methods of the class. */
1657 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
1660 /* Add this role to the roles list. */
1661 VTABLE_push_pmc(interp
, roles_list
, role
);
1664 /* As a result of composing this role, we will also now do the roles
1665 * that it did itself. Note that we already have the correct methods
1666 * as roles "flatten" the methods they get from other roles into their
1667 * own method list. */
1668 Parrot_PCCINVOKE(interp
, role
,
1669 CONST_STRING(interp
, "roles"), "->P", &roles_of_role
);
1670 roles_of_role_count
= VTABLE_elements(interp
, roles_of_role
);
1672 for (i
= 0; i
< roles_of_role_count
; i
++) {
1673 /* Only add if we don't already have it in the list. */
1674 PMC
* const cur_role
= VTABLE_get_pmc_keyed_int(interp
,
1678 for (j
= 0; j
< roles_count
; j
++) {
1679 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, j
) == cur_role
) {
1680 /* We ain't be havin' it. */
1681 VTABLE_push_pmc(interp
, roles_list
, cur_role
);
1694 F<include/parrot/oo.h>, F<include/parrot/oo_private.h>,
1695 F<docs/pdds/pdd15_objects.pod>.
1703 * c-file-style: "parrot"
1705 * vim: expandtab shiftwidth=4: