@@ -235,6 +235,48 @@ internal MemberInfoCache(RuntimeTypeCache runtimeTypeCache)
235
235
236
236
internal MethodBase AddMethod ( RuntimeType declaringType , RuntimeMethodHandleInternal method , CacheType cacheType )
237
237
{
238
+ // First, see if we've already cached an RuntimeMethodInfo or
239
+ // RuntimeConstructorInfo that corresponds to this member. Since another
240
+ // thread could be updating the backing store at the same time it's
241
+ // possible that the check below will result in a false negative. That's
242
+ // ok; we'll handle any concurrency issues in the later call to Insert.
243
+
244
+ T ? [ ] ? allMembersLocal = m_allMembers ;
245
+ if ( allMembersLocal != null )
246
+ {
247
+ // if not a Method or a Constructor, fall through
248
+ if ( cacheType == CacheType . Method )
249
+ {
250
+ foreach ( T ? candidate in allMembersLocal )
251
+ {
252
+ if ( candidate is null )
253
+ {
254
+ break ; // end of list; stop iteration and fall through to slower path
255
+ }
256
+
257
+ if ( candidate is RuntimeMethodInfo candidateRMI && candidateRMI . MethodHandle . Value == method . Value )
258
+ {
259
+ return candidateRMI ; // match!
260
+ }
261
+ }
262
+ }
263
+ else if ( cacheType == CacheType . Constructor )
264
+ {
265
+ foreach ( T ? candidate in allMembersLocal )
266
+ {
267
+ if ( candidate is null )
268
+ {
269
+ break ; // end of list; stop iteration and fall through to slower path
270
+ }
271
+
272
+ if ( candidate is RuntimeConstructorInfo candidateRCI && candidateRCI . MethodHandle . Value == method . Value )
273
+ {
274
+ return candidateRCI ; // match!
275
+ }
276
+ }
277
+ }
278
+ }
279
+
238
280
T [ ] list = null ! ;
239
281
MethodAttributes methodAttributes = RuntimeMethodHandle . GetAttributes ( method ) ;
240
282
bool isPublic = ( methodAttributes & MethodAttributes . MemberAccessMask ) == MethodAttributes . Public ;
@@ -262,6 +304,29 @@ internal MethodBase AddMethod(RuntimeType declaringType, RuntimeMethodHandleInte
262
304
263
305
internal FieldInfo AddField ( RuntimeFieldHandleInternal field )
264
306
{
307
+ // First, see if we've already cached an RtFieldInfo that corresponds
308
+ // to this field. Since another thread could be updating the backing
309
+ // store at the same time it's possible that the check below will
310
+ // result in a false negative. That's ok; we'll handle any concurrency
311
+ // issues in the later call to Insert.
312
+
313
+ T ? [ ] ? allMembersLocal = m_allMembers ;
314
+ if ( allMembersLocal != null )
315
+ {
316
+ foreach ( T ? candidate in allMembersLocal )
317
+ {
318
+ if ( candidate is null )
319
+ {
320
+ break ; // end of list; stop iteration and fall through to slower path
321
+ }
322
+
323
+ if ( candidate is RtFieldInfo candidateRtFI && candidateRtFI . GetFieldHandle ( ) == field . Value )
324
+ {
325
+ return candidateRtFI ; // match!
326
+ }
327
+ }
328
+ }
329
+
265
330
// create the runtime field info
266
331
FieldAttributes fieldAttributes = RuntimeFieldHandle . GetAttributes ( field ) ;
267
332
bool isPublic = ( fieldAttributes & FieldAttributes . FieldAccessMask ) == FieldAttributes . Public ;
@@ -506,7 +571,7 @@ private void MergeWithGlobalList(T[] list)
506
571
}
507
572
508
573
Debug . Assert ( cachedMembers ! [ freeSlotIndex ] == null ) ;
509
- cachedMembers [ freeSlotIndex ] = newMemberInfo ;
574
+ Volatile . Write ( ref cachedMembers [ freeSlotIndex ] , newMemberInfo ) ; // value may be read outside of lock
510
575
freeSlotIndex ++ ;
511
576
}
512
577
}
0 commit comments