2 Copyright (C) 2007-2010, Parrot 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"
26 #include "pmc/pmc_object.h"
30 /* HEADERIZER HFILE: include/parrot/oo.h */
32 /* HEADERIZER BEGIN: static */
33 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
35 PARROT_WARN_UNUSED_RESULT
36 PARROT_CAN_RETURN_NULL
37 static PMC
* C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
38 __attribute__nonnull__(1)
39 __attribute__nonnull__(2);
41 static void debug_trace_find_meth(PARROT_INTERP
,
42 ARGIN(const PMC
*_class
),
43 ARGIN(const STRING
*name
),
44 ARGIN_NULLOK(const PMC
*sub
))
45 __attribute__nonnull__(1)
46 __attribute__nonnull__(2)
47 __attribute__nonnull__(3);
49 static INTVAL
fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
50 __attribute__nonnull__(1)
51 __attribute__nonnull__(2);
53 PARROT_WARN_UNUSED_RESULT
54 PARROT_CAN_RETURN_NULL
55 static PMC
* find_method_direct_1(PARROT_INTERP
,
57 ARGIN(STRING
*method_name
))
58 __attribute__nonnull__(1)
59 __attribute__nonnull__(2)
60 __attribute__nonnull__(3);
63 PARROT_CANNOT_RETURN_NULL
64 PARROT_WARN_UNUSED_RESULT
65 static PMC
* get_pmc_proxy(PARROT_INTERP
, INTVAL type
)
66 __attribute__nonnull__(1);
68 static void invalidate_all_caches(PARROT_INTERP
)
69 __attribute__nonnull__(1);
71 static void invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
72 __attribute__nonnull__(1);
74 #define ASSERT_ARGS_C3_merge __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
75 PARROT_ASSERT_ARG(interp) \
76 , PARROT_ASSERT_ARG(merge_list))
77 #define ASSERT_ARGS_debug_trace_find_meth __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
78 PARROT_ASSERT_ARG(interp) \
79 , PARROT_ASSERT_ARG(_class) \
80 , PARROT_ASSERT_ARG(name))
81 #define ASSERT_ARGS_fail_if_type_exists __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
82 PARROT_ASSERT_ARG(interp) \
83 , PARROT_ASSERT_ARG(name))
84 #define ASSERT_ARGS_find_method_direct_1 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
85 PARROT_ASSERT_ARG(interp) \
86 , PARROT_ASSERT_ARG(_class) \
87 , PARROT_ASSERT_ARG(method_name))
88 #define ASSERT_ARGS_get_pmc_proxy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
89 PARROT_ASSERT_ARG(interp))
90 #define ASSERT_ARGS_invalidate_all_caches __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
91 PARROT_ASSERT_ARG(interp))
92 #define ASSERT_ARGS_invalidate_type_caches __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
93 PARROT_ASSERT_ARG(interp))
94 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
95 /* HEADERIZER END: static */
99 =item C<void Parrot_oo_extract_methods_from_namespace(PARROT_INTERP, PMC *self,
102 Extract methods and vtable overrides from the given namespace and insert them
110 Parrot_oo_extract_methods_from_namespace(PARROT_INTERP
, ARGIN(PMC
*self
), ARGIN(PMC
*ns
))
112 ASSERT_ARGS(Parrot_oo_extract_methods_from_namespace
)
113 PMC
*methods
, *vtable_overrides
;
115 /* Pull in methods from the namespace, if any. */
119 /* Import any methods. */
120 Parrot_pcc_invoke_method_from_c_args(interp
, ns
, CONST_STRING(interp
, "get_associated_methods"), "->P", &methods
);
122 if (!PMC_IS_NULL(methods
)) {
123 PMC
* const iter
= VTABLE_get_iter(interp
, methods
);
125 while (VTABLE_get_bool(interp
, iter
)) {
126 STRING
* const meth_name
= VTABLE_shift_string(interp
, iter
);
127 PMC
* const meth_sub
= VTABLE_get_pmc_keyed_str(interp
, methods
,
129 VTABLE_add_method(interp
, self
, meth_name
, meth_sub
);
133 /* Import any vtables. */
134 Parrot_pcc_invoke_method_from_c_args(interp
, ns
, CONST_STRING(interp
, "get_associated_vtable_methods"), "->P", &vtable_overrides
);
136 if (!PMC_IS_NULL(vtable_overrides
)) {
137 PMC
* const iter
= VTABLE_get_iter(interp
, vtable_overrides
);
138 while (VTABLE_get_bool(interp
, iter
)) {
139 STRING
* const vtable_index_str
= VTABLE_shift_string(interp
, iter
);
140 PMC
* const vtable_sub
= VTABLE_get_pmc_keyed_str(interp
,
141 vtable_overrides
, vtable_index_str
);
143 /* Look up the name of the vtable function from the index. */
144 const INTVAL vtable_index
= Parrot_str_to_int(interp
, vtable_index_str
);
145 const char * const meth_c
= Parrot_vtable_slot_names
[vtable_index
];
146 STRING
* const vtable_name
= Parrot_str_new(interp
, meth_c
, 0);
147 VTABLE_add_vtable_override(interp
, self
, vtable_name
, vtable_sub
);
155 =item C<PMC * Parrot_oo_get_class(PARROT_INTERP, PMC *key)>
157 Lookup a class object from a namespace, string, or key PMC.
159 TODO: This function is terribly inefficient. It needs to be refactored in a
167 PARROT_CAN_RETURN_NULL
168 PARROT_WARN_UNUSED_RESULT
170 Parrot_oo_get_class(PARROT_INTERP
, ARGIN(PMC
*key
))
172 ASSERT_ARGS(Parrot_oo_get_class
)
173 PMC
*classobj
= PMCNULL
;
175 if (PMC_IS_NULL(key
))
178 if (PObj_is_class_TEST(key
))
181 /* Fast select of behavior based on type of the lookup key */
182 switch (key
->vtable
->base_type
) {
183 case enum_class_NameSpace
:
184 classobj
= VTABLE_get_class(interp
, key
);
186 case enum_class_String
:
188 case enum_class_ResizableStringArray
:
190 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
,
191 interp
->HLL_namespace
,
192 Parrot_pcc_get_HLL(interp
, CURRENT_CONTEXT(interp
)));
193 PMC
* const ns
= Parrot_get_namespace_keyed(interp
,
196 if (!PMC_IS_NULL(ns
))
197 classobj
= VTABLE_get_class(interp
, ns
);
204 /* If the PMCProxy doesn't exist yet for the given key, we look up the
205 type ID here and create a new one */
206 if (PMC_IS_NULL(classobj
)) {
208 const INTVAL base_type
= key
->vtable
->base_type
;
210 /* This is a hack! All PMCs should be able to be handled through
211 a single codepath, and all of them should be able to avoid
212 stringification because it's so imprecise. */
213 if (base_type
== enum_class_Key
214 || base_type
== enum_class_ResizableStringArray
215 || base_type
== enum_class_String
)
216 type
= Parrot_pmc_get_type(interp
, key
);
218 type
= Parrot_pmc_get_type_str(interp
, VTABLE_get_string(interp
, key
));
220 classobj
= get_pmc_proxy(interp
, type
);
228 =item C<PMC * Parrot_oo_clone_object(PARROT_INTERP, PMC *pmc, PMC *dest)>
230 Clone an Object PMC. If an existing PMC C<dest> is provided, reuse that
231 PMC to store copies of the data. Otherwise, create a new PMC and populate
238 PARROT_CANNOT_RETURN_NULL
240 Parrot_oo_clone_object(PARROT_INTERP
, ARGIN(PMC
*pmc
), ARGMOD_NULLOK(PMC
*dest
))
242 ASSERT_ARGS(Parrot_oo_clone_object
)
243 Parrot_Object_attributes
*obj
= PARROT_OBJECT(pmc
);
244 Parrot_Object_attributes
*cloned_guts
;
245 Parrot_Class_attributes
*_class
;
250 if (!PMC_IS_NULL(dest
)) {
254 cloned
= Parrot_pmc_new_noinit(interp
, enum_class_Object
);
257 _class
= PARROT_CLASS(obj
->_class
);
258 PARROT_ASSERT(_class
);
259 num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
261 /* Set custom GC mark and destroy on the object. */
262 PObj_custom_mark_SET(cloned
);
263 PObj_custom_destroy_SET(cloned
);
265 /* Flag that it is an object */
266 PObj_is_object_SET(cloned
);
268 /* Now clone attributes list.class. */
269 cloned_guts
= (Parrot_Object_attributes
*) PMC_data(cloned
);
270 cloned_guts
->_class
= obj
->_class
;
271 cloned_guts
->attrib_store
= VTABLE_clone(interp
, obj
->attrib_store
);
272 num_attrs
= VTABLE_elements(interp
, cloned_guts
->attrib_store
);
273 for (i
= 0; i
< num_attrs
; ++i
) {
274 PMC
* const to_clone
= VTABLE_get_pmc_keyed_int(interp
, cloned_guts
->attrib_store
, i
);
275 if (!PMC_IS_NULL(to_clone
)) {
276 VTABLE_set_pmc_keyed_int(interp
, cloned_guts
->attrib_store
, i
,
277 VTABLE_clone(interp
, to_clone
));
281 /* Some of the attributes may have been the PMCs providing storage for any
282 * PMCs we inherited from; also need to clone those. */
283 if (CLASS_has_alien_parents_TEST(obj
->_class
)) {
285 /* Locate any PMC parents. */
286 for (j
= 0; j
< num_classes
; ++j
) {
287 PMC
* const cur_class
= VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, j
);
288 if (cur_class
->vtable
->base_type
== enum_class_PMCProxy
) {
289 /* Clone this PMC too. */
290 STRING
* const proxy
= CONST_STRING(interp
, "proxy");
291 VTABLE_set_attr_keyed(interp
, cloned
, cur_class
, proxy
,
293 VTABLE_get_attr_keyed(interp
, cloned
, cur_class
, proxy
)));
298 /* And we have ourselves a clone. */
304 =item C<static PMC * get_pmc_proxy(PARROT_INTERP, INTVAL type)>
306 Get the PMC proxy for a PMC with the given type, creating it if does not exist.
307 If type is not a valid type, return PMCNULL. This code assumes that
308 all PMCProxy objects live in the 'parrot' HLL namespace -- if/when
309 we allow PMC types to exist in other HLL namespaces, this code will
312 For internal use only.
319 PARROT_CANNOT_RETURN_NULL
320 PARROT_WARN_UNUSED_RESULT
322 get_pmc_proxy(PARROT_INTERP
, INTVAL type
)
324 ASSERT_ARGS(get_pmc_proxy
)
327 /* Check if not a PMC or invalid type number */
328 if (type
> interp
->n_vtable_max
|| type
<= 0)
331 type_class
= interp
->vtables
[type
]->pmc_class
;
332 if (type
!= enum_class_Class
333 && type_class
->vtable
->base_type
== enum_class_Class
) {
337 PMC
* const parrot_hll
= Parrot_get_namespace_keyed_str(interp
, interp
->root_namespace
, CONST_STRING(interp
, "parrot"));
339 Parrot_make_namespace_keyed_str(interp
, parrot_hll
,
340 interp
->vtables
[type
]->whoami
);
341 PMC
* proxy
= VTABLE_get_class(interp
, pmc_ns
);
343 /* Create proxy if not found */
344 if (PMC_IS_NULL(proxy
)) {
345 proxy
= Parrot_pmc_new_init_int(interp
, enum_class_PMCProxy
, type
);
346 Parrot_pcc_invoke_method_from_c_args(interp
, pmc_ns
, CONST_STRING(interp
, "set_class"), "P->", proxy
);
354 =item C<PMC * Parrot_oo_get_class_str(PARROT_INTERP, STRING *name)>
356 Lookup a class object from the string C<name>. If the metaobject is found,
357 return it. Otherwise, create a new PMCProxy for the type ID number.
364 PARROT_CAN_RETURN_NULL
365 PARROT_WARN_UNUSED_RESULT
367 Parrot_oo_get_class_str(PARROT_INTERP
, ARGIN_NULLOK(STRING
*name
))
369 ASSERT_ARGS(Parrot_oo_get_class_str
)
371 if (STRING_IS_NULL(name
))
375 /* First check in current HLL namespace */
376 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
, interp
->HLL_namespace
,
377 Parrot_pcc_get_HLL(interp
, CURRENT_CONTEXT(interp
)));
378 PMC
* const ns
= Parrot_get_namespace_keyed_str(interp
, hll_ns
, name
);
379 PMC
* const _class
= PMC_IS_NULL(ns
)
380 ? PMCNULL
: VTABLE_get_class(interp
, ns
);
382 /* If not found, check for a PMC */
383 if (PMC_IS_NULL(_class
))
384 return get_pmc_proxy(interp
, Parrot_pmc_get_type_str(interp
, name
));
393 =item C<PMC * Parrot_oo_newclass_from_str(PARROT_INTERP, STRING *name)>
395 Create a new Class PMC for a new type of the given C<name>.
401 PARROT_CAN_RETURN_NULL
402 PARROT_WARN_UNUSED_RESULT
404 Parrot_oo_newclass_from_str(PARROT_INTERP
, ARGIN(STRING
*name
))
406 ASSERT_ARGS(Parrot_oo_newclass_from_str
)
407 PMC
* const namearg
= Parrot_pmc_new(interp
, enum_class_String
);
408 PMC
* const namehash
= Parrot_pmc_new(interp
, enum_class_Hash
);
411 VTABLE_set_string_native(interp
, namearg
, name
);
412 VTABLE_set_pmc_keyed_str(interp
, namehash
, CONST_STRING(interp
, "name"), namearg
);
414 classobj
= Parrot_pmc_new_init(interp
, enum_class_Class
, namehash
);
416 PARROT_ASSERT(classobj
);
423 =item C<PMC * Parrot_oo_find_vtable_override_for_class(PARROT_INTERP, PMC
424 *classobj, STRING *name)>
426 Find the vtable override with the specified C<name> in the given C<classobj>
434 PARROT_CAN_RETURN_NULL
435 PARROT_WARN_UNUSED_RESULT
437 Parrot_oo_find_vtable_override_for_class(PARROT_INTERP
,
438 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
440 ASSERT_ARGS(Parrot_oo_find_vtable_override_for_class
)
441 const Parrot_Class_attributes
* const class_info
= PARROT_CLASS(classobj
);;
442 PARROT_ASSERT(PObj_is_class_TEST(classobj
));
444 return VTABLE_get_pmc_keyed_str(interp
, class_info
->vtable_overrides
, name
);
450 =item C<PMC * Parrot_oo_find_vtable_override(PARROT_INTERP, PMC *classobj,
453 Lookup a vtable override in a class, including any vtable overrides inherited
461 PARROT_CAN_RETURN_NULL
462 PARROT_WARN_UNUSED_RESULT
464 Parrot_oo_find_vtable_override(PARROT_INTERP
,
465 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
467 ASSERT_ARGS(Parrot_oo_find_vtable_override
)
468 Parrot_Class_attributes
* const _class
= PARROT_CLASS(classobj
);
470 VTABLE_get_pmc_keyed_str(interp
, _class
->parent_overrides
, name
);
472 if (PMC_IS_NULL(result
)) {
473 /* Walk and search for the vtable. */
474 const INTVAL num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
477 for (i
= 0; i
< num_classes
; ++i
) {
479 PMC
* const cur_class
=
480 VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, i
);
482 result
= Parrot_oo_find_vtable_override_for_class(interp
,
485 if (!PMC_IS_NULL(result
))
488 if (PMC_IS_NULL(result
))
489 result
= Parrot_pmc_new(interp
, enum_class_Undef
);
490 VTABLE_set_pmc_keyed_str(interp
, _class
->parent_overrides
, name
, result
);
492 if (result
->vtable
->base_type
== enum_class_Undef
)
500 =item C<INTVAL Parrot_get_vtable_index(PARROT_INTERP, const STRING *name)>
502 Return index if C<name> is a valid vtable slot name.
510 Parrot_get_vtable_index(PARROT_INTERP
, ARGIN(const STRING
*name
))
512 ASSERT_ARGS(Parrot_get_vtable_index
)
513 char * const name_c
= Parrot_str_to_cstring(interp
, name
);
515 /* some of the first "slots" don't have names. skip 'em. */
516 INTVAL low
= PARROT_VTABLE_LOW
;
517 INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
520 const INTVAL mid
= (low
+ high
) / 2;
521 const char * const meth_c
= Parrot_vtable_slot_names
[mid
];
523 const INTVAL cmp
= strcmp(name_c
, meth_c
);
526 Parrot_str_free_cstring(name_c
);
535 Parrot_str_free_cstring(name_c
);
543 =item C<const char * Parrot_get_vtable_name(PARROT_INTERP, INTVAL idx)>
545 Return the method name at the specified index in the vtable slot array.
546 Use this function when you cannot access Parrot_vtable_slot_names directly.
554 PARROT_CAN_RETURN_NULL
556 Parrot_get_vtable_name(SHIM_INTERP
, INTVAL idx
)
558 ASSERT_ARGS(Parrot_get_vtable_name
)
560 const INTVAL low
= PARROT_VTABLE_LOW
;
561 const INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
563 PARROT_ASSERT(idx
> 0);
565 if (idx
< low
|| idx
> high
) {
569 return Parrot_vtable_slot_names
[idx
];
575 =item C<static INTVAL fail_if_type_exists(PARROT_INTERP, PMC *name)>
577 This function throws an exception if a PMC or class with the same name *
578 already exists in the global type registry. The global type registry
579 will go away eventually, but this allows the new object metamodel to
580 interact with the old one until it does.
587 fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
589 ASSERT_ARGS(fail_if_type_exists
)
590 PMC
* const value
= (PMC
*)VTABLE_get_pointer_keyed(interp
, interp
->class_hash
, name
);
592 if (PMC_IS_NULL(value
))
595 switch (VTABLE_type(interp
, value
)) {
596 case enum_class_NameSpace
:
599 case enum_class_Integer
:
601 const INTVAL type
= VTABLE_get_integer(interp
, value
);
602 if (type
< enum_type_undef
) {
603 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
604 "native type with name '%s' already exists - "
605 "can't register Class", data_types
[type
].name
);
611 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INTERP_ERROR
,
612 "Unrecognized class name PMC type");
620 =item C<INTVAL Parrot_oo_register_type(PARROT_INTERP, PMC *name, PMC
623 This function registers a type in the global registry, first checking if it
624 already exists. The global type registry will go away eventually, but this
625 allows the new object metamodel to interact with the old one until it does.
631 PARROT_WARN_UNUSED_RESULT
633 Parrot_oo_register_type(PARROT_INTERP
, ARGIN(PMC
*name
), ARGIN(PMC
*_namespace
))
635 ASSERT_ARGS(Parrot_oo_register_type
)
637 const INTVAL typeid_exists
= fail_if_type_exists(interp
, name
);
639 PMC
* const classobj
= VTABLE_get_class(interp
, _namespace
);
640 if (!PMC_IS_NULL(classobj
)) {
641 STRING
* const classname
= VTABLE_get_string(interp
, _namespace
);
642 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
643 "Class %Ss already registered!\n",
644 Parrot_str_escape(interp
, classname
));
647 /* Type doesn't exist, so go ahead and register it. Lock interpreter so
648 * pt_shared_fixup() can safely do a type lookup. */
649 LOCK_INTERPRETER(interp
);
651 type
= Parrot_pmc_get_new_vtable_index(interp
);
654 if (!typeid_exists
) {
655 /* set entry in name->type hash */
656 PMC
* const classname_hash
= interp
->class_hash
;
657 PMC
* const item
= Parrot_pmc_new_init_int(interp
,
658 enum_class_Integer
, type
);
659 VTABLE_set_pmc_keyed(interp
, classname_hash
, name
, item
);
662 UNLOCK_INTERPRETER(interp
);
669 =item C<void mark_object_cache(PARROT_INTERP)>
671 Marks all PMCs in the object method cache as live. This shouldn't strictly be
672 necessary, as they're likely all reachable from namespaces and classes, but
673 it's unlikely to hurt anything except mark phase performance.
679 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
680 #define TBL_SIZE (1 + TBL_SIZE_MASK)
683 mark_object_cache(PARROT_INTERP
)
685 ASSERT_ARGS(mark_object_cache
)
686 Caches
* const mc
= interp
->caches
;
692 for (type
= 0; type
< mc
->mc_size
; ++type
) {
696 for (entry
= 0; entry
< TBL_SIZE
; ++entry
) {
697 Meth_cache_entry
*e
= mc
->idx
[type
][entry
];
699 Parrot_gc_mark_PMC_alive(interp
, e
->pmc
);
709 =item C<void init_object_cache(PARROT_INTERP)>
711 Allocate memory for object cache.
718 init_object_cache(PARROT_INTERP
)
720 ASSERT_ARGS(init_object_cache
)
721 Caches
* const mc
= interp
->caches
= mem_gc_allocate_zeroed_typed(interp
, Caches
);
728 =item C<void destroy_object_cache(PARROT_INTERP)>
730 Destroy the object cache. Loop over all caches and invalidate them. Then
731 free the caches back to the OS.
738 destroy_object_cache(PARROT_INTERP
)
740 ASSERT_ARGS(destroy_object_cache
)
742 Caches
* const mc
= interp
->caches
;
744 /* mc->idx[type][bits] = e; */
745 for (i
= 0; i
< mc
->mc_size
; ++i
) {
747 invalidate_type_caches(interp
, i
);
750 mem_gc_free(interp
, mc
->idx
);
751 mem_gc_free(interp
, mc
);
757 =item C<static void invalidate_type_caches(PARROT_INTERP, UINTVAL type)>
759 Invalidate the cache of the specified type. Free each entry and then free
767 invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
769 ASSERT_ARGS(invalidate_type_caches
)
770 Caches
* const mc
= interp
->caches
;
776 /* is it a valid entry */
777 if (type
>= mc
->mc_size
|| !mc
->idx
[type
])
780 for (i
= 0; i
< TBL_SIZE
; ++i
) {
781 Meth_cache_entry
*e
= mc
->idx
[type
][i
];
783 Meth_cache_entry
* const next
= e
->next
;
784 mem_gc_free(interp
, e
);
789 mem_gc_free(interp
, mc
->idx
[type
]);
790 mc
->idx
[type
] = NULL
;
796 =item C<static void invalidate_all_caches(PARROT_INTERP)>
798 Invalidate all caches by looping over each cache and calling
799 C<invalidate_type_caches> on them.
806 invalidate_all_caches(PARROT_INTERP
)
808 ASSERT_ARGS(invalidate_all_caches
)
810 for (i
= 1; i
< interp
->n_vtable_max
; ++i
)
811 invalidate_type_caches(interp
, i
);
817 =item C<void Parrot_invalidate_method_cache(PARROT_INTERP, STRING *_class)>
819 Clear method cache for the given class. If class is NULL, caches for
820 all classes are invalidated.
828 Parrot_invalidate_method_cache(PARROT_INTERP
, ARGIN_NULLOK(STRING
*_class
))
830 ASSERT_ARGS(Parrot_invalidate_method_cache
)
833 /* during interp creation and NCI registration the class_hash
835 if (!interp
->class_hash
)
838 if (interp
->resume_flag
& RESUME_INITIAL
)
842 invalidate_all_caches(interp
);
846 type
= Parrot_pmc_get_type_str(interp
, _class
);
849 invalidate_all_caches(interp
);
851 invalidate_type_caches(interp
, (UINTVAL
)type
);
856 =item C<PMC * Parrot_find_method_direct(PARROT_INTERP, PMC *_class, STRING
859 Find a method PMC for a named method, given the class PMC, current
860 interpreter, and name of the method. Don't use a possible method cache.
867 PARROT_CAN_RETURN_NULL
868 PARROT_WARN_UNUSED_RESULT
870 Parrot_find_method_direct(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
872 ASSERT_ARGS(Parrot_find_method_direct
)
873 PMC
* const found
= find_method_direct_1(interp
, _class
, method_name
);
875 if (!PMC_IS_NULL(found
))
879 if (Parrot_str_equal(interp
, method_name
, CONST_STRING(interp
, "__get_string")))
880 return find_method_direct_1(interp
, _class
, CONST_STRING(interp
, "__get_repr"));
888 =item C<PMC * Parrot_find_method_with_cache(PARROT_INTERP, PMC *_class, STRING
891 Find a method PMC for a named method, given the class PMC, current
892 interp, and name of the method.
894 This routine should use the current scope's method cache, if there is
895 one. If not, it creates a new method cache. Or, rather, it will when
896 we've got that bit working. For now it unconditionally goes and looks up
897 the name in the global stash.
904 PARROT_CAN_RETURN_NULL
905 PARROT_WARN_UNUSED_RESULT
907 Parrot_find_method_with_cache(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
909 ASSERT_ARGS(Parrot_find_method_with_cache
)
915 PARROT_ASSERT(method_name
!= 0);
917 #if DISABLE_METH_CACHE
918 return Parrot_find_method_direct(interp
, _class
, method_name
);
921 if (! PObj_constant_TEST(method_name
))
922 return Parrot_find_method_direct(interp
, _class
, method_name
);
925 type
= _class
->vtable
->base_type
;
926 bits
= (((UINTVAL
) Buffer_bufstart(method_name
)) >> 2) & TBL_SIZE_MASK
;
928 if (type
>= mc
->mc_size
) {
930 mc
->idx
= mem_gc_realloc_n_typed_zeroed(interp
, mc
->idx
,
931 type
+ 1, mc
->mc_size
, Meth_cache_entry
**);
934 mc
->idx
= mem_gc_allocate_n_zeroed_typed(interp
, type
+ 1, Meth_cache_entry
**);
936 mc
->mc_size
= type
+ 1;
939 if (mc
->idx
[type
] == NULL
) {
940 mc
->idx
[type
] = mem_gc_allocate_n_zeroed_typed(interp
,
941 TBL_SIZE
, Meth_cache_entry
*);
944 e
= mc
->idx
[type
][bits
];
946 while (e
&& e
->strstart
!= Buffer_bufstart(method_name
)) {
951 /* when here no or no correct entry was at [bits] */
952 /* Use zeroed allocation because find_method_direct can trigger GC */
953 e
= mem_gc_allocate_zeroed_typed(interp
, Meth_cache_entry
);
955 mc
->idx
[type
][bits
] = e
;
957 e
->pmc
= Parrot_find_method_direct(interp
, _class
, method_name
);
959 e
->strstart
= Buffer_bufstart(method_name
);
970 =item C<static void debug_trace_find_meth(PARROT_INTERP, const PMC *_class,
971 const STRING *name, const PMC *sub)>
973 Print some information about the search for a sub.
980 # define TRACE_FM(i, c, m, sub)
982 # define TRACE_FM(i, c, m, sub) \
983 debug_trace_find_meth((i), (c), (m), (sub))
986 debug_trace_find_meth(PARROT_INTERP
, ARGIN(const PMC
*_class
),
987 ARGIN(const STRING
*name
), ARGIN_NULLOK(const PMC
*sub
))
989 ASSERT_ARGS(debug_trace_find_meth
)
994 if (!Interp_trace_TEST(interp
, PARROT_TRACE_FIND_METH_FLAG
))
997 if (PObj_is_class_TEST(_class
)) {
998 SLOTTYPE
* const class_array
= PMC_data_typed(_class
, SLOTTYPE
*);
999 PMC
* const class_name_pmc
= get_attrib_num(class_array
, PCD_CLASS_NAME
);
1000 class_name
= VTABLE_get_string(interp
, class_name_pmc
);
1003 class_name
= _class
->vtable
->whoami
;
1006 if (sub
->vtable
->base_type
== enum_class_NCI
)
1014 tracer
= (interp
->pdb
&& interp
->pdb
->debugger
) ?
1015 interp
->pdb
->debugger
:
1017 Parrot_io_eprintf(tracer
, "# find_method class '%Ss' method '%Ss': %s\n",
1018 class_name
, name
, result
);
1026 =item C<static PMC * find_method_direct_1(PARROT_INTERP, PMC *_class, STRING
1029 Find the method with the given name in the specified class.
1035 PARROT_WARN_UNUSED_RESULT
1036 PARROT_CAN_RETURN_NULL
1038 find_method_direct_1(PARROT_INTERP
, ARGIN(PMC
*_class
),
1039 ARGIN(STRING
*method_name
))
1041 ASSERT_ARGS(find_method_direct_1
)
1044 PMC
* const mro
= _class
->vtable
->mro
;
1045 const INTVAL n
= VTABLE_elements(interp
, mro
);
1046 STRING
* const methods_str
= CONST_STRING(interp
, "methods");
1047 STRING
* const class_str
= CONST_STRING(interp
, "class");
1049 for (i
= 0; i
< n
; ++i
) {
1050 PMC
* const _class
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
1051 PMC
* const ns
= VTABLE_get_namespace(interp
, _class
);
1052 PMC
* const class_obj
= VTABLE_inspect_str(interp
, ns
, class_str
);
1053 PMC
*method
= PMCNULL
;
1056 if (PMC_IS_NULL(class_obj
))
1057 method_hash
= VTABLE_inspect_str(interp
, ns
, methods_str
);
1059 method_hash
= VTABLE_inspect_str(interp
, class_obj
, methods_str
);
1061 if (!PMC_IS_NULL(method_hash
))
1062 method
= VTABLE_get_pmc_keyed_str(interp
, method_hash
, method_name
);
1064 if (PMC_IS_NULL(method
))
1065 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, method_name
);
1067 TRACE_FM(interp
, _class
, method_name
, method
);
1069 if (!PMC_IS_NULL(method
))
1073 TRACE_FM(interp
, _class
, method_name
, NULL
);
1080 =item C<static PMC* C3_merge(PARROT_INTERP, PMC *merge_list)>
1082 Merge together the MRO of the items in the list.
1088 PARROT_WARN_UNUSED_RESULT
1089 PARROT_CAN_RETURN_NULL
1091 C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
1093 ASSERT_ARGS(C3_merge
)
1094 PMC
*accepted
= PMCNULL
;
1095 PMC
*result
= PMCNULL
;
1096 const int list_count
= VTABLE_elements(interp
, merge_list
);
1100 /* Try and find something appropriate to add to the MRO - basically, the
1101 * first list head that is not in the tail of all the other lists. */
1102 for (i
= 0; i
< list_count
; ++i
) {
1103 PMC
* const cand_list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1109 if (VTABLE_elements(interp
, cand_list
) == 0)
1112 cand_class
= VTABLE_get_pmc_keyed_int(interp
, cand_list
, 0);
1115 for (j
= 0; j
< list_count
; ++j
) {
1116 /* Skip the current list. */
1118 /* Is it in the tail? If so, reject. */
1119 PMC
* const check_list
=
1120 VTABLE_get_pmc_keyed_int(interp
, merge_list
, j
);
1122 const int check_length
= VTABLE_elements(interp
, check_list
);
1125 for (k
= 1; k
< check_length
; ++k
) {
1126 if (VTABLE_get_pmc_keyed_int(interp
, check_list
, k
) ==
1135 /* If we didn't reject it, this candidate will do. */
1137 accepted
= cand_class
;
1142 /* If we never found any candidates, return an empty list. */
1143 if (cand_count
== 0)
1144 return Parrot_pmc_new(interp
, enum_class_ResizablePMCArray
);
1146 /* If we didn't find anything to accept, error. */
1147 if (PMC_IS_NULL(accepted
))
1148 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_ILL_INHERIT
,
1149 "Could not build C3 linearization: ambiguous hierarchy");
1151 /* Otherwise, remove what was accepted from the merge lists. */
1152 for (i
= 0; i
< list_count
; ++i
) {
1154 PMC
* const list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1155 const INTVAL sublist_count
= VTABLE_elements(interp
, list
);
1158 for (j
= 0; j
< sublist_count
; ++j
) {
1159 if (VTABLE_get_pmc_keyed_int(interp
, list
, j
) == accepted
) {
1160 VTABLE_delete_keyed_int(interp
, list
, j
);
1166 /* Need to merge what remains of the list, then put what was accepted on
1167 * the start of the list, and we're done. */
1168 result
= C3_merge(interp
, merge_list
);
1169 VTABLE_unshift_pmc(interp
, result
, accepted
);
1177 =item C<PMC* Parrot_ComputeMRO_C3(PARROT_INTERP, PMC *_class)>
1179 Computes the C3 linearization for the given class. C3 is an algorithm to
1180 compute the method resolution order (MRO) of a class that is inheriting
1181 from multiple parent classes (multiple inheritance). C3 was first described
1182 by Barrett et al at:
1184 F<http://192.220.96.201/dylan/linearization-oopsla96.html>
1191 PARROT_WARN_UNUSED_RESULT
1192 PARROT_CAN_RETURN_NULL
1194 Parrot_ComputeMRO_C3(PARROT_INTERP
, ARGIN(PMC
*_class
))
1196 ASSERT_ARGS(Parrot_ComputeMRO_C3
)
1198 PMC
* const immediate_parents
= VTABLE_inspect_str(interp
, _class
, CONST_STRING(interp
, "parents"));
1203 INTVAL parent_count
;
1205 /* Now get immediate parents list. */
1206 if (PMC_IS_NULL(immediate_parents
))
1207 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_METHOD_NOT_FOUND
,
1208 "Failed to get parents list from class!");
1210 parent_count
= VTABLE_elements(interp
, immediate_parents
);
1212 if (parent_count
== 0) {
1213 /* No parents - MRO just contains this class. */
1214 result
= Parrot_pmc_new(interp
, enum_class_ResizablePMCArray
);
1215 VTABLE_push_pmc(interp
, result
, _class
);
1219 /* Otherwise, need to do merge. For that, need linearizations of all of
1220 * our parents added to the merge list. */
1221 merge_list
= PMCNULL
;
1222 for (i
= 0; i
< parent_count
; ++i
) {
1223 PMC
* const lin
= Parrot_ComputeMRO_C3(interp
,
1224 VTABLE_get_pmc_keyed_int(interp
, immediate_parents
, i
));
1226 if (PMC_IS_NULL(lin
))
1229 /* instantiated lazily */
1230 if (PMC_IS_NULL(merge_list
))
1231 merge_list
= Parrot_pmc_new(interp
, enum_class_ResizablePMCArray
);
1233 VTABLE_push_pmc(interp
, merge_list
, lin
);
1236 /* Finally, need list of direct parents on the end of the merge list, then
1238 VTABLE_push_pmc(interp
, merge_list
, immediate_parents
);
1239 result
= C3_merge(interp
, merge_list
);
1241 if (PMC_IS_NULL(result
))
1244 /* Merged result needs this class on the start, and then we're done. */
1245 VTABLE_unshift_pmc(interp
, result
, _class
);
1253 =item C<void Parrot_ComposeRole(PARROT_INTERP, PMC *role, PMC *exclude, int
1254 got_exclude, PMC *alias, int got_alias, PMC *methods_hash, PMC *roles_list)>
1256 Used by the Class and Object PMCs internally to compose a role into either of
1257 them. The C<role> parameter is the role that we are composing into the class
1258 or role. C<methods_hash> is the hash of method names to invokable PMCs that
1259 contains the methods the class or role has. C<roles_list> is the list of roles
1260 the the class or method does.
1262 The C<role> parameter is only dealt with by its external interface. Whether
1263 this routine is usable by any other object system implemented in Parrot very
1264 much depends on how closely the role composition semantics they want are to
1265 the default implementation.
1273 Parrot_ComposeRole(PARROT_INTERP
, ARGIN(PMC
*role
),
1274 ARGIN(PMC
*exclude
), int got_exclude
,
1275 ARGIN(PMC
*alias
), int got_alias
,
1276 ARGIN(PMC
*methods_hash
), ARGIN(PMC
*roles_list
))
1278 ASSERT_ARGS(Parrot_ComposeRole
)
1282 PMC
*proposed_add_methods
;
1284 INTVAL roles_of_role_count
;
1287 /* Check we have not already composed the role; if so, just ignore it. */
1288 INTVAL roles_count
= VTABLE_elements(interp
, roles_list
);
1290 for (i
= 0; i
< roles_count
; ++i
)
1291 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, i
) == role
)
1294 /* Get the methods from the role. */
1295 Parrot_pcc_invoke_method_from_c_args(interp
, role
, CONST_STRING(interp
, "methods"), "->P", &methods
);
1297 if (PMC_IS_NULL(methods
))
1300 /* We need to check for conflicts before we do the composition. We
1301 * put each method that would be OK to add into a proposal list, and
1302 * bail out right away if we find a problem. */
1303 proposed_add_methods
= Parrot_pmc_new(interp
, enum_class_Hash
);
1304 methods_iter
= VTABLE_get_iter(interp
, methods
);
1306 while (VTABLE_get_bool(interp
, methods_iter
)) {
1307 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1308 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
, methods
,
1311 /* Need to find the name we'll check for a conflict on. */
1314 /* Check if it's in the exclude list. */
1316 const int exclude_count
= VTABLE_elements(interp
, exclude
);
1318 for (i
= 0; i
< exclude_count
; ++i
) {
1319 const STRING
* const check
=
1320 VTABLE_get_string_keyed_int(interp
, exclude
, i
);
1322 if (Parrot_str_equal(interp
, check
, method_name
)) {
1329 /* If we weren't excluded... */
1331 /* Is there a method with this name already in the class? */
1333 if (VTABLE_exists_keyed_str(interp
, methods_hash
, method_name
)) {
1334 /* Conflicts with something already in the class, unless it's a
1336 PMC
* const cur_entry
= VTABLE_get_pmc_keyed_str(interp
, methods_hash
, method_name
);
1337 if (PMC_IS_NULL(cur_entry
) || !VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub")))
1338 Parrot_ex_throw_from_c_args(interp
, NULL
,
1339 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1340 "A conflict occurred during role composition "
1341 "due to method '%S'.", method_name
);
1344 /* What about a conflict with ourslef? */
1345 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1347 /* Something very weird is going on. */
1348 Parrot_ex_throw_from_c_args(interp
, NULL
,
1349 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1350 "A conflict occurred during role composition;"
1351 " the method '%S' from the role managed to conflict "
1352 "with itself somehow.", method_name
);
1354 /* If we got here, no conflicts! Add method to the "to compose"
1356 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1357 method_name
, cur_method
);
1360 /* Now see if we've got an alias. */
1361 if (got_alias
&& VTABLE_exists_keyed_str(interp
, alias
, method_name
)) {
1362 /* Got one. Get name to alias it to. */
1363 STRING
* const alias_name
= VTABLE_get_string_keyed_str(interp
,
1364 alias
, method_name
);
1366 /* Is there a method with this name already in the class? If it's
1367 * not a multi-method, error. */
1368 if (VTABLE_exists_keyed_str(interp
, methods_hash
, alias_name
)) {
1369 PMC
* const cur_entry
= VTABLE_get_pmc_keyed_str(interp
, methods_hash
, alias_name
);
1370 if (PMC_IS_NULL(cur_entry
) || !VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub")))
1371 /* Conflicts with something already in the class. */
1372 Parrot_ex_throw_from_c_args(interp
, NULL
,
1373 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1374 "A conflict occurred during role composition"
1375 " due to the aliasing of '%S' to '%S'.",
1376 method_name
, alias_name
);
1379 /* What about a conflict with ourslef? */
1380 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1382 Parrot_ex_throw_from_c_args(interp
, NULL
,
1383 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1384 "A conflict occurred during role composition"
1385 " due to the aliasing of '%S' to '%S' (role already has"
1386 " a method '%S').", method_name
, alias_name
, alias_name
);
1388 /* If we get here, no conflicts! Add method to the "to compose"
1389 * list with its alias. */
1390 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1391 alias_name
, cur_method
);
1395 /* If we get here, we detected no conflicts. Go ahead and compose the
1397 methods_iter
= VTABLE_get_iter(interp
, proposed_add_methods
);
1399 while (VTABLE_get_bool(interp
, methods_iter
)) {
1400 /* Get current method and its name. */
1401 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1402 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
,
1403 proposed_add_methods
, method_name
);
1405 /* Add it to the methods of the class. */
1406 PMC
* const cur_entry
= VTABLE_get_pmc_keyed_str(interp
, methods_hash
, method_name
);
1407 if (VTABLE_isa(interp
, cur_method
, CONST_STRING(interp
, "MultiSub"))) {
1408 /* The thing we're adding is a multi-sub, but is the thing in the
1409 * class already a multi-sub? */
1410 if (!PMC_IS_NULL(cur_entry
) && VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub"))) {
1411 /* Class already has a multi-sub; need to merge our methods into it. */
1412 const INTVAL num_subs
= VTABLE_elements(interp
, cur_method
);
1414 for (j
= 0; j
< num_subs
; ++j
)
1415 VTABLE_push_pmc(interp
, cur_entry
, VTABLE_get_pmc_keyed_int(interp
,
1419 /* It's not, and we didn't conflict so must be no entry. Just stick it in. */
1420 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
1424 /* Are we adding into a multi-sub? */
1425 if (!PMC_IS_NULL(cur_entry
) && VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub")))
1426 VTABLE_push_pmc(interp
, cur_entry
, cur_method
);
1428 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
1432 /* Add this role to the roles list. */
1433 VTABLE_push_pmc(interp
, roles_list
, role
);
1436 /* As a result of composing this role, we will also now do the roles
1437 * that it did itself. Note that we already have the correct methods
1438 * as roles "flatten" the methods they get from other roles into their
1439 * own method list. */
1440 Parrot_pcc_invoke_method_from_c_args(interp
, role
, CONST_STRING(interp
, "roles"), "->P", &roles_of_role
);
1441 roles_of_role_count
= VTABLE_elements(interp
, roles_of_role
);
1443 for (i
= 0; i
< roles_of_role_count
; ++i
) {
1444 /* Only add if we don't already have it in the list. */
1445 PMC
* const cur_role
= VTABLE_get_pmc_keyed_int(interp
,
1449 for (j
= 0; j
< roles_count
; ++j
) {
1450 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, j
) == cur_role
) {
1451 /* We ain't be havin' it. */
1452 VTABLE_push_pmc(interp
, roles_list
, cur_role
);
1465 F<include/parrot/oo.h>, F<include/parrot/oo_private.h>,
1466 F<docs/pdds/pdd15_objects.pod>.
1474 * c-file-style: "parrot"
1476 * vim: expandtab shiftwidth=4: