openjdk.ruOpenJDK на русском

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.
  • Производительность: стандартное регрессионное тестирование