diff options
author | Michal Strehovsky <michals@microsoft.com> | 2018-06-22 01:21:18 +0300 |
---|---|---|
committer | Michal Strehovsky <michals@microsoft.com> | 2018-06-22 01:21:18 +0300 |
commit | 2bcf67a5f1d0a8f1b97bfa0d5e2e084a9678a0e1 (patch) | |
tree | c317cfa1a7edad1551063860f9dc083fa2618901 /src/ILCompiler.Compiler | |
parent | 5821d7e3cd349af97829cc5d2cc3b6c682a420c1 (diff) |
Allow constructed byref-like types
We were not allowing these because we couldn't properly fill out the vtable (can't really make unboxing thunks to put in the vtable). We actually need the vtable, but only because the generic dictionary lives there and reflection might touch it.
[tfs-changeset: 1705047]
Diffstat (limited to 'src/ILCompiler.Compiler')
3 files changed, 34 insertions, 8 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.BoxedTypes.cs b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.BoxedTypes.cs index 44e7ec038..71b9720fc 100644 --- a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.BoxedTypes.cs +++ b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.BoxedTypes.cs @@ -290,7 +290,17 @@ namespace ILCompiler Module = owningModule; ValueTypeRepresented = valuetype; - BoxedValue = new BoxedValueField(this); + + // Unboxing thunks for byref-like types don't make sense. Byref-like types cannot be boxed. + // We still allow these to exist in the system, because it's easier than trying to prevent + // their creation. We create them as if they existed (in lieu of e.g. pointing all of them + // to the same __unreachable method body) so that the various places that store pointers to + // them because they want to be able to extract the target instance method can use the same + // mechanism they use for everything else at runtime. + // The main difference is that the "Boxed_ValueType" version has no fields. Reference types + // cannot have byref-like fields. + if (!valuetype.IsByRefLike) + BoxedValue = new BoxedValueField(this); } public override ClassLayoutMetadata GetClassLayout() => default(ClassLayoutMetadata); @@ -332,7 +342,7 @@ namespace ILCompiler public override FieldDesc GetField(string name) { - if (name == BoxedValueFieldName) + if (name == BoxedValueFieldName && BoxedValue != null) return BoxedValue; return null; @@ -340,7 +350,10 @@ namespace ILCompiler public override IEnumerable<FieldDesc> GetFields() { - yield return BoxedValue; + if (BoxedValue != null) + return new FieldDesc[] { BoxedValue }; + + return Array.Empty<FieldDesc>(); } /// <summary> @@ -439,6 +452,15 @@ namespace ILCompiler public override MethodIL EmitIL() { + if (_owningType.BoxedValue == null) + { + // If this is the fake unboxing thunk for ByRef-like types, just make a method that throws. + return new ILStubMethodIL(this, + new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ }, + Array.Empty<LocalVariableDefinition>(), + Array.Empty<object>()); + } + // Generate the unboxing stub. This loosely corresponds to following C#: // return BoxedValue.InstanceMethod(this.m_pEEType, [rest of parameters]) @@ -507,6 +529,15 @@ namespace ILCompiler public override MethodIL EmitIL() { + if (_owningType.BoxedValue == null) + { + // If this is the fake unboxing thunk for ByRef-like types, just make a method that throws. + return new ILStubMethodIL(this, + new byte[] { (byte)ILOpcode.ldnull, (byte)ILOpcode.throw_ }, + Array.Empty<LocalVariableDefinition>(), + Array.Empty<object>()); + } + // Generate the unboxing stub. This loosely corresponds to following C#: // return BoxedValue.InstanceMethod([rest of parameters]) diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 07efe41dd..70e39e6c1 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -27,7 +27,6 @@ namespace ILCompiler.DependencyAnalysis Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any)); Debug.Assert(type == type.ConvertToCanonForm(CanonicalFormKind.Specific)); Debug.Assert(!type.IsMdArray); - Debug.Assert(!type.IsByRefLike); } public override bool StaticDependenciesAreComputed => true; diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index 6f9d6016a..23a9a47d2 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -204,10 +204,6 @@ namespace ILCompiler.DependencyAnalysis if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) return false; - // Byref-like types have interior pointers and cannot be heap allocated. - if (type.IsByRefLike) - return false; - // The global "<Module>" type can never be allocated. if (((MetadataType)type).IsModuleType) return false; |