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; } } } }
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); }