test/library: Also test __GM_GetBaseParent() in function with C argument passing.
[AROS.git] / rom / oop / metaclass.c
blob346c46727fa100ca3baeeb352b2176299c7ebe79
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: OOP metaclass
6 Lang: english
7 */
9 #include <proto/exec.h>
10 #include <proto/utility.h>
11 #include <exec/alerts.h>
12 #include <exec/memory.h>
14 #include <proto/oop.h>
15 #include <oop/oop.h>
17 #include "intern.h"
18 #include "hash.h"
19 #include "private.h"
21 #undef SDEBUG
22 #undef DEBUG
23 #define SDEBUG 0
24 #define DEBUG 0
25 /* #define DUMP_BUCKET */
27 #include <aros/debug.h>
29 #define IFI(cl) ((struct ifmeta_inst *)cl)
31 /* Allocates and initializes the interface hashtable, and the methodtables */
32 static BOOL ifmeta_allocdisptabs(OOP_Class *cl, OOP_Object *o, struct P_meta_allocdisptabs *msg);
33 static VOID ifmeta_freedisptabs(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
35 static IPTR Meta_DoMethod(OOP_Object *o, OOP_Msg msg);
36 static IPTR Meta_CoerceMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
37 static IPTR Meta_DoSuperMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg);
39 /* Hooks */
40 VOID freebucket(struct Bucket *b, struct IntOOPBase *OOPBase);
41 struct Bucket *copybucket(struct Bucket *old_b, APTR data, struct IntOOPBase *OOPBase);
43 /* Internal */
44 static struct IFBucket *createbucket(CONST_STRPTR interface_id, ULONG local_id ,ULONG num_methods);
45 static BOOL expandbucket(struct IFBucket *b, ULONG num_methods);
47 static ULONG calc_ht_entries(struct ifmeta_inst *cl ,OOP_Class *super,
48 const struct OOP_InterfaceDescr *ifDescr ,struct IntOOPBase *OOPBase);
51 The metaclass is used to create class. That means,
52 classes are instances of the meta class.
53 The meta class is itself both a class (you can
54 create instances of it), and an object (you can invoke
55 methods on it.
56 */
59 #ifdef DUMP_BUCKET
61 static void dump_bucket(struct IFBucket *b)
63 ULONG i;
65 bug("[META] Bucket 0x%p (%s) with %u methods:\n", b, b->GlobalInterfaceID, b->NumMethods);
67 for (i = 0; i < b->NumMethods; i++)
68 bug("[META] Method ID 0x%08X function 0x%p\n", i, b->MethodTable[i].MethodFunc);
71 #else
73 #define dump_bucket(b)
75 #endif
77 /********************
78 ** IFMeta::New() **
79 ********************/
80 static OOP_Object *ifmeta_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
82 struct IntOOPBase *OOPBase = (struct IntOOPBase *)cl->OOPBasePtr;
83 struct Library *UtilityBase = OOPBase->ob_UtilityBase;
84 IPTR (*domethod)(OOP_Object *, OOP_Msg) = NULL;
85 IPTR (*coercemethod)(OOP_Class *, OOP_Object *, OOP_Msg) = NULL;
86 IPTR (*dosupermethod)(OOP_Class *, OOP_Object *, OOP_Msg) = NULL;
88 EnterFunc(bug("IFMeta::New(cl=%s, (0x%p), msg = %p)\n",
89 cl->ClassNode.ln_Name, cl, msg));
91 /* Let the BaseMeta class initialize some stuff for us */
92 o = (OOP_Object *)OOP_DoSuperMethod((OOP_Class *)cl, o, (OOP_Msg)msg);
93 D(bug("IFMeta: Superclass returned 0x%p\n", o));
95 if (o)
98 struct ifmeta_inst *inst;
100 inst = (struct ifmeta_inst *)o;
102 domethod = (IPTR (*)())GetTagData(aMeta_DoMethod, 0, msg->attrList);
103 coercemethod = (IPTR (*)())GetTagData(aMeta_CoerceMethod, 0, msg->attrList);
104 dosupermethod = (IPTR (*)())GetTagData(aMeta_DoSuperMethod, 0, msg->attrList);
107 D(bug("Instance allocated %p\n", inst));
110 if (!domethod)
111 domethod = Meta_DoMethod;
113 if (!coercemethod)
114 coercemethod = Meta_CoerceMethod;
116 if (!dosupermethod)
119 OOP_Class *superptr = inst->base.public.superclass;
120 if (superptr)
122 D(bug("Got superptr: %p\n", superptr));
123 /* Use superclass' DoSupermethod call if superclass isn't
124 an instance of the HIDDMetaClass
126 if (OOP_OCLASS(superptr) != (OOP_Class *)cl)
128 D(bug("superptr has different meta\n"));
130 dosupermethod = superptr->cl_DoSuperMethod;
132 else
134 D(bug("superptr has same meta\n"));
136 dosupermethod = Meta_DoSuperMethod;
140 else /* if (class has no superclass) */
142 dosupermethod = NULL;
147 inst->base.public.OOPBasePtr = OOPBase;
149 inst->base.public.cl_DoMethod = domethod;
150 inst->base.public.cl_CoerceMethod = coercemethod;
151 inst->base.public.cl_DoSuperMethod = dosupermethod;
153 D(bug("Classes' functions set\n"));
156 ReturnPtr ("IFMeta::New", OOP_Object *, o);
159 /******************************
160 ** IFMeta::allocdisptabs() **
161 ******************************/
163 /* Allocates and initializes the interface hashtable, and the methodtables */
164 static BOOL ifmeta_allocdisptabs(OOP_Class *cl, OOP_Object *o, struct P_meta_allocdisptabs *msg)
166 struct IntOOPBase *OOPBase = (struct IntOOPBase *)cl->OOPBasePtr;
167 ULONG num_if;
169 struct ifmeta_inst *inst = (struct ifmeta_inst *)o;
171 EnterFunc(bug("IFMeta::allocdisptabs(cl=%p, o=%p,ifDescr=%p)\n",
172 cl, o, msg->ifdescr));
174 /* Get number of needed hash entries */
175 num_if = calc_ht_entries(inst, msg->superclass, msg->ifdescr, OOPBase);
177 inst->base.numinterfaces = num_if;
179 D(bug("numinterfaces set to %ld\n", num_if));
181 /* Create a new integer hashtable, with a reasonable size */
182 inst->data.iftable = NewHash(num_if, HT_INTEGER, OOPBase);
183 if (inst->data.iftable)
185 const struct OOP_InterfaceDescr *ifdescr;
187 D(bug("Got iftable\n"));
188 /* Save hashmask for use in method lookup */
189 inst->data.hashmask = HashMask(inst->data.iftable);
191 if (msg->superclass) /* This test makes it work for initializing root classes */
194 /* Copy parent interfaces into the new class */
195 struct IFMethod *superif;
196 struct P_meta_iterateifs ii_msg;
197 CONST_STRPTR interface_id;
198 ULONG num_methods;
200 /* must be initialized to zero */
201 IPTR iterval = 0UL;
203 D(bug("Adding superclass' methods\n"));
205 ii_msg.mid = OOP_GetMethodID(IID_Meta, MO_meta_iterateifs);
207 ii_msg.iterval_ptr = &iterval;
208 ii_msg.interface_id_ptr = &interface_id;
209 ii_msg.num_methods_ptr = &num_methods;
212 for (;;)
214 struct IFBucket *ifb = NULL;
215 ULONG local_id = 0;
217 superif = (struct IFMethod *)OOP_CoerceMethod(OOP_OCLASS(msg->superclass)
218 ,(OOP_Object *)msg->superclass
219 ,(OOP_Msg)&ii_msg);
220 if (!superif)
221 break;
223 /* Get correct ID for the interface (string ID => interface ID mapping) */
224 if (init_mi_methodbase(interface_id, &local_id, OOPBase))
226 /* Allocate and insert the interface into the new class */
227 ifb = createbucket(interface_id, local_id, num_methods);
230 if (!ifb)
231 goto failure;
233 /* Copy the interface */
234 D(bug("[META] Copying from superclass methods for if %s, local ID 0x%08X, basmetaroot %p, superif %p\n",
235 ifb->GlobalInterfaceID, ifb->InterfaceID, OOPBase->ob_BaseMetaObject.inst.rootif, superif));
237 CopyMem(superif, ifb->MethodTable, sizeof(struct IFMethod) * num_methods);
238 InsertBucket(inst->data.iftable, (struct Bucket *)ifb, OOPBase);
240 } /* for (;;) */
242 } /* if (we inherit interfaces from some superclass) */
244 /* Insert our own interfaces */
245 D(bug("[META] Inserting own methods...\n"));
246 for ( ifdescr = msg->ifdescr; ifdescr->MethodTable; ifdescr ++)
248 struct IFBucket *ifb;
249 ULONG i;
250 ULONG iid;
251 ULONG num_methods = 0;
253 /* Get variable interface ID */
254 D(bug("[META] Getting Local ifID for global ID %s\n", ifdescr->InterfaceID));
255 if (!init_mi_methodbase(ifdescr->InterfaceID, &iid, OOPBase))
256 goto failure;
258 D(bug("[META] Got local ifID 0x%08X\n", iid));
261 * Count how many methods we are going to have in our interface.
262 * Caller-supplied MethodTable in interface descriptor table may
263 * have skipped entries (noone promised that it will cover the
264 * whole range from 0 to maximum method offset). However our bucket's
265 * MethodTable must cover the whole range, since method offset is an
266 * index into this table (see Meta_CoerceMethod() below).
267 * So we determine the largest offset and then add 1.
269 * v42.1 : ifdescr->NumMethods is completely ignored. This member is
270 * actually redundant and not needed.
272 for (i = 0; ifdescr->MethodTable[i].MethodFunc; i++)
274 if (ifdescr->MethodTable[i].MethodIdx > num_methods)
275 num_methods = ifdescr->MethodTable[i].MethodIdx;
278 num_methods++;
279 D(bug("[META] Interface will have %u methods\n", num_methods));
281 /* Lookup hashtable to see if interface has been copied from superclass */
282 ifb = (struct IFBucket *)inst->data.iftable->Lookup(
283 inst->data.iftable
284 , (IPTR)iid
285 , OOPBase);
287 D(bug("[META] tried to find bucket in hashtable: 0x%p\n", ifb));
288 if (!ifb)
290 D(bug("[META] Bucket doesn't exist, creating...\n"));
292 /* Bucket doesn't exist, allocate it */
293 ifb = createbucket(ifdescr->InterfaceID, iid, num_methods);
294 if (!ifb)
295 goto failure;
296 else
298 D(bug("[META] Inserting bucket 0x%p for IF %s\n", ifb, ifdescr->InterfaceID));
299 InsertBucket(inst->data.iftable, (struct Bucket *)ifb, OOPBase);
302 else if (ifb->NumMethods < num_methods)
304 D(bug("[META] Current bucket has %u methods, expanding...\n", ifb->NumMethods));
306 if (!expandbucket(ifb, num_methods))
307 goto failure;
310 D(bug("[META] overriding methods...\n"));
312 /* Ovveride the superclass methods with our new ones */
313 for (i = 0; ifdescr->MethodTable[i].MethodFunc; i ++)
315 D(bug("[META] Method ID 0x%08X function 0x%p\n", ifdescr->MethodTable[i].MethodIdx, ifdescr->MethodTable[i].MethodFunc));
317 ifb->MethodTable[ ifdescr->MethodTable[i].MethodIdx ].MethodFunc = ifdescr->MethodTable[i].MethodFunc;
318 ifb->MethodTable[ ifdescr->MethodTable[i].MethodIdx ].mClass = (OOP_Class *)o;
319 } /* for (each method in the interface) */
321 } /* for (each interface to add to class) */
323 /* For speedup in method lookup */
324 inst->data.iftab_directptr = (struct IFBucket **)inst->data.iftable->Table;
326 ReturnBool ("IFMeta::allocdisptabs", TRUE);
328 } /* if (interface hash table allocated) */
330 failure:
331 D(bug("FAILURE\n"));
332 if (inst->data.iftable)
333 FreeHash(inst->data.iftable, freebucket, OOPBase);
334 ReturnBool ("IFMeta::allocdisptabs", FALSE);
337 /*****************************
338 ** IFMeta::freedisptabs() **
339 *****************************/
340 static VOID ifmeta_freedisptabs(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
343 struct IntOOPBase *OOPBase = (struct IntOOPBase *)cl->OOPBasePtr;
344 struct ifmeta_inst *inst = (struct ifmeta_inst *)o;
345 /* This frees the hashtable + all buckets */
347 FreeHash(inst->data.iftable, freebucket, OOPBase);
349 return;
352 /**************************
353 ** IFMeta::getifinfo() **
354 **************************/
355 static struct IFMethod *ifmeta_getifinfo(OOP_Class *cl, OOP_Object *o, struct P_meta_getifinfo *msg)
357 struct IntOOPBase *OOPBase = (struct IntOOPBase *)cl->OOPBasePtr;
358 ULONG iid;
359 struct ifmeta_inst *inst = (struct ifmeta_inst *)o;
360 struct IFMethod *mtab = NULL;
361 struct IFBucket *b;
363 /* Get the ULONG variable interface id */
364 iid = OOP_GetMethodID(msg->interface_id, 0);
366 /* Try looking it up in the class' table */
367 b = (struct IFBucket *)inst->data.iftable->Lookup(inst->data.iftable, (IPTR)iid, OOPBase);
369 *(msg->num_methods_ptr) = b->NumMethods;
371 mtab = b->MethodTable;
374 return mtab;
377 /***************************
378 ** IFMeta::iterateifs() **
379 ***************************/
380 static struct IFMethod *ifmeta_iterateifs(OOP_Class *cl, OOP_Object *o, struct P_meta_iterateifs *msg)
382 struct HashTable *ht = ((struct ifmeta_inst *)o)->data.iftable;
383 struct IFBucket *found_bucket = NULL; /* MUST default to NULL */
385 struct IFBucket *ifb = NULL; /* keep compiler happy */
388 struct IFMethod *current_if = NULL; /* MUST default to NULL */
390 UWORD last_idx = (*(msg->iterval_ptr)) >> 16;
391 UWORD last_bucket_no = (*(msg->iterval_ptr)) & 0x0000FFFF;
393 UWORD idx;
395 UWORD bucket_no = 0; /* keep compiler happy */
396 EnterFunc(bug("IFMeta::iterateifs(cl=%s, o=%s)\n",
397 cl->ClassNode.ln_Name, ((OOP_Class *)o)->ClassNode.ln_Name ));
399 D(bug("last_idx: %ld, last_bucket_no=%ld\n", last_idx, last_bucket_no));
402 for (idx = last_idx ;idx < HashSize(ht); idx ++)
404 D(bug("idx=%ld\n", idx));
406 bucket_no = 0;
408 for (ifb = (struct IFBucket *)ht->Table[idx]; ifb; )
410 D(bug("ifb=%s, netx=%p, bucket_no=%ld\n",
411 ifb->GlobalInterfaceID, ifb->Next, bucket_no));
412 /* Is this a new bucket in the iteration ? */
414 if ((idx > last_idx) || (bucket_no >= last_bucket_no))
416 found_bucket = ifb;
418 /* Yes, it's a goto, but it really simplifies things here */
419 goto after_loop;
421 else
423 ifb = ifb->Next;
424 bucket_no ++;
427 } /* for (all buckets at each idx) */
429 } /* for (each entry at east index from last idx) */
431 after_loop:
433 /* OK, found a bucket ? */
434 if (found_bucket)
436 D(bug("bucket found: %s at idx %ld, b_no %ld\n",
437 found_bucket->GlobalInterfaceID, idx, bucket_no));
438 *(msg->iterval_ptr) = (idx << 16) + bucket_no + 1;
439 *(msg->interface_id_ptr) = ifb->GlobalInterfaceID;
440 *(msg->num_methods_ptr) = ifb->NumMethods;
442 current_if = ifb->MethodTable;
445 ReturnPtr ("IFMeta::iterateifs", struct IFMethod *, current_if);
448 /***************************
449 ** IFMeta::findmethod() **
450 ***************************/
452 /* Used for finding a method for method objects */
453 static struct IFMethod *ifmeta_findmethod(OOP_Class *cl, OOP_Object *o, struct P_meta_findmethod *msg)
455 register struct IFBucket *b;
456 register ULONG method_offset;
457 struct ifmeta_inst *inst = (struct ifmeta_inst *)o;
459 /* Get interfaceID part of methodID */
460 register ULONG ifid = msg->method_to_find & (~METHOD_MASK);
462 EnterFunc(bug("IFMeta::findmethod(o=%p, mid=%ld)\n", o, msg->method_to_find));
465 /* Get method offset part of methdoID */
466 method_offset = msg->method_to_find & METHOD_MASK;
468 /* Look up ID in hashtable and get linked list of buckets,
469 storing interfaces
471 b = inst->data.iftab_directptr[ifid & inst->data.hashmask];
472 loop:
473 if (b)
475 /* Found correct interface ? */
476 if (b->InterfaceID == ifid)
478 /* Yep. Return method at supplied method offset */
479 ReturnPtr ("IFMeta::findmethod", struct IFMethod *, &(b->MethodTable[method_offset]));
482 b = b->Next;
483 goto loop;
485 /* Method not found, return NULL */
486 ReturnPtr ("IFMeta::findmethod", struct IFMethod *, NULL);
490 /**********
491 Support
492 **********/
494 /*************************
495 ** init_ifmetaclass() **
496 *************************/
498 #define NUM_META_METHODS 5
499 #define NUM_ROOT_METHODS 1
501 static const struct OOP_MethodDescr root_mdescr[NUM_ROOT_METHODS + 1]=
503 { (IPTR (*)())ifmeta_new, moRoot_New },
504 { NULL, 0UL }
507 static const struct OOP_MethodDescr meta_mdescr[NUM_META_METHODS + 1]=
509 { (IPTR (*)())ifmeta_allocdisptabs, MO_meta_allocdisptabs },
510 { (IPTR (*)())ifmeta_freedisptabs, MO_meta_freedisptabs },
511 { (IPTR (*)())ifmeta_getifinfo, MO_meta_getifinfo },
512 { (IPTR (*)())ifmeta_iterateifs, MO_meta_iterateifs },
513 { (IPTR (*)())ifmeta_findmethod, MO_meta_findmethod },
514 { NULL, 0 }
517 static const struct OOP_InterfaceDescr meta_descr[] =
519 {root_mdescr, IID_Root, NUM_ROOT_METHODS},
520 {meta_mdescr, IID_Meta, NUM_META_METHODS},
521 {NULL, NULL, 0UL}
524 BOOL init_ifmetaclass(struct IntOOPBase *OOPBase)
527 struct ifmetaobject *imo = &(OOPBase->ob_IFMetaObject);
528 struct P_meta_allocdisptabs adt_msg;
529 OOP_Class *ifmeta_cl;
531 EnterFunc(bug("init_ifmetaclass()\n"));
533 ifmeta_cl = &(imo->inst.base.public);
535 D(bug("Got ifmeta classptr 0x%p\n", ifmeta_cl));
537 imo->inst.base.public.superclass = BASEMETAPTR;
538 imo->inst.base.public.OOPBasePtr = OOPBase;
540 D(bug("Initialized ifmeta superclass 0x%p\n", imo->inst.base.public.superclass));
542 adt_msg.superclass = imo->inst.base.public.superclass;
543 adt_msg.ifdescr = meta_descr;
545 /* allocdisptabs() must know the OOPBase */
546 imo->inst.base.public.UserData = (APTR)OOPBase;
547 /* It must also have a valid DoSuperMethod(), more exatly
548 the DoSuperMethod() of the BaseMeta class
550 imo->inst.base.public.cl_DoSuperMethod = BASEMETAPTR->cl_DoSuperMethod;
552 D(bug("Allocating ifmeta disptabs\n"));
554 if (ifmeta_allocdisptabs(ifmeta_cl, (OOP_Object *)ifmeta_cl, &adt_msg))
556 D(bug("ifmeta disptabs allocated\n"));
557 /* initialize Class ID */
559 imo->inst.base.public.ClassNode.ln_Name = CLID_MIMeta;
560 imo->inst.base.public.InstOffset = sizeof (struct metadata);
562 D(bug("IFMeta DoMethod=%p\n", Meta_DoMethod));
563 imo->inst.base.public.cl_DoMethod = Meta_DoMethod;
564 imo->inst.base.public.cl_CoerceMethod = Meta_CoerceMethod;
566 imo->inst.base.instsize = sizeof (struct ifmeta_data);
567 imo->inst.base.subclasscount = 0UL;
568 imo->inst.base.objectcount = 0UL;
570 imo->inst.data.numinterfaces = 2UL;
572 /* This class' class is itself */
573 imo->oclass = &(imo->inst.base.public);
575 /* {
576 ULONG i;
577 D(bug("Trying to call get_if_info on ifmeta many times\n"));
578 for (i = 0; i < 10; i ++)
580 ULONG num_methods;
581 meta_getifinfo((OOP_Object *)imo->oclass, IID_Meta, &num_methods);
583 D(bug("IF has %ld methods\n", num_methods));
587 */ /* Make it public */
588 OOP_AddClass(ifmeta_cl);
589 ReturnBool ("init_metaclass", TRUE);
591 ReturnBool ("init_ifmetaclass", FALSE);
596 /************************
597 ** calc_ht_entries() **
598 ************************/
600 /* Calculates the number of interfaces the new class has
601 ( == number of buckets in the hashtable)
603 static ULONG calc_ht_entries(struct ifmeta_inst *cl ,OOP_Class *super,
604 const struct OOP_InterfaceDescr *ifDescr, struct IntOOPBase *OOPBase)
606 ULONG num_if = 0;
608 EnterFunc(bug("calc_ht_entries(cl=%p, ifDescr=%p, super=%p)\n", cl, ifDescr, super));
610 if (super)
612 /* Get number of interfaces (method tables) in superclass */
614 num_if = MD(super)->numinterfaces;
616 D(bug("Super-interfaces: %ld\n", num_if));
618 /* Check if there are any new interfaces in this class */
620 for (; ifDescr->MethodTable; ifDescr ++)
622 struct P_meta_getifinfo gii_msg;
623 ULONG num_methods;
625 D(bug("Checking for interface %s\n", ifDescr->InterfaceID));
627 gii_msg.mid = OOP_GetMethodID(IID_Meta, MO_meta_getifinfo);
628 gii_msg.interface_id = ifDescr->InterfaceID;
629 gii_msg.num_methods_ptr = &num_methods;
632 /* Does super support interface ? */
633 D(bug("Calling CoerceMethod on class %s\n", OOP_OCLASS(super)->ClassNode.ln_Name));
634 if (!OOP_CoerceMethod(OOP_OCLASS(super), (OOP_Object *)super, (OOP_Msg)&gii_msg))
636 D(bug("Found new interface: %s\n", ifDescr->InterfaceID));
638 /* If it didn't then we have a new interface for this class */
639 num_if ++;
642 } /* for (each interface in the description for the class) */
645 else
647 /* This is a baseclass, count the interfaces */
648 for (; ifDescr->MethodTable; ifDescr ++)
650 num_if ++;
652 } /* for (each interface in the description for the class) */
654 ReturnInt ("calc_ht_entries", ULONG, num_if);
657 /*********************
658 ** createbucket() **
659 *********************/
660 /* Creates a new interface bucket */
661 static struct IFBucket *createbucket(CONST_STRPTR interface_id, ULONG local_id, ULONG num_methods)
663 /* Allocate bucket */
664 struct IFBucket *ifb;
666 ifb = AllocMem(sizeof (struct IFBucket), MEMF_ANY);
667 if (ifb)
669 /* Allocate method table for this interface */
670 ifb->MethodTable = AllocVec(sizeof(struct IFMethod) * num_methods, MEMF_CLEAR);
671 if (ifb->MethodTable)
673 /* Set correct ID for the interface (string ID => interface ID mapping) */
674 ifb->InterfaceID = local_id;
675 ifb->GlobalInterfaceID = interface_id;
677 /* Save number of methods in the interface */
678 ifb->NumMethods = num_methods;
680 D(bug("[META] Created bucket 0x%p for %u methods\n", ifb, num_methods));
681 return ifb;
683 FreeMem(ifb, sizeof (struct IFBucket));
685 return NULL;
688 /***********************
689 ** Hash table hooks **
690 ***********************/
691 #define IB(x) ((struct IFBucket *)x)
693 VOID freebucket(struct Bucket *b, struct IntOOPBase *OOPBase)
695 D(bug("[META] freebucket(0x%p)\n", b));
697 /* Free methodtable */
698 FreeVec(IB(b)->MethodTable);
700 /* Free the bucket itself */
701 FreeMem(b, sizeof (struct IFBucket));
704 return;
707 /* Copies a hashtable bucket */
708 struct Bucket *copyBucket(struct Bucket *old_b, APTR data, struct IntOOPBase *OOPBase)
710 struct IFBucket *new_b;
712 EnterFunc(bug("CopyBucket(old_b=%p)\n", old_b));
714 /* Allocate the new interface bucket */
715 new_b = createbucket(IB(old_b)->GlobalInterfaceID, IB(old_b)->InterfaceID, IB(old_b)->NumMethods);
717 if (new_b)
718 /* Copy methodtable to destination */
719 CopyMem(IB(old_b)->MethodTable, new_b->MethodTable, sizeof(struct IFMethod) * IB(old_b)->NumMethods);
721 ReturnPtr ("CopyBucket", struct Bucket *, (struct Bucket *)new_b );
724 /* Expand method table in IFBucket up to num_methods entries */
725 static BOOL expandbucket(struct IFBucket *b, ULONG num_methods)
727 struct IFMethod *ifm = AllocVec(sizeof(struct IFMethod) * num_methods, MEMF_CLEAR);
729 if (!ifm)
730 return FALSE;
732 CopyMem(b->MethodTable, ifm, sizeof(struct IFMethod) * b->NumMethods);
733 FreeVec(b->MethodTable);
734 b->MethodTable = ifm;
736 return TRUE;
739 /* Default function for calling DoMethod() on a local object */
740 /*****************
741 ** DoMethod() **
742 *****************/
744 static IPTR Meta_DoMethod(OOP_Object *object, OOP_Msg msg)
746 D(bug("[META] DoMethod(0x%p), class 0x%p\n", object, OOP_OCLASS(object)));
748 return Meta_CoerceMethod(OOP_OCLASS(object), object, msg);
751 /*******************
752 ** CoerceMethod **
753 *******************/
754 static IPTR Meta_CoerceMethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
756 register struct IFBucket *b;
757 register OOP_MethodID mid = *msg;
758 register ULONG ifid = mid & (~METHOD_MASK);
760 mid &= METHOD_MASK;
762 b = IFI(cl)->data.iftab_directptr[ifid & IFI(cl)->data.hashmask];
763 while (b)
765 if (b->InterfaceID == ifid)
767 dump_bucket(b);
769 /* Ensure that method offset fits into the table */
770 if (mid < b->NumMethods)
772 register struct IFMethod *method = &b->MethodTable[mid];
774 if (method->MethodFunc)
775 return method->MethodFunc(method->mClass, o, msg);
779 * TODO: Looks like it would be nice to post alerts with some extra information
780 * attached.
781 * Current exec.library API does not allow this. Need to invent something.
783 bug("[OOP metaclass] Unimplemented method 0x%08X called on class 0x%p (%s)\n", mid, cl, cl->ClassNode.ln_Name);
784 bug("[OOP metaclass] Interface ID %s\n", b->GlobalInterfaceID);
785 bug("[OOP metaclass] Object 0x%p\n", o);
788 * Throw an alert. It is recoverable, so won't harm.
789 * But the developer will be able to examine a stack trace.
791 Alert(AN_OOP);
793 return 0;
795 b = b->Next;
798 return 0;
801 /********************
802 ** DoSuperMethod **
803 ********************/
804 static IPTR Meta_DoSuperMethod(OOP_Class *cl, OOP_Object *object, OOP_Msg msg)
806 return Meta_CoerceMethod(IFI(cl)->base.public.superclass, object, msg);