2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
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>
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
);
40 VOID
freebucket(struct Bucket
*b
, struct IntOOPBase
*OOPBase
);
41 struct Bucket
*copybucket(struct Bucket
*old_b
, APTR data
, struct IntOOPBase
*OOPBase
);
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
61 static void dump_bucket(struct IFBucket
*b
)
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
);
73 #define dump_bucket(b)
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
));
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
));
111 domethod
= Meta_DoMethod
;
114 coercemethod
= Meta_CoerceMethod
;
119 OOP_Class
*superptr
= inst
->base
.public.superclass
;
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
;
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
;
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
;
200 /* must be initialized to zero */
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
;
214 struct IFBucket
*ifb
= NULL
;
217 superif
= (struct IFMethod
*)OOP_CoerceMethod(OOP_OCLASS(msg
->superclass
)
218 ,(OOP_Object
*)msg
->superclass
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
);
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
);
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
;
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
))
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
;
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(
287 D(bug("[META] tried to find bucket in hashtable: 0x%p\n", 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
);
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
))
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) */
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
);
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
;
359 struct ifmeta_inst
*inst
= (struct ifmeta_inst
*)o
;
360 struct IFMethod
*mtab
= NULL
;
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
;
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;
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
));
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
))
418 /* Yes, it's a goto, but it really simplifies things here */
427 } /* for (all buckets at each idx) */
429 } /* for (each entry at east index from last idx) */
433 /* OK, found a 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,
471 b
= inst
->data
.iftab_directptr
[ifid
& inst
->data
.hashmask
];
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
]));
485 /* Method not found, return NULL */
486 ReturnPtr ("IFMeta::findmethod", struct IFMethod
*, NULL
);
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
},
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
},
517 static const struct OOP_InterfaceDescr meta_descr
[] =
519 {root_mdescr
, IID_Root
, NUM_ROOT_METHODS
},
520 {meta_mdescr
, IID_Meta
, NUM_META_METHODS
},
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);
577 D(bug("Trying to call get_if_info on ifmeta many times\n"));
578 for (i = 0; i < 10; i ++)
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
)
608 EnterFunc(bug("calc_ht_entries(cl=%p, ifDescr=%p, super=%p)\n", cl
, ifDescr
, 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
;
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 */
642 } /* for (each interface in the description for the class) */
647 /* This is a baseclass, count the interfaces */
648 for (; ifDescr
->MethodTable
; ifDescr
++)
652 } /* for (each interface in the description for the class) */
654 ReturnInt ("calc_ht_entries", ULONG
, num_if
);
657 /*********************
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
);
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
));
683 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
)
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
));
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
);
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
);
732 CopyMem(b
->MethodTable
, ifm
, sizeof(struct IFMethod
) * b
->NumMethods
);
733 FreeVec(b
->MethodTable
);
734 b
->MethodTable
= ifm
;
739 /* Default function for calling DoMethod() on a local object */
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
);
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
);
762 b
= IFI(cl
)->data
.iftab_directptr
[ifid
& IFI(cl
)->data
.hashmask
];
765 if (b
->InterfaceID
== ifid
)
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
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.
801 /********************
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
);