1

我正在用 C# 编写自己的脚本语言,具有一些我喜欢的特性,并且我选择使用 MSIL 作为输出的字节码(Reflection.Emit 非常有用,我不必想出另一个字节码)。它可以工作,发出可执行文件,可以运行(甚至可以使用 Reflector 反编译 :))并且速度非常快。

但是 - 我想在一个进程+一个线程中运行多个“进程”,并手动控制它们分配的 CPU 时间(也实现由 .NET 框架提供的更强大的 IPC)有没有办法完全禁用 JIT 并创建自己的VM,使用.NET框架(并控制内存使用等)在指令后步进指令,无需自己编写任何东西,或者要实现这一点,我必须编写整个MSIL解释?

编辑 1): 我知道解释 IL 并不是世界上最快的事情:)

编辑2):澄清-我希望我的VM成为某种“操作系统”-它获得一些CPU时间并将其分配给进程,控制它们的内存分配等等。它不必很快,也不必有效,而只是我的一些实验的概念证明。我不需要在处理每条指令的级别上实现它 - 如果这应该由 .NET 完成,我不会介意,我只想说:第一步指令,等到我告诉你下一步。

编辑 3):我意识到,ICorDebug 可能可以满足我的需求,现在正在查看 Mono 运行时的实现。

4

4 回答 4

5

您可以使用Mono - 我相信它允许一个选项来解释 IL 而不是 JITting 它。它是开源的这一事实意味着(取决于许可)您也应该能够根据自己的需要对其进行修改。

诚然,Mono 不具备 .NET 的所有功能——但它可以满足您的所有需求。

于 2009-03-06T13:54:08.047 回答
1

请注意,MSIL 被设计为由 JIT 编译器解析。它不太适合口译员。一个很好的例子可能是 ADD 指令。它用于添加多种值类型值:byte、short、int32、int64、ushort、uint32、uint64。您的编译器知道需要什么样的添加,但在生成 MSIL 时您会丢失该类型信息。

现在您需要在运行时找到它,这需要检查评估堆栈上的值的类型。非常慢。

易于解释的 IL 具有专用的 ADD 指令,例如 ADD8、ADD16 等。

于 2009-03-06T14:16:27.887 回答
1

Microsoft 的公共语言运行时实现只有一个执行系统,即 JIT。另一方面,Mono 同时带有 JIT 和解释器。

但是,我并不完全了解您自己到底想做什么以及您希望将什么留给微软的实施:

有没有办法完全禁用 JIT 并创建自己的 VM?

...无需我自己写任何东西,或者为了实现这一点,我必须编写整个 MSIL 解释?

有点矛盾。

如果你认为,你可以写出比微软的 JIT 更好的执行系统,你将不得不从头开始编写它。但是请记住,microsoft 和 monos JIT 都是高度优化的编译器。(编程语言枪战)

在用户模式下,无法准确地为操作系统进程安排 CPU 时间。这就是操作系统的任务。

一些绿色线程的实现可能是一个想法,但这绝对是非托管代码的主题。如果这是您想要的,请查看 CLR 托管 API。

我建议您尝试在 CIL 中实现您的语言。毕竟,它被编译为原始 x86。如果您不关心可验证性,则可以在必要时使用指针。

于 2009-03-06T14:35:58.010 回答
1

您可以考虑做的一件事是以状态机样式生成代码。让我解释一下我的意思。

当您在 C# 中使用 yield return 编写生成器方法时,该方法将编译为实现状态机的内部 IEnumerator 类。该方法的代码被编译成逻辑块,这些逻辑块以 yield return 或 yield break 语句终止,每个块对应一个编号状态。因为每个收益返回都必须提供一个值,所以每个块都以在本地字段中存储一个值结束。枚举器对象,为了生成它的下一个值,调用一个由当前状态编号上的巨型 switch 语句组成的方法,以便运行当前块,然后推进状态并返回本地字段的值。

您的脚本语言可以以类似的方式生成其方法,其中方法对应于状态机对象,VM 通过在分配的时间内推进状态机来分配时间。这个方法有一些棘手的部分:实现方法调用和 try/finally 块比直接生成 MSIL 更难。

于 2012-05-14T20:34:17.920 回答