FieldLayout.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #include "il2cpp-config.h"
  2. #include "il2cpp-class-internals.h"
  3. #include "vm/Class.h"
  4. #include "vm/GenericClass.h"
  5. #include "vm/Type.h"
  6. #include "metadata/FieldLayout.h"
  7. #include <limits>
  8. #include <algorithm>
  9. using il2cpp::vm::Class;
  10. using il2cpp::vm::GenericClass;
  11. using il2cpp::vm::Type;
  12. namespace il2cpp
  13. {
  14. namespace metadata
  15. {
  16. typedef void* voidptr_t;
  17. #define IL2CPP_ALIGN_STRUCT(type) struct type ## AlignStruct {uint8_t pad; type t; };
  18. IL2CPP_ALIGN_STRUCT(voidptr_t)
  19. IL2CPP_ALIGN_STRUCT(int8_t)
  20. IL2CPP_ALIGN_STRUCT(int16_t)
  21. IL2CPP_ALIGN_STRUCT(int32_t)
  22. IL2CPP_ALIGN_STRUCT(int64_t)
  23. IL2CPP_ALIGN_STRUCT(intptr_t)
  24. IL2CPP_ALIGN_STRUCT(float)
  25. IL2CPP_ALIGN_STRUCT(double)
  26. #define IL2CPP_ALIGN_OF(type) ((size_t)offsetof(type ## AlignStruct, t))
  27. SizeAndAlignment FieldLayout::GetTypeSizeAndAlignment(const Il2CppType* type)
  28. {
  29. SizeAndAlignment sa = { 0 };
  30. if (type->byref)
  31. {
  32. sa.size = sizeof(voidptr_t);
  33. sa.alignment = IL2CPP_ALIGN_OF(voidptr_t);
  34. return sa;
  35. }
  36. switch (type->type)
  37. {
  38. case IL2CPP_TYPE_I1:
  39. case IL2CPP_TYPE_U1:
  40. case IL2CPP_TYPE_BOOLEAN:
  41. sa.size = sizeof(int8_t);
  42. sa.alignment = IL2CPP_ALIGN_OF(int8_t);
  43. return sa;
  44. case IL2CPP_TYPE_I2:
  45. case IL2CPP_TYPE_U2:
  46. case IL2CPP_TYPE_CHAR:
  47. sa.size = sizeof(int16_t);
  48. sa.alignment = IL2CPP_ALIGN_OF(int16_t);
  49. return sa;
  50. case IL2CPP_TYPE_I4:
  51. case IL2CPP_TYPE_U4:
  52. sa.size = sizeof(int32_t);
  53. sa.alignment = IL2CPP_ALIGN_OF(int32_t);
  54. return sa;
  55. case IL2CPP_TYPE_I8:
  56. case IL2CPP_TYPE_U8:
  57. sa.size = sizeof(int64_t);
  58. sa.alignment = IL2CPP_ALIGN_OF(int64_t);
  59. return sa;
  60. case IL2CPP_TYPE_I:
  61. case IL2CPP_TYPE_U:
  62. // TODO should we use pointer or size_t here?
  63. sa.size = sizeof(intptr_t);
  64. sa.alignment = IL2CPP_ALIGN_OF(intptr_t);
  65. return sa;
  66. case IL2CPP_TYPE_R4:
  67. sa.size = sizeof(float);
  68. sa.alignment = IL2CPP_ALIGN_OF(float);
  69. return sa;
  70. case IL2CPP_TYPE_R8:
  71. sa.size = sizeof(double);
  72. sa.alignment = IL2CPP_ALIGN_OF(double);
  73. return sa;
  74. case IL2CPP_TYPE_PTR:
  75. case IL2CPP_TYPE_FNPTR:
  76. case IL2CPP_TYPE_STRING:
  77. case IL2CPP_TYPE_SZARRAY:
  78. case IL2CPP_TYPE_ARRAY:
  79. case IL2CPP_TYPE_CLASS:
  80. case IL2CPP_TYPE_OBJECT:
  81. case IL2CPP_TYPE_VAR:
  82. case IL2CPP_TYPE_MVAR:
  83. sa.size = sizeof(voidptr_t);
  84. sa.alignment = IL2CPP_ALIGN_OF(voidptr_t);
  85. return sa;
  86. case IL2CPP_TYPE_VALUETYPE:
  87. if (Type::IsEnum(type))
  88. {
  89. return GetTypeSizeAndAlignment(Class::GetEnumBaseType(Type::GetClass(type)));
  90. }
  91. else
  92. {
  93. uint32_t alignment;
  94. Il2CppClass* klass = Type::GetClass(type);
  95. sa.size = Class::GetValueSize(klass, &alignment);
  96. sa.alignment = alignment;
  97. sa.naturalAlignment = klass->naturalAligment;
  98. return sa;
  99. }
  100. case IL2CPP_TYPE_GENERICINST:
  101. {
  102. Il2CppGenericClass* gclass = type->data.generic_class;
  103. Il2CppClass* container_class = GenericClass::GetTypeDefinition(gclass);
  104. if (container_class != NULL && container_class->byval_arg.valuetype)
  105. {
  106. if (container_class->enumtype)
  107. {
  108. return GetTypeSizeAndAlignment(Class::GetEnumBaseType(container_class));
  109. }
  110. else
  111. {
  112. uint32_t alignment;
  113. sa.size = Class::GetValueSize(Class::FromIl2CppType(type), &alignment);
  114. sa.alignment = alignment;
  115. return sa;
  116. }
  117. }
  118. else
  119. {
  120. sa.size = sizeof(voidptr_t);
  121. sa.alignment = IL2CPP_ALIGN_OF(voidptr_t);
  122. return sa;
  123. }
  124. }
  125. default:
  126. IL2CPP_ASSERT(0);
  127. break;
  128. }
  129. return sa;
  130. }
  131. static size_t AlignTo(size_t size, size_t alignment)
  132. {
  133. if (size & (alignment - 1))
  134. {
  135. size += alignment - 1;
  136. size &= ~(alignment - 1);
  137. }
  138. return size;
  139. }
  140. void FieldLayout::LayoutFields(const Il2CppClass* klass, FieldInfoFilter filter, size_t parentSize, size_t actualParentSize, size_t parentAlignment, uint8_t packing, FieldLayoutData& data)
  141. {
  142. data.classSize = parentSize;
  143. data.actualClassSize = actualParentSize;
  144. IL2CPP_ASSERT(parentAlignment <= std::numeric_limits<uint8_t>::max());
  145. data.minimumAlignment = static_cast<uint8_t>(parentAlignment);
  146. data.naturalAlignment = 0;
  147. for (uint16_t i = 0; i < klass->field_count; i++)
  148. {
  149. if (!filter(klass->fields + i))
  150. continue;
  151. SizeAndAlignment sa = GetTypeSizeAndAlignment(klass->fields[i].type);
  152. // For fields, we might not want to take the actual alignment of the type - that might account for
  153. // packing. When a type is used as a field, we should not care about its alignment with packing,
  154. // instead let's use its natural alignment, without regard for packing. So if it's alignment
  155. // is less than the compiler's minimum alignment (4 bytes), lets use the natural alignment if we have it.
  156. uint8_t alignment = sa.alignment;
  157. if (alignment < 4 && sa.naturalAlignment != 0)
  158. alignment = sa.naturalAlignment;
  159. if (packing != 0)
  160. alignment = std::min(sa.alignment, packing);
  161. size_t offset = data.actualClassSize;
  162. offset += alignment - 1;
  163. offset &= ~(alignment - 1);
  164. data.FieldOffsets.push_back(offset);
  165. data.actualClassSize = offset + std::max(sa.size, (size_t)1);
  166. data.minimumAlignment = std::max(data.minimumAlignment, alignment);
  167. data.naturalAlignment = std::max({data.naturalAlignment, sa.alignment, sa.naturalAlignment});
  168. }
  169. data.classSize = AlignTo(data.actualClassSize, data.minimumAlignment);
  170. // C++ ABI difference between MS and Clang
  171. #if IL2CPP_CXX_ABI_MSVC
  172. data.actualClassSize = data.classSize;
  173. #endif
  174. }
  175. } /* namespace vm */
  176. } /* namespace il2cpp */