| 1 | /* ***** BEGIN LICENSE BLOCK ***** | 
|---|
| 2 | * Version: CDDL 1.0/LGPL 2.1 | 
|---|
| 3 | * | 
|---|
| 4 | * The contents of this file are subject to the COMMON DEVELOPMENT AND | 
|---|
| 5 | * DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use | 
|---|
| 6 | * this file except in compliance with the License. You may obtain a copy of | 
|---|
| 7 | * the License at http://www.sun.com/cddl/ | 
|---|
| 8 | * | 
|---|
| 9 | * Software distributed under the License is distributed on an "AS IS" basis, | 
|---|
| 10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | 
|---|
| 11 | * for the specific language governing rights and limitations under the | 
|---|
| 12 | * License. | 
|---|
| 13 | * | 
|---|
| 14 | * The Original Code is "NOM" Netlabs Object Model | 
|---|
| 15 | * | 
|---|
| 16 | * The Initial Developer of the Original Code is | 
|---|
| 17 | * netlabs.org: Chris Wohlgemuth <cinc-ml@netlabs.org>. | 
|---|
| 18 | * Portions created by the Initial Developer are Copyright (C) 2005-2006 | 
|---|
| 19 | * the Initial Developer. All Rights Reserved. | 
|---|
| 20 | * | 
|---|
| 21 | * Contributor(s): | 
|---|
| 22 | * | 
|---|
| 23 | * Alternatively, the contents of this file may be used under the terms of | 
|---|
| 24 | * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which | 
|---|
| 25 | * case the provisions of the LGPL are applicable instead of those above. If | 
|---|
| 26 | * you wish to allow use of your version of this file only under the terms of | 
|---|
| 27 | * the LGPL, and not to allow others to use your version of this file under | 
|---|
| 28 | * the terms of the CDDL, indicate your decision by deleting the provisions | 
|---|
| 29 | * above and replace them with the notice and other provisions required by the | 
|---|
| 30 | * LGPL. If you do not delete the provisions above, a recipient may use your | 
|---|
| 31 | * version of this file under the terms of any one of the CDDL or the LGPL. | 
|---|
| 32 | * | 
|---|
| 33 | * ***** END LICENSE BLOCK ***** */ | 
|---|
| 34 |  | 
|---|
| 35 | #define INCL_DOS | 
|---|
| 36 | #define INCL_DOSERRORS | 
|---|
| 37 |  | 
|---|
| 38 | #include <os2.h> | 
|---|
| 39 | #include <stdio.h> | 
|---|
| 40 | #include <string.h> | 
|---|
| 41 | #include <glib.h> | 
|---|
| 42 | #define SOM_NO_OBJECTS  /* Otherwise som.h includes the IBM SOM classes */ | 
|---|
| 43 |  | 
|---|
| 44 | /* For nomToken etc. */ | 
|---|
| 45 | #include <nom.h> | 
|---|
| 46 | #include <nomtk.h> | 
|---|
| 47 | #include <nomobj.h> | 
|---|
| 48 |  | 
|---|
| 49 | /********************************************************/ | 
|---|
| 50 |  | 
|---|
| 51 | /* Define if you want to have messages from building NOMObject */ | 
|---|
| 52 | //#define DEBUG_BUILDNOMOBJECT | 
|---|
| 53 |  | 
|---|
| 54 | /********************************************************/ | 
|---|
| 55 |  | 
|---|
| 56 | /********************************************************/ | 
|---|
| 57 |  | 
|---|
| 58 | extern PNOM_ENV pGlobalNomEnv; | 
|---|
| 59 |  | 
|---|
| 60 | /* | 
|---|
| 61 | Thunking code to get the instance var address from an object pointer pushed | 
|---|
| 62 | on the stack. The following translates into this assembler code: | 
|---|
| 63 |  | 
|---|
| 64 | MOV EAX,DWORD PTR [ESP+4] ;Move object ptr into EAX | 
|---|
| 65 | ADD EAX, +4 | 
|---|
| 66 | RET | 
|---|
| 67 | */ | 
|---|
| 68 |  | 
|---|
| 69 | static ULONG thunk[]={0x0424448b, 0x00000405, 0x0000c300}; | 
|---|
| 70 |  | 
|---|
| 71 | /* | 
|---|
| 72 | MOV ECX,DWORD PTR [ESP+4] : move object pointer from stack in ECX | 
|---|
| 73 | MOV EDX,DWORD PTR [ECX]   : move [ECX] in EDX -> mtab in EDX | 
|---|
| 74 | JMP DWORD PTR [EDX+0ACh]  : JMP to address pointing to by EDX+0ACh | 
|---|
| 75 | */ | 
|---|
| 76 | static ULONG mThunkCode[]={0x04244c8b, 0xff00518b, 0x0000aca2 , 0x16000000}; | 
|---|
| 77 |  | 
|---|
| 78 | /********************************************************/ | 
|---|
| 79 |  | 
|---|
| 80 |  | 
|---|
| 81 | /* | 
|---|
| 82 | Create the SOMClassPriv structure *only* for SOMObject and fill it with info | 
|---|
| 83 | from the sci. | 
|---|
| 84 |  | 
|---|
| 85 | This function does | 
|---|
| 86 |  | 
|---|
| 87 | -allocate the memory for the struct depending on the sci info | 
|---|
| 88 | -creates the mtab in this memory | 
|---|
| 89 | -fills all the necessary pointers in the mtab | 
|---|
| 90 | -fills the method addresses in the mtab | 
|---|
| 91 |  | 
|---|
| 92 | It does not insert a class object pointer! | 
|---|
| 93 |  | 
|---|
| 94 | */ | 
|---|
| 95 | static NOMClassPriv *buildNOMClassPrivStructForNOMObject(nomStaticClassInfo *sci) | 
|---|
| 96 | { | 
|---|
| 97 |  | 
|---|
| 98 | NOMClassPriv *nClass; /* This struct holds our private data. A pointer will be in mtab->nomClsInfo */ | 
|---|
| 99 |  | 
|---|
| 100 | NOM_ulong mtabSize; | 
|---|
| 101 | NOM_ulong ulMemSize=0; | 
|---|
| 102 | BYTE * mem; | 
|---|
| 103 | int a; | 
|---|
| 104 |  | 
|---|
| 105 | /* ulMemsize will be the size of our private class structure NOMClassPriv */ | 
|---|
| 106 | ulMemSize=sizeof(NOMClassPriv)-sizeof(nomMethodTab); /* start size class struct without the nomMethodTab | 
|---|
| 107 | holding the method pointers. The size of this | 
|---|
| 108 | nomMethodTab will be added later. */ | 
|---|
| 109 |  | 
|---|
| 110 | /* Calculate the size of the method tab to be added to the size of the private class struct */ | 
|---|
| 111 | mtabSize=sizeof(nomMethodTab)+sizeof(nomMethodProc*)*(sci->ulNumStaticMethods);/* ulNumStaticMethods is correct here! NOT | 
|---|
| 112 | ulNumStaticMethods-1! entries[0] in fact | 
|---|
| 113 | contains the class pointer not a method | 
|---|
| 114 | pointer. */ | 
|---|
| 115 | ulMemSize+=mtabSize; /* Add size of base mtab struct */ | 
|---|
| 116 |  | 
|---|
| 117 | /* Alloc private class struct using NOMCalloc. */ | 
|---|
| 118 | if((nClass=(NOMClassPriv*)NOMCalloc(1, ulMemSize))==NULLHANDLE) | 
|---|
| 119 | return NULLHANDLE; | 
|---|
| 120 |  | 
|---|
| 121 |  | 
|---|
| 122 | /* The size of each instance of this class. A SOM object has a method tab pointer | 
|---|
| 123 | at the beginning followed by the instance variables. */ | 
|---|
| 124 | nClass->ulClassSize=sci->ulInstanceDataSize+sizeof(nomMethodTab*); | 
|---|
| 125 | nClass->sci=sci;                                   /* Save static class info for internal use          */ | 
|---|
| 126 | nClass->ulPrivClassSize=ulMemSize;                 /* Internal housekeeping. Not needed by NOM methods */ | 
|---|
| 127 |  | 
|---|
| 128 |  | 
|---|
| 129 | /* Fill all the pointers to methodtable we need in the *private* structure */ | 
|---|
| 130 | nClass->mtab=(nomMethodTab*)&nClass->thisMtab;            /* create the mtab pointer and store it           */ | 
|---|
| 131 | nClass->mtabList.mtab= (nomMethodTab*)&nClass->thisMtab;  /* thisMtab is the position where the mtab starts */ | 
|---|
| 132 | nClass->parentMtabStruct.mtab=(nomMethodTab*)&nClass->thisMtab; | 
|---|
| 133 |  | 
|---|
| 134 |  | 
|---|
| 135 | /**********************************/ | 
|---|
| 136 | /*     Fill methodtable mtab      */ | 
|---|
| 137 | /**********************************/ | 
|---|
| 138 | nClass->mtab->mtabSize=mtabSize;        /* This mtab is the same as the one used in the public NOMClass */ | 
|---|
| 139 | nClass->mtab->nomClsInfo=(nomClassInfo*)nClass;        /* Hold a pointer to the private data that is this NOMClassPriv */ | 
|---|
| 140 | #warning !!!!! Change this when nomId is a GQuark !!!!! | 
|---|
| 141 | nClass->mtab->nomClassName=*sci->nomClassId; | 
|---|
| 142 | nClass->mtab->ulInstanceSize=sci->ulInstanceDataSize+sizeof(nomMethodTabPtr); /* sizeof(methodTabStruct*) + size of instance data of this class | 
|---|
| 143 | and all parent classes. This is NOMObject so we have no parents. */ | 
|---|
| 144 |  | 
|---|
| 145 | /* Get mem for method thunking code. This assembler code is needed so the indirect | 
|---|
| 146 | jump to the methods from the object pointer which is known does work. For each class | 
|---|
| 147 | an individual thunking code must be calculated because the number of instance | 
|---|
| 148 | variables is not defined. */ | 
|---|
| 149 | nClass->mThunk=NOMMalloc(sizeof(nomMethodThunk)*sci->ulNumStaticMethods); | 
|---|
| 150 | if(!nClass->mThunk) { | 
|---|
| 151 | NOMFree(nClass); | 
|---|
| 152 | return NULLHANDLE; | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|
| 155 | memcpy(nClass->thunk, thunk, sizeof(thunk));       /* Copy assembler thunking code for instance data   */ | 
|---|
| 156 |  | 
|---|
| 157 | /* Copy class data. This goes at the address of "nomMethodProc* entries[0]". | 
|---|
| 158 | Entries[] contain copies of the ClassDataStruct and thus the proc addresses of the static methods. | 
|---|
| 159 | We don't use the static classDataStruct directly because subclasses will override the proc addresses. */ | 
|---|
| 160 | mem=(char*)&(nClass->mtab->entries[0]); /* Target address.entries[0] will contain the class pointer */ | 
|---|
| 161 | /* Add class struct of this class. This includes the proc adresses. */ | 
|---|
| 162 | if(sci->ulNumStaticMethods) { | 
|---|
| 163 | #ifdef DEBUG_BUILDNOMOBJECT | 
|---|
| 164 | nomPrintf("copy: %d (classptr+numProcs*procpointersize) from %x (cds, classDataStruct) to %x\n", | 
|---|
| 165 | sizeof(NOMClass*)+sci->ulNumStaticMethods*sizeof(nomMethodProc*), | 
|---|
| 166 | sci->nomCds, mem); | 
|---|
| 167 | #endif | 
|---|
| 168 | /* Copy classDataStruct with the resolved proc addresses */ | 
|---|
| 169 | memcpy( mem, sci->nomCds, sizeof(NOMClass*)+sci->ulNumStaticMethods*sizeof(nomMethodProc*)); | 
|---|
| 170 | /* Now finally put the thunking in so the procedures are resolved correctly. */ | 
|---|
| 171 | for(a=0;a<sci->ulNumStaticMethods;a++) { | 
|---|
| 172 | ULONG ulOffset; | 
|---|
| 173 |  | 
|---|
| 174 | memcpy(&nClass->mThunk[a], mThunkCode, sizeof(mThunkCode));               /* Copy method thunking code template  */ | 
|---|
| 175 | ulOffset=(ULONG)((char*)(mem+sizeof(NOMClass*))-(char*)nClass->mtab);     /* Skip priv class data pointer        */ | 
|---|
| 176 | nClass->mThunk[a].thunk[2]=((ulOffset+a*sizeof(nomMethodProc*))<<8)+0xa2; /* Calculate offset for assembler code */ | 
|---|
| 177 | #ifdef DEBUG_BUILDNOMOBJECT | 
|---|
| 178 | nomPrintf(" %d: %d : Thunk offset: %d (0x%x) -> address will be: %x\n", | 
|---|
| 179 | __LINE__, a, ulOffset, ulOffset, mem+ulOffset+a*sizeof(nomMethodProc*) ); | 
|---|
| 180 | #endif | 
|---|
| 181 | /* Put thunking code address into CClassStruct */ | 
|---|
| 182 | sci->nomCds->nomTokens[a]=(void*)&nClass->mThunk[a]; | 
|---|
| 183 | } /* for */ | 
|---|
| 184 | } /* if(ulNumStaticMethods) */ | 
|---|
| 185 | return nClass; /* This is not a NOMClass* but a NOMClassPriv* */ | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | /* | 
|---|
| 189 | Create a NOMClassPriv (which will be put into the classInfo of the mtab) for | 
|---|
| 190 | NOMObject. This contains an mtab which is completely built but without | 
|---|
| 191 | a pointer to the class object. This pointer will be inserted later when we have | 
|---|
| 192 | a NOMClass. | 
|---|
| 193 |  | 
|---|
| 194 | !!! This function is only called once for building NOMObject !!! | 
|---|
| 195 | */ | 
|---|
| 196 | NOMClassPriv * NOMLINK priv_buildNOMObjectClassInfo(NOM_ulong ulReserved, | 
|---|
| 197 | nomStaticClassInfo *sci, | 
|---|
| 198 | NOM_ulong majorVersion, | 
|---|
| 199 | NOM_ulong minorVersion) | 
|---|
| 200 | { | 
|---|
| 201 | NOMClassPriv *nClassPriv; /* This struct holds our private data. A pointer will be in mtab->nomClsInfo */ | 
|---|
| 202 | ULONG ulParentDataSize=0; | 
|---|
| 203 |  | 
|---|
| 204 | #ifdef DEBUG_BUILDNOMOBJECT | 
|---|
| 205 | nomPrintf("%d: Entering %s to build the NOMClassPriv for NOMObjects\n", __LINE__, __FUNCTION__); | 
|---|
| 206 | _dumpSci(sci); | 
|---|
| 207 | #endif | 
|---|
| 208 |  | 
|---|
| 209 | /* Note: NOMObject has no parents */ | 
|---|
| 210 | if((nClassPriv=buildNOMClassPrivStructForNOMObject(sci))==NULLHANDLE) | 
|---|
| 211 | return NULLHANDLE; | 
|---|
| 212 |  | 
|---|
| 213 | #ifdef DEBUG_BUILDNOMOBJECT | 
|---|
| 214 | nomPrintf("mtab: %x nClassPriv: %x\n", nClassPriv->mtab, nClassPriv); | 
|---|
| 215 | #endif | 
|---|
| 216 |  | 
|---|
| 217 | sci->ccds->parentMtab=&nClassPriv->parentMtabStruct;  /* Insert pointer into CClassDataStructure */ | 
|---|
| 218 | /* Fill somParentMtabStruct in CClassDataStructure */ | 
|---|
| 219 | sci->ccds->parentMtab->mtab=nClassPriv->mtab;         /* This class mtab                               */ | 
|---|
| 220 | sci->ccds->parentMtab->next=NULL;                     /* We dont have parents because we are NOMObject */ | 
|---|
| 221 | sci->ccds->parentMtab->nomClassObject=NULLHANDLE;     /* NOMClass* Class object. We don't have one yet */ | 
|---|
| 222 | sci->ccds->parentMtab->ulInstanceSize=nClassPriv->mtab->ulInstanceSize; | 
|---|
| 223 | /* C Class data structure */ | 
|---|
| 224 |  | 
|---|
| 225 | /* Thunking code see above. Adjust the offset to the instance data so the right | 
|---|
| 226 | variables are accessed. The offset is different depending on the number of parent | 
|---|
| 227 | classes (which isn't fix) and the number of parent instance vars (which isn't known | 
|---|
| 228 | at compile time) */ | 
|---|
| 229 | nClassPriv->thunk[1]=(ulParentDataSize<<8)+0x05; //0x00000405 | 
|---|
| 230 | sci->ccds->instanceDataToken=&nClassPriv->thunk; | 
|---|
| 231 |  | 
|---|
| 232 |  | 
|---|
| 233 | #ifdef DEBUG_BUILDNOMOBJECT | 
|---|
| 234 | nomPrintf("No class ptr (temp. class object for NOMObject) yet. (NOMClassPriv: %x) for %s\n", | 
|---|
| 235 | nClassPriv, *sci->nomClassId); | 
|---|
| 236 | nomPrintf("%d: Dumping the filled classdata structure:\n", __LINE__); | 
|---|
| 237 | _dumpClassDataStruct(sci->nomCds, sci->ulNumStaticMethods); | 
|---|
| 238 | #endif | 
|---|
| 239 |  | 
|---|
| 240 |  | 
|---|
| 241 | /* NOMObject is special because it's root of normal classes and meta classes. Because of this it | 
|---|
| 242 | cannot be insert into the class list yet. We have to wait until NOMClass was built. | 
|---|
| 243 | We also use this info to check if NOMObject was already built in other places. */ | 
|---|
| 244 | pGlobalNomEnv->ncpNOMObject=nClassPriv; | 
|---|
| 245 |  | 
|---|
| 246 | //priv_addPrivClassToGlobalClassList(pGlobalNomEnv, nClassPriv); | 
|---|
| 247 |  | 
|---|
| 248 | /* | 
|---|
| 249 | FIXME: This explanantion isn't correct anymore | 
|---|
| 250 |  | 
|---|
| 251 | We don't run the somInit() method here because the SOMObject class isn't yet completely built. | 
|---|
| 252 | First a SOMClass meta class must be created because SOMObject needs a SOMClass as the class object like | 
|---|
| 253 | any other class. In case some code in somInit() tries to access the class object initialization would | 
|---|
| 254 | fail. In the function building the root SOMClass a metaclass for SOMObject will be created and attached. | 
|---|
| 255 |  | 
|---|
| 256 | Not running somInit() here shouldn't be a problem because we know what we are doing ;-). | 
|---|
| 257 | If there will ever be the need for special initialization for this very first SOMObject we think again... | 
|---|
| 258 |  | 
|---|
| 259 | In any case fiddling with somInit() in SOMObject and SOMClass is a dangerous thing because at least one of the | 
|---|
| 260 | two classes won't be completely built at that point in time (because SOMClass is a subclass of SOMObject | 
|---|
| 261 | and SOMObject needs a SOMClass as metaclass). | 
|---|
| 262 |  | 
|---|
| 263 | _somInit(somClass); | 
|---|
| 264 | */ | 
|---|
| 265 |  | 
|---|
| 266 | /* Run initialization code if any */ | 
|---|
| 267 | _nomInit((NOMObject*)nClassPriv, NULLHANDLE); | 
|---|
| 268 | return NULLHANDLE; | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 |  | 
|---|
| 272 |  | 
|---|
| 273 |  | 
|---|