.NET MSIL: Как команды определяют размер операндов?
Есть один add
команда в MSIL для добавления двух аргументов (извлечение из стека, добавление, вставка в стек). Как он узнает, должен ли он вытолкнуть 2 байта или 4 или 8 байтов?
В java разные байт-коды (fadd, dadd, iadd, ...), но как они справляются с этим в.NET?
3 ответа
Байт-код Java был оптимизирован для выполнения интерпретатором, в ранних JVM еще не было Hotspot. .NET msil был спроектирован с первого дня, чтобы всегда сочетаться, специальные опкоды для разных типов операндов не требовались.
Джиттер знает тип операнда из состояния стека. Какой бы код операции не поместил значение в стек, он также указывает на тип. Скажем, Opcodes.Ldarg_0, джиттер знает тип по сигнатуре метода. Отслеживание состояния стека - это то, что вам никогда не нужно делать в интерпретаторе, это значительно замедляет выполнение кода, джиттер должен делать это только один раз.
Из раздела I инфраструктуры общего языка (CLI): концепции и архитектура, раздел 12.1:
... CLI поддерживает только подмножество этих типов в своих операциях над значениями, хранящимися в его стеке оценки -
int32
,int64
, а такжеnative int
, Кроме того, CLI поддерживает внутренний тип данных для представления значений с плавающей запятой во внутреннем стеке оценки....
Как описано ниже, инструкции CIL не указывают свои типы операндов. Вместо этого CLI отслеживает типы операндов, основываясь на потоке данных и опираясь на требование согласованности стека, описанное ниже. Например, сингл
add
Инструкция добавит два целых числа или два числа с плавающей точкой из стека.
"Ниже" обсуждение согласованности стека относится к разделу 12.3.2.1:
Стек оценки состоит из слотов, которые могут содержать любой тип данных, включая распакованный экземпляр типа значения. Состояние типа стека (глубина стека и типы каждого элемента в стеке) в любой заданной точке программы должно быть идентичным для всех возможных путей потока управления. Например, программа, которая зацикливается на неизвестное число раз и помещает новый элемент в стек на каждой итерации, будет запрещена.
То есть всякий раз, когда он сталкивается с add
инструкция, он всегда знает "форму" стека в точке и поэтому может построить правильные собственные инструкции. И все равно он работает с ограниченным набором типов.
(Другие спецификации для CLI можно найти на этой странице)
Если вы напишите тестовую программу на C# и декомпилируете ее в MSIL, вы увидите, что размер установлен ldc
или же conv
инструкции перед add
называется.