JEP 215: Tiered Attribution for javac
Поэтапная атрибуция в javac
| Authors | Vicente 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).