Подтвердить что ты не робот

Как обобщить компиляцию компилятора JIT?

Я знаю, что generics скомпилированы JIT (как и все остальное), в отличие от шаблонов, которые генерируются при компиляции кода.
Дело в том, что новые родовые типы могут быть созданы во время выполнения, используя отражение.
Это может, конечно, повлиять на общие ограничения. Который уже прошел семантический парсер.

Может кто-нибудь объяснить, как это обрабатывается? И что именно происходит?
 (И генерация кода, и семантическая проверка)

4b9b3361

Ответ 1

Я рекомендую читать Generics в С#, Java и С++: Беседа с Андерсом Хейльсбергом.

Qn 1. Как обобщить обобщения JIT-компилятор?

Из интервью:

Андерс Хейлсберг: [...] В CLR [Common Language Runtime] когда вы компилируете List или любой другой общий тип, он компилируется до IL [Промежуточный язык] и метаданные как и любой нормальный тип. ИЛ и метаданные содержат дополнительные информация, которая знает там тип параметр, конечно, но в принцип, обобщенный тип компиляции просто так, как любой другой тип компиляции. Во время выполнения, когда ваш приложение делает свою первую ссылку к списку, система смотрит на если кто-то уже попросил List<int>. Если нет, он загружается в JIT IL и метаданные для List<T>и аргумент типа int. JITER, в процессе JITing IL, также заменяет параметр типа.

[...]

Теперь, что мы делаем тогда для всех типов экземпляры, которые являются значениями типы, такие как List<int>, List<long>, List<double>, List<float> - мы создаем уникальная копия исполняемого файла код. Таким образом, List<int> получает свой собственный код. List<long> получает свой собственный код. List<float> получает свой собственный код. Для всех ссылочные типы, которыми мы разделяем код, потому что они репрезентативно идентичны. Это просто указатели.


Qn 2. Дело в том, что новые типовые типы могут быть созданы во время выполнения, используя отражение. Что может, конечно, повлиять общие ограничения. Который уже прошел семантический парсер. Может кто-нибудь объяснить, как это обрабатываются?

По сути, IL сохраняет высокоуровневое представление общих типов, что позволяет CLR проверять ограничения на "динамически построенные" общие типы во время выполнения так же, как компилятор С# может делать для "статически построенных" типов в источнике С# -код во время компиляции.

Вот еще один фрагмент (акцент мой):

Андерс Хейлсберг: [...] С ограничением вы можете динамическая проверка вашего кода и проверить его во время компиляции или время загрузки.. Когда вы говорите, что K должен реализовать IComparable, пару всякое случается. При любом значении типа K, теперь вы можете напрямую получить доступ к интерфейсные методы без литья, потому что семантически в программе он гарантировал, что он будет реализовывать этот интерфейс. Всякий раз, когда вы пытаетесь создать экземпляр этого типа, компилятор проверяет, что любой тип вы даете в качестве аргумента K аргументы IComparable, иначе вы получите компиляцию временная ошибка. Или, если вы делаете это с вы получаете исключение.

Брюс Эккел: Вы сказали, что компилятор и время выполнения.

Андерс Хейлсберг: Проверка компилятора это, но вы также можете сделать это на времени выполнения с отражением, а затем система проверяет его. Как я уже говорил, все, что вы можете сделать во время компиляции, вы также можете выполнять во время работы с отражение.

Ответ 2

Обозначения типов generics все становятся такими же; генерируемые значения типа отдельно.

Это потому, что ссылочные типы - это всего лишь Object ссылки (4 или 8 байтов), тогда как типы значений различны и не могут обрабатываться одним фрагментом кода из-за различий в расположении стека и т.д. Поэтому, несколько копий родового типа с типами значений увеличивают использование памяти на много, тогда как экземпляры нескольких копий со ссылочными типами не будут.