forked from mono/mono
-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[metadata] Fields whose types are gparams with a reference type const…
…raint aren't blittlable. (mono#15761) * [metadata] Fields whose types are gparams with a reference type constraint aren't blittlable. Don't try to layout the field to find out if it's blittable. For gshared gparams, follow the blittability of the constraint. Fixes certain recursive examples. ``` using System; namespace TestRecursiveType { class Program { static void Main(string[] args) { SubClass subC = new SubClass(); Console.WriteLine(subC.GetTest()); } } public struct ValueTest<U> { // When U is instantiated with T, from BaseClass, we know it'll be a // reference field, so we know the instantiation ValueTest<T> won't // be blittable. public readonly U value; } public abstract class BaseClass<T> where T : BaseClass<T> { public ValueTest<T> valueTest = default(ValueTest<T>); } public class SubClass : BaseClass<SubClass> { private String test = "test"; public string GetTest() { return test; } } } ``` Fixes mono#15760 --- The failure is happening when we are doing mono_class_setup_fields ("BaseClass<T>") which needs to decide for each field whether it is blittable or not. So therefore we are trying to decide if ValueTest<T> (that is: the ValueTest<U> field inside BaseClass<T>) is blittable or not. So we instantiate U with T. Now to decide whether VaueTest<T> is blittable or not, we look at every field. So then we look at T value. To decide if T is blittable we first check if it's a reference type. That check is currently inadequate for generic parameters - what the PR adds is the ability to see if theres a T : class constraint or a T : C constraint - where C is some class. As soon as we know that T's constraint will force it to be a reference type we can definitely say that T won't be blittable without having to initialize C, at all. Previously, Mono would see that T is some kind of type for which it couldn't definitively decide that it's a reference type and it would call: mono_class_setup_fields (field_class) which would then try to setup the fields of the parent class BaseClass<T>. And that would hit the recursion check. Unity cherry-pick note: Needed to bring MONO_CLASS_IS_INTERFACE_INTERNAL and mono_class_get_valuetype_class forward
- Loading branch information
1 parent
7a3ac72
commit 8e9be33
Showing
6 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System; | ||
|
||
class Program { | ||
static void Main (string[] args) | ||
{ | ||
// If this runs without a TLE, the test passed. A | ||
// TypeLoadException due to recursion during type | ||
// initialization is a failure. | ||
var subC = new SubClass (); | ||
Console.WriteLine (subC.GetTest ()); | ||
// same as above, but try to land in generic sharing code. | ||
var genSubC = new GenericSubClass<object> (); | ||
Console.WriteLine (genSubC.GetTest ()); | ||
} | ||
} | ||
|
||
public struct ValueTest<U> { | ||
// When U is instantiated with T, from BaseClass, we know it'll be a | ||
// reference field without having to fully initialize its parent | ||
// (namely BaseClass<T> itself), so we know the instantiation | ||
// ValueTest<T> won't be blittable. | ||
public readonly U value; | ||
} | ||
|
||
public abstract class BaseClass<T> where T : BaseClass<T> { | ||
public ValueTest<T> valueTest = default (ValueTest<T>); | ||
} | ||
|
||
public class SubClass : BaseClass<SubClass> { | ||
private string test = "test"; | ||
|
||
public string GetTest() | ||
{ | ||
return test; | ||
} | ||
} | ||
|
||
public class GenericSubClass<T> : BaseClass<GenericSubClass<T>> { | ||
private string test = "test"; | ||
|
||
public string GetTest() | ||
{ | ||
return test; | ||
} | ||
} |
I had to add this null check here. Upstream the MonoGenericParamInfo is stored within the MonoGenericParam struct and is possibly why this is never null?