Skip to content

Commit a2092a3

Browse files
Allow caching IDynamicInterfaceCastable results (#117646)
Resolves #107999.
1 parent f858ecf commit a2092a3

File tree

2 files changed

+52
-32
lines changed

2 files changed

+52
-32
lines changed

src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,7 @@ private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
2929
IntPtr pTargetCode = RhResolveDispatchWorker(pObject, (void*)pCell, ref cellInfo);
3030
if (pTargetCode != IntPtr.Zero)
3131
{
32-
// We don't update the dispatch cell cache if this is IDynamicInterfaceCastable because this
33-
// scenario is by-design dynamic. There is no guarantee that another instance with the same MethodTable
34-
// as the one we just resolved would do the resolution the same way. We will need to ask again.
35-
if (!pObject.GetMethodTable()->IsIDynamicInterfaceCastable)
36-
{
37-
return InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.GetMethodTable(), ref cellInfo);
38-
}
39-
else
40-
{
41-
return pTargetCode;
42-
}
32+
return InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.GetMethodTable(), ref cellInfo);
4333
}
4434

4535
// "Valid method implementation was not found."

src/tests/Interop/IDynamicInterfaceCastable/Program.cs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ public class DynamicInterfaceCastable : IDynamicInterfaceCastable, IDirectlyImpl
213213
{
214214
private Dictionary<Type, Type> interfaceToImplMap;
215215

216-
public DynamicInterfaceCastable(Dictionary<Type, Type> interfaceToImplMap)
216+
protected DynamicInterfaceCastable(Dictionary<Type, Type> interfaceToImplMap)
217217
{
218218
this.interfaceToImplMap = interfaceToImplMap;
219219
}
@@ -347,14 +347,20 @@ public RuntimeTypeHandle GetInterfaceImplementation(RuntimeTypeHandle interfaceT
347347
[ActiveIssue("https://github.com/dotnet/runtime/issues/55742", TestRuntimes.Mono)]
348348
public class Program
349349
{
350+
class DynamicInterfaceCastable_ValidateBasicInterface : DynamicInterfaceCastable
351+
{
352+
public DynamicInterfaceCastable_ValidateBasicInterface()
353+
: base(new Dictionary<Type, Type> {
354+
{ typeof(ITest), typeof(ITestImpl) }
355+
}) { }
356+
}
357+
350358
[Fact]
351359
public static void ValidateBasicInterface()
352360
{
353361
Console.WriteLine($"Running {nameof(ValidateBasicInterface)}");
354362

355-
object castableObj = new DynamicInterfaceCastable(new Dictionary<Type, Type> {
356-
{ typeof(ITest), typeof(ITestImpl) }
357-
});
363+
object castableObj = new DynamicInterfaceCastable_ValidateBasicInterface();
358364

359365
Console.WriteLine(" -- Validate cast");
360366

@@ -365,7 +371,7 @@ public static void ValidateBasicInterface()
365371

366372
Console.WriteLine(" -- Validate method call");
367373
Assert.Same(castableObj, testObj.ReturnThis());
368-
Assert.Equal(typeof(DynamicInterfaceCastable), testObj.GetMyType());
374+
Assert.Equal(typeof(DynamicInterfaceCastable_ValidateBasicInterface), testObj.GetMyType());
369375

370376
Console.WriteLine(" -- Validate method call which calls methods using 'this'");
371377
Assert.Equal(DynamicInterfaceCastable.ImplementedMethodReturnValue, testObj.CallImplemented(ImplementationToCall.Class));
@@ -379,16 +385,22 @@ public static void ValidateBasicInterface()
379385
Assert.Same(castableObj, func());
380386
}
381387

388+
class DynamicInterfaceCastable_ValidateGenericInterface : DynamicInterfaceCastable
389+
{
390+
public DynamicInterfaceCastable_ValidateGenericInterface()
391+
: base(new Dictionary<Type, Type> {
392+
{ typeof(ITestGeneric<int, int>), typeof(ITestGenericIntImpl) },
393+
{ typeof(ITestGeneric<string, string>), typeof(ITestGenericImpl<string, string>) },
394+
{ typeof(ITestGeneric<string, object>), typeof(ITestGenericImpl<object, string>) },
395+
}) { }
396+
}
397+
382398
[Fact]
383399
public static void ValidateGenericInterface()
384400
{
385401
Console.WriteLine($"Running {nameof(ValidateGenericInterface)}");
386402

387-
object castableObj = new DynamicInterfaceCastable(new Dictionary<Type, Type> {
388-
{ typeof(ITestGeneric<int, int>), typeof(ITestGenericIntImpl) },
389-
{ typeof(ITestGeneric<string, string>), typeof(ITestGenericImpl<string, string>) },
390-
{ typeof(ITestGeneric<string, object>), typeof(ITestGenericImpl<object, string>) },
391-
});
403+
object castableObj = new DynamicInterfaceCastable_ValidateGenericInterface();
392404

393405
Console.WriteLine(" -- Validate cast");
394406

@@ -442,15 +454,21 @@ public static void ValidateGenericInterface()
442454
Assert.Equal(expectedStr, funcVar(expectedStr));
443455
}
444456

457+
class DynamicInterfaceCastable_ValidateOverriddenInterface : DynamicInterfaceCastable
458+
{
459+
public DynamicInterfaceCastable_ValidateOverriddenInterface()
460+
: base(new Dictionary<Type, Type> {
461+
{ typeof(ITest), typeof(IOverrideTestImpl) },
462+
{ typeof(IOverrideTest), typeof(IOverrideTestImpl) },
463+
}) { }
464+
}
465+
445466
[Fact]
446467
public static void ValidateOverriddenInterface()
447468
{
448469
Console.WriteLine($"Running {nameof(ValidateOverriddenInterface)}");
449470

450-
object castableObj = new DynamicInterfaceCastable(new Dictionary<Type, Type> {
451-
{ typeof(ITest), typeof(IOverrideTestImpl) },
452-
{ typeof(IOverrideTest), typeof(IOverrideTestImpl) },
453-
});
471+
object castableObj = new DynamicInterfaceCastable_ValidateOverriddenInterface();
454472

455473
Console.WriteLine(" -- Validate cast");
456474

@@ -476,30 +494,42 @@ public static void ValidateOverriddenInterface()
476494
Assert.Equal(IOverrideTestImpl.GetMyTypeReturnValue, funcGetType());
477495
}
478496

497+
class DynamicInterfaceCastable_ValidateNotImplemented : DynamicInterfaceCastable
498+
{
499+
public DynamicInterfaceCastable_ValidateNotImplemented()
500+
: base(new Dictionary<Type, Type> {
501+
{ typeof(ITest), typeof(ITestImpl) }
502+
}) { }
503+
}
504+
479505
[Fact]
480506
public static void ValidateNotImplemented()
481507
{
482508
Console.WriteLine($"Running {nameof(ValidateNotImplemented)}");
483509

484-
object castableObj = new DynamicInterfaceCastable(new Dictionary<Type, Type> {
485-
{ typeof(ITest), typeof(ITestImpl) }
486-
});
510+
object castableObj = new DynamicInterfaceCastable_ValidateNotImplemented();
487511

488512
Assert.False(castableObj is INotImplemented, $"Should not be castable to {nameof(INotImplemented)} via is");
489513
Assert.Null(castableObj as INotImplemented);
490514
var ex = Assert.Throws<DynamicInterfaceCastableException>(() => { var _ = (INotImplemented)castableObj; });
491515
Assert.Equal(string.Format(DynamicInterfaceCastableException.ErrorFormat, typeof(INotImplemented)), ex.Message);
492516
}
493517

518+
class DynamicInterfaceCastable_ValidateDirectlyImplemented : DynamicInterfaceCastable
519+
{
520+
public DynamicInterfaceCastable_ValidateDirectlyImplemented()
521+
: base(new Dictionary<Type, Type> {
522+
{ typeof(ITest), typeof(ITestImpl) },
523+
{ typeof(IDirectlyImplemented), typeof(IDirectlyImplementedImpl) },
524+
}) { }
525+
}
526+
494527
[Fact]
495528
public static void ValidateDirectlyImplemented()
496529
{
497530
Console.WriteLine($"Running {nameof(ValidateDirectlyImplemented)}");
498531

499-
object castableObj = new DynamicInterfaceCastable(new Dictionary<Type, Type> {
500-
{ typeof(ITest), typeof(ITestImpl) },
501-
{ typeof(IDirectlyImplemented), typeof(IDirectlyImplementedImpl) },
502-
});
532+
object castableObj = new DynamicInterfaceCastable_ValidateDirectlyImplemented();
503533

504534
Console.WriteLine(" -- Validate cast");
505535
Assert.True(castableObj is IDirectlyImplemented, $"Should be castable to {nameof(IDirectlyImplemented)} via is");

0 commit comments

Comments
 (0)