Почему JVM по-прежнему не поддерживает оптимизацию хвостового вызова?

Через два года после does-the-jvm-prevent-tail-call-optimizations существует прототип реализация и MLVM перечислил эту функцию как "proto 80 %" в течение некоторого времени.

Нет ли активного интереса со стороны Sun/Oracle в поддержке хвостовых вызовов или это только то, что хвостовые звонки "[...] суждено прийти на второе место в каждом списке приоритетов функций [...]", как упомянуто на JVM Language Summit?

Мне было бы очень интересно, если кто-то протестировал сборку MLVM и мог бы поделиться некоторыми впечатлениями о том, насколько хорошо он работает (если вообще).

Обновление: Обратите внимание, что некоторые виртуальные машины, такие как Avian, поддерживают надлежащие хвостовые вызовы без каких-либо проблем.

Ответ 1

Диагностика кода Java: повышение производительности вашего Java-кода (alt) объясняет, почему JVM не поддерживает оптимизацию хвостового вызова.

Но, хотя хорошо известно, как автоматически преобразовывать хвостовую рекурсивную функцию в простой цикл, спецификация Java не требует, чтобы это преобразование было выполнено. Предположительно, одна из причин, по которой это не требование, состоит в том, что, вообще говоря, преобразование не может быть сделано статически на объектно-ориентированном языке. Вместо этого преобразование из хвостовой рекурсивной функции в простой цикл должно выполняться динамически с помощью JIT-компилятора.

Затем он приводит пример кода Java, который не будет преобразовываться.

Итак, как показывает пример в листинге 3, мы не можем ожидать, что статические компиляторы будут выполнять преобразование хвостовой рекурсии на Java-код, сохраняя при этом семантику языка. Вместо этого мы должны полагаться на динамическую компиляцию JIT. В зависимости от JVM JIT может или не может этого сделать.

Затем он дает тест, который вы можете использовать, чтобы выяснить, работает ли ваш JIT.

Естественно, поскольку это документ IBM, он включает в себя плагин:

Я запускал эту программу с помощью пары Java SDK, и результаты были удивительно. Запуск на солнечной точке JVM версии 1.3 показывает, что Точка доступа не выполняет преобразование. При настройках по умолчанию, пространство стека исчерпано меньше чем на моей машине. На с другой стороны, IBM JVM для версии 1.3 мурлычет без проблем, что он преобразует кода таким образом.

Ответ 2

Одна из причин, по которой я видел в прошлом не реализовывать TCO (и это воспринимается как трудная) в Java, заключается в том, что модель разрешения в JVM чувствительна к стеку, и поэтому хвостовые вызовы должны обрабатывать аспекты безопасности.

Я считаю, что это не было препятствием для Клементса и Феллесина [1] [2], и я уверен, что упоминаемый в вопросе MLVM-патч также затрагивает его.

Я понимаю, что это не отвечает на ваш вопрос; просто добавив интересную информацию.

Ответ 3

Возможно, вы уже знаете об этом, но эта функция не такая тривиальная, как может показаться, поскольку язык Java фактически предоставляет трассировку стека программисту.

Рассмотрим следующую программу:

public class Test {

    public static String f() {
        String s = Math.random() > .5 ? f() : g();
        return s;
    }

    public static String g() {
        if (Math.random() > .9) {
            StackTraceElement[] ste = new Throwable().getStackTrace();
            return ste[ste.length / 2].getMethodName();
        }
        return f();
    }

    public static void main(String[] args) {
        System.out.println(f());
    }
}

Даже если у этого есть "хвостовой вызов", он не может быть оптимизирован. (Если он оптимизирован, он по-прежнему требует учета всего пакета вызовов, поскольку семантика программы зависит от него.)

В основном это означает, что это трудно поддерживать, сохраняя при этом обратную совместимость.

Ответ 4

Java - это наименее функциональный язык, который вы могли бы себе представить (ну, ОК, возможно, не!), но это было бы большим преимуществом для JVM языки, такие как Scala.

Мои наблюдения заключаются в том, что создание JVM платформы для других языков никогда не казалось вершиной списка приоритетов для Sun, и я думаю, теперь для Oracle.