intfoo(int[] a) { intsum=0; for (inti=0; i < a.length; i++) { if (a == null) { // null check thrownewNullPointerException(); } if (i < 0 || i >= a.length) { // range check thrownewArrayIndexOutOfBoundsException(); } sum += a[i]; } return sum; }
intfoo(int[] a) { intsum=0; if (a == null) { deoptimize(); // never returns } for (inti=0; i < a.length; i++) { if (a == null) { // now evluate to false thrownewNullPointerException(); } if (i < 0 || i >= a.length) { // range check thrownewArrayIndexOutOfBoundsException(); } sum += a[i]; } return sum; }
外提range check
由于如果外提range check之后,将无法再引用到循环变量,因此即时编译器需要转换检测条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
for (inti= INIT; i < LIMIT; i += STRIDE) { if (i < 0 || i >= a.length) { // range check thrownewArrayIndexOutOfBoundsException(); } sum += a[i]; } ---------- // 经过range check外提之后 if (INIT < 0 || IMAX >= a.length) { // IMAX是i所能达到的最大值,不一定是LIMIT-1 detopimize(); // never returns } for (inti= INIT; i < LIMIT; i += STRIDE) { sum += a[i]; // 不再包含range check }
循环展开
循环展开:在循环体中重复多次循环迭代,并减少循环次数的编译优化,是一种以空间换时间的优化方式
1 2 3 4 5 6 7
intfoo(int[] a) { intsum=0; for (inti=0; i < 64; i++) { sum += (i % 2 == 0) ? a[i] : -a[i]; } return sum; }
经过一次循环展开后
1 2 3 4 5 6 7 8
intfoo(int[] a) { intsum=0; for (inti=0; i < 64; i += 2) { // 步长为2 sum += (i % 2 == 0) ? a[i] : -a[i]; sum += ((i + 1) % 2 == 0) ? a[i + 1] : -a[i + 1]; } return sum; }
计数循环
在C2中,只有计数循环才能被展开,计数循环需要满足以下条件
维护一个循环计数器,并且基于计数器的循环出口只有一个
但可以有基于其他判断条件的出口
循环计数器的类型只能为int/short/char
每个迭代循环计数器的增量为常数
循环计数器的上限和下限是与循环无关的数值
1 2 3 4 5 6 7 8 9
for (inti= START; i < LIMIT; i += STRIDE) { .. } // 等价于 inti= START; while (i < LIMIT) { .. i += STRIDE; } // 只要LIMIT是与循环无关的数值,STRIDE是常数,而且循环中除了i < LIMIT之外没有其他基于循环变量i的循环出口 // 那么C2便会将该循环标识为计数循环