В информатике опережающая компиляция ( AOT-компиляция ) — это процесс компиляции (часто) языка программирования более высокого уровня в (часто) язык более низкого уровня перед выполнением программы, обычно во время сборки, для сокращения объема работы, которую необходимо выполнить во время выполнения .
Чаще всего он ассоциируется с процессом компиляции языка программирования более высокого уровня, такого как C или C++ , или промежуточного представления, такого как байт-код Java или код Common Intermediate Language (CIL), в машинный код , чтобы полученный двоичный файл мог выполняться нативно, как и стандартный нативный компилятор. При использовании в этом контексте его часто рассматривают как противоположность компиляции just-in-time (JIT).
Говоря более обобщенно, целевые языки компиляции AOT не обязательно специфичны для машинного кода , а определяются довольно произвольно. Некоторые академические статьи используют это слово для обозначения действия компиляции байт-кода Java в C [1] или времени выполнения конвейера оптимизации. [2] Академический проект [3] использует это слово для обозначения действия предварительной компиляции JavaScript в машинно-зависимый оптимизированный IR для V8 (движок JavaScript) [4] и в машинно-независимый байт-код для JavaScriptCore . [5] Некоторые промышленные реализации языка (например, Clojure [6] и движок Hermes JavaScript [7] ) используют это слово для обозначения действия предварительной компиляции исходного языка в байт-код, специфичный для виртуальной машины. Angular (веб-фреймворк) использует это слово для обозначения преобразования своего шаблона HTML и TypeScript в JavaScript . [8]
Фактически, поскольку вся статическая компиляция технически выполняется заранее, эта конкретная формулировка часто используется для подчеркивания примеров, где есть значительные преимущества в производительности по сравнению с действием такой предварительной компиляции. Поэтому действие компиляции Java в байт-код Java редко называют AOT, поскольку это обычно требование, а не оптимизация.
Некоторые языки программирования с управляемым кодом времени выполнения, который может быть скомпилирован в промежуточное представление, используют компиляцию just-in-time (JIT). Это кратковременно компилирует промежуточный код в машинный код для собственного запуска, пока промежуточный код выполняется, что может замедлить производительность приложения. Компиляция до начала выполнения устраняет необходимость в этом шаге, поскольку происходит до выполнения, а не во время выполнения.
Предварительная компиляция динамически типизированных языков в машинный код или другой статический байт-код виртуальной машины возможна только в ограниченном числе случаев. [ требуется ссылка ] Например, AOT-компилятор High Performance Erlang Project (HiPE) для языка Erlang может делать это благодаря передовым методам статической реконструкции типов и спекуляциям типов.
В большинстве ситуаций с полностью скомпилированными AOT-программами и библиотеками можно удалить часть среды выполнения , тем самым экономя дисковое пространство, память, время работы батареи и время запуска (без фазы разогрева JIT) и т. д. Благодаря этому он может быть полезен во встраиваемых или мобильных устройствах.
Компиляторы AOT могут выполнять сложные и продвинутые оптимизации кода , которые в большинстве случаев JIT-компиляции будут считаться слишком затратными. Напротив, AOT обычно не может выполнять некоторые оптимизации, возможные в JIT, такие как оптимизация с управлением профилем во время выполнения (PGO), распространение псевдоконстант или встраивание косвенных виртуальных функций . AOT должен компилироваться в целевую архитектуру, в то время как JIT может компилировать код, чтобы максимально использовать реальный процессор, на котором он работает, даже спустя годы после выпуска программного обеспечения.
Кроме того, JIT-компиляторы могут спекулятивно оптимизировать горячий код, делая предположения о коде. Сгенерированный код может быть деоптимизирован, если спекулятивное предположение позже окажется неверным. Такая операция замедляет производительность работающего программного обеспечения, пока код не будет снова оптимизирован с помощью адаптивной оптимизации . AOT-компилятор не может делать такие предположения и должен выводить как можно больше информации во время компиляции. Ему нужно прибегнуть к менее специализированному коду, поскольку он не может знать, какие типы пройдут через метод. Такие проблемы можно смягчить с помощью оптимизаций, управляемых профилем. Но даже в этом случае сгенерированный код не может динамически адаптироваться к изменяющемуся профилю времени выполнения, как это сделал бы JIT-компилятор.