2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/pmc/object.pmc - An instance of a class
11 Implements an instance of a class.
21 #include "parrot/parrot.h"
22 #include "parrot/oo_private.h"
23 #include "pmc_class.h"
25 /* This finds the index of an attribute in an object's attribute store and
26 * returns it. Returns -1 if the attribute does not exist. */
28 get_attrib_index(PARROT_INTERP, PMC *self, STRING *name)
30 Parrot_Class_attributes * const _class = PARROT_CLASS(self);
31 INTVAL cur_hll = CONTEXT(interp)->current_HLL;
34 CONTEXT(interp)->current_HLL = 0;
36 /* First see if we can find it in the cache. */
37 if (VTABLE_exists_keyed_str(interp, _class->attrib_cache, name)) {
39 VTABLE_get_integer_keyed_str(interp, _class->attrib_cache, name);
40 CONTEXT(interp)->current_HLL = cur_hll;
44 /* No hit. We need to walk up the list of parents to try and find the
46 num_classes = VTABLE_elements(interp, _class->all_parents);
48 for (i = 0; i < num_classes; i++) {
49 /* Get the class and its attribute metadata hash. */
50 PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp,
51 _class->all_parents, i);
53 /* Build a string representing the fully qualified attribute name. */
54 STRING *fq_name = VTABLE_get_string(interp, cur_class);
55 fq_name = string_append(interp, fq_name, name);
58 if (VTABLE_exists_keyed_str(interp, _class->attrib_index, fq_name)) {
59 /* Found it. Get value, cache it and we're done. */
60 const INTVAL index = VTABLE_get_integer_keyed_str(interp,
61 _class->attrib_index, fq_name);
62 VTABLE_set_integer_keyed_str(interp, _class->attrib_cache, name,
65 CONTEXT(interp)->current_HLL = cur_hll;
70 CONTEXT(interp)->current_HLL = cur_hll;
74 /* This variation bypasses the cache and finds the index of a particular
75 * parent's attribute in an object's attribute store and returns it. Returns -1
76 * if the attribute does not exist. */
79 get_attrib_index_keyed(PARROT_INTERP, PMC *self, PMC *key, STRING *name)
81 Parrot_Class_attributes * const _class = PARROT_CLASS(self);
82 PMC * const class_cache = VTABLE_get_pmc_keyed_str(interp,
83 _class->attrib_cache, VTABLE_get_string(interp, key));
87 if (!PMC_IS_NULL(class_cache))
88 if (VTABLE_exists_keyed_str(interp, class_cache, name))
89 return VTABLE_get_integer_keyed_str(interp, class_cache, name);
91 /* Build a string representing the fully qualified attribute name. */
92 parent_class = Parrot_oo_get_class(interp, key);
93 fq_name = VTABLE_get_string(interp, parent_class);
94 fq_name = string_append(interp, fq_name, name);
97 if (VTABLE_exists_keyed_str(interp, _class->attrib_index, fq_name)) {
98 /* Found it. Get value and we're done. */
99 const INTVAL index = VTABLE_get_integer_keyed_str(interp,
100 _class->attrib_index, fq_name);
107 pmclass Object need_ext {
108 ATTR PMC *_class; /* The class this is an instance of. */
109 ATTR PMC *attrib_store; /* The attributes store - a resizable PMC array. */
115 Raises an exception; you can only instantiate objects from a class.
122 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
123 "Object must be created by a class.");
129 =item C<void init_pmc(PMC *class)>
131 Raises an exception; you can only instantiate objects from a class.
137 VTABLE void init_pmc(PMC *worreva) {
138 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
139 "Object must be created by a class.");
144 =item C<void destroy()>
146 Free the object's underlying struct.
151 VTABLE void destroy() {
152 mem_sys_free(PMC_data(SELF));
157 =item C<STRING *name()>
159 Returns the fully qualified name of the object's class.
165 VTABLE STRING *name() {
166 PMC * const _class = VTABLE_get_class(interp, SELF);
167 STRING * const name = CONST_STRING(interp, "name");
169 /* If there's a vtable override for 'name' run that instead. */
170 PMC * const method = Parrot_oo_find_vtable_override(interp, _class, name);
172 if (!PMC_IS_NULL(method))
173 return (STRING *)Parrot_run_meth_fromc_args(interp, method, SELF, name, "S");
175 return VTABLE_get_string(interp, _class);
182 Mark any referenced strings and PMCs.
188 if (PARROT_OBJECT(SELF)) {
189 Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
192 pobject_lives(interp, (PObj*)obj->_class);
193 if (obj->attrib_store)
194 pobject_lives(interp, (PObj*)obj->attrib_store);
200 =item C<PMC *get_attr_str(STRING *name)>
202 Gets the value of an attribute for this object. Will find the first attribute
203 of the given name walking up the inheritance tree.
208 VTABLE PMC *get_attr_str(STRING *name) {
209 Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
210 STRING * const get_attr = CONST_STRING(interp, "get_attr_str");
213 /* If there's a vtable override for 'get_attr_str' run that first. */
214 PMC * const method = Parrot_oo_find_vtable_override(interp,
215 VTABLE_get_class(interp, SELF), get_attr);
217 if (!PMC_IS_NULL(method))
218 return (PMC *)Parrot_run_meth_fromc_args(interp, method, SELF,
219 get_attr, "PS", name);
221 /* Look up the index. */
222 index = get_attrib_index(interp, obj->_class, name);
224 /* If lookup failed, exception. */
226 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ATTRIB_NOT_FOUND,
227 "No such attribute '%S'", name);
229 return VTABLE_get_pmc_keyed_int(interp, obj->attrib_store, index);
234 =item C<PMC *get_attr_keyed(PMC *key, STRING *name)>
236 Gets the value of an attribute for this object. Will only look for attributes
237 defined in the parent identified by the given key.
242 VTABLE PMC *get_attr_keyed(PMC *key, STRING *name) {
243 Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
245 /* Look up the index. */
246 const INTVAL index = get_attrib_index_keyed(interp, obj->_class, key, name);
248 /* If lookup failed, exception. */
250 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ATTRIB_NOT_FOUND,
251 "No such attribute '%S' in class '%S'", name,
252 VTABLE_get_string(interp, key));
254 return VTABLE_get_pmc_keyed_int(interp, obj->attrib_store, index);
259 =item C<void set_attr_str(STRING *name, PMC *value)>
261 Sets the value of an attribute for this object. Will set the first attribute
262 of the given name walking up the inheritance tree.
267 VTABLE void set_attr_str(STRING *name, PMC *value) {
268 Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
269 STRING *vtable_meth_name = CONST_STRING(interp, "set_attr_str");
272 /* If there's a vtable override for 'set_attr_str' run that first. */
273 PMC * const method = Parrot_oo_find_vtable_override(interp,
274 VTABLE_get_class(interp, SELF), vtable_meth_name);
275 if (!PMC_IS_NULL(method)) {
276 PMC *unused = (PMC *)Parrot_run_meth_fromc_args(interp, method,
277 SELF, vtable_meth_name, "vSP", name, value);
282 index = get_attrib_index(interp, obj->_class, name);
284 /* If lookup failed, exception. */
286 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ATTRIB_NOT_FOUND,
287 "No such attribute '%S'", name);
289 VTABLE_set_pmc_keyed_int(interp, obj->attrib_store, index, value);
294 =item C<void set_attr_keyed(PMC *key, STRING *name, PMC *value)>
296 Sets the value of an attribute for this object. Will only set attributes
297 defined in the parent identified by the given key.
302 VTABLE void set_attr_keyed(PMC *key, STRING *name, PMC *value) {
303 Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
304 const INTVAL index = get_attrib_index_keyed(interp, obj->_class, key, name);
306 /* If lookup failed, exception. */
308 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_ATTRIB_NOT_FOUND,
309 "No such attribute '%S' in class '%S'", name,
310 VTABLE_get_string(interp, key));
312 VTABLE_set_pmc_keyed_int(interp, obj->attrib_store, index, value);
317 =item C<PMC *find_method(STRING *name)>
319 Queries this object's class to find the method with the given name.
324 VTABLE PMC *find_method(STRING *name) {
325 Parrot_Object_attributes * const obj = PARROT_OBJECT(SELF);
326 Parrot_Class_attributes * const _class = PARROT_CLASS(obj->_class);
327 PMC *method = PMCNULL;
328 STRING *find_method = CONST_STRING(interp, "find_method");
330 /* Walk and search. One day, we'll use the cache first. */
331 const int num_classes = VTABLE_elements(interp,
332 _class->all_parents);
333 const int all_in_universe = !CLASS_has_alien_parents_TEST(obj->_class);
334 int alien_parents_pos = VTABLE_elements(interp,
335 _class->attrib_metadata);
338 for (i = 0; i < num_classes; i++) {
340 PMC * const cur_class =
341 VTABLE_get_pmc_keyed_int(interp, _class->all_parents, i);
343 /* If there's a vtable override for 'find_method' in the current
344 * class, run that first. */
345 method = Parrot_oo_find_vtable_override_for_class(interp, cur_class,
348 if (!PMC_IS_NULL(method))
349 return (PMC *)Parrot_run_meth_fromc_args(interp, method, SELF,
350 find_method, "PS", name);
352 /* If it's from this universe or the class doesn't inherit from
353 * anything outside of it... */
354 if (all_in_universe || VTABLE_isa(interp, cur_class, CONST_STRING(interp, "Class"))) {
355 const Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class);
356 if (VTABLE_exists_keyed_str(interp, class_info->methods, name)) {
358 method = VTABLE_get_pmc_keyed_str(interp, class_info->methods, name);
363 /* Delegate the lookup to the class. */
364 PMC * const del_class = VTABLE_get_pmc_keyed_int(interp, obj->attrib_store,
366 method = VTABLE_find_method(interp, del_class, name);
368 if (!PMC_IS_NULL(method)) {
369 /* Found it. However, if we just hand this back and it's
370 * an NCI and we call it, we will get the wrong invocant
371 * passed. Therefore, we need to close the NCI and make it
372 * into a BoundNCI. */
373 if (method->vtable->base_type == enum_class_NCI) {
374 method = VTABLE_clone(interp, method);
375 method->vtable = interp->vtables[enum_class_Bound_NCI];
376 VTABLE_set_pmc(interp, method, del_class);
379 /* Found a method, so we're done. */
392 =item C<PMC *get_class()>
394 Get the class PMC representing the class that this object is an instance of.
399 VTABLE PMC *get_class() {
400 PMC * const classobj = PARROT_OBJECT(SELF)->_class;
401 STRING *get_class = CONST_STRING(interp, "get_class");
402 /* If there's a vtable override for 'get_class' run that instead. */
403 PMC * const method = Parrot_oo_find_vtable_override(interp,
404 classobj, get_class);
406 if (!PMC_IS_NULL(method))
407 return (PMC *)Parrot_run_meth_fromc_args(interp, method, SELF,
415 =item C<INTVAL can(STRING *method_name)>
417 Returns 0 if the class does not have a method with the given name and a
418 non-zero value if it does.
423 VTABLE INTVAL can(STRING *method_name) {
424 /* Just use find_method and see it if finds anything. */
425 const PMC * const method = VTABLE_find_method(interp, SELF, method_name);
426 return !PMC_IS_NULL(method);
431 =item C<INTVAL isa_pmc(PMC *classname)>
433 Returns whether the object's class is or inherits from C<*classname>.
439 VTABLE INTVAL isa_pmc(PMC *lookup) {
440 if (PMC_IS_NULL(lookup))
446 /* Dispatch isa to the object's class */
447 return VTABLE_isa_pmc(interp, VTABLE_get_class(interp, SELF), lookup);
452 =item C<INTVAL isa(STRING *classname)>
454 Returns whether the class is or inherits from C<*classname>.
460 VTABLE INTVAL isa(STRING *classname) {
463 if (SUPER(classname))
466 _class = VTABLE_get_class(interp, SELF);
467 return VTABLE_isa(interp, _class, classname);
472 =item C<INTVAL does(STRING *role_name)>
474 Returns whether the object's class does the role with name C<*role_name>.
480 VTABLE INTVAL does(STRING *role_name) {
484 /* Dispatch to the object's class */
485 return VTABLE_does(interp, VTABLE_get_class(interp, SELF), role_name);
490 =item C<INTVAL does_pmc(PMC *role)>
492 Returns whether the object's class does C<*role>.
498 VTABLE INTVAL does_pmc(PMC *role) {
499 if (PMC_IS_NULL(role))
505 /* Dispatch to the object's class */
506 return VTABLE_does_pmc(interp, VTABLE_get_class(interp, SELF), role);
511 =item C<opcode_t *invoke(void *next)>
513 Invokes the object (if this vtable function is overridden).
519 opcode_t * invoke(void *next) {
520 Parrot_Object_attributes * const obj = PARROT_OBJECT(pmc);
521 Parrot_Class_attributes * const _class = PARROT_CLASS(obj->_class);
523 /* Walk and search for the vtable method. */
524 const int num_classes = VTABLE_elements(interp, _class->all_parents);
527 for (i = 0; i < num_classes; i++) {
529 STRING *meth_name = CONST_STRING(interp, "invoke");
530 STRING *proxy = CONST_STRING(interp, "proxy");
531 PMC * const cur_class =
532 VTABLE_get_pmc_keyed_int(interp, _class->all_parents, i);
535 Parrot_oo_find_vtable_override_for_class(interp, cur_class,
537 if (!PMC_IS_NULL(meth))
538 return VTABLE_invoke(interp, meth, next);
540 if (cur_class->vtable->base_type == enum_class_PMCProxy) {
541 /* Get the PMC instance and call the vtable method on that. */
542 PMC * const del_object =
543 VTABLE_get_attr_keyed(interp, pmc, cur_class, proxy);
545 if (!PMC_IS_NULL(del_object))
546 return VTABLE_invoke(interp, del_object, next);
550 return (opcode_t *)Parrot_default_invoke(interp, pmc, next);
555 =item C<INTVAL type()>
557 Returns the integer type of the object's class.
563 VTABLE INTVAL type() {
564 PMC *_class = VTABLE_get_class(interp, SELF);
565 return VTABLE_type(interp, _class);
570 =item C<PMC * clone()>
572 Creates a clone of the object.
578 VTABLE PMC * clone() {
579 Parrot_Object_attributes * const obj = PARROT_OBJECT(pmc);
580 Parrot_Class_attributes * const _class = PARROT_CLASS(obj->_class);
581 STRING * const meth_name = CONST_STRING(interp, "clone");
583 Parrot_Object_attributes * cloned_guts;
585 /* See if we have a custom override of the method first. */
586 const int num_classes = VTABLE_elements(interp, _class->all_parents);
588 for (i = 0; i < num_classes; i++) {
590 PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp, _class->all_parents, i);
592 /* Look for a method and run it if we find one. */
594 Parrot_oo_find_vtable_override_for_class(interp, cur_class, meth_name);
595 if (!PMC_IS_NULL(meth))
596 return (PMC*)Parrot_run_meth_fromc_args(interp, meth, pmc, meth_name, "P");
599 /* If we get here, no custom clone. Create a new object PMC. */
600 cloned = pmc_new_noinit(interp, enum_class_Object);
602 /* Set custom DOD mark and destroy on the object. */
603 PObj_custom_mark_SET(cloned);
604 PObj_active_destroy_SET(cloned);
606 /* Flag that it is an object */
607 PObj_is_object_SET(cloned);
609 /* Now create the underlying structure, and clone attributes list.class. */
610 cloned_guts = mem_allocate_zeroed_typed(Parrot_Object_attributes);
611 cloned_guts->_class = obj->_class;
612 cloned_guts->attrib_store = VTABLE_clone(INTERP, obj->attrib_store);
613 PMC_data(cloned) = cloned_guts;
615 /* Some of the attributes may have been the PMCs providing storage for any
616 * PMCs we inherited from; also need to clone those. */
617 if (CLASS_has_alien_parents_TEST(obj->_class)) {
618 /* Locate any PMC parents. */
619 for (i = 0; i < num_classes; i++) {
620 PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp, _class->all_parents, i);
621 if (cur_class->vtable->base_type == enum_class_PMCProxy) {
622 /* Clone this PMC too. */
623 STRING *proxy = CONST_STRING(interp, "proxy");
624 VTABLE_set_attr_str(interp, cloned, proxy,
626 VTABLE_get_attr_keyed(interp, pmc, cur_class, proxy)));
631 /* And we have ourselves a clone. */
637 =item C<void visit(visit_info *info)>
639 This is used by freeze/thaw to visit the contents of the object.
641 C<*info> is the visit info, (see F<include/parrot/pmc_freeze.h>).
647 VTABLE void visit(visit_info *info) {
648 Parrot_Object_attributes * const obj_data = PARROT_OBJECT(SELF);
652 pos = &obj_data->_class;
653 info->thaw_ptr = pos;
654 (info->visit_pmc_now)(INTERP, *pos, info);
656 /* 2) visit the attributes */
657 pos = &obj_data->attrib_store;
658 info->thaw_ptr = pos;
659 (info->visit_pmc_now)(INTERP, *pos, info);
664 =item C<void thaw(visit_info *info)>
666 Used to unarchive the object.
672 VTABLE void thaw(visit_info *info) {
673 if (info->extra_flags == EXTRA_IS_PROP_HASH) {
676 else if (info->extra_flags == EXTRA_IS_NULL) {
677 /* Allocate the object's core data struct */
678 PMC_data(SELF) = mem_allocate_zeroed_typed(Parrot_Object_attributes);
684 =item C<void thawfinish(visit_info *info)>
686 Called after the object has been thawed.
692 void thawfinish(visit_info *info) {
693 /* Set custom DOD mark and destroy on the object. */
694 PObj_custom_mark_SET(SELF);
695 PObj_active_destroy_SET(SELF);
697 /* Flag that it is an object */
698 PObj_is_object_SET(SELF);
703 =item C<PMC * share_ro()>
705 Used to mark a PMC as read-only shared.
710 VTABLE PMC *share_ro() {
711 PMC *ret, *_true, *data;
714 Parrot_Interp master;
716 PMC *vtable_cache = PMCNULL;
718 if (PObj_is_PMC_shared_TEST(SELF))
721 master = interpreter_array[0];
722 classobj = VTABLE_get_class(INTERP, SELF);
723 type_num = SELF->vtable->base_type;
725 /* keep the original vtable from going away... */
726 vtable_cache = PARROT_CLASS(classobj)->vtable_cache;
727 if (PMC_IS_NULL(vtable_cache)) {
728 vtable_cache = pmc_new(INTERP, enum_class_VtableCache);
729 PMC_struct_val(vtable_cache) = INTERP->vtables[type_num];
730 PARROT_CLASS(classobj)->vtable_cache = vtable_cache;
733 add_pmc_sync(INTERP, vtable_cache);
734 PObj_is_PMC_shared_SET(vtable_cache);
736 /* make sure metadata doesn't go away unexpectedly */
737 if (PMC_metadata(pmc))
738 PMC_metadata(pmc) = pt_shared_fixup(interp, PMC_metadata(pmc));
740 PARROT_ASSERT(master->vtables[type_num]->pmc_class);
741 /* don't want the referenced class disappearing on us */
742 LOCK_INTERPRETER(master);
743 SELF->vtable->pmc_class = master->vtables[type_num]->pmc_class;
744 UNLOCK_INTERPRETER(master);
747 _true = pmc_new(INTERP, enum_class_Integer);
749 /* Setting the '_ro' property switches to the read-only vtable */
750 VTABLE_set_integer_native(INTERP, _true, 1);
751 VTABLE_setprop(INTERP, ret, CONST_STRING(interp, "_ro"), _true);
752 SELF->vtable->pmc_class = master->vtables[type_num]->pmc_class;
753 add_pmc_sync(INTERP, ret);
754 PObj_is_PMC_shared_SET(ret);
756 data = PARROT_CLASS(classobj)->parents;
757 n = VTABLE_elements(INTERP, data);
759 for (i = 0; i < n; ++i) {
760 PMC * cur_class = VTABLE_get_pmc_keyed_int(INTERP, data, i);
761 VTABLE_set_pmc_keyed_int(INTERP, data, i, VTABLE_share_ro(INTERP, cur_class));
764 /* XXX This is perhaps not the best way to fix this up, but we
765 * need to ensure that the class object won't go away when
766 * this interpreter dies.
768 PARROT_ASSERT(ret->vtable->pmc_class);
769 PARROT_ASSERT(ret->vtable->share_ro == Parrot_Object_share_ro);
776 =item C<void morph(INTVAL type)>
778 Changes the PMC to a PMC of a new type
784 VTABLE void morph(INTVAL type) {
795 F<docs/pdds/pdd15_objects.pod>.
803 * c-file-style: "parrot"
805 * vim: expandtab shiftwidth=4: