Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>2017-05-15 23:06:44 +0300
committerGitHub <noreply@github.com>2017-05-15 23:06:44 +0300
commit9aa607be455d6d3b013fdb8caaabda600d649fde (patch)
treee07a068dd27917c4793e018a22633f31015a025d
parent692b07d0946a9df4918199d4287ce957c3e81521 (diff)
Finish support for rank 1 mdarrays (#3610)
Three parts: 1. Update casting logic to allow casting SzArray to rank 1 MdArray (but not the other way around) 2. Update MdArray rank 1 methods to be able to operate on SzArrays 3. Update array creation path to emulate the behavior where allocating rank 1 MdArray with 0 lower bounds actually gives you an SzArray Third bullet point makes this the most annoying, because we can't reliably support `newobj instance void int32[0...]::.ctor(int32)` without hitting the type loader. I was also considering adding an optional field on Rank 1 MdArrays that lets you get to the SzArray's EEType from it. It might be better. Fixes #3331.
-rw-r--r--src/Common/src/TypeSystem/Common/CastingHelper.cs8
-rw-r--r--src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs41
-rw-r--r--src/ILCompiler.TypeSystem/tests/CastingTests.cs5
-rw-r--r--src/Runtime.Base/src/System/Runtime/TypeCast.cs12
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs8
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs7
-rw-r--r--src/System.Private.CoreLib/src/System/Array.CoreRT.cs19
-rw-r--r--src/System.Private.CoreLib/src/System/MDArray.cs6
-rw-r--r--src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs30
9 files changed, 90 insertions, 46 deletions
diff --git a/src/Common/src/TypeSystem/Common/CastingHelper.cs b/src/Common/src/TypeSystem/Common/CastingHelper.cs
index ebfe39515..b7576923c 100644
--- a/src/Common/src/TypeSystem/Common/CastingHelper.cs
+++ b/src/Common/src/TypeSystem/Common/CastingHelper.cs
@@ -78,6 +78,14 @@ namespace Internal.TypeSystem
// Casting array to something else (between SzArray and Array, for example)?
if (thisType.Category != otherType.Category)
{
+ // An SzArray is castable to MdArray rank 1. We follow the same casting rules as SzArray to SzArray.
+ if (thisType.Category == TypeFlags.SzArray
+ && otherType.Category == TypeFlags.Array
+ && ((ArrayType)otherType).Rank == 1)
+ {
+ return thisType.CanCastParamTo(((ArrayType)otherType).ParameterType, protect);
+ }
+
return false;
}
diff --git a/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs b/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs
index c9b4c6ecb..4e8e7a171 100644
--- a/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs
+++ b/src/Common/src/TypeSystem/IL/Stubs/ArrayMethodILEmitter.cs
@@ -142,6 +142,44 @@ namespace Internal.IL.Stubs
}
}
+ // Methods on Rank 1 MdArray need to be able to handle `this` that is an SzArray
+ // because SzArray is castable to Rank 1 MdArray (but not the other way around).
+
+ ILCodeLabel rangeCheckDoneLabel = null;
+ if (_rank == 1)
+ {
+ TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object);
+ TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr");
+ ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType);
+
+ codeStream.EmitLdArg(0);
+ codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null)));
+ codeStream.EmitStLoc(thisEEType);
+ codeStream.EmitLdLoca(thisEEType);
+ codeStream.Emit(ILOpcode.call,
+ _emitter.NewToken(eetypePtrType.GetKnownMethod("get_IsSzArray", null)));
+
+ ILCodeLabel notSzArrayLabel = _emitter.NewCodeLabel();
+ codeStream.Emit(ILOpcode.brfalse, notSzArrayLabel);
+
+ // We have an SzArray - do the bounds check differently
+ EmitLoadInteriorAddress(codeStream, pointerSize);
+ codeStream.Emit(ILOpcode.dup);
+ codeStream.Emit(ILOpcode.ldind_i4);
+ codeStream.EmitLdArg(argStartOffset);
+ codeStream.EmitStLoc(totalLocalNum);
+ codeStream.EmitLdLoc(totalLocalNum);
+ codeStream.Emit(ILOpcode.ble_un, rangeExceptionLabel);
+
+ codeStream.EmitLdc(pointerSize);
+ codeStream.Emit(ILOpcode.add);
+
+ rangeCheckDoneLabel = _emitter.NewCodeLabel();
+ codeStream.Emit(ILOpcode.br, rangeCheckDoneLabel);
+
+ codeStream.EmitLabel(notSzArrayLabel);
+ }
+
for (int i = 0; i < _rank; i++)
{
// The first two fields are EEType pointer and total length. Lengths for each dimension follows.
@@ -174,6 +212,9 @@ namespace Internal.IL.Stubs
int firstElementOffset = (2 * pointerSize + 2 * _rank * sizeof(int));
EmitLoadInteriorAddress(codeStream, firstElementOffset);
+ if (rangeCheckDoneLabel != null)
+ codeStream.EmitLabel(rangeCheckDoneLabel);
+
codeStream.EmitLdLoc(totalLocalNum);
int elementSize = _elementType.GetElementSize().AsInt;
diff --git a/src/ILCompiler.TypeSystem/tests/CastingTests.cs b/src/ILCompiler.TypeSystem/tests/CastingTests.cs
index b2771234c..573bc1822 100644
--- a/src/ILCompiler.TypeSystem/tests/CastingTests.cs
+++ b/src/ILCompiler.TypeSystem/tests/CastingTests.cs
@@ -73,6 +73,7 @@ namespace TypeSystemTests
TypeDesc shortBasedEnumType = _testModule.GetType("Casting", "ShortBasedEnum");
Assert.True(intType.MakeArrayType().CanCastTo(uintType.MakeArrayType()));
+ Assert.True(intType.MakeArrayType().CanCastTo(uintType.MakeArrayType(1)));
Assert.False(intType.CanCastTo(uintType));
Assert.True(byteType.MakeArrayType().CanCastTo(sbyteType.MakeArrayType()));
@@ -121,7 +122,9 @@ namespace TypeSystemTests
TypeDesc stringSzArrayType = stringType.MakeArrayType();
TypeDesc objectSzArrayType = objectType.MakeArrayType();
- Assert.False(intSzArrayType.CanCastTo(intArray1Type));
+ Assert.True(intSzArrayType.CanCastTo(intArray1Type));
+ Assert.False(intArray1Type.CanCastTo(intSzArrayType));
+
Assert.False(intArray1Type.CanCastTo(intArray2Type));
Assert.True(intSzArrayType.CanCastTo(arrayType));
diff --git a/src/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/Runtime.Base/src/System/Runtime/TypeCast.cs
index d7a549a4b..62dea8448 100644
--- a/src/Runtime.Base/src/System/Runtime/TypeCast.cs
+++ b/src/Runtime.Base/src/System/Runtime/TypeCast.cs
@@ -219,8 +219,16 @@ namespace System.Runtime
// compare the array types structurally
- if (pObjType->ParameterizedTypeShape == pTargetType->ParameterizedTypeShape &&
- CastCache.AreTypesAssignableInternal(pObjType->RelatedParameterType, pTargetType->RelatedParameterType,
+ if (pObjType->ParameterizedTypeShape != pTargetType->ParameterizedTypeShape)
+ {
+ // If the shapes are different, there's one more case to check for: Casting SzArray to MdArray rank 1.
+ if (!pObjType->IsSzArray || pTargetType->ArrayRank != 1)
+ {
+ return null;
+ }
+ }
+
+ if (CastCache.AreTypesAssignableInternal(pObjType->RelatedParameterType, pTargetType->RelatedParameterType,
AssignmentVariation.AllowSizeEquivalence))
{
return obj;
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
index 5e29b5907..67c6378c8 100644
--- a/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
@@ -147,6 +147,14 @@ namespace Internal.Runtime.Augments
}
}
+ if (lengths.Length == 1)
+ {
+ // We just checked above that all lower bounds are zero. In that case, we should actually allocate
+ // a new SzArray instead.
+ RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(typeHandleForArrayType.ToEETypePtr().ArrayElementType);
+ return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), lengths[0]);
+ }
+
// Create a local copy of the lenghts that cannot be motified by the caller
int* pLengths = stackalloc int[lengths.Length];
for (int i = 0; i < lengths.Length; i++)
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs b/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs
index 1f76a8b00..8b27d139f 100644
--- a/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs
@@ -41,6 +41,13 @@ namespace Internal.Runtime.CompilerHelpers
return ret;
}
+ else if (nDimensions == 1)
+ {
+ // Multidimensional array of rank 1 with 0 lower bounds gets actually allocated
+ // as an SzArray. SzArray is castable to MdArray rank 1.
+ RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(eeType.ArrayElementType);
+ return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), pDimensions[0]);
+ }
else
{
// Multidimensional arrays have two ctors, one with and one without lower bounds
diff --git a/src/System.Private.CoreLib/src/System/Array.CoreRT.cs b/src/System.Private.CoreLib/src/System/Array.CoreRT.cs
index 31168971e..aaa4af523 100644
--- a/src/System.Private.CoreLib/src/System/Array.CoreRT.cs
+++ b/src/System.Private.CoreLib/src/System/Array.CoreRT.cs
@@ -181,15 +181,7 @@ namespace System
elementType = elementType.UnderlyingSystemType;
- if (lengths.Length == 1 && lowerBounds[0] == 0)
- {
- int length = lengths[0];
- return CreateSzArray(elementType, length);
- }
- else
- {
- return CreateMultiDimArray(elementType, lengths, lowerBounds);
- }
+ return CreateMultiDimArray(elementType, lengths, lowerBounds);
}
private static Array CreateSzArray(Type elementType, int length)
@@ -990,6 +982,13 @@ namespace System
Debug.Assert(eeType.IsArray && !eeType.IsSzArray);
Debug.Assert(rank == eeType.ArrayRank);
+ // Code below assumes 0 lower bounds. MdArray of rank 1 with zero lower bounds should never be allocated.
+ // The runtime always allocates an SzArray for those:
+ // * newobj instance void int32[0...]::.ctor(int32)" actually gives you int[]
+ // * int[] is castable to int[*] to make it mostly transparent
+ // The callers need to check for this.
+ Debug.Assert(rank != 1);
+
ulong totalLength = 1;
bool maxArrayDimensionLengthOverflow = false;
@@ -1679,11 +1678,9 @@ namespace System
}
}
-#if CORERT
public class MDArray
{
public const int MinRank = 1;
public const int MaxRank = 32;
}
-#endif
}
diff --git a/src/System.Private.CoreLib/src/System/MDArray.cs b/src/System.Private.CoreLib/src/System/MDArray.cs
index 5614e9b1f..a7256bdc7 100644
--- a/src/System.Private.CoreLib/src/System/MDArray.cs
+++ b/src/System.Private.CoreLib/src/System/MDArray.cs
@@ -24,12 +24,6 @@ namespace System
// The desktop CLR supports arrays of up to 32 dimensions so that provides
// an upper limit on how much this needs to be built out.
- public class MDArray
- {
- public const int MinRank = 2;
- public const int MaxRank = 32;
- }
-
[StructLayout(LayoutKind.Sequential)]
public class MDArrayRank2<T>
{
diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs
index 252e1a05e..feb436d87 100644
--- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs
+++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs
@@ -65,34 +65,12 @@ namespace System.Reflection.Runtime.TypeInfos
InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException,
delegate (Object _this, Object[] args)
{
- if (rank == 1)
- {
- // Legacy: This seems really wrong in the rank1-multidim case (as it's a case of a synthetic constructor that's declared on T[*] returning an instance of T[])
- // This is how the desktop behaves, however.
-
- int count = (int)(args[0]);
-
- RuntimeTypeInfo vectorType;
- if (multiDim)
- {
- vectorType = arrayType.InternalRuntimeElementType.GetArrayType();
- }
- else
- {
- vectorType = arrayType;
- }
-
- return ReflectionCoreExecution.ExecutionEnvironment.NewArray(vectorType.TypeHandle, count);
- }
- else
+ int[] lengths = new int[rank];
+ for (int i = 0; i < rank; i++)
{
- int[] lengths = new int[rank];
- for (int i = 0; i < rank; i++)
- {
- lengths[i] = (int)(args[i]);
- }
- return ReflectionCoreExecution.ExecutionEnvironment.NewMultiDimArray(arrayType.TypeHandle, lengths, null);
+ lengths[i] = (int)(args[i]);
}
+ return ReflectionCoreExecution.ExecutionEnvironment.NewMultiDimArray(arrayType.TypeHandle, lengths, null);
}
);
}