2 Copyright (C) 2007-2009, 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"
27 #include "pmc/pmc_context.h"
31 /* HEADERIZER HFILE: include/parrot/oo.h */
33 /* HEADERIZER BEGIN: static */
34 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
36 PARROT_WARN_UNUSED_RESULT
37 PARROT_CAN_RETURN_NULL
38 static PMC
* C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(2);
42 static void debug_trace_find_meth(PARROT_INTERP
,
43 ARGIN(const PMC
*_class
),
44 ARGIN(const STRING
*name
),
45 ARGIN_NULLOK(const PMC
*sub
))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(2)
48 __attribute__nonnull__(3);
50 static INTVAL
fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
51 __attribute__nonnull__(1)
52 __attribute__nonnull__(2);
54 PARROT_WARN_UNUSED_RESULT
55 PARROT_CAN_RETURN_NULL
56 static PMC
* find_method_direct_1(PARROT_INTERP
,
58 ARGIN(STRING
*method_name
))
59 __attribute__nonnull__(1)
60 __attribute__nonnull__(2)
61 __attribute__nonnull__(3);
64 PARROT_CANNOT_RETURN_NULL
65 PARROT_WARN_UNUSED_RESULT
66 static PMC
* get_pmc_proxy(PARROT_INTERP
, INTVAL type
)
67 __attribute__nonnull__(1);
69 static void invalidate_all_caches(PARROT_INTERP
)
70 __attribute__nonnull__(1);
72 static void invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
73 __attribute__nonnull__(1);
75 #define ASSERT_ARGS_C3_merge __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
76 PARROT_ASSERT_ARG(interp) \
77 , PARROT_ASSERT_ARG(merge_list))
78 #define ASSERT_ARGS_debug_trace_find_meth __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
79 PARROT_ASSERT_ARG(interp) \
80 , PARROT_ASSERT_ARG(_class) \
81 , PARROT_ASSERT_ARG(name))
82 #define ASSERT_ARGS_fail_if_type_exists __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
83 PARROT_ASSERT_ARG(interp) \
84 , PARROT_ASSERT_ARG(name))
85 #define ASSERT_ARGS_find_method_direct_1 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
86 PARROT_ASSERT_ARG(interp) \
87 , PARROT_ASSERT_ARG(_class) \
88 , PARROT_ASSERT_ARG(method_name))
89 #define ASSERT_ARGS_get_pmc_proxy __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
90 PARROT_ASSERT_ARG(interp))
91 #define ASSERT_ARGS_invalidate_all_caches __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
92 PARROT_ASSERT_ARG(interp))
93 #define ASSERT_ARGS_invalidate_type_caches __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
94 PARROT_ASSERT_ARG(interp))
95 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
96 /* HEADERIZER END: static */
100 =item C<void Parrot_oo_extract_methods_from_namespace(PARROT_INTERP, PMC *self,
103 Extract methods and vtable overrides from the given namespace and insert them
111 Parrot_oo_extract_methods_from_namespace(PARROT_INTERP
, ARGIN(PMC
*self
), ARGIN(PMC
*ns
))
113 ASSERT_ARGS(Parrot_oo_extract_methods_from_namespace
)
114 PMC
*methods
, *vtable_overrides
;
116 /* Pull in methods from the namespace, if any. */
120 /* Import any methods. */
121 Parrot_pcc_invoke_method_from_c_args(interp
, ns
, CONST_STRING(interp
, "get_associated_methods"), "->P", &methods
);
123 if (!PMC_IS_NULL(methods
)) {
124 PMC
* const iter
= VTABLE_get_iter(interp
, methods
);
126 while (VTABLE_get_bool(interp
, iter
)) {
127 STRING
* const meth_name
= VTABLE_shift_string(interp
, iter
);
128 PMC
* const meth_sub
= VTABLE_get_pmc_keyed_str(interp
, methods
,
130 VTABLE_add_method(interp
, self
, meth_name
, meth_sub
);
134 /* Import any vtable methods. */
135 Parrot_pcc_invoke_method_from_c_args(interp
, ns
, CONST_STRING(interp
, "get_associated_vtable_methods"), "->P", &vtable_overrides
);
137 if (!PMC_IS_NULL(vtable_overrides
)) {
138 PMC
* const iter
= VTABLE_get_iter(interp
, vtable_overrides
);
139 while (VTABLE_get_bool(interp
, iter
)) {
140 STRING
* const vtable_index_str
= VTABLE_shift_string(interp
, iter
);
141 PMC
* const vtable_sub
= VTABLE_get_pmc_keyed_str(interp
,
142 vtable_overrides
, vtable_index_str
);
144 /* Look up the name of the vtable function from the index. */
145 const INTVAL vtable_index
= Parrot_str_to_int(interp
, vtable_index_str
);
146 const char * const meth_c
= Parrot_vtable_slot_names
[vtable_index
];
147 STRING
* const vtable_name
= Parrot_str_new(interp
, meth_c
, 0);
148 VTABLE_add_vtable_override(interp
, self
, vtable_name
, vtable_sub
);
156 =item C<PMC * Parrot_oo_get_namespace(PARROT_INTERP, const PMC *classobj)>
158 Lookup a namespace object from a class PMC.
160 This function is deprecated, see TT #1069.
161 Use the inspect interface in the Class PMC instead.
167 PARROT_CAN_RETURN_NULL
168 PARROT_WARN_UNUSED_RESULT
170 Parrot_oo_get_namespace(SHIM_INTERP
, ARGIN(const PMC
*classobj
))
172 ASSERT_ARGS(Parrot_oo_get_namespace
)
173 Parrot_Class_attributes
* const _class
= PARROT_CLASS(classobj
);
174 PMC
* const _namespace
= _class
->_namespace
;
176 if (PMC_IS_NULL(_namespace
))
185 =item C<PMC * Parrot_oo_get_class(PARROT_INTERP, PMC *key)>
187 Lookup a class object from a namespace, string, or key PMC.
194 PARROT_CAN_RETURN_NULL
195 PARROT_WARN_UNUSED_RESULT
197 Parrot_oo_get_class(PARROT_INTERP
, ARGIN(PMC
*key
))
199 ASSERT_ARGS(Parrot_oo_get_class
)
200 PMC
*classobj
= PMCNULL
;
202 if (PObj_is_class_TEST(key
))
205 /* Fast select of behavior based on type of the lookup key */
206 switch (key
->vtable
->base_type
) {
207 case enum_class_NameSpace
:
208 classobj
= VTABLE_get_class(interp
, key
);
210 case enum_class_String
:
212 case enum_class_ResizableStringArray
:
214 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
,
215 interp
->HLL_namespace
,
216 Parrot_pcc_get_HLL(interp
, CURRENT_CONTEXT(interp
)));
217 PMC
* const ns
= Parrot_get_namespace_keyed(interp
,
220 if (!PMC_IS_NULL(ns
))
221 classobj
= VTABLE_get_class(interp
, ns
);
228 /* If the PMCProxy doesn't exist yet for the given key, we look up the
229 type ID here and create a new one */
230 if (PMC_IS_NULL(classobj
)) {
232 const INTVAL base_type
= key
->vtable
->base_type
;
234 /* This is a hack! All PMCs should be able to be handled through
235 a single codepath, and all of them should be able to avoid
236 stringification because it's so imprecise. */
237 if (base_type
== enum_class_Key
238 || base_type
== enum_class_ResizableStringArray
239 || base_type
== enum_class_String
)
240 type
= pmc_type_p(interp
, key
);
242 type
= pmc_type(interp
, VTABLE_get_string(interp
, key
));
244 classobj
= get_pmc_proxy(interp
, type
);
252 =item C<PMC * Parrot_oo_clone_object(PARROT_INTERP, PMC *pmc, PMC *class_, PMC
255 Clone an Object PMC. If an existing PMC C<dest> is provided, reuse that
256 PMC to store copies of the data. Otherwise, create a new PMC and populate
263 PARROT_CANNOT_RETURN_NULL
265 Parrot_oo_clone_object(PARROT_INTERP
, ARGIN(PMC
*pmc
),
266 ARGMOD_NULLOK(PMC
*class_
), ARGMOD_NULLOK(PMC
*dest
))
268 ASSERT_ARGS(Parrot_oo_clone_object
)
269 Parrot_Object_attributes
*obj
;
270 Parrot_Object_attributes
*cloned_guts
;
271 Parrot_Class_attributes
*_class
;
276 if (!PMC_IS_NULL(dest
)) {
277 PARROT_ASSERT(!PMC_IS_NULL(class_
));
278 PARROT_ASSERT(class_
->vtable
->base_type
== enum_class_Class
);
279 obj
= PARROT_OBJECT(pmc
);
283 obj
= PARROT_OBJECT(pmc
);
284 cloned
= pmc_new_noinit(interp
, enum_class_Object
);
287 _class
= PARROT_CLASS(obj
->_class
);
288 PARROT_ASSERT(_class
);
289 num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
291 /* Set custom GC mark and destroy on the object. */
292 PObj_custom_mark_SET(cloned
);
293 PObj_custom_destroy_SET(cloned
);
295 /* Flag that it is an object */
296 PObj_is_object_SET(cloned
);
298 /* Now clone attributes list.class. */
299 cloned_guts
= (Parrot_Object_attributes
*) PMC_data(cloned
);
300 cloned_guts
->_class
= obj
->_class
;
301 cloned_guts
->attrib_store
= NULL
;
302 cloned_guts
->attrib_store
= VTABLE_clone(interp
, obj
->attrib_store
);
303 num_attrs
= VTABLE_elements(interp
, cloned_guts
->attrib_store
);
304 for (i
= 0; i
< num_attrs
; i
++) {
305 PMC
* const to_clone
= VTABLE_get_pmc_keyed_int(interp
, cloned_guts
->attrib_store
, i
);
306 if (!PMC_IS_NULL(to_clone
)) {
307 VTABLE_set_pmc_keyed_int(interp
, cloned_guts
->attrib_store
, i
,
308 VTABLE_clone(interp
, to_clone
));
312 /* Some of the attributes may have been the PMCs providing storage for any
313 * PMCs we inherited from; also need to clone those. */
314 if (CLASS_has_alien_parents_TEST(obj
->_class
)) {
315 /* Locate any PMC parents. */
316 for (i
= 0; i
< num_classes
; i
++) {
317 PMC
* const cur_class
= VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, i
);
318 if (cur_class
->vtable
->base_type
== enum_class_PMCProxy
) {
319 /* Clone this PMC too. */
320 STRING
* const proxy
= CONST_STRING(interp
, "proxy");
321 VTABLE_set_attr_keyed(interp
, cloned
, cur_class
, proxy
,
323 VTABLE_get_attr_keyed(interp
, cloned
, cur_class
, proxy
)));
328 /* And we have ourselves a clone. */
334 =item C<static PMC * get_pmc_proxy(PARROT_INTERP, INTVAL type)>
336 Get the PMC proxy for a PMC with the given type, creating it if does not exist.
337 If type is not a valid type, return PMCNULL. This code assumes that
338 all PMCProxy objects live in the 'parrot' HLL namespace -- if/when
339 we allow PMC types to exist in other HLL namespaces, this code will
342 For internal use only.
349 PARROT_CANNOT_RETURN_NULL
350 PARROT_WARN_UNUSED_RESULT
352 get_pmc_proxy(PARROT_INTERP
, INTVAL type
)
354 ASSERT_ARGS(get_pmc_proxy
)
357 /* Check if not a PMC or invalid type number */
358 if (type
> interp
->n_vtable_max
|| type
<= 0)
361 type_class
= interp
->vtables
[type
]->pmc_class
;
362 if (type
!= enum_class_Class
363 && type_class
->vtable
->base_type
== enum_class_Class
) {
367 PMC
* const parrot_hll
= Parrot_get_namespace_keyed_str(interp
, interp
->root_namespace
, CONST_STRING(interp
, "parrot"));
369 Parrot_make_namespace_keyed_str(interp
, parrot_hll
,
370 interp
->vtables
[type
]->whoami
);
371 PMC
* proxy
= VTABLE_get_class(interp
, pmc_ns
);
373 /* Create proxy if not found */
374 if (PMC_IS_NULL(proxy
)) {
375 PMC
* const type_num
= pmc_new(interp
, enum_class_Integer
);
376 VTABLE_set_integer_native(interp
, type_num
, type
);
377 proxy
= pmc_new_init(interp
, enum_class_PMCProxy
, type_num
);
378 Parrot_pcc_invoke_method_from_c_args(interp
, pmc_ns
, CONST_STRING(interp
, "set_class"), "P->", proxy
);
386 =item C<PMC * Parrot_oo_get_class_str(PARROT_INTERP, STRING *name)>
388 Lookup a class object from a builtin string.
395 PARROT_CAN_RETURN_NULL
396 PARROT_WARN_UNUSED_RESULT
398 Parrot_oo_get_class_str(PARROT_INTERP
, ARGIN_NULLOK(STRING
*name
))
400 ASSERT_ARGS(Parrot_oo_get_class_str
)
402 if (STRING_IS_NULL(name
))
406 /* First check in current HLL namespace */
407 PMC
* const hll_ns
= VTABLE_get_pmc_keyed_int(interp
, interp
->HLL_namespace
,
408 Parrot_pcc_get_HLL(interp
, CURRENT_CONTEXT(interp
)));
409 PMC
* const ns
= Parrot_get_namespace_keyed_str(interp
, hll_ns
, name
);
410 PMC
* const _class
= PMC_IS_NULL(ns
)
411 ? PMCNULL
: VTABLE_get_class(interp
, ns
);
413 /* If not found, check for a PMC */
414 if (PMC_IS_NULL(_class
))
415 return get_pmc_proxy(interp
, pmc_type(interp
, name
));
424 =item C<PMC * Parrot_oo_newclass_from_str(PARROT_INTERP, STRING *name)>
426 Create a new class object from a string name.
432 PARROT_CAN_RETURN_NULL
433 PARROT_WARN_UNUSED_RESULT
435 Parrot_oo_newclass_from_str(PARROT_INTERP
, ARGIN(STRING
*name
))
437 ASSERT_ARGS(Parrot_oo_newclass_from_str
)
438 PMC
* const namearg
= pmc_new(interp
, enum_class_String
);
439 PMC
* const namehash
= pmc_new(interp
, enum_class_Hash
);
442 VTABLE_set_string_native(interp
, namearg
, name
);
443 VTABLE_set_pmc_keyed_str(interp
, namehash
, CONST_STRING(interp
, "name"), namearg
);
445 classobj
= pmc_new_init(interp
, enum_class_Class
, namehash
);
447 PARROT_ASSERT(classobj
);
454 =item C<PMC * Parrot_oo_find_vtable_override_for_class(PARROT_INTERP, PMC
455 *classobj, STRING *name)>
457 Lookup a vtable override in a specific class object.
464 PARROT_CAN_RETURN_NULL
465 PARROT_WARN_UNUSED_RESULT
467 Parrot_oo_find_vtable_override_for_class(PARROT_INTERP
,
468 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
470 ASSERT_ARGS(Parrot_oo_find_vtable_override_for_class
)
471 Parrot_Class_attributes
*class_info
;
472 PARROT_ASSERT(PObj_is_class_TEST(classobj
));
474 class_info
= PARROT_CLASS(classobj
);
475 return VTABLE_get_pmc_keyed_str(interp
, class_info
->vtable_overrides
, name
);
481 =item C<PMC * Parrot_oo_find_vtable_override(PARROT_INTERP, PMC *classobj,
484 Lookup a vtable override in a class, including any vtable overrides inherited
492 PARROT_CAN_RETURN_NULL
493 PARROT_WARN_UNUSED_RESULT
495 Parrot_oo_find_vtable_override(PARROT_INTERP
,
496 ARGIN(PMC
*classobj
), ARGIN(STRING
*name
))
498 ASSERT_ARGS(Parrot_oo_find_vtable_override
)
499 Parrot_Class_attributes
* const _class
= PARROT_CLASS(classobj
);
501 VTABLE_get_pmc_keyed_str(interp
, _class
->parent_overrides
, name
);
503 if (PMC_IS_NULL(result
)) {
504 /* Walk and search for the vtable method. */
505 const INTVAL num_classes
= VTABLE_elements(interp
, _class
->all_parents
);
508 for (i
= 0; i
< num_classes
; i
++) {
510 PMC
* const cur_class
=
511 VTABLE_get_pmc_keyed_int(interp
, _class
->all_parents
, i
);
513 result
= Parrot_oo_find_vtable_override_for_class(interp
,
516 if (!PMC_IS_NULL(result
))
519 if (PMC_IS_NULL(result
))
520 result
= pmc_new(interp
, enum_class_Undef
);
521 VTABLE_set_pmc_keyed_str(interp
, _class
->parent_overrides
, name
, result
);
523 if (result
->vtable
->base_type
== enum_class_Undef
)
531 =item C<INTVAL Parrot_get_vtable_index(PARROT_INTERP, const STRING *name)>
533 Return index if C<name> is a valid vtable slot name.
541 Parrot_get_vtable_index(PARROT_INTERP
, ARGIN(const STRING
*name
))
543 ASSERT_ARGS(Parrot_get_vtable_index
)
544 char * const name_c
= Parrot_str_to_cstring(interp
, name
);
546 /* some of the first "slots" don't have names. skip 'em. */
547 INTVAL low
= PARROT_VTABLE_LOW
;
548 INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
551 const INTVAL mid
= (low
+ high
) / 2;
552 const char * const meth_c
= Parrot_vtable_slot_names
[mid
];
554 const INTVAL cmp
= strcmp(name_c
, meth_c
);
557 Parrot_str_free_cstring(name_c
);
566 Parrot_str_free_cstring(name_c
);
574 =item C<const char * Parrot_get_vtable_name(PARROT_INTERP, INTVAL idx)>
576 Return the method name at the specified index in the vtable slot array.
577 Use this function when you cannot access Parrot_vtable_slot_names directly.
585 PARROT_CAN_RETURN_NULL
587 Parrot_get_vtable_name(SHIM_INTERP
, INTVAL idx
)
589 ASSERT_ARGS(Parrot_get_vtable_name
)
591 const INTVAL low
= PARROT_VTABLE_LOW
;
592 const INTVAL high
= NUM_VTABLE_FUNCTIONS
+ PARROT_VTABLE_LOW
;
594 PARROT_ASSERT(idx
> 0);
596 if (idx
< low
|| idx
> high
) {
600 return Parrot_vtable_slot_names
[idx
];
606 =item C<static INTVAL fail_if_type_exists(PARROT_INTERP, PMC *name)>
608 This function throws an exception if a PMC or class with the same name *
609 already exists in the global type registry. The global type registry
610 will go away eventually, but this allows the new object metamodel to
611 interact with the old one until it does.
618 fail_if_type_exists(PARROT_INTERP
, ARGIN(PMC
*name
))
620 ASSERT_ARGS(fail_if_type_exists
)
621 PMC
* const value
= (PMC
*)VTABLE_get_pointer_keyed(interp
, interp
->class_hash
, name
);
623 if (PMC_IS_NULL(value
))
626 switch (VTABLE_type(interp
, value
)) {
627 case enum_class_NameSpace
:
630 case enum_class_Integer
:
632 const INTVAL type
= VTABLE_get_integer(interp
, value
);
633 if (type
< enum_type_undef
) {
634 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
635 "native type with name '%s' already exists - "
636 "can't register Class", data_types
[type
].name
);
642 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INTERP_ERROR
,
643 "Unrecognized class name PMC type");
651 =item C<INTVAL Parrot_oo_register_type(PARROT_INTERP, PMC *name, PMC
654 This function registers a type in the global registry, first checking if it
655 already exists. The global type registry will go away eventually, but this
656 allows the new object metamodel to interact with the old one until it does.
662 PARROT_WARN_UNUSED_RESULT
664 Parrot_oo_register_type(PARROT_INTERP
, ARGIN(PMC
*name
), ARGIN(PMC
*_namespace
))
666 ASSERT_ARGS(Parrot_oo_register_type
)
668 const INTVAL typeid_exists
= fail_if_type_exists(interp
, name
);
670 PMC
* const classobj
= VTABLE_get_class(interp
, _namespace
);
671 if (!PMC_IS_NULL(classobj
)) {
672 STRING
* const classname
= VTABLE_get_string(interp
, _namespace
);
673 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
674 "Class %Ss already registered!\n",
675 Parrot_str_escape(interp
, classname
));
678 /* Type doesn't exist, so go ahead and register it. Lock interpreter so
679 * pt_shared_fixup() can safely do a type lookup. */
680 LOCK_INTERPRETER(interp
);
682 type
= get_new_vtable_index(interp
);
685 if (!typeid_exists
) {
686 PMC
* const classname_hash
= interp
->class_hash
;
687 PMC
* const item
= pmc_new(interp
, enum_class_Integer
);
688 /* set entry in name->type hash */
689 VTABLE_set_integer_native(interp
, item
, type
);
691 VTABLE_set_pmc_keyed(interp
, classname_hash
, name
, item
);
694 UNLOCK_INTERPRETER(interp
);
701 =item C<void mark_object_cache(PARROT_INTERP)>
703 Marks all PMCs in the object method cache as live. This shouldn't strictly be
704 necessary, as they're likely all reachable from namespaces and classes, but
705 it's unlikely to hurt anything except mark phase performance.
711 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
712 #define TBL_SIZE (1 + TBL_SIZE_MASK)
715 mark_object_cache(PARROT_INTERP
)
717 ASSERT_ARGS(mark_object_cache
)
718 Caches
* const mc
= interp
->caches
;
724 for (type
= 0; type
< mc
->mc_size
; type
++) {
728 for (entry
= 0; entry
< TBL_SIZE
; ++entry
) {
729 Meth_cache_entry
*e
= mc
->idx
[type
][entry
];
731 Parrot_gc_mark_PMC_alive(interp
, e
->pmc
);
741 =item C<void init_object_cache(PARROT_INTERP)>
743 Allocate memory for object cache.
750 init_object_cache(PARROT_INTERP
)
752 ASSERT_ARGS(init_object_cache
)
753 Caches
* const mc
= interp
->caches
= mem_allocate_zeroed_typed(Caches
);
760 =item C<void destroy_object_cache(PARROT_INTERP)>
762 Destroy the object cache. Loop over all caches and invalidate them. Then
763 free the caches back to the OS.
770 destroy_object_cache(PARROT_INTERP
)
772 ASSERT_ARGS(destroy_object_cache
)
774 Caches
* const mc
= interp
->caches
;
776 /* mc->idx[type][bits] = e; */
777 for (i
= 0; i
< mc
->mc_size
; i
++) {
779 invalidate_type_caches(interp
, i
);
782 mem_sys_free(mc
->idx
);
789 =item C<static void invalidate_type_caches(PARROT_INTERP, UINTVAL type)>
791 Invalidate the cache of the specified type. Free each entry and then free
799 invalidate_type_caches(PARROT_INTERP
, UINTVAL type
)
801 ASSERT_ARGS(invalidate_type_caches
)
802 Caches
* const mc
= interp
->caches
;
808 /* is it a valid entry */
809 if (type
>= mc
->mc_size
|| !mc
->idx
[type
])
812 for (i
= 0; i
< TBL_SIZE
; ++i
) {
813 Meth_cache_entry
*e
= mc
->idx
[type
][i
];
815 Meth_cache_entry
* const next
= e
->next
;
821 mem_sys_free(mc
->idx
[type
]);
822 mc
->idx
[type
] = NULL
;
828 =item C<static void invalidate_all_caches(PARROT_INTERP)>
830 Invalidate all caches by looping over each cache and calling
831 C<invalidate_type_caches> on them.
838 invalidate_all_caches(PARROT_INTERP
)
840 ASSERT_ARGS(invalidate_all_caches
)
842 for (i
= 1; i
< (UINTVAL
)interp
->n_vtable_max
; ++i
)
843 invalidate_type_caches(interp
, i
);
849 =item C<void Parrot_invalidate_method_cache(PARROT_INTERP, STRING *_class)>
851 Clear method cache for the given class. If class is NULL, caches for
852 all classes are invalidated.
860 Parrot_invalidate_method_cache(PARROT_INTERP
, ARGIN_NULLOK(STRING
*_class
))
862 ASSERT_ARGS(Parrot_invalidate_method_cache
)
865 /* during interp creation and NCI registration the class_hash
867 if (!interp
->class_hash
)
870 if (interp
->resume_flag
& RESUME_INITIAL
)
874 invalidate_all_caches(interp
);
878 type
= pmc_type(interp
, _class
);
881 invalidate_all_caches(interp
);
883 invalidate_type_caches(interp
, (UINTVAL
)type
);
888 =item C<PMC * Parrot_find_method_direct(PARROT_INTERP, PMC *_class, STRING
891 Find a method PMC for a named method, given the class PMC, current
892 interpreter, and name of the method. Don't use a possible method cache.
899 PARROT_CAN_RETURN_NULL
900 PARROT_WARN_UNUSED_RESULT
902 Parrot_find_method_direct(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
904 ASSERT_ARGS(Parrot_find_method_direct
)
905 PMC
* const found
= find_method_direct_1(interp
, _class
, method_name
);
907 if (!PMC_IS_NULL(found
))
911 if (Parrot_str_equal(interp
, method_name
, CONST_STRING(interp
, "__get_string")))
912 return find_method_direct_1(interp
, _class
, CONST_STRING(interp
, "__get_repr"));
920 =item C<PMC * Parrot_find_method_with_cache(PARROT_INTERP, PMC *_class, STRING
923 Find a method PMC for a named method, given the class PMC, current
924 interp, and name of the method.
926 This routine should use the current scope's method cache, if there is
927 one. If not, it creates a new method cache. Or, rather, it will when
928 we've got that bit working. For now it unconditionally goes and looks up
929 the name in the global stash.
936 PARROT_CAN_RETURN_NULL
937 PARROT_WARN_UNUSED_RESULT
939 Parrot_find_method_with_cache(PARROT_INTERP
, ARGIN(PMC
*_class
), ARGIN(STRING
*method_name
))
941 ASSERT_ARGS(Parrot_find_method_with_cache
)
945 Meth_cache_entry
*e
, *old
;
947 PARROT_ASSERT(method_name
!= 0);
949 #if DISABLE_METH_CACHE
950 return Parrot_find_method_direct(interp
, _class
, method_name
);
953 if (! PObj_constant_TEST(method_name
))
954 return Parrot_find_method_direct(interp
, _class
, method_name
);
957 type
= _class
->vtable
->base_type
;
958 bits
= (((UINTVAL
) method_name
->strstart
) >> 2) & TBL_SIZE_MASK
;
960 if (type
>= mc
->mc_size
) {
962 mc
->idx
= (Meth_cache_entry
***)mem_sys_realloc_zeroed(mc
->idx
,
963 sizeof (Meth_cache_entry
***) * (type
+ 1),
964 sizeof (Meth_cache_entry
***) * mc
->mc_size
);
967 mc
->idx
= mem_allocate_n_zeroed_typed(type
+ 1, Meth_cache_entry
**);
969 mc
->mc_size
= type
+ 1;
972 if (mc
->idx
[type
] == NULL
) {
973 mc
->idx
[type
] = (Meth_cache_entry
**)mem_sys_allocate_zeroed(
974 sizeof (Meth_cache_entry
*) * TBL_SIZE
);
977 e
= mc
->idx
[type
][bits
];
980 while (e
&& e
->strstart
!= method_name
->strstart
) {
986 /* when here no or no correct entry was at [bits] */
987 e
= mem_allocate_typed(Meth_cache_entry
);
992 mc
->idx
[type
][bits
] = e
;
994 e
->pmc
= Parrot_find_method_direct(interp
, _class
, method_name
);
996 e
->strstart
= method_name
->strstart
;
1005 =item C<static void debug_trace_find_meth(PARROT_INTERP, const PMC *_class,
1006 const STRING *name, const PMC *sub)>
1008 Print some information about the search for a sub.
1015 # define TRACE_FM(i, c, m, sub)
1017 # define TRACE_FM(i, c, m, sub) \
1018 debug_trace_find_meth((i), (c), (m), (sub))
1021 debug_trace_find_meth(PARROT_INTERP
, ARGIN(const PMC
*_class
),
1022 ARGIN(const STRING
*name
), ARGIN_NULLOK(const PMC
*sub
))
1024 ASSERT_ARGS(debug_trace_find_meth
)
1029 if (!Interp_trace_TEST(interp
, PARROT_TRACE_FIND_METH_FLAG
))
1032 if (PObj_is_class_TEST(_class
)) {
1033 SLOTTYPE
* const class_array
= PMC_data_typed(_class
, SLOTTYPE
*);
1034 PMC
* const class_name_pmc
= get_attrib_num(class_array
, PCD_CLASS_NAME
);
1035 class_name
= VTABLE_get_string(interp
, class_name_pmc
);
1038 class_name
= _class
->vtable
->whoami
;
1041 if (sub
->vtable
->base_type
== enum_class_NCI
)
1049 tracer
= (interp
->pdb
&& interp
->pdb
->debugger
) ?
1050 interp
->pdb
->debugger
:
1052 Parrot_io_eprintf(tracer
, "# find_method class '%Ss' method '%Ss': %s\n",
1053 class_name
, name
, result
);
1061 =item C<static PMC * find_method_direct_1(PARROT_INTERP, PMC *_class, STRING
1064 Find the method with the given name in the specified class.
1070 PARROT_WARN_UNUSED_RESULT
1071 PARROT_CAN_RETURN_NULL
1073 find_method_direct_1(PARROT_INTERP
, ARGIN(PMC
*_class
),
1074 ARGIN(STRING
*method_name
))
1076 ASSERT_ARGS(find_method_direct_1
)
1079 PMC
* const mro
= _class
->vtable
->mro
;
1080 const INTVAL n
= VTABLE_elements(interp
, mro
);
1082 for (i
= 0; i
< n
; ++i
) {
1085 _class
= VTABLE_get_pmc_keyed_int(interp
, mro
, i
);
1086 ns
= VTABLE_get_namespace(interp
, _class
);
1087 method
= VTABLE_get_pmc_keyed_str(interp
, ns
, method_name
);
1089 TRACE_FM(interp
, _class
, method_name
, method
);
1091 if (!PMC_IS_NULL(method
))
1095 TRACE_FM(interp
, _class
, method_name
, NULL
);
1102 =item C<static PMC* C3_merge(PARROT_INTERP, PMC *merge_list)>
1104 Merge together the MRO of the items in the list.
1110 PARROT_WARN_UNUSED_RESULT
1111 PARROT_CAN_RETURN_NULL
1113 C3_merge(PARROT_INTERP
, ARGIN(PMC
*merge_list
))
1115 ASSERT_ARGS(C3_merge
)
1116 PMC
*accepted
= PMCNULL
;
1117 PMC
*result
= PMCNULL
;
1118 const int list_count
= VTABLE_elements(interp
, merge_list
);
1122 /* Try and find something appropriate to add to the MRO - basically, the
1123 * first list head that is not in the tail of all the other lists. */
1124 for (i
= 0; i
< list_count
; i
++) {
1125 PMC
* const cand_list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1131 if (VTABLE_elements(interp
, cand_list
) == 0)
1134 cand_class
= VTABLE_get_pmc_keyed_int(interp
, cand_list
, 0);
1137 for (j
= 0; j
< list_count
; j
++) {
1138 /* Skip the current list. */
1140 /* Is it in the tail? If so, reject. */
1141 PMC
* const check_list
=
1142 VTABLE_get_pmc_keyed_int(interp
, merge_list
, j
);
1144 const int check_length
= VTABLE_elements(interp
, check_list
);
1147 for (k
= 1; k
< check_length
; k
++) {
1148 if (VTABLE_get_pmc_keyed_int(interp
, check_list
, k
) ==
1157 /* If we didn't reject it, this candidate will do. */
1159 accepted
= cand_class
;
1164 /* If we never found any candidates, return an empty list. */
1165 if (cand_count
== 0)
1166 return pmc_new(interp
, enum_class_ResizablePMCArray
);
1168 /* If we didn't find anything to accept, error. */
1169 if (PMC_IS_NULL(accepted
))
1170 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_ILL_INHERIT
,
1171 "Could not build C3 linearization: ambiguous hierarchy");
1173 /* Otherwise, remove what was accepted from the merge lists. */
1174 for (i
= 0; i
< list_count
; i
++) {
1176 PMC
* const list
= VTABLE_get_pmc_keyed_int(interp
, merge_list
, i
);
1177 const INTVAL list_count
= VTABLE_elements(interp
, list
);
1180 for (j
= 0; j
< list_count
; j
++) {
1181 if (VTABLE_get_pmc_keyed_int(interp
, list
, j
) == accepted
) {
1182 VTABLE_delete_keyed_int(interp
, list
, j
);
1188 /* Need to merge what remains of the list, then put what was accepted on
1189 * the start of the list, and we're done. */
1190 result
= C3_merge(interp
, merge_list
);
1191 VTABLE_unshift_pmc(interp
, result
, accepted
);
1199 =item C<PMC* Parrot_ComputeMRO_C3(PARROT_INTERP, PMC *_class)>
1201 Computes the C3 linearization for the given class. C3 is an algorithm to
1202 compute the method resolution order (MRO) of a class that is inheriting
1203 from multiple parent classes (multiple inheritance). C3 was first described
1204 by Barrett et al at:
1206 F<http://192.220.96.201/dylan/linearization-oopsla96.html>
1213 PARROT_WARN_UNUSED_RESULT
1214 PARROT_CAN_RETURN_NULL
1216 Parrot_ComputeMRO_C3(PARROT_INTERP
, ARGIN(PMC
*_class
))
1218 ASSERT_ARGS(Parrot_ComputeMRO_C3
)
1220 PMC
* const immediate_parents
= VTABLE_inspect_str(interp
, _class
, CONST_STRING(interp
, "parents"));
1225 INTVAL parent_count
;
1227 /* Now get immediate parents list. */
1228 if (!immediate_parents
)
1229 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_METHOD_NOT_FOUND
,
1230 "Failed to get parents list from class!");
1232 parent_count
= VTABLE_elements(interp
, immediate_parents
);
1234 if (parent_count
== 0) {
1235 /* No parents - MRO just contains this class. */
1236 result
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1237 VTABLE_push_pmc(interp
, result
, _class
);
1241 /* Otherwise, need to do merge. For that, need linearizations of all of
1242 * our parents added to the merge list. */
1243 merge_list
= PMCNULL
;
1244 for (i
= 0; i
< parent_count
; i
++) {
1245 PMC
* const lin
= Parrot_ComputeMRO_C3(interp
,
1246 VTABLE_get_pmc_keyed_int(interp
, immediate_parents
, i
));
1248 if (PMC_IS_NULL(lin
))
1251 /* instantiated lazily */
1252 if (PMC_IS_NULL(merge_list
))
1253 merge_list
= pmc_new(interp
, enum_class_ResizablePMCArray
);
1255 VTABLE_push_pmc(interp
, merge_list
, lin
);
1258 /* Finally, need list of direct parents on the end of the merge list, then
1260 VTABLE_push_pmc(interp
, merge_list
, immediate_parents
);
1261 result
= C3_merge(interp
, merge_list
);
1263 if (PMC_IS_NULL(result
))
1266 /* Merged result needs this class on the start, and then we're done. */
1267 VTABLE_unshift_pmc(interp
, result
, _class
);
1275 =item C<void Parrot_ComposeRole(PARROT_INTERP, PMC *role, PMC *exclude, int
1276 got_exclude, PMC *alias, int got_alias, PMC *methods_hash, PMC *roles_list)>
1278 Used by the Class and Object PMCs internally to compose a role into either of
1279 them. The C<role> parameter is the role that we are composing into the class
1280 or role. C<methods_hash> is the hash of method names to invokable PMCs that
1281 contains the methods the class or role has. C<roles_list> is the list of roles
1282 the the class or method does.
1284 The C<role> parameter is only dealt with by its external interface. Whether
1285 this routine is usable by any other object system implemented in Parrot very
1286 much depends on how closely the role composition semantics they want are to
1287 the default implementation.
1295 Parrot_ComposeRole(PARROT_INTERP
, ARGIN(PMC
*role
),
1296 ARGIN(PMC
*exclude
), int got_exclude
,
1297 ARGIN(PMC
*alias
), int got_alias
,
1298 ARGIN(PMC
*methods_hash
), ARGIN(PMC
*roles_list
))
1300 ASSERT_ARGS(Parrot_ComposeRole
)
1304 PMC
*proposed_add_methods
;
1306 INTVAL roles_of_role_count
;
1309 /* Check we have not already composed the role; if so, just ignore it. */
1310 INTVAL roles_count
= VTABLE_elements(interp
, roles_list
);
1312 for (i
= 0; i
< roles_count
; i
++)
1313 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, i
) == role
)
1316 /* Get the methods from the role. */
1317 Parrot_pcc_invoke_method_from_c_args(interp
, role
, CONST_STRING(interp
, "methods"), "->P", &methods
);
1319 if (PMC_IS_NULL(methods
))
1322 /* We need to check for conflicts before we do the composition. We
1323 * put each method that would be OK to add into a proposal list, and
1324 * bail out right away if we find a problem. */
1325 proposed_add_methods
= pmc_new(interp
, enum_class_Hash
);
1326 methods_iter
= VTABLE_get_iter(interp
, methods
);
1328 while (VTABLE_get_bool(interp
, methods_iter
)) {
1329 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1330 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
, methods
,
1333 /* Need to find the name we'll check for a conflict on. */
1336 /* Check if it's in the exclude list. */
1338 const int exclude_count
= VTABLE_elements(interp
, exclude
);
1340 for (i
= 0; i
< exclude_count
; i
++) {
1341 const STRING
* const check
=
1342 VTABLE_get_string_keyed_int(interp
, exclude
, i
);
1344 if (Parrot_str_equal(interp
, check
, method_name
)) {
1351 /* If we weren't excluded... */
1353 /* Is there a method with this name already in the class? */
1355 if (VTABLE_exists_keyed_str(interp
, methods_hash
, method_name
)) {
1356 /* Conflicts with something already in the class, unless it's a
1358 PMC
* const cur_entry
= VTABLE_get_pmc_keyed_str(interp
, methods_hash
, method_name
);
1359 if (PMC_IS_NULL(cur_entry
) || !VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub")))
1360 Parrot_ex_throw_from_c_args(interp
, NULL
,
1361 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1362 "A conflict occurred during role composition "
1363 "due to method '%S'.", method_name
);
1366 /* What about a conflict with ourslef? */
1367 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1369 /* Something very weird is going on. */
1370 Parrot_ex_throw_from_c_args(interp
, NULL
,
1371 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1372 "A conflict occurred during role composition;"
1373 " the method '%S' from the role managed to conflict "
1374 "with itself somehow.", method_name
);
1376 /* If we got here, no conflicts! Add method to the "to compose"
1378 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1379 method_name
, cur_method
);
1382 /* Now see if we've got an alias. */
1383 if (got_alias
&& VTABLE_exists_keyed_str(interp
, alias
, method_name
)) {
1384 /* Got one. Get name to alias it to. */
1385 STRING
* const alias_name
= VTABLE_get_string_keyed_str(interp
,
1386 alias
, method_name
);
1388 /* Is there a method with this name already in the class? If it's
1389 * not a multi-method, error. */
1390 if (VTABLE_exists_keyed_str(interp
, methods_hash
, alias_name
)) {
1391 PMC
* const cur_entry
= VTABLE_get_pmc_keyed_str(interp
, methods_hash
, alias_name
);
1392 if (PMC_IS_NULL(cur_entry
) || !VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub")))
1393 /* Conflicts with something already in the class. */
1394 Parrot_ex_throw_from_c_args(interp
, NULL
,
1395 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1396 "A conflict occurred during role composition"
1397 " due to the aliasing of '%S' to '%S'.",
1398 method_name
, alias_name
);
1401 /* What about a conflict with ourslef? */
1402 if (VTABLE_exists_keyed_str(interp
, proposed_add_methods
,
1404 Parrot_ex_throw_from_c_args(interp
, NULL
,
1405 EXCEPTION_ROLE_COMPOSITION_METHOD_CONFLICT
,
1406 "A conflict occurred during role composition"
1407 " due to the aliasing of '%S' to '%S' (role already has"
1408 " a method '%S').", method_name
, alias_name
, alias_name
);
1410 /* If we get here, no conflicts! Add method to the "to compose"
1411 * list with its alias. */
1412 VTABLE_set_pmc_keyed_str(interp
, proposed_add_methods
,
1413 alias_name
, cur_method
);
1417 /* If we get here, we detected no conflicts. Go ahead and compose the
1419 methods_iter
= VTABLE_get_iter(interp
, proposed_add_methods
);
1421 while (VTABLE_get_bool(interp
, methods_iter
)) {
1422 /* Get current method and its name. */
1423 STRING
* const method_name
= VTABLE_shift_string(interp
, methods_iter
);
1424 PMC
* const cur_method
= VTABLE_get_pmc_keyed_str(interp
,
1425 proposed_add_methods
, method_name
);
1427 /* Add it to the methods of the class. */
1428 PMC
* const cur_entry
= VTABLE_get_pmc_keyed_str(interp
, methods_hash
, method_name
);
1429 if (VTABLE_isa(interp
, cur_method
, CONST_STRING(interp
, "MultiSub"))) {
1430 /* The thing we're adding is a multi-sub, but is the thing in the
1431 * class already a multi-sub? */
1432 if (!PMC_IS_NULL(cur_entry
) && VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub"))) {
1433 /* Class already has a multi-sub; need to merge our methods into it. */
1434 const INTVAL num_subs
= VTABLE_elements(interp
, cur_method
);
1436 for (j
= 0; j
< num_subs
; j
++)
1437 VTABLE_push_pmc(interp
, cur_entry
, VTABLE_get_pmc_keyed_int(interp
,
1441 /* It's not, and we didn't conflict so must be no entry. Just stick it in. */
1442 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
1446 /* Are we adding into a multi-sub? */
1447 if (!PMC_IS_NULL(cur_entry
) && VTABLE_isa(interp
, cur_entry
, CONST_STRING(interp
, "MultiSub")))
1448 VTABLE_push_pmc(interp
, cur_entry
, cur_method
);
1450 VTABLE_set_pmc_keyed_str(interp
, methods_hash
, method_name
, cur_method
);
1454 /* Add this role to the roles list. */
1455 VTABLE_push_pmc(interp
, roles_list
, role
);
1458 /* As a result of composing this role, we will also now do the roles
1459 * that it did itself. Note that we already have the correct methods
1460 * as roles "flatten" the methods they get from other roles into their
1461 * own method list. */
1462 Parrot_pcc_invoke_method_from_c_args(interp
, role
, CONST_STRING(interp
, "roles"), "->P", &roles_of_role
);
1463 roles_of_role_count
= VTABLE_elements(interp
, roles_of_role
);
1465 for (i
= 0; i
< roles_of_role_count
; i
++) {
1466 /* Only add if we don't already have it in the list. */
1467 PMC
* const cur_role
= VTABLE_get_pmc_keyed_int(interp
,
1471 for (j
= 0; j
< roles_count
; j
++) {
1472 if (VTABLE_get_pmc_keyed_int(interp
, roles_list
, j
) == cur_role
) {
1473 /* We ain't be havin' it. */
1474 VTABLE_push_pmc(interp
, roles_list
, cur_role
);
1487 F<include/parrot/oo.h>, F<include/parrot/oo_private.h>,
1488 F<docs/pdds/pdd15_objects.pod>.
1496 * c-file-style: "parrot"
1498 * vim: expandtab shiftwidth=4: