2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
9 #include <proto/exec.h>
10 #include <proto/oop.h>
11 #include <proto/utility.h>
12 #include <exec/memory.h>
23 #include <aros/debug.h>
25 #define MD(x) ((struct metadata *)x)
27 /***************************
28 ** RootClass' metaclass **
29 ***************************/
30 /* The root class' meta class is not really needed, but
31 it makes code of other metaclasses more consistent
34 #define OOPBase ((struct IntOOPBase *)(cl->OOPBasePtr))
35 #define IS_META_ATTR(attr, idx) ( (idx = attr - MetaAttrBase) < num_Meta_Attrs )
36 /**********************
38 **********************/
39 static OOP_Object
*basemeta_new(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
41 struct metadata
*data
;
43 struct OOP_InterfaceDescr
*ifdescr
= NULL
;
44 STRPTR superid
= NULL
, clid
= "-- private class -- ";
45 struct metadata
*superptr
= NULL
;
46 struct TagItem
*tag
, *tstate
;
47 ULONG instsize
= (ULONG
)-1L;
51 EnterFunc(bug("BaseMeta::New(cl=%s, msg = %p)\n",
52 cl
->ClassNode
.ln_Name
, msg
));
54 /* Analyze the taglist before object is allocated,
55 ** so we can easily exit cleanly if some info is missing
58 tstate
= msg
->attrList
;
60 while ((tag
= NextTagItem((const struct TagItem
**)&tstate
)))
62 if (IS_META_ATTR(tag
->ti_Tag
, idx
))
64 D(bug("Got meta attr %lx with TagIdx %ld\n",
71 /* ID of superclass */
72 superid
= (STRPTR
)tag
->ti_Data
;
73 D(bug("Got superID: %s\n", superid
));
76 case aoMeta_InterfaceDescr
:
77 D(bug("Got ifdescr\n"));
78 /* What interfaces does the class support ? */
79 ifdescr
= (struct OOP_InterfaceDescr
*)tag
->ti_Data
;
83 /* The new class' ID */
84 clid
= (STRPTR
)tag
->ti_Data
;
85 D(bug("Got classID: %s\n", clid
));
89 D(bug("Got superPtr\n"));
90 /* If the super class is private, than we must have
93 superptr
= (struct metadata
*)tag
->ti_Data
;
97 /* Instance data size for the new class */
98 instsize
= (ULONG
)tag
->ti_Data
;
107 /* The user must supply instance size */
108 if (instsize
== (ULONG
)-1)
109 ReturnPtr ("Meta::New, no instsize", OOP_Object
*, NULL
);
111 /* The new class must have interfaces */
113 ReturnPtr ("Meta::New, no ifdescr", OOP_Object
*, NULL
);
115 /* The new class must have a superclass */
120 superptr
= (struct metadata
*)FindName((struct List
*)&(GetOBase(OOPBase
)->ob_ClassList
), superid
);
122 ReturnPtr ("Meta::New, no superptr/id", OOP_Object
*, NULL
);
126 /* We are sure we have enough args, and can let rootclass alloc the instance data */
127 o
= (OOP_Object
*)OOP_DoSuperMethod((OOP_Class
*)cl
, o
, (OOP_Msg
)msg
);
131 ULONG dispose_mid
= OOP_GetMethodID(IID_Root
, moRoot_Dispose
);
133 D(bug("Instance allocated\n"));
135 data
= OOP_INST_DATA(cl
, o
);
137 D(bug("o=%p,data=%p\n", o
, data
));
138 D(bug("instoffset: %ld\n", cl
->InstOffset
));
140 /* Clear instdata, so we in Dispose() can see what's been allocated */
141 memset(data
, 0, sizeof (struct metadata
));
143 D(bug("superptr=%p\n", superptr
));
145 data
->public.OOPBasePtr
= (struct IntOOPBase
*)OOPBase
;
148 /* Let subclass create an initialize dispatch tables for the new class object*/
149 if (meta_allocdisptabs(o
, (OOP_Class
*)superptr
, ifdescr
))
151 data
->disptabs_inited
= TRUE
;
153 /* Copy the class' ID */
154 D(bug("Allocating class ID\n"));
155 data
->public.ClassNode
.ln_Name
= AllocVec(strlen (clid
) + 1, MEMF_ANY
);
156 if (data
->public.ClassNode
.ln_Name
)
158 D(bug("class ID allocated\n"));
160 /* Initialize class fields */
161 D(bug("Setting instoffset\n"));
164 data
->public.InstOffset
= superptr
->public.InstOffset
+ superptr
->instsize
;
166 data
->public.InstOffset
= 0UL;
167 D(bug("Setting other stuff\n"));
169 data
->subclasscount
= 0UL;
170 data
->objectcount
= 0UL;
171 data
->superclass
= (OOP_Class
*)superptr
;
172 data
->instsize
= instsize
;
174 D(bug("Copying class ID\n"));
176 strcpy(data
->public.ClassNode
.ln_Name
, clid
);
179 ReturnPtr ("Meta::New", OOP_Object
*, o
);
183 OOP_CoerceMethod((OOP_Class
*)cl
, o
, (OOP_Msg
)&dispose_mid
);
186 ReturnPtr ("Meta::New", OOP_Object
*, NULL
);
190 /**************************
191 ** BaseMeta::Dispose() **
192 **************************/
193 static VOID
basemeta_dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
195 struct metadata
*data
= OOP_INST_DATA(cl
, o
);
197 STRPTR interface_id
= NULL
;
198 ULONG num_methods
= 0UL;
200 if (data
->public.ClassNode
.ln_Name
)
201 FreeVec(data
->public.ClassNode
.ln_Name
);
203 /* Release interfaces from global interface table */
204 while (meta_iterateifs(o
, &iterval
, &interface_id
, &num_methods
))
206 /* Only release the interfaces that were new for the class */
207 if (!meta_getifinfo((OOP_Object
*)MD(o
)->superclass
, interface_id
, &num_methods
))
208 release_idbucket(interface_id
, GetOBase(OOPBase
));
212 if (data
->disptabs_inited
)
213 meta_freedisptabs(o
);
215 OOP_DoSuperMethod(cl
, o
, msg
);
221 /****************************
222 ** BaseMeta::getifinfo() **
223 ****************************/
224 static struct IFMethod
*basemeta_getifinfo(OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_getifinfo
*msg
)
226 struct IFMethod
*mtab
= NULL
;
227 EnterFunc(bug("BaseMeta::hasinterface(cl=%p, o=%p, iid=%s\n",
228 cl
, o
, msg
->interface_id
));
230 /* The object passed might be one of two classes: Root class or basemetaclass */
231 if (0 == strcmp(msg
->interface_id
, IID_Root
))
233 /* Both classes support the root interface */
234 D(bug("Root interface\n"));
235 *(msg
->num_methods_ptr
) = num_Root_Methods
;
236 if ( ((OOP_Class
*)o
) == BASEMETAPTR
)
238 mtab
= OOPBase
->ob_BaseMetaObject
.inst
.rootif
;
242 mtab
= OOPBase
->ob_RootClassObject
.inst
.rootif
;
246 else if (0 == strcmp(msg
->interface_id
, IID_Meta
))
248 D(bug("Meta interface. BASEMETAPTR: %p\n", BASEMETAPTR
));
249 if ( ((OOP_Class
*)o
) == BASEMETAPTR
)
252 /* Only BaseMeta has Meta interface */
253 mtab
= OOPBase
->ob_BaseMetaObject
.inst
.metaif
;
254 *(msg
->num_methods_ptr
) = NUMTOTAL_M_Meta
;
258 ReturnPtr ("BaseMeta::hasinterface", struct IFMethod
*, mtab
);
262 /*****************************
263 ** BaseMeta::iterateifs() **
264 *****************************/
265 static struct IFMethod
*basemeta_iterateifs(
266 OOP_Class
*cl
, OOP_Object
*o
, struct P_meta_iterateifs
*msg
)
268 struct IFMethod
*current_if
= NULL
;
270 EnterFunc(bug("BaseMeta::iterateifs(o=%p)\n", o
));
272 /* As in has_interface() the object here can only be the basemetaclass, or rootclass */
273 if (((OOP_Class
*)o
) == ROOTCLASSPTR
)
275 /* Rootclass have only one interface */
276 if ( *(msg
->iterval_ptr
) )
282 current_if
= OOPBase
->ob_RootClassObject
.inst
.rootif
;
283 *(msg
->num_methods_ptr
) = num_Root_Methods
;
284 *(msg
->interface_id_ptr
) = IID_Root
;
285 *(msg
->iterval_ptr
) = 1UL; /* We're through iterating */
288 else if (((OOP_Class
*)o
) == BASEMETAPTR
)
290 struct basemeta_inst
*inst
= (struct basemeta_inst
*)o
;
291 switch (*(msg
->iterval_ptr
))
294 current_if
= inst
->rootif
;
295 *(msg
->num_methods_ptr
) = num_Root_Methods
;
296 *(msg
->interface_id_ptr
) = IID_Root
;
300 current_if
= inst
->metaif
;
301 *(msg
->num_methods_ptr
) = NUMTOTAL_M_Meta
;
302 *(msg
->interface_id_ptr
) = IID_Meta
;
310 (*(msg
->iterval_ptr
)) ++;
315 /* Should never get here, unless someone has created an instance
316 of the BaseMeta class (which is meaningless)
323 D(bug("Current IF: %s, num_methods %ld\n",
324 *(msg
->interface_id_ptr
), *(msg
->num_methods_ptr
)));
327 ReturnPtr ("BaseMeta::iterate_ifs", struct IFMethod
*, current_if
);
333 /*******************************
334 ** BaseMeta DoSuperMethod() **
335 *******************************/
336 /* cl->USerData passed to DoSuperMethodA might be
337 a subclass of rootclass, which does not have
338 the OOPBase in cl->UserData, so instead we use the
339 meta's UserData (IFMeta or HIDDMeta class
342 #define OOPBase ((struct IntOOPBase *)cl->OOPBasePtr)
344 static IPTR
basemeta_dosupermethod(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
346 ULONG method_offset
= *msg
& METHOD_MASK
;
347 struct IFMethod
*ifm
;
349 EnterFunc(bug("basemeta_dosupermethod(cl=%p, o=%p, msg=%p)\n",
352 if (MD(cl
)->superclass
== ROOTCLASSPTR
)
354 ifm
= &(OOPBase
->ob_RootClassObject
.inst
.rootif
[*msg
]);
356 else /* superclass is the BaseMeta class */
358 switch (*msg
>> NUM_METHOD_BITS
)
362 ifm
= &(OOPBase
->ob_BaseMetaObject
.inst
.rootif
[method_offset
]);
366 ifm
= &(OOPBase
->ob_BaseMetaObject
.inst
.metaif
[method_offset
]);
371 D(bug("Error: basemeta_dosupermethod got method call to unknown interface %d\n",
372 *msg
>> NUM_METHOD_BITS
));
377 ReturnPtr ("basemeta_dosupermethod", IPTR
, ifm
->MethodFunc(ifm
->mClass
, o
, msg
));
382 #define OOPBase ((struct IntOOPBase *)(cl->OOPBasePtr))
383 /*******************************
384 ** BaseMeta CoerceMethod() **
385 *******************************/
386 static IPTR
basemeta_coercemethod(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
388 ULONG method_offset
= *msg
& METHOD_MASK
;
389 struct IFMethod
*ifm
;
391 EnterFunc(bug("basemeta_coercemethod(cl=%p, o=%p, msg=%p)\n",
395 switch (*msg
>> NUM_METHOD_BITS
)
399 ifm
= &(OOPBase
->ob_BaseMetaObject
.inst
.rootif
[method_offset
]);
403 ifm
= &(OOPBase
->ob_BaseMetaObject
.inst
.metaif
[method_offset
]);
408 D(bug("Error: basemeta_coercemethod got method call to unknown interface %d\n",
409 *msg
>> NUM_METHOD_BITS
));
413 ReturnPtr ("basemeta_coercemethod", IPTR
, ifm
->MethodFunc(ifm
->mClass
, o
, msg
));
416 /************************
417 ** BaseMeta DoMethod **
418 ************************/
420 static IPTR
basemeta_domethod(OOP_Object
*o
, OOP_Msg msg
)
422 return basemeta_coercemethod(OOP_OCLASS(o
), o
, msg
);
426 /**********************
427 ** init_basemeta() **
428 **********************/
430 BOOL
init_basemeta(struct IntOOPBase
*OOPBase
)
432 struct basemetaobject
*bmo
;
436 EnterFunc(bug("init_basemeta()\n"));
438 bmo
= &(OOPBase
->ob_BaseMetaObject
);
439 bmo
->oclass
= BASEMETAPTR
;
441 bmo
->inst
.data
.public.ClassNode
.ln_Name
= "private base metaclass";
442 bmo
->inst
.data
.public.OOPBasePtr
= (struct Library
*)OOPBase
;
443 bmo
->inst
.data
.public.InstOffset
= 0UL;
444 bmo
->inst
.data
.public.UserData
= OOPBase
;
445 bmo
->inst
.data
.public.cl_DoSuperMethod
= basemeta_dosupermethod
;
446 bmo
->inst
.data
.public.cl_CoerceMethod
= basemeta_coercemethod
;
447 bmo
->inst
.data
.public.cl_DoMethod
= basemeta_domethod
;
449 bmo
->inst
.data
.superclass
= ROOTCLASSPTR
;
450 bmo
->inst
.data
.subclasscount
= 0UL;
451 bmo
->inst
.data
.objectcount
= 0UL;
452 bmo
->inst
.data
.instsize
= sizeof (struct metadata
);
453 bmo
->inst
.data
.numinterfaces
= NUM_BASEMETA_IFS
;
455 /* Initialize interface table */
456 bmo
->inst
.iftable
[0] = bmo
->inst
.rootif
;
457 bmo
->inst
.iftable
[1] = bmo
->inst
.metaif
;
459 /* initialize interfaces */
460 bmo
->inst
.rootif
[moRoot_New
].MethodFunc
= (IPTR (*)())basemeta_new
;
461 bmo
->inst
.rootif
[moRoot_Dispose
].MethodFunc
= (IPTR (*)())basemeta_dispose
;
463 bmo
->inst
.rootif
[moRoot_New
].mClass
= BASEMETAPTR
;
464 bmo
->inst
.rootif
[moRoot_Dispose
].mClass
= BASEMETAPTR
;
466 /* Initialize meta interface */
467 bmo
->inst
.metaif
[MO_meta_allocdisptabs
].MethodFunc
= (IPTR (*)())NULL
;
468 bmo
->inst
.metaif
[MO_meta_freedisptabs
].MethodFunc
= (IPTR (*)())NULL
;
469 bmo
->inst
.metaif
[MO_meta_getifinfo
].MethodFunc
= (IPTR (*)())basemeta_getifinfo
;
470 bmo
->inst
.metaif
[MO_meta_iterateifs
].MethodFunc
= (IPTR (*)())basemeta_iterateifs
;
472 bmo
->inst
.metaif
[MO_meta_allocdisptabs
].mClass
= BASEMETAPTR
;
473 bmo
->inst
.metaif
[MO_meta_freedisptabs
].mClass
= BASEMETAPTR
;
474 bmo
->inst
.metaif
[MO_meta_getifinfo
].mClass
= BASEMETAPTR
;
475 bmo
->inst
.metaif
[MO_meta_iterateifs
].mClass
= BASEMETAPTR
;
477 /* Meta interface ID gets initialized to 1 */
478 success
= init_mi_methodbase(IID_Meta
, &mbase
, OOPBase
);
480 ReturnBool ("init_basemeta", success
);
484 /* Root class is the base class of all classes.
485 (Well, one can create new baseclasses, but all classes must
486 implement the root interface).
489 /************************
490 ** Rootclass methods **
491 ************************/
496 #define OOPBase ((struct IntOOPBase*)(root_cl->OOPBasePtr))
499 OOP_Object
*root_new(OOP_Class
*root_cl
, OOP_Class
*cl
, struct pRoot_New
*param
)
501 struct _OOP_Object
*o
;
502 struct RootData
*data
;
504 EnterFunc(bug("Root::New(cl=%s, param = %p)\n",
505 cl
->ClassNode
.ln_Name
, param
));
507 /* Allocate memory for the object */
508 D(bug("Object size: %ld\n", MD(cl
)->public.InstOffset
+ MD(cl
)->instsize
+ sizeof (struct _OOP_Object
)));
509 o
= AllocVec(MD(cl
)->public.InstOffset
+ MD(cl
)->instsize
+ sizeof (struct _OOP_Object
), MEMF_ANY
|MEMF_CLEAR
);
512 D(bug("Mem allocated: %p\n", o
));
513 o
->o_Class
= (OOP_Class
*)cl
;
515 data
= (struct RootData
*)OOP_BASEOBJECT(o
);
517 /* Class has one more object */
518 MD(cl
)->objectcount
++;
520 ReturnPtr ("Root::New", OOP_Object
*, OOP_BASEOBJECT(o
) );
523 ReturnPtr ("Root::New", OOP_Object
*, NULL
);
529 static VOID
root_dispose(OOP_Class
*root_cl
, OOP_Object
*o
, OOP_Msg msg
)
531 EnterFunc(bug("Root::Dispose(o=%p, oclass=%s)\n", o
, _OOP_OBJECT(o
)->o_Class
->ClassNode
.ln_Name
));
533 MD(OOP_OCLASS(o
))->objectcount
--;
534 D(bug("Object mem: %p, size: %ld\n", _OOP_OBJECT(o
), ((ULONG
*)_OOP_OBJECT(o
))[-1] ));
536 /* Free object's memory */
537 FreeVec(_OOP_OBJECT(o
));
539 ReturnVoid("Root::Dispose");
542 static VOID
root_get(OOP_Class
*root_cl
, OOP_Object
*p
, struct pRoot_Get
*msg
)
545 D(bug("!!! Get() METHOD REACHED ROOTCLASS !!!\n"));
551 /**********************
552 ** init_rootclass() **
553 **********************/
554 BOOL
init_rootclass(struct IntOOPBase
*OOPBase
)
557 struct rootclassobject
*rco
;
558 OOP_Class
*rootclass
;
563 EnterFunc(bug("init_rootclass()\n"));
565 rco
= &(OOPBase
->ob_RootClassObject
);
566 rootclass
= &(rco
->inst
.data
.public);
568 /* Its class is the metaobject */
569 rco
->oclass
= &(OOPBase
->ob_BaseMetaObject
.inst
.data
.public);
571 rco
->inst
.data
.public.ClassNode
.ln_Name
= CLID_Root
;
572 rco
->inst
.data
.public.OOPBasePtr
= (struct Library
*)OOPBase
;
573 rco
->inst
.data
.public.InstOffset
= 0;
574 rco
->inst
.data
.public.UserData
= (APTR
)OOPBase
;
576 rco
->inst
.data
.public.cl_DoMethod
= NULL
;
577 rco
->inst
.data
.public.cl_CoerceMethod
= NULL
;
578 rco
->inst
.data
.public.cl_DoSuperMethod
= basemeta_dosupermethod
;
579 rco
->inst
.data
.public.cl_CoerceMethod
= basemeta_coercemethod
;
580 rco
->inst
.data
.public.cl_DoMethod
= basemeta_domethod
;
582 D(bug("Root stuff: dosupermethod %p, coeremethod %p, domethod %p\n",
583 basemeta_dosupermethod
, basemeta_coercemethod
, basemeta_domethod
));
585 rco
->inst
.data
.superclass
= NULL
;
586 rco
->inst
.data
.subclasscount
= 0UL;
587 rco
->inst
.data
.objectcount
= 0UL;
588 rco
->inst
.data
.instsize
= 0UL;
589 rco
->inst
.data
.numinterfaces
= 1UL;
591 /* Initialize methodtable */
593 rco
->inst
.rootif
[moRoot_New
].MethodFunc
= (IPTR (*)())root_new
;
594 rco
->inst
.rootif
[moRoot_New
].mClass
= rootclass
;
596 rco
->inst
.rootif
[moRoot_Dispose
].MethodFunc
= (IPTR (*)())root_dispose
;
597 rco
->inst
.rootif
[moRoot_Dispose
].mClass
= rootclass
;
599 rco
->inst
.rootif
[moRoot_Get
].MethodFunc
= (IPTR (*)())root_get
;
600 rco
->inst
.rootif
[moRoot_Get
].mClass
= rootclass
;
602 /* Important: IID_Root interface ID MUST be the first one
603 initialized, so that it gets the value 0UL. This is
604 because it's used as rootclass both for IFMeta and HIDDMeta classes
607 success
= init_mi_methodbase(IID_Root
, &mbase
, OOPBase
);
611 OOP_AddClass(rootclass
);
614 ReturnBool ("init_rootclass", success
);
617 /* Below is rootclass DoMethod and CoerceMethod. They are hardly useful,
618 cause you would never create an object of rootclass
622 #define ROOT_CALLMETHOD(cl, o, m) \
624 register struct IFMethod *ifm; \
625 ifm = &(RI(cl)->rootif[msg->MethodID]); \
626 return ifm->MethodFunc(ifm->mClass, o, msg); \
629 #define RI(cl) ((struct rootinst *)cl)
631 static IPTR root_domethod(OOP_Object *o, OOP_Msg msg)
636 ROOT_CALLMETHOD(cl, o, msg);
639 static IPTR root_coercemethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
641 ROOT_CALLMETHOD(cl, o, msg);