2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
9 #include <proto/exec.h>
10 #include <proto/utility.h>
11 #include <exec/memory.h>
13 #include <proto/oop.h>
24 #include <aros/debug.h>
26 #define MD(cl) ((struct metadata *)cl)
27 #define IFI(cl) ((struct ifmeta_inst *)cl)
29 # define IntCallMethod(cl, o, msg) \
31 register struct IFBucket *b; \
32 register OOP_MethodID mid = *msg; \
33 register ULONG ifid = mid & (~METHOD_MASK); \
34 register struct IFMethod *method; \
38 b = IFI(cl)->data.iftab_directptr[ifid & IFI(cl)->data.hashmask]; \
41 if (b->InterfaceID == ifid) \
43 method = &(b->MethodTable[mid]); \
44 return (method->MethodFunc(method->mClass, o, msg)); \
53 #define UB(x) ((UBYTE *)x)
55 /* Allocates and initializes the interface hashtable, and the methodtables */
56 static BOOL
ifmeta_allocdisptabs(OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_allocdisptabs
*msg
);
57 static VOID
ifmeta_freedisptabs(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
);
59 static IPTR
Meta_DoMethod(OOP_Object
*o
, OOP_Msg msg
);
60 static IPTR
Meta_CoerceMethod(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
);
61 static IPTR
Meta_DoSuperMethod(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
);
64 VOID
freebucket(struct Bucket
*b
, struct IntOOPBase
*OOPBase
);
65 struct Bucket
*copybucket(struct Bucket
*old_b
, APTR data
, struct IntOOPBase
*OOPBase
);
68 static struct IFBucket
*createbucket(
71 ,struct IntOOPBase
*OOPBase
);
73 static ULONG
calc_ht_entries(struct ifmeta_inst
*cl
75 ,struct OOP_InterfaceDescr
*ifDescr
76 ,struct IntOOPBase
*OOPBase
);
81 The metaclass is used to create class. That means,
82 classes are instances of the meta class.
83 The meta class is itself both a class (you can
84 create instances of it), and an object (you can invoke
89 #define OOPBase (GetOBase(cl->OOPBasePtr))
94 static OOP_Object
*ifmeta_new(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
96 IPTR (*domethod
)(OOP_Object
*, OOP_Msg
) = NULL
;
97 IPTR (*coercemethod
)(OOP_Class
*, OOP_Object
*, OOP_Msg
) = NULL
;
98 IPTR (*dosupermethod
)(OOP_Class
*, OOP_Object
*, OOP_Msg
) = NULL
;
100 EnterFunc(bug("IFMeta::New(cl=%s, msg = %p)\n",
101 cl
->ClassNode
.ln_Name
, msg
));
103 /* Let the BaseMeta class initialize some stuff for us */
104 o
= (OOP_Object
*)OOP_DoSuperMethod((OOP_Class
*)cl
, o
, (OOP_Msg
)msg
);
108 struct ifmeta_inst
*inst
;
110 inst
= (struct ifmeta_inst
*)o
;
112 domethod
= (IPTR (*)())GetTagData(aMeta_DoMethod
, 0, msg
->attrList
);
113 coercemethod
= (IPTR (*)())GetTagData(aMeta_CoerceMethod
, 0, msg
->attrList
);
114 dosupermethod
= (IPTR (*)())GetTagData(aMeta_DoSuperMethod
, 0, msg
->attrList
);
117 D(bug("Instance allocated %p\n", inst
));
121 domethod
= Meta_DoMethod
;
124 coercemethod
= Meta_CoerceMethod
;
129 OOP_Class
*superptr
= inst
->base
.superclass
;
132 D(bug("Got superptr: %p\n", superptr
));
133 /* Use superclass' DoSupermethod call if superclass isn't
134 an instance of the HIDDMetaClass
136 if (OOP_OCLASS(superptr
) != (OOP_Class
*)cl
)
138 D(bug("superptr has different meta\n"));
140 dosupermethod
= superptr
->cl_DoSuperMethod
;
144 D(bug("superptr has same meta\n"));
146 dosupermethod
= Meta_DoSuperMethod
;
150 else /* if (class has no superclass) */
152 dosupermethod
= NULL
;
157 inst
->base
.public.OOPBasePtr
= (struct IntOOPBase
*)OOPBase
;
159 inst
->base
.public.cl_DoMethod
= domethod
;
160 inst
->base
.public.cl_CoerceMethod
= coercemethod
;
161 inst
->base
.public.cl_DoSuperMethod
= dosupermethod
;
163 D(bug("Classes' functions set\n"));
166 ReturnPtr ("IFMeta::New", OOP_Object
*, o
);
169 /******************************
170 ** IFMeta::allocdisptabs() **
171 ******************************/
173 /* Allocates and initializes the interface hashtable, and the methodtables */
174 static BOOL
ifmeta_allocdisptabs(OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_allocdisptabs
*msg
)
178 struct ifmeta_inst
*inst
= (struct ifmeta_inst
*)o
;
180 EnterFunc(bug("IFMeta::allocdisptabs(cl=%p, o=%p,ifDescr=%p)\n",
181 cl
, o
, msg
->ifdescr
));
183 /* Get number of needed hash entries */
184 num_if
= calc_ht_entries(inst
, msg
->superclass
, msg
->ifdescr
, OOPBase
);
186 inst
->base
.numinterfaces
= num_if
;
188 D(bug("numinterfaces set to %ld\n", num_if
));
190 /* Create a new integer hashtable, with a reasonable size */
191 inst
->data
.iftable
= NewHash(num_if
, HT_INTEGER
, OOPBase
);
192 if (inst
->data
.iftable
)
194 struct OOP_InterfaceDescr
*ifdescr
;
195 D(bug("Got iftable\n"));
196 /* Save hashmask for use in method lookup */
197 inst
->data
.hashmask
= HashMask(inst
->data
.iftable
);
199 if (msg
->superclass
) /* This test makes it work for initializing root classes */
202 /* Copy parent interfaces into the new class */
203 struct IFMethod
*superif
;
204 struct P_meta_iterateifs ii_msg
;
208 /* must be initialized to zero */
211 D(bug("Adding superclass' methods\n"));
213 ii_msg
.mid
= OOP_GetMethodID(IID_Meta
, MO_meta_iterateifs
);
215 ii_msg
.iterval_ptr
= &iterval
;
216 ii_msg
.interface_id_ptr
= &interface_id
;
217 ii_msg
.num_methods_ptr
= &num_methods
;
222 struct IFBucket
*ifb
;
223 struct IFMethod
*ifm
= NULL
;
226 superif
= (struct IFMethod
*)OOP_CoerceMethod(OOP_OCLASS(msg
->superclass
)
227 ,(OOP_Object
*)msg
->superclass
232 /* Allocate and insert the interface into the new class */
233 ifb
= createbucket(interface_id
, num_methods
, OOPBase
);
234 D(bug("Created bucket: %p\n", ifb
));
238 /* Copy the interface */
239 mtab_size
= UB (&ifm
[num_methods
]) - UB( &ifm
[0]);
240 D(bug("Copying from superclass methods for if %s, mtab_size=%d,basmetaroot %p, superif %p\n",
241 ifb
->GlobalInterfaceID
, mtab_size
, OOPBase
->ob_BaseMetaObject
.inst
.rootif
, superif
));
243 CopyMem(superif
, ifb
->MethodTable
, mtab_size
);
244 InsertBucket(inst
->data
.iftable
, (struct Bucket
*)ifb
, OOPBase
);
248 } /* if (we inherit interfaces from some superclass) */
250 /* Insert our own interfaces */
251 D(bug("Inserting own methods\n"));
252 for ( ifdescr
= msg
->ifdescr
; ifdescr
->MethodTable
; ifdescr
++)
254 struct IFBucket
*ifb
;
258 /* Get variable interface ID */
260 D(bug("Getting Local ifID for global ID %s\n", ifdescr
->InterfaceID
));
261 if (!init_mi_methodbase(ifdescr
->InterfaceID
, &iid
, OOPBase
))
264 D(bug("Got local ifID %ld\n", iid
));
266 /* Lookup hashtable to see if interface has been copied from superclass */
267 ifb
= (struct IFBucket
*)inst
->data
.iftable
->Lookup(
272 D(bug("tried to find bucket in hashtable: %p\n", ifb
));
275 D(bug("Bucket doesn't exist, creating..\n"));
276 /* Bucket doesn't exist, allocate it */
277 ifb
= createbucket(ifdescr
->InterfaceID
, ifdescr
->NumMethods
, OOPBase
);
282 D(bug("Inserting bucket for IF %s\n", ifdescr
->InterfaceID
));
283 InsertBucket(inst
->data
.iftable
, (struct Bucket
*)ifb
, OOPBase
);
288 D(bug("overriding methods\n"));
290 /* Ovveride the superclass methods with our new ones */
291 for (i
= 0; ifdescr
->MethodTable
[i
].MethodFunc
; i
++)
293 if (ifdescr
->MethodTable
[i
].MethodFunc
)
295 ifb
->MethodTable
[ ifdescr
->MethodTable
[i
].MethodIdx
].MethodFunc
= ifdescr
->MethodTable
[i
].MethodFunc
;
296 ifb
->MethodTable
[ ifdescr
->MethodTable
[i
].MethodIdx
].mClass
= (OOP_Class
*)o
;
298 } /* for (each method in the interface) */
300 } /* for (each interface to add to class) */
302 /* For speedup in method lookup */
303 inst
->data
.iftab_directptr
= (struct IFBucket
**)inst
->data
.iftable
->Table
;
305 ReturnBool ("IFMeta::allocdisptabs", TRUE
);
307 } /* if (interface hash table allocated) */
311 if (inst
->data
.iftable
)
312 FreeHash(inst
->data
.iftable
, freebucket
, OOPBase
);
313 ReturnBool ("IFMeta::allocdisptabs", FALSE
);
316 /*****************************
317 ** IFMeta::freedisptabs() **
318 *****************************/
319 static VOID
ifmeta_freedisptabs(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
322 struct ifmeta_inst
*inst
= (struct ifmeta_inst
*)o
;
323 /* This frees the hashtable + all buckets */
325 FreeHash(inst
->data
.iftable
, freebucket
, OOPBase
);
330 /**************************
331 ** IFMeta::getifinfo() **
332 **************************/
333 static struct IFMethod
*ifmeta_getifinfo(OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_getifinfo
*msg
)
336 struct ifmeta_inst
*inst
= (struct ifmeta_inst
*)o
;
337 struct IFMethod
*mtab
= NULL
;
340 /* Get the ULONG variable interface id */
341 iid
= OOP_GetMethodID(msg
->interface_id
, 0);
343 /* Try looking it up in the class' table */
344 b
= (struct IFBucket
*)inst
->data
.iftable
->Lookup(inst
->data
.iftable
, (IPTR
)iid
, OOPBase
);
346 *(msg
->num_methods_ptr
) = b
->NumMethods
;
348 mtab
= b
->MethodTable
;
354 /***************************
355 ** IFMeta::iterateifs() **
356 ***************************/
357 static struct IFMethod
*ifmeta_iterateifs(OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_iterateifs
*msg
)
359 struct HashTable
*ht
= ((struct ifmeta_inst
*)o
)->data
.iftable
;
360 struct IFBucket
*found_bucket
= NULL
; /* MUST default to NULL */
362 struct IFBucket
*ifb
= NULL
; /* keep compiler happy */
365 struct IFMethod
*current_if
= NULL
; /* MUST default to NULL */
367 UWORD last_idx
= (*(msg
->iterval_ptr
)) >> 16;
368 UWORD last_bucket_no
= (*(msg
->iterval_ptr
)) & 0x0000FFFF;
372 UWORD bucket_no
= 0; /* keep compiler happy */
373 EnterFunc(bug("IFMeta::iterateifs(cl=%s, o=%s)\n",
374 cl
->ClassNode
.ln_Name
, ((OOP_Class
*)o
)->ClassNode
.ln_Name
));
376 D(bug("last_idx: %ld, last_bucket_no=%ld\n", last_idx
, last_bucket_no
));
379 for (idx
= last_idx
;idx
< HashSize(ht
); idx
++)
381 D(bug("idx=%ld\n", idx
));
385 for (ifb
= (struct IFBucket
*)ht
->Table
[idx
]; ifb
; )
387 D(bug("ifb=%s, netx=%p, bucket_no=%ld\n",
388 ifb
->GlobalInterfaceID
, ifb
->Next
, bucket_no
));
389 /* Is this a new bucket in the iteration ? */
391 if ((idx
> last_idx
) || (bucket_no
>= last_bucket_no
))
395 /* Yes, it's a goto, but it really simplifies things here */
404 } /* for (all buckets at each idx) */
406 } /* for (each entry at east index from last idx) */
410 /* OK, found a bucket ? */
413 D(bug("bucket found: %s at idx %ld, b_no %ld\n",
414 found_bucket
->GlobalInterfaceID
, idx
, bucket_no
));
415 *(msg
->iterval_ptr
) = (idx
<< 16) + bucket_no
+ 1;
416 *(msg
->interface_id_ptr
) = ifb
->GlobalInterfaceID
;
417 *(msg
->num_methods_ptr
) = ifb
->NumMethods
;
419 current_if
= ifb
->MethodTable
;
422 ReturnPtr ("IFMeta::iterateifs", struct IFMethod
*, current_if
);
425 /***************************
426 ** IFMeta::findmethod() **
427 ***************************/
429 /* Used for finding a method for method objects */
430 static struct IFMethod
*ifmeta_findmethod(OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_findmethod
*msg
)
432 register struct IFBucket
*b
;
433 register ULONG method_offset
;
434 struct ifmeta_inst
*inst
= (struct ifmeta_inst
*)o
;
436 /* Get interfaceID part of methodID */
437 register ULONG ifid
= msg
->method_to_find
& (~METHOD_MASK
);
439 EnterFunc(bug("IFMeta::findmethod(o=%p, mid=%ld)\n", o
, msg
->method_to_find
));
442 /* Get method offset part of methdoID */
443 method_offset
= msg
->method_to_find
& METHOD_MASK
;
445 /* Look up ID in hashtable and get linked list of buckets,
448 b
= inst
->data
.iftab_directptr
[ifid
& inst
->data
.hashmask
];
452 /* Found correct interface ? */
453 if (b
->InterfaceID
== ifid
)
455 /* Yep. Return method at supplied method offset */
456 ReturnPtr ("IFMeta::findmethod", struct IFMethod
*, &(b
->MethodTable
[method_offset
]));
462 /* Method not found, return NULL */
463 ReturnPtr ("IFMeta::findmethod", struct IFMethod
*, NULL
);
473 /*************************
474 ** init_ifmetaclass() **
475 *************************/
477 #define NUM_META_METHODS 5
478 #define NUM_ROOT_METHODS 1
479 BOOL
init_ifmetaclass(struct IntOOPBase
*OOPBase
)
481 struct OOP_MethodDescr root_mdescr
[NUM_ROOT_METHODS
+ 1]=
483 { (IPTR (*)())ifmeta_new
, moRoot_New
},
487 struct OOP_MethodDescr meta_mdescr
[NUM_META_METHODS
+ 1]=
489 { (IPTR (*)())ifmeta_allocdisptabs
, MO_meta_allocdisptabs
},
490 { (IPTR (*)())ifmeta_freedisptabs
, MO_meta_freedisptabs
},
491 { (IPTR (*)())ifmeta_getifinfo
, MO_meta_getifinfo
},
492 { (IPTR (*)())ifmeta_iterateifs
, MO_meta_iterateifs
},
493 { (IPTR (*)())ifmeta_findmethod
, MO_meta_findmethod
},
498 struct OOP_InterfaceDescr meta_descr
[] =
500 {root_mdescr
, IID_Root
, 1},
501 {meta_mdescr
, IID_Meta
, NUM_META_METHODS
},
505 struct ifmetaobject
*imo
= &(OOPBase
->ob_IFMetaObject
);
506 struct P_meta_allocdisptabs adt_msg
;
507 OOP_Class
*ifmeta_cl
;
509 EnterFunc(bug("init_ifmetaclass()\n"));
511 ifmeta_cl
= &(imo
->inst
.base
.public);
513 D(bug("Got ifmeta classptr\n"));
515 imo
->inst
.base
.superclass
= BASEMETAPTR
;
516 imo
->inst
.base
.public.OOPBasePtr
= (struct OOPBase
*)OOPBase
;
518 D(bug("Initialized ifmeta superclass\n"));
520 adt_msg
.superclass
= imo
->inst
.base
.superclass
;
521 adt_msg
.ifdescr
= meta_descr
;
523 /* allocdisptabs() must know the OOPBase */
524 imo
->inst
.base
.public.UserData
= (APTR
)OOPBase
;
525 /* It must also have a valid DoSuperMethod(), more exatly
526 the DoSuperMethod() of the BaseMeta class
528 imo
->inst
.base
.public.cl_DoSuperMethod
= BASEMETAPTR
->cl_DoSuperMethod
;
531 D(bug("Allocating ifmeta disptabs\n"));
534 if (ifmeta_allocdisptabs(ifmeta_cl
, (OOP_Object
*)ifmeta_cl
, &adt_msg
))
536 D(bug("ifmeta disptabs allocated\n"));
537 /* initialize Class ID */
539 imo
->inst
.base
.public.ClassNode
.ln_Name
= CLID_MIMeta
;
540 imo
->inst
.base
.public.InstOffset
= sizeof (struct metadata
);
542 D(bug("IFMeta DoMethod=%p\n", Meta_DoMethod
));
543 imo
->inst
.base
.public.cl_DoMethod
= Meta_DoMethod
;
544 imo
->inst
.base
.public.cl_CoerceMethod
= Meta_CoerceMethod
;
546 imo
->inst
.base
.instsize
= sizeof (struct ifmeta_data
);
547 imo
->inst
.base
.subclasscount
= 0UL;
548 imo
->inst
.base
.objectcount
= 0UL;
550 imo
->inst
.data
.numinterfaces
= 2UL;
552 /* This class' class is itself */
553 imo
->oclass
= &(imo
->inst
.base
.public);
557 D(bug("Trying to call get_if_info on ifmeta many times\n"));
558 for (i = 0; i < 10; i ++)
561 meta_getifinfo((OOP_Object *)imo->oclass, IID_Meta, &num_methods);
563 D(bug("IF has %ld methods\n", num_methods));
567 */ /* Make it public */
568 OOP_AddClass(ifmeta_cl
);
569 ReturnBool ("init_metaclass", TRUE
);
571 ReturnBool ("init_ifmetaclass", FALSE
);
576 /************************
577 ** calc_ht_entries() **
578 ************************/
580 /* Calculates the number of interfaces the new class has
581 ( == number of buckets in the hashtable)
583 static ULONG
calc_ht_entries(struct ifmeta_inst
*cl
585 ,struct OOP_InterfaceDescr
*ifDescr
586 ,struct IntOOPBase
*OOPBase
)
590 EnterFunc(bug("calc_ht_entries(cl=%p, ifDescr=%p, super=%p)\n", cl
, ifDescr
, super
));
596 /* Get number of interfaces (method tables) in superclass */
599 num_if
= MD(super
)->numinterfaces
;
601 D(bug("Super-interfaces: %ld\n", num_if
));
603 /* Check if there are any new interfaces in this class */
605 for (; ifDescr
->MethodTable
; ifDescr
++)
607 struct P_meta_getifinfo gii_msg
;
610 D(bug("Checking for interface %s\n", ifDescr
->InterfaceID
));
612 gii_msg
.mid
= OOP_GetMethodID(IID_Meta
, MO_meta_getifinfo
);
613 gii_msg
.interface_id
= ifDescr
->InterfaceID
;
614 gii_msg
.num_methods_ptr
= &num_methods
;
617 /* Does super support interface ? */
618 D(bug("Calling CoerceMethod on class %s\n", OOP_OCLASS(super
)->ClassNode
.ln_Name
));
619 if (!OOP_CoerceMethod(OOP_OCLASS(super
), (OOP_Object
*)super
, (OOP_Msg
)&gii_msg
))
621 D(bug("Found new interface: %s\n", ifDescr
->InterfaceID
));
623 /* If it didn't then we have a new interface for this class */
627 } /* for (each interface in the description for the class) */
632 /* This is a baseclass, count the interfaces */
633 for (; ifDescr
->MethodTable
; ifDescr
++)
637 } /* for (each interface in the description for the class) */
639 ReturnInt ("calc_ht_entries", ULONG
, num_if
);
647 /*********************
649 *********************/
650 /* Creates a new interface bucket */
651 static struct IFBucket
*createbucket(
654 ,struct IntOOPBase
*OOPBase
)
656 struct IFMethod
*ifm
= NULL
;
657 ULONG mtab_size
= UB (&ifm
[num_methods
]) - UB( &ifm
[0]);
659 /* Allocate bucket */
660 struct IFBucket
*ifb
;
662 ifb
= (struct IFBucket
*)AllocMem( sizeof (struct IFBucket
), MEMF_ANY
);
665 /* Allocate method table for this interface */
666 ifb
->MethodTable
= (struct IFMethod
*)AllocVec(mtab_size
, MEMF_ANY
);
667 if (ifb
->MethodTable
)
669 /* Get correct ID for the interface (string ID => interface ID mapping) */
670 ifb
->InterfaceID
= 0;
671 if (init_mi_methodbase(interface_id
, &(ifb
->InterfaceID
), OOPBase
))
673 /* Save number of methods in the interface */
674 ifb
->NumMethods
= num_methods
;
676 /* Save the global string representations of the ID */
677 ifb
->GlobalInterfaceID
= interface_id
;
682 FreeMem (ifb
, sizeof (struct IFBucket
));
688 /***********************
689 ** Hash table hooks **
690 ***********************/
691 #define IB(x) ((struct IFBucket *)x)
693 VOID
freebucket(struct Bucket
*b
, struct IntOOPBase
*OOPBase
)
696 /* Free methodtable */
697 FreeVec(IB(b
)->MethodTable
);
699 /* Free the bucket itself */
700 FreeMem(b
, sizeof (struct IFBucket
));
706 /* Copies a hashtable bucket */
707 struct Bucket
*copyBucket(struct Bucket
*old_b
, APTR data
, struct IntOOPBase
*OOPBase
)
709 struct IFBucket
*new_b
;
711 EnterFunc(bug("CopyBucket(old_b=%p)\n", old_b
));
713 /* Allocate memory for the new interface bucket */
714 new_b
= (struct IFBucket
*)AllocMem(sizeof (struct IFBucket
), MEMF_ANY
);
717 struct IFMethod
*ifm
= NULL
;
720 /* Get number of methods in source methodtable */
721 ULONG numentries
= IB(old_b
)->NumMethods
;
723 mtab_size
= UB(&ifm
[numentries
]) - UB(&ifm
[0]);
725 /* Allocate memory for methodtable of same size as source one */
726 new_b
->MethodTable
= (struct IFMethod
*)AllocVec(mtab_size
, MEMF_ANY
);
727 if (new_b
->MethodTable
)
729 /* Copy methodtable to destination */
730 CopyMem(IB(old_b
)->MethodTable
, new_b
->MethodTable
, mtab_size
);
732 /* Initialize bucket */
733 new_b
->InterfaceID
= IB(old_b
)->InterfaceID
;
734 new_b
->NumMethods
= IB(old_b
)->NumMethods
;
735 new_b
->GlobalInterfaceID
= IB(old_b
)->GlobalInterfaceID
;
737 ReturnPtr ("CopyBucket", struct Bucket
*, (struct Bucket
*)new_b
);
739 FreeMem (new_b
, sizeof (struct IFBucket
));
742 ReturnPtr ("CopyBucket", struct Bucket
*, NULL
);
747 /* Default function for calling DoMethod() on a local object */
752 #define OOPBase ((struct IntOOPBase *)OOP_OOPBASE(object))
754 static IPTR
Meta_DoMethod(OOP_Object
*object
, OOP_Msg msg
)
756 struct metadata
*cl
= (struct metadata
*)OOP_OCLASS(object
);
759 /* Macro below defined in intern.h */
760 IntCallMethod(cl
, object
, msg
);
768 static IPTR
Meta_CoerceMethod(OOP_Class
*cl
, OOP_Object
*object
, OOP_Msg msg
)
770 IntCallMethod(cl
, object
, msg
);
773 /********************
775 ********************/
776 static IPTR
Meta_DoSuperMethod(OOP_Class
*cl
, OOP_Object
*object
, OOP_Msg msg
)
778 cl
= IFI(cl
)->base
.superclass
;
779 IntCallMethod(cl
, object
, msg
);