Понятно, что Microsoft возится со своим x64 abi. Что именно они сделали и когда, однако, совершенно неясно, документация неполная, разбросанная и плохо датированная. Я лично считаю работу по обратному инжинирингу, проделанную Агнером Фогом, единственным действительно надежным источником информации. Однако он не занимается генерацией управляемого кода.
Утверждение, что это было изменено в 4.5, довольно неправдоподобно. Гораздо более вероятно, что это было изменено в RyuJIT, новом джиттере x64, чтобы заменить довольно глючный и неуправляемый джиттер x64. Первоначально выпущенный в предварительной версии как 4.5.3, что, возможно, объясняет претензию 4.5, но позже был увеличен до 4.6. Вероятным источником вдохновения для этого изменения является проект .NETCore, разница abi Microsoft x64 с генераторами кода Unix (GNU и LLVM) довольно болезненна.
Но в отличие от изменений генератора кода компилятора C++ (модифицированных в обновлении VS2015 в соответствии с Agner Fog, gack), это изменение вряд ли сломается. Несоответствие могло произойти только в pinvoke, джиттер никогда не поддерживал CallingConvention.ThisCall. К счастью, на ваши вопросы легко ответить:
Что означает буфер?
Это имеет значение только для методов, которые возвращают "агрегатный тип". Другими словами, значение, которое больше не помещается в регистры ЦП. В C# это struct
, с дополнительным условием, что он должен быть нетривиальным (более 2 членов или нетривиальный тип поля).
Вызывающий метод должен выделить место в своем кадре стека для возвращаемого значения («буфер») и передать указатель на это пространство. Этот указатель передается как скрытый дополнительный аргумент метода. Традиционно первый аргумент перед скрытым аргументом this
. Это сделало this
вторым аргументом и, следовательно, передавалось через регистр RDX вместо регистра RCX. Изменение меняет порядок, this
всегда является первым аргументом и передается через RCX, указатель возвращаемого значения является вторым. Вызванный метод копирует возвращаемое значение в этот буфер перед возвратом.
Как насчет того, чтобы использовать статический класс
Относится только к статическому методу. Тогда нет дополнительного скрытого аргумента this
, поэтому он просто опускается. По сути, никаких изменений по сравнению с тем, как это было сделано раньше, скрытый указатель возвращаемого значения автоматически всегда является первым аргументом и, таким образом, передается через RCX.
Если это важно для вас, обязательно воспользуйтесь окном Debugger > Windows > Disassembly. Запустите его на небольшой тестовой программе, она легко подскажет, какие регистры используются.
person
Hans Passant
schedule
22.08.2016