Open ashmind opened 7 years ago
@JosephTremoulet Thanks! I actually considered that and tried to use MakeGenericType
with System.__Canon
, but I wasn't able to get it to work either. My current guess is that clrmd resolves shared generics incorrectly, but sadly that will require significant time to research/debug.
The problem here is that HotSize
is 0
btw (no cold either). I saw same issue with some other generics (inherited/non-open) where the same method was duplicated on a type -- once without proper HotColdInfo
and once with it. I was able to resolve it by finding a correct duplicate. Might be related, but I can't apply the same solution here.
Maybe you could try using the approach outlined here and see if it gets better results than using HotColdInfo
.
This works in .NET Core branch, so closing as "cannot reproduce".
Just saw this message pop up, and noticed this issue was "cannot reproduce", so sharing:
using System;
using SharpLab.Runtime;
public class C {
[JitGeneric(typeof(int)), JitGeneric(typeof(string))]
public string M<T>() {
if (typeof(T) == typeof(int))
return "int";
if (typeof(T) == typeof(string))
return "string";
return "neither";
}
}
Compile as x64 (or Default/master), Release. Link.
using System;
using System.Runtime.CompilerServices;
using SharpLab.Runtime;
public static class CompareDynamicCasting {
[JitGeneric(typeof(int)), JitGeneric(typeof(string))]
public static T UseUnsafeAs<T>()
{
if (typeof(T) == typeof(string))
{
var myStr = MakeString();
return Unsafe.As<string, T>(ref myStr);
}else if (typeof(T) == typeof(int)){
int myInt = MakeNumber();
return Unsafe.As<int, T>(ref myInt);
}else{
return default;
}
}
[JitGeneric(typeof(int)), JitGeneric(typeof(string))]
public static T UseChangeType<T>()
{
if (typeof(T) == typeof(string))
{
var myStr = MakeString();
return (T)Convert.ChangeType(myStr, typeof(T));
}else if (typeof(T) == typeof(int)){
int myInt = MakeNumber();
return (T)Convert.ChangeType(myInt, typeof(T));
}else{
return default;
}
}
[MethodImplAttribute(MethodImplOptions.NoInlining)]
private static string MakeString() => "boo";
[MethodImplAttribute(MethodImplOptions.NoInlining)]
private static int MakeNumber() => 1;
}
Viewing JIT Asm works for int
but not for string
.
Thanks! I'll revisit it when I have a moment.
Yep, simple case:
using System;
using SharpLab.Runtime;
public class C {}
public struct S {}
public class Program
{
[JitGeneric(typeof(C)), JitGeneric(typeof(S))]
public bool IsValueType<T>() => typeof(T).IsValueType;
}
Is there any way we can view JIT compiled code on our own (in Release)? That way we'll at least be able to see what is actually being generated when we define a generic that accepts reference typed arguments.
Just FYI, asked for some more clarification in https://github.com/dotnet/runtime/discussions/56274.
i use MethodImplOptions.AggressiveInlining flag for this case sharplab
If anyone needs workaround, you can use a generic class instead of generic method. For example while this one is not working:
public class C {}
public struct S {}
public class Program
{
[JitGeneric(typeof(C)), JitGeneric(typeof(S))]
public bool IsValueType<T>() => typeof(T).IsValueType;
}
Convert to this will work:
public class C {}
public struct S {}
public class Program
{
[JitGeneric(typeof(C)), JitGeneric(typeof(S))]
public class Wrapper<T>
{
public bool IsValueType() => typeof(T).IsValueType;
}
}
I'm also seeing this issue with a generic struct containing a reference type.
[JitGeneric(typeof(KeyValuePair<int, object>))]
I'd guess this has to do with "generic sharing" - for reference types, we generate a single method body of jitted machine code and use that for all of them (it has extra indirections for things that depend on the specific reference type, like if the code has
new T()
). There's a special placeholder type calledSystem. Canon
that represents "some unspecified reference type" which is what the VM tells the JIT is the type argument that the generic is being instantiated with in these cases. So I wouldn't be surprised if you're referencing a specific reference type in some api call where you need to be substitutingSystem. Canon
instead. But I'm not familiar enough with these interfaces to know which might be having the issue or how to referenceSystem. Canon
in it...(all of this is just a guess based on the statement that reference types are what's failing, btw)