我正在用C#编写自己的脚本语言,有一些我喜欢的功能,我选择使用MSIL作为输出的字节码(Reflection.Emit非常有用,我不必考虑另一个字节码)。它工作,发出可执行文件,可以运行(甚至用Reflector :)反编译)并且非常快。
但是 - 我想在一个进程+一个线程中运行多个'进程',并手动控制它们分配的CPU时间(也实现.NET框架提供的更强大的IPC)有没有办法完全禁用JIT并创建自己的VM,使用.NET框架(和控制内存使用等)逐步执行指令,而不需要自己编写任何内容,或者要实现这一点我必须编写完整的MSIL解释?
编辑1):我知道解释IL不是宇宙中最快的东西:)
编辑2):澄清 - 我希望我的虚拟机成为某种'操作系统' - 它获得一些CPU时间并在进程之间划分,控制它们的内存分配,等等。它不必是快速的,也不是有效的,而只是我的一些实验的概念证明。我不需要在处理每条指令的程度上实现它 - 如果这应该由.NET完成,我不介意,我只想说:第一步说明,等到我告诉你下一步。
编辑3):我意识到,ICorDebug可以完成我的需求,现在看看Mono运行时的实现。
答案 0 :(得分:5)
您可以使用Mono - 我相信允许选项来解释IL而不是JIT它。它的开源意味着(需要许可)你应该能够根据自己的需要对其进行修改。
Mono并不具备.NET的所有功能 - 但可能会完成您所需要的一切。
答案 1 :(得分:1)
请注意,MSIL旨在由JIT编译器解析。它不太适合翻译。一个很好的例子可能是ADD指令。它用于添加各种值类型值:byte,short,int32,int64,ushort,uint32,uint64。您的编译器知道需要哪种类型的添加,但在生成MSIL时您将丢失该类型信息。
现在您需要在运行时找回它,并且需要检查评估堆栈上的值的类型。很慢。
易于解释的IL具有ADD8,ADD16等专用ADD指令
答案 2 :(得分:1)
Common Language Runtime的Microsofts实现只有一个执行系统JIT。另一方面,Mono同时带有JIT和翻译。
但是,我并不完全明白你自己想要做什么以及你想要留给Microsofts实现的内容:
有没有办法完全禁用JIT并创建自己的VM?
和
...我不需要自己写任何东西,或者要实现这一点我必须编写完整的MSIL解释?
有点矛盾。
如果你认为,你可以编写一个比微软JIT更好的执行系统,你将不得不从头开始编写它。但请记住,微软和单声道JIT都是高度优化的编译器。 (Programming language shootout)
无法从用户模式准确地为操作系统进程安排CPU时间。那是操作系统的任务。
绿色线程的某些实现可能是一个想法,但这绝对是非托管代码的主题。如果这就是您想要的,请查看CLR托管API。
我建议你尝试在CIL中实现你的语言。毕竟,它被编译为原始x86。如果您不关心可验证性,可以在必要时使用指针。
答案 3 :(得分:1)
您可以考虑做的一件事是以状态机方式生成代码。让我解释一下我的意思。
当您使用yield return在C#中编写生成器方法时,该方法将编译为实现状态机的内部IEnumerator类。方法的代码被编译为逻辑块,这些逻辑块以yield return或yield break语句终止,并且每个块对应于编号状态。因为每个yield return必须提供一个值,所以每个块以在本地字段中存储值结束。枚举器对象为了生成其下一个值,调用一个方法,该方法由当前状态号上的巨型switch语句组成,以便运行当前块,然后提前状态并返回本地字段的值。
您的脚本语言可以以类似的方式生成其方法,其中方法对应于状态机对象,并且VM通过在分配的时间内推进状态机来分配时间。这个方法的一些棘手的部分:实现方法调用和try / finally块之类的东西比生成直接的MSIL更难。