HasThis & ExplicitThis соглашения о вызовах - PullRequest
0 голосов
/ 27 декабря 2018

Я сталкиваюсь с HasThis и ExplicitThis соглашениями о вызовах для .NET Framework ссылочного источника , и поэтому я начинаю задумываться:

  • Когда они устанавливаются компилятором?
  • Существуют ли примеры, использующие эту комбинацию соглашений о вызовах (в управляемой программе "реального мира")?

MSDN описывает их как:

ExplicitThis

Указывает, что подпись является подписью указателя функции, представляющей вызов экземпляра или виртуального метода (не статического метода).Если установлено ExplicitThis, также должно быть установлено HasThis.Первый аргумент, передаваемый вызываемому методу, все еще является указателем this, но тип первого аргумента теперь неизвестен.Поэтому токен, который описывает тип (или класс) указателя this, явно сохраняется в его сигнатуре метаданных.

HasThis

Указывает экземпляр или виртуальный метод (не статический метод).Во время выполнения вызываемому методу передается указатель на целевой объект в качестве первого аргумента (указатель this).Сигнатура, хранящаяся в метаданных, не включает тип этого первого аргумента, поскольку метод известен, и его класс владельца может быть обнаружен из метаданных.

Вот пример программы , которую я написал, чтобы сгенерировать класс и конструктор, используя набор следующих битов:

const string FileName = "MyDynamicLib.dll";
AppDomain currentDomain = AppDomain.CurrentDomain;

AssemblyName assemblyName = new AssemblyName(assemblyName: "MyAssembly");
AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly(
                                                                      name  : assemblyName,
                                                                      access: AssemblyBuilderAccess.RunAndSave
                                                                     );
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(
                                                                  name          : "MyModule",
                                                                  fileName      : FileName,
                                                                  emitSymbolInfo: true
                                                                 );

TypeBuilder typeBuilder = moduleBuilder.DefineType(
                                                   name: "MyClass",
                                                   attr: TypeAttributes.Public | TypeAttributes.BeforeFieldInit
                                                  );
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
                                                                      attributes       : MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                                                                      callingConvention: CallingConventions.HasThis | CallingConventions.ExplicitThis,
                                                                      parameterTypes   : null
                                                                     );
constructorBuilder.GetILGenerator().Emit(opcode: OpCodes.Ret);
typeBuilder.CreateType();

assemblyBuilder.Save(
                     assemblyFileName      : FileName,
                     portableExecutableKind: PortableExecutableKinds.Required32Bit,
                     imageFileMachine      : ImageFileMachine.I386
                    );

Что известно до сих пор:
Невозможно изменить соглашение о вызовах метода с использованием синтаксиса C #.Это возможно только на уровне IL, также с использованием Reflection emit API.
HasThis и Standard - наиболее часто используемые, объяснять это не нужно. С другой стороны,
VarArgs bit, он установлен для __arglist метода:

static void VariadicMethod(__arglist)

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Я постараюсь ответить осторожно, потому что это одна из самых неясных тем в ECMA, но, возможно, я смогу пролить свет на это.

Вы можете перейти к разделу «Назад к вашему вопросу»чтобы увидеть окончательный ответ.


Ответ немного длинный, потому что я хочу привести ссылку, поэтому вместо того, чтобы писать свое мнение, я процитирую.Надеюсь это будет достаточно понятно.Если нет, я отредактирую ответ с дополнительными пояснениями.

Подчеркивания в цитатах мои.Некоторые цитаты были обрезаны.

Бит EXPLICITTHIS (0x40) может быть установлен только в сигнатурах для указателей на функции: сигнатуры, которым перед MethodDefSig предшествует FNPTR

Из CoreCLR

EXPLICITTHIS и нативные конвы вызовов предназначены только для автономных подписчиков (для calli)

Указатели на функцию - это способ вызова неуправляемых методов.

Неуправляемые методы также можно вызывать с помощью указателей на функции.

Указатели функций можно вызывать с помощью calli инструкции

Указатель метода должен хранить адрес точки входа для метода, сигнатура которого равна method-signature-compatible-with типауказатель метода.Метод можно вызвать с помощью указателя метода с инструкцией calli.

Подробнее об этом

Правильный CIL требует, чтобы указатель функции содержал адрес метода, чья сигнатура method-signature compatible-with указана callsitedescr, и что аргументыПравильно соответствуют типам функции указателя this, если требуется, и параметрам.В целях сопоставления подписи флаги HASTHIS и EXPLICITTHIS игнорируются;все остальные элементы должны быть идентичны двум подписям.

И

Инструкция calli содержит call site description, который включает в себя информацию о собственном соглашении о вызовах, которое следует использовать для вызова метода.Правильный код CIL должен указывать соглашение о вызовах в инструкции calli, которое соответствует соглашению о вызовах для вызываемого метода.

Описание сайта вызова

Ccall siteописание (представленное как токен метаданных для stand-alone call signature), которое обеспечивает: • Количество передаваемых аргументов.• Тип данных каждого аргумента .• Порядок, в котором они были размещены в стеке вызовов.• Собственное соглашение о вызовах, которое будет использоваться

Метод-подпись-совместимый-со средним

Тип сигнатуры метода T совместим с сигнатурой метода-тип сигнатуры методаU тогда и только тогда, когда: 1. Для каждой подписи независимо, если подпись предназначена для метода экземпляра, она имеет тип this.[Примечание: это всегда верно для сигнатур указателей метода экземпляра, созданных инструкцией ldvirtftn.2. Соглашения о вызовах T и U должны точно совпадать, игнорируя различие между статическими и экземплярами методов (т. Е. Параметр this, если таковой имеется, специально не обрабатывается).


Назадна ваш вопрос

  • Когда они установлены компилятором?
  • Есть ли примеры использования этой комбинации соглашений о вызовах (в управляемой программе "реального мира")?

ExplicitThis может использоваться только при вызове указателей на функции с помощью инструкции calli.

AFAIK компилятор C # не генерирующий calli инструкцию, поэтому вы не увидите кода C #, который устанавливает этот бит.


Ссылки

C # компилятор не будет генерировать инструкции калли

Исходный код Roslyn

EXPLICITTHIS и собственные вызовы являются автономнымитолько сиги (для калли)

подписи под капотом

ECMA

0 голосов
/ 27 декабря 2018

Первое, что приходит на ум в связи с этими двумя флагами: Методы расширения , есть даже некоторая информация о , как выполняется привязка этих методов во время компиляции кода .

Надеюсь, это поможет!

...