Чем пришлось бы пожертвовать jvm, чтобы реализовать оптимизацию конечных вызовов?
-
06-07-2019 - |
Вопрос
Люди говорят, что реализация clojure превосходна, если не считать ограничения отсутствия оптимизации конечных вызовов - ограничения jvm, а не реализации clojure.
http://lambda-the-ultimate.org/node/2547
Было сказано, что для внедрения TCO в Python пришлось бы пожертвовать
- дампы трассировки стека и
- регулярность отладки.
Объясните мне, что такого особенного в оптимизации хвостовых вызовов и зачем это нужно Python
Должны ли быть принесены такие же жертвы для совместной реализации TCO?Пришлось бы пожертвовать чем-нибудь еще?
Решение
Несмотря на отличие (в том, что инструкции il уже существовали), стоит отметить дополнительные усилия, приложенные .Net 64-битная команда JIT пришлось пройти до конца, чтобы уважать все вызовы "хвоста".
Я обращаюсь, в частности, к комментарию:
Недостатком, конечно, является то, что если вам нужно отлаживать или профилировать оптимизированный код, будьте готовы иметь дело со стеками вызовов, которые выглядят так, как будто в них не хватает нескольких фреймов.
Я бы подумал, что крайне маловероятно, что JVM также сможет избежать этого.
Учитывая, что в обстоятельствах, когда была запрошена оптимизация хвостового вызова, JIT должен предположить, что это требуемый чтобы избежать переполнения стека, это не то, что можно просто отключить в отладочных сборках.От них мало толку для отладки, если они выходят из строя до того, как вы переходите к интересной части."Оптимизация" на самом деле является постоянной функцией и проблемой для трассировок стека, на которые она влияет.
Стоит отметить, что любая оптимизация, которая позволяет избежать создания реального фрейма стека при выполнении операции, которую программист концептуально описывает / понимает как операцию стека (например, вызов функции), по своей сути вызовет разрыв между тем, что представляется пользователю при отладке / предоставлении трассировки стека, и реальностью.
Это неизбежно, поскольку код, описывающий операцию, становится все более и более отделенным от механики конечного автомата, выполняющего операцию.
Другие советы
Работа - это сейчас идет работа чтобы добавить хвостовые вызовы в JVM.Там есть вики - страница обсуждаем некоторые детали.
Да, как правило, реализация TCO не позволит вам получить полные трассировки стека.Это неизбежно, потому что весь смысл TCO заключается в том, чтобы избежать создания дополнительных фреймов стека.
Также стоит интересно отметить, что Clojure имеет не требующую стека функцию "recur", позволяющую обойти это ограничение в текущих версиях JVM.
Пример:
(defn triangle [n accumulator]
(if
(<= n 0)
accumulator
(recur (dec n) (+ n accumulator))))
(triangle 1000000 0)
=> 500000500000 (note stack does not explode here!)