diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2017-12-29 23:11:16 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-12-29 23:11:16 +0300 |
commit | ab4222fba0dddecc122b3a5d0437b8c7b6bfee60 (patch) | |
tree | 796587af5deed41c43fb9712c94f844b885fcb89 | |
parent | b01af15177f8b2124d10c31a17a1502d6613eda9 (diff) |
Ensure reflection has access to instance methods on byref-like types (#5165)
* Ensure reflection has access to instance methods on byref-like types
Adding the test uncovered a subtle issue. When rooting a virtual method for reflection, we should root the virtual method use of the slot defining method (not e.g. the `ToString` method on the byref-like type - we don't have virtual method use information for that).
* Disable part that doesn't work on Unix
-rw-r--r-- | src/ILCompiler.Compiler/src/Compiler/Compilation.cs | 6 | ||||
-rw-r--r-- | src/ILCompiler/src/RdXmlRootProvider.cs | 5 | ||||
-rw-r--r-- | tests/src/Simple/Reflection/Reflection.cs | 45 |
3 files changed, 50 insertions, 6 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs index 0c2ba2453..d686a0d7b 100644 --- a/src/ILCompiler.Compiler/src/Compiler/Compilation.cs +++ b/src/ILCompiler.Compiler/src/Compiler/Compilation.cs @@ -400,8 +400,10 @@ namespace ILCompiler { Debug.Assert(method.IsVirtual); - if (!_factory.VTable(method.OwningType).HasFixedSlots) - _graph.AddRoot(_factory.VirtualMethodUse(method), reason); + // Virtual method use is tracked on the slot defining method only. + MethodDesc slotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); + if (!_factory.VTable(slotDefiningMethod.OwningType).HasFixedSlots) + _graph.AddRoot(_factory.VirtualMethodUse(slotDefiningMethod), reason); if (method.IsAbstract) { diff --git a/src/ILCompiler/src/RdXmlRootProvider.cs b/src/ILCompiler/src/RdXmlRootProvider.cs index 8698f1d5f..d55f87720 100644 --- a/src/ILCompiler/src/RdXmlRootProvider.cs +++ b/src/ILCompiler/src/RdXmlRootProvider.cs @@ -181,10 +181,7 @@ namespace ILCompiler // Virtual methods should be rooted as if they were called virtually if (method.IsVirtual) - { - MethodDesc slotMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method); - rootProvider.RootVirtualMethodForReflection(slotMethod, "RD.XML root"); - } + rootProvider.RootVirtualMethodForReflection(method, "RD.XML root"); if (!method.IsAbstract) rootProvider.AddCompilationRoot(method, "RD.XML root"); diff --git a/tests/src/Simple/Reflection/Reflection.cs b/tests/src/Simple/Reflection/Reflection.cs index 189090b3a..f24a855a8 100644 --- a/tests/src/Simple/Reflection/Reflection.cs +++ b/tests/src/Simple/Reflection/Reflection.cs @@ -28,6 +28,7 @@ internal class ReflectionTest #if !OPTIMIZED_MODE_WITHOUT_SCANNER TestContainment.Run(); TestInterfaceMethod.Run(); + TestByRefLikeTypeMethod.Run(); #endif TestAttributeInheritance.Run(); TestStringConstructor.Run(); @@ -324,6 +325,50 @@ internal class ReflectionTest } } + class TestByRefLikeTypeMethod + { + ref struct ByRefLike + { + public readonly int Value; + + public ByRefLike(int value) + { + Value = value; + } + + public override string ToString() + { + return Value.ToString(); + } + } + + delegate string ToStringDelegate(ref ByRefLike thisObj); + + public static void Run() + { + Console.WriteLine(nameof(TestByRefLikeTypeMethod)); + + // Ensure things we reflect on are in the static callgraph + if (string.Empty.Length > 0) + { + default(ByRefLike).ToString(); + ToStringDelegate s = null; + s = s.Invoke; + } + + Type byRefLikeType = GetTestType(nameof(TestByRefLikeTypeMethod), nameof(ByRefLike)); + MethodInfo toStringMethod = byRefLikeType.GetMethod("ToString"); + /*var toString = (ToStringDelegate)*/toStringMethod.CreateDelegate(typeof(ToStringDelegate)); + + // Doesn't work on Unix: https://github.com/dotnet/corert/issues/4379 +#if false + ByRefLike foo = new ByRefLike(123); + if (toString(ref foo) != "123") + throw new Exception(); +#endif + } + } + class TestInterfaceMethod { interface IFoo |