@@ -62,10 +62,7 @@ private static unsafe void CopyImpl(Array sourceArray, int sourceIndex, Array de
62
62
if ( ( uint ) ( destinationIndex + length ) > destinationArray . NativeLength )
63
63
throw new ArgumentException ( SR . Arg_LongerThanDestArray , nameof ( destinationArray ) ) ;
64
64
65
- ArrayAssignType assignType = ArrayAssignType . WrongType ;
66
-
67
- if ( sourceArray . GetType ( ) == destinationArray . GetType ( )
68
- || ( assignType = CanAssignArrayType ( sourceArray , destinationArray ) ) == ArrayAssignType . SimpleCopy )
65
+ if ( sourceArray . GetType ( ) == destinationArray . GetType ( ) || IsSimpleCopy ( sourceArray , destinationArray ) )
69
66
{
70
67
MethodTable * pMT = RuntimeHelpers . GetMethodTable ( sourceArray ) ;
71
68
@@ -89,57 +86,44 @@ private static unsafe void CopyImpl(Array sourceArray, int sourceIndex, Array de
89
86
throw new ArrayTypeMismatchException ( SR . ArrayTypeMismatch_ConstrainedCopy ) ;
90
87
91
88
// Rare
92
- CopySlow ( sourceArray , sourceIndex , destinationArray , destinationIndex , length , assignType ) ;
89
+ CopySlow ( sourceArray , sourceIndex , destinationArray , destinationIndex , length ) ;
93
90
}
94
91
95
- private static CorElementType GetNormalizedIntegralArrayElementType ( CorElementType elementType )
96
- {
97
- Debug . Assert ( elementType . IsPrimitiveType ( ) ) ;
98
-
99
- // Array Primitive types such as E_T_I4 and E_T_U4 are interchangeable
100
- // Enums with interchangeable underlying types are interchangeable
101
- // BOOL is NOT interchangeable with I1/U1, neither CHAR -- with I2/U2
102
- switch ( elementType )
103
- {
104
- case CorElementType . ELEMENT_TYPE_U1 :
105
- case CorElementType . ELEMENT_TYPE_U2 :
106
- case CorElementType . ELEMENT_TYPE_U4 :
107
- case CorElementType . ELEMENT_TYPE_U8 :
108
- case CorElementType . ELEMENT_TYPE_U :
109
- return elementType - 1 ; // normalize to signed type
110
- default :
111
- return elementType ;
112
- }
113
- }
92
+ [ MethodImpl ( MethodImplOptions . InternalCall ) ]
93
+ private static extern bool IsSimpleCopy ( Array sourceArray , Array destinationArray ) ;
114
94
115
95
// Reliability-wise, this method will either possibly corrupt your
116
96
// instance & might fail when called from within a CER, or if the
117
97
// reliable flag is true, it will either always succeed or always
118
98
// throw an exception with no side effects.
119
- private static unsafe void CopySlow ( Array sourceArray , int sourceIndex , Array destinationArray , int destinationIndex , int length , ArrayAssignType assignType )
99
+ private static unsafe void CopySlow ( Array sourceArray , int sourceIndex , Array destinationArray , int destinationIndex , int length )
120
100
{
121
101
Debug . Assert ( sourceArray . Rank == destinationArray . Rank ) ;
122
102
123
- if ( assignType == ArrayAssignType . WrongType )
103
+ void * srcTH = RuntimeHelpers . GetMethodTable ( sourceArray ) ->ElementType ;
104
+ void * destTH = RuntimeHelpers . GetMethodTable ( destinationArray ) ->ElementType ;
105
+ AssignArrayEnum r = CanAssignArrayType ( srcTH , destTH ) ;
106
+
107
+ if ( r == AssignArrayEnum . AssignWrongType )
124
108
throw new ArrayTypeMismatchException ( SR . ArrayTypeMismatch_CantAssignType ) ;
125
109
126
110
if ( length > 0 )
127
111
{
128
- switch ( assignType )
112
+ switch ( r )
129
113
{
130
- case ArrayAssignType . UnboxValueClass :
114
+ case AssignArrayEnum . AssignUnboxValueClass :
131
115
CopyImplUnBoxEachElement ( sourceArray , sourceIndex , destinationArray , destinationIndex , length ) ;
132
116
break ;
133
117
134
- case ArrayAssignType . BoxValueClassOrPrimitive :
118
+ case AssignArrayEnum . AssignBoxValueClassOrPrimitive :
135
119
CopyImplBoxEachElement ( sourceArray , sourceIndex , destinationArray , destinationIndex , length ) ;
136
120
break ;
137
121
138
- case ArrayAssignType . MustCast :
122
+ case AssignArrayEnum . AssignMustCast :
139
123
CopyImplCastCheckEachElement ( sourceArray , sourceIndex , destinationArray , destinationIndex , length ) ;
140
124
break ;
141
125
142
- case ArrayAssignType . PrimitiveWiden :
126
+ case AssignArrayEnum . AssignPrimitiveWiden :
143
127
CopyImplPrimitiveWiden ( sourceArray , sourceIndex , destinationArray , destinationIndex , length ) ;
144
128
break ;
145
129
@@ -150,76 +134,18 @@ private static unsafe void CopySlow(Array sourceArray, int sourceIndex, Array de
150
134
}
151
135
}
152
136
153
- private enum ArrayAssignType
137
+ // Must match the definition in arraynative.cpp
138
+ private enum AssignArrayEnum
154
139
{
155
- SimpleCopy ,
156
- WrongType ,
157
- MustCast ,
158
- BoxValueClassOrPrimitive ,
159
- UnboxValueClass ,
160
- PrimitiveWiden ,
140
+ AssignWrongType ,
141
+ AssignMustCast ,
142
+ AssignBoxValueClassOrPrimitive ,
143
+ AssignUnboxValueClass ,
144
+ AssignPrimitiveWiden ,
161
145
}
162
146
163
- private static unsafe ArrayAssignType CanAssignArrayType ( Array sourceArray , Array destinationArray )
164
- {
165
- TypeHandle srcTH = RuntimeHelpers . GetMethodTable ( sourceArray ) ->GetArrayElementTypeHandle ( ) ;
166
- TypeHandle destTH = RuntimeHelpers . GetMethodTable ( destinationArray ) ->GetArrayElementTypeHandle ( ) ;
167
-
168
- if ( TypeHandle . AreSameType ( srcTH , destTH ) ) // This check kicks for different array kind or dimensions
169
- return ArrayAssignType . SimpleCopy ;
170
-
171
- // Value class boxing
172
- if ( srcTH . IsValueType && ! destTH . IsValueType )
173
- {
174
- if ( srcTH . CanCastTo ( destTH ) )
175
- return ArrayAssignType . BoxValueClassOrPrimitive ;
176
- else
177
- return ArrayAssignType . WrongType ;
178
- }
179
-
180
- // Value class unboxing.
181
- if ( ! srcTH . IsValueType && destTH . IsValueType )
182
- {
183
- if ( srcTH . CanCastTo ( destTH ) )
184
- return ArrayAssignType . UnboxValueClass ;
185
- else if ( destTH . CanCastTo ( srcTH ) ) // V extends IV. Copying from IV to V, or Object to V.
186
- return ArrayAssignType . UnboxValueClass ;
187
- else
188
- return ArrayAssignType . WrongType ;
189
- }
190
-
191
- CorElementType srcElType = srcTH . GetVerifierCorElementType ( ) ;
192
- CorElementType destElType = destTH . GetVerifierCorElementType ( ) ;
193
-
194
- // Copying primitives from one type to another
195
- if ( srcElType . IsPrimitiveType ( ) && destElType . IsPrimitiveType ( ) )
196
- {
197
- if ( GetNormalizedIntegralArrayElementType ( srcElType ) == GetNormalizedIntegralArrayElementType ( destElType ) )
198
- return ArrayAssignType . SimpleCopy ;
199
- else if ( RuntimeHelpers . CanPrimitiveWiden ( srcElType , destElType ) )
200
- return ArrayAssignType . PrimitiveWiden ;
201
- else
202
- return ArrayAssignType . WrongType ;
203
- }
204
-
205
- // src Object extends dest
206
- if ( srcTH . CanCastTo ( destTH ) )
207
- return ArrayAssignType . SimpleCopy ;
208
-
209
- // dest Object extends src
210
- if ( destTH . CanCastTo ( srcTH ) )
211
- return ArrayAssignType . MustCast ;
212
-
213
- // class X extends/implements src and implements dest.
214
- if ( destTH . IsInterface && srcElType != CorElementType . ELEMENT_TYPE_VALUETYPE )
215
- return ArrayAssignType . MustCast ;
216
-
217
- // class X implements src and extends/implements dest
218
- if ( srcTH . IsInterface && srcElType != CorElementType . ELEMENT_TYPE_VALUETYPE )
219
- return ArrayAssignType . MustCast ;
220
-
221
- return ArrayAssignType . WrongType ;
222
- }
147
+ [ LibraryImport ( RuntimeHelpers . QCall , EntryPoint = "Array_CanAssignArrayType" ) ]
148
+ private static unsafe partial AssignArrayEnum CanAssignArrayType ( void * srcTH , void * dstTH ) ;
223
149
224
150
// Unboxes from an Object[] into a value class or primitive array.
225
151
private static unsafe void CopyImplUnBoxEachElement ( Array sourceArray , int sourceIndex , Array destinationArray , int destinationIndex , int length )
0 commit comments