Может ли совместимый компилятор Java оптимизировать этот код? - программирование
Подтвердить что ты не робот

Может ли совместимый компилятор Java оптимизировать этот код?

Сегодня я преподавал вводный курс программирования и проходил через простой код с назначением переменных в Java. Точка кода заключалась не в том, чтобы показать что-то особенное, но в основном для того, чтобы ученики поняли переменные присваивания.

У меня был следующий метод на доске и он прослеживал через него по одной строке за раз:

private void simpleMethod() {
    int myInt = 137;
    myInt = 42;
    myInt = myInt + 1;

    /* ... code using myInt ... */
}

Студент спросил меня, будет ли myInt когда-либо иметь значения 137 и 42, когда программа запустится, или если он просто прыгнет прямо в холдинг 43. Я сказал ученику, что код будет выполнять каждую строку поочередно, поэтому переменная будет фактически удерживать эти промежуточные значения.

Честно говоря, я не был уверен, что будет вызываться байт-код javac (полностью игнорируя оптимизацию, выполняемую JVM). Является ли javac (или любой Java-компилятор) законным образом разрешать оптимизацию глупых операторов присваивания и вместо этого просто непосредственно инициализировать myInt до 43?

Согласно javap, в моей системе приведенный выше код javac генерирует

   0: sipush        137
   3: istore_1      
   4: bipush        42
   6: istore_1      
   7: iload_1       
   8: iconst_1      
   9: iadd          
  10: istore_1      
  11: return        

Итак, здесь нет оптимизации. Мой вопрос, однако, в том, является ли законным оптимизировать это или нет, поэтому это ничего не решает.

4b9b3361

Ответ 1

JLS указывает только контракт наблюдаемого поведения, создаваемого вашей программой. Поскольку myInt является локальным, оптимизация действительно может быть оптимизирована во время компиляции, так как это приведет к поведению, совместимому с spec, и в спецификации нет ничего, что говорит, что это не разрешено (по крайней мере, не то, что я нашел!). Глава 1 спецификации специфицирует наблюдаемую спецификацию явно: This document fully specifies the (apparent) order of evaluation of expressions.... Поскольку кажущееся поведение неизменено постоянным сгибанием до myInt = 43, оптимизация будет соответствовать JLS.

Фактически, цель компиляции Java-приложения даже не указана в JLS. В главе 1 говорится, что Java-приложения "обычно" компилируются в байт-код, указанный в спецификации JVM (отдельный документ), но не требуют, чтобы они это делали. Существуют некоторые утверждения, которые необходимо оптимизировать во время компиляции, но myInt не является таковым. Даже если myInt было полем, я думаю, что оптимизация будет разрешена; другое поведение по-прежнему будет действительным поведением, даже если myInt является изменчивым (поскольку он представляет собой одно допустимое упорядочение событий).

Итак, короткий ответ, я думаю, что ваш ученик прав; это прекрасно, чтобы оптимизировать его до всего myInt = 43. Тем не менее, javac обычно делает очень мало - практически ничего - на пути оптимизации. Оптимизации почти все сделано в JIT.

Ответ 2

Я считаю, что компилятору Java разрешено делать любую постоянную фальцовку, которую он может статически определять во время компиляции.

Итак, это можно оптимизировать с помощью javac.

Однако javac не нужно делать эту оптимизацию, потому что JVM JIT-компилятор почти наверняка сделает такую ​​же оптимизацию для вас немного дальше по линии. С этой точки зрения, действительно ли компилятор Java → Bytecode делает эту оптимизацию, вероятно, не имеет отношения к влиянию на фактический собственный код, выполняемый во время выполнения.

Ответ 3

Итак, здесь нет оптимизации.

Это не должно быть слишком неожиданным, если Java использует динамическую компиляцию.

JVM оптимизирует почти весь код во время выполнения, это означает, что независимо от того, используете ли вы код, скомпилированный для Java 1.0 в 1996 году или Scala или JRuby, JGo и т.д., вы получаете полное преимущество оптимизации от собственного кода вашей конкретной модели процессора.

По этой причине многие языки имеют JVM-реализации, поэтому им не нужно создавать оптимальный код для всех платформ, на которых работает JVM.

Ответ 4

Хотя это верно, мой вопрос заключается в том, является ли компилятор законным разрешено делать эту оптимизацию

По традиционному анализу потока данных (функции потока/передачи, встроенные, исходящие, ген-наборы, kill-sets и т.д.), в частности потоки данных с определенными траекториями, также определяющие определения (или use-def цепи)... да. По сути, оптимизатор может связывать каждое использование переменной с определениями, которые ее достигают.

В этом случае оптимизатор может определить, что первоначальное определение myInt (= 137) никогда не достигает своего использования, в то время как другое определение (= 42 1) действительно достигает своего использования, поскольку оно никогда не переопределен на любом (некотором) пути от этого определения до его использования.

Литература:

  • Книга Дракона 1ed (1986) глава 10
  • Книга дракона 2ed (2007), глава 9 (специально для 9.2)

1 - Я все время использую 42 в своем учебном коде. Бьюсь об заклад, все мы делаем.