+ (Parrot_class_offset): Make "Not an object" a real_exception.
[parrot.git] / src / objects.c
bloba82e5b6166cb726475a731e6f0567a0789c55b74
1 /*
2 Copyright (C) 2001-2003, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 objects.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_OBJECTS_C
22 #include "parrot/parrot.h"
23 #include <assert.h>
25 #include "objects.str"
27 static void parrot_class_register(Interp * , PMC *name,
28 PMC *new_class, PMC *parent, PMC *mro);
32 =item C<int Parrot_is_vtable_name(Interp *, const char *name)>
34 Return true if C<name> is a valid vtable slot name.
36 =cut
40 int
41 Parrot_is_vtable_name(Interp *interp, const char *name)
43 int i;
44 const char *meth;
45 for (i = 0; (meth = Parrot_vtable_slot_names[i]); ++i) {
46 if (!*meth)
47 continue;
48 /* XXX slot_names still have __ in front */
49 if (strcmp(name, meth + 2) == 0)
50 return 1;
52 return 0;
55 STRING*
56 readable_name(Interp *interp, PMC *name)
58 if (name->vtable->base_type == enum_class_String)
59 return VTABLE_get_string(interp, name);
60 else {
61 STRING *j = CONST_STRING(interp, ";");
62 PMC *ar = pmc_new(interp, enum_class_ResizableStringArray);
63 assert(name->vtable->base_type == enum_class_Key);
64 while (name) {
65 VTABLE_push_string(interp, ar, key_string(interp, name));
66 name = key_next(interp, name);
68 return string_join(interp, j, ar);
72 static void
73 fail_if_exist(Interp *interp, PMC *name)
75 STRING *class_name;
76 INTVAL type;
78 PMC * const classname_hash = interp->class_hash;
79 PMC * type_pmc = VTABLE_get_pointer_keyed(interp,
80 classname_hash, name);
81 if (PMC_IS_NULL(type_pmc) ||
82 type_pmc->vtable->base_type == enum_class_NameSpace)
83 type = 0;
84 else
85 type = VTABLE_get_integer(interp, type_pmc);
86 /* TODO get printable name */
87 class_name = VTABLE_get_string(interp, name);
88 if (type > enum_type_undef) {
89 real_exception(interp, NULL, INVALID_OPERATION,
90 "Class %Ss already registered!\n", class_name);
92 if (type < enum_type_undef) {
93 real_exception(interp, NULL, INVALID_OPERATION,
94 "native type with name '%s' already exists - "
95 "can't register Class", data_types[type].name);
100 * FIXME make array clone shallow
102 static PMC *
103 clone_array(Interp *interp, PMC *source_array)
105 PMC * const new_array = pmc_new(interp,
106 source_array->vtable->base_type);
107 const INTVAL count = VTABLE_elements(interp, source_array);
108 INTVAL i;
111 * preserve type, we have OrderedHash and Array
112 * XXX this doesn't preserve the keys of the ordered hash
113 * (but the keys aren't used -leo)
115 VTABLE_set_integer_native(interp, new_array, count);
116 for (i = 0; i < count; i++) {
117 VTABLE_set_pmc_keyed_int(interp, new_array, i,
118 VTABLE_get_pmc_keyed_int(interp, source_array, i));
120 return new_array;
123 /* Take the class and completely rebuild the attribute stuff for
124 it. Horribly destructive, and definitely not a good thing to do if
125 there are instantiated objects for the class */
126 static void
127 rebuild_attrib_stuff(Interp *interp, PMC *class)
129 INTVAL cur_offset;
130 SLOTTYPE *class_slots;
131 PMC *attr_offset_hash;
132 PMC *mro;
133 STRING *classname;
134 INTVAL n_class;
135 INTVAL n_mro;
136 PMC *attribs;
137 INTVAL attr_count;
138 #ifndef NDEBUG
139 PMC * const orig_class = class;
140 #endif
142 /* attrib count isn't set yet, a GC causedd by concat could
143 * corrupt data under construction
145 Parrot_block_DOD(interp);
147 class_slots = PMC_data(class);
148 attr_offset_hash = pmc_new(interp, enum_class_Hash);
149 set_attrib_num(class, class_slots, PCD_ATTRIBUTES, attr_offset_hash);
151 mro = class->vtable->mro;
152 n_mro = VTABLE_elements(interp, mro);
155 * walk from oldest parent downto n_class == 0 which is this class
157 cur_offset = 0;
158 for (n_class = n_mro - 1; n_class >= 0; --n_class) {
159 class = VTABLE_get_pmc_keyed_int(interp, mro, n_class);
160 if (!PObj_is_class_TEST(class)) {
161 /* this Class isa PMC - no attributes there
163 continue;
166 class_slots = PMC_data(class);
167 classname = VTABLE_get_string(interp,
168 get_attrib_num(class_slots, PCD_CLASS_NAME));
169 attribs = get_attrib_num(class_slots, PCD_CLASS_ATTRIBUTES);
170 attr_count = VTABLE_elements(interp, attribs);
171 if (attr_count) {
172 INTVAL offset;
174 STRING * const partial_name =
175 string_concat(interp, classname,
176 string_from_cstring(interp, "\0", 1),
178 for (offset = 0; offset < attr_count; offset++) {
179 STRING * const attr_name =
180 VTABLE_get_string_keyed_int(interp, attribs, offset);
181 STRING * const full_name =
182 string_concat(interp, partial_name, attr_name, 0);
184 * store this attribute with short and full name
186 VTABLE_set_integer_keyed_str(interp, attr_offset_hash,
187 attr_name, cur_offset);
188 VTABLE_set_integer_keyed_str(interp, attr_offset_hash,
189 full_name, cur_offset++);
194 #ifndef NDEBUG
195 assert(class == orig_class);
196 #endif
198 /* And note the totals */
199 CLASS_ATTRIB_COUNT(class) = cur_offset;
200 Parrot_unblock_DOD(interp);
205 =item C<static PMC *find_vtable_override_byname(Interp *interp,
206 PMC *class,
207 STRING *method_name)>
209 Tries to locate a PIR override method for the given v-table method in the
210 given class. If one is found, returns the method.
212 =cut
216 static PMC*
217 find_vtable_override_byname(Interp *interp, PMC *class_name,
218 STRING *method_name)
220 /* First try it in the :vtable namespace. */
221 STRING* vtable_str = string_from_const_cstring(interp,
222 "\0VTABLE\0", 8);
223 PMC *ns = Parrot_find_global_k(interp, class_name, vtable_str);
224 if (!PMC_IS_NULL(ns)) {
225 STRING *no_underscores = string_substr(interp, method_name,
226 2, method_name->strlen - 2, NULL, 0);
227 PMC *res = VTABLE_get_pmc_keyed_str(interp, ns,
228 no_underscores);
229 if (!PMC_IS_NULL(res))
230 return res;
233 /* Otherwise, do lookup in the old way. */
234 return Parrot_find_global_k(interp, class_name, method_name);
239 =item C<static void create_deleg_pmc_vtable(Interp *, PMC *class,
240 PMC *class_name, int full)>
242 Create a vtable that dispatches either to the contained PMC in the first
243 attribute (deleg_pmc) or to an overridden method (delegate), depending
244 on the existence of the method for this class.
246 =cut
250 static void
251 create_deleg_pmc_vtable(Interp *interp, PMC *class,
252 PMC *class_name, int full)
254 int i;
255 const char *meth;
256 STRING meth_str;
257 DECL_CONST_CAST;
259 PMC * const vtable_pmc = get_attrib_num((SLOTTYPE*)PMC_data(class),
260 PCD_OBJECT_VTABLE);
261 VTABLE * const vtable = PMC_struct_val(vtable_pmc);
262 VTABLE * const ro_vtable = vtable->ro_variant_vtable;
263 VTABLE * const deleg_pmc_vtable =
264 interp->vtables[enum_class_deleg_pmc];
265 VTABLE * const object_vtable =
266 interp->vtables[enum_class_ParrotObject];
267 VTABLE * const ro_object_vtable = object_vtable->ro_variant_vtable;
268 VTABLE * const delegate_vtable = interp->vtables[enum_class_delegate];
270 memset(&meth_str, 0, sizeof(meth_str));
271 meth_str.encoding = Parrot_fixed_8_encoding_ptr;
272 meth_str.charset = Parrot_default_charset_ptr;
273 for (i = 0; (meth = Parrot_vtable_slot_names[i]); ++i) {
274 if (!*meth)
275 continue;
276 meth_str.strstart = const_cast(meth);
277 meth_str.strlen = meth_str.bufused = strlen(meth);
278 meth_str.hashval = 0;
279 if (find_vtable_override_byname(interp, class_name, &meth_str)) {
281 * the method exists; keep the ParrotObject aka delegate vtable slot
283 ((void **)vtable)[i] = ((void**)object_vtable)[i];
284 if (ro_vtable)
285 ((void **)ro_vtable)[i] = ((void**)ro_object_vtable)[i];
287 #if 0
288 PIO_eprintf(interp, "deleg_pmc class '%Ss' found '%s'\n",
289 class_name, meth);
290 #endif
292 else if (full) {
294 * the method doesn't exist; put in the deleg_pmc vtable,
295 * but only if ParrotObject hasn't overridden the method
297 if (((void **)delegate_vtable)[i] == ((void**)object_vtable)[i]) {
298 if (ro_vtable)
299 ((void **)ro_vtable)[i] = ((void**)deleg_pmc_vtable)[i];
300 ((void **)vtable)[i] = ((void**)deleg_pmc_vtable)[i];
302 else {
303 ((void **)vtable)[i] = ((void**)object_vtable)[i];
304 if (ro_vtable)
305 ((void **)ro_vtable)[i] = ((void**)ro_object_vtable)[i];
314 =item C<const char* Parrot_MMD_method_name(Interp*, INTVAL)>
316 Return the method name for the given MMD enum.
318 =item C<INTVAL Parrot_MMD_method_idx(Interp*, STRING *)>
320 Return the MMD function number for method name or -1 on failure.
322 TODO allow dynamic expansion at runtime.
324 =cut
327 const char*
328 Parrot_MMD_method_name(Interp *interp, INTVAL idx)
330 assert(idx >= 0);
332 if (idx >= MMD_USER_FIRST)
333 return NULL;
334 return Parrot_mmd_func_names[idx];
337 INTVAL
338 Parrot_MMD_method_idx(Interp *interp, char *name)
340 INTVAL i;
342 for (i = 0; i < MMD_USER_FIRST; ++i) {
343 if (!strcmp(Parrot_mmd_func_names[i], name))
344 return i;
346 return -1;
352 =item C<PMC *
353 Parrot_single_subclass(Interp *interp, PMC *base_class,
354 PMC *child_class_name)>
356 Subclass a class. Single parent class, nice and straightforward. If
357 C<child_class> is C<NULL>, this is an anonymous subclass we're creating,
358 which happens commonly enough to warrant an actual single-subclass
359 function.
361 =cut
365 PMC *
366 Parrot_single_subclass(Interp *interp, PMC *base_class,
367 PMC *name)
369 PMC *child_class;
370 SLOTTYPE *child_class_array;
371 PMC *parents, *temp_pmc, *mro;
372 int parent_is_class;
374 /* Set the classname, if we have one */
375 if (!PMC_IS_NULL(name)) {
376 fail_if_exist(interp, name);
378 else {
379 /* XXX not really threadsafe but good enough for now */
380 static int anon_count;
382 STRING *child_class_name = Parrot_sprintf_c(interp,
383 "%c%canon_%d", 0, 0, ++anon_count);
384 name = pmc_new(interp, enum_class_String);
385 VTABLE_set_string_native(interp, name, child_class_name );
388 * ParrotClass is the baseclass anyway, so build just a new class
390 if (base_class == interp->vtables[enum_class_ParrotClass]->class) {
391 return pmc_new_init(interp, enum_class_ParrotClass, name);
393 parent_is_class = PObj_is_class_TEST(base_class);
395 child_class = pmc_new(interp, enum_class_ParrotClass);
396 /* Hang an array off the data pointer */
397 set_attrib_array_size(child_class, PCD_MAX);
398 child_class_array = PMC_data(child_class);
399 set_attrib_flags(child_class);
400 /* We will have five entries in this array */
402 /* We have the same number of attributes as our parent */
403 CLASS_ATTRIB_COUNT(child_class) = parent_is_class
404 ? CLASS_ATTRIB_COUNT(base_class) : 0;
406 /* Our parent class array has a single member in it */
407 parents = pmc_new(interp, enum_class_ResizablePMCArray);
408 VTABLE_set_integer_native(interp, parents, 1);
409 VTABLE_set_pmc_keyed_int(interp, parents, 0, base_class);
410 set_attrib_num(child_class, child_class_array, PCD_PARENTS, parents);
413 set_attrib_num(child_class, child_class_array, PCD_CLASS_NAME, name);
415 /* Our mro list is a clone of our parent's mro
416 * list, with our self unshifted onto the beginning
418 mro = VTABLE_clone(interp, base_class->vtable->mro);
419 VTABLE_unshift_pmc(interp, mro, child_class);
421 /* But we have no attributes of our own. Yet */
422 temp_pmc = pmc_new(interp, enum_class_ResizablePMCArray);
423 set_attrib_num(child_class, child_class_array, PCD_CLASS_ATTRIBUTES,
424 temp_pmc);
426 parrot_class_register(interp, name, child_class,
427 base_class, mro);
429 rebuild_attrib_stuff(interp, child_class);
431 if (!parent_is_class) {
432 /* we append one attribute to hold the PMC */
433 Parrot_add_attribute(interp, child_class,
434 CONST_STRING(interp, "__value"));
436 * then create a vtable derived from ParrotObject and
437 * deleg_pmc - the ParrotObject vtable is already built
439 create_deleg_pmc_vtable(interp, child_class, name, 1);
441 else {
443 * if any parent isa PMC, then still individual vtables might
444 * be overridden in this subclass
446 const PMC* parent;
447 int i, n, any_pmc_parent;
449 n = VTABLE_elements(interp, mro);
450 any_pmc_parent = 0;
452 /* 0 = this, 1 = parent (handled above), 2 = grandpa */
453 for (i = 2; i < n; ++i) {
454 parent = VTABLE_get_pmc_keyed_int(interp, mro, i);
455 if (!PObj_is_class_TEST(parent)) {
456 any_pmc_parent = 1;
457 break;
460 if (any_pmc_parent)
461 create_deleg_pmc_vtable(interp, child_class, name, 0);
463 return child_class;
468 =item C<void
469 Parrot_new_class(Interp *interp, PMC *class, PMC *class_name)>
471 Creates a new class, named C<class_name>.
473 =cut
477 void
478 Parrot_new_class(Interp *interp, PMC *class, PMC *name)
480 SLOTTYPE *class_array;
481 PMC *mro;
483 /* check against duplicate newclasses */
484 fail_if_exist(interp, name);
486 /* Hang an array off the data pointer, empty of course */
487 set_attrib_array_size(class, PCD_MAX);
488 class_array = PMC_data(class);
489 /* set_attrib_flags(class); init does it */
491 /* Our parent class array has nothing in it */
492 set_attrib_num(class, class_array, PCD_PARENTS,
493 pmc_new(interp, enum_class_ResizablePMCArray));
494 /* TODO create all class structures in constant PMC pool
498 * create MRO (method resolution order) array
499 * first entry is this class itself
501 mro = pmc_new(interp, enum_class_ResizablePMCArray);
502 VTABLE_push_pmc(interp, mro, class);
504 /* no attributes yet
506 set_attrib_num(class, class_array, PCD_CLASS_ATTRIBUTES,
507 pmc_new(interp, enum_class_ResizablePMCArray));
509 /* Set the classname */
510 set_attrib_num(class, class_array, PCD_CLASS_NAME, name);
512 parrot_class_register(interp, name, class, NULL, mro);
514 rebuild_attrib_stuff(interp, class);
519 =item C<PMC *
520 Parrot_class_lookup(Interp *interp, STRING *class_name)>
522 =item C<PMC *
523 Parrot_class_lookup_p(Interp *interp, PMC *class_name)>
525 Looks for the class named C<class_name> and returns it if it exists.
526 Otherwise it returns C<PMCNULL>.
528 =cut
532 PMC *
533 Parrot_class_lookup(Interp *interp, STRING *class_name)
535 const INTVAL type = pmc_type(interp, class_name);
536 if (type > 0) {
537 PMC * const pmc = interp->vtables[type]->class;
538 assert(pmc);
539 return pmc;
541 return PMCNULL;
544 PMC *
545 Parrot_class_lookup_p(Interp *interp, PMC *class_name)
547 const INTVAL type = pmc_type_p(interp, class_name);
548 if (type > 0) {
549 PMC * const pmc = interp->vtables[type]->class;
550 assert(pmc);
551 return pmc;
553 return PMCNULL;
556 static INTVAL
557 register_type(Interp *interp, PMC *name)
559 INTVAL type;
560 PMC * classname_hash, *item;
562 /* so pt_shared_fixup() can safely do a type lookup */
563 LOCK_INTERPRETER(interp);
564 classname_hash = interp->class_hash;
566 type = interp->n_vtable_max++;
567 /* Have we overflowed the table? */
568 if (type >= interp->n_vtable_alloced) {
569 parrot_realloc_vtables(interp);
571 /* set entry in name->type hash */
572 item = pmc_new(interp, enum_class_Integer);
573 PMC_int_val(item) = type;
574 VTABLE_set_pmc_keyed(interp, classname_hash, name, item);
575 UNLOCK_INTERPRETER(interp);
577 return type;
582 =item C<static void
583 parrot_class_register(Interp *interp, PMC *class_name,
584 PMC *new_class, PMC *mro)>
586 This is the way to register a new Parrot class as an instantiable
587 type. Doing this involves putting it in the class hash, setting its
588 vtable so that the C<init> method initializes objects of the class rather than
589 the class itself, and adding it to the interpreter's base type table so
590 you can create a new C<foo> in PASM like this: C<new Px, foo>.
592 =cut
596 static void
597 parrot_class_register(Interp *interp, PMC *name,
598 PMC *new_class, PMC *parent, PMC *mro)
600 VTABLE *new_vtable, *parent_vtable;
601 PMC *vtable_pmc;
602 PMC *ns, *top;
603 INTVAL new_type;
605 new_type = register_type(interp, name);
606 /* Build a new vtable for this class
607 * The child class PMC gets the vtable of its parent class or
608 * a ParrotClass vtable
610 parent_vtable = new_class->vtable;
611 if (parent && PObj_is_class_TEST(parent))
612 parent_vtable = parent->vtable;
613 else
614 parent_vtable = new_class->vtable;
615 new_vtable = Parrot_clone_vtable(interp, parent_vtable);
617 /* Set the vtable's type to the newly allocated type */
618 new_vtable->base_type = new_type;
619 /* And cache our class PMC in the vtable so we can find it later */
620 new_vtable->class = new_class;
621 new_vtable->mro = mro;
623 if (parent_vtable->ro_variant_vtable)
624 new_vtable->ro_variant_vtable =
625 Parrot_clone_vtable(interp, parent_vtable->ro_variant_vtable);
627 /* Reset the init method to our instantiation method */
628 new_vtable->init = Parrot_instantiate_object;
629 new_vtable->init_pmc = Parrot_instantiate_object_init;
630 new_class->vtable = new_vtable;
632 /* Put our new vtable in the global table */
633 interp->vtables[new_type] = new_vtable;
635 /* check if we already have a NameSpace */
636 top = CONTEXT(interp->ctx)->current_namespace;
637 ns = VTABLE_get_pmc_keyed(interp, top, name);
638 /* XXX nested, use current as base ? */
639 if (PMC_IS_NULL(ns)) {
640 /* XXX try HLL namespace too XXX */
641 top = Parrot_get_ctx_HLL_namespace(interp);
642 ns = VTABLE_get_pmc_keyed(interp, top, name);
644 if (PMC_IS_NULL(ns)) {
645 ns = pmc_new(interp, enum_class_NameSpace);
646 VTABLE_set_pmc_keyed(interp, top, name, ns);
648 /* attach namspace to vtable */
649 new_vtable->_namespace = ns;
651 if (new_vtable->ro_variant_vtable) {
652 VTABLE * const ro_vt = new_vtable->ro_variant_vtable;
653 ro_vt->base_type = new_vtable->base_type;
654 ro_vt->class = new_vtable->class;
655 ro_vt->mro = new_vtable->mro;
656 ro_vt->_namespace = new_vtable->_namespace;
660 * prepare object vtable - again that of the parent or
661 * a ParrotObject vtable
663 if (parent && PObj_is_class_TEST(parent)) {
664 vtable_pmc =
665 get_attrib_num((SLOTTYPE*)PMC_data(parent), PCD_OBJECT_VTABLE);
666 parent_vtable = PMC_struct_val(vtable_pmc);
668 else
669 parent_vtable = interp->vtables[enum_class_ParrotObject];
671 new_vtable = Parrot_clone_vtable(interp, parent_vtable);
672 if (parent_vtable->ro_variant_vtable)
673 new_vtable->ro_variant_vtable =
674 Parrot_clone_vtable(interp, parent_vtable->ro_variant_vtable);
675 new_vtable->base_type = new_type;
676 new_vtable->mro = mro;
677 new_vtable->class = new_class;
679 set_attrib_num(new_class, (SLOTTYPE*)PMC_data(new_class), PCD_OBJECT_VTABLE,
680 vtable_pmc = constant_pmc_new(interp, enum_class_VtableCache));
681 PMC_struct_val(vtable_pmc) = new_vtable;
682 /* attach namspace to object vtable too */
683 new_vtable->_namespace = ns;
685 if (new_vtable->ro_variant_vtable) {
686 VTABLE * const ro_vt = new_vtable->ro_variant_vtable;
687 ro_vt->base_type = new_vtable->base_type;
688 ro_vt->class = new_vtable->class;
689 ro_vt->mro = new_vtable->mro;
690 ro_vt->_namespace = new_vtable->_namespace;
694 static PMC*
695 get_init_meth(Interp *interp, PMC *class,
696 STRING *prop_str , STRING **meth_str)
698 STRING *meth;
699 HashBucket *b;
700 PMC *props, *ns, *method;
702 *meth_str = NULL;
703 #if 0
704 PMC *prop;
705 prop = VTABLE_getprop(interp, class, prop_str);
706 if (!VTABLE_defined(interp, prop))
707 return NULL;
708 meth = VTABLE_get_string(interp, prop);
709 #else
710 if ( !(props = PMC_metadata(class)))
711 return NULL;
712 b = parrot_hash_get_bucket(interp,
713 (Hash*) PMC_struct_val(props), prop_str);
714 if (!b)
715 return NULL;
716 meth = PMC_str_val((PMC*) b->value);
717 #endif
718 *meth_str = meth;
720 ns = VTABLE_namespace(interp, class);
721 method = VTABLE_get_pmc_keyed_str(interp, ns, meth);
722 return PMC_IS_NULL(method) ? NULL : method;
726 static void
727 do_initcall(Interp *interp, PMC* class, PMC *object, PMC *init)
729 PMC * const classsearch_array = class->vtable->mro;
730 PMC *parent_class;
731 INTVAL i, nparents;
733 * 1) if class has a CONSTRUCT property run it on the object
734 * no redispatch
736 * XXX isn't CONSTRUCT for creating new objects?
738 STRING *meth_str;
739 PMC *meth = get_init_meth(interp, class,
740 CONST_STRING(interp, "CONSTRUCT"), &meth_str);
741 int default_meth;
743 if (meth) {
744 if (init)
745 Parrot_run_meth_fromc_args(interp, meth,
746 object, meth_str, "vP", init);
747 else
748 Parrot_run_meth_fromc_args(interp, meth,
749 object, meth_str, "v");
752 * 2. if class has a BUILD property call it for all classes
753 * in reverse search order - this class last.
755 * Note: mro contains this class as first element
757 nparents = VTABLE_elements(interp, classsearch_array);
758 for (i = nparents - 1; i >= 0; --i) {
759 parent_class = VTABLE_get_pmc_keyed_int(interp,
760 classsearch_array, i);
761 /* if it's a PMC, we put one PMC of that type into
762 * the attribute slot #0 and call init() on that PMC
764 if (!PObj_is_class_TEST(parent_class)) {
765 PMC *attr, *next_parent;
766 SLOTTYPE *obj_data;
769 * but only if init isn't inherited
770 * or rather just on the last non-class parent
772 assert(i >= 1);
773 next_parent = VTABLE_get_pmc_keyed_int(interp,
774 classsearch_array, i - 1);
775 if (!PObj_is_class_TEST(next_parent)) {
776 continue;
778 attr = pmc_new_noinit(interp,
779 parent_class->vtable->base_type);
780 obj_data = PMC_data(object);
781 set_attrib_num(object, obj_data, 0, attr);
782 VTABLE_init(interp, attr);
783 continue;
785 meth = get_init_meth(interp, parent_class,
786 CONST_STRING(interp, "BUILD"), &meth_str);
787 /* no method found and no BUILD property set? */
788 if (!meth && meth_str == NULL) {
789 PMC *ns;
790 PMC *vtable_ns;
791 STRING *vtable_ns_name = string_from_const_cstring(interp,
792 "\0VTABLE\0", 8);
793 STRING *meth_str_v;
794 /* use __init as fallback constructor method, if it exists */
795 meth_str = CONST_STRING(interp, "__init");
796 meth_str_v = CONST_STRING(interp, "init");
797 ns = VTABLE_namespace(interp, parent_class);
798 vtable_ns = Parrot_get_namespace_keyed_str(interp, ns,
799 vtable_ns_name);
800 /* can't use find_method, it walks mro */
801 if (!PMC_IS_NULL(vtable_ns))
802 meth = VTABLE_get_pmc_keyed_str(interp, vtable_ns,
803 meth_str_v);
804 if (PMC_IS_NULL(meth))
805 meth = VTABLE_get_pmc_keyed_str(interp, ns, meth_str);
806 if (meth == PMCNULL)
807 meth = NULL;
808 default_meth = 1;
810 else
811 default_meth = 0;
812 if (meth) {
813 if (init)
814 Parrot_run_meth_fromc_args(interp, meth,
815 object, meth_str, "vP", init);
816 else
817 Parrot_run_meth_fromc_args(interp, meth,
818 object, meth_str, "v");
820 else if (meth_str != NULL &&
821 string_length(interp, meth_str) != 0 && !default_meth) {
822 real_exception(interp, NULL, METH_NOT_FOUND,
823 "Class BUILD method ('%Ss') not found", meth_str);
830 =item C<void
831 Parrot_instantiate_object(Interp *interp, PMC *object, PMC *init)>
833 Creates a Parrot object. Takes a passed-in class PMC that has sufficient
834 information to describe the layout of the object and, well, makes the
835 darned object.
837 =cut
841 static void instantiate_object(Interp*, PMC *object, PMC *init);
843 void
844 Parrot_instantiate_object_init(Interp *interp,
845 PMC *object, PMC *init)
847 instantiate_object(interp, object, init);
850 void
851 Parrot_instantiate_object(Interp *interp, PMC *object)
853 instantiate_object(interp, object, NULL);
856 static void
857 instantiate_object(Interp *interp, PMC *object, PMC *init)
859 SLOTTYPE *new_object_array;
860 INTVAL attrib_count, i;
862 PMC * const class = object->vtable->class;
864 * put in the real vtable
866 PMC * const vtable_pmc = get_attrib_num((SLOTTYPE *)PMC_data(class),
867 PCD_OBJECT_VTABLE);
868 object->vtable = PMC_struct_val(vtable_pmc);
870 /* Grab the attribute count from the class */
871 attrib_count = CLASS_ATTRIB_COUNT(class);
873 /* Build the array that hangs off the new object */
874 /* First presize it */
875 set_attrib_array_size(object, attrib_count);
876 new_object_array = PMC_data(object);
878 /* fill with PMCNULL, so that access doesn't segfault */
879 for (i = 0; i < attrib_count; ++i)
880 set_attrib_num(object, new_object_array, i, PMCNULL);
882 /* turn marking on */
883 set_attrib_flags(object);
885 /* We are an object now */
886 PObj_is_object_SET(object);
888 /* We really ought to call the class init routines here...
889 * this assumes that an object isa delegate
891 do_initcall(interp, class, object, init);
896 =item C<PMC *
897 Parrot_add_parent(Interp *interp, PMC *class,
898 PMC *parent)>
900 Add the parent class to the current class' parent list. This also
901 involved adding all the parent's parents, as well as all attributes of
902 the parent classes that we're adding in.
904 The MRO (method resolution order) is the C3 algorithm used by Perl6
905 and Python (>= 2.3). See also:
906 L<http://pugs.blogs.com/pugs/2005/07/day_165_r5671_j.html>
908 =cut
913 /* create a list if non-empty lists */
914 static PMC*
915 not_empty(Interp *interp, PMC *seqs)
917 INTVAL i;
918 PMC * const nseqs = pmc_new(interp, enum_class_ResizablePMCArray);
920 for (i = 0; i < VTABLE_elements(interp, seqs); ++i) {
921 PMC * const list = VTABLE_get_pmc_keyed_int(interp, seqs, i);
922 if (VTABLE_elements(interp, list))
923 VTABLE_push_pmc(interp, nseqs, list);
925 return nseqs;
928 /* merge the list if lists */
929 static PMC*
930 class_mro_merge(Interp *interp, PMC *seqs)
932 PMC *res, *seq, *cand, *nseqs, *s;
933 INTVAL i, j, k;
934 cand = NULL; /* silence compiler uninit warning */
936 res = pmc_new(interp, enum_class_ResizablePMCArray);
937 while (1) {
938 nseqs = not_empty(interp, seqs);
939 if (!VTABLE_elements(interp, nseqs))
940 break;
941 for (i = 0; i < VTABLE_elements(interp, nseqs); ++i) {
942 seq = VTABLE_get_pmc_keyed_int(interp, nseqs, i);
943 cand = VTABLE_get_pmc_keyed_int(interp, seq, 0);
944 /* check if candidate is valid */
945 for (j = 0; j < VTABLE_elements(interp, nseqs); ++j) {
946 s = VTABLE_get_pmc_keyed_int(interp, nseqs, j);
947 for (k = 1; k < VTABLE_elements(interp, s); ++k)
948 if (VTABLE_get_pmc_keyed_int(interp, s, k) == cand) {
949 cand = NULL;
950 break;
953 if (cand)
954 break;
956 if (!cand)
957 real_exception(interp, NULL, E_TypeError,
958 "inconsisten class hierarchy");
959 /* push candidate onto mro result */
960 VTABLE_push_pmc(interp, res, cand);
961 /* remove candidate from head of lists */
962 for (i = 0; i < VTABLE_elements(interp, nseqs); ++i) {
963 seq = VTABLE_get_pmc_keyed_int(interp, nseqs, i);
964 if (VTABLE_get_pmc_keyed_int(interp, seq, 0) == cand) {
965 VTABLE_shift_pmc(interp, seq);
969 return res;
972 /* create C3 MRO */
973 static PMC*
974 create_class_mro(Interp *interp, PMC *class)
976 PMC *lparents, *bases;
977 INTVAL i;
979 /* list of lists
980 * [ [class] [mro of bases] [bases] ]
982 PMC * const lall = pmc_new(interp, enum_class_ResizablePMCArray);
983 PMC * const lc = pmc_new(interp, enum_class_ResizablePMCArray);
985 VTABLE_push_pmc(interp, lc, class);
986 VTABLE_push_pmc(interp, lall, lc);
988 bases = get_attrib_num(PMC_data(class), PCD_PARENTS);
989 for (i = 0; i < VTABLE_elements(interp, bases); ++i) {
990 PMC * const base = VTABLE_get_pmc_keyed_int(interp, bases, i);
991 PMC * const lmap = PObj_is_class_TEST(base) ?
992 create_class_mro(interp, base) : base->vtable->mro;
993 VTABLE_push_pmc(interp, lall, lmap);
995 lparents = VTABLE_clone(interp, bases);
996 VTABLE_push_pmc(interp, lall, lparents);
997 return class_mro_merge(interp, lall);
1000 PMC *
1001 Parrot_add_parent(Interp *interp, PMC *class, PMC *parent)
1003 PMC *current_parent_array;
1005 if (!PObj_is_class_TEST(class))
1006 internal_exception(1, "Class isn't a ParrotClass");
1007 if (!PObj_is_class_TEST(parent) && parent == parent->vtable->class) {
1008 /* Permit inserting non-classes so at least thaw'ing classes
1009 * is easy. Adding these parents after classes have been
1010 * subclassed is dangerous, however.
1012 PMC *class_name;
1014 if (CLASS_ATTRIB_COUNT(class) != 0) {
1015 internal_exception(1, "Subclassing built-in type too late");
1017 Parrot_add_attribute(interp, class,
1018 CONST_STRING(interp, "__value"));
1019 class_name = pmc_new(interp, enum_class_String);
1020 VTABLE_set_string_native(interp, class_name,
1021 VTABLE_name(interp, class));
1022 create_deleg_pmc_vtable(interp, class, class_name, 1);
1023 } else if (!PObj_is_class_TEST(parent)) {
1024 internal_exception(1, "Parent isn't a ParrotClass");
1028 current_parent_array = get_attrib_num(PMC_data(class), PCD_PARENTS);
1029 VTABLE_push_pmc(interp, current_parent_array, parent);
1031 class->vtable->mro = create_class_mro(interp, class);
1033 rebuild_attrib_stuff(interp, class);
1034 return NULL;
1039 =item C<PMC *
1040 Parrot_remove_parent(Interp *interp, PMC *removed_class,
1041 PMC *existing_class)>
1043 This currently does nothing but return C<NULL>.
1045 =cut
1049 PMC *
1050 Parrot_remove_parent(Interp *interp, PMC *removed_class,
1051 PMC *existing_class) {
1052 return NULL;
1057 =item C<PMC *
1058 Parrot_multi_subclass(Interp *interp, PMC *base_class_array,
1059 STRING *child_class_name)>
1061 This currently does nothing but return C<NULL>.
1063 =cut
1067 PMC *
1068 Parrot_multi_subclass(Interp *interp, PMC *base_class_array,
1069 STRING *child_class_name) {
1070 return NULL;
1075 =item C<INTVAL
1076 Parrot_object_isa(Interp *interp, PMC *pmc, PMC *cl)>
1078 Return whether the object C<pmc> is an instance of class C<cl>.
1080 =cut
1084 INTVAL
1085 Parrot_object_isa(Interp *interp, PMC *pmc, PMC *cl)
1087 PMC *mro;
1088 INTVAL i, classcount;
1090 /* if this is not a class */
1091 if (!PObj_is_class_TEST(pmc)) {
1092 pmc = VTABLE_get_class(interp, pmc);
1094 mro = pmc->vtable->mro;
1095 classcount = VTABLE_elements(interp, mro);
1096 for (i = 0; i < classcount; ++i) {
1097 if (VTABLE_get_pmc_keyed_int(interp, mro, i) == cl)
1098 return 1;
1100 return 0;
1105 =item C<PMC *
1106 Parrot_new_method_cache(Interp *interp)>
1108 This should create and return a new method cache PMC.
1110 Currently it does nothing but return C<NULL>.
1112 =cut
1116 PMC *
1117 Parrot_new_method_cache(Interp *interp) {
1118 return NULL;
1123 =item C<PMC *
1124 Parrot_find_method_with_cache(Interp *interp, PMC *class,
1125 STRING *method_name)>
1127 Find a method PMC for a named method, given the class PMC, current
1128 interp, and name of the method.
1130 This routine should use the current scope's method cache, if there is
1131 one. If not, it creates a new method cache. Or, rather, it will when
1132 we've got that bit working. For now it unconditionally goes and looks up
1133 the name in the global stash.
1135 =item C<PMC *
1136 Parrot_find_method_direct(Interp *interp, PMC *class,
1137 STRING *method_name)>
1139 Find a method PMC for a named method, given the class PMC, current
1140 interpreter, and name of the method. Don't use a possible method cache.
1142 =item void Parrot_invalidate_method_cache(Interp *, STRING *class)
1144 Clear method cache for the given class. If class is NULL caches for
1145 all classes are invalidated.
1147 =cut
1151 static PMC* find_method_direct(Interp*, PMC *, STRING*);
1153 void
1154 mark_object_cache(Interp *interp)
1158 void
1159 init_object_cache(Interp *interp)
1161 Caches * const mc = interp->caches =
1162 mem_sys_allocate_zeroed(sizeof(*mc));
1163 SET_NULL(mc->idx);
1166 #define TBL_SIZE_MASK 0x1ff /* x bits 2..10 */
1167 #define TBL_SIZE (1 + TBL_SIZE_MASK)
1169 static void
1170 invalidate_type_caches(Interp *interp, UINTVAL type)
1172 Caches * const mc = interp->caches;
1173 INTVAL i;
1175 if (!mc)
1176 return;
1177 /* is it a valid entry */
1178 if (type >= mc->mc_size || !mc->idx[type])
1179 return;
1180 for (i = 0; i < TBL_SIZE; ++i) {
1181 Meth_cache_entry *e;
1182 for (e = mc->idx[type][i]; e; ) {
1183 Meth_cache_entry * const next = e->next;
1184 mem_sys_free(e);
1185 e = next;
1188 mem_sys_free(mc->idx[type]);
1189 mc->idx[type] = NULL;
1192 static void
1193 invalidate_all_caches(Interp *interp)
1195 UINTVAL i;
1196 for (i = 1; i < (UINTVAL)interp->n_vtable_max; ++i)
1197 invalidate_type_caches(interp, i);
1200 void
1201 Parrot_invalidate_method_cache(Interp *interp, STRING *class, STRING *meth)
1203 INTVAL type;
1205 /* during interp creation and NCI registration the class_hash
1206 * isn't yet up */
1207 if (!interp->class_hash)
1208 return;
1209 if (interp->resume_flag & RESUME_INITIAL)
1210 return;
1211 if (!class) {
1212 invalidate_all_caches(interp);
1213 return;
1215 type = pmc_type(interp, class);
1216 if (type < 0)
1217 return;
1218 if (type == 0) {
1219 invalidate_all_caches(interp);
1220 return;
1222 invalidate_type_caches(interp, (UINTVAL)type);
1226 * quick'n'dirty method cache
1227 * TODO: use a hash if method_name is not constant
1228 * i.e. from obj.$Sreg(args)
1229 * If this hash is implemented mark it during DOD
1231 PMC *
1232 Parrot_find_method_direct(Interp *interp, PMC *class,
1233 STRING *method_name)
1235 return find_method_direct(interp, class, method_name);
1238 PMC *
1239 Parrot_find_method_with_cache(Interp *interp, PMC *class,
1240 STRING *method_name)
1243 UINTVAL type;
1244 Caches *mc;
1245 int is_const;
1246 UINTVAL bits, i;
1247 Meth_cache_entry *e, *old;
1249 assert(method_name != 0);
1251 #if DISABLE_METH_CACHE
1252 return find_method_direct(interp, class, method_name);
1253 #endif
1255 is_const = PObj_constant_TEST(method_name);
1256 if (!is_const) {
1257 return find_method_direct(interp, class, method_name);
1259 mc = interp->caches;
1260 type = class->vtable->base_type;
1261 bits = (((UINTVAL) method_name->strstart ) >> 2) & TBL_SIZE_MASK;
1262 if (type >= mc->mc_size) {
1263 if (mc->idx) {
1264 mc->idx = mem_sys_realloc(mc->idx, sizeof(UINTVAL*) * (type + 1));
1266 else {
1267 mc->idx = mem_sys_allocate(sizeof(UINTVAL*) * (type + 1));
1269 for (i = mc->mc_size; i <= type; ++i)
1270 mc->idx[i] = NULL;
1271 mc->mc_size = type + 1;
1273 if (!mc->idx[type]) {
1274 mc->idx[type] = mem_sys_allocate(sizeof(Meth_cache_entry*) * TBL_SIZE);
1275 for (i = 0; i < TBL_SIZE; ++i)
1276 mc->idx[type][i] = NULL;
1278 e = mc->idx[type][bits];
1279 old = NULL;
1280 while (e && e->strstart != method_name->strstart) {
1281 old = e;
1282 e = e->next;
1284 if (!e) {
1285 PMC * const found = find_method_direct(interp, class, method_name);
1286 /* when here no or no correct entry was at [bits] */
1287 e = mem_sys_allocate(sizeof(Meth_cache_entry));
1288 if (old)
1289 old->next = e;
1290 else
1291 mc->idx[type][bits] = e;
1292 e->pmc = found;
1293 e->next = NULL;
1294 e->strstart = method_name->strstart;
1297 return e->pmc;
1300 #ifdef NDEBUG
1301 # define TRACE_FM(i, c, m, sub)
1302 #else
1303 static void
1304 debug_trace_find_meth(Interp *interp, PMC *class, STRING *name, PMC *sub)
1306 STRING *class_name;
1307 const char *result;
1308 Interp *tracer;
1310 if (!Interp_trace_TEST(interp, PARROT_TRACE_FIND_METH_FLAG))
1311 return;
1312 if (PObj_is_class_TEST(class)) {
1313 SLOTTYPE * const class_array = PMC_data(class);
1314 PMC *const class_name_pmc = get_attrib_num(class_array, PCD_CLASS_NAME);
1315 class_name = PMC_str_val(class_name_pmc);
1317 else
1318 class_name = class->vtable->whoami;
1319 if (sub) {
1320 if (sub->vtable->base_type == enum_class_NCI)
1321 result = "NCI";
1322 else
1323 result = "Sub";
1325 else
1326 result = "no";
1327 tracer = interp->debugger ?
1328 interp->debugger : interp;
1329 PIO_eprintf(tracer,
1330 "# find_method class '%Ss' method '%Ss': %s\n",
1331 class_name, name, result);
1334 # define TRACE_FM(i, c, m, sub) \
1335 debug_trace_find_meth(i, c, m, sub)
1336 #endif
1338 static PMC *
1339 find_method_direct_1(Interp *interp, PMC *class,
1340 STRING *method_name)
1342 PMC* method, *ns;
1343 INTVAL i;
1345 PMC * const mro = class->vtable->mro;
1346 const INTVAL n = VTABLE_elements(interp, mro);
1347 for (i = 0; i < n; ++i) {
1348 class = VTABLE_get_pmc_keyed_int(interp, mro, i);
1349 ns = VTABLE_namespace(interp, class);
1350 method = VTABLE_get_pmc_keyed_str(interp, ns, method_name);
1351 TRACE_FM(interp, class, method_name, method);
1352 if (!PMC_IS_NULL(method)) {
1353 return method;
1356 TRACE_FM(interp, class, method_name, NULL);
1357 return NULL;
1360 static PMC *
1361 find_method_direct(Interp *interp, PMC *class,
1362 STRING *method_name)
1364 PMC * const found = find_method_direct_1(interp, class, method_name);
1365 STRING * s1, *s2;
1366 if (found)
1367 return found;
1368 s1 = CONST_STRING(interp, "__get_string");
1369 s2 = CONST_STRING(interp, "__get_repr");
1370 if (string_equal(interp, method_name, s1) == 0)
1371 return find_method_direct_1(interp, class, s2);
1372 return NULL;
1376 =item C<void
1377 Parrot_note_method_offset(Interp *interp, UINTVAL offset, PMC *method)>
1379 Notes where in the hierarchy we just found a method. Used so that we
1380 can do a next and continue the search through the hierarchy for the
1381 next instance of this method.
1384 void
1385 Parrot_note_method_offset(Interp *interp, UINTVAL offset, PMC *method)
1391 =item C<INTVAL
1392 Parrot_add_attribute(Interp *interp, PMC* class, STRING* attr)>
1394 Adds the attribute C<attr> to the class.
1396 =cut
1400 /* Life is ever so much easier if a class keeps its attributes at the
1401 end of the attribute array, since we don't have to insert and
1402 reorder attributes. Inserting's no big deal, especially since we're
1403 going to break horribly if you insert into a class that's been
1404 subclassed, but it'll do for now */
1406 INTVAL
1407 Parrot_add_attribute(Interp *interp, PMC* class, STRING* attr)
1409 STRING *full_attr_name;
1410 char *c_error;
1412 SLOTTYPE * const class_array = (SLOTTYPE *)PMC_data(class);
1413 STRING * const class_name = VTABLE_get_string(interp,
1414 get_attrib_num(class_array, PCD_CLASS_NAME));
1415 PMC * const attr_array = get_attrib_num(class_array, PCD_CLASS_ATTRIBUTES);
1416 PMC * const attr_hash = get_attrib_num(class_array, PCD_ATTRIBUTES);
1417 INTVAL idx = VTABLE_elements(interp, attr_array);
1419 VTABLE_set_integer_native(interp, attr_array, idx + 1);
1420 VTABLE_set_string_keyed_int(interp, attr_array, idx, attr);
1421 full_attr_name = string_concat(interp, class_name,
1422 string_from_cstring(interp, "\0", 1), 0);
1423 full_attr_name = string_concat(interp, full_attr_name, attr, 0);
1424 /* TODO escape NUL char */
1425 if (VTABLE_exists_keyed_str(interp, attr_hash, full_attr_name))
1427 c_error = string_to_cstring(interp, full_attr_name);
1428 internal_exception(1, "Attribute '%s' already exists", c_error);
1429 string_cstring_free(c_error);
1432 * TODO check if someone is trying to add attributes to a parent class
1433 * while there are already child class attrs
1435 idx = CLASS_ATTRIB_COUNT(class)++;
1436 VTABLE_set_integer_keyed_str(interp, attr_hash,
1437 attr, idx);
1438 VTABLE_set_integer_keyed_str(interp, attr_hash,
1439 full_attr_name, idx);
1440 return idx;
1445 =item C<PMC *
1446 Parrot_get_attrib_by_num(Interp *interp, PMC *object, INTVAL attrib)>
1448 Returns attribute number C<attrib> from C<object>. Presumably the code
1449 is asking for the correct attribute number.
1451 =item C<PMC *
1452 Parrot_get_attrib_by_str(Interp *interp, PMC *object, STRING *attr)>
1454 Returns attribute with full qualified name C<attr> from C<object>.
1456 =cut
1460 PMC *
1461 Parrot_get_attrib_by_num(Interp *interp, PMC *object, INTVAL attrib)
1464 * this is called from ParrotObject's vtable now, so
1465 * their is no need for checking object being a valid
1466 * object PMC
1468 SLOTTYPE * const attrib_array = PMC_data(object);
1469 const INTVAL attrib_count = PMC_int_val(object);
1471 if (attrib >= attrib_count || attrib < 0) {
1472 real_exception(interp, NULL, ATTRIB_NOT_FOUND,
1473 "No such attribute #%d", (int)attrib);
1475 return get_attrib_num(attrib_array, attrib);
1478 static INTVAL
1479 attr_str_2_num(Interp *interp, PMC *object, STRING *attr)
1481 PMC *class;
1482 PMC *attr_hash;
1483 SLOTTYPE *class_array;
1484 HashBucket *b;
1485 STRING *delimit;
1486 STRING *attr_name;
1487 STRING *obj_name;
1488 int idx, length;
1490 if (!PObj_is_object_TEST(object))
1491 internal_exception(INTERNAL_NOT_IMPLEMENTED,
1492 "Can't set non-core object attribs yet");
1494 class = GET_CLASS((SLOTTYPE *)PMC_data(object), object);
1495 if (PObj_is_PMC_shared_TEST(object)) {
1496 /* XXX Shared objects have the 'wrong' class stored in them
1497 * (because of the reference to the namespace and because it
1498 * references PMCs that may go away),
1499 * since we actually want one from the current interpreter. */
1500 class = VTABLE_get_class(interp, object);
1502 class_array = (SLOTTYPE *)PMC_data(class);
1503 attr_hash = get_attrib_num(class_array, PCD_ATTRIBUTES);
1504 b = parrot_hash_get_bucket(interp,
1505 (Hash*) PMC_struct_val(attr_hash), attr);
1506 if (b)
1507 return PMC_int_val((PMC*)b->value);
1509 /* Create a delimiter for splitting up the Class\0attribute syntax. */
1510 delimit = string_from_cstring(interp, "\0", 1);
1512 /* Calculate the offset and the length of the attribute string. */
1513 idx = string_str_index(interp, attr, delimit, 0) + 1;
1514 if (!idx) {
1515 real_exception(interp, NULL, ATTRIB_NOT_FOUND,
1516 "No such attribute '%Ss'", attr);
1517 return 0;
1519 length = string_length(interp, attr) - idx;
1521 /* Extract the attribute and object name. */
1522 attr_name = string_substr(interp, attr, idx, length, 0, 0);
1523 obj_name = string_substr(interp, attr, 0, idx-1, 0, 0);
1525 real_exception(interp, NULL, ATTRIB_NOT_FOUND,
1526 "No such attribute '%Ss\\0%Ss'",
1527 obj_name, attr_name);
1529 return 0;
1532 PMC *
1533 Parrot_get_attrib_by_str(Interp *interp, PMC *object, STRING *attr)
1535 return Parrot_get_attrib_by_num(interp, object,
1536 attr_str_2_num(interp, object, attr));
1541 =item C<PMC *
1542 Parrot_set_attrib_by_num(Interp *interp, PMC *object,
1543 INTVAL attrib, PMC *value)>
1545 Set attribute number C<attrib> from C<object> to C<value>. Presumably the code
1546 is asking for the correct attribute number.
1548 =item C<PMC *
1549 Parrot_set_attrib_by_str(Interp *interp, PMC *object,
1550 STRING *attr, PMC *value)>
1552 Sets attribute with full qualified name C<attr> from C<object> to C<value>.
1554 =cut
1558 void
1559 Parrot_set_attrib_by_num(Interp *interp, PMC *object,
1560 INTVAL attrib, PMC *value)
1562 SLOTTYPE * const attrib_array = PMC_data(object);
1563 const INTVAL attrib_count = PMC_int_val(object);
1565 if (attrib >= attrib_count || attrib < 0) {
1566 real_exception(interp, NULL, ATTRIB_NOT_FOUND,
1567 "No such attribute #%d", (int)attrib);
1569 set_attrib_num(object, attrib_array, attrib, value);
1572 void
1573 Parrot_set_attrib_by_str(Interp *interp, PMC *object,
1574 STRING *attr, PMC *value)
1577 Parrot_set_attrib_by_num(interp, object,
1578 attr_str_2_num(interp, object, attr),
1579 value);
1582 INTVAL
1583 Parrot_class_offset(Interp *interp, PMC *object, STRING *class) {
1584 PMC *class_pmc, *mro, *attribs;
1585 INTVAL offset, i, n, attr_count;
1587 if (!PObj_is_object_TEST(object))
1588 real_exception(interp, NULL, 1, "Not an object");
1589 class_pmc = GET_CLASS((SLOTTYPE *)PMC_data(object), object);
1590 /* unroll common case - object is this class */
1591 attribs = get_attrib_num(PMC_data(class_pmc), PCD_CLASS_ATTRIBUTES);
1592 attr_count = VTABLE_elements(interp, attribs);
1593 offset = PMC_int_val(object) - attr_count;
1594 if (!string_equal(interp, VTABLE_name(interp, class_pmc), class))
1595 return offset;
1596 /* now check mro */
1597 mro = class_pmc->vtable->mro;
1598 n = VTABLE_elements(interp, mro);
1599 for (i = 1; i < n; ++i) {
1600 class_pmc = VTABLE_get_pmc_keyed_int(interp, mro, i);
1601 attribs = get_attrib_num(PMC_data(class_pmc), PCD_CLASS_ATTRIBUTES);
1602 attr_count = VTABLE_elements(interp, attribs);
1603 offset -= attr_count;
1604 if (!string_equal(interp,
1605 VTABLE_name(interp, class_pmc), class))
1606 return offset;
1608 return -1; /* error is catched in opcode */
1613 =item C<PMC *Parrot_find_class_constructor(Interp *interp,
1614 STRING *class, INTVAL classtoken)>
1616 Find and return the constructor method PMC for the named sub. The
1617 classtoken is an identifier for the class used for fast lookup, or 0
1618 if you don't have an identifier token. Which, as they're currently
1619 undefined, is pretty likely
1621 =cut
1625 PMC *Parrot_find_class_constructor(Interp *interp, STRING *class,
1626 INTVAL classtoken)
1628 return NULL;
1631 PMC *Parrot_find_class_destructor(Interp *interp, STRING *class,
1632 INTVAL classtoken)
1634 return NULL;
1637 PMC *Parrot_find_class_fallback(Interp *interp, STRING *class,
1638 INTVAL classtoken)
1640 return NULL;
1643 void Parrot_set_class_constructor(Interp *interp, STRING *class,
1644 INTVAL classtoken, STRING *method)
1648 void Parrot_set_class_destructor(Interp *interp, STRING *class,
1649 INTVAL classtoken, STRING *method)
1653 void Parrot_set_class_fallback(Interp *interp, STRING *class,
1654 INTVAL classtoken, STRING *method)
1660 =back
1662 =head1 SEE ALSO
1664 F<include/parrot/objects.h>, F<docs/pdds/pdd15_objects.pod>.
1666 =cut
1672 * Local variables:
1673 * c-file-style: "parrot"
1674 * End:
1675 * vim: expandtab shiftwidth=4: