HasThis 和 ExplicitThis 调用约定
HasThis & ExplicitThis calling conventions
我在 .NET Framework reference source 上遇到 HasThis
和 ExplicitThis
调用约定,因此我开始怀疑:
- 编译器什么时候设置它们?
- 是否有使用这种调用约定组合的示例(在 "real world" 托管程序中)?
MSDN 将它们描述为:
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.
有这个
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 生成一个 class 和使用这些位集的构造函数:
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
位,另一方面,它是为 __arglist
方法设置的:
static void VariadicMethod(__arglist)
关于这两个标志首先想到的是Extension Methods, there's even some information on how the binding of those methods is done while the code is being compiled。
希望对您有所帮助!
我会尽量认真回答,因为它是 ECMA 中最不明确的主题之一,但也许我能对此有所阐明。
您可以跳到 "Back to your question" 部分查看最终答案。
答案有点长,因为我想带一个参考,所以我不会写我的意见,而是引用。我希望它能被充分理解。如果没有,我将编辑答案并提供更多解释。
引文中的重点是我的。一些引用被删减了。
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
EXPLICITTHIS and native call convs are for stand-alone sigs only (for calli)
我在 .NET Framework reference source 上遇到 HasThis
和 ExplicitThis
调用约定,因此我开始怀疑:
- 编译器什么时候设置它们?
- 是否有使用这种调用约定组合的示例(在 "real world" 托管程序中)?
MSDN 将它们描述为:
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 athis
pointer, but the type of the first argument is now unknown. Therefore, a token that describes the type (or class) of thethis
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 生成一个 class 和使用这些位集的构造函数:
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
位,另一方面,它是为 __arglist
方法设置的:
static void VariadicMethod(__arglist)
关于这两个标志首先想到的是Extension Methods, there's even some information on how the binding of those methods is done while the code is being compiled。
希望对您有所帮助!
我会尽量认真回答,因为它是 ECMA 中最不明确的主题之一,但也许我能对此有所阐明。
您可以跳到 "Back to your question" 部分查看最终答案。
答案有点长,因为我想带一个参考,所以我不会写我的意见,而是引用。我希望它能被充分理解。如果没有,我将编辑答案并提供更多解释。
引文中的重点是我的。一些引用被删减了。
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 thecalli
instruction.
更多信息
Correct CIL requires that the function pointer contains the address of a method whose signature is
method-signature compatible-with
that specified bycallsitedescr
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 acall 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 thecalli
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
EXPLICITTHIS and native call convs are for stand-alone sigs only (for calli)