Предложение дизайна: llvm несколько контекстов выполнения

Мое приложение должно запускать множество отдельных контекстов в одном и том же (однопоточном) процессе. Все они имеют один LLVMContext.

В процессе будет выполняться множество контекстов (в смысле потока); то есть каждый из них выполняет функцию в объекте продолжения на основе boost::context (все еще в хранилище, предварительно одобренном lib), это означает, что каждый контекст может дать, но они в основном работают в одном однопоточном процессе. Каждый из них должен работать в основном независимо от другого, и, что более важно, ошибка компиляции в каждом из них не должна влиять на выполнение других.

Каждый из этих контекстов будет динамически вызывать код, который охватывает несколько единиц перевода (TU). некоторые единицы перевода могут быть разделены во многих из этих контекстов. ошибки компиляции в новой или модифицированной системе перевода не должны влиять на другие контексты.

Редактирование разъяснений: Например, T.U. A может быть разделен между двумя контекстами, контекстом X и Y. только для того, чтобы иметь полную картину, скажем, что X также будет запускать код из других единиц перевода, то есть B и D, тогда как Y будет также C. В в какой-то момент X решает внести изменения в A, поэтому он создает новый TU A.1, который является копией A, и применяет там модификацию, поэтому они не будут влиять на контекст Y. Надеемся, что этот пример дает понять, требование.

Мой первоначальный импульс состоял в том, чтобы связать один llvm::Module для каждого контекста, но поскольку его undefined в LLVM, что происходит с модулем в промежуточном состоянии компиляции, я решил добавить один llvm::Module для каждой единицы перевода ( см. этот вопрос по причине), плюс политика копирования на запись, о которой я объяснил ранее, когда модификации единицы перевода происходят локально в контексте, чтобы избежать изменение, влияющее на другие контексты.

Основной двусмысленный вопрос, который у меня есть:

  • Как мне связать разные модули в контексте, чтобы вызвать их как унифицированную библиотеку? Я использую С++ api. Я особенно опасаюсь эта неприятная, старая ошибка, влияющая на эту функциональность. Эта ошибка все равно повлияет на меня, если я передам право владения всеми модулями в JIT с помощью ExecutionEngine::addModule()?

  • Каковы требуемые шаги после того, как модификация блока перевода заставляет обновить один из модулей? мне нужно удалить/удалить старый объект модуля и создать новый? есть ли политика утилизации, о которой я не читал?

Второй вопрос, который у меня есть, следующий:

  • Сколько ExecutionEngine мне нужно? один для всего приложения? один за контекст? по одному на модуль?

Надеюсь, что вопрос не слишком ошеломляющий.

Ответ 1

Я думаю, вам нужна концептуальная основа для "зависания" ваших идей. Думая о различных исполняемых битах как командах (возможно, даже при использовании с использованием шаблона команды), вы получите более очевидный набор точек взаимодействия. Что, как говорится; вам понадобится контекст для каждого отдельного выполнения, к которому вы хотите вернуться. Для более чем двух требуется, чтобы вы создали соответствующий бухгалтерский учет. Я считаю, что два в основном обрабатываются бесплатно. Связь между исполняемыми битами аналогично вам. Создание состояния (memento), которое разделяется между контекстами выполнения, является одним из решений, которое приходит на ум. У вас также может быть подходящее состояние, встроенное в ваше время выполнения, тогда дополнительный уровень не потребуется. Как вы указали, глобальные перемены не являются вашим другом в этих взаимодействиях. Реализация версий и имен также является проблемой. Сохранение отдельных исполняемых битов имеет большое значение для решения этой проблемы. Как только вы решаете проблему координации, это больше зависит от того, какие биты вы уже создали. Это также означает, что нет необходимости в переработке, просто создавайте новые каждый раз, и нет перезагрузки. Вам также придется управлять окончанием срока службы этих битов после завершения их выполнения. Я предлагаю один ExecutionEngine за исполняемый бит. Не делать этого означает гораздо большую работу, пытаясь "защитить" рабочий код от последствий неправильного кода. Я считаю, что это можно сделать с помощью одного движка, но это будет значительно более рискованно.