Указатель "this" в документе clr abi
Только для AMD64: до.NET Framework 4.5 управляемый указатель "this" обрабатывался так же, как и собственный указатель "this" (то есть это был второй аргумент, когда вызов использовал буфер возврата и передавался в RDX вместо RCX),
Я нашел вышеупомянутое утверждение в документе clr abi, исходя из моего понимания, что это до.NET Framework 4.5, указатель "this" был вторым аргументом, когда вызов использовал буфер возврата и был передан в RDX;
Итак, у меня есть два вопроса:
Какой смысл для буфера? Буфер, ссылающийся на буфер потока, такой как httpwebresponse или что-нибудь еще?
Как насчет того, чтобы использовать статический класс, я думаю, что в этом случае не существует указателя "this", и вышеприведенный оператор указан для объекта экземпляра, верно?
1 ответ
Понятно, что Microsoft возилась с их x64 abi. Точно то, что они сделали и когда, однако, совершенно неясно, документация неполна, точна и плохо датирована. Я лично считаю, что работы по реинжинирингу, выполненные Agner Fog, являются исключительно надежным источником информации. Однако он не занимается управляемой генерацией кода.
Утверждение, что это было изменено в 4.5, довольно неправдоподобно. Гораздо более вероятно, что это было изменено в RyuJIT, новом джиттере x64, чтобы заменить довольно глючный и не поддерживаемый устаревший джиттер x64. Первоначально выпущен в превью как 4.5.3, возможно, объясняя претензию 4.5, но позже увеличен до 4.6. Вероятным источником вдохновения для этого изменения является проект.NETCore, отличия Microsoft x64 abi от генераторов кода Unix (GNU и LLVM) довольно болезненны.
Но в отличие от изменений генератора кода компилятора C++ (измененных в обновлении VS2015 согласно Agner Fog, gack), это изменение вряд ли будет нарушено. Несоответствие могло произойти только в pinvoke, джиттер никогда не поддерживал CallingConvention.ThisCall. К счастью, на ваши вопросы легко ответить:
Какой смысл для буфера?
Это имеет значение только для методов, которые возвращают "агрегатный тип". Другими словами, значение, которое больше не помещается в ЦП, больше регистрируется. В C# это struct
с дополнительным условием, что он должен быть нетривиальным (более 2 членов или нетривиальный тип поля).
Вызывающий метод должен выделить пространство в своем кадре стека для возвращаемого значения ("буфер") и передать указатель на это пространство. Этот указатель передается как скрытый дополнительный аргумент в метод. Традиционно первый аргумент, прежде чем скрытый this
аргумент. Это сделало this
второй аргумент и, следовательно, был передан через регистр RDX вместо регистра RCX. Изменение меняет порядок, this
всегда является первым аргументом и передается через RCX, указатель возвращаемого значения - второй. Вызываемый метод копирует возвращаемое значение в этот буфер до его возврата.
Как насчет того, если мы используем статический класс
Относится только к статическому методу. Тогда нет лишних скрытых this
аргумент, поэтому он просто опущен. По сути, никаких изменений по сравнению с тем, как это было сделано ранее, указатель скрытого возвращаемого значения автоматически всегда становится первым аргументом и, таким образом, передается через RCX.
Если это важно для вас, обязательно воспользуйтесь окном Debugger's Debug > Windows > Disassembly. Запустите его на небольшой тестовой программе, он легко подскажет, какие регистры используются.