У меня есть простой для цикла с доступом к массиву, написанный с использованием ILGenerator. Когда метод создается с помощью этого точного кода, я открываю разборку, и все в порядке, проверка границ массива не выполняется.Проверка границ массива в DynamicAssembly работает только тогда, когда оценочный стек пуст
Но когда я впервые поместил экземпляр другого класса в стек оценки, затем запустил цикл, он проверяет границы массива. Я бегу от выпуска.
Любая идея, почему? Я уже прочитал сообщение в блоге о проверках границ массивов: http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds-check-elimination-in-the-clr.aspx
// Uncomment this to enable bound checks, type of arg0 is some my class
//il.Emit(OpCodes.Ldarg_0);
var startLbl = il.DefineLabel();
var testLbl = il.DefineLabel();
var index = il.DeclareLocal(typeof(Int32));
var arr = il.DeclareLocal(typeof(Int32).MakeArrayType());
// arr = new int[4];
il.Emit(OpCodes.Ldc_I4_4);
il.Emit(OpCodes.Newarr, typeof(Int32));
il.Emit(OpCodes.Stloc, arr);
// Index = 0
il.Emit(OpCodes.Ldc_I4_0); // Push index
il.Emit(OpCodes.Stloc, index); // Pop index, store
il.Emit(OpCodes.Br_S, testLbl); // Go to test
// Begin for
il.MarkLabel(startLbl);
// Load array, index
il.Emit(OpCodes.Ldloc, arr);
il.Emit(OpCodes.Ldloc, index);
// Now on stack: array, index
// Load element
il.Emit(OpCodes.Ldelem_I4);
// Nothing here now, later some function call
il.Emit(OpCodes.Pop);
// Index++
il.Emit(OpCodes.Ldloc, index);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc, index);
il.MarkLabel(testLbl);
// Load index, count, test for end
il.Emit(OpCodes.Ldloc, index);
il.Emit(OpCodes.Ldloc, arr);
il.Emit(OpCodes.Ldlen); // Push len
il.Emit(OpCodes.Conv_I4); // Push len
il.Emit(OpCodes.Blt_S, startLbl);
// End for
// Remove instance added on top
//il.Emit(OpCodes.Pop);
Как сгенерировать IL-код, лучше держать экземпляры классов на стеке вычислений или в локальном переменных?
E.g. Я получаю экземпляр, просматриваю поля, для каждого поля делаю что-нибудь и возвращаю. Я просто сохранил экземпляр в стеке и назвал Emit (OpCodes.Dup) перед чтением следующего поля. Но это кажется неправильным (по крайней мере, для случая, упомянутого выше).
Любые статьи/сообщения в блоге о генерации (эффективный/хорошо сформированный) код IL оценен.