HasThis & ExplicitThis calling conventions

时光毁灭记忆、已成空白 提交于 2021-01-27 18:40:35

问题


I come across HasThis and ExplicitThis calling conventions on .NET Framework reference source, and thus I begin to wonder:

  • When are they set by compiler?
  • Are there any examples using this combination of calling conventions (in "real world" managed program)?

MSDN has described them as:

ExplicitThis

Specifies that the signature is a function-pointer signature, representing a call to an instance or virtual method (not a static method). If ExplicitThis is set, HasThis must also be set. The first argument passed to the called method is still a this pointer, but the type of the first argument is now unknown. Therefore, a token that describes the type (or class) of the this pointer is explicitly stored into its metadata signature.

HasThis

Specifies an instance or virtual method (not a static method). At run-time, the called method is passed a pointer to the target object as its first argument (the this pointer). The signature stored in metadata does not include the type of this first argument, because the method is known and its owner class can be discovered from metadata.

Here is a sample program I wrote to generate a class and constructor using these bits set:

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
                    );

What is known so far:
It is not possible to change method's calling convention using C# syntax. This is only possible at IL level, also using Reflection emit API.
HasThis and Standard are the most commonly used, there is no need to explain these.
VarArgs bit, on the other hand, it is set for __arglist method:

static void VariadicMethod(__arglist)

回答1:


I will try to answer carefully because it's one of the most less clear subject in ECMA but maybe I will be able to shed some light on this.

You can skip to "Back to your question" section to see the final answer.


The answer is a little long because I want to bring a reference so instead of writing my opinion I'll quote. I hope it will be understandable enough. If not, I'll edit the answer with more explanations.

The emphases in quotations are mine. Some quotes were cut.

The EXPLICITTHIS (0x40) bit can be set only in signatures for function pointers: signatures whose MethodDefSig is preceded by FNPTR

From CoreCLR

EXPLICITTHIS and native call convs are for stand-alone sigs only (for calli)

Function pointers is a way to call unmanaged methods.

Unmanaged methods can also be called via function pointers.

Function pointers can be called via calli instruction

Method pointer shall store the address of the entry point to a method whose signature is method-signature-compatible-with the type of the method pointer. A method can be called by using a method pointer with the calli instruction.

More about it

Correct CIL requires that the function pointer contains the address of a method whose signature is method-signature compatible-with that specified by callsitedescr and that the arguments correctly correspond to the types of the destination function’s this pointer, if required, and parameters. For the purposes of signature matching, the HASTHIS and EXPLICITTHIS flags are ignored; all other items must be identical in the two signatures.

And

The calli instruction includes a call site description that includes information about the native calling convention that should be used to invoke the method. Correct CIL code shall specify a calling convention in the calli instruction that matches the calling convention for the method that is being called.

Call site description

Ccall site description (represented as a metadata token for a stand-alone call signature) that provides: • The number of arguments being passed. • The data type of each argument. • The order in which they have been placed on the call stack. • The native calling convention to be used

Method-signature-compatible-with mean

A method signature type T is method-signature compatible-with a method signature type U if and only if: 1. For each signature, independently, if the signature is for an instance method it carries the type of this. [Note: This is always true for the signatures of instance method pointers produced by ldvirtftn instruction. 2. The calling conventions of T and U shall match exactly, ignoring the distinction between static and instance methods (i.e., the this parameter, if any, is not treated specially).


Back to your question

  • When are they set by compiler?
  • Are there any examples using this combination of calling conventions (in "real world" managed program)?

ExplicitThis can be using only when calling function pointers via calli instruction.

AFAIK the C# compiler not generating calli instruction, so you will not see any C# code that set this bit.


References

C# compiler won't generate calli instructions

Roslyn source code

EXPLICITTHIS and native call convs are for stand-alone sigs only (for calli)

Signatures under the hood

ECMA




回答2:


The first thing that comes to mind about those two flags are Extension Methods, there's even some information on how the binding of those methods is done while the code is being compiled.

Hope it helps!



来源:https://stackoverflow.com/questions/53939755/hasthis-explicitthis-calling-conventions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!