C++ 设计建议:llvm多运行时上下文

C++ 设计建议:llvm多运行时上下文,c++,llvm,C++,Llvm,我的应用程序需要在同一(单线程)进程中运行多个单独的上下文。它们都共享一个LLVMContext 进程将运行许多上下文(线程意义上);也就是说,每个上下文都基于boost::context(仍在vault上,预批准的库中)在延续对象中运行一个函数。这意味着每个上下文都可以生成,但它们基本上在相同的单线程过程中运行。每一个都应该基本上独立于另一个运行,更重要的是,每一个中的编译错误不应该影响其他的执行 每个上下文都将动态调用跨多个翻译单元(TU)的代码。一些翻译单元可以在许多这样的上下文中共享。新

我的应用程序需要在同一(单线程)进程中运行多个单独的上下文。它们都共享一个
LLVMContext

进程将运行许多上下文(线程意义上);也就是说,每个上下文都基于
boost::context
(仍在vault上,预批准的库中)在延续对象中运行一个函数。这意味着每个上下文都可以生成,但它们基本上在相同的单线程过程中运行。每一个都应该基本上独立于另一个运行,更重要的是,每一个中的编译错误不应该影响其他的执行

每个上下文都将动态调用跨多个翻译单元(TU)的代码。一些翻译单元可以在许多这样的上下文中共享。新的或修改的翻译单元中的编译错误不应影响其他上下文

澄清编辑: 例如,T.U.A可能在两个上下文中共享,上下文X和Y。为了获得完整的图片,假设X也将运行来自其他翻译单元的代码,即B和D,而Y也将运行C。在某个点上,X决定对A进行修改,因此它创建了一个新的T.U.A.1,它是A的副本,并在那里应用修改,这样就不会影响上下文Y。希望这个示例能够清楚地说明需求

我最初的冲动是为每个上下文关联一个
llvm::Module
,但由于它在llvm中未定义处于编译中间状态的模块会发生什么,我决定为每个翻译单元添加一个
llvm::Module
(请参阅),加上我之前解释过的写时拷贝策略,当翻译单元的修改发生在本地上下文时,为了避免修改影响其他上下文

我遇到的主要两个问题是:

  • 如何将上下文中的不同模块链接在一起,以便将它们作为统一库调用?我使用的是C++ API。我特别担心影响此功能。如果我使用
    ExecutionEngine::addModule()
    ,将所有模块的所有权转移到JIT,这个bug还会影响我吗

  • 一旦对翻译单元的修改强制更新其中一个模块,需要采取哪些步骤?我是否需要删除旧的模块对象并创建新的模块对象?有没有我没读过的回收政策

关于这一点,我的第二个问题是:

  • 我需要多少执行引擎?整个应用程序一个?每个上下文一个?每个模块一个

希望问题的范围不要太大。

我认为你需要一个概念框架来“坚持”你的观点。将各种执行位看作命令(甚至可能使用命令模式实现)将为您提供一组更明显的交互点。话虽如此,;对于希望返回的每个离散执行,您都需要一个上下文。超过两种情况需要您创建适当的簿记。我相信在boost中,两个基本上是免费处理的。
执行位之间的通信同样取决于您。创建一个跨执行上下文共享的状态(memento)是我想到的一个解决方案。您可能已经在运行时内置了合适的状态,那么就不需要额外的层了。正如你所指出的,在这些互动中,全球人不是你的朋友。 版本控制和名称解析也是一个问题。保持执行位分开对于解决这个问题有很大的帮助。一旦您解决了协调问题,这更多的是跟踪您已经创建的位的问题。这也意味着不需要回收,只需每次创建新的,而无需重新加载。一旦这些位完成执行,您还必须管理它们的寿命结束。
我建议每个执行位有一个
ExecutionEngine
。不这样做意味着要做更多的工作,试图“保护”工作代码不受错误代码的影响。我相信用一台发动机就可以做到这一点,但风险要大得多。

我不是专家,但我想我可以在这里添加一些东西,至少可以让您开始。对于问题1a:问题的底部似乎是肯定的,将模块投入JIT确实可以解决问题。到1b:建议没有资源循环利用,只是一个。所以,这取决于模块的变异。To 2:我说,考虑到前两个问题的解决方案,让你的设计和需求决定这一点。祝你好运这是我能做出的最简洁的伪答案。尽管我承认自己在设计说明、文档和LLVM操作背后的编译器理论方面犯了错误,但如果您希望我将其形式化为实际答案,请务必告诉我。