diff options
-rw-r--r-- | src/jit/compiler.h | 3 | ||||
-rwxr-xr-x | src/jit/ee_il_dll.cpp | 30 | ||||
-rw-r--r--[-rwxr-xr-x] | src/jit/importer.cpp | 267 | ||||
-rw-r--r-- | src/jit/instr.cpp | 3 | ||||
-rwxr-xr-x | src/jit/lower.cpp | 3 | ||||
-rw-r--r-- | tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj | 23 | ||||
-rw-r--r-- | tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj | 22 | ||||
-rw-r--r-- | tests/src/JIT/Methodical/Arrays/misc/initializearray.il | 640 |
8 files changed, 934 insertions, 57 deletions
diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 2a0d4eed72..81a2bd00cd 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -6397,7 +6397,10 @@ public : CORINFO_EE_INFO * eeGetEEInfo(); + // Gets the offset of a SDArray's first element unsigned eeGetArrayDataOffset(var_types type); + // Gets the offset of a MDArray's first element + unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank); GenTreePtr eeGetPInvokeCookie(CORINFO_SIG_INFO *szMetaSig); diff --git a/src/jit/ee_il_dll.cpp b/src/jit/ee_il_dll.cpp index 787c311368..f51e4521e3 100755 --- a/src/jit/ee_il_dll.cpp +++ b/src/jit/ee_il_dll.cpp @@ -494,7 +494,14 @@ GenTreePtr Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO *szMetaSig) return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL); } -/*****************************************************************************/ +//------------------------------------------------------------------------ +// eeGetArrayDataOffset: Gets the offset of a SDArray's first element +// +// Arguments: +// type - The array element type +// +// Return Value: +// The offset to the first array element. unsigned Compiler::eeGetArrayDataOffset(var_types type) { @@ -502,6 +509,27 @@ unsigned Compiler::eeGetArrayDataOffset(var_types type) : offsetof(CORINFO_Array, u1Elems); } +//------------------------------------------------------------------------ +// eeGetMDArrayDataOffset: Gets the offset of a MDArray's first element +// +// Arguments: +// type - The array element type +// rank - The array rank +// +// Return Value: +// The offset to the first array element. +// +// Assumptions: +// The rank should be greater than 0. + +unsigned Compiler::eeGetMDArrayDataOffset(var_types type, unsigned rank) +{ + assert(rank > 0); + // Note that below we're specifically using genTypeSize(TYP_INT) because array + // indices are not native int. + return eeGetArrayDataOffset(type) + 2 * genTypeSize(TYP_INT) * rank; +} + /*****************************************************************************/ void Compiler::eeGetStmtOffsets() diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 5a3bcf852b..4ca25255b5 100755..100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -2666,23 +2666,30 @@ BOOL Compiler::impLocAllocOnStack() return(FALSE); } -/*****************************************************************************/ +//------------------------------------------------------------------------ +// impInitializeArrayIntrinsic: Attempts to replace a call to InitializeArray +// with a GT_COPYBLK node. +// +// Arguments: +// sig - The InitializeArray signature. +// +// Return Value: +// A pointer to the newly created GT_COPYBLK node if the replacement succeeds or +// nullptr otherwise. +// +// Notes: +// The function recognizes the following IL pattern: +// ldc <length> or a list of ldc <lower bound>/<length> +// newarr or newobj +// dup +// ldtoken <field handle> +// call InitializeArray +// The lower bounds need not be constant except when the array rank is 1. +// The function recognizes all kinds of arrays thus enabling a small runtime +// such as CoreRT to skip providing an implementation for InitializeArray. GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) { - // - // The IL for array initialization looks like the following: - // - // ldc <number of elements> - // newarr - // dup - // ldtoken <field handle> - // call InitializeArray - // - // We will try to implement it using a GT_COPYBLK node to avoid the - // runtime call to the helper. - // - assert(sig->numArgs == 2); GenTreePtr fieldTokenNode = impStackTop(0).val; @@ -2767,6 +2774,9 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) // // Verify that it is one of the new array helpers. // + + bool isMDArray = false; + if (newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) && newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) && newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_VC) && @@ -2776,57 +2786,195 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) #endif ) { - // - // In order to simplify the code, we won't support the multi-dim - // case. Instead we simply return NULL, and the caller will insert - // a run-time call to the helper. Note that we can't assert - // failure here, because this is a valid case. - // + if (newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEW_MDARR_NONVARARG)) + return nullptr; - return NULL; + isMDArray = true; } + CORINFO_CLASS_HANDLE arrayClsHnd = (CORINFO_CLASS_HANDLE) newArrayCall->gtCall.compileTimeHelperArgumentHandle; // - // Make sure there are exactly two arguments: the array class and - // the number of elements. + // Make sure we found a compile time handle to the array // - GenTreePtr arrayLengthNode; + if (!arrayClsHnd) + return nullptr; + + unsigned rank; + S_UINT32 numElements; - GenTreeArgList* args = newArrayCall->gtCall.gtCallArgs; -#ifdef FEATURE_READYTORUN_COMPILER - if (newArrayCall->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1)) + if (isMDArray) { - // Array length is 1st argument for readytorun helper - arrayLengthNode = args->Current(); + rank = info.compCompHnd->getArrayRank(arrayClsHnd); + + if (rank == 0) + return nullptr; + + GenTreeArgList* tokenArg = newArrayCall->gtCall.gtCallArgs; + assert(tokenArg != nullptr); + GenTreeArgList* numArgsArg = tokenArg->Rest(); + assert(numArgsArg != nullptr); + GenTreeArgList* argsArg = numArgsArg->Rest(); + assert(argsArg != nullptr); + + // + // The number of arguments should be a constant between 1 and 64. The rank can't be 0 + // so at least one length must be present and the rank can't exceed 32 so there can + // be at most 64 arguments - 32 lengths and 32 lower bounds. + // + + if ((!numArgsArg->Current()->IsCnsIntOrI()) || + (numArgsArg->Current()->AsIntCon()->IconValue() < 1) || + (numArgsArg->Current()->AsIntCon()->IconValue() > 64)) + { + return nullptr; + } + + unsigned numArgs = static_cast<unsigned>(numArgsArg->Current()->AsIntCon()->IconValue()); + bool lowerBoundsSpecified; + + if (numArgs == rank * 2) + { + lowerBoundsSpecified = true; + } + else if (numArgs == rank) + { + lowerBoundsSpecified = false; + + // + // If the rank is 1 and a lower bound isn't specified then the runtime creates + // a SDArray. Note that even if a lower bound is specified it can be 0 and then + // we get a SDArray as well, see the for loop below. + // + + if (rank == 1) + isMDArray = false; + } + else + { + return nullptr; + } + + // + // The rank is known to be at least 1 so we can start with numElements being 1 + // to avoid the need to special case the first dimension. + // + + numElements = S_UINT32(1); + + struct Match + { + static bool IsArgsFieldInit(GenTree* tree, unsigned index, unsigned lvaNewObjArrayArgs) + { + return (tree->OperGet() == GT_ASG) && + IsArgsFieldIndir(tree->gtGetOp1(), index, lvaNewObjArrayArgs) && + IsArgsAddr(tree->gtGetOp1()->gtGetOp1()->gtGetOp1(), lvaNewObjArrayArgs); + } + + static bool IsArgsFieldIndir(GenTree* tree, unsigned index, unsigned lvaNewObjArrayArgs) + { + return (tree->OperGet() == GT_IND) && + (tree->gtGetOp1()->OperGet() == GT_ADD) && + (tree->gtGetOp1()->gtGetOp2()->IsIntegralConst(sizeof(INT32) * index)) && + IsArgsAddr(tree->gtGetOp1()->gtGetOp1(), lvaNewObjArrayArgs); + } + + static bool IsArgsAddr(GenTree* tree, unsigned lvaNewObjArrayArgs) + { + return (tree->OperGet() == GT_ADDR) && + (tree->gtGetOp1()->OperGet() == GT_LCL_VAR) && + (tree->gtGetOp1()->AsLclVar()->GetLclNum() == lvaNewObjArrayArgs); + } + + static bool IsComma(GenTree* tree) + { + return (tree != nullptr) && + (tree->OperGet() == GT_COMMA); + } + }; + + int argIndex = 0; + GenTree* comma; + + for (comma = argsArg->Current(); Match::IsComma(comma); comma = comma->gtGetOp2()) + { + if (lowerBoundsSpecified) + { + // + // In general lower bounds can be ignored because they're not needed to + // calculate the total number of elements. But for single dimensional arrays + // we need to know if the lower bound is 0 because in this case the runtime + // creates a SDArray and this affects the way the array data offset is calculated. + // + + if (rank == 1) + { + GenTree* lowerBoundAssign = comma->gtGetOp1(); + assert(Match::IsArgsFieldInit(lowerBoundAssign, argIndex, lvaNewObjArrayArgs)); + GenTree* lowerBoundNode = lowerBoundAssign->gtGetOp2(); + + if (lowerBoundNode->IsIntegralConst(0)) + isMDArray = false; + } + + comma = comma->gtGetOp2(); + argIndex++; + } + + GenTree* lengthNodeAssign = comma->gtGetOp1(); + assert(Match::IsArgsFieldInit(lengthNodeAssign, argIndex, lvaNewObjArrayArgs)); + GenTree* lengthNode = lengthNodeAssign->gtGetOp2(); + + if (!lengthNode->IsCnsIntOrI()) + return nullptr; + + numElements *= S_SIZE_T(lengthNode->AsIntCon()->IconValue()); + argIndex++; + } + + assert((comma != nullptr) && Match::IsArgsAddr(comma, lvaNewObjArrayArgs)); + + if (argIndex != numArgs) + return nullptr; } else -#endif { - // Array length is 2nd argument for regular helper - arrayLengthNode = args->Rest()->Current(); - } + // + // Make sure there are exactly two arguments: the array class and + // the number of elements. + // - // - // Make sure that the number of elements look valid. - // - if (arrayLengthNode->gtOper != GT_CNS_INT) - { - return NULL; - } + GenTreePtr arrayLengthNode; - S_UINT32 numElements = S_SIZE_T(arrayLengthNode->gtIntCon.gtIconVal); - CORINFO_CLASS_HANDLE arrayClsHnd = (CORINFO_CLASS_HANDLE) newArrayCall->gtCall.compileTimeHelperArgumentHandle; + GenTreeArgList* args = newArrayCall->gtCall.gtCallArgs; +#ifdef FEATURE_READYTORUN_COMPILER + if (newArrayCall->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1)) + { + // Array length is 1st argument for readytorun helper + arrayLengthNode = args->Current(); + } + else +#endif + { + // Array length is 2nd argument for regular helper + arrayLengthNode = args->Rest()->Current(); + } - // - // Make sure we found a compile time handle to the array - // + // + // Make sure that the number of elements look valid. + // + if (arrayLengthNode->gtOper != GT_CNS_INT) + { + return NULL; + } - if (!arrayClsHnd || - !info.compCompHnd->isSDArray(arrayClsHnd)) - { - return NULL; + numElements = S_SIZE_T(arrayLengthNode->gtIntCon.gtIconVal); + + if (!info.compCompHnd->isSDArray(arrayClsHnd)) + { + return NULL; + } } CORINFO_CLASS_HANDLE elemClsHnd; @@ -2868,10 +3016,24 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) impPopStack(); impPopStack(); - GenTreePtr dst = gtNewOperNode(GT_ADDR, - TYP_BYREF, - gtNewIndexRef(elementType, arrayLocalNode, gtNewIconNode(0))); + GenTreePtr dst; + if (isMDArray) + { + unsigned dataOffset = eeGetMDArrayDataOffset(elementType, rank); + + dst = gtNewOperNode(GT_ADD, + TYP_BYREF, + arrayLocalNode, + gtNewIconNode(dataOffset, TYP_I_IMPL)); + } + else + { + dst = gtNewOperNode(GT_ADDR, + TYP_BYREF, + gtNewIndexRef(elementType, arrayLocalNode, gtNewIconNode(0))); + } + return gtNewBlkOpNode(GT_COPYBLK, dst, // dst gtNewIconHandleNode((size_t) initData, GTF_ICON_STATIC_HDL), // src @@ -4828,6 +4990,7 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, } node->gtFlags |= args->gtFlags & GTF_GLOB_EFFECT; + node->gtCall.compileTimeHelperArgumentHandle = (CORINFO_GENERIC_HANDLE)pResolvedToken->hClass; // Remember that this basic block contains 'new' of a md array compCurBB->bbFlags |= BBF_HAS_NEWARRAY; diff --git a/src/jit/instr.cpp b/src/jit/instr.cpp index 3dd10f2d2d..4fb23f662e 100644 --- a/src/jit/instr.cpp +++ b/src/jit/instr.cpp @@ -580,8 +580,7 @@ void CodeGen::instGetAddrMode(GenTreePtr addr, else *indScale = 0; - *cns = compiler->eeGetArrayDataOffset(addr->gtArrElem.gtArrElemType) - + 2 * sizeof(int) * addr->gtArrElem.gtArrRank; + *cns = compiler->eeGetMDArrayDataOffset(addr->gtArrElem.gtArrElemType, addr->gtArrElem.gtArrRank); } else if (addr->gtOper == GT_LEA) { diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index d76ce8cd92..da34404fbd 100755 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -3689,8 +3689,7 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data) // Generate the LEA and make it reverse evaluation, because we want to evaluate the index expression before the base. GenTreePtr leaBase = comp->gtClone(arrObjNode); unsigned scale = arrElem->gtArrElem.gtArrElemSize; - // Note that below we're specifically using genTypeSize(TYP_INT) because array indices are not native int. - unsigned offset = comp->eeGetArrayDataOffset(arrElem->gtArrElem.gtArrElemType) + 2 * genTypeSize(TYP_INT) * arrElem->gtArrElem.gtArrRank; + unsigned offset = comp->eeGetMDArrayDataOffset(arrElem->gtArrElem.gtArrElemType, arrElem->gtArrElem.gtArrRank); GenTreePtr leaIndexNode = prevArrOffs; if (!jitIsScaleIndexMul(scale)) { diff --git a/tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj b/tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj new file mode 100644 index 0000000000..466865d22a --- /dev/null +++ b/tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>$(MSBuildProjectName)</AssemblyName> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp> + <DebugType>Full</DebugType> + <Optimize>false</Optimize> + </PropertyGroup> + <ItemGroup> + <Compile Include="initializearray.il" /> + <None Include="app.config" /> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj b/tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj new file mode 100644 index 0000000000..689b3e00fd --- /dev/null +++ b/tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>$(MSBuildProjectName)</AssemblyName> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp> + <Optimize>true</Optimize> + </PropertyGroup> + <ItemGroup> + <Compile Include="initializearray.il" /> + <None Include="app.config" /> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/Methodical/Arrays/misc/initializearray.il b/tests/src/JIT/Methodical/Arrays/misc/initializearray.il new file mode 100644 index 0000000000..256c2bece9 --- /dev/null +++ b/tests/src/JIT/Methodical/Arrays/misc/initializearray.il @@ -0,0 +1,640 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89) + .ver 4:0:0:0 +} +.assembly initializearray +{ + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module initializearray.exe +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + +.class private auto ansi beforefieldinit InitializeArray extends [mscorlib]System.Object +{ + .method private hidebysig static int32 Main() cil managed + { + .entrypoint + .maxstack 8 + + call bool InitializeArray::SZArray_Int64_5_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::SZArray_Int64_6_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int16_10_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int16_0_10_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int16_11_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_8x10_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_10x10_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Float32_4x5_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Float32_5x5_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_2_4x3_5_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_2_5x3_5_InvalidInitializationTest() + brfalse.s fail + + ldc.i4.s 100 + ret + + fail: + ldc.i4.s 0 + ret + } + + .method private hidebysig static bool SZArray_Int64_5_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int64[] InitializeArray::SZArray_Initialize_Int64_5() + call int64[] InitializeArray::SZArray_Initialize_Int64_5_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int64[] SZArray_Initialize_Int64_5() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 5 + newarr int64 + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize40' 'ArrayInitializers'::'InitializerField40' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int64[] SZArray_Initialize_Int64_5_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 5 + newarr int64 + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize40' 'ArrayInitializers'::'InitializerField40' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool SZArray_Int64_6_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 11 + newarr int64 + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Int16_10_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int16[0...] InitializeArray::MDArray_Initialize_Int16_10() + call int16[0...] InitializeArray::MDArray_Initialize_Int16_10_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int16[0...] MDArray_Initialize_Int16_10() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 10 + newobj instance void int16[0...]::.ctor(int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int16[0...] MDArray_Initialize_Int16_10_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 10 + newobj instance void int16[0...]::.ctor(int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Int16_11_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 11 + newobj instance void int16[0...]::.ctor(int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Int16_0_10_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int16[...] InitializeArray::MDArray_Initialize_Int16_0_10() + call int16[...] InitializeArray::MDArray_Initialize_Int16_0_10_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int16[...] MDArray_Initialize_Int16_0_10() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 0 + ldc.i4 10 + newobj instance void int16[...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int16[...] MDArray_Initialize_Int16_0_10_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 0 + ldc.i4 10 + newobj instance void int16[...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + + .method private hidebysig static bool MDArray_Int8_8x10_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int8[0..., 0...] InitializeArray::MDArray_Initialize_Int8_8x10() + call int8[0..., 0...] InitializeArray::MDArray_Initialize_Int8_8x10_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int8[0..., 0...] MDArray_Initialize_Int8_8x10() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 8 + ldc.i4 10 + newobj instance void int8 [0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int8[0..., 0...] MDArray_Initialize_Int8_8x10_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 8 + ldc.i4 10 + newobj instance void int8[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Int8_10x10_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 10 + ldc.i4 10 + newobj instance void int8[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Float32_4x5_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call float32[0..., 0...] InitializeArray::MDArray_Initialize_Float32_4x5() + call float32[0..., 0...] InitializeArray::MDArray_Initialize_Float32_4x5_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static float32[0..., 0...] MDArray_Initialize_Float32_4x5_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4.4 + ldc.i4.5 + newobj instance void float32[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static float32[0..., 0...] MDArray_Initialize_Float32_4x5() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 4 + ldc.i4 5 + newobj instance void float32[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Float32_5x5_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 5 + ldc.i4 5 + newobj instance void float32[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Int8_2_4x3_5_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int8[..., ...] InitializeArray::MDArray_Initialize_Int8_2_4x3_5() + call int8[..., ...] InitializeArray::MDArray_Initialize_Int8_2_4x3_5_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int8[..., ...] MDArray_Initialize_Int8_2_4x3_5() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4.2 + ldc.i4.4 + ldc.i4.3 + ldc.i4.5 + newobj instance void int8 [..., ...]::.ctor(int32, int32, int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int8[..., ...] MDArray_Initialize_Int8_2_4x3_5_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4.2 + ldc.i4.4 + ldc.i4.3 + ldc.i4.5 + newobj instance void int8[..., ...]::.ctor(int32, int32, int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Int8_2_5x3_5_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4.2 + ldc.i4.5 + ldc.i4.3 + ldc.i4.5 + newobj instance void int8[..., ...]::.ctor(int32, int32, int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + +// +// ArrayEquals was generated from the following C# code: +// +//static bool ArrayEquals(Array x, Array y) +//{ +// if (x.Rank != y.Rank) +// return false; + +// var lower = new int[x.Rank]; +// var indices = new int[x.Rank]; +// var upper = new int[x.Rank]; + +// for (int i = 0; i < indices.Length; i++) +// { +// if (x.GetLowerBound(i) != y.GetLowerBound(i)) +// return false; +// if (x.GetLength(i) != y.GetLength(i)) +// return false; +// lower[i] = x.GetLowerBound(i); +// indices[i] = lower[i]; +// upper[i] = lower[i] + x.GetLength(i); +// } + +// while (true) +// { +// if (!object.Equals(x.GetValue(indices), y.GetValue(indices))) +// return false; + +// int i = 0; +// indices[i]++; + +// while (indices[i] >= upper[i]) +// { +// indices[i] = lower[i]; +// i++; + +// if (i >= indices.Length) +// return true; + +// indices[i]++; +// } +// } +//} + + .method private hidebysig static bool ArrayEquals(class [mscorlib]System.Array x, class [mscorlib]System.Array y) cil managed + { + .maxstack 5 + .locals init ( + [0] int32[] lower, + [1] int32[] indices, + [2] int32[] upper, + [3] int32 i, + [4] int32 V_4) + L_0000: ldarg.0 + L_0001: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_0006: ldarg.1 + L_0007: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_000c: beq.s L_0010 + L_000e: ldc.i4.0 + L_000f: ret + L_0010: ldarg.0 + L_0011: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_0016: newarr int32 + L_001b: stloc.0 + L_001c: ldarg.0 + L_001d: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_0022: newarr int32 + L_0027: stloc.1 + L_0028: ldarg.0 + L_0029: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_002e: newarr int32 + L_0033: stloc.2 + L_0034: ldc.i4.0 + L_0035: stloc.3 + L_0036: br.s L_007e + L_0038: ldarg.0 + L_0039: ldloc.3 + L_003a: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + L_003f: ldarg.1 + L_0040: ldloc.3 + L_0041: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + L_0046: beq.s L_004a + L_0048: ldc.i4.0 + L_0049: ret + L_004a: ldarg.0 + L_004b: ldloc.3 + L_004c: callvirt instance int32 [mscorlib]System.Array::GetLength(int32) + L_0051: ldarg.1 + L_0052: ldloc.3 + L_0053: callvirt instance int32 [mscorlib]System.Array::GetLength(int32) + L_0058: beq.s L_005c + L_005a: ldc.i4.0 + L_005b: ret + L_005c: ldloc.0 + L_005d: ldloc.3 + L_005e: ldarg.0 + L_005f: ldloc.3 + L_0060: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + L_0065: stelem.i4 + L_0066: ldloc.1 + L_0067: ldloc.3 + L_0068: ldloc.0 + L_0069: ldloc.3 + L_006a: ldelem.i4 + L_006b: stelem.i4 + L_006c: ldloc.2 + L_006d: ldloc.3 + L_006e: ldloc.0 + L_006f: ldloc.3 + L_0070: ldelem.i4 + L_0071: ldarg.0 + L_0072: ldloc.3 + L_0073: callvirt instance int32 [mscorlib]System.Array::GetLength(int32) + L_0078: add + L_0079: stelem.i4 + L_007a: ldloc.3 + L_007b: ldc.i4.1 + L_007c: add + L_007d: stloc.3 + L_007e: ldloc.3 + L_007f: ldloc.1 + L_0080: ldlen + L_0081: conv.i4 + L_0082: blt.s L_0038 + L_0084: ldarg.0 + L_0085: ldloc.1 + L_0086: callvirt instance object [mscorlib]System.Array::GetValue(int32[]) + L_008b: ldarg.1 + L_008c: ldloc.1 + L_008d: callvirt instance object [mscorlib]System.Array::GetValue(int32[]) + L_0092: call bool [mscorlib]System.Object::Equals(object, object) + L_0097: brtrue.s L_009b + L_0099: ldc.i4.0 + L_009a: ret + L_009b: ldc.i4.0 + L_009c: stloc.s V_4 + L_009e: ldloc.1 + L_009f: ldloc.s V_4 + L_00a1: ldelema int32 + L_00a6: dup + L_00a7: ldind.i4 + L_00a8: ldc.i4.1 + L_00a9: add + L_00aa: stind.i4 + L_00ab: br.s L_00d1 + L_00ad: ldloc.1 + L_00ae: ldloc.s V_4 + L_00b0: ldloc.0 + L_00b1: ldloc.s V_4 + L_00b3: ldelem.i4 + L_00b4: stelem.i4 + L_00b5: ldloc.s V_4 + L_00b7: ldc.i4.1 + L_00b8: add + L_00b9: stloc.s V_4 + L_00bb: ldloc.s V_4 + L_00bd: ldloc.1 + L_00be: ldlen + L_00bf: conv.i4 + L_00c0: blt.s L_00c4 + L_00c2: ldc.i4.1 + L_00c3: ret + L_00c4: ldloc.1 + L_00c5: ldloc.s V_4 + L_00c7: ldelema int32 + L_00cc: dup + L_00cd: ldind.i4 + L_00ce: ldc.i4.1 + L_00cf: add + L_00d0: stind.i4 + L_00d1: ldloc.1 + L_00d2: ldloc.s V_4 + L_00d4: ldelem.i4 + L_00d5: ldloc.2 + L_00d6: ldloc.s V_4 + L_00d8: ldelem.i4 + L_00d9: bge.s L_00ad + L_00db: br.s L_0084 + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} + +.class private auto ansi 'ArrayInitializers' extends [mscorlib]System.Object +{ + .class explicit ansi sealed nested private 'StaticArrayInitTypeSize20' extends [mscorlib]System.ValueType + { + .pack 1 + .size 20 + } + + .class explicit ansi sealed nested private 'StaticArrayInitTypeSize40' extends [mscorlib]System.ValueType + { + .pack 1 + .size 40 + } + + .class explicit ansi sealed nested private 'StaticArrayInitTypeSize80' extends [mscorlib]System.ValueType + { + .pack 1 + .size 80 + } + + .field static assembly valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'InitializerField20' at InitializerField20Data + .field static assembly valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize40' 'InitializerField40' at InitializerField40Data + .field static assembly valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'InitializerField80' at InitializerField80Data +} + +.data cil InitializerField20Data = bytearray (01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14) + +.data cil InitializerField40Data = bytearray (01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 + 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28) + +.data cil InitializerField80Data = bytearray (01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 + 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 + 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C + 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50) |