[t][cage] Remove PGE-dependence from t/op/inf_nan.t since it is part of 'make coretest'
[parrot.git] / src / oo.c
blobb798855af7a7e65e6f888ff5ff2194078c7fc819
1 /*
2 Copyright (C) 2007-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 oo.c - Class and object
9 =head1 DESCRIPTION
11 Handles class and object manipulation.
13 =head2 Functions
15 =over 4
17 =cut
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"
29 #include "oo.str"
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,
57 ARGIN(PMC *_class),
58 ARGIN(STRING *method_name))
59 __attribute__nonnull__(1)
60 __attribute__nonnull__(2)
61 __attribute__nonnull__(3);
63 PARROT_INLINE
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,
101 PMC *ns)>
103 Extract methods and vtable overrides from the given namespace and insert them
104 into the class.
106 =cut
110 void
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. */
117 if (PMC_IS_NULL(ns))
118 return;
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,
129 meth_name);
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.
163 =cut
167 PARROT_CAN_RETURN_NULL
168 PARROT_WARN_UNUSED_RESULT
169 PMC *
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))
177 return PMCNULL;
179 return _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.
189 =cut
193 PARROT_EXPORT
194 PARROT_CAN_RETURN_NULL
195 PARROT_WARN_UNUSED_RESULT
196 PMC *
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))
203 classobj = key;
204 else {
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);
209 break;
210 case enum_class_String:
211 case enum_class_Key:
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,
218 hll_ns, key);
220 if (!PMC_IS_NULL(ns))
221 classobj = VTABLE_get_class(interp, ns);
223 default:
224 break;
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)) {
231 INTVAL type;
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);
241 else
242 type = pmc_type(interp, VTABLE_get_string(interp, key));
244 classobj = get_pmc_proxy(interp, type);
247 return classobj;
252 =item C<PMC * Parrot_oo_clone_object(PARROT_INTERP, PMC *pmc, PMC *class_, PMC
253 *dest)>
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
257 that with the data.
259 =cut
263 PARROT_CANNOT_RETURN_NULL
264 PMC *
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;
272 PMC *cloned;
273 INTVAL num_classes;
274 INTVAL i, num_attrs;
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);
280 cloned = dest;
282 else {
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,
322 VTABLE_clone(interp,
323 VTABLE_get_attr_keyed(interp, cloned, cur_class, proxy)));
328 /* And we have ourselves a clone. */
329 return cloned;
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
340 need to be updated.
342 For internal use only.
344 =cut
348 PARROT_INLINE
349 PARROT_CANNOT_RETURN_NULL
350 PARROT_WARN_UNUSED_RESULT
351 static PMC *
352 get_pmc_proxy(PARROT_INTERP, INTVAL type)
354 ASSERT_ARGS(get_pmc_proxy)
355 PMC * type_class;
357 /* Check if not a PMC or invalid type number */
358 if (type > interp->n_vtable_max || type <= 0)
359 return PMCNULL;
361 type_class = interp->vtables[type]->pmc_class;
362 if (type != enum_class_Class
363 && type_class->vtable->base_type == enum_class_Class) {
364 return type_class;
366 else {
367 PMC * const parrot_hll = Parrot_get_namespace_keyed_str(interp, interp->root_namespace, CONST_STRING(interp, "parrot"));
368 PMC * const pmc_ns =
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);
380 return proxy;
386 =item C<PMC * Parrot_oo_get_class_str(PARROT_INTERP, STRING *name)>
388 Lookup a class object from a builtin string.
390 =cut
394 PARROT_EXPORT
395 PARROT_CAN_RETURN_NULL
396 PARROT_WARN_UNUSED_RESULT
397 PMC *
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))
403 return PMCNULL;
404 else {
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));
416 else
417 return _class;
424 =item C<PMC * Parrot_oo_newclass_from_str(PARROT_INTERP, STRING *name)>
426 Create a new class object from a string name.
428 =cut
432 PARROT_CAN_RETURN_NULL
433 PARROT_WARN_UNUSED_RESULT
434 PMC *
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);
440 PMC *classobj;
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);
448 return 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.
459 =cut
463 PARROT_EXPORT
464 PARROT_CAN_RETURN_NULL
465 PARROT_WARN_UNUSED_RESULT
466 PMC *
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,
482 STRING *name)>
484 Lookup a vtable override in a class, including any vtable overrides inherited
485 from parents.
487 =cut
491 PARROT_EXPORT
492 PARROT_CAN_RETURN_NULL
493 PARROT_WARN_UNUSED_RESULT
494 PMC *
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);
500 PMC *result =
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);
506 INTVAL i;
508 for (i = 0; i < num_classes; i++) {
509 /* Get the class. */
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,
514 cur_class, name);
516 if (!PMC_IS_NULL(result))
517 break;
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)
524 result = PMCNULL;
525 return result;
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.
535 =cut
539 PARROT_EXPORT
540 INTVAL
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;
550 while (low < high) {
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);
556 if (cmp == 0) {
557 Parrot_str_free_cstring(name_c);
558 return mid;
560 else if (cmp > 0)
561 low = mid + 1;
562 else
563 high = mid;
566 Parrot_str_free_cstring(name_c);
568 return -1;
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.
579 =cut
583 PARROT_EXPORT
584 PARROT_PURE_FUNCTION
585 PARROT_CAN_RETURN_NULL
586 const char *
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) {
597 return NULL;
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.
613 =cut
617 static INTVAL
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))
624 return 0;
626 switch (VTABLE_type(interp, value)) {
627 case enum_class_NameSpace:
628 return 0;
629 break;
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);
638 return type;
640 break;
641 default:
642 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INTERP_ERROR,
643 "Unrecognized class name PMC type");
644 break;
651 =item C<INTVAL Parrot_oo_register_type(PARROT_INTERP, PMC *name, PMC
652 *_namespace)>
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.
658 =cut
662 PARROT_WARN_UNUSED_RESULT
663 INTVAL
664 Parrot_oo_register_type(PARROT_INTERP, ARGIN(PMC *name), ARGIN(PMC *_namespace))
666 ASSERT_ARGS(Parrot_oo_register_type)
667 INTVAL 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);
696 return type;
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.
707 =cut
711 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
712 #define TBL_SIZE (1 + TBL_SIZE_MASK)
714 void
715 mark_object_cache(PARROT_INTERP)
717 ASSERT_ARGS(mark_object_cache)
718 Caches * const mc = interp->caches;
719 UINTVAL type, entry;
721 if (!mc)
722 return;
724 for (type = 0; type < mc->mc_size; type++) {
725 if (!mc->idx[type])
726 continue;
728 for (entry = 0; entry < TBL_SIZE; ++entry) {
729 Meth_cache_entry *e = mc->idx[type][entry];
730 while (e) {
731 Parrot_gc_mark_PMC_alive(interp, e->pmc);
732 e = e->next;
741 =item C<void init_object_cache(PARROT_INTERP)>
743 Allocate memory for object cache.
745 =cut
749 void
750 init_object_cache(PARROT_INTERP)
752 ASSERT_ARGS(init_object_cache)
753 Caches * const mc = interp->caches = mem_allocate_zeroed_typed(Caches);
754 mc->idx = NULL;
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.
765 =cut
769 void
770 destroy_object_cache(PARROT_INTERP)
772 ASSERT_ARGS(destroy_object_cache)
773 UINTVAL i;
774 Caches * const mc = interp->caches;
776 /* mc->idx[type][bits] = e; */
777 for (i = 0; i < mc->mc_size; i++) {
778 if (mc->idx[i])
779 invalidate_type_caches(interp, i);
782 mem_sys_free(mc->idx);
783 mem_sys_free(mc);
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
792 the entire cache.
794 =cut
798 static void
799 invalidate_type_caches(PARROT_INTERP, UINTVAL type)
801 ASSERT_ARGS(invalidate_type_caches)
802 Caches * const mc = interp->caches;
803 INTVAL i;
805 if (!mc)
806 return;
808 /* is it a valid entry */
809 if (type >= mc->mc_size || !mc->idx[type])
810 return;
812 for (i = 0; i < TBL_SIZE; ++i) {
813 Meth_cache_entry *e = mc->idx[type][i];
814 while (e) {
815 Meth_cache_entry * const next = e->next;
816 mem_sys_free(e);
817 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.
833 =cut
837 static void
838 invalidate_all_caches(PARROT_INTERP)
840 ASSERT_ARGS(invalidate_all_caches)
841 UINTVAL i;
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.
854 =cut
858 PARROT_EXPORT
859 void
860 Parrot_invalidate_method_cache(PARROT_INTERP, ARGIN_NULLOK(STRING *_class))
862 ASSERT_ARGS(Parrot_invalidate_method_cache)
863 INTVAL type;
865 /* during interp creation and NCI registration the class_hash
866 * isn't yet up */
867 if (!interp->class_hash)
868 return;
870 if (interp->resume_flag & RESUME_INITIAL)
871 return;
873 if (!_class) {
874 invalidate_all_caches(interp);
875 return;
878 type = pmc_type(interp, _class);
880 if (type == 0)
881 invalidate_all_caches(interp);
882 else if (type > 0)
883 invalidate_type_caches(interp, (UINTVAL)type);
888 =item C<PMC * Parrot_find_method_direct(PARROT_INTERP, PMC *_class, STRING
889 *method_name)>
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.
894 =cut
898 PARROT_EXPORT
899 PARROT_CAN_RETURN_NULL
900 PARROT_WARN_UNUSED_RESULT
901 PMC *
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))
908 return 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"));
914 return PMCNULL;
920 =item C<PMC * Parrot_find_method_with_cache(PARROT_INTERP, PMC *_class, STRING
921 *method_name)>
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.
931 =cut
935 PARROT_EXPORT
936 PARROT_CAN_RETURN_NULL
937 PARROT_WARN_UNUSED_RESULT
938 PMC *
939 Parrot_find_method_with_cache(PARROT_INTERP, ARGIN(PMC *_class), ARGIN(STRING *method_name))
941 ASSERT_ARGS(Parrot_find_method_with_cache)
942 UINTVAL type, bits;
944 Caches *mc;
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);
951 #endif
953 if (! PObj_constant_TEST(method_name))
954 return Parrot_find_method_direct(interp, _class, method_name);
956 mc = interp->caches;
957 type = _class->vtable->base_type;
958 bits = (((UINTVAL) method_name->strstart) >> 2) & TBL_SIZE_MASK;
960 if (type >= mc->mc_size) {
961 if (mc->idx) {
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);
966 else {
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];
978 old = NULL;
980 while (e && e->strstart != method_name->strstart) {
981 old = e;
982 e = e->next;
985 if (!e) {
986 /* when here no or no correct entry was at [bits] */
987 e = mem_allocate_typed(Meth_cache_entry);
989 if (old)
990 old->next = e;
991 else
992 mc->idx[type][bits] = e;
994 e->pmc = Parrot_find_method_direct(interp, _class, method_name);
995 e->next = NULL;
996 e->strstart = method_name->strstart;
999 return e->pmc;
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.
1010 =cut
1014 #ifdef NDEBUG
1015 # define TRACE_FM(i, c, m, sub)
1016 #else
1017 # define TRACE_FM(i, c, m, sub) \
1018 debug_trace_find_meth((i), (c), (m), (sub))
1020 static void
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)
1025 STRING *class_name;
1026 const char *result;
1027 Interp *tracer;
1029 if (!Interp_trace_TEST(interp, PARROT_TRACE_FIND_METH_FLAG))
1030 return;
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);
1037 else
1038 class_name = _class->vtable->whoami;
1040 if (sub) {
1041 if (sub->vtable->base_type == enum_class_NCI)
1042 result = "NCI";
1043 else
1044 result = "Sub";
1046 else
1047 result = "no";
1049 tracer = (interp->pdb && interp->pdb->debugger) ?
1050 interp->pdb->debugger :
1051 interp;
1052 Parrot_io_eprintf(tracer, "# find_method class '%Ss' method '%Ss': %s\n",
1053 class_name, name, result);
1056 #endif
1061 =item C<static PMC * find_method_direct_1(PARROT_INTERP, PMC *_class, STRING
1062 *method_name)>
1064 Find the method with the given name in the specified class.
1066 =cut
1070 PARROT_WARN_UNUSED_RESULT
1071 PARROT_CAN_RETURN_NULL
1072 static PMC *
1073 find_method_direct_1(PARROT_INTERP, ARGIN(PMC *_class),
1074 ARGIN(STRING *method_name))
1076 ASSERT_ARGS(find_method_direct_1)
1077 INTVAL i;
1079 PMC * const mro = _class->vtable->mro;
1080 const INTVAL n = VTABLE_elements(interp, mro);
1082 for (i = 0; i < n; ++i) {
1083 PMC *method, *ns;
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))
1092 return method;
1095 TRACE_FM(interp, _class, method_name, NULL);
1096 return PMCNULL;
1102 =item C<static PMC* C3_merge(PARROT_INTERP, PMC *merge_list)>
1104 Merge together the MRO of the items in the list.
1106 =cut
1110 PARROT_WARN_UNUSED_RESULT
1111 PARROT_CAN_RETURN_NULL
1112 static PMC*
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);
1119 int cand_count = 0;
1120 int i;
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);
1127 PMC *cand_class;
1128 int reject = 0;
1129 int j;
1131 if (VTABLE_elements(interp, cand_list) == 0)
1132 continue;
1134 cand_class = VTABLE_get_pmc_keyed_int(interp, cand_list, 0);
1135 cand_count++;
1137 for (j = 0; j < list_count; j++) {
1138 /* Skip the current list. */
1139 if (j != i) {
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);
1145 int k;
1147 for (k = 1; k < check_length; k++) {
1148 if (VTABLE_get_pmc_keyed_int(interp, check_list, k) ==
1149 cand_class) {
1150 reject = 1;
1151 break;
1157 /* If we didn't reject it, this candidate will do. */
1158 if (!reject) {
1159 accepted = cand_class;
1160 break;
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);
1178 INTVAL j;
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);
1183 break;
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);
1193 return result;
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>
1208 =cut
1212 PARROT_EXPORT
1213 PARROT_WARN_UNUSED_RESULT
1214 PARROT_CAN_RETURN_NULL
1215 PMC*
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"));
1221 PMC *merge_list;
1222 PMC *result;
1224 INTVAL i;
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);
1238 return result;
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))
1249 return PMCNULL;
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
1259 * we can merge. */
1260 VTABLE_push_pmc(interp, merge_list, immediate_parents);
1261 result = C3_merge(interp, merge_list);
1263 if (PMC_IS_NULL(result))
1264 return PMCNULL;
1266 /* Merged result needs this class on the start, and then we're done. */
1267 VTABLE_unshift_pmc(interp, result, _class);
1269 return result;
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.
1289 =cut
1293 PARROT_EXPORT
1294 void
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)
1301 PMC *methods;
1302 PMC *methods_iter;
1303 PMC *roles_of_role;
1304 PMC *proposed_add_methods;
1306 INTVAL roles_of_role_count;
1307 INTVAL i;
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)
1314 return;
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))
1320 return;
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,
1331 method_name);
1333 /* Need to find the name we'll check for a conflict on. */
1334 int excluded = 0;
1336 /* Check if it's in the exclude list. */
1337 if (got_exclude) {
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)) {
1345 excluded = 1;
1346 break;
1351 /* If we weren't excluded... */
1352 if (!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
1357 * multi-method. */
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,
1368 method_name))
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"
1377 * list. */
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,
1403 alias_name))
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
1418 * methods. */
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);
1435 INTVAL j;
1436 for (j = 0; j < num_subs; j++)
1437 VTABLE_push_pmc(interp, cur_entry, VTABLE_get_pmc_keyed_int(interp,
1438 cur_method, j));
1440 else {
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);
1445 else {
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);
1449 else
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);
1456 roles_count++;
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,
1468 roles_of_role, i);
1469 INTVAL j;
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);
1483 =back
1485 =head1 SEE ALSO
1487 F<include/parrot/oo.h>, F<include/parrot/oo_private.h>,
1488 F<docs/pdds/pdd15_objects.pod>.
1490 =cut
1495 * Local variables:
1496 * c-file-style: "parrot"
1497 * End:
1498 * vim: expandtab shiftwidth=4: