我的应用程序需要在同一个(单线程)进程中运行许多单独的上下文.他们都共享一个LLVMContext
.
该过程将运行许多上下文(在线程意义上); 也就是说,每个基于boost::context
(仍在库,预先批准的库)的延续对象中运行一个函数,这意味着每个上下文都可以产生,但它们基本上在相同的单线程进程中运行.每个应该基本上独立于另一个运行,更重要的是,每个中的编译错误不应该影响其他的执行.
这些上下文中的每一个都将动态调用跨多个转换单元(TU)的代码.一些翻译单元可以在许多这些上下文中共享.新的或修改的翻译单元中的编译错误不应影响其他上下文.
澄清编辑: 例如,TU A可能在两个上下文之间共享,上下文X和Y.仅仅为了拥有完整的图片,假设X也将运行来自其他翻译单元的代码,即B和D,同时Y也会有C.在某些时候,X决定对A进行修改,因此它创建一个新的TU A.1,它是A的副本,并在那里应用修改,因此这些不会影响上下文Y.希望这个例子清楚说明要求.
我最初的冲动是llvm::Module
为每个上下文关联一个,但由于它在LLVM中未定义,在处于中间编译状态的模块中会发生什么,我决定llvm::Module
为每个翻译单元添加一个(因为这个原因,请参阅此问题),以及副本我之前解释过的写入策略,当翻译单元的修改本地发生在上下文时,以避免修改影响其他上下文.
我遇到的主要双重问题是:
如何将上下文中的不同模块链接在一起,以便将它们作为统一库调用?我正在使用C++ api.我特别警惕这个影响这个功能的讨厌的旧bug.如果我将所有模块的所有权转移到JIT,这个bug会不会影响我ExecutionEngine::addModule()
?
一旦翻译单元上的修改强制更新其中一个模块,需要执行哪些步骤?我是否需要删除/删除旧模块对象并创建一个新模块?有没有我读过的回收政策?
我对此的第二个问题是:
ExecutionEngine
我需要?整个申请一个?每个上下文一个?每个模块一个?希望问题的范围不要过于庞大.
小智 1
我认为你需要一个概念框架来“悬挂”你的想法。将各种执行位视为命令(甚至可能使用命令模式来实现)将为您提供一组更明显的交互点。话虽如此; 您需要为您希望返回的每个离散执行提供一个上下文。超过两个将要求您创建适当的簿记。我相信这两个在 boost 中基本上是免费处理的。
执行位之间的通信同样取决于您。创建一个在执行上下文之间共享的状态(备忘录)是我想到的一种解决方案。您也可能已经在运行时中内置了合适的状态,那么就不需要额外的层。正如您所指出的,全局变量在这些交互中不是您的朋友。版本控制和名称解析也是一个问题。保持执行位分离对于解决这个问题有很大帮助。一旦解决了协调问题,这更多的是跟踪您已经创建的位的问题。这也意味着无需回收,只需每次创建新的即可,无需重新加载。一旦这些位完成执行,您还必须管理它们的生命周期。我建议ExecutionEngine
每个执行位一个。如果不这样做,就意味着需要做大量的工作来尝试“保护”工作代码免受错误代码的影响。我相信用单个引擎可以做到这一点,但风险会更大。