/* special/collectible static */
continue;
- pos = field_offset / TARGET_SIZEOF_VOID_P;
- pos += offset;
-
- type = mono_type_get_underlying_type (field->type);
-
- switch (type->type) {
- case MONO_TYPE_U:
- case MONO_TYPE_I:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- break;
- case MONO_TYPE_STRING:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_ARRAY:
- g_assert ((m_field_get_offset (field) % wordsize) == 0);
-
- g_assert (pos < GINT_TO_UINT32(size) || pos <= GINT_TO_UINT32(max_size));
- bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
- *max_set = MAX (GINT_TO_UINT32(*max_set), pos);
- break;
- case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (type)) {
+ guint32 field_iter = 1;
+ guint32 field_instance_offset = field_offset;
+ // If struct has InlineArray attribute, iterate `length` times to set a bitmap
+ if (m_class_is_inlinearray (p))
+ field_iter = m_class_inlinearray_value (p);
+
+ if (field_iter > 500)
+ g_warning ("Large number of iterations detected when creating a GC bitmap, might affect performance.");
+
+ while (field_iter) {
+ pos = field_instance_offset / TARGET_SIZEOF_VOID_P;
+ pos += offset;
+
+ type = mono_type_get_underlying_type (field->type);
+
+ switch (type->type) {
+ case MONO_TYPE_U:
+ case MONO_TYPE_I:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
+ break;
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_ARRAY:
g_assert ((m_field_get_offset (field) % wordsize) == 0);
+ g_assert (pos < GINT_TO_UINT32(size) || pos <= GINT_TO_UINT32(max_size));
bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
*max_set = MAX (GINT_TO_UINT32(*max_set), pos);
break;
- } else {
- /* fall through */
+ case MONO_TYPE_GENERICINST:
+ if (!mono_type_generic_inst_is_valuetype (type)) {
+ g_assert ((m_field_get_offset (field) % wordsize) == 0);
+
+ bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
+ *max_set = MAX (GINT_TO_UINT32(*max_set), pos);
+ break;
+ } else {
+ /* fall through */
+ }
+ case MONO_TYPE_TYPEDBYREF:
+ case MONO_TYPE_VALUETYPE: {
+ MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
+ if (m_class_has_references (fclass)) {
+ /* remove the object header */
+ compute_class_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS, max_set, FALSE);
+ }
+ break;
}
- case MONO_TYPE_TYPEDBYREF:
- case MONO_TYPE_VALUETYPE: {
- MonoClass *fclass = mono_class_from_mono_type_internal (field->type);
- if (m_class_has_references (fclass)) {
- /* remove the object header */
- compute_class_bitmap (fclass, bitmap, size, pos - MONO_OBJECT_HEADER_BITS, max_set, FALSE);
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ break;
+ default:
+ g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (m_field_get_parent (field)), field->name);
+ break;
}
- break;
- }
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- case MONO_TYPE_BOOLEAN:
- case MONO_TYPE_CHAR:
- break;
- default:
- g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (m_field_get_parent (field)), field->name);
- break;
- }
-
- // A struct with the inline array attribute is handled in the same way as an array
- if (m_class_is_inlinearray (klass)) {
- g_assert ((m_field_get_offset (field) % wordsize) == 0);
- g_assert (pos < GINT_TO_UINT32(size) || pos <= GINT_TO_UINT32(max_size));
- bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
- *max_set = MAX (GINT_TO_UINT32(*max_set), pos);
+ field_instance_offset += field_offset;
+ field_iter--;
}
}
if (static_fields)
[UnscopedRef]
public ref (object o, short s) this[int i] => ref Unsafe.Add(ref element, i);
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static ObjShortArr CreateArray(int recCount) {
+ if (recCount > 0) {
+ return CreateArray(recCount-1);
+ } else {
+ var arr = new ObjShortArr();
+ for (short i = 0; i < ObjShortArr.Length; i++)
+ {
+ arr[i].o = i;
+ arr[i].s = (short)(i + 1);
+ }
+ return arr;
+ }
+ }
}
[Fact]
Assert.Equal(1, *gcSeriesPtr);
}
}
+
+ // ====================== MonoGCDesc ==========================================================
+
+ class Holder {
+ public ObjShortArr arr;
+ }
+
+ static Holder CreateArray() {
+ var arr = ObjShortArr.CreateArray(100);
+ var holder = new Holder();
+ holder.arr = arr;
+ return holder;
+ }
+
+ [Fact]
+ public static void MonoGCDescOpt()
+ {
+ Console.WriteLine($"{nameof(MonoGCDescOpt)}...");
+
+ var holder = CreateArray();
+
+ GC.Collect(2, GCCollectionMode.Forced, true, true);
+
+ MakeGarbage();
+
+ for (short i = 0; i < ObjShortArr.Length; i++)
+ {
+ Assert.Equal(i, holder.arr[i].o);
+ Assert.Equal(i + 1, holder.arr[i].s);
+ }
+ }
}