ModelGeneratorContext

class ModelGeneratorContext

All LLVM code generating objects basically need at a minimum three things to operate:

1: sbml Model - what to process 2: llvm Context - all llvm functions need this, manages llvm memory 3: llvm Module - where the generated code will go

Code generators also need to know the symbols that are in the sbml doc. These could be re-determined in each code gen, but wastefull. The symbols can be thought of as the first pass of the compiler, so all symbols are determined ahead of time before any code generation.

They also make use of an llvm IRBuilder, one of these could be allocated in each code gen object, but that would be wasteful, so we use a single one per sbml compilation, and each code gen just resets the builder insert point, that is what is was designed to do.

So, that leaves us with 5 object that are needed by code generators. Should all code gens have all 5 args passed to thier ctors? There is much talk about how context objects are evil, however this one is NOT inteneded to grow, only store the absolute minimun information that all code generators need.

This class basically functions as a set of ivars if all code generators were methods on a single code gen class.

TODO doc wise discuss the problems with context objects, and why this one address all the concerns.

TODO document memory managment, engine owns model, …

Public Functions

ModelGeneratorContext(const libsbml::SBMLDocument *_doc, unsigned options, std::unique_ptr<Jit> jitEngine)

attach to an existing sbml document, we borrow a reference to this doc and DO NOT take ownership of it.

ModelGeneratorContext()

does not attach to any sbml doc,

useful for testing out LLVM functionality.

~ModelGeneratorContext()
const LLVMModelDataSymbols &getModelDataSymbols() const
const LLVMModelSymbols &getModelSymbols() const
const libsbml::SBMLDocument *getDocument() const
const libsbml::Model *getModel() const
Jit *getJitNonOwning() const
void transferObjectsToResources(std::shared_ptr<rrllvm::ModelResources> modelResources)

nearly all llvm functions expect a pointer to module, so we define this as a pointer type instead of reference, even though we gaurantee this to be non-null

if optimization is enabled, this gets the function pass manager loaded with all the requested optimizers. NULL if no optimization is specified.

However, when a model is successfully generated, we need a way to give it the exec engine, and whatever other bits it requires.

So, this method exists so that the generated model can steal all the objects it needs from us, these object are transfered to the model, and our pointers to them are cleared.

Returns:

a borrowed reference that is owned by ModelGeneratorContext A lot can go wrong in the process of generating a model from an sbml doc. This class is intended to be stack allocated, so when any exception is thrown in the course of model generation, this class will clean up all the contexts and execution engines and so forth.

bool getConservedMoietyAnalysis() const
bool useSymbolCache() const
inline unsigned getOptions() const
Random *getRandom() const

get a pointer to the random object.

The random object exists if the document has the distrib package, is null otherwise.

Private Functions

void cleanup()

free any memory this class allocated.

Private Members

libsbml::SBMLDocument *ownedDoc

these point to the same location, ownedDoc is set if we create the doc, otherwise its nullptr, meaning we’re borrowing the the doc.

const libsbml::SBMLDocument *doc

always references the sbml doc.

const LLVMModelDataSymbols *symbols
std::unique_ptr<LLVMModelSymbols> modelSymbols

make sure this is listed AFTER the doc and model, so it get initialized after the previous two are initialized.

const libsbml::Model *model
Random *random

As the model is being generated, various distributions may be created which are added to the random object.

Ownership of the random object is then transfered to the ExecutableModel which owns up untill the ExecutableModel is destroyed.

The logic here is that many distributions used the normal_distribution object which maintains a state and has an expensive startup cost. So, the distributions are created whilst the model is being generated, and then the distribution calls just end up calling an existing distribution object inside this class.

A pointer to this object is stored in the ModelData struct, and when the generated sbml code calls a stochastic dist function, it passes in a pionter to this object so the func can look up the distribution.

The alternative to this approach would have been to simply have global distributions and a global RNG. This however would use more memory and would not be thread safe, and the RNG would have to be shared amoungst multiple models, and would not be be able to create a repeatable stream of random numbers.

unsigned options
std::unique_ptr<Jit> jit

Jit dependency injection to support multiple different compilation strategies.

std::unique_ptr<rr::conservation::ConservedMoietyConverter> moietyConverter

the moiety converter, for the time being owns the converted document.