1/*
2Copyright (C) 2001-2014, Parrot Foundation.
3
4=head1 NAME
5
6src/pmc/class.pmc - Class PMC
7
8=head1 DESCRIPTION
9
10This class implements the Class PMC, as outlined in
11F<docs/pdds/pdd15_objects.pod>.
12
13Class is not derived from any other PMC.
14
15=head2 Structure
16
17The Class PMC structure (C<Parrot_Class>) consists of twelve items:
18
19=over 4
20
21=item C<id>
22
23The type number of the PMC.
24
25=item C<name>
26
27The name of the class -- a STRING.
28An empty STRING is allocated during initialization.
29
30=item C<namespace>
31
32The namespace the class is associated with, if any.
33A Null PMC is allocated during initialization.
34
35=item C<instantiated>
36
37A flag denoting whether this class has been instantiated since last
38modification.  A native integer with value zero is allocated during
39initialization.
40
41=item C<parents>
42
43An array of immediate parent classes.
44An empty ResizablePMCArray PMC is allocated during initialization.
45
46=item C<all_parents>
47
48A cached array of ourself and all parent classes, in method resolution
49order (MRO). A ResizablePMCArray PMC is allocated during initialization,
50and is populated with the current class.
51
52=item C<roles>
53
54An array of the roles this class has been composed from.
55An empty ResizablePMCArray PMC is allocated during initialization.
56
57=item C<methods>
58
59A directory of method names and method bodies this class provides.
60An empty Hash PMC is allocated during initialization.
61
62=item C<vtable_overrides>
63
64A directory of vtable function names and method bodies this class overrides.
65An empty Hash PMC is allocated during initialization.
66
67=item C<attrib_metadata>
68
69A directory of attribute names and attribute metadata this class contains.
70An empty Hash PMC is allocated during initialization.
71
72=item C<attrib_index>
73
74A lookup table for attributes in this class and parents.
75A Null PMC is allocated during initialization.
76
77=item C<attrib_cache>
78
79A cache of visible attribute names to attribute indexes.
80A Null PMC is allocated during initialization.
81
82=item C<resolve_method>
83
84A list of method names the class provides used for name conflict resolution.
85An empty ResizablePMCArray PMC is allocated during initialization.
86
87=cut
88
89*/
90
91#include "parrot/oo_private.h"
92#include "pmc/pmc_object.h"
93#include "pmc/pmc_namespace.h"
94
95/* HEADERIZER HFILE: none */
96/* HEADERIZER BEGIN: static */
97/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
98
99static void build_attrib_index(PARROT_INTERP, ARGIN(PMC *self))
100        __attribute__nonnull__(1)
101        __attribute__nonnull__(2);
102
103static int cache_class_attribs(PARROT_INTERP,
104    ARGIN(PMC *cur_class),
105    ARGIN(PMC *attrib_index),
106    ARGIN(PMC *cache),
107    int cur_index)
108        __attribute__nonnull__(1)
109        __attribute__nonnull__(2)
110        __attribute__nonnull__(3)
111        __attribute__nonnull__(4);
112
113static void calculate_mro(PARROT_INTERP,
114    ARGIN(PMC *SELF),
115    INTVAL num_parents)
116        __attribute__nonnull__(1)
117        __attribute__nonnull__(2);
118
119static void init_class_from_hash(PARROT_INTERP,
120    ARGMOD(PMC *self),
121    ARGIN_NULLOK(PMC *info))
122        __attribute__nonnull__(1)
123        __attribute__nonnull__(2)
124        FUNC_MODIFIES(*self);
125
126static void initialize_parents(PARROT_INTERP,
127    ARGIN(PMC *object),
128    ARGIN(PMC *all_parents))
129        __attribute__nonnull__(1)
130        __attribute__nonnull__(2)
131        __attribute__nonnull__(3);
132
133static void initialize_parents_pmc(PARROT_INTERP,
134    ARGIN(PMC *object),
135    ARGIN(PMC *all_parents),
136    ARGIN(PMC *init))
137        __attribute__nonnull__(1)
138        __attribute__nonnull__(2)
139        __attribute__nonnull__(3)
140        __attribute__nonnull__(4);
141
142PARROT_CANNOT_RETURN_NULL
143static STRING * make_class_name(PARROT_INTERP, ARGIN(PMC *SELF))
144        __attribute__nonnull__(1)
145        __attribute__nonnull__(2);
146
147#define ASSERT_ARGS_build_attrib_index __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
148       PARROT_ASSERT_ARG(interp) \
149    , PARROT_ASSERT_ARG(self))
150#define ASSERT_ARGS_cache_class_attribs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
151       PARROT_ASSERT_ARG(interp) \
152    , PARROT_ASSERT_ARG(cur_class) \
153    , PARROT_ASSERT_ARG(attrib_index) \
154    , PARROT_ASSERT_ARG(cache))
155#define ASSERT_ARGS_calculate_mro __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
156       PARROT_ASSERT_ARG(interp) \
157    , PARROT_ASSERT_ARG(SELF))
158#define ASSERT_ARGS_init_class_from_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
159       PARROT_ASSERT_ARG(interp) \
160    , PARROT_ASSERT_ARG(self))
161#define ASSERT_ARGS_initialize_parents __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
162       PARROT_ASSERT_ARG(interp) \
163    , PARROT_ASSERT_ARG(object) \
164    , PARROT_ASSERT_ARG(all_parents))
165#define ASSERT_ARGS_initialize_parents_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
166       PARROT_ASSERT_ARG(interp) \
167    , PARROT_ASSERT_ARG(object) \
168    , PARROT_ASSERT_ARG(all_parents) \
169    , PARROT_ASSERT_ARG(init))
170#define ASSERT_ARGS_make_class_name __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
171       PARROT_ASSERT_ARG(interp) \
172    , PARROT_ASSERT_ARG(SELF))
173/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
174/* HEADERIZER END: static */
175
176/*
177
178=item C<static int cache_class_attribs(PARROT_INTERP, PMC *cur_class, PMC
179*attrib_index, PMC *cache, int cur_index)>
180
181Create a cached map of all attributes (including those inherited from parent
182types), where the name of each attribute is mapped to an integer index into
183a storage array.
184
185=cut
186
187*/
188
189static int
190cache_class_attribs(PARROT_INTERP,
191        ARGIN(PMC *cur_class), ARGIN(PMC *attrib_index),
192        ARGIN(PMC *cache), int cur_index)
193{
194    ASSERT_ARGS(cache_class_attribs)
195    /* The attribute metadata hash. */
196    Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class);
197    PMC          * const attribs     = class_info->attrib_metadata;
198    PMC          * const iter        = VTABLE_get_iter(interp, attribs);
199
200    /* Build a string representing the fully qualified class name. */
201    /* Retrieve the fully qualified class name for the class. */
202    STRING       * const fq_class    = VTABLE_get_string(interp, cur_class);
203    PMC          * const class_cache = Parrot_pmc_new(interp, enum_class_Hash);
204    VTABLE_set_pmc_keyed_str(interp, cache, fq_class, class_cache);
205
206    /* Iterate over the attributes. */
207    while (VTABLE_get_bool(interp, iter)) {
208        /* Get attribute. */
209        PMC    * const cur_attrib  = VTABLE_get_pmc_keyed_str(interp,
210                attribs, VTABLE_shift_string(interp, iter));
211
212        /* Get attribute name and append it to the key. */
213        STRING * const name_str    = CONST_STRING(interp, "name");
214        STRING * const attrib_name = VTABLE_get_string_keyed_str(
215            interp, cur_attrib, name_str);
216
217        STRING * const full_key    = Parrot_str_concat(interp, fq_class, attrib_name);
218
219        /* Insert into hash, along with index. */
220        VTABLE_set_integer_keyed_str(interp, attrib_index, full_key, cur_index);
221        VTABLE_set_integer_keyed_str(interp, class_cache, attrib_name, cur_index);
222        ++cur_index;
223    }
224
225    return cur_index;
226}
227
228/*
229
230=item C<static void build_attrib_index(PARROT_INTERP, PMC *self)>
231
232This function builds the attribute index (table to map class name and
233attribute name to an index) for the current class.
234
235=cut
236
237*/
238
239static void
240build_attrib_index(PARROT_INTERP, ARGIN(PMC *self))
241{
242    ASSERT_ARGS(build_attrib_index)
243    Parrot_Class_attributes * const _class = PARROT_CLASS(self);
244    int                  cur_index    = 0;
245    PMC * const          attrib_index = Parrot_pmc_new(interp, enum_class_Hash);
246    PMC * const          cache        = Parrot_pmc_new_init_int(interp,
247                                            enum_class_Hash, enum_type_INTVAL);
248    const int            num_classes  = VTABLE_elements(interp, _class->all_parents);
249    int                  i;
250
251    /* Go over the list of all parents to construct the attribute index. */
252    for (i = 0; i < num_classes; ++i) {
253       /* Get the class and check that it respects the standard class interface
254        * (if not we don't know how it stores its attributes, so we'll have to
255        * delegate the lookup). */
256        PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp,
257                                    _class->all_parents, i);
258
259        if (PObj_is_class_TEST(cur_class))
260            cur_index = cache_class_attribs(interp, cur_class,
261                attrib_index, cache, cur_index);
262    }
263
264    /* Store built attribute index and invalidate cache. */
265    _class->attrib_index = attrib_index;
266    _class->attrib_cache = cache;
267
268    PARROT_GC_WRITE_BARRIER(interp, self);
269}
270
271/*
272
273=item C<static void init_class_from_hash(PARROT_INTERP, PMC *self, PMC *info)>
274
275Takes a hash and initializes the class based on it.
276
277=cut
278
279*/
280
281static void
282init_class_from_hash(PARROT_INTERP, ARGMOD(PMC *self), ARGIN_NULLOK(PMC *info))
283{
284    ASSERT_ARGS(init_class_from_hash)
285    Parrot_Class_attributes * const _class      = PARROT_CLASS(self);
286    STRING  * const name_str    = CONST_STRING(interp, "name");
287    STRING  * const parents_str = CONST_STRING(interp, "parents");
288    STRING  * const methods_str = CONST_STRING(interp, "methods");
289    STRING  * const roles_str   = CONST_STRING(interp, "roles");
290    STRING  * const attrs_str   = CONST_STRING(interp, "attributes");
291    STRING  * const resolve_method_str = CONST_STRING(interp, "resolve_method");
292    STRING  * const set_class_str = CONST_STRING(interp, "set_class");
293    PMC     *old_ns;
294
295    /* Ensure we actually have some initialization info. */
296    if (PMC_IS_NULL(info))
297        return;
298
299    /* Take a copy of the current namespace the class is attached to. */
300    old_ns = _class->_namespace;
301
302    /* Check if we have a name/namespace. */
303    if (VTABLE_exists_keyed_str(interp, info, name_str)) {
304        STRING *new_name;
305        PMC    *new_namespace;
306        PMC    *name_arg = VTABLE_get_pmc_keyed_str(interp, info, name_str);
307        VTABLE *new_vtable;
308        INTVAL type_num;
309
310        /* If we were passed a namespace PMC, set the namespace attribute
311         * directly. Otherwise, lookup or create the appropriate namespace. */
312        if (name_arg->vtable->base_type == enum_class_NameSpace) {
313            new_namespace = name_arg;
314            name_arg      = Parrot_ns_get_name(interp, new_namespace);
315            VTABLE_shift_string(interp, name_arg);
316        }
317        else {
318            PMC * const hll_ns = VTABLE_get_pmc_keyed_int(interp,
319                    interp->HLL_namespace, Parrot_pcc_get_HLL(interp, CURRENT_CONTEXT(interp)));
320            new_namespace = Parrot_ns_make_namespace_keyed(interp, hll_ns, name_arg);
321        }
322
323        if (PMC_IS_NULL(new_namespace))
324            Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INVALID_OPERATION,
325                "Failed to set namespace for class");
326
327        /* Set the name of the class to the name of the innermost namespace
328         * associated with the class.  */
329        new_name = VTABLE_get_string(interp, new_namespace);
330
331        if (STRING_IS_NULL(new_name) || STRING_IS_EMPTY(new_name))
332              Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INVALID_OPERATION,
333                "Failed to set name for class");
334
335        _class->_namespace = new_namespace;
336        _class->name       = new_name;
337
338        /* At this point we know the class isn't anonymous */
339        CLASS_is_anon_CLEAR(self);
340
341        /* Register a type number for the class. */
342        type_num   = Parrot_oo_register_type(interp, name_arg, new_namespace);
343
344        /* Link the type number with the class's vtable. */
345        new_vtable = Parrot_vtbl_clone_vtable(interp, self->vtable);
346
347        new_vtable->base_type         = type_num;
348        new_vtable->pmc_class         = self;
349        new_vtable->whoami            = VTABLE_get_string(interp, self);
350        new_vtable->mro               = _class->all_parents;
351        new_vtable->ro_variant_vtable =
352                Parrot_vtbl_clone_vtable(interp, self->vtable->ro_variant_vtable);
353
354        /* Store the class's vtable in the global table */
355        interp->vtables[type_num]     = new_vtable;
356
357        _class->id                    = type_num;
358    }
359
360    /* If we were attached to a namespace and are now attached to a new one,
361     * need to unset ourselves in the old namespace. */
362    if (!PMC_IS_NULL(old_ns) && _class->_namespace != old_ns)
363        Parrot_pcc_invoke_method_from_c_args(interp, old_ns,
364                                             set_class_str,
365                                             "P->", PMCNULL);
366
367    /* Link namespace to this class, if there is one. */
368    if (!PMC_IS_NULL(_class->_namespace)) {
369        Parrot_pcc_invoke_method_from_c_args(interp, _class->_namespace,
370                                             set_class_str,
371                                             "P->", self);
372    }
373
374    /* Initialize resolve_method. */
375    if (VTABLE_exists_keyed_str(interp, info, resolve_method_str)) {
376        /* Set it. */
377        _class->resolve_method =
378            VTABLE_get_pmc_keyed_str(interp, info, resolve_method_str);
379    }
380
381    /* Initialize parents, if we have any. */
382    if (VTABLE_exists_keyed_str(interp, info, parents_str)) {
383        /* Loop over parents array and add them. */
384        PMC * const parent_list = VTABLE_get_pmc_keyed_str(interp, info,
385            parents_str);
386        const int  parent_count = VTABLE_elements(interp, parent_list);
387        int i;
388
389        for (i = 0; i < parent_count; ++i)
390            VTABLE_add_parent(interp, self,
391                VTABLE_get_pmc_keyed_int(interp, parent_list, i));
392    }
393
394    /* Initialize roles, if we have any. */
395    if (VTABLE_exists_keyed_str(interp, info, roles_str)) {
396        /* Loop over roles array and compose them. */
397        PMC * const role_list  = VTABLE_get_pmc_keyed_str(interp, info,
398            roles_str);
399        const int   role_count = VTABLE_elements(interp, role_list);
400        int i;
401
402        for (i = 0; i < role_count; ++i)
403            VTABLE_add_role(interp, self,
404                VTABLE_get_pmc_keyed_int(interp, role_list, i));
405    }
406
407    /* Initialize attributes, if we have any. */
408    if (VTABLE_exists_keyed_str(interp, info, attrs_str)) {
409        /* Loop over attributes array and add them. */
410        PMC * const attrs_name_list = VTABLE_get_pmc_keyed_str(interp, info,
411                                            attrs_str);
412        const int   attrib_count    = VTABLE_elements(interp, attrs_name_list);
413        int i;
414
415        for (i = 0; i < attrib_count; ++i) {
416            STRING * const attr_name = VTABLE_get_string_keyed_int(interp,
417                attrs_name_list, i);
418            VTABLE_add_attribute(interp, self, attr_name, PMCNULL);
419        }
420    }
421
422    /* Initialize methods. */
423    if (VTABLE_exists_keyed_str(interp, info, methods_str)) {
424        /* Get the methods hash. */
425        PMC * const methods = VTABLE_get_pmc_keyed_str(interp, info,
426            methods_str);
427
428        /* Iterate over the list of methods. */
429        PMC * const iter    = VTABLE_get_iter(interp, methods);
430
431        while (VTABLE_get_bool(interp, iter)) {
432            /* Add the method. */
433            STRING * const method_name = VTABLE_shift_string(interp, iter);
434            PMC    * const method_pmc  = VTABLE_get_pmc_keyed_str(interp,
435                methods, method_name);
436            VTABLE_add_method(interp, self, method_name, method_pmc);
437        }
438    }
439
440    /* Extract any methods from the namespace */
441    Parrot_oo_extract_methods_from_namespace(interp, self, _class->_namespace);
442}
443
444/*
445
446=item C<static void initialize_parents(PARROT_INTERP, PMC *object, PMC
447*all_parents)>
448
449Loop over all parents in the MRO, setting up delegate objects if necessary and
450calling C<init> vtables on them, if necessary.
451
452=cut
453
454*/
455
456static void
457initialize_parents(PARROT_INTERP, ARGIN(PMC *object), ARGIN(PMC *all_parents))
458{
459    ASSERT_ARGS(initialize_parents)
460    INTVAL  parent_index = VTABLE_elements(interp, all_parents) - 1;
461    STRING * const name  = CONST_STRING(interp, "init");
462
463    /* Loop through the parents in reverse MRO order. */
464    for (; parent_index >= 0; --parent_index) {
465        PMC *meth;
466        PMC * const parent = VTABLE_get_pmc_keyed_int(interp,
467                                 all_parents, parent_index);
468
469        /* PMCProxy parents store an instance to delegate to */
470        if (parent->vtable->base_type == enum_class_PMCProxy) {
471            PMC    *proxy     = VTABLE_instantiate(interp, parent, PMCNULL);
472            STRING *proxy_str = CONST_STRING(interp, "proxy");
473            VTABLE_set_attr_keyed(interp, object, parent, proxy_str, proxy);
474        }
475
476        meth = Parrot_oo_find_vtable_override_for_class(interp, parent, name);
477
478        if (!PMC_IS_NULL(meth)) {
479            /* preserve current_object */
480            Parrot_ext_call(interp, meth, "Pi->", object);
481        }
482    }
483}
484
485/*
486
487=item C<static void initialize_parents_pmc(PARROT_INTERP, PMC *object, PMC
488*all_parents, PMC *init)>
489
490Loop over all parents in the MRO, setting up delegate objects if necessary and
491calling C<init_pmc> vtables on them, if necessary.
492
493=cut
494
495*/
496
497static void
498initialize_parents_pmc(PARROT_INTERP, ARGIN(PMC *object),
499        ARGIN(PMC *all_parents), ARGIN(PMC *init))
500{
501    ASSERT_ARGS(initialize_parents_pmc)
502    INTVAL parent_index = VTABLE_elements(interp, all_parents) - 1;
503    STRING * const name  = CONST_STRING(interp, "init_pmc");
504
505    /* Loop through the parents in reverse MRO order. */
506    for (; parent_index >= 0; --parent_index) {
507        PMC *meth;
508        PMC * const parent = VTABLE_get_pmc_keyed_int(interp,
509            all_parents, parent_index);
510
511        /* PMCProxy parents store an instance to delegate to */
512        if (parent->vtable->base_type == enum_class_PMCProxy) {
513            PMC    * const proxy     = VTABLE_instantiate(interp, parent, init);
514            STRING * const proxy_str = CONST_STRING(interp, "proxy");
515            VTABLE_set_attr_keyed(interp, object, parent, proxy_str, proxy);
516        }
517
518        meth = Parrot_oo_find_vtable_override_for_class(interp, parent, name);
519
520        if (!PMC_IS_NULL(meth))
521            Parrot_ext_call(interp, meth, "PiP->", object, init);
522    }
523}
524
525/*
526
527=item C<static STRING * make_class_name(PARROT_INTERP, PMC *SELF)>
528
529This function makes and caches the name of this class, returning the string
530directly.  C<VTABLE_isa()> uses the name without copying it, for efficiency
531reasons, as it does not modify the STRING.  C<VTABLE_get_string()> makes a
532copy of the STRING, so its callers are free to modify it.
533
534=cut
535
536*/
537
538PARROT_CANNOT_RETURN_NULL
539static STRING *
540make_class_name(PARROT_INTERP, ARGIN(PMC *SELF))
541{
542    ASSERT_ARGS(make_class_name)
543    Parrot_Class_attributes * const  _class    = PARROT_CLASS(SELF);
544    PMC          * const _namespace = _class->_namespace;
545
546    if (!PMC_IS_NULL(_namespace)) {
547        if (_class->fullname)
548            return _class->fullname;
549        else {
550
551            /* Call the 'get_name' method on the class's associated
552             * namespace to retrieve a fully qualified list of names, then
553             * join the list with a semicolon.  */
554            PMC * const names = Parrot_ns_get_name(interp, _namespace);
555
556            if (!PMC_IS_NULL(names))
557                /* remove the HLL namespace name */
558                VTABLE_shift_string(interp, names);
559                PARROT_GC_WRITE_BARRIER(interp, SELF);
560                _class->fullname = Parrot_str_join(interp, CONST_STRING(interp, ";"), names);
561                return _class->fullname;
562        }
563    }
564
565    /* Otherwise, copy the stored string name of the class. */
566    return _class->name;
567}
568
569/*
570
571=item C<static void calculate_mro(PARROT_INTERP, PMC *SELF, INTVAL num_parents)>
572
573Calculates the C3 method resolution order for this class. C3 is the name of an
574algorithm used to calculate the method resolution order (MRO) to use in a
575system with multiple inheritance. For more information see the documentation
576associated with C<Parrot_ComputeMRO_C3>.
577
578=cut
579
580*/
581
582static void
583calculate_mro(PARROT_INTERP, ARGIN(PMC *SELF), INTVAL num_parents)
584{
585    ASSERT_ARGS(calculate_mro)
586    Parrot_Class_attributes  * const _class = PARROT_CLASS(SELF);
587
588    /* SELF is already on the all_parents */
589    if (num_parents == 0)
590        return;
591
592    if (num_parents == 1) {
593        STRING * const ap         = CONST_STRING(interp, "all_parents");
594        PMC    * const parent     = VTABLE_get_pmc_keyed_int(interp,
595                _class->parents, 0);
596        PMC    * const parent_mro = VTABLE_inspect_str(interp, parent, ap);
597        PMC    * const mro        = VTABLE_clone(interp, parent_mro);
598        VTABLE_unshift_pmc(interp, mro, SELF);
599        PARROT_GC_WRITE_BARRIER(interp, SELF);
600        _class->all_parents = mro;
601    }
602    else {
603        PARROT_GC_WRITE_BARRIER(interp, SELF);
604        _class->all_parents = Parrot_ComputeMRO_C3(interp, SELF);
605    }
606
607    if (!CLASS_is_anon_TEST(SELF))
608        interp->vtables[VTABLE_type(interp, SELF)]->mro = _class->all_parents;
609}
610
611/*
612
613=back
614
615=head2 Functions
616
617=over 4
618
619=cut
620
621*/
622
623pmclass Class auto_attrs {
624
625    ATTR INTVAL id;             /* The type number of the PMC. */
626    ATTR STRING *name;          /* The name of the class. */
627    ATTR STRING *fullname;      /* The name of the class. */
628    ATTR PMC *_namespace;       /* The namespace it's linked to, if any. */
629    ATTR INTVAL instantiated;   /* Any instantiations since last modification? */
630    ATTR PMC *parents;          /* Immediate parent classes. */
631    ATTR PMC *all_parents;      /* Cached list of ourself and all parents, in MRO order. */
632    ATTR PMC *roles;            /* An array of roles. */
633    ATTR PMC *methods;          /* Hash of method names to methods in this class. */
634    ATTR PMC *vtable_overrides; /* Hash of Parrot v-table methods we override. */
635    ATTR PMC *attrib_metadata;  /* Hash of attributes in this class to hashes of metadata. */
636    ATTR PMC *attrib_index;     /* Lookup table for attributes in this and parents. */
637    ATTR PMC *attrib_cache;     /* Cache of visible attrib names to indexes. */
638    ATTR PMC *resolve_method;   /* List of method names the class provides to resolve
639                                 * conflicts with methods from roles. */
640    ATTR PMC  *parent_overrides;
641    ATTR PMC  *meth_cache;
642    ATTR Hash *isa_cache;
643
644/*
645
646=item C<void init()>
647
648Initializes a Class PMC.
649
650=item C<void init_pmc(PMC *init_data)>
651
652The actual class creation code, called from C<newclass> opcode. The C<init_data>
653argument may be either the name of the class or a hash of initialization
654arguments. The class is attached to the current HLL namespace.
655
656=cut
657
658*/
659
660    VTABLE void init() {
661        Parrot_Class_attributes * const _class =
662                (Parrot_Class_attributes *) PMC_data(SELF);
663
664        /* Set flag for custom GC mark. */
665        PObj_custom_mark_destroy_SETALL(SELF);
666
667        /* Set up the object. */
668        _class->name            = CONST_STRING(INTERP, "");
669        _class->_namespace      = PMCNULL;
670        _class->parents         = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
671        _class->all_parents     = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
672        _class->roles           = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
673        _class->methods         = Parrot_pmc_new(INTERP, enum_class_Hash);
674        _class->attrib_metadata = Parrot_pmc_new(INTERP, enum_class_Hash);
675        _class->attrib_index    = PMCNULL;
676        _class->attrib_cache    = PMCNULL;
677        _class->meth_cache      = PMCNULL;
678        _class->resolve_method  = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
679
680        _class->vtable_overrides = Parrot_pmc_new(INTERP, enum_class_Hash);
681        _class->parent_overrides = Parrot_pmc_new(INTERP, enum_class_Hash);
682
683        _class->isa_cache        = Parrot_hash_create(INTERP,
684            enum_type_INTVAL, Hash_key_type_PMC_ptr);
685
686
687        /* We put ourself on the all parents list. */
688        VTABLE_push_pmc(INTERP, _class->all_parents, SELF);
689
690        /* We are a class. */
691        PObj_is_class_SET(SELF);
692
693        /* By default we're anonymous. */
694        CLASS_is_anon_SET(SELF);
695    }
696
697    VTABLE void init_pmc(PMC *init_data) {
698        PMC           *arg;
699        const INTVAL   arg_type = VTABLE_type(INTERP, init_data);
700        STRING * const name_str = CONST_STRING(INTERP, "name");
701
702        /* Set up the object. */
703        SELF.init();
704
705        /* fast attempt to determine init_data type */
706        switch (arg_type) {
707          case enum_class_String:
708          case enum_class_Key:
709          case enum_class_ResizableStringArray:
710          case enum_class_NameSpace:
711            /* set only the name property */
712            arg = Parrot_pmc_new(INTERP, enum_class_Hash);
713            VTABLE_set_pmc_keyed_str(INTERP, arg, name_str, init_data);
714            break;
715
716          case enum_class_Hash:
717            arg = init_data;
718            break;
719
720            /* slow attempt to determine init_data type */
721          default:
722            if (VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "String"))
723             || VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "Key"))
724             || VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "ResizableStringArray"))) {
725                /* set only the name property */
726                arg = Parrot_pmc_new(INTERP, enum_class_Hash);
727                VTABLE_set_pmc_keyed_str(INTERP, arg, name_str, init_data);
728            }
729
730            if (VTABLE_isa(INTERP, init_data, CONST_STRING(INTERP, "Hash")))
731                arg = init_data;
732            else
733                Parrot_ex_throw_from_c_noargs(INTERP,
734                        EXCEPTION_INVALID_OPERATION,
735                            "Invalid class name key in init_pmc for Class");
736            break;
737        }
738
739        /* Initialize the class with the supplied data. */
740        init_class_from_hash(INTERP, SELF, arg);
741    }
742
743    void destroy() {
744        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
745        Parrot_hash_destroy(INTERP, _class->isa_cache);
746    }
747
748/*
749
750=item C<STRING *get_string()>
751
752Returns the name of the class (without the HLL namespace).
753
754=cut
755
756*/
757
758    VTABLE STRING *get_string() :no_wb {
759        return make_class_name(INTERP, SELF);
760    }
761
762/*
763
764=item C<void mark()>
765
766Marks any referenced strings and PMCs in the structure as live.
767
768=cut
769
770*/
771
772    VTABLE void mark() :no_wb {
773        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
774        Parrot_gc_mark_STRING_alive(INTERP, _class->name);
775        Parrot_gc_mark_STRING_alive(INTERP, _class->fullname);
776        Parrot_gc_mark_PMC_alive(INTERP, _class->_namespace);
777        Parrot_gc_mark_PMC_alive(INTERP, _class->parents);
778        Parrot_gc_mark_PMC_alive(INTERP, _class->all_parents);
779        Parrot_gc_mark_PMC_alive(INTERP, _class->roles);
780        Parrot_gc_mark_PMC_alive(INTERP, _class->methods);
781        Parrot_gc_mark_PMC_alive(INTERP, _class->vtable_overrides);
782        Parrot_gc_mark_PMC_alive(INTERP, _class->parent_overrides);
783        Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_metadata);
784        Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_index);
785        Parrot_gc_mark_PMC_alive(INTERP, _class->attrib_cache);
786        Parrot_gc_mark_PMC_alive(INTERP, _class->resolve_method);
787        Parrot_gc_mark_PMC_alive(INTERP, _class->meth_cache);
788        if (_class->isa_cache)
789            Parrot_hash_mark(INTERP, _class->isa_cache);
790    }
791
792
793/*
794
795=item C<void add_attribute(STRING *name, PMC *type)>
796
797Adds the given attribute (C<name>) with an optional C<type>.
798Throws an exception if the current class has been instantiated.
799Enters the attribute in the C<attrib_metadata> table.
800Returns an error if an attribute of C<name> already exists.
801
802=cut
803
804*/
805
806    VTABLE void add_attribute(STRING *name, PMC *type) {
807        Parrot_Class_attributes * const _class        = PARROT_CLASS(SELF);
808        PMC          * const new_attribute = Parrot_pmc_new(INTERP, enum_class_Hash);
809
810        /* If we've been instantiated already, not allowed. */
811        if (_class->instantiated)
812            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
813                "Modifications to classes are not allowed after instantiation");
814
815        /* If we already have an attribute of this name, it's an error. */
816        if (VTABLE_exists_keyed_str(INTERP, _class->attrib_metadata, name))
817            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
818                "Attribute '%Ss' already exists in '%Ss'", name,
819                VTABLE_get_string(INTERP, SELF));
820
821        /* Set name and type. */
822        VTABLE_set_string_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "name"), name);
823
824        if (!PMC_IS_NULL(type))
825            VTABLE_set_pmc_keyed_str(INTERP, new_attribute, CONST_STRING(INTERP, "type"), type);
826
827        /* Enter the attribute in the attrib_metadata table. */
828        VTABLE_set_pmc_keyed_str(INTERP, _class->attrib_metadata, name,
829            new_attribute);
830    }
831
832/*
833
834=item C<void remove_attribute(STRING *name)>
835
836Removes the given attribute (C<name>) from the class. Throws an exception if
837the current class has been instantiated, or if the class has no attribute
838C<name>.
839
840=cut
841
842*/
843
844    VTABLE void remove_attribute(STRING *name) :manual_wb {
845        Parrot_Class_attributes * const _class        = PARROT_CLASS(SELF);
846
847        /* If we've been instantiated already, not allowed. */
848        if (_class->instantiated)
849            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
850                "Modifications to classes are not allowed after instantiation");
851
852        /* If we don't have an attribute of this name, it's an error. */
853        if (!VTABLE_exists_keyed_str(INTERP, _class->attrib_metadata, name))
854            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
855                "Attribute '%Ss' cannot be removed, does not exist in '%Ss'", name,
856                VTABLE_get_string(INTERP, SELF));
857
858        /* Remove the attribute from the attrib_metadata table. */
859        VTABLE_delete_keyed_str(INTERP, _class->attrib_metadata, name);
860
861        build_attrib_index(INTERP, SELF); /* calls WB */
862    }
863
864/*
865
866=item C<void add_method(STRING *name, PMC *sub)>
867
868Adds the given sub PMC as a method with the given name.
869
870=cut
871
872*/
873    VTABLE void add_method(STRING *name, PMC *sub) {
874        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
875        PMC                     * const method =
876                 VTABLE_get_pmc_keyed_str(INTERP, _class->methods, name);
877
878        /* If we have already added a method with this name... */
879        if (!PMC_IS_NULL(method)) {
880            if (method == sub)
881                return;
882
883            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
884                "A method named '%S' already exists in class '%S'. "
885                "It may have been supplied by a role",
886                name, VTABLE_get_string(INTERP, SELF));
887        }
888
889        /* Enter it into the table. */
890        VTABLE_set_pmc_keyed_str(INTERP, _class->methods, name, sub);
891    }
892
893/*
894
895=item C<void remove_method(STRING *name)>
896
897Removes the method with the given name.
898
899=cut
900
901*/
902    VTABLE void remove_method(STRING *name) {
903        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
904        if (VTABLE_exists_keyed_str(INTERP, _class->methods, name))
905            VTABLE_delete_keyed_str(INTERP, _class->methods, name);
906        else
907            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
908                "No method named '%S' to remove in class '%S'",
909                name, VTABLE_get_string(INTERP, SELF));
910    }
911
912/*
913
914=item C<void add_vtable_override(STRING *name, PMC *sub)>
915
916Adds the given sub PMC as a vtable override with the given name.
917
918=cut
919
920*/
921    VTABLE void add_vtable_override(STRING *name, PMC *sub) {
922        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
923
924        /* Check that the name is actually valid as a vtable override */
925        if (Parrot_get_vtable_index(INTERP, name) == -1)
926            Parrot_ex_throw_from_c_args(INTERP, NULL,
927                EXCEPTION_METHOD_NOT_FOUND,
928                "'%S' is not a valid vtable function name", name);
929
930        /* Add it to vtable list. */
931        VTABLE_set_pmc_keyed_str(INTERP, _class->vtable_overrides, name, sub);
932    }
933
934/*
935
936=item C<void add_parent(PMC *parent)>
937
938Adds the supplied PMC to the list of parents for the class.
939
940=cut
941
942*/
943    VTABLE void add_parent(PMC *parent) {
944        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
945        int parent_count, index;
946
947        /* If we've been instantiated already, not allowed. */
948        if (_class->instantiated)
949            Parrot_ex_throw_from_c_noargs(INTERP,
950                EXCEPTION_INVALID_OPERATION,
951                "Modifications to classes are not allowed after instantiation");
952
953        if (PMC_IS_NULL(parent)) {
954            STRING * const me_str = make_class_name(INTERP, SELF);
955            Parrot_ex_throw_from_c_args(INTERP, NULL,
956                EXCEPTION_UNEXPECTED_NULL, "Parent of '%Ss' is null", me_str);
957        }
958
959        /* Ensure it really is a class. */
960        if (!PObj_is_class_TEST(parent)) {
961            STRING * const pstr = VTABLE_get_string(INTERP, parent);
962            STRING * me_str = make_class_name(INTERP, SELF);
963            Parrot_ex_throw_from_c_args(INTERP, NULL,
964                EXCEPTION_INVALID_OPERATION,
965                "Parent '%Ss' of '%Ss' isn't a Class", pstr, me_str);
966        }
967
968        /* Check is not self */
969        if (parent == SELF)
970            Parrot_ex_throw_from_c_noargs(INTERP,
971                    EXCEPTION_INVALID_OPERATION, "Can't be own parent");
972
973        /* get number of direct parents */
974        parent_count = VTABLE_elements(INTERP, _class->parents);
975
976        /* iterate over all direct parents, check whether this class already has
977         * the parent being added. */
978        for (index = 0; index < parent_count; ++index) {
979            /* get the next parent */
980            PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP,
981                                      _class->parents, index);
982
983            /* throw an exception if we already have this parent */
984            if (current_parent == parent)
985                Parrot_ex_throw_from_c_args(INTERP, NULL,
986                    EXCEPTION_INVALID_OPERATION,
987                    "The class '%S' already has a parent class '%S'. "
988                    "It may have been supplied by a role",
989                    VTABLE_get_string(INTERP, SELF),
990                    VTABLE_get_string(INTERP, parent));
991        }
992
993        /* Check that none of the parents is self */
994        parent_count = VTABLE_elements(INTERP, PARROT_CLASS(parent)->all_parents);
995
996        for (index = 0; index < parent_count; ++index) {
997            /* get the next parent */
998            PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP,
999                PARROT_CLASS(parent)->all_parents, index);
1000
1001            if (current_parent == SELF)
1002                Parrot_ex_throw_from_c_args(INTERP, NULL,
1003                    EXCEPTION_INVALID_OPERATION,
1004                    "Loop in class hierarchy: '%S' is an ancestor of '%S'",
1005                    VTABLE_get_string(INTERP, SELF),
1006                    VTABLE_get_string(INTERP, parent));
1007        }
1008
1009        /* Add to the lists of our immediate parents and all parents. */
1010        VTABLE_push_pmc(INTERP, _class->parents, parent);
1011        Parrot_hash_put(INTERP, _class->isa_cache, (void *)parent, (void *)1);
1012        calculate_mro(INTERP, SELF, parent_count + 1);
1013    }
1014
1015/*
1016
1017=item C<void remove_parent(PMC *parent)>
1018
1019Remove the supplied class object from the list of parents for the class.
1020Throws an exception if parent is null, is not a class, or is not a parent, or
1021if the class has been instantiated.
1022
1023=cut
1024
1025*/
1026    VTABLE void remove_parent(PMC *parent) {
1027        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1028        int parent_count, index;
1029
1030        /* If we've been instantiated already, not allowed. */
1031        if (_class->instantiated)
1032            Parrot_ex_throw_from_c_noargs(INTERP,
1033                EXCEPTION_INVALID_OPERATION,
1034                "Modifications to classes are not allowed after instantiation");
1035
1036        /* Ensure it really is a class. */
1037        if (!PObj_is_class_TEST(parent))
1038            Parrot_ex_throw_from_c_noargs(INTERP,
1039                EXCEPTION_INVALID_OPERATION, "Parent isn't a Class");
1040
1041        /* get number of direct parents */
1042        parent_count = VTABLE_elements(INTERP, _class->parents);
1043
1044        /* iterate over all direct parents, looking for the parent to remove */
1045        for (index = 0; index < parent_count; ++index) {
1046            /* get the next parent */
1047            PMC * const current_parent = VTABLE_get_pmc_keyed_int(INTERP,
1048                                      _class->parents, index);
1049            if (current_parent == parent)
1050                break;
1051        }
1052
1053        if (index >= parent_count)
1054            Parrot_ex_throw_from_c_noargs(INTERP,
1055                EXCEPTION_INVALID_OPERATION,
1056                "Can't remove_parent: is not a parent");
1057
1058        VTABLE_delete_keyed_int(INTERP, _class->parents, index);
1059        Parrot_hash_put(INTERP, _class->isa_cache, (void *)parent, (void *)0);
1060        calculate_mro(INTERP, SELF, parent_count - 1);
1061    }
1062
1063/*
1064
1065=item C<void add_role(PMC *role)>
1066
1067Adds the supplied PMC to the list of roles for the class, provided there are
1068no conflicts.
1069
1070=cut
1071
1072*/
1073    VTABLE void add_role(PMC *role) {
1074        const Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1075
1076        /* Do the composition. */
1077        Parrot_ComposeRole(INTERP, role,
1078            _class->resolve_method, !PMC_IS_NULL(_class->resolve_method),
1079           PMCNULL, 0, _class->methods, _class->roles);
1080    }
1081
1082/*
1083
1084=item C<PMC *inspect_str(STRING *what)>
1085
1086Provides introspection of a specific piece of information about the class. The
1087available information is:
1088
1089=over 8
1090
1091=item name
1092
1093String PMC containing the name of the class
1094
1095=item namespace
1096
1097NameSpace PMC of the namespace attached to the class.
1098
1099=item attributes
1100
1101Hash keyed on attribute name, where the value is a hash describing it.
1102
1103=item methods
1104
1105Hash keyed on method name, value is an invokable PMC. Includes methods composed
1106in from roles.
1107
1108=item roles
1109
1110Array of Role PMCs. Includes roles done by the roles that were composed into
1111this class.
1112
1113=item parents
1114
1115Array of Class PMCs representing the direct parents of this class.
1116
1117=back
1118
1119=cut
1120
1121*/
1122    VTABLE PMC *inspect_str(STRING *what) :no_wb {
1123        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1124
1125        /* What should we return? */
1126        PMC *found;
1127
1128        if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "attributes"))) {
1129            found = _class->attrib_metadata;
1130        }
1131        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "parents"))) {
1132            found = _class->parents;
1133        }
1134        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "name"))) {
1135            found = Parrot_pmc_new(INTERP, enum_class_String);
1136            VTABLE_set_string_native(INTERP, found, _class->name);
1137        }
1138        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "id"))) {
1139            found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer, _class->id);
1140        }
1141        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "namespace"))) {
1142            /* Should not clone this. */
1143            return _class->_namespace;
1144        }
1145        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "attrib_index"))) {
1146            found = _class->attrib_index;
1147        }
1148        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "methods"))) {
1149            found = _class->methods;
1150        }
1151        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "vtable_overrides"))) {
1152            found = _class->vtable_overrides;
1153        }
1154        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "all_parents"))) {
1155            found = _class->all_parents;
1156        }
1157        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "roles"))) {
1158            found = _class->roles;
1159        }
1160        else if (STRING_equal(INTERP, what, CONST_STRING(INTERP, "flags"))) {
1161            found = Parrot_pmc_new_init_int(INTERP, enum_class_Integer,
1162                (INTVAL)PObj_get_FLAGS(SELF));
1163        }
1164        else
1165            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
1166                "Unknown introspection value '%S'", what);
1167
1168        /* return found value */
1169        if (PMC_IS_NULL(found))
1170            return PMCNULL;
1171
1172        if (found->vtable->base_type == enum_class_Hash) {
1173            /* for Hash return values, create and return a shallow
1174             * clone because the VTABLE_clone does a deep clone */
1175            PMC * const hash = Parrot_pmc_new(INTERP, enum_class_Hash);
1176            Hash       *src  = (Hash *)VTABLE_get_pointer(interp, found);
1177            Hash       *dest = (Hash *)VTABLE_get_pointer(interp, hash);
1178
1179            Parrot_hash_clone_prunable(interp, src, dest, 0);
1180
1181            return hash;
1182        }
1183
1184        return VTABLE_clone(INTERP, found);
1185    }
1186
1187/*
1188
1189=item C<PMC *inspect()>
1190
1191Returns a Hash describing the class, with key/value pairs as described in
1192inspect_str.
1193
1194=cut
1195
1196*/
1197    VTABLE PMC *inspect() :no_wb {
1198        /* Create a hash, then use inspect_str to get all of the data to
1199         * fill it up with. */
1200        PMC    * const metadata    = Parrot_pmc_new(INTERP, enum_class_Hash);
1201        STRING * const name_str    = CONST_STRING(INTERP, "name");
1202        STRING * const ns_str      = CONST_STRING(INTERP, "namespace");
1203        STRING * const attrs_str   = CONST_STRING(INTERP, "attributes");
1204        STRING * const meths_str   = CONST_STRING(INTERP, "methods");
1205        STRING * const parents_str = CONST_STRING(INTERP, "parents");
1206        STRING * const roles_str   = CONST_STRING(INTERP, "roles");
1207        STRING * const flags_str   = CONST_STRING(INTERP, "flags");
1208
1209        VTABLE_set_pmc_keyed_str(INTERP, metadata, name_str,
1210            VTABLE_inspect_str(INTERP, SELF, name_str));
1211
1212        VTABLE_set_pmc_keyed_str(INTERP, metadata, ns_str,
1213            VTABLE_inspect_str(INTERP, SELF, ns_str));
1214
1215        VTABLE_set_pmc_keyed_str(INTERP, metadata, attrs_str,
1216            VTABLE_inspect_str(INTERP, SELF, attrs_str));
1217
1218        VTABLE_set_pmc_keyed_str(INTERP, metadata, meths_str,
1219            VTABLE_inspect_str(INTERP, SELF, meths_str));
1220
1221        VTABLE_set_pmc_keyed_str(INTERP, metadata, parents_str,
1222            VTABLE_inspect_str(INTERP, SELF, parents_str));
1223
1224        VTABLE_set_pmc_keyed_str(INTERP, metadata, roles_str,
1225            VTABLE_inspect_str(INTERP, SELF, roles_str));
1226
1227        VTABLE_set_pmc_keyed_str(INTERP, metadata, flags_str,
1228            VTABLE_inspect_str(INTERP, SELF, flags_str));
1229
1230        return metadata;
1231    }
1232
1233/*
1234
1235=item C<PMC *clone()>
1236
1237Returns an anonymous copy of the class (with no name and no link to a
1238namespace). Unsets the instantiated flag, allowing modifications.
1239
1240=cut
1241
1242*/
1243
1244    VTABLE PMC *clone() :no_wb {
1245        Parrot_Class_attributes * const _class    = PARROT_CLASS(SELF);
1246
1247        /* Create the new class PMC, of the same type of this one (we may
1248         * have been subclassed). */
1249        PMC          * const copy      = SUPER();
1250
1251        /* Clone parents, roles, methods, attributes and resolve data. We do
1252         * not copy name/namespace related stuff (need anonymous clone) or
1253         * stuff that gets computed on the first instantiation. */
1254
1255        Parrot_Class_attributes * const new_class = PARROT_CLASS(copy);
1256
1257        new_class->name                = CONST_STRING(INTERP, "");
1258        new_class->_namespace          = PMCNULL;
1259        new_class->parents             = VTABLE_clone(INTERP, _class->parents);
1260        new_class->roles               = VTABLE_clone(INTERP, _class->roles);
1261        new_class->methods             = VTABLE_clone(INTERP, _class->methods);
1262        new_class->vtable_overrides    = VTABLE_clone(INTERP,
1263                                            _class->vtable_overrides);
1264        new_class->parent_overrides    = VTABLE_clone(INTERP,
1265                                            _class->parent_overrides);
1266        new_class->attrib_metadata     = VTABLE_clone(INTERP,
1267                                            _class->attrib_metadata);
1268        new_class->resolve_method      = VTABLE_clone(INTERP,
1269                                            _class->resolve_method);
1270
1271        /* Return cloned class. */
1272        return copy;
1273    }
1274
1275/*
1276
1277=item C<PMC *clone_pmc(PMC *args)>
1278
1279Makes a copy of the class, then modifies or adds to it based upon the contents
1280of the supplied initialization data. If a new name or namespace is not supplied
1281in C<args> then the cloned class will be anonymous. The instantiated flag is
1282unset to allow further modifications.
1283
1284=cut
1285
1286*/
1287
1288    VTABLE PMC *clone_pmc(PMC *args) :no_wb {
1289        /* Do the standard clone. */
1290        PMC * const copy = SELF.clone();
1291
1292        init_class_from_hash(INTERP, copy, args);
1293
1294        return copy;
1295    }
1296
1297/*
1298
1299=item C<PMC *instantiate(PMC *init)>
1300
1301Creates a new PMC object of the type of the class and calls init().
1302
1303=cut
1304
1305*/
1306
1307    VTABLE PMC *instantiate(PMC *init) :manual_wb {
1308        Parrot_Class_attributes  * const _class = PARROT_CLASS(SELF);
1309        PMC                      *object;
1310
1311        /* If we've not been instantiated before... */
1312        if (!_class->instantiated) {
1313            /* Check that we have all methods listed in resolve list. */
1314            const int resolve_count  = VTABLE_elements(INTERP,
1315                                                       _class->resolve_method);
1316            const INTVAL cur_hll     = Parrot_pcc_get_HLL(INTERP, CURRENT_CONTEXT(INTERP));
1317            const INTVAL num_parents = VTABLE_elements(INTERP, _class->parents);
1318            INTVAL       mro_length;
1319            int          i;
1320
1321            /* don't use HLL mappings for internal-only data */
1322            Parrot_pcc_set_HLL(INTERP, CURRENT_CONTEXT(INTERP), 0);
1323
1324            for (i = 0; i < resolve_count; ++i) {
1325                STRING * const check_meth =
1326                    VTABLE_get_string_keyed_int(INTERP, _class->resolve_method, i);
1327                if (!VTABLE_exists_keyed_str(INTERP, _class->methods, check_meth))
1328                    Parrot_ex_throw_from_c_args(INTERP, NULL,
1329                        EXCEPTION_METHOD_NOT_FOUND, "The method '%S' was named "
1330                        "in the resolve list, but not supplied", check_meth);
1331            }
1332
1333            /* Build full parents list. */
1334            calculate_mro(INTERP, SELF, num_parents);
1335            build_attrib_index(INTERP, SELF);
1336
1337            if (PMC_IS_NULL(_class->attrib_index)) {
1338                return PMCNULL;
1339            }
1340
1341            /* See if we have any parents from other universes and if so set a
1342             * flag stating so. */
1343            mro_length = VTABLE_elements(INTERP, _class->all_parents);
1344
1345            for (i = 0; i < mro_length; ++i) {
1346                PMC * const class_check = VTABLE_get_pmc_keyed_int(INTERP,
1347                    _class->all_parents, i);
1348                if (class_check->vtable->base_type != enum_class_Class) {
1349                    /* Found one; that's enough. */
1350                    CLASS_has_alien_parents_SET(SELF);
1351                    break;
1352                }
1353            }
1354
1355            Parrot_pcc_set_HLL(INTERP, CURRENT_CONTEXT(INTERP), cur_hll);
1356        }
1357
1358        /* Set instantiated flag. */
1359        _class->instantiated = 1;
1360
1361        /* Create object. */
1362        object = Parrot_pmc_new_noinit(INTERP, enum_class_Object);
1363
1364        /* Set custom GC mark and destroy on the object. */
1365        PObj_custom_mark_destroy_SETALL(object);
1366
1367        /* Flag that it is an object */
1368        PObj_is_object_SET(object);
1369
1370        /* Initialize the object's underlying structure, pointing it to this
1371         * class. */
1372        /* TODO: this has been changed in order to use auto_attrs in the
1373         * Object PMC. Needs to be redone in a cleaner way. */
1374        {
1375            Parrot_Object_attributes * const objattr =
1376                PMC_data_typed(object, Parrot_Object_attributes *);
1377            objattr->_class       = SELF;
1378            /* Big L1 Instr fetch miss */
1379            objattr->attrib_store =
1380                Parrot_pmc_new_init_int(INTERP, enum_class_ResizablePMCArray,
1381                        VTABLE_elements(INTERP, _class->attrib_index));
1382            PARROT_GC_WRITE_BARRIER(INTERP, object);
1383        }
1384
1385        if (!PMC_IS_NULL(init)) {
1386            /* Initialize attributes with the supplied values. */
1387            PMC * const iter = VTABLE_get_iter(INTERP, init);
1388
1389            while (VTABLE_get_bool(INTERP, iter)) {
1390                STRING * const name  = VTABLE_shift_string(INTERP, iter);
1391                PMC    * const value = VTABLE_get_pmc_keyed_str(INTERP, init,
1392                                            name);
1393
1394                /* Set the attribute. */
1395                VTABLE_set_attr_str(INTERP, object, name, value);
1396            }
1397
1398            /* Check for overrides on the init_pmc vtable function */
1399            initialize_parents_pmc(INTERP, object, _class->all_parents, init);
1400        }
1401        else
1402            /* Check for overrides on the init vtable function */
1403            initialize_parents(INTERP, object, _class->all_parents);
1404
1405        return object;
1406    }
1407
1408
1409/*
1410
1411=item C<INTVAL isa_pmc(PMC *class)>
1412
1413Returns whether the class is or inherits from C<*class>.
1414
1415=cut
1416
1417*/
1418
1419    VTABLE INTVAL isa_pmc(PMC *lookup) :manual_wb {
1420        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1421        PMC          *classobj;
1422        HashBucket   *b;
1423        INTVAL        i, num_classes, retval = 0;
1424
1425        if (PMC_IS_NULL(lookup))
1426            return 0;
1427
1428        if (PObj_is_class_TEST(lookup)) {
1429            if (lookup == SELF)
1430                return 1;
1431            else
1432                classobj = lookup;
1433        }
1434        else
1435            classobj = Parrot_oo_get_class(INTERP, lookup);
1436
1437        if (PMC_IS_NULL(classobj))
1438            return 0;
1439
1440        /* Check if the class object is the same as self's class object */
1441        if (VTABLE_is_same(INTERP, SELF, classobj))
1442            goto found;
1443
1444        if (_class->instantiated) {
1445            b = Parrot_hash_get_bucket(INTERP, _class->isa_cache,
1446                 (void *)classobj);
1447            if (b)
1448                return PTR2INTVAL(b->value);
1449        }
1450
1451        /* this is effectively what the default PMC's isa_pmc does
1452         * ... but this can cheat and avoid COW STRINGs for the classobj
1453         * only in these two, very specific and common cases */
1454        if (classobj->vtable->base_type == enum_class_Class
1455        ||  classobj->vtable->base_type == enum_class_PMCProxy) {
1456            STRING *classname = make_class_name(INTERP, classobj);
1457            PARROT_ASSERT(SELF->vtable->isa_hash);
1458            if (Parrot_hash_exists(INTERP, SELF->vtable->isa_hash, classname))
1459                goto found;
1460        }
1461
1462        /* Iterate over all the parents and check if they respond true
1463         * for 'isa' on the original comparison. */
1464        num_classes = VTABLE_elements(INTERP, _class->parents);
1465
1466        for (i = 0; i < num_classes; ++i) {
1467            PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1468                    _class->parents, i);
1469
1470            if (VTABLE_isa_pmc(INTERP, cur_class, lookup))
1471                goto found;
1472        }
1473
1474    cache_and_return:
1475        if (_class->instantiated) {
1476            PARROT_GC_WRITE_BARRIER(INTERP, SELF);
1477            Parrot_hash_put(INTERP, _class->isa_cache, (void *)classobj,
1478                            INTVAL2PTR(void *, retval));
1479        }
1480        return retval;
1481
1482    found:
1483        retval = 1;
1484        goto cache_and_return;
1485    }
1486
1487/*
1488
1489=item C<INTVAL isa(STRING *classname)>
1490
1491Returns whether the class is or inherits from C<*classname>.
1492
1493=cut
1494
1495*/
1496
1497    VTABLE INTVAL isa(STRING *classname) :no_wb {
1498        PMC *want_class;
1499
1500        /* hard-code this one exception right away */
1501        if (STRING_equal(INTERP, classname, CONST_STRING(INTERP, "Class")))
1502            return 1;
1503
1504        want_class = Parrot_oo_get_class_str(INTERP, classname);
1505
1506        if (PMC_IS_NULL(want_class))
1507            return 0;
1508
1509        if (SELF == want_class)
1510            return 1;
1511        else {
1512            Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1513
1514            const INTVAL num_classes = VTABLE_elements(INTERP, _class->all_parents);
1515            int i;
1516
1517            for (i = 1; i < num_classes; ++i) {
1518                PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1519                                            _class->all_parents, i);
1520
1521                if (VTABLE_is_same(INTERP, want_class, cur_class))
1522                    return 1;
1523            }
1524        }
1525
1526        return 0;
1527    }
1528
1529/*
1530
1531=item C<INTVAL does(STRING *role_name)>
1532
1533Returns whether the class does the role with the given C<*role_name>.
1534
1535=cut
1536
1537*/
1538    VTABLE INTVAL does(STRING *role_name) :no_wb {
1539        Parrot_Class_attributes * const _class    = PARROT_CLASS(SELF);
1540        PMC          * const role_list = _class->roles;
1541        INTVAL i, count;
1542
1543        if (!role_list)
1544            return 0;
1545
1546        count = VTABLE_elements(INTERP, role_list);
1547
1548        for (i = 0; i < count; ++i) {
1549            PMC * const role = VTABLE_get_pmc_keyed_int(INTERP, role_list, i);
1550
1551            if (VTABLE_does(INTERP, role, role_name))
1552                return 1;
1553        }
1554
1555        /* Iterate over all the parents and check if they respond true
1556         * for 'does' on the original comparison. */
1557        count = VTABLE_elements(INTERP, _class->parents);
1558
1559        for (i = 0; i < count; ++i) {
1560            PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1561                    _class->parents, i);
1562
1563            if (VTABLE_does(INTERP, cur_class, role_name))
1564                return 1;
1565        }
1566
1567        return VTABLE_isa(INTERP, SELF, role_name);
1568    }
1569
1570/*
1571
1572=item C<INTVAL does_pmc(PMC *role)>
1573
1574Returns whether the class does the given C<*role>.
1575
1576=cut
1577
1578*/
1579    VTABLE INTVAL does_pmc(PMC *role) :no_wb {
1580        Parrot_Class_attributes * const _class    = PARROT_CLASS(SELF);
1581        PMC * const role_list          = _class->roles;
1582        INTVAL i, role_count, count;
1583
1584        if (!role_list)
1585            return 0;
1586
1587        role_count = VTABLE_elements(INTERP, role_list);
1588
1589        for (i = 0; i < role_count; ++i) {
1590            PMC    * const test_role = VTABLE_get_pmc_keyed_int(INTERP, role_list, i);
1591            if (VTABLE_does_pmc(INTERP, test_role, role))
1592                return 1;
1593        }
1594
1595        /* Iterate over all the parents and check if they respond true
1596         * for 'does' on the original comparison. */
1597        count = VTABLE_elements(INTERP, _class->parents);
1598
1599        for (i = 0; i < count; ++i) {
1600            PMC * const cur_class = VTABLE_get_pmc_keyed_int(INTERP,
1601                    _class->parents, i);
1602
1603            if (VTABLE_does_pmc(INTERP, cur_class, role))
1604                return 1;
1605        }
1606
1607        return VTABLE_isa_pmc(INTERP, SELF, role);
1608    }
1609
1610    VTABLE INTVAL is_equal(PMC * p) :no_wb {
1611        UNUSED(INTERP)
1612        return p == SELF;
1613    }
1614
1615/*
1616
1617=item C<INTVAL type()>
1618
1619Returns the integer type of the class.
1620
1621=cut
1622
1623*/
1624
1625    VTABLE INTVAL type() :no_wb {
1626        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1627        UNUSED(INTERP)
1628        return _class->id;
1629    }
1630
1631/*
1632
1633=item C<void visit(PMC *info)>
1634
1635This is used by freeze/thaw to visit the contents of the class.
1636
1637C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).
1638
1639=cut
1640
1641*/
1642
1643    VTABLE void visit(PMC *info) :no_wb {
1644        /* 1) visit the attribute description hash */
1645        VISIT_PMC_ATTR(INTERP, info, SELF, Class, attrib_metadata);
1646
1647        /* 2) visit list of parents */
1648        VISIT_PMC_ATTR(INTERP, info, SELF, Class, parents);
1649
1650        /* 3) visit list of roles */
1651        VISIT_PMC_ATTR(INTERP, info, SELF, Class, roles);
1652
1653        /* 4) visit hash of methods */
1654        VISIT_PMC_ATTR(INTERP, info, SELF, Class, methods);
1655
1656        /* 5) visit hash of vtable overrides */
1657        VISIT_PMC_ATTR(INTERP, info, SELF, Class, vtable_overrides);
1658
1659        /* 6) visit list of resolve methods */
1660        VISIT_PMC_ATTR(INTERP, info, SELF, Class, resolve_method);
1661    }
1662
1663/*
1664
1665=item C<void freeze(PMC *info)>
1666
1667Used to archive the class.
1668
1669=cut
1670
1671*/
1672
1673    VTABLE void freeze(PMC *info) :no_wb {
1674        Parrot_Class_attributes * const class_data = PARROT_CLASS(SELF);
1675        STRING       *serial_namespace = CONST_STRING(INTERP, "");
1676
1677        /* 1) freeze class id */
1678        VTABLE_push_integer(INTERP, info, class_data->id);
1679
1680        /* 2) freeze class name */
1681        VTABLE_push_string(INTERP, info, class_data->name);
1682
1683        /* 3) serialize namespace name, including HLL */
1684        if (!PMC_IS_NULL(class_data->_namespace)) {
1685            PMC * const names = Parrot_ns_get_name(INTERP,
1686                    class_data->_namespace);
1687            if (!PMC_IS_NULL(names))
1688                serial_namespace = Parrot_str_join(INTERP, CONST_STRING(INTERP, ";"), names);
1689        }
1690        VTABLE_push_string(INTERP, info, serial_namespace);
1691        /* PARROT_GC_WRITE_BARRIER(INTERP, info); */
1692    }
1693
1694/*
1695
1696=item C<void thaw(PMC *info)>
1697
1698Used to unarchive the class.
1699
1700=cut
1701
1702*/
1703
1704    VTABLE void thaw(PMC *info) {
1705        /* The class might already exist in the interpreter, so create it as an
1706         * anonymous class and later decide whether to link it into the
1707         * namespace.  */
1708
1709        /* 1) thaw class id */
1710        const INTVAL id = VTABLE_shift_integer(INTERP, info);
1711
1712        /* 2) thaw class name */
1713        STRING * const name = VTABLE_shift_string(INTERP, info);
1714
1715        /* 3) deserialize namespace name, including HLL */
1716        STRING * const serial_namespace = VTABLE_shift_string(INTERP, info);
1717        STRING * const semicolon_str = CONST_STRING(INTERP, ";");
1718        PMC    * const namespace_array =
1719            Parrot_str_split(INTERP, semicolon_str, serial_namespace);
1720        PMC *ns = Parrot_ns_get_namespace_keyed(INTERP,
1721                INTERP->root_namespace, namespace_array);
1722
1723        /* If the namespace doesn't exist, we create it, and initialize
1724         * ourselves in it */
1725        if (PMC_IS_NULL(ns)) {
1726            ns = Parrot_ns_make_namespace_keyed(INTERP,
1727                    INTERP->root_namespace, namespace_array);
1728            SELF.init_pmc(ns);
1729        }
1730        /* If the namespace exists already, we point to it, but otherwise
1731         * act as an anonymous class. */
1732        else {
1733            SELF.init();
1734            PARROT_CLASS(SELF)->_namespace = ns;
1735        }
1736
1737        /* Set the class's short name to the frozen name */
1738        PARROT_CLASS(SELF)->name = name;
1739
1740        /* Set the class's id the frozen id */
1741        PARROT_CLASS(SELF)->id = id;
1742    }
1743
1744/*
1745
1746=item C<INTVAL get_integer()>
1747
1748This is just a temporary hack. Type ID numbers shouldn't be externally
1749visible to the average PIR user. However, we need this for now to interface
1750with functions like Parrot_pmc_new and pmc_reuse, which take type ID numbers still.
1751
1752=cut
1753
1754*/
1755
1756    VTABLE INTVAL get_integer() :no_wb {
1757        UNUSED(INTERP)
1758        return PARROT_CLASS(SELF)->id;
1759    }
1760
1761/*
1762
1763=item C<void thawfinish(PMC *info)>
1764
1765Called after the class has been thawed.
1766
1767=cut
1768
1769*/
1770
1771    VTABLE void thawfinish(PMC *info) :manual_wb {
1772        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1773        UNUSED(info)
1774
1775        /* Recalculate full MRO from thawed parents */
1776        _class->all_parents         = Parrot_ComputeMRO_C3(INTERP, SELF);
1777        _class->parent_overrides    = Parrot_pmc_new(INTERP, enum_class_Hash);
1778
1779        /* Rebuild attribute index from thawed attribute metadata */
1780        build_attrib_index(INTERP, SELF); /* calls PARROT_GC_WRITE_BARRIER */
1781    }
1782
1783    /* **********************************************************************
1784     * Below here are methods that eventually will go in a role
1785     * that is composed into here to optionally give a nice interface from
1786     * PIR (ParrotClass isa Class does ClassMethods or something like this).
1787     * **********************************************************************/
1788
1789/*
1790
1791=item C<void name(STRING *name :optional, int has_name :opt_flag)>
1792
1793Sets the name of the class, and updates the namespace accordingly.
1794
1795=cut
1796
1797*/
1798    METHOD name(STRING *name :optional, int has_name :opt_flag) :manual_wb {
1799        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
1800        STRING *ret_name;
1801
1802        if (has_name) {
1803            /* We'll build a hash just containing the name, then give this to
1804             * init_class_from_hash - saves some code duplication. */
1805            PMC    * const naming_hash = Parrot_pmc_new(INTERP, enum_class_Hash);
1806            STRING * const name_str    = CONST_STRING(INTERP, "name");
1807
1808            VTABLE_set_string_keyed_str(INTERP, naming_hash, name_str, name);
1809            init_class_from_hash(INTERP, SELF, naming_hash);
1810            PARROT_GC_WRITE_BARRIER(INTERP, SELF);
1811        }
1812
1813        ret_name = _class->name;
1814        RETURN(STRING *ret_name);
1815    }
1816
1817/*
1818
1819=item C<void get_namespace()>
1820
1821Gets the namespace that this class is attached to.
1822
1823=cut
1824
1825*/
1826    METHOD get_namespace(PMC *_namespace :optional, int has_name :opt_flag) :no_wb {
1827        Parrot_Class_attributes * const _class        = PARROT_CLASS(SELF);
1828        PMC          * const ret_namespace = _class->_namespace;
1829        UNUSED(_namespace);
1830        UNUSED(has_name);
1831        RETURN(PMC *ret_namespace);
1832    }
1833
1834/*
1835
1836=item C<void resolve_method()>
1837
1838Sets the list of method names that the class provides to resolve conflicts in
1839methods from roles. When called with no parameter, returns the list.
1840
1841=cut
1842
1843*/
1844    METHOD resolve_method(PMC *resolve_list :optional, int has_list :opt_flag) :manual_wb {
1845        Parrot_Class_attributes * const _class   = PARROT_CLASS(SELF);
1846        PMC *ret_list;
1847
1848        /* Store list. */
1849        if (has_list) {
1850            _class->resolve_method = resolve_list;
1851            PARROT_GC_WRITE_BARRIER(INTERP, SELF);
1852        }
1853
1854        ret_list = _class->resolve_method;
1855        RETURN(PMC *ret_list);
1856    }
1857
1858/*
1859
1860=item C<void new(PMC *args :slurpy :named)>
1861
1862Creates an instance of the object. Initializes any attributes specified in the
1863parameter list.
1864
1865=cut
1866
1867*/
1868    METHOD new(PMC *args :slurpy :named) {
1869        /* Check if any arguments are in the slurpy hash, don't pass an empty
1870         * hash to instantiate */
1871        PMC * const obj =
1872            VTABLE_elements(INTERP, args) > 0
1873                ? VTABLE_instantiate(INTERP, SELF, args)
1874                : VTABLE_instantiate(INTERP, SELF, PMCNULL);
1875
1876        RETURN(PMC *obj);
1877     }
1878
1879/*
1880
1881=item C<void attributes()>
1882
1883Return a hash where the keys are attribute names and the values are hashes
1884providing a set of key/value pairs describing the attribute.
1885
1886=cut
1887
1888*/
1889    METHOD attributes() {
1890        STRING * const attr_str            = CONST_STRING(INTERP, "attributes");
1891        PMC    * const ret_attrib_metadata = SELF.inspect_str(attr_str);
1892
1893        RETURN(PMC *ret_attrib_metadata);
1894    }
1895
1896/*
1897
1898=item C<void add_attribute()>
1899
1900Add an attribute to the class. Requires a name and, optionally, a type.
1901
1902=cut
1903
1904*/
1905    METHOD add_attribute(STRING *attribute_name,
1906            PMC *attribute_type :optional, int has_type :opt_flag) {
1907        PMC * const type = has_type ? attribute_type : PMCNULL;
1908        SELF.add_attribute(attribute_name, type);
1909    }
1910
1911/*
1912
1913=item C<void methods()>
1914
1915Return a hash where the keys are method names and the values are methods.
1916
1917=cut
1918
1919*/
1920    METHOD methods() :no_wb {
1921        PMC * const ret_methods = SELF.inspect_str(CONST_STRING(INTERP, "methods"));
1922
1923        RETURN(PMC *ret_methods);
1924    }
1925
1926/*
1927
1928=item C<void add_method(STRING *name, PMC *sub)>
1929
1930Adds the given sub PMC as a method with the given name. Delegates to the
1931C<add_method> vtable.
1932
1933=cut
1934
1935*/
1936    METHOD add_method(STRING *name, PMC *sub) :manual_wb {
1937        SELF.add_method(name, sub);
1938    }
1939
1940/*
1941
1942=item C<void add_vtable_override(STRING *name, PMC *sub)>
1943
1944Adds the given sub PMC as a vtable override with the given name. Delegates to
1945the C<add_vtable_override> vtable.
1946
1947=cut
1948
1949*/
1950    METHOD add_vtable_override(STRING *name, PMC *sub) :manual_wb {
1951        VTABLE_add_vtable_override(INTERP, SELF, name, sub);
1952    }
1953
1954/*
1955
1956=item C<void remove_method(STRING *name)>
1957
1958Removes the method with the given name.
1959
1960=cut
1961
1962*/
1963    METHOD remove_method(STRING *name) :manual_wb {
1964        VTABLE_remove_method(INTERP, SELF, name);
1965    }
1966
1967/*
1968
1969=item C<PMC *find_method(STRING *name)>
1970
1971Walks the MRO of the class and finds the method with the given name.
1972
1973=cut
1974
1975*/
1976
1977    METHOD find_method(STRING *name) :no_wb {
1978        Parrot_Class_attributes * const  _class    = PARROT_CLASS(SELF);
1979        int i;
1980
1981        /* Walk and search. One day, we'll use the cache first. */
1982        const int num_classes = VTABLE_elements(INTERP, _class->all_parents);
1983
1984        for (i = 0; i < num_classes; ++i) {
1985            /* Get the class and see if it has the method. */
1986            PMC * const cur_class =
1987                VTABLE_get_pmc_keyed_int(INTERP, _class->all_parents, i);
1988            const Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class);
1989
1990            /* Found it! */
1991            if (VTABLE_exists_keyed_str(INTERP, class_info->methods, name)) {
1992                PMC * const ret = VTABLE_get_pmc_keyed_str(INTERP, class_info->methods, name);
1993                RETURN(PMC *ret);
1994            }
1995        }
1996
1997        RETURN(PMC *PMCNULL);
1998    }
1999
2000/*
2001
2002=item C<void parents()>
2003
2004Returns the parents array PMC.
2005
2006=cut
2007
2008*/
2009    METHOD parents() :no_wb {
2010        PMC * const ret_parents = SELF.inspect_str(CONST_STRING(INTERP, "parents"));
2011
2012        RETURN(PMC *ret_parents);
2013    }
2014
2015/*
2016
2017=item C<void add_parent(PMC *parent)>
2018
2019Adds the supplied PMC to the list of parents for the class.
2020
2021=cut
2022
2023*/
2024    METHOD add_parent(PMC *parent) :manual_wb {
2025        SELF.add_parent(parent);
2026    }
2027
2028/*
2029
2030=item C<void roles()>
2031
2032Returns the roles array PMC.
2033
2034=cut
2035
2036*/
2037    METHOD roles() :no_wb {
2038        PMC * const ret_roles = SELF.inspect_str(CONST_STRING(INTERP, "roles"));
2039
2040        RETURN(PMC *ret_roles);
2041    }
2042
2043/*
2044
2045=item C<void add_role(PMC *role, PMC *exclude :optional :named("exclude"),
2046PMC *alias :optional :named("alias"))>
2047
2048Composes a role into a class with the given exclusions and aliases.
2049
2050=cut
2051
2052*/
2053    METHOD add_role(PMC *role,
2054            PMC *exclude_method     :optional :named("exclude_method"),
2055            int has_exclude_method  :opt_flag,
2056            PMC *alias_method       :optional :named("alias_method"),
2057            int has_alias_method    :opt_flag) {
2058
2059        Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
2060
2061        /* Add everything on the resolve list to the exclude list; if we have
2062         * no exclude list, pass along the resolve list in its place if it has
2063         * any methods listed in it. */
2064        if (!has_exclude_method) {
2065            if (VTABLE_elements(INTERP, _class->resolve_method) != 0) {
2066                exclude_method     = _class->resolve_method;
2067                has_exclude_method = 1;
2068            }
2069        }
2070        else {
2071            const int resolve_count = VTABLE_elements(INTERP, _class->resolve_method);
2072            int i;
2073
2074            for (i = 0; i < resolve_count; ++i) {
2075                STRING * const meth_name = VTABLE_get_string_keyed_int(INTERP,
2076                    _class->resolve_method, i);
2077                VTABLE_push_string(INTERP, exclude_method, meth_name);
2078            }
2079        }
2080
2081        /* Do the composition. */
2082        Parrot_ComposeRole(INTERP, role, exclude_method, has_exclude_method,
2083                           alias_method, has_alias_method,
2084                           _class->methods, _class->roles);
2085    }
2086
2087/*
2088
2089=item C<void inspect(STRING *what :optional)>
2090
2091Gets all introspection data for the class or, if the optional string
2092parameter is supplied, a particular item of introspection data.
2093
2094=cut
2095
2096*/
2097    METHOD inspect(STRING *what :optional, int has_what :opt_flag) :no_wb {
2098        PMC *found;
2099
2100        /* Just delegate to the appropriate vtable. */
2101        if (has_what)
2102            found = SELF.inspect_str(what);
2103        else
2104            found = SELF.inspect();
2105
2106        RETURN(PMC *found);
2107    }
2108
2109/*
2110
2111=item C<void isa(STRING *class_name)>
2112
2113Returns true if this object is or derives from the class named in
2114C<class_name>, false otherwise.
2115
2116=cut
2117
2118*/
2119    METHOD isa(STRING *class_name) :no_wb {
2120        const INTVAL isa = SELF.isa(class_name);
2121
2122        RETURN(INTVAL isa);
2123    }
2124
2125/*
2126
2127=item C<void does(STRING *role_name)>
2128
2129Returns true if this object or one of its parents performs the named role,
2130false otherwise.
2131
2132=cut
2133
2134*/
2135    METHOD does(STRING *role_name) :no_wb {
2136        const INTVAL does = VTABLE_does(INTERP, SELF, role_name);
2137        RETURN(INTVAL does);
2138    }
2139
2140    METHOD clear_method_cache() {
2141        Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF);
2142        PMC * const cache = attrs->meth_cache;
2143        if (cache)
2144            attrs->meth_cache = PMCNULL;
2145    }
2146
2147    METHOD get_method_cache() :no_wb {
2148        Parrot_Class_attributes * const attrs = PARROT_CLASS(SELF);
2149        PMC * cache = attrs->meth_cache;
2150        if (!cache) {
2151            cache = Parrot_pmc_new(INTERP, enum_class_Hash);
2152            attrs->meth_cache = cache;
2153        }
2154        RETURN(PMC *cache);
2155    }
2156
2157} /* END pmclass */
2158
2159/*
2160
2161=back
2162
2163=head1 SEE ALSO
2164
2165F<docs/pdds/pdd15_objects.pod>.
2166
2167=cut
2168
2169*/
2170
2171/*
2172 * Local variables:
2173 *   c-file-style: "parrot"
2174 * End:
2175 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
2176 */
2177