Как JohannesD предложил в комментарии , вряд ли можно считать от 0 до Integer.MAX_VALUE
(и, после переполнения, от -Integer.MAX_VALUE
до 0) так быстро.
Чтобы проверить предположение о том, что JIT выполняет некоторую магическую оптимизацию, я создал слегка модифицированную программу, внедрив некоторые методы, облегчающие идентификацию частей кода:
class IntOverflowTest
{
public static void main(String[] args) {
runLoop();
}
public static void runLoop()
{
int i = 1;
int k = 0;
while (true) {
if(++i==0) doPrint(++k);
}
}
public static void doPrint(int k)
{
System.out.println("loop: " + k);
}
}
Байт-код, испускаемый и показанный с помощью javap -c IntOverflowTest
, не вызывает удивления:
class IntOverflowTest {
IntOverflowTest();
Code:
0: aload_0
1: invokespecial #1
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #2
3: return
public static void runLoop();
Code:
0: iconst_1
1: istore_0
2: iconst_0
3: istore_1
4: iinc 0, 1
7: iload_0
8: ifne 4
11: iinc 1, 1
14: iload_1
15: invokestatic #3
18: goto 4
public static void doPrint(int);
Code:
0: getstatic #4
3: new #5
6: dup
7: invokespecial #6
10: ldc #7
12: invokevirtual #8
15: iload_0
16: invokevirtual #9
19: invokevirtual #10
22: invokevirtual #11
25: return
}
Он явно увеличивает обе локальные переменные (runLoop
, смещения 4 и 11).
Однако, при запуске кода с -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -XX:+PrintAssembly
в дизассемблере Hotspot, машинный код в итоге получается следующим:
Decoding compiled method 0x00000000025c2c50:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} {0x000000001bb40408} 'runLoop' '()V' in 'IntOverflowTest'
# [sp+0x20] (sp of caller)
0x00000000025c2da0: mov %eax,-0x6000(%rsp)
0x00000000025c2da7: push %rbp
0x00000000025c2da8: sub [112]x10,%rsp ;*synchronization entry
; - IntOverflowTest::runLoop@-1 (line 10)
0x00000000025c2dac: mov [112]x1,%ebp ;*iinc
; - IntOverflowTest::runLoop@11 (line 13)
0x00000000025c2db1: mov %ebp,%edx
0x00000000025c2db3: callq 0x00000000024f6360 ; OopMap{off=24}
;*invokestatic doPrint
; - IntOverflowTest::runLoop@15 (line 13)
; {static_call}
0x00000000025c2db8: inc %ebp ;*iinc
; - IntOverflowTest::runLoop@11 (line 13)
0x00000000025c2dba: jmp 0x00000000025c2db1 ;*invokestatic doPrint
; - IntOverflowTest::runLoop@15 (line 13)
0x00000000025c2dbc: mov %rax,%rdx
0x00000000025c2dbf: add [112]x10,%rsp
0x00000000025c2dc3: pop %rbp
0x00000000025c2dc4: jmpq 0x00000000025b0d20 ; {runtime_call}
0x00000000025c2dc9: hlt
Можно ясно видеть, что он не увеличивается внешняя переменная i
больше. Он вызывает только метод doPrint
, увеличивает на единицу переменную (k
в коде), а затем сразу же возвращается к точке, предшествующей вызову doPrint
.
Таким образом, JIT действительно обнаруживает, что нет реального «условия», связанного с печатью вывода, и что код эквивалентен бесконечному циклу, который печатает и увеличивает только одну переменную.
Это кажется довольно сложной оптимизацией для меня. Я ожидаю, что это далеко не тривиально, чтобы обнаружить такой случай. Но, очевидно, им удалось это сделать ...
Это невозможно. Vim по своей природе является текстовым редактором и не предлагает стиль Microsoft Word WYSIWYG. Вы не можете редактировать отформатированные документы.
Конечно, вы можете отредактировать исходный код файла RTF (RTF - довольно простой язык форматирования, поэтому редактировать его вручную теоретически возможно), но я не делаю думаю, это то, что вы ищете.
Если вы хотите редактировать с помощью Vim, но по-прежнему производите документы с форматированием, ваш лучший снимок - LaTeX . Это позволяет создавать профессиональные документы с помощью языка программирования макросов.