Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port type system tests from CoreRT repo #38128

Merged
merged 4 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eng/Subsets.props
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
$(CoreClrProjectRoot)src\tools\dotnet-pgo\dotnet-pgo.csproj;
$(CoreClrProjectRoot)src\tools\r2rtest\R2RTest.csproj" Category="clr" BuildInParallel="true" />
<ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\aot\crossgen2\crossgen2.csproj" Category="clr" />
<ProjectToBuild Include="$(CoreClrProjectRoot)src\tools\aot\ILCompiler.TypeSystem.ReadyToRun.Tests\ILCompiler.TypeSystem.ReadyToRun.Tests.csproj" Test="true" Category="clr" />
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>

<ItemGroup Condition="$(_subset.Contains('+clr.packages+'))">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Internal.TypeSystem
{
public static class ConstructedTypeRewritingHelpers
{
/// <summary>
/// Determine if the construction of a type contains one of a given set of types. This is a deep
/// scan. For instance, given type MyType&lt;SomeGeneric&lt;int[]&gt;&gt;, and a set of typesToFind
/// that includes int, this function will return true. Does not detect the open generics that may be
/// instantiated over in this type. IsConstructedOverType would return false if only passed MyType,
/// or SomeGeneric for the above examplt.
/// </summary>
/// <param name="type">type to examine</param>
/// <param name="typesToFind">types to search for in the construction of type</param>
/// <returns>true if a type in typesToFind is found</returns>
public static bool IsConstructedOverType(this TypeDesc type, TypeDesc[] typesToFind)
{
int directDiscoveryIndex = Array.IndexOf(typesToFind, type);

if (directDiscoveryIndex != -1)
return true;

if (type.HasInstantiation)
{
for (int instantiationIndex = 0; instantiationIndex < type.Instantiation.Length; instantiationIndex++)
{
if (type.Instantiation[instantiationIndex].IsConstructedOverType(typesToFind))
{
return true;
}
}
}
else if (type.IsParameterizedType)
{
ParameterizedType parameterizedType = (ParameterizedType)type;
return parameterizedType.ParameterType.IsConstructedOverType(typesToFind);
}
else if (type.IsFunctionPointer)
{
MethodSignature functionPointerSignature = ((FunctionPointerType)type).Signature;
if (functionPointerSignature.ReturnType.IsConstructedOverType(typesToFind))
return true;

for (int paramIndex = 0; paramIndex < functionPointerSignature.Length; paramIndex++)
{
if (functionPointerSignature[paramIndex].IsConstructedOverType(typesToFind))
return true;
}
}

return false;
}

/// <summary>
/// Replace some of the types in a type's construction with a new set of types. This function does not
/// support any situation where there is an instantiated generic that is not represented by an
/// InstantiatedType. Does not replace the open generics that may be instantiated over in this type.
///
/// For instance, Given MyType&lt;object, int[]&gt;,
/// an array of types to replace such as {int,object}, and
/// an array of replacement types such as {string,__Canon}.
/// The result shall be MyType&lt;__Canon, string[]&gt;
///
/// This function cannot be used to replace MyType in the above example.
/// </summary>
public static TypeDesc ReplaceTypesInConstructionOfType(this TypeDesc type, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
{
int directReplacementIndex = Array.IndexOf(typesToReplace, type);

if (directReplacementIndex != -1)
return replacementTypes[directReplacementIndex];

if (type.HasInstantiation)
{
TypeDesc[] newInstantiation = null;
Debug.Assert(type is InstantiatedType);
int instantiationIndex = 0;
for (; instantiationIndex < type.Instantiation.Length; instantiationIndex++)
{
TypeDesc oldType = type.Instantiation[instantiationIndex];
TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
if ((oldType != newType) || (newInstantiation != null))
{
if (newInstantiation == null)
{
newInstantiation = new TypeDesc[type.Instantiation.Length];
for (int i = 0; i < instantiationIndex; i++)
newInstantiation[i] = type.Instantiation[i];
}
newInstantiation[instantiationIndex] = newType;
}
}
if (newInstantiation != null)
return type.Context.GetInstantiatedType((MetadataType)type.GetTypeDefinition(), new Instantiation(newInstantiation));
}
else if (type.IsParameterizedType)
{
ParameterizedType parameterizedType = (ParameterizedType)type;
TypeDesc oldParameter = parameterizedType.ParameterType;
TypeDesc newParameter = oldParameter.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
if (oldParameter != newParameter)
{
if (type.IsArray)
{
ArrayType arrayType = (ArrayType)type;
if (arrayType.IsSzArray)
return type.Context.GetArrayType(newParameter);
else
return type.Context.GetArrayType(newParameter, arrayType.Rank);
}
else if (type.IsPointer)
{
return type.Context.GetPointerType(newParameter);
}
else if (type.IsByRef)
{
return type.Context.GetByRefType(newParameter);
}
Debug.Fail("Unknown form of type");
}
}
else if (type.IsFunctionPointer)
{
MethodSignature oldSig = ((FunctionPointerType)type).Signature;
MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(oldSig);
sigBuilder.ReturnType = oldSig.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
for (int paramIndex = 0; paramIndex < oldSig.Length; paramIndex++)
sigBuilder[paramIndex] = oldSig[paramIndex].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);

MethodSignature newSig = sigBuilder.ToSignature();
if (newSig != oldSig)
return type.Context.GetFunctionPointerType(newSig);
}

return type;
}

/// <summary>
/// Replace some of the types in a method's construction with a new set of types.
/// Does not replace the open generics that may be instantiated over in this type.
///
/// For instance, Given MyType&lt;object, int[]&gt;.Function&lt;short&gt;(),
/// an array of types to replace such as {int,short}, and
/// an array of replacement types such as {string,char}.
/// The result shall be MyType&lt;object, string[]&gt;.Function&lt;char&gt;
///
/// This function cannot be used to replace MyType in the above example.
/// </summary>
public static MethodDesc ReplaceTypesInConstructionOfMethod(this MethodDesc method, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
{
TypeDesc newOwningType = method.OwningType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
MethodDesc methodOnOwningType = null;
bool owningTypeChanged = false;
if (newOwningType == method.OwningType)
{
methodOnOwningType = method.GetMethodDefinition();
}
else
{
methodOnOwningType = TypeSystemHelpers.FindMethodOnExactTypeWithMatchingTypicalMethod(newOwningType, method);
owningTypeChanged = true;
}

MethodDesc result;
if (!method.HasInstantiation)
{
result = methodOnOwningType;
}
else
{
Debug.Assert(method is InstantiatedMethod);

TypeDesc[] newInstantiation = null;
int instantiationIndex = 0;
for (; instantiationIndex < method.Instantiation.Length; instantiationIndex++)
{
TypeDesc oldType = method.Instantiation[instantiationIndex];
TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
if ((oldType != newType) || (newInstantiation != null))
{
if (newInstantiation == null)
{
newInstantiation = new TypeDesc[method.Instantiation.Length];
for (int i = 0; i < instantiationIndex; i++)
newInstantiation[i] = method.Instantiation[i];
}
newInstantiation[instantiationIndex] = newType;
}
}

if (newInstantiation != null)
result = method.Context.GetInstantiatedMethod(methodOnOwningType, new Instantiation(newInstantiation));
else if (owningTypeChanged)
result = method.Context.GetInstantiatedMethod(methodOnOwningType, method.Instantiation);
else
result = method;
}

return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Internal.TypeSystem.Ecma;
using Internal.TypeSystem;

using Xunit;

namespace TypeSystemTests
{
public class ArchitectureSpecificFieldLayoutTests
{
TestTypeSystemContext _contextX86;
ModuleDesc _testModuleX86;
TestTypeSystemContext _contextX64;
ModuleDesc _testModuleX64;
TestTypeSystemContext _contextARM;
ModuleDesc _testModuleARM;

public ArchitectureSpecificFieldLayoutTests()
{
_contextX64 = new TestTypeSystemContext(TargetArchitecture.X64);
var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly");
_contextX64.SetSystemModule(systemModuleX64);

_testModuleX64 = systemModuleX64;

_contextARM = new TestTypeSystemContext(TargetArchitecture.ARM);
var systemModuleARM = _contextARM.CreateModuleForSimpleName("CoreTestAssembly");
_contextARM.SetSystemModule(systemModuleARM);

_testModuleARM = systemModuleARM;

_contextX86 = new TestTypeSystemContext(TargetArchitecture.X86);
var systemModuleX86 = _contextX86.CreateModuleForSimpleName("CoreTestAssembly");
_contextX86.SetSystemModule(systemModuleX86);

_testModuleX86 = systemModuleX86;
}

[Fact]
public void TestInstanceLayoutDoubleBool()
{
MetadataType tX64 = _testModuleX64.GetType("Sequential", "ClassDoubleBool");
MetadataType tX86 = _testModuleX86.GetType("Sequential", "ClassDoubleBool");
MetadataType tARM = _testModuleARM.GetType("Sequential", "ClassDoubleBool");

Assert.Equal(0x8, tX64.InstanceByteAlignment.AsInt);
Assert.Equal(0x8, tARM.InstanceByteAlignment.AsInt);
Assert.Equal(0x4, tX86.InstanceByteAlignment.AsInt);

Assert.Equal(0x11, tX64.InstanceByteCountUnaligned.AsInt);
Assert.Equal(0x11, tARM.InstanceByteCountUnaligned.AsInt);
Assert.Equal(0x11, tX86.InstanceByteCountUnaligned.AsInt);

Assert.Equal(0x18, tX64.InstanceByteCount.AsInt);
Assert.Equal(0x18, tARM.InstanceByteCount.AsInt);
Assert.Equal(0x14, tX86.InstanceByteCount.AsInt);
}

[Fact]
public void TestInstanceLayoutBoolDoubleBool()
{
MetadataType tX64 = _testModuleX64.GetType("Sequential", "ClassBoolDoubleBool");
MetadataType tX86 = _testModuleX86.GetType("Sequential", "ClassBoolDoubleBool");
MetadataType tARM = _testModuleARM.GetType("Sequential", "ClassBoolDoubleBool");

Assert.Equal(0x8, tX64.InstanceByteAlignment.AsInt);
Assert.Equal(0x8, tARM.InstanceByteAlignment.AsInt);
Assert.Equal(0x4, tX86.InstanceByteAlignment.AsInt);

Assert.Equal(0x19, tX64.InstanceByteCountUnaligned.AsInt);
Assert.Equal(0x11, tARM.InstanceByteCountUnaligned.AsInt);
Assert.Equal(0x11, tX86.InstanceByteCountUnaligned.AsInt);

Assert.Equal(0x20, tX64.InstanceByteCount.AsInt);
Assert.Equal(0x18, tARM.InstanceByteCount.AsInt);
Assert.Equal(0x14, tX86.InstanceByteCount.AsInt);
}
}
}
Loading