JIT является одним из аспектов CLR.
В частности, именно эта часть отвечает за преобразование CIL / MSIL (в дальнейшем называемого IL), созданного компилятором исходного языка (например, csc.exe для Microsoft c #), в машинный код, родной для текущего процессора (и архитектуры, которую он предоставляет в текущий процесс, например 32 / 64bit). Если рассматриваемая сборка была ngen'd, тогда процесс JIT совершенно не нужен, и CLR без проблем выполнит этот код.
Перед использованием метода, который еще не был преобразован из промежуточного представления, JIT несет ответственность за его преобразование.
Точно когда сработает JIT, зависит от конкретной реализации и может быть изменено. Однако проект CLR требует, чтобы JIT происходил за до , когда соответствующий код выполняется, а JVM, напротив, может свободно интерпретировать код некоторое время, пока отдельный поток создает представление машинного кода.
«Обычный» CLR использует подход pre-JIT-заглушки , где методы JIT компилируются только по мере их использования. Это подразумевает, что исходная заглушка нативного метода является косвенным указанием JIT скомпилировать метод, а затем изменить исходный вызов, чтобы пропустить начальную заглушку. Вместо этого текущая компактная версия компилирует все методы для типа при его загрузке.
Для решения вопроса добавления Generics.
Это было последнее значительное изменение спецификации IL и JIT с точки зрения его семантики, а не внутренних деталей реализации.
Было добавлено несколько новых инструкций IL, и было предоставлено больше опций метаданных для типов инструментов и элементов.
Ограничения были добавлены и на уровне IL.
Когда JIT компилирует метод, который имеет общие аргументы (явно или неявно через содержащий класс), он может устанавливать различные пути кода (инструкции машинного кода) для каждого используемого типа. На практике JIT использует общую реализацию для всех ссылочных типов, поскольку переменные для них будут иметь одинаковую семантику и занимать одинаковое пространство (IntPtr.Size).
Каждый тип значения получит определенный код, сгенерированный для него, и главной причиной этого является уменьшение / увеличение размера переменных в стеке / куче. Кроме того, путем выдачи ограниченного кода операции перед вызовом метода многим вызовам не ссылочных типов не нужно указывать значение для вызова метода (эта оптимизация также используется в неуниверсальных случаях). Это также позволяет правильно обрабатывать поведение по умолчанию <T>
и исключать операции сравнения со значением NULL в виде отсутствия операций (всегда false), когда используется тип значения, отличный от Nullable.
Если во время выполнения предпринята попытка создать экземпляр универсального типа с помощью отражения, тогда параметры типа будут проверены средой выполнения, чтобы убедиться, что они проходят любые ограничения. Это напрямую не влияет на JIT, если только он не используется в системе типов (маловероятно, хотя возможно).