void MetaData_Fill_FieldDef(tMD_TypeDef *pParentType, tMD_FieldDef *pFieldDef, U32 memOffset, tMD_TypeDef **ppClassTypeArgs) { U32 sigLength; PTR sig; tMetaData *pMetaData; //log_f(5,"MetaData_Fill_FieldDef %s.%s\n", pParentType->name,pFieldDef->name); pFieldDef->pParentType = pParentType; sig = MetaData_GetBlob(pFieldDef->signature, &sigLength); MetaData_DecodeSigEntry(&sig); // First entry always 0x06 pFieldDef->pType = Type_GetTypeFromSig(pFieldDef->pMetaData, &sig, ppClassTypeArgs, NULL); if (pFieldDef->pType == NULL) { // If the field is a core generic type definition, then we can't do anything more return; } MetaData_Fill_TypeDef(pFieldDef->pType, NULL, NULL); // A check for 0 is done so if a type has a field of it's own type it is handled correctly. pFieldDef->memSize = (pFieldDef->pType->stackSize>0)?pFieldDef->pType->stackSize:sizeof(void*); pFieldDef->memOffset = memOffset; pFieldDef->pFieldDef = pFieldDef; pMetaData = pFieldDef->pMetaData; if (FIELD_HASFIELDRVA(pFieldDef)) { U32 i, top; // Field has RVA, so load it from FieldRVA top = pMetaData->tables.numRows[MD_TABLE_FIELDRVA]; for (i=1; i<=top; i++) { tMD_FieldRVA *pFieldRVA; pFieldRVA = (tMD_FieldRVA*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_FIELDRVA, i)); if (pFieldRVA->field == pFieldDef->tableIndex) { pFieldDef->pMemory = (PTR)pFieldRVA->rva; break; } } } else if (FIELD_ISLITERAL(pFieldDef)) { // Field is literal, so make pMemory point to the value signature U32 i, top; top = pMetaData->tables.numRows[MD_TABLE_CONSTANT]; for (i=1; i<=top; i++) { tMD_Constant *pConst; pConst = (tMD_Constant*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_CONSTANT, i)); if (pConst->parent == pFieldDef->tableIndex) { // Found the field pFieldDef->pMemory = (PTR)pConst; break; } } } }
tMD_ImplMap* MetaData_GetImplMap(tMetaData *pMetaData, IDX_TABLE memberForwardedToken) { U32 i; for (i=pMetaData->tables.numRows[MD_TABLE_IMPLMAP]; i >= 1; i--) { tMD_ImplMap *pImplMap = (tMD_ImplMap*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_IMPLMAP, i)); if (pImplMap->memberForwarded == memberForwardedToken) { return pImplMap; } } Crash("MetaData_GetImplMap() Cannot find mapping for token: 0x%08x", memberForwardedToken); FAKE_RETURN; }
// TODO: This is not the most efficient way of doing this, as it has to search through all the // entries in the GenericParams table for all lookups. This can be improved. static tMD_GenericParam* FindGenericParam(tMD_TypeDef *pCoreType, U32 typeArgIndex) { tMD_GenericParam *pGenericParam; U32 i; pGenericParam = (tMD_GenericParam*)MetaData_GetTableRow(pCoreType->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_GENERICPARAM, 1)); for (i=0; i<pCoreType->pMetaData->tables.numRows[MD_TABLE_GENERICPARAM]; i++, pGenericParam++) { if (pGenericParam->owner == pCoreType->tableIndex && pGenericParam->number == typeArgIndex) { return pGenericParam; } } return NULL; }
tMD_TypeDef* MetaData_GetTypeDefFromFieldDef(tMD_FieldDef *pFieldDef) { tMetaData *pMetaData; U32 i; pMetaData = pFieldDef->pMetaData; for (i=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i>0; i--) { tMD_TypeDef *pTypeDef; pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); if (pTypeDef->fieldList <= pFieldDef->tableIndex) { return pTypeDef; } } Crash("MetaData_GetTypeDefFromFieldDef(): Cannot find type for field: %s", pFieldDef->name); FAKE_RETURN; }
tMD_TypeDef* MetaData_GetTypeDefFromName(tMetaData *pMetaData, STRING nameSpace, STRING name, tMD_TypeDef *pInNestedClass) { U32 i; for (i=1; i<=pMetaData->tables.numRows[MD_TABLE_TYPEDEF]; i++) { tMD_TypeDef *pTypeDef; pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_TYPEDEF, i)); if (pInNestedClass == pTypeDef->pNestedIn && strcmp(name, pTypeDef->name) == 0 && (pInNestedClass != NULL || strcmp(nameSpace, pTypeDef->nameSpace) == 0)) { return pTypeDef; } } Crash("MetaData_GetTypeDefFromName(): Cannot find type %s.%s", nameSpace, name); FAKE_RETURN; }
// Find the method that has been overridden by pMethodDef. // This is to get the correct vTable offset for the method. // This must search the MethodImpl table to see if the default inheritence rules are being overridden. // Return NULL if this method does not override anything. static tMD_MethodDef* FindVirtualOverriddenMethod(tMD_TypeDef *pTypeDef, tMD_MethodDef *pMethodDef) { U32 i; do { // Search MethodImpl table for (i=pTypeDef->pMetaData->tables.numRows[MD_TABLE_METHODIMPL]; i>0; i--) { tMD_MethodImpl *pMethodImpl; pMethodImpl = (tMD_MethodImpl*)MetaData_GetTableRow(pTypeDef->pMetaData, MAKE_TABLE_INDEX(MD_TABLE_METHODIMPL, i)); if (pMethodImpl->class_ == pTypeDef->tableIndex) { tMD_MethodDef *pMethodDeclDef; pMethodDeclDef = MetaData_GetMethodDefFromDefRefOrSpec(pTypeDef->pMetaData, pMethodImpl->methodDeclaration, pTypeDef->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs); if (pMethodDeclDef->tableIndex == pMethodDef->tableIndex) { IDX_TABLE methodToken; tMD_MethodDef *pMethod; methodToken = pMethodImpl->methodBody; pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pTypeDef->pMetaData, methodToken); return pMethod; } } } // Use normal inheritence rules // It must be a virtual method that's being overridden. for (i=pTypeDef->numVirtualMethods - 1; i != 0xffffffff; i--) { if (MetaData_CompareNameAndSig(pMethodDef->name, pMethodDef->signature, pMethodDef->pMetaData, pMethodDef->pParentType->ppClassTypeArgs, pMethodDef->ppMethodTypeArgs, pTypeDef->pVTable[i], pTypeDef->ppClassTypeArgs, NULL)) { return pTypeDef->pVTable[i]; } } pTypeDef = pTypeDef->pParent; } while (pTypeDef != NULL); return NULL; }
tMetaData* CLIFile_GetMetaDataForAssembly(unsigned char *pAssemblyName) { tFilesLoaded *pFiles; // Convert "mscorlib" to "corlib" if (strcmp(pAssemblyName, "mscorlib") == 0) { pAssemblyName = "corlib"; } // Look in already-loaded files first pFiles = pFilesLoaded; while (pFiles != NULL) { tCLIFile *pCLIFile; tMD_Assembly *pThisAssembly; pCLIFile = pFiles->pCLIFile; // Get the assembly info - there is only ever one of these in the each file's metadata pThisAssembly = MetaData_GetTableRow(pCLIFile->pMetaData, MAKE_TABLE_INDEX(0x20, 1)); if (strcmp(pAssemblyName, pThisAssembly->name) == 0) { // Found the correct assembly, so return its meta-data return pCLIFile->pMetaData; } pFiles = pFiles->pNext; } // Assembly not loaded, so load it if possible { tCLIFile *pCLIFile; unsigned char fileName[128]; sprintf(fileName, "%s.dll", pAssemblyName); pCLIFile = CLIFile_Load(fileName); if (pCLIFile == NULL) { Crash("Cannot load required assembly file: %s", fileName); } return pCLIFile->pMetaData; } }
static void GetMethodDefs() { IDX_TABLE token, last; tMetaData *pMetaData; pMetaData = types[TYPE_SYSTEM_ARRAY_NO_TYPE]->pMetaData; last = types[TYPE_SYSTEM_ARRAY_NO_TYPE]->isLast? MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, pMetaData->tables.numRows[MD_TABLE_METHODDEF]): (types[TYPE_SYSTEM_ARRAY_NO_TYPE][1].methodList - 1); token = types[TYPE_SYSTEM_ARRAY_NO_TYPE]->methodList; for (; token <= last; token++) { tMD_MethodDef *pMethod; U32 i; pMethod = (tMD_MethodDef*)MetaData_GetTableRow(pMetaData, token); for (i=0; i<GENERICARRAYMETHODS_NUM; i++) { if (strcmp(pMethod->name, pGenericArrayMethodsInit[i]) == 0) { ppGenericArrayMethods[i] = pMethod; break; } } } genericArrayMethodsInited = 1; }
static tCLIFile* LoadPEFile(void *pData) { tCLIFile *pRet = TMALLOC(tCLIFile); unsigned char *pMSDOSHeader = (unsigned char*)&(((unsigned char*)pData)[0]); unsigned char *pPEHeader; unsigned char *pPEOptionalHeader; unsigned char *pPESectionHeaders; unsigned char *pCLIHeader; unsigned char *pRawMetaData; int i; unsigned int lfanew; unsigned short machine; int numSections; unsigned int imageBase; int fileAlignment; unsigned int cliHeaderRVA, cliHeaderSize; unsigned int metaDataRVA, metaDataSize; tMetaData *pMetaData; pRet->pRVA = RVA(); pRet->pMetaData = pMetaData = MetaData(); lfanew = *(unsigned int*)&(pMSDOSHeader[0x3c]); pPEHeader = pMSDOSHeader + lfanew + 4; pPEOptionalHeader = pPEHeader + 20; pPESectionHeaders = pPEOptionalHeader + 224; machine = *(unsigned short*)&(pPEHeader[0]); if (machine != DOT_NET_MACHINE) { return NULL; } numSections = *(unsigned short*)&(pPEHeader[2]); imageBase = *(unsigned int*)&(pPEOptionalHeader[28]); fileAlignment = *(int*)&(pPEOptionalHeader[36]); for (i=0; i<numSections; i++) { unsigned char *pSection = pPESectionHeaders + i * 40; RVA_Create(pRet->pRVA, pData, pSection); } cliHeaderRVA = *(unsigned int*)&(pPEOptionalHeader[208]); cliHeaderSize = *(unsigned int*)&(pPEOptionalHeader[212]); pCLIHeader = RVA_FindData(pRet->pRVA, cliHeaderRVA); metaDataRVA = *(unsigned int*)&(pCLIHeader[8]); metaDataSize = *(unsigned int*)&(pCLIHeader[12]); pRet->entryPoint = *(unsigned int*)&(pCLIHeader[20]); pRawMetaData = RVA_FindData(pRet->pRVA, metaDataRVA); // Load all metadata { unsigned int versionLen = *(unsigned int*)&(pRawMetaData[12]); unsigned int ofs, numberOfStreams; void *pTableStream = NULL; unsigned int tableStreamSize; pRet->pVersion = &(pRawMetaData[16]); log_f(1, "CLI version: %s\n", pRet->pVersion); ofs = 16 + versionLen; numberOfStreams = *(unsigned short*)&(pRawMetaData[ofs + 2]); ofs += 4; for (i=0; i<(signed)numberOfStreams; i++) { unsigned int streamOffset = *(unsigned int*)&pRawMetaData[ofs]; unsigned int streamSize = *(unsigned int*)&pRawMetaData[ofs+4]; unsigned char *pStreamName = &pRawMetaData[ofs+8]; void *pStream = pRawMetaData + streamOffset; ofs += (unsigned int)((strlen(pStreamName)+4) & (~0x3)) + 8; if (strcasecmp(pStreamName, "#Strings") == 0) { MetaData_LoadStrings(pMetaData, pStream, streamSize); } else if (strcasecmp(pStreamName, "#US") == 0) { MetaData_LoadUserStrings(pMetaData, pStream, streamSize); } else if (strcasecmp(pStreamName, "#Blob") == 0) { MetaData_LoadBlobs(pMetaData, pStream, streamSize); } else if (strcasecmp(pStreamName, "#GUID") == 0) { MetaData_LoadGUIDs(pMetaData, pStream, streamSize); } else if (strcasecmp(pStreamName, "#~") == 0) { pTableStream = pStream; tableStreamSize = streamSize; } } // Must load tables last if (pTableStream != NULL) { MetaData_LoadTables(pMetaData, pRet->pRVA, pTableStream, tableStreamSize); } } // Mark all generic definition types and methods as such for (i=pMetaData->tables.numRows[MD_TABLE_GENERICPARAM]; i>0; i--) { tMD_GenericParam *pGenericParam; IDX_TABLE ownerIdx; pGenericParam = (tMD_GenericParam*)MetaData_GetTableRow (pMetaData, MAKE_TABLE_INDEX(MD_TABLE_GENERICPARAM, i)); ownerIdx = pGenericParam->owner; switch (TABLE_ID(ownerIdx)) { case MD_TABLE_TYPEDEF: { tMD_TypeDef *pTypeDef = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, ownerIdx); pTypeDef->isGenericDefinition = 1; } break; case MD_TABLE_METHODDEF: { tMD_MethodDef *pMethodDef = (tMD_MethodDef*)MetaData_GetTableRow(pMetaData, ownerIdx); pMethodDef->isGenericDefinition = 1; } break; default: Crash("Wrong generic parameter owner: 0x%08x", ownerIdx); } } // Mark all nested classes as such for (i=pMetaData->tables.numRows[MD_TABLE_NESTEDCLASS]; i>0; i--) { tMD_NestedClass *pNested; tMD_TypeDef *pParent, *pChild; pNested = (tMD_NestedClass*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_NESTEDCLASS, i)); pParent = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, pNested->enclosingClass); pChild = (tMD_TypeDef*)MetaData_GetTableRow(pMetaData, pNested->nestedClass); pChild->pNestedIn = pParent; } return pRet; }
void MetaData_Fill_TypeDef_(tMD_TypeDef *pTypeDef, tMD_TypeDef **ppClassTypeArgs, tMD_TypeDef **ppMethodTypeArgs) { IDX_TABLE firstIdx, lastIdx, token; U32 instanceMemSize, staticMemSize, virtualOfs, i, j; tMetaData *pMetaData; tMD_TypeDef *pParent; pMetaData = pTypeDef->pMetaData; pTypeDef->isFilled = 1; pTypeDef->pTypeDef = pTypeDef; pTypeDef->pParent = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, pTypeDef->extends, ppClassTypeArgs, ppMethodTypeArgs); pParent = pTypeDef->pParent; if (pParent != NULL) { MetaData_Fill_TypeDef(pParent, NULL, NULL); virtualOfs = pParent->numVirtualMethods; } else { virtualOfs = 0; } pTypeDef->isValueType = (U8)Type_IsValueType(pTypeDef); // If not primed, then work out how many methods & fields there are. if (!pTypeDef->isPrimed) { // Methods lastIdx = (pTypeDef->isLast)? MAKE_TABLE_INDEX(MD_TABLE_METHODDEF, pTypeDef->pMetaData->tables.numRows[MD_TABLE_METHODDEF]): (pTypeDef[1].methodList - 1); pTypeDef->numMethods = lastIdx - pTypeDef->methodList + 1; // Fields lastIdx = (pTypeDef->isLast)? MAKE_TABLE_INDEX(MD_TABLE_FIELDDEF, pTypeDef->pMetaData->tables.numRows[MD_TABLE_FIELDDEF]): (pTypeDef[1].fieldList - 1); pTypeDef->numFields = lastIdx - pTypeDef->fieldList + 1; } // Must create the virtual method table BEFORE any other type resolution is done // Note that this must not do ANY filling of types or methods. // This is to ensure that the parent object(s) in any type inheritance hierachy are allocated // their virtual method offset before derived types. firstIdx = pTypeDef->methodList; lastIdx = firstIdx + pTypeDef->numMethods - 1; // This only needs to be done for non-generic types, or for generic types that are not a definition // I.e. Fully instantiated generic types if (!pTypeDef->isGenericDefinition) { for (token = firstIdx; token <= lastIdx; token++) { tMD_MethodDef *pMethodDef; pMethodDef = MetaData_GetMethodDefFromDefRefOrSpec(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); // This is needed, so array resolution can work correctly and FindVirtualOverriddenMethod() can work. pMethodDef->pParentType = pTypeDef; if (METHOD_ISVIRTUAL(pMethodDef)) { if (METHOD_ISNEWSLOT(pMethodDef) || pTypeDef->pParent == NULL) { // Allocate a new vTable slot if method is explicitly marked as NewSlot, or // this is of type Object. pMethodDef->vTableOfs = virtualOfs++; } else { tMD_MethodDef *pVirtualOveriddenMethod; pVirtualOveriddenMethod = FindVirtualOverriddenMethod(pTypeDef->pParent, pMethodDef); Assert(pVirtualOveriddenMethod != NULL); pMethodDef->vTableOfs = pVirtualOveriddenMethod->vTableOfs; } } else { // Dummy value - make it obvious it's not valid! pMethodDef->vTableOfs = 0xffffffff; } } // Create the virtual method table pTypeDef->numVirtualMethods = virtualOfs; // Resolve fields, members, interfaces. // Only needs to be done if it's not a generic definition type // It it's not a value-type and the stack-size is not preset, then set it up now. // It needs to be done here as non-static fields in non-value types can point to the containing type if (pTypeDef->stackSize == 0 && !pTypeDef->isValueType) { pTypeDef->stackType = EVALSTACK_O; pTypeDef->stackSize = sizeof(void*); } // Resolve all fields - instance ONLY at this point, // because static fields in value-types can be of the containing type, and the size is not yet known. firstIdx = pTypeDef->fieldList; lastIdx = firstIdx + pTypeDef->numFields - 1; staticMemSize = 0; if (pTypeDef->numFields > 0) { pTypeDef->ppFields = mallocForever(pTypeDef->numFields * sizeof(tMD_FieldDef*)); } instanceMemSize = (pTypeDef->pParent == NULL)?0:pTypeDef->pParent->instanceMemSize; for (token = firstIdx, i=0; token <= lastIdx; token++, i++) { tMD_FieldDef *pFieldDef; pFieldDef = MetaData_GetFieldDefFromDefOrRef(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); if (!FIELD_ISSTATIC(pFieldDef)) { // Only handle non-static fields at the moment if (pTypeDef->pGenericDefinition != NULL) { // If this is a generic instantiation type, then all field defs need to be copied, // as there will be lots of different instantiations. tMD_FieldDef *pFieldCopy = TMALLOCFOREVER(tMD_FieldDef); memcpy(pFieldCopy, pFieldDef, sizeof(tMD_FieldDef)); pFieldDef = pFieldCopy; } if (FIELD_ISLITERAL(pFieldDef) || FIELD_HASFIELDRVA(pFieldDef)) { // If it's a literal, then analyse the field, but don't include it in any memory allocation // If is has an RVA, then analyse the field, but don't include it in any memory allocation MetaData_Fill_FieldDef(pTypeDef, pFieldDef, 0, ppClassTypeArgs); } else { MetaData_Fill_FieldDef(pTypeDef, pFieldDef, instanceMemSize, ppClassTypeArgs); instanceMemSize += pFieldDef->memSize; } pTypeDef->ppFields[i] = pFieldDef; } } if (pTypeDef->instanceMemSize == 0) { pTypeDef->instanceMemSize = instanceMemSize; } // Sort out stack type and size. // Note that this may already be set, as some basic types have this preset; // or if it's not a value-type it'll already be set if (pTypeDef->stackSize == 0) { // if it gets here then it must be a value type pTypeDef->stackType = EVALSTACK_VALUETYPE; pTypeDef->stackSize = pTypeDef->instanceMemSize; } // Sort out array element size. Note that some basic types will have this preset. if (pTypeDef->arrayElementSize == 0) { pTypeDef->arrayElementSize = pTypeDef->stackSize; } // Handle static fields for (token = firstIdx, i=0; token <= lastIdx; token++, i++) { tMD_FieldDef *pFieldDef; pFieldDef = MetaData_GetFieldDefFromDefOrRef(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); if (FIELD_ISSTATIC(pFieldDef)) { // Only handle static fields here if (pTypeDef->pGenericDefinition != NULL) { // If this is a generic instantiation type, then all field defs need to be copied, // as there will be lots of different instantiations. tMD_FieldDef *pFieldCopy = TMALLOCFOREVER(tMD_FieldDef); memcpy(pFieldCopy, pFieldDef, sizeof(tMD_FieldDef)); pFieldDef = pFieldCopy; } if (FIELD_ISLITERAL(pFieldDef) || FIELD_HASFIELDRVA(pFieldDef)) { // If it's a literal, then analyse the field, but don't include it in any memory allocation // If is has an RVA, then analyse the field, but don't include it in any memory allocation MetaData_Fill_FieldDef(pTypeDef, pFieldDef, 0, ppClassTypeArgs); } else { MetaData_Fill_FieldDef(pTypeDef, pFieldDef, staticMemSize, ppClassTypeArgs); staticMemSize += pFieldDef->memSize; } pTypeDef->ppFields[i] = pFieldDef; } } if (staticMemSize > 0) { pTypeDef->pStaticFields = mallocForever(staticMemSize); memset(pTypeDef->pStaticFields, 0, staticMemSize); // Set the field addresses (->pMemory) of all static fields for (i = 0; i<pTypeDef->numFields; i++) { tMD_FieldDef *pFieldDef; pFieldDef = pTypeDef->ppFields[i]; if (FIELD_ISSTATIC(pFieldDef) && pFieldDef->pMemory == NULL) { // Only set it if it isn't already set. It will be already set if this field has an RVA pFieldDef->pMemory = pTypeDef->pStaticFields + pFieldDef->memOffset; } } pTypeDef->staticFieldSize = staticMemSize; } // Resolve all members firstIdx = pTypeDef->methodList; lastIdx = firstIdx + pTypeDef->numMethods - 1; pTypeDef->ppMethods = mallocForever(pTypeDef->numMethods * sizeof(tMD_MethodDef*)); pTypeDef->pVTable = mallocForever(pTypeDef->numVirtualMethods * sizeof(tMD_MethodDef*)); // Copy initial vTable from parent if (pTypeDef->pParent != NULL) { memcpy(pTypeDef->pVTable, pTypeDef->pParent->pVTable, pTypeDef->pParent->numVirtualMethods * sizeof(tMD_MethodDef*)); } for (token = firstIdx, i = 0; token <= lastIdx; token++, i++) { tMD_MethodDef *pMethodDef; pMethodDef = MetaData_GetMethodDefFromDefRefOrSpec(pMetaData, token, ppClassTypeArgs, ppMethodTypeArgs); if (pTypeDef->pGenericDefinition != NULL) { // If this is a generic instantiation type, then all method defs need to be copied, // as there will be lots of different instantiations. tMD_MethodDef *pMethodCopy = TMALLOCFOREVER(tMD_MethodDef); memcpy(pMethodCopy, pMethodDef, sizeof(tMD_MethodDef)); pMethodDef = pMethodCopy; } if (METHOD_ISSTATIC(pMethodDef) && strcmp(pMethodDef->name, ".cctor") == 0) { // This is a static constructor pTypeDef->pStaticConstructor = pMethodDef; } if (!METHOD_ISSTATIC(pMethodDef) && pTypeDef->pParent != NULL && strcmp(pMethodDef->name, "Finalize") == 0) { // This is a Finalizer method, but not for Object. // Delibrately miss out Object's Finalizer because it's empty and will cause every object // of any type to have a Finalizer which will be terrible for performance. pTypeDef->pFinalizer = pMethodDef; } if (METHOD_ISVIRTUAL(pMethodDef)) { // This is a virtual method, so enter it in the vTable pTypeDef->pVTable[pMethodDef->vTableOfs] = pMethodDef; } pTypeDef->ppMethods[i] = pMethodDef; } // Find inherited Finalizer, if this type doesn't have an explicit Finalizer, and if there is one if (pTypeDef->pFinalizer == NULL) { tMD_TypeDef *pInheritedType = pTypeDef->pParent; while (pInheritedType != NULL) { if (pInheritedType->pFinalizer != NULL) { pTypeDef->pFinalizer = pInheritedType->pFinalizer; break; } pInheritedType = pInheritedType->pParent; } } // Fill all method definitions for this type for (i=0; i<pTypeDef->numMethods; i++) { MetaData_Fill_MethodDef(pTypeDef, pTypeDef->ppMethods[i], ppClassTypeArgs, ppMethodTypeArgs); } // Map all interface method calls. This only needs to be done for Classes, not Interfaces // And is not done for generic definitions. if (!TYPE_ISINTERFACE(pTypeDef)) { firstIdx = 0; if (pTypeDef->pParent != NULL) { j = pTypeDef->numInterfaces = pTypeDef->pParent->numInterfaces; } else { j = 0; } // TODO: Better to do this once during file load (the bit in this for loop) for (i=1; i<=pMetaData->tables.numRows[MD_TABLE_INTERFACEIMPL]; i++) { tMD_InterfaceImpl *pInterfaceImpl; pInterfaceImpl = (tMD_InterfaceImpl*)MetaData_GetTableRow(pMetaData, MAKE_TABLE_INDEX(MD_TABLE_INTERFACEIMPL, i)); if (pInterfaceImpl->class_ == pTypeDef->tableIndex) { // count how many interfaces are implemented pTypeDef->numInterfaces++; if (firstIdx == 0) { firstIdx = MAKE_TABLE_INDEX(MD_TABLE_INTERFACEIMPL, i); } lastIdx = MAKE_TABLE_INDEX(MD_TABLE_INTERFACEIMPL, i); } } if (pTypeDef->numInterfaces > 0 && !pTypeDef->isGenericDefinition) { U32 mapNum; pTypeDef->pInterfaceMaps = (tInterfaceMap*)mallocForever(pTypeDef->numInterfaces * sizeof(tInterfaceMap)); // Copy interface maps from parent type if (j > 0) { memcpy(pTypeDef->pInterfaceMaps, pTypeDef->pParent->pInterfaceMaps, j * sizeof(tInterfaceMap)); } mapNum = j; if (firstIdx > 0) { for (token=firstIdx; token<=lastIdx; token++, mapNum++) { tMD_InterfaceImpl *pInterfaceImpl; pInterfaceImpl = (tMD_InterfaceImpl*)MetaData_GetTableRow(pMetaData, token); if (pInterfaceImpl->class_ == pTypeDef->tableIndex) { tMD_TypeDef *pInterface; tInterfaceMap *pMap; // Get the interface that this type implements pInterface = MetaData_GetTypeDefFromDefRefOrSpec(pMetaData, pInterfaceImpl->interface_, ppClassTypeArgs, ppMethodTypeArgs); MetaData_Fill_TypeDef(pInterface, NULL, NULL); pMap = &pTypeDef->pInterfaceMaps[mapNum]; pMap->pInterface = pInterface; pMap->pVTableLookup = (U32*)mallocForever(pInterface->numVirtualMethods * sizeof(U32)); pMap->ppMethodVLookup = NULL; // Discover interface mapping for each interface method for (i=0; i<pInterface->numVirtualMethods; i++) { tMD_MethodDef *pInterfaceMethod, *pOverriddenMethod; pInterfaceMethod = pInterface->pVTable[i]; pOverriddenMethod = FindVirtualOverriddenMethod(pTypeDef, pInterfaceMethod); Assert(pOverriddenMethod != NULL); pMap->pVTableLookup[i] = pOverriddenMethod->vTableOfs; } } else { Crash("Problem with interface class"); } } } } } // If this is an enum type, then pretend its stack type is its underlying type if (pTypeDef->pParent == types[TYPE_SYSTEM_ENUM]) { pTypeDef->stackType = EVALSTACK_INT32; } } // If this is a nested type, then find the namespace of it if (pTypeDef->pNestedIn != NULL) { tMD_TypeDef *pRootTypeDef = pTypeDef->pNestedIn; while (pRootTypeDef->pNestedIn != NULL) { pRootTypeDef = pRootTypeDef->pNestedIn; } pTypeDef->nameSpace = pRootTypeDef->nameSpace; } log_f(2, "Type: %s.%s\n", pTypeDef->nameSpace, pTypeDef->name); }