compiler/vm/packed_env

  Source   Edit

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

Templates

template mapList[D, S](d: seq[D]; s: openArray[S]; it: untyped; code)
s and d get evaluated multiple times, so beware   Source   Edit