Как динамические языки JITT?

Как динамически типизированный код JIT компилируется в машинный код в динамических языках? Более конкретно: делает ли компилятор в какой-то момент выводы о типах? Или это строго трактуется в этих случаях?

Например, если у меня есть что-то вроде следующего псевокода

def func(arg)
    if (arg)
        return 6
    else
        return "Hi"

Как платформа выполнения может знать перед запуском кода, какой тип возвращаемого значения имеет функция?


person Dan    schedule 28.08.2012    source источник


Ответы (1)


В общем, нет. Однако он может принимать любой тип и оптимизировать для этого. Детали зависят от того, что это за JIT.

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

; calculate arg
guard_true(arg)
boxed_object o1 = box_int(6)
guard_is_boxed_int(o1)
int i1 = unbox_int(o1)
int i2 = 1
i3 = add_int(res2, res3)

а затем оптимизирует его так:

; calculate arg
; may even be elided, arg may be constant without you realizing it
guard_true(arg)
; guard_is_boxed_int constant-folded away
; unbox_int constant-folded away
; add_int constant-folded away
int i3 = 7

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

Другие JIT придерживаются более статичного подхода. Например, вы можете быстро и неточно определить тип, чтобы распознать хотя бы несколько операций. Некоторые JIT-компиляторы работают только в области видимости функции (некоторые из них их называют JIT-компиляторами методов), поэтому они, вероятно, не могут сделать большую часть вашего фрагмента кода (одна из причин, по которой отслеживание JIT-компиляторов очень популярно). Тем не менее они существуют - примером является последняя версия движка JavaScript Mozilla, Ion Monkey, хотя, по-видимому, также черпает вдохновение в трассировке JIT. Вы также можете добавить не всегда корректные оптимизации (например, встроить функцию, которая может быть изменена позже) и удалить их, когда они станут неправильными.

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

person Community    schedule 28.08.2012