c# - HasThis 和 ExplicitThis 调用约定

标签 c# .net reflection clr calling-convention

我在 .NET Framework reference source 上遇到 HasThisExplicitThis 调用约定,因此我开始想:

  • 编译器何时设置它们?
  • 是否有使用这种调用约定组合的示例(在“现实世界”托管程序中)?

MSDN将它们描述为:

显式的

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.

有这个

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.

这是一个sample program我编写了使用这些位集生成类和构造函数的方法:

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 级别实现,也可以使用反射发射 API。
HasThisStandard 是最常用的,无需解释。
VarArgs 位,另一方面,它是为 __arglist 方法设置的:

static void VariadicMethod(__arglist)

最佳答案

我会尝试仔细回答,因为这是 ECMA 中最不太明确的主题之一,但也许我能够对此做出一些说明。

您可以跳到“返回您的问题”部分查看最终答案。


答案有点长,因为我想提供引用,所以我不会写下我的观点,而是引用。我希望它足够容易理解。如果没有,我将编辑答案并提供更多解释。

引文中的重点是我的。一些引言被删除。

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

来自 CoreCLR

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

函数指针是一种调用非托管方法的方法。

Unmanaged methods can also be called via function pointers.

函数指针可以通过calli指令调用

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.

更多相关信息

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.

还有

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.

调用站点说明

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

方法签名与平均值兼容

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


回到你的问题

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

ExplicitThis 只能仅在通过 calli 指令调用函数指针时使用。

据我所知,C# 编译器不会生成 calli 指令,因此您不会看到任何设置该位的 C# 代码。


引用文献

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

关于c# - HasThis 和 ExplicitThis 调用约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53939755/

相关文章:

.net - 是什么导致 WPF 应用程序中出现 InvalidDeploymentException?

reflection - 通过 MetadataType 属性获取应用于生成实体的自定义属性

c# - 如何使用没有主键的 SqlAdapter.Update 更新表

c# - 如何查看系统音频是否静音?

.net - 为什么 NUnit 在命令行中挂起,但在 TestDriven.NET 下却没有挂起?

c# - 方法参数和重载

c# - 从 Mono 2.8.2 中的 methodInfo 创建委托(delegate)

c# - 如何反射(reflection)没有参数的方法?

c# - 如何获取测试用例描述?

c# - 是否可以在不序列化的情况下将对象从 SilverLight 传递到 JavaScript?