JEP 165: Compiler Control
Управление компиляторами
| Ответственный | Nils Eliasson |
| Тип | Feature |
| Область | JDK |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Компонент | hotspot / compiler |
| Обсуждение | hotspot dash compiler dash dev at openjdk dot java dot net |
| Трудоёмкость | M |
| Длительность | M |
| Рецензенты | Jesper Wilhelmsson |
| Одобрен | Mikael Vidstedt |
| Создан | 2011/12/02 20:00 |
| Обновлён | 2026/07/29 18:54 |
| Задача | 8046155 |
Аннотация
Этот JEP предлагает усовершенствованный способ управления компиляторами JVM. Он позволяет использовать флаги компилятора, которыми можно управлять во время выполнения и которые зависят от метода. (Во время одной компиляции они не меняются.)
Цели
-
Детальное управление компиляторами JVM (C1 и C2), зависящее от контекста метода
-
Возможность менять параметры управления компиляторами JVM во время выполнения
-
Без снижения производительности
Мотивация
Управление процессом компиляции, зависящее от контекста метода, — мощный инструмент для написания небольших изолированных тестов компиляторов JVM, которые можно запускать без перезапуска всей JVM. Оно также очень полезно для обхода ошибок в компиляторах JVM. Кроме того, хорошая инкапсуляция параметров компилятора — это хорошая практика.
Описание
Директивы
Все параметры, управляющие компиляторами JVM, будут собраны в единый набор параметров. Набор параметров со значениями называется директивой компилятора и представляет собой инструкцию о том, как компилировать. Директива передаётся VM вместе с сопоставителем методов, который определяет, к каким методам она применяется. Во время выполнения одновременно может действовать несколько директив, но к конкретной компиляции применяется только одна. Директивы можно добавлять и удалять во время выполнения.
Формат директив
У файлов директив есть определённый стандартизированный и удобочитаемый формат. Файлы директив можно загружать через командную строку и через диагностическую команду. В файле директив определена одна или несколько директив. Директива содержит один шаблон методов и некоторое количество параметров со значениями. Порядок директив имеет значение. compilerBroker применит к компиляции первую директиву, шаблон которой совпадает.
Формат файла директив будет подмножеством JSON с некоторыми дополнениями. От JSON формат отличается следующим:
- Поддерживаются только числа, совместимые с параметрами командной строки, — int и double.
- Допускаются комментарии — строки, начинающиеся с «//»
- В массивах и объектах допускаются лишние завершающие '',"
- Экранированные символы, вероятно, не будут допускаться (TBD)
- Имена параметров — строки, но заключать их в кавычки необязательно
В файле можно использовать все символы UTF-8, поддерживаемые спецификацией JVM. Эти символы зарезервированы для формата файла:
{ - curly brace open
} - curly brace end
[ - square brace open
] - square brace end
" - quotes
: - colon
, - comma
Пример директив 1
[ // Start if array of directives
{ // Start of directive block
// Exactly one match with one or several patterns
// The array is not required with a single pattern
match: ["java*::*", "oracle*::*"],
// A directives block that only apply to a single compiler
c1: {
// A bool option. Extra trailing comma should not cause a parse error
PrintAssembly:true,
},
// Another compiler block
c2: {
// force inline patters prepended with +, prevent with -
inline: ["+vm*::*","-*::*" ]
},
// Options outside compiler block apply to all compilers
BreakAtExecute: true // enable break in compiled code
BreakAtCompile: true // enable break in compiler
},
{ // start of another directives block
// match ant method whose class end with 'Concurrent'
match: ["*Concurrent::*"],
c2: {
// disable compilation
Exclude:true,
}
// with the c1 directive unspecified the options remains default.
}
]
Пример директив 2
[
{
// pattern to match against class+method+signature
// leading and trailing wildcard (*) allowed
match: "apa.Dingo::*",
// override defaults for specified compiler
// the innermost option has the highest priority
c1: {
//override c1 presets
PrintInlining: false // Example - this option may not exist
}
c2: {
// control inlining of method
// + force inline, - dont inline
inline : [ "+java.util::*", "-com.sun::*"],
}
// directives outside a specific preset applies to all compilers
inline : [ "+java.util::*", "-com.sun::*"],
PrintAssembly: true
},
{
// matching several patterns require an array
match: ["steve::*","alex::*"]
c2: {
Enable: false, // Ignore this directive for c2.
BreakAtExecute: true // This will not be applied since Enable is false above
}
// applies to all compilers
// + force inline, - dont inline
inline : [ "+java.util::*", "-com.sun::*"],
PrintInlining: true
},
]
Список параметров директив
Первая реализация содержит следующие параметры. Все эти параметры ранее использовались в командах параметра CompileCommand. Будут добавлены и другие параметры.
Общие флаги: Enable, bool Exclude, bool BreakAtExecute, bool BreakAtCompile, bool Log, bool PrintAssembly, bool PrintInlining, bool PrintNMethods, bool ReplayInline, bool DumpReplay, bool DumpInline, bool CompilerDirectivesIgnoreCompileCommands, bool Inline, ccstr[]
Только C2: BlockLayoutByFrequency, bool PrintOptoAssembly, bool PrintIntrinsics, bool raceOptoPipelining, bool TraceOptoOutput, bool TraceSpilling, bool Vectorize, bool VectorizeDebug, bool CloneMapDebug, bool IGVPrintLevel, intx MaxNodeLimit, intx DisableIntrinsics, ccstr
inline:<one pattern or an array of string patterns>
The pattern is a string that matches a method name in the same way as directives are matched.
A '+' prepended to the pattern signifies that methods matching should be force-inlined.
A '-' that it should be prevented from inlining.
The command from the first pattern that matches is used.
Example1: inline:["+java.lang.*::*", -"sun*::*"]
Example2: inline:"+java.lang.*::*"
Шаблоны директив
Шаблоны методов, используемые в параметрах «match» и «inline», имеют следующий вид: Class.method(signature)
Class включает имена пакетов, разделённые символом / Class и method могут содержать подстановочный символ * в начале и в конце или быть заменены на * Если signature опущена, по умолчанию используется *
Допустимые шаблоны: "java.lang.String::indexOf" "java/lang/String.indexOf" ".lang.String::indexOf(I)" "java/lang/String.(I)" "java/lang/String.()" "." "::" "java.lang.::"
Парсер директив
Парсер директив отвечает за разбор файла директив и перенос информации во внутренний формат VM.
Если в командной строке указан некорректный файл директив, VM выведет ошибку и завершит работу. Если некорректный файл директив добавлен через диагностическую команду, он будет проигнорирован и будет выведено соответствующее предупреждение.
Парсер проверит, что все параметры допустимы. Для платформенно-зависимых параметров на платформах, которые их не поддерживают, будут выводиться предупреждения. Смысл в том, чтобы одни и те же файлы директив можно было использовать независимо от платформы, на которой они развёрнуты.
Для неуказанных параметров будет использоваться значение по умолчанию. Если параметр указан в командной строке, значением по умолчанию будет он. Значение по умолчанию для шаблона методов — «.» (совпадает со всеми методами).
CompilerBroker
У compilerBroker есть стек директив, в котором находятся все применённые директивы. Нижняя директива — набор по умолчанию, её нельзя удалить. При загрузке файла с дополнительными директивами они добавляются в обратном порядке, так что первая директива из файла оказывается на вершине стека. Это сделано для удобства использования.
Когда метод отправляется на компиляцию, compilerBroker выбирает первую совпадающую директиву и передаёт её компилятору. compilerBroker и компиляторы будут игнорировать параметры, которые привели бы к некорректному коду (например, принудительное использование аппаратной инструкции на платформе, которая её не поддерживает), и будет выведено соответствующее предупреждение. У параметров директив те же ограничения, что и у обычных флагов командной строки: например, принудительное встраивание будет соблюдаться только до тех пор, пока IR не станет слишком большим.
Интерфейс командной строки
Файл директив можно добавить в командной строке. VM завершит работу с сообщением об ошибке, если флаг указан неверно (обычный разбор командной строки), файл отсутствует или содержимое файла некорректно.
-XX:CompilerDirectivesFile=<file>
Интерфейс диагностических команд
Вот диагностические команды, которые будут использоваться для управления компиляторами:
jcmd <pid> Compiler.add_directives <file>
Add additional directives from the file. The new directives will be added on top of the old, with the first directive in the file ending up on the top of the directives stack.
jcmd <pid> Compiler.list_directives
List all directives on the directives stack from top to bottom.
jcmd <pid> Compiler.clear_directives
Clear the directives stack
jcmd <pid> Compiler.remove_directives
Remove the top element from the directives stack
CompileCommand и обратная совместимость
CompilerControl должен заменить CompileCommand во всех сценариях использования. CompileCommand будет сохранён для обратной совместимости, и цель — по возможности сохранить его поведение.
Можно применять четыре уровня управления. Compiler Control будет иметь наивысший приоритет и переопределять любой другой флаг или команду. Второй уровень — CompileCommand, третий — любой флаг командной строки, четвёртый — значение флага по умолчанию. Если используются и Compiler control, и CompileCommand, Compiler control будет считать, что CompileCommand переопределяет значение по умолчанию.
JVM должна выводить предупреждение, если используются и CompileCommand, и директивы компилятора.
Шаблоны методов
Compiler Control будет использовать тот же формат шаблонов методов, что и CompileCommand. Шаблон состоит из трёх частей: имени пакета и класса, имени метода и сигнатуры. В любой из этих трёх частей может использоваться подстановочный символ * в начале или в конце. Значение по умолчанию для любой части — *.
Пример:
java/example/Test.split
Состоит из трёх частей
java/example/Test + split + (Ljava/lang/String;)Ljava/lang/String;
Риски и допущения
Из-за огромного количества параметров компилятора нам придётся поначалу ограничиться их подмножеством. Мы сосредоточимся на подмножестве и будем расширять его.
Зависимости
- Диагностическая команда — уже реализована
- Работа с полным JDK — уже реализована
Влияние
- Документация: флаги и API
- CCC: потребуется запрос CCC для формата директив, изменений флагов компиляторов JVM и API.
- Производительность: стандартное регрессионное тестирование