我有简单的 for 循环和使用 ILGenerator 编写的数组访问。当使用这个确切的代码创建方法时,我打开反汇编,没关系,没有数组边界检查。
但是当我首先将其他类的实例放在评估堆栈上,然后运行 for 循环时,它会检查数组边界。我正在发布。
知道为什么吗?我已经阅读了有关数组绑定检查的博客文章: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 代码时,最好将类的实例保存在评估堆栈或局部变量中?
例如,我得到实例,遍历字段,为每个字段做任何事情然后返回。在读取下一个字段之前,我刚刚将实例保存在堆栈上并调用了 Emit(OpCodes.Dup)。但这似乎是错误的(至少对于上述情况)。
任何关于生成(高效/格式良好)IL 代码的文章/博客文章都值得赞赏。