@@ -78,8 +78,35 @@ public ManagedClassInstance(SnapshotFile file, RawManagedObjectInfo info, Manage
78
78
79
79
if ( IsArray )
80
80
{
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
+
83
110
return ;
84
111
}
85
112
@@ -111,30 +138,48 @@ private IFieldValue[] ReadFields(SnapshotFile file, Span<byte> data, int depth)
111
138
if ( isValueType )
112
139
fieldOffset -= file . VirtualMachineInformation . ObjectHeaderSize ;
113
140
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 ) ;
133
144
}
134
145
135
146
return fields ;
136
147
}
137
148
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
+
138
183
private bool IsEnumType ( SnapshotFile file )
139
184
=> TypeInfo . BaseTypeIndex == file . WellKnownTypes . Enum ;
140
185
@@ -221,8 +266,13 @@ private void AppendRetentionReason(StringBuilder sb, SnapshotFile file, ManagedC
221
266
break ;
222
267
}
223
268
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 ( " <- " ) ;
225
274
break ;
275
+ }
226
276
default :
227
277
throw new ArgumentOutOfRangeException ( nameof ( child ) , "Invalid LoadedReason" ) ;
228
278
}
0 commit comments