123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- #include "ClassFieldLayoutCalculator.h"
- #include "metadata/FieldLayout.h"
- #include "metadata/GenericMetadata.h"
- #include "vm/Field.h"
- #include "InterpreterImage.h"
- namespace hybridclr
- {
- namespace metadata
- {
- typedef void* voidptr_t;
- #define IL2CPP_ALIGN_STRUCT(type) struct type ## AlignStruct {uint8_t pad; type t; };
- IL2CPP_ALIGN_STRUCT(voidptr_t)
- IL2CPP_ALIGN_STRUCT(int8_t)
- IL2CPP_ALIGN_STRUCT(int16_t)
- IL2CPP_ALIGN_STRUCT(int32_t)
- IL2CPP_ALIGN_STRUCT(int64_t)
- IL2CPP_ALIGN_STRUCT(intptr_t)
- IL2CPP_ALIGN_STRUCT(float)
- IL2CPP_ALIGN_STRUCT(double)
- #define IL2CPP_ALIGN_OF(type) ((int32_t)offsetof(type ## AlignStruct, t))
- SizeAndAlignment ClassFieldLayoutCalculator::GetTypeSizeAndAlignment(const Il2CppType* type)
- {
- SizeAndAlignment sa = { };
- if (type->byref)
- {
- sa.size = sa.nativeSize = sizeof(voidptr_t);
- sa.alignment = IL2CPP_ALIGN_OF(voidptr_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- }
- switch (type->type)
- {
- case IL2CPP_TYPE_I1:
- case IL2CPP_TYPE_U1:
- case IL2CPP_TYPE_BOOLEAN:
- sa.size = sa.nativeSize = sizeof(int8_t);
- sa.alignment = IL2CPP_ALIGN_OF(int8_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_I2:
- case IL2CPP_TYPE_U2:
- case IL2CPP_TYPE_CHAR:
- sa.size = sa.nativeSize = sizeof(int16_t);
- sa.alignment = IL2CPP_ALIGN_OF(int16_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_I4:
- case IL2CPP_TYPE_U4:
- sa.size = sa.nativeSize = sizeof(int32_t);
- sa.alignment = IL2CPP_ALIGN_OF(int32_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_I8:
- case IL2CPP_TYPE_U8:
- sa.size = sa.nativeSize = sizeof(int64_t);
- sa.alignment = IL2CPP_ALIGN_OF(int64_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_I:
- case IL2CPP_TYPE_U:
- // TODO should we use pointer or int32_t here?
- sa.size = sa.nativeSize = sizeof(intptr_t);
- sa.alignment = IL2CPP_ALIGN_OF(intptr_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_R4:
- sa.size = sa.nativeSize = sizeof(float);
- sa.alignment = IL2CPP_ALIGN_OF(float);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_R8:
- sa.size = sa.nativeSize = sizeof(double);
- sa.alignment = IL2CPP_ALIGN_OF(double);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_PTR:
- case IL2CPP_TYPE_FNPTR:
- case IL2CPP_TYPE_STRING:
- case IL2CPP_TYPE_SZARRAY:
- case IL2CPP_TYPE_ARRAY:
- case IL2CPP_TYPE_CLASS:
- case IL2CPP_TYPE_OBJECT:
- sa.size = sa.nativeSize = sizeof(voidptr_t);
- sa.alignment = IL2CPP_ALIGN_OF(voidptr_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_VAR:
- case IL2CPP_TYPE_MVAR:
- sa.size = sa.nativeSize = 1;
- sa.alignment = 1;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- return sa;
- case IL2CPP_TYPE_VALUETYPE:
- {
- CalcClassNotStaticFields(type);
- ClassLayoutInfo& classLayout = *_classMap[type];
- sa.size = classLayout.instanceSize - sizeof(Il2CppObject);
- sa.nativeSize = classLayout.nativeSize;
- sa.alignment = classLayout.alignment;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = classLayout.naturalAlignment;
- #endif
- return sa;
- }
- case IL2CPP_TYPE_GENERICINST:
- {
- Il2CppGenericClass* gclass = type->data.generic_class;
- //Il2CppClass* container_class = GenericClass::GetTypeDefinition(gclass);
- const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
- if (IsValueType(typeDef))
- {
- CalcClassNotStaticFields(type);
- ClassLayoutInfo& classLayout = *_classMap[type];
- sa.size = classLayout.instanceSize - sizeof(Il2CppObject);
- sa.nativeSize = classLayout.nativeSize;
- sa.alignment = classLayout.alignment;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = classLayout.naturalAlignment;
- #endif
- }
- else
- {
- sa.size = sa.nativeSize = sizeof(voidptr_t);
- sa.alignment = IL2CPP_ALIGN_OF(voidptr_t);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- sa.naturalAlignment = sa.alignment;
- #endif
- }
- return sa;
- }
- default:
- IL2CPP_ASSERT(0);
- break;
- }
- return sa;
- }
- static int32_t AlignTo(int32_t size, int32_t alignment)
- {
- if (size & (alignment - 1))
- {
- size += alignment - 1;
- size &= ~(alignment - 1);
- }
- return size;
- }
- void ClassFieldLayoutCalculator::LayoutFields(int32_t actualParentSize, int32_t parentAlignment, uint8_t packing, std::vector<FieldLayout*>& fields, FieldLayoutData& data)
- {
- //data.classSize = parentSize;
- data.actualClassSize = actualParentSize;
- IL2CPP_ASSERT(parentAlignment <= std::numeric_limits<uint8_t>::max());
- data.minimumAlignment = static_cast<uint8_t>(parentAlignment);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- data.naturalAlignment = 0;
- #endif
- data.nativeSize = 0;
- for (FieldLayout* field : fields)
- {
- SizeAndAlignment sa = GetTypeSizeAndAlignment(field->type);
- field->size = sa.size;// sa.nativeSize > 0 ? sa.nativeSize : sa.size;
- // For fields, we might not want to take the actual alignment of the type - that might account for
- // packing. When a type is used as a field, we should not care about its alignment with packing,
- // instead let's use its natural alignment, without regard for packing. So if it's alignment
- // is less than the compiler's minimum alignment (4 bytes), lets use the natural alignment if we have it.
- uint8_t alignment = sa.alignment;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- if (alignment < 4 && sa.naturalAlignment != 0)
- alignment = sa.naturalAlignment;
- #endif
- if (packing != 0)
- alignment = std::min(sa.alignment, packing);
- int32_t offset = data.actualClassSize;
- offset += alignment - 1;
- offset &= ~(alignment - 1);
- field->offset = offset;
- data.FieldOffsets.push_back(offset);
- data.actualClassSize = offset + std::max(sa.size, (int32_t)1);
- data.minimumAlignment = std::max(data.minimumAlignment, alignment);
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- data.naturalAlignment = std::max({ data.naturalAlignment, sa.alignment, sa.naturalAlignment });
- #endif
- data.nativeSize += sa.size;
- }
- data.classSize = AlignTo(data.actualClassSize, data.minimumAlignment);
- // C++ ABI difference between MS and Clang
- #if IL2CPP_CXX_ABI_MSVC
- data.actualClassSize = data.classSize;
- #endif
- }
- inline bool IsRawNormalStaticField(const Il2CppType* type, int32_t offset)
- {
- if ((type->attrs & FIELD_ATTRIBUTE_STATIC) == 0)
- return false;
- if (offset == THREAD_LOCAL_STATIC_MASK)
- return false;
- if ((type->attrs & FIELD_ATTRIBUTE_LITERAL) != 0)
- return false;
- return true;
- }
- inline bool IsRawThreadStaticField(const Il2CppType* type, int32_t offset)
- {
- if ((type->attrs & FIELD_ATTRIBUTE_STATIC) == 0)
- return false;
- if (offset != THREAD_LOCAL_STATIC_MASK)
- return false;
- if ((type->attrs & FIELD_ATTRIBUTE_LITERAL) != 0)
- return false;
- return true;
- }
- void ClassFieldLayoutCalculator::CalcClassNotStaticFields(const Il2CppType* type)
- {
- auto it = _classMap.find(type);
- if (it != _classMap.end())
- {
- return;
- }
- ClassLayoutInfo& layout = *(_classMap[type] = new (HYBRIDCLR_MALLOC_ZERO(sizeof(ClassLayoutInfo))) ClassLayoutInfo());
- layout.type = type;
- const Il2CppTypeDefinition* typeDef = GetUnderlyingTypeDefinition(type);
- const char* typeName = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex);
- std::vector<FieldLayout>& fields = layout.fields;
- fields.resize(typeDef->field_count, {});
- bool isCurAssemblyType = DecodeImageIndex(typeDef->byvalTypeIndex) == _image->GetIndex();
- if ((type->type == IL2CPP_TYPE_VALUETYPE || type->type == IL2CPP_TYPE_CLASS) && !isCurAssemblyType)
- {
- Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type);
- il2cpp::vm::Class::SetupFields(klass);
- layout.instanceSize = klass->instance_size;
- layout.actualSize = klass->actualSize;
- layout.nativeSize = klass->native_size;
- layout.alignment = klass->minimumAlignment;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- layout.naturalAlignment = klass->naturalAligment;
- #endif
- return;
- }
- const Il2CppGenericContext* gc = type->type == IL2CPP_TYPE_GENERICINST ? &type->data.generic_class->context : nullptr;
- for (uint16_t i = 0; i < typeDef->field_count; i++)
- {
- Il2CppFieldDefinition* fieldDef = (Il2CppFieldDefinition*)il2cpp::vm::GlobalMetadata::GetFieldDefinitionFromTypeDefAndFieldIndex(typeDef, i);
- const Il2CppType* fieldType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(fieldDef->typeIndex);
- const Il2CppType* inflatedFieldType = gc ? TryInflateIfNeed(fieldType, gc, true) : fieldType;
- FieldLayout& fieldLayout = fields[i];
- fieldLayout.type = inflatedFieldType;
- if (isCurAssemblyType)
- {
- int32_t offset = _image->GetFieldOffset(typeDef, i);
- fieldLayout.offset = offset;
- fieldLayout.isNormalStatic = IsRawNormalStaticField(inflatedFieldType, offset);
- fieldLayout.isThreadStatic = IsRawThreadStaticField(inflatedFieldType, offset);
- }
- else
- {
- Il2CppClass* klass = il2cpp::vm::GlobalMetadata::GetTypeInfoFromHandle((Il2CppMetadataTypeHandle)typeDef);
- il2cpp::vm::Class::SetupFields(klass);
- FieldInfo* fieldInfo = klass->fields + i;
- fieldLayout.offset = fieldInfo->offset;
- fieldLayout.isNormalStatic = il2cpp::vm::Field::IsNormalStatic(fieldInfo);
- fieldLayout.isThreadStatic = il2cpp::vm::Field::IsThreadStatic(fieldInfo);
- }
- }
- if (il2cpp::metadata::GenericMetadata::ContainsGenericParameters(type)
- || ((type->type == IL2CPP_TYPE_VALUETYPE || type->type == IL2CPP_TYPE_CLASS) && typeDef->genericContainerIndex != kGenericContainerIndexInvalid))
- {
- layout.instanceSize = 0;
- layout.actualSize = 0;
- layout.nativeSize = -1;
- layout.alignment = 1;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- layout.naturalAlignment = 1;
- #endif
- return;
- }
- TbClassLayout classLayoutData = _image->GetClassLayout(typeDef);
- uint8_t packingSize = (uint8_t)classLayoutData.packingSize;
- int32_t classSize = (int32_t)(classLayoutData.classSize + sizeof(Il2CppObject));
- std::vector<FieldLayout*> instanceFields;
- for (FieldLayout& field : fields)
- {
- if (IsInstanceField(field.type))
- instanceFields.push_back(&field);
- }
- bool isExplictLayout = typeDef->flags & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT;
- if (isExplictLayout)
- {
- IL2CPP_ASSERT(IsValueType(typeDef));
- IL2CPP_ASSERT(isCurAssemblyType);
- int32_t instanceSize = IL2CPP_SIZEOF_STRUCT_WITH_NO_INSTANCE_FIELDS + sizeof(Il2CppObject);
- if (classLayoutData.classSize > 0)
- {
- instanceSize = std::max(instanceSize, (int32_t)classLayoutData.classSize + (int32_t)sizeof(Il2CppObject));
- }
- int32_t maxAlignment = 1;
- int32_t nativeSize = 1;
- for (FieldLayout* field : instanceFields)
- {
- SizeAndAlignment sa = GetTypeSizeAndAlignment(field->type);
- instanceSize = std::max(instanceSize, field->offset + (int32_t)sa.size);
- maxAlignment = std::max(maxAlignment, (int32_t)sa.alignment);
- if (packingSize != 0)
- {
- maxAlignment = std::min(maxAlignment, (int32_t)packingSize);
- }
- nativeSize = AlignTo(std::max(nativeSize, field->offset + sa.nativeSize - (int32_t)sizeof(Il2CppObject)), maxAlignment);
- }
- layout.alignment = maxAlignment;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- layout.naturalAlignment = layout.alignment;
- #endif
- layout.actualSize = layout.instanceSize = AlignTo(instanceSize, layout.alignment);
- layout.nativeSize = nativeSize;
- if (classLayoutData.classSize > 0)
- {
- layout.actualSize = std::max(layout.actualSize, classSize);
- layout.instanceSize = std::max(layout.instanceSize, classSize);
- layout.nativeSize = std::max((int32_t)classLayoutData.classSize, layout.nativeSize);
- }
- }
- else
- {
- uint8_t parentMinimumAligment;
- int32_t parentActualSize = 0;
- bool isValueType = IsValueType(typeDef);
- if (typeDef->parentIndex != kInvalidIndex)
- {
- if (isValueType)
- {
- parentMinimumAligment = 1;
- parentActualSize = sizeof(Il2CppObject);
- }
- else
- {
- const Il2CppType* parentType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->parentIndex);
- parentType = TryInflateIfNeed(parentType, gc, true);
- CalcClassNotStaticFields(parentType);
- ClassLayoutInfo* parentLayout = GetClassLayoutInfo(parentType);
- parentActualSize = parentLayout->actualSize;
- parentMinimumAligment = parentLayout->alignment;
- }
- }
- else
- {
- parentActualSize = sizeof(Il2CppObject);
- parentMinimumAligment = PTR_SIZE;
- }
- FieldLayoutData layoutData;
- LayoutFields(parentActualSize, parentMinimumAligment, packingSize, instanceFields, layoutData);
- if (instanceFields.empty() && isValueType)
- {
- layoutData.classSize = layoutData.actualClassSize = IL2CPP_SIZEOF_STRUCT_WITH_NO_INSTANCE_FIELDS + sizeof(Il2CppObject);
- layoutData.nativeSize = IL2CPP_SIZEOF_STRUCT_WITH_NO_INSTANCE_FIELDS;
- }
- layout.alignment = layoutData.minimumAlignment;
- #if !HYBRIDCLR_UNITY_2022_OR_NEW
- layout.naturalAlignment = layoutData.naturalAlignment;
- #endif
- layout.actualSize = layoutData.actualClassSize;
- layout.instanceSize = layoutData.classSize;
- layout.nativeSize = AlignTo(layoutData.nativeSize, layout.alignment);
- if (!isValueType)
- {
- layout.nativeSize = -1;
- }
- if (classLayoutData.classSize > 0)
- {
- layout.actualSize = std::max(layout.actualSize, classSize);
- layout.instanceSize = std::max(layout.instanceSize, classSize);
- layout.nativeSize = isValueType ? std::max((int32_t)classLayoutData.classSize, layout.nativeSize) : -1;
- }
- }
- }
- void ClassFieldLayoutCalculator::CalcClassStaticFields(const Il2CppType* type)
- {
- IL2CPP_ASSERT(_classMap.find(type) != _classMap.end());
- ClassLayoutInfo& layout = *_classMap[type];
- std::vector<FieldLayout*> staticFields;
- std::vector<FieldLayout*> threadStaticFields;
- for (FieldLayout& field : layout.fields)
- {
- if (field.isNormalStatic)
- {
- staticFields.push_back(&field);
- }
- else if (field.isThreadStatic)
- {
- threadStaticFields.push_back(&field);
- }
- }
- if (!staticFields.empty())
- {
- FieldLayoutData staticLayoutData;
- LayoutFields(0, 1, 0, staticFields, staticLayoutData);
- layout.staticFieldsSize = staticLayoutData.classSize;
- }
- if (!threadStaticFields.empty())
- {
- FieldLayoutData threadStaticLayoutData;
- LayoutFields(0, 1, 0, threadStaticFields, threadStaticLayoutData);
- layout.threadStaticFieldsSize = threadStaticLayoutData.classSize;
- for (FieldLayout* field : threadStaticFields)
- {
- field->offset = field->offset | THREAD_LOCAL_STATIC_MASK;
- }
- }
- }
- }
- }
|