This module contains the type definitions for a packed representation of all the state required for loading and running a standalone VM instance.
In addition, procedures for storing and loading the original objects to and from the packed environment object are also located here.
For reading and writing PackedEnv to files, a rodfile-based solution is provided.
First collecting/packing into a data structure that is then written to disk in a separate is not as resource efficient (both in terms of memory consumption and time) as doing both steps in a combined manner. The first (and current) approach is less complex however, which is why it's chosen over the latter.
Types
DataEncoder = object config*: ConfigRef types*: ptr TypeEnv i: int ## the index in `PackedEnv.nodes` where the next item is to be stored
- Contextual state needed for turning data PNode-trees into PackedDataNode trees and storing them into the packed environment Source Edit
PackedDataKind = enum pdkInt, pdkIntLit, ## an embedded literal pdkFloat, pdkString, pdkPtr, pdkObj, pdkArray, pdkSet, pdkField
- Source Edit
PackedDataNode = object kind*: PackedDataKind pos*: uint32 ## for {pdkInt, pdkFloat, pdkString}: the respective `LitId` ## for {pdkObj, pdkArray, pdkSet}: the number of children ## for pdkPtr: `0` if nil, `1` otherwise ## for `pdkField`: the field's position ## for `pdkIntLit`: a direct literal that fits into 4 byte
- A single node in a depth-first linear tree that is meant for storing complex data. If a node has children, they follow directly after their parent node. PackedDataNode can be seen as a specialized version of PackedNodeLite Source Edit
PackedEncoder = object typeInfoEnc: TypeInfoEncoder typeMap*: Table[PVmType, VmTypeId] ## Maps each type instance to it's ID
- Source Edit
PackedEnv = object strings*: BiTable[string] numbers*: BiTable[BiggestInt] files*: seq[string] infos*: BiTable[TLineInfo] dbgSyms*: seq[tuple[name, info: LitId]] nodes*: seq[PackedDataNode] ## complex data. Currently used for storing ## complex constants consts*: seq[(ConstantKind, uint32)] cconsts*: seq[tuple[typ: VmTypeId, packedId: uint32]] ## ## Packed `TCtx.complexConsts`. The constants type together with an ## index referencing a sub-tree in `nodes` tfields*: seq[tuple[offset: uint32, typId: uint32]] tbranches*: seq[BranchListEntry] types*: seq[PackedVmType] globals*: seq[VmTypeId] ## All globals. Only their types are stored functions*: seq[tuple[sym: uint32, sig: RoutineSigId, t1: VmTypeId, isClosure: bool, kind: CallableKind, a, b: uint32]] callbacks*: seq[string] code*: seq[TInstr] debug*: seq[uint32] ehTable*: seq[HandlerTableEntry] ehCode*: seq[EhInstr] nimNodes: seq[PackedNodeLite] nimSyms: seq[PackedSymLite] nimTypes: seq[PackedTypeLite] typeInfos: seq[tuple[nt: TypeId, t: VmTypeId]] ## ## Packed version of `TCtx.rtti` entryPoint*: FunctionIndex
- Source Edit
PackedVmType = object size*: uint32 align*: uint8 kind*: AtomKind numFields*: uint16
- Source Edit
SliceListType = BiggestInt | BiggestFloat | ConstantId
- Source Edit
Procs
func getFloatVal(pe: PackedEnv; n: PackedDataNode): BiggestFloat {.inline, ...raises: [], tags: [].}
- Source Edit
func getIntVal(pe: PackedEnv; n: PackedDataNode): BiggestInt {.inline, ...raises: [], tags: [].}
- Source Edit
func init(enc: var PackedEncoder; types: seq[PVmType]) {....raises: [], tags: [].}
- Initializes the encoder. The sequence pass to types should not change past this point. Else, encoding error may happen Source Edit
proc loadEnv(dst: var TCtx; src: PackedEnv) {....raises: [Exception], tags: [RootEffect].}
- Loads all data from src into dst for which no further/extra processing is required. Things that are not loaded are: complex constants, globals, code, and the callback list. Source Edit
proc loadSliceList[T: SliceListType](p: PackedEnv; id: uint32): seq[Slice[T]]
- Source Edit
proc loadTypeInfos(p: PackedEnv; types: seq[PVmType]): seq[VmTypeInfo] {. ...raises: [Exception], tags: [RootEffect].}
- Source Edit
proc readFromFile(p: var PackedEnv; file: AbsoluteFile): RodFileError {. ...raises: [IOError], tags: [ReadIOEffect].}
- Source Edit
func startEncoding(enc: var DataEncoder; e: PackedEnv) {.inline, ...raises: [], tags: [].}
- Source Edit
func storeData(enc: var DataEncoder; e: var PackedEnv; tree: MirTree): int {. ...raises: [Exception, ERecoverableError], tags: [RootEffect].}
- Packs the MIR constant expression tree and puts it into e. Returns the index of the top data node. Source Edit
func storeEnv(enc: var PackedEncoder; dst: var PackedEnv; c: TCtx) {. ...raises: [KeyError, Exception], tags: [RootEffect].}
- Stores all relevant data provided by c into dst. Previously stored data (except nodes, numbers, and strings) is thrown away. The only parts of dst not touched by storeEnv are: cconsts, globals, and entryPoint. These have to be filled in separately. Source Edit
proc writeToFile(p: PackedEnv; file: AbsoluteFile): RodFileError {. ...raises: [IOError], tags: [WriteIOEffect].}
- Source Edit