HasThis 和 ExplicitThis 调用约定

2024-04-17

我遇到HasThis and ExplicitThis调用约定.NET框架参考源 https://referencesource.microsoft.com/#mscorlib/system/reflection/callingconventions.cs,0e671adbca70e090,因此我开始怀疑:

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

MSDN https://learn.microsoft.com/en-us/dotnet/api/system.reflection.callingconventions将它们描述为:

显式这个

指定签名是函数指针签名,表示对实例或虚拟方法(不是静态方法)的调用。如果ExplicitThis已设定,HasThis也必须设置。传递给被调用方法的第一个参数仍然是this指针,但第一个参数的类型现在未知。因此,描述该类型(或类)的标记this指针显式存储到其元数据签名中。

HasThis

指定实例或虚拟方法(不是静态方法)。在运行时,被调用的方法将传递一个指向目标对象的指针作为其第一个参数(this指针)。存储在元数据中的签名不包括第一个参数的类型,因为该方法是已知的并且可以从元数据中发现其所有者类。

这里有一个示例程序 https://dotnetfiddle.net/NRLH08我编写了使用这些位集生成一个类和构造函数的方法:

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。
HasThis and Standard这些都是最常用的,无需解释。
VarArgs位,另一方面,它被设置为__arglist方法:

static void VariadicMethod(__arglist)

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

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


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

引文中的强调是我的。一些引言被删掉了。

EXPLICITTHIS (0x40) 位只能设置在函数指针的签名中:签名其 MethodDefSig 前面是 FNPTR

来自 CoreCLR

EXPLICITTHIS 和本机调用转换仅适用于独立信号(对于愈伤组织)

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

非托管方法也可以通过函数指针调用。

函数指针可以通过调用calli操作说明

方法指针应存储其签名的方法的入口点地址 是method-signature-compatible-with方法指针的类型。可以通过使用方法指针和calli操作说明。

更多相关信息

正确的 CIL 要求函数指针包含其签名的方法的地址 是method-signature compatible-with由指定的callsitedescr并且这些论点 如果需要,正确对应于目标函数的 this 指针的类型,并且 参数。为了签名匹配的目的,HASTHIS 和 EXPLICITTHIS 标志是 被忽视;两个签名中的所有其他项目必须相同。

And

The calli指令包括一个call site description其中包括有关本机调用的信息 应该用于调用该方法的约定。正确的 CIL 代码应在calli与正在调用的方法的调用约定相匹配的指令。

调用站点说明

呼唤站点 描述(表示为元数据标记stand-alone call signature) 提供: • 传递的参数数量。 • 这每个参数的数据类型。 • 它们在调用堆栈上的放置顺序。 • 要使用的本机调用约定

方法签名与均值兼容

方法签名类型 T 与方法签名类型 U 方法签名兼容,如果 并且仅当: 1. 对于每个签名,独立地,如果该签名是针对其携带的实例方法 这个的类型。 [注意:对于实例方法指针的签名始终如此 由 ldvirtftn 指令生成。 2、T和U的调用约定要完全匹配,忽略区别 静态方法和实例方法之间(即 this 参数,如果有的话,不被处理 特别)。


回到你的问题

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

ExplicitThis can仅在通过调用函数指针时使用calli操作说明。

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


参考

C#编译器不会生成calli指令 https://blogs.msdn.microsoft.com/shawnfa/2004/06/14/calli-is-not-verifiable/

罗斯林源代码 https://github.com/dotnet/roslyn

EXPLICITTHIS 和本机调用转换仅适用于独立信号(对于愈伤组织) https://github.com/dotnet/coreclr/blob/03f0b6d5f97a5d65387cad5fd0f60342d3118047/src/utilcode/util.cpp#L2140

引擎盖下的签名 https://www.codeproject.com/Articles/42649/%2FArticles%2F42649%2FNET-file-format-Signatures-under-the-hood-Part-1

ECMA https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HasThis 和 ExplicitThis 调用约定 的相关文章

随机推荐

  • 为什么链接时会出现多重定义错误?

    我使用这两个文件here https raw github com elanthis easylogger master easylogger h and here https raw github com elanthis easylog
  • 如何在Java中从字符串中提取多个整数? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我得到了一系列像这样的字符串 123
  • 如何解析 Perl 中的符号链接?

    我有一个象征性的名字java or jre or jre1 5 or jre1 6 or java1 5 or java1 6它将指向相应的目录 考虑到第一个实例 它看起来像 java gt usr java jdk1 5 x x 我的目标
  • NeDB中如何实现持久化存储?

    我在 node webkit 中尝试了 NeDB 它在内存数据上运行良好 但无法存储在持久存储中 绝对没有 node webkit 或 nedb 专家 但这就是我所做的并且它有效 正如 mvanderw 在评论中已经提到的 一定要确保检查自
  • 在 git 中查找文件的第一次提交

    情况 我有一个来自 github 项目的 tar gz 版本 但想弄清楚这是从哪个提交中获取的 它似乎没有被标记 或者从提交消息本身来看是显而易见的 所以我可以计算文件的 sha1 但想知道这些文件属于哪个提交 召唤 git 向导 由于 g
  • 读取图像并确定其是否损坏 C#

    如何确定作为原始字节的图像是否已损坏 是否有任何开源库可以处理 C 中多种格式的此问题 Thanks 尝试从该文件创建 GDI 位图 如果创建 Bitmap 对象失败 则您可以假设图像已损坏 GDI 支持多种文件格式 http msdn m
  • 将代码从 openCV 更新到 openCV2

    我正在尝试将 python 中的一些代码从 openCV 更新为 openCV2 原代码如下 self capture cv CaptureFromCAM 0 cv SetCaptureProperty self capture cv CV
  • 按 SQL IN() 子句中值的顺序排序

    我想知道是否有 可能是更好的方法 按 IN 子句中的值的顺序进行排序 问题是我有 2 个查询 一个查询获取所有 ID 第二个查询检索所有信息 第一个创建了我希望第二个按照其排序的 ID 顺序 ID 以正确的顺序放入 IN 子句中 所以它会像
  • Excel VBA - 1004 运行时错误、应用程序或对象定义错误

    我正在尝试浏览工作表中的一系列单元格并在每个单元格中编写一个公式 但我不断收到错误 Run time error 1004 Application defined or object defined error 代码现在看起来像这样 Sub
  • 可参数化的 JSR-303 验证值

    我使用 JSR 303 bean 验证和 Spring 3 我需要根据用例为注释提供不同的值 例如 值min参数输入 Size min 对于某些验证必须为 1 对于另一种情况必须为 5 我想从属性文件中读取此值 我知道可以从中读取消息参数V
  • C 控制台底部的输入栏

    窗底 一些应用程序 如 vim mutt aptitude 包含 用于输出的顶部窗口部分和 底部供用户输入或显示状态 假设有一个子进程用于输出 另一个子进程用于接受用户输入 目的是允许在您键入输入或查看状态的同时更新输出 Actions U
  • Access 2010编译错误用户定义类型未定义

    我将 2003 年的数据库转换为 2010 年的数据库 并且 2003 年创建的 VBA 脚本在 2010 年不起作用 我收到一条消息 指出存在 编译错误 未定义用户定义的类型 我没有 VBA 脚本编写经验 也没有创建脚本 但了解它在数据库
  • Spring - 如何注入具体的接口实现?

    我需要通过 Autowired 注入服务类的具体实现 服务接口 public interface PostService 执行 Service postServiceImpl public class PostServiceImpl imp
  • Cordova Momentum 在 iOS 溢出元素上滚动

    在 Safari iOS 浏览器中侦听滚动事件每次都会触发控制台消息 即使是在动量上 但在 cordova 构建的应用程序中 只有当滚动停止时才会触发 el with webkit overflow scrolling touch on s
  • 带有反向引用的简单 java 正则表达式不起作用

    我无法用正则表达式的反向引用替换字符串 没有任何东西被替换 我总是以我的输入结束 我的代码 String input A12 3 bla bla my input input StringUtils replacePattern input
  • Bootstrap下拉菜单三角形有何奥秘?

    我试图了解 Twitter Bootstrap 下拉菜单包含在导航栏中和不包含在导航栏中时的区别 当它们包含在导航栏中时 扩展菜单上会显示一个向上的三角形 箭头 当不使用导航栏时 不会显示该三角形 http twitter github c
  • 使用 WM_COPYDATA 在进程之间发送数据

    我希望在进程之间发送文本 我发现了很多这样的例子 但没有一个我可以工作 这是我到目前为止所拥有的 对于发送部分 COPYDATASTRUCT CDS CDS dwData 1 CDS cbData 8 CDS lpData NULL Sen
  • 安装 Sqlite3 for Ruby (Mac OSX 10.5.8)

    我正在遵循本 ATM 指南 http guides rubyonrails org getting started html getting up and running quickly with scaffolding http guid
  • 使用 OCaml 收集外部命令的输出

    在 OCaml 中调用外部命令并收集其输出的正确方法是什么 在Python中 我可以做这样的事情 os popen cmd read 如何在 OCaml 中获取外部程序的所有输出 或者 更好的是 带有 Lwt 的 OCaml Thanks
  • HasThis 和 ExplicitThis 调用约定

    我遇到HasThis and ExplicitThis调用约定 NET框架参考源 https referencesource microsoft com mscorlib system reflection callingconventio