Possible bug in JIT or CLR

154 views Asked by At

My code generates a method to dynamically create a multidimensional array assuming an array of dimension lengths, however it seems the the JIT-compiler or even the CLR fails to load items from the dimension lengths array appropriately.

Instead of creating an array of int[10, 10, 10], an array of int[10, 10, 0] is created. It appears to go wrong at OpCodes.Ldelem_I, however, using OpCodes.Ldelem, typeof(int) instead just works. The reproduce this behavior, Any CPU settings are required, x86 works fine. This problem occurs on both debug and release mode.

So is this a bug? I feel to uncertain to judge this as I am unable to dig deeper into this.

class Program
{
    static void Main(string[] args)
    {
        CreateMultidimensionalArrayCreator(typeof(int[, ,])).Invoke(new int[] { 10, 10, 10 }); ;            
    }

    static Func<int[], Array> CreateMultidimensionalArrayCreator(Type type)
    {
        int rank = type.GetArrayRank();

        DynamicMethod method = new DynamicMethod(String.Empty, typeof(Array), new Type[] { typeof(int[]) }, typeof(Program), false);
        ILGenerator ilGen = method.GetILGenerator();

        for (int i = 0; i < rank; i++)
        {
            // Load element from dimension lengths array
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldc_I4, i);
            ilGen.Emit(OpCodes.Ldelem_I); // Somehow returns 0 for last element, however, OpCodes.Ldelem appears to work fine
            // Duplicate element and write to console for diagnostics
            ilGen.Emit(OpCodes.Dup);
            ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }));
        }

        // Get parameters for multidimensional array constructor
        //
        Type[] parameterTypes = new Type[rank];

        for (int i = 0; i < rank; i++)
        {
            parameterTypes[i] = typeof(int);
        }

        ilGen.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, parameterTypes, null));
        ilGen.Emit(OpCodes.Ret);

        return (Func<int[], Array>)method.CreateDelegate(typeof(Func<int[], Array>));
    }
}
1

There are 1 answers

0
Evgeniy Mironov On

Replace line:

ilGen.Emit(OpCodes.Ldelem_I); // Somehow returns...

to line:

ilGen.Emit(OpCodes.Ldelem_I4); // Somehow returns 0 for last element....