Fix handling of the generic byreflike constraint (#81684)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Wed, 8 Feb 2023 06:34:39 +0000 (15:34 +0900)
committerGitHub <noreply@github.com>
Wed, 8 Feb 2023 06:34:39 +0000 (15:34 +0900)
Some support for NativeAOT was written in #67783 but the test didn't actually pass because of these missing pieces.

src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Validation.cs
src/coreclr/tools/Common/TypeSystem/Ecma/EcmaGenericParameter.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingServiceProvider.cs
src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
src/tests/nativeaot/SmokeTests/DynamicGenerics/rd.xml

index dcbccd6..8112602 100644 (file)
@@ -149,8 +149,7 @@ namespace ILCompiler
                     if (typeArg.IsByRef
                         || typeArg.IsPointer
                         || typeArg.IsFunctionPointer
-                        || typeArg.IsVoid
-                        || typeArg.IsByRefLike)
+                        || typeArg.IsVoid)
                     {
                         ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
                     }
index 0ecf1c4..ee59976 100644 (file)
@@ -103,7 +103,8 @@ namespace Internal.TypeSystem.Ecma
             {
                 Debug.Assert((int)GenericConstraints.DefaultConstructorConstraint == (int)GenericParameterAttributes.DefaultConstructorConstraint);
                 GenericParameter parameter = _module.MetadataReader.GetGenericParameter(_handle);
-                return (GenericConstraints)(parameter.Attributes & GenericParameterAttributes.SpecialConstraintMask);
+                const GenericParameterAttributes mask = GenericParameterAttributes.SpecialConstraintMask | (GenericParameterAttributes)GenericConstraints.AcceptByRefLike;
+                return (GenericConstraints)(parameter.Attributes & mask);
             }
         }
 
index 443c463..12a590d 100644 (file)
@@ -43,19 +43,26 @@ namespace ILCompiler
 
         public void AddReflectionRoot(TypeDesc type, string reason)
         {
+            _factory.TypeSystemContext.EnsureLoadableType(type);
             _rootAdder(_factory.ReflectedType(type), reason);
         }
 
         public void AddReflectionRoot(MethodDesc method, string reason)
         {
             if (!_factory.MetadataManager.IsReflectionBlocked(method))
+            {
+                _factory.TypeSystemContext.EnsureLoadableMethod(method);
                 _rootAdder(_factory.ReflectedMethod(method), reason);
+            }
         }
 
         public void AddReflectionRoot(FieldDesc field, string reason)
         {
             if (!_factory.MetadataManager.IsReflectionBlocked(field))
+            {
+                _factory.TypeSystemContext.EnsureLoadableType(field.OwningType);
                 _rootAdder(_factory.ReflectedField(field), reason);
+            }
         }
 
         public void AddCompilationRoot(object o, string reason)
index 7c6f93b..498d9eb 100644 (file)
@@ -1098,7 +1098,49 @@ namespace Internal.IL
 
         private void ImportBox(int token)
         {
-            AddBoxingDependencies((TypeDesc)_methodIL.GetObject(token), "Box");
+            var type = (TypeDesc)_methodIL.GetObject(token);
+
+            // There are some sequences of box with ByRefLike types that are allowed
+            // per the extension to the ECMA-335 specification.
+            // Everything else is invalid.
+            if (!type.IsRuntimeDeterminedType && type.IsByRefLike)
+            {
+                ILReader reader = new ILReader(_ilBytes, _currentOffset);
+                ILOpcode nextOpcode = reader.ReadILOpcode();
+
+                // box ; br_true/false
+                if (nextOpcode is ILOpcode.brtrue or ILOpcode.brtrue_s or ILOpcode.brfalse or ILOpcode.brfalse_s)
+                    return;
+
+                if (nextOpcode is ILOpcode.unbox_any or ILOpcode.isinst)
+                {
+                    var type2 = (TypeDesc)_methodIL.GetObject(reader.ReadILToken());
+                    if (type == type2)
+                    {
+                        // box ; unbox_any with same token
+                        if (nextOpcode == ILOpcode.unbox_any)
+                            return;
+
+                        nextOpcode = reader.ReadILOpcode();
+
+                        // box ; isinst ; br_true/false
+                        if (nextOpcode is ILOpcode.brtrue or ILOpcode.brtrue_s or ILOpcode.brfalse or ILOpcode.brfalse_s)
+                            return;
+
+                        // box ; isinst ; unbox_any
+                        if (nextOpcode == ILOpcode.unbox_any)
+                        {
+                            type2 = (TypeDesc)_methodIL.GetObject(reader.ReadILToken());
+                            if (type2 == type)
+                                return;
+                        }
+                    }
+                }
+
+                ThrowHelper.ThrowInvalidProgramException();
+            }
+
+            AddBoxingDependencies(type, "Box");
         }
 
         private void AddBoxingDependencies(TypeDesc type, string reason)
index 6f47355..f656b4e 100644 (file)
       <Type Name="InterfacesTests+UseFrobber`2[InterfacesTests+FrobtasticFrobberStruct,[System.String, netstandard]]" Dynamic="Required All" />
 
       <Type Name="ConstraintsTests+TypeWithClassConstraint`1[[System.Object, netstandard]]" Dynamic="Required All"/>
-      <Type Name="ConstraintsTests+TypeRequiringIFoo`1[[System.Object, netstandard]]" Dynamic="Required All"/>
+      <Type Name="ConstraintsTests+TypeRequiringIFoo`1[[ConstraintsTests+IFoo]]" Dynamic="Required All"/>
       <Type Name="ConstraintsTests+TypeWithPrivateCtor" Dynamic="Required All"/>
       <Type Name="ConstraintsTests+TypeWithNewConstraint`1[[System.Object, netstandard]]" Dynamic="Required All"/>
       <Type Name="ConstraintsTests+TypeWithSelfReferenceConstraint`2[[System.Object, netstandard],[System.Object, netstandard]]" Dynamic="Required All"/>