@@ -119,28 +119,57 @@ internal static bool TransformSpanTArrayInitialization(NewObj inst, StatementTra
119119 replacement = null ;
120120 if ( ! context . Settings . ArrayInitializers )
121121 return false ;
122- if ( MatchSpanTCtorWithPointerAndSize ( inst , context , out var elementType , out var field , out var size ) )
122+ if ( ! MatchSpanTCtorWithPointerAndSize ( inst , context , out var elementType , out var field , out var size ) )
123+ return false ;
124+ if ( ! field . HasFlag ( System . Reflection . FieldAttributes . HasFieldRVA ) )
125+ return false ;
126+ var initialValue = field . GetInitialValue ( context . PEFile , context . TypeSystem ) ;
127+ replacement = DecodeArrayInitializerOrUTF8StringLiteral ( context , elementType , initialValue , size ) ;
128+ return replacement != null ;
129+ }
130+
131+ internal static bool TransformRuntimeHelpersCreateSpanInitialization ( Call inst , StatementTransformContext context , out ILInstruction replacement )
132+ {
133+ replacement = null ;
134+ if ( ! context . Settings . ArrayInitializers )
135+ return false ;
136+ if ( ! MatchRuntimeHelpersCreateSpan ( inst , context , out var elementType , out var field ) )
137+ return false ;
138+ if ( ! field . HasFlag ( System . Reflection . FieldAttributes . HasFieldRVA ) )
139+ return false ;
140+ if ( IsSubPatternOfCpblkInitializer ( inst ) )
141+ return false ;
142+ var initialValue = field . GetInitialValue ( context . PEFile , context . TypeSystem ) ;
143+ var elementTypeSize = elementType . GetSize ( ) ;
144+ if ( elementTypeSize <= 0 || initialValue . Length % elementTypeSize != 0 )
145+ return false ;
146+ var size = initialValue . Length / elementTypeSize ;
147+ replacement = DecodeArrayInitializerOrUTF8StringLiteral ( context , elementType , initialValue , size ) ;
148+ return replacement != null ;
149+ }
150+
151+ private static bool IsSubPatternOfCpblkInitializer ( Call inst )
152+ {
153+ if ( inst . Parent is not AddressOf { Parent : Call { Parent : Cpblk cpblk } get_Item } )
154+ return false ;
155+ return MatchGetStaticFieldAddress ( get_Item , out _ ) ;
156+ }
157+
158+ private static ILInstruction DecodeArrayInitializerOrUTF8StringLiteral ( StatementTransformContext context , IType elementType , BlobReader initialValue , int size )
159+ {
160+ if ( context . Settings . Utf8StringLiterals && elementType . IsKnownType ( KnownTypeCode . Byte )
161+ && DecodeUTF8String ( initialValue , size , out string text ) )
123162 {
124- if ( field . HasFlag ( System . Reflection . FieldAttributes . HasFieldRVA ) )
125- {
126- var valuesList = new List < ILInstruction > ( ) ;
127- var initialValue = field . GetInitialValue ( context . PEFile , context . TypeSystem ) ;
128- if ( context . Settings . Utf8StringLiterals &&
129- elementType . IsKnownType ( KnownTypeCode . Byte ) &&
130- DecodeUTF8String ( initialValue , size , out string text ) )
131- {
132- replacement = new LdStrUtf8 ( text ) ;
133- return true ;
134- }
135- if ( DecodeArrayInitializer ( elementType , initialValue , new [ ] { size } , valuesList ) )
136- {
137- var tempStore = context . Function . RegisterVariable ( VariableKind . InitializerTarget , new ArrayType ( context . TypeSystem , elementType ) ) ;
138- replacement = BlockFromInitializer ( tempStore , elementType , new [ ] { size } , valuesList . ToArray ( ) ) ;
139- return true ;
140- }
141- }
163+ return new LdStrUtf8 ( text ) ;
142164 }
143- return false ;
165+ var valuesList = new List < ILInstruction > ( ) ;
166+ if ( DecodeArrayInitializer ( elementType , initialValue , new [ ] { size } , valuesList ) )
167+ {
168+ var tempStore = context . Function . RegisterVariable ( VariableKind . InitializerTarget , new ArrayType ( context . TypeSystem , elementType ) ) ;
169+ return BlockFromInitializer ( tempStore , elementType , new [ ] { size } , valuesList . ToArray ( ) ) ;
170+ }
171+
172+ return null ;
144173 }
145174
146175 private static unsafe bool DecodeUTF8String ( BlobReader blob , int size , out string text )
@@ -153,9 +182,13 @@ private static unsafe bool DecodeUTF8String(BlobReader blob, int size, out strin
153182 for ( int i = 0 ; i < size ; i ++ )
154183 {
155184 byte val = blob . CurrentPointer [ i ] ;
156- // If the string has control characters, it's probably binary data and not a string.
157- if ( val < 0x20 && val is not ( ( byte ) '\r ' or ( byte ) '\n ' or ( byte ) '\t ' ) )
185+ if ( val == 0 && i == size - 1 && size > 1 )
186+ {
187+ // Allow explicit null-termination character.
188+ }
189+ else if ( val < 0x20 && val is not ( ( byte ) '\r ' or ( byte ) '\n ' or ( byte ) '\t ' ) )
158190 {
191+ // If the string has control characters, it's probably binary data and not a string.
159192 text = null ;
160193 return false ;
161194 }
@@ -187,6 +220,25 @@ static bool MatchSpanTCtorWithPointerAndSize(NewObj newObj, StatementTransformCo
187220 return true ;
188221 }
189222
223+ static bool MatchRuntimeHelpersCreateSpan ( Call inst , StatementTransformContext context , out IType elementType , out FieldDefinition field )
224+ {
225+ field = default ;
226+ elementType = null ;
227+ if ( ! IsRuntimeHelpers ( inst . Method . DeclaringType ) )
228+ return false ;
229+ if ( inst . Arguments . Count != 1 )
230+ return false ;
231+ if ( inst . Method is not { Name : "CreateSpan" , TypeArguments : [ var type ] } )
232+ return false ;
233+ elementType = type ;
234+ if ( ! inst . Arguments [ 0 ] . UnwrapConv ( ConversionKind . StopGCTracking ) . MatchLdMemberToken ( out var member ) )
235+ return false ;
236+ if ( member . MetadataToken . IsNil )
237+ return false ;
238+ field = context . PEFile . Metadata . GetFieldDefinition ( ( FieldDefinitionHandle ) member . MetadataToken ) ;
239+ return true ;
240+ }
241+
190242 bool DoTransformMultiDim ( ILFunction function , Block body , int pos )
191243 {
192244 if ( pos >= body . Instructions . Count - 2 )
@@ -334,7 +386,7 @@ bool HandleCpblkInitializer(Block block, int pos, ILVariable v, long length, out
334386 return true ;
335387 }
336388
337- bool MatchGetStaticFieldAddress ( ILInstruction input , out IField field )
389+ static bool MatchGetStaticFieldAddress ( ILInstruction input , out IField field )
338390 {
339391 if ( input . MatchLdsFlda ( out field ) )
340392 return true ;
@@ -357,7 +409,7 @@ bool MatchGetStaticFieldAddress(ILInstruction input, out IField field)
357409 return field != null ;
358410 }
359411
360- static bool IsRuntimeHelpers ( IType type ) => type is { Name : "RuntimeHelpers" , Namespace : "System.Runtime.CompilerServices" } ;
412+ static bool IsRuntimeHelpers ( IType type ) => type is { Name : "RuntimeHelpers" , Namespace : "System.Runtime.CompilerServices" , TypeParameterCount : 0 } ;
361413
362414 unsafe bool HandleSequentialLocAllocInitializer ( Block block , int pos , ILVariable store , ILInstruction locAllocInstruction , out IType elementType , out StObj [ ] values , out int instructionsToRemove )
363415 {
0 commit comments