@@ -78,8 +78,35 @@ public ManagedClassInstance(SnapshotFile file, RawManagedObjectInfo info, Manage
7878
7979 if ( IsArray )
8080 {
81- //TODO array items
82- Fields = Array . Empty < IFieldValue > ( ) ;
81+ var arrayElementCount = file . ReadArrayLength ( TypeDescriptionFlags , data ) ;
82+
83+ if ( arrayElementCount == 0 )
84+ {
85+ Fields = Array . Empty < IFieldValue > ( ) ;
86+ return ;
87+ }
88+
89+ var typeInfo = file . GetTypeInfo ( info . TypeDescriptionIndex ) ;
90+
91+ if ( typeInfo . BaseTypeIndex < 0 )
92+ {
93+ Console . WriteLine ( "WARNING: Skipping uninitialized array type" ) ;
94+ Fields = Array . Empty < IFieldValue > ( ) ;
95+ return ;
96+ }
97+
98+ var elementType = file . GetTypeInfo ( typeInfo . BaseTypeIndex ) ;
99+ var elementFlags = file . GetTypeFlagsByIndex ( elementType . TypeIndex ) ;
100+ var elementTypeSize = ( elementFlags & TypeFlags . ValueType ) != 0 ? file . GetTypeDescriptionSizeBytes ( elementType . TypeIndex ) : 8 ;
101+ var arrayData = info . Data . AsSpan ( file . VirtualMachineInformation . ArrayHeaderSize ..) ;
102+
103+ Fields = new IFieldValue [ arrayElementCount ] ;
104+ for ( var i = 0 ; i < arrayElementCount ; i ++ )
105+ {
106+ var elementData = arrayData [ ( i * elementTypeSize ) ..] ;
107+ Fields [ i ] = ReadFieldValue ( file , elementData , depth , elementFlags , elementTypeSize , elementType . TypeIndex , i ) ;
108+ }
109+
83110 return ;
84111 }
85112
@@ -111,30 +138,48 @@ private IFieldValue[] ReadFields(SnapshotFile file, Span<byte> data, int depth)
111138 if ( isValueType )
112139 fieldOffset -= file . VirtualMachineInformation . ObjectHeaderSize ;
113140
114- var fieldPtr = data [ fieldOffset ..] ;
115-
116- //For all integer types, we just handle unsigned as signed
117- if ( info . TypeDescriptionIndex == file . WellKnownTypes . String )
118- fields [ index ] = new StringFieldValue ( file , fieldPtr ) ;
119- else if ( info . TypeDescriptionIndex == file . WellKnownTypes . Boolean || info . TypeDescriptionIndex == file . WellKnownTypes . Byte )
120- fields [ index ] = new IntegerFieldValue ( fieldPtr [ 0 ] ) ;
121- else if ( info . TypeDescriptionIndex == file . WellKnownTypes . Int16 || info . TypeDescriptionIndex == file . WellKnownTypes . UInt16 || info . TypeDescriptionIndex == file . WellKnownTypes . Char )
122- fields [ index ] = new IntegerFieldValue ( BitConverter . ToInt16 ( fieldPtr ) ) ;
123- else if ( info . TypeDescriptionIndex == file . WellKnownTypes . Int32 || info . TypeDescriptionIndex == file . WellKnownTypes . UInt32 )
124- fields [ index ] = new IntegerFieldValue ( BitConverter . ToInt32 ( fieldPtr ) ) ;
125- else if ( info . TypeDescriptionIndex == file . WellKnownTypes . Int64 || info . TypeDescriptionIndex == file . WellKnownTypes . UInt64 || info . TypeDescriptionIndex == file . WellKnownTypes . IntPtr )
126- fields [ index ] = new IntegerFieldValue ( BitConverter . ToInt64 ( fieldPtr ) ) ;
127- else if ( info . TypeDescriptionIndex == file . WellKnownTypes . Single )
128- fields [ index ] = new FloatingPointFieldValue ( BitConverter . ToSingle ( fieldPtr ) ) ;
129- else if ( info . TypeDescriptionIndex == file . WellKnownTypes . Double )
130- fields [ index ] = new FloatingPointFieldValue ( BitConverter . ToDouble ( fieldPtr ) ) ;
131- else
132- fields [ index ] = new ComplexFieldValue ( file , info , this , fieldPtr , depth + 1 ) ;
141+ var fieldData = data [ fieldOffset ..] ;
142+
143+ fields [ index ] = ReadFieldValue ( file , info , fieldData , depth , false ) ;
133144 }
134145
135146 return fields ;
136147 }
137148
149+ private IFieldValue ReadFieldValue ( SnapshotFile file , BasicFieldInfoCache info , Span < byte > fieldData , int depth , bool array )
150+ {
151+ //For all integer types, we just handle unsigned as signed
152+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . String )
153+ return new StringFieldValue ( file , fieldData ) ;
154+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . Boolean || info . TypeDescriptionIndex == file . WellKnownTypes . Byte )
155+ return new IntegerFieldValue ( fieldData [ 0 ] ) ;
156+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . Int16 || info . TypeDescriptionIndex == file . WellKnownTypes . UInt16 || info . TypeDescriptionIndex == file . WellKnownTypes . Char )
157+ return new IntegerFieldValue ( BitConverter . ToInt16 ( fieldData ) ) ;
158+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . Int32 || info . TypeDescriptionIndex == file . WellKnownTypes . UInt32 )
159+ return new IntegerFieldValue ( BitConverter . ToInt32 ( fieldData ) ) ;
160+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . Int64 || info . TypeDescriptionIndex == file . WellKnownTypes . UInt64 || info . TypeDescriptionIndex == file . WellKnownTypes . IntPtr )
161+ return new IntegerFieldValue ( BitConverter . ToInt64 ( fieldData ) ) ;
162+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . Single )
163+ return new FloatingPointFieldValue ( BitConverter . ToSingle ( fieldData ) ) ;
164+ if ( info . TypeDescriptionIndex == file . WellKnownTypes . Double )
165+ return new FloatingPointFieldValue ( BitConverter . ToDouble ( fieldData ) ) ;
166+
167+ return new ComplexFieldValue ( file , info , this , fieldData , depth + 1 , array ) ;
168+ }
169+
170+ private IFieldValue ReadFieldValue ( SnapshotFile file , Span < byte > fieldData , int depth , TypeFlags fieldTypeFlags , int fieldTypeSize , int fieldTypeIndex , int arrayOffset )
171+ {
172+ BasicFieldInfoCache info = new ( )
173+ {
174+ Flags = fieldTypeFlags ,
175+ FieldIndex = arrayOffset ,
176+ TypeDescriptionIndex = fieldTypeIndex ,
177+ FieldTypeSize = fieldTypeSize ,
178+ } ;
179+
180+ return ReadFieldValue ( file , info , fieldData , depth , true ) ;
181+ }
182+
138183 private bool IsEnumType ( SnapshotFile file )
139184 => TypeInfo . BaseTypeIndex == file . WellKnownTypes . Enum ;
140185
@@ -221,8 +266,13 @@ private void AppendRetentionReason(StringBuilder sb, SnapshotFile file, ManagedC
221266 break ;
222267 }
223268 case LoadedReason . ArrayElement :
224- //TODO
269+ {
270+ var parentName = file . GetTypeName ( parent . TypeInfo . TypeIndex ) ;
271+ sb . Append ( "Array Element " ) . Append ( child . FieldIndexOrArrayOffset ) . Append ( " of " ) ;
272+ sb . Append ( parentName ) . Append ( " at 0x" ) . Append ( parent . ObjectAddress . ToString ( "X" ) ) ;
273+ sb . Append ( " <- " ) ;
225274 break ;
275+ }
226276 default :
227277 throw new ArgumentOutOfRangeException ( nameof ( child ) , "Invalid LoadedReason" ) ;
228278 }
0 commit comments