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

JEP 215: Tiered Attribution for javac

Поэтапная атрибуция в javac

AuthorsVicente Arturo Romero Zaldivar, Maurizio Cimadamore
ОтветственныйVicente Arturo Romero Zaldivar
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск9
Компонентtools / javac
Обсуждениеcompiler dash dev at openjdk dot java dot net
ТрудоёмкостьM
ДлительностьL
Связан сJEP 217: Annotations Pipeline 2.0
JEP 216: Process Import Statements Correctly
РецензентыBrian Goetz, Maurizio Cimadamore
ОдобренBrian Goetz
Создан2014/07/24 21:18
Обновлён2016/07/12 21:00
Задача8051946

Аннотация

Реализовать в javac новую стратегию проверки типов в методах, чтобы ускорить атрибуцию poly-выражений в позиции аргумента.

Цели

Реализовать новый подход к проверке типов poly-выражений — tiered attribution (TA, поэтапная атрибуция), который обеспечивает:

  • более высокую производительность за счёт подхода, сокращающего число (избыточных) проходов, нужных для атрибуции данного выражения, и

  • те же результаты, что и текущая реализация проверки типов.

Что не является целью

Изменение множества компилируемых программ не является целью, хотя некоторые изменения могут возникнуть как следствие исправления скрытых ошибок в существующей схеме проверки типов. Также следует ожидать некоторых незначительных различий в сообщениях, генерируемых компилятором.

Целью также не является существенное улучшение чистоты и сопровождаемости текущего кода — хотя, возможно, некоторые изменения, внесённые этим JEP, также сделают код чище.

Мотивация

Реализованный в настоящее время подход к проверке типов poly-выражений Java SE 8 известен как «Speculative attribution» (SA, спекулятивная атрибуция); основная идея SA — проверять типы одного и того же дерева несколько раз относительно разных целевых типов; это позволяет, например, проверить лямбда-выражение относительно нескольких целевых типов при разрешении перегрузки.

Возможность выполнять проверку типов посреди разрешения перегрузки — очень мощный и гибкий приём, но за него приходится платить очень высокую цену в плане производительности. Точнее, при N кандидатах перегрузки одно и то же выражение-аргумент может быть проверено до N * 3 раз (по одному разу на каждую фазу перегрузки: strict, loose, varargs) + 1 (финальная фаза проверки). Если выражения-аргументы допускают вложенность (например, лямбда, возвращающая poly-вызов метода), эти множители нужно перемножить, что приводит к комбинаторному взрыву числа вызовов атрибуции.

Экспоненциальное число обращений к механизму спекулятивной атрибуции привело к проблемам с производительностью, которые наблюдались и были зарегистрированы как ошибки, например JDK-8077247, JDK-8078093 и JDK-8055984.

Описание

Этот JEP предлагает альтернативную и более эффективную схему реализации поддержки проверки типов poly-выражений в javac. Концептуально нет необходимости проверять типы выражения во время разрешения перегрузки; на самом деле выражение-аргумент либо может быть проверено снизу вверх — и тогда проверка перегрузки выполняется без атрибуции, либо такое выражение не относится к применимости (см. JLS 15.12.2.2), то есть не участвует в проверке применимости при разрешении перегрузки. Например, лямбда-выражение может быть либо явным — и тогда проверку типов его тела можно выполнить до разрешения перегрузки, либо неявным — и тогда во время разрешения перегрузки проверка типов не требуется.

Основная идея tiered attribution — до разрешения перегрузки построить снизу вверх структурные типы (по одному на каждое poly-выражение-аргумент в данном вызове метода), содержащие всю информацию, необходимую для проверки применимости при разрешении перегрузки, то есть без дальнейшей необходимости в атрибуции. Такие структурные типы могут содержать частично выведенные переменные типа, которые будут зафиксированы только на более позднем этапе — при выводе типов вызова (см. JLS 18.5.2). Новые структурные типы будут создаваться для следующих выражений-аргументов:

  • лямбда-выражений,
  • условных poly-выражений,
  • вызовов обобщённых методов,
  • poly-выражений в скобках,
  • ссылок на методы и
  • выражений создания экземпляра с оператором diamond.

Поскольку некоторые из перечисленных выражений допускают вложенность, структурный тип может ссылаться на другие структурные типы. Например, случай лямбда-выражения, возвращающего вызов обобщённого метода, можно смоделировать структурным типом (для лямбда-выражения), указывающим на другой структурный тип, который моделирует вызов обобщённого метода. В таких случаях проверка перегрузки, связанная со структурным типом, может быть рекурсивной: например, все структурные типы, на которые ссылаются return-выражения в теле лямбды, придётся проверить относительно целевого типа, предоставленного механизмом разрешения перегрузки.

Как правило, структурные типы будут создаваться при атрибуции аргументов вызова метода или конструктора. Poly-выражения, встречающиеся в контексте, отличном от вызова метода или конструктора, должны обрабатываться так же, как сейчас.

Для корректной реализации вложенных вызовов обобщённых методов также потребуются некоторые изменения в выводе типов; точнее, механизм вывода типов должен получить более совершенные средства сохранения и отката, чтобы обрабатывать проверки перегрузки с участием вызовов обобщённых методов (которые могут потребовать выполнения некоторых задач вывода), не загрязняя необратимо контекстную информацию, связанную с такими вызовами.

Тестирование

javac уже содержит обширный набор регрессионных тестов, подтверждающих, что SA работает как ожидается; хотя большинство этих тестов — в основном тесты по принципу чёрного ящика, они должны эффективно выявлять ошибки реализации tiered attribution. В рамках этого JEP могут быть добавлены дополнительные тесты, особенно касающиеся хорошо известных узких мест производительности.

Зависимости

Предлагаемая здесь работа может быть полезна двум связанным JEP: Process Import Statements Correctly (JEP 216) и Annotations Pipeline 2.0 (JEP 217).