vmdef

Source   Edit  

This module contains the type definitions for the evaluation engine. It is a register based VM that works on "packed data": values are laid out in memory like the C backend lays them out (see vmlayout), all VM memory is managed by vmmem.

Registers are 8 byte slots of the current stack frame; register i lives at the frame pointer + 8*i. A scalar (integer, float, pointer, handle) that is held in a register is always widened to 64 bits; an aggregate value (object, tuple, array, string, seq, closure, ...) that is held in registers occupies ceil(size/8) consecutive slots and uses the packed memory layout. Memory outside of registers is always packed and is accessed via typed loads and stores that narrow and widen scalars.

An instruction is a 64 bit word: opcode, A, B, C (16 bits each). Operand sizes and kinds are encoded in the opcode (one opcode per MemKind for loads and stores) so that the interpreter does not dispatch on them at runtime. Some instructions are followed by an extra 64 bit word W that holds an immediate value.

Types

CallShape = object
  paramOffsets*: seq[int]
  paramTypes*: seq[PType]
  resultType*: PType
  resultSlots*: int
  callbackIdx*: int
where the arguments of a call live, relative to the first argument slot Source   Edit  
LocalInfo = object
  slot*: int32
  boxed*: bool
  inMemory*: bool ## a scalar whose address is taken is stored packed in
                  ## its slot and must be accessed via the opcLdSlot*/opcStSlot* instructions
Source   Edit  
PCtx = ref TCtx
Source   Edit  
PProc = ref object
  blocks*: seq[TBlock]
  tries*: seq[TryInfo]
  sym*: PSym
  regInfo*: seq[SlotUse]
  locals*: Table[ItemId, LocalInfo]
  addrTaken*: IntSet
  paramAddrTaken*: IntSet
  resultAddrTaken*: bool
  paramSlots*: seq[LocalInfo]
  resultInfo*: LocalInfo
  hasResult*: bool
  injected*: bool
Source   Edit  
Profiler = object
  tEnter*: float
  tos*: PStackFrame
Source   Edit  
SlotUse = object
  inUse*: bool
  isTemp*: bool
  rangeLen*: int32
per register bookkeeping of the code generator Source   Edit  
TBlock = object
  label*: PSym
  fixups*: seq[TPosition]
  tryDepth*: int
Source   Edit  
TCtx = object of TPassContext
  code*: seq[TInstr]
  lastEof*: int              ## position of the last `opcEof`; -1 if there is none
  typeKindDefault*: int
  debug*: seq[TLineInfo]
  mem*: VmMemory
  layouts*: LayoutCache
  globalAddrs*: Table[ItemId, Address]
  constAddrs*: Table[ItemId, Address]
  branchTables*: seq[seq[(BiggestInt, BiggestInt)]]
  callShapes*: seq[CallShape]
  procShapes*: Table[ItemId, CallShape]
  excNames*: Table[int, Address]
  semCtx*: PPassContext
  emptyCStr*: Address
  currentExceptionA*, currentExceptionB*: Address
  exceptionInstr*: int
  prc*: PProc
  module*: PSym
  callsite*: PNode
  mode*: TEvalMode
  features*: TSandboxFlags
  traceActive*: bool
  loopIterations*, callDepth*: int
  comesFromHeuristic*: TLineInfo
  callbacks*: seq[VmCallback]
  callbackIndex*: Table[string, int]
  errorFlag*: string
  cache*: IdentCache
  config*: ConfigRef
  graph*: ModuleGraph
  oldErrorCount*: int
  profiler*: Profiler
  templInstCounter*: ref int
  vmstateDiff*: seq[(PSym, PNode)]
  procToCodePos*: Table[int, VmProcInfo]
  cannotEval*: bool
  when false:
    ffiSites*: seq[FfiSite]
  locals*: IntSet
Source   Edit  
TDest = range[-1 .. 65535'u64.int]
Source   Edit  
TEvalMode = enum
  emRepl,                   ## evaluate because in REPL mode
  emConst,                  ## evaluate for 'const' according to spec
  emOptimize,               ## evaluate for optimization purposes (same as
                             ## emConst?)
  emStaticExpr,             ## evaluate for enforced compile time eval
                             ## ('static' context)
  emStaticStmt               ## 'static' as an expression
reason for evaluation Source   Edit  
TInstr = distinct TInstrType
Source   Edit  
TInstrType = uint64
Source   Edit  
TOpcode = enum
  opcEof, opcRet, opcYldYoid, opcYldVal, opcMov, opcMovN, opcZeroN, opcLdImmInt,
  opcLdImm, opcAddrSlot, opcAddrOff, opcAddrOffW, opcLdI8, opcLdI16, opcLdI32,
  opcLdU8, opcLdU16, opcLdU32, opcLdF32, opcLd64, opcSt8, opcSt16, opcSt32,
  opcStF32, opcSt64, opcLdSlotI8, opcLdSlotI16, opcLdSlotI32, opcLdSlotU8,
  opcLdSlotU16, opcLdSlotU32, opcLdSlotF32, opcStSlot8, opcStSlot16,
  opcStSlot32, opcStSlotF32, opcCopyMem, opcZeroMem, opcIdxArr, opcIdxSeq,
  opcIdxOpenArr, opcIdxPtr, opcSlice, opcAddInt, opcAddImmInt, opcSubInt,
  opcSubImmInt, opcMulInt, opcDivInt, opcModInt, opcAddFloat, opcSubFloat,
  opcMulFloat, opcDivFloat, opcShrInt, opcShlInt, opcAshrInt, opcBitandInt,
  opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, opcDivu, opcModu,
  opcEqInt, opcLeInt, opcLtInt, opcEqFloat, opcLeFloat, opcLtFloat, opcLeu,
  opcLtu, opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
  opcIsNil, opcCastIntToFloat32, opcCastIntToFloat64, opcCastFloatToInt32,
  opcCastFloatToInt64, opcIntToFloat, opcUIntToFloat, opcFloatToInt,
  opcFloatToUInt, opcFloatToF32, opcNarrowS, opcNarrowU, opcSignExtend,
  opcRangeChck, opcRangeChckF, opcRangeChckSucc, opcToStr, opcParseFloat,
  opcSetIncl, opcSetExcl, opcSetInclRange, opcSetContains, opcSetCard, opcSetLe,
  opcSetLt, opcBSetIncl, opcBSetExcl, opcBSetInclRange, opcBSetContains,
  opcBSetCard, opcBSetUnion, opcBSetInter, opcBSetDiff, opcBSetXor, opcBSetEq,
  opcBSetLe, opcBSetLt, opcStrNew, opcStrSetLen, opcStrAddCh, opcStrAddStr,
  opcStrAsgn, opcStrEq, opcStrLe, opcStrLt, opcStrToCStr, opcCStrToStr,
  opcCStrLen, opcCStrEq, opcStrFromChars, opcSeqNew, opcSeqSetLen,
  opcSeqGrowOne, opcSeqData, opcPayloadFree, opcSamePayload, opcSeqCopyPayload,
  opcMakeUnique, opcUnshare, opcDestroyValue, opcCopyValue, opcSinkValue,
  opcNewRef, opcIncRef, opcNodeIncRef, opcNodeDecRef, opcDecRefIsLast,
  opcDisposeRef, opcDynDestructor, opcInitObj, opcOf, opcIs, opcAlloc,
  opcDealloc, opcRealloc, opcAllocTemp, opcMemMove, opcMemZero, opcMemCmp,
  opcRepr, opcQuit, opcInvalidField, opcNLen, opcToNode, opcFromNode, opcNAdd,
  opcNAddMultiple, opcNKind, opcNSymKind, opcNIntVal, opcNFloatVal, opcNSymbol,
  opcNIdent, opcNGetType, opcNTypeKind, opcNGetTypeInst, opcNGetTypeImpl,
  opcNGetTypeInstSkipAlias, opcNStrVal, opcNSigHash, opcNGetSize, opcNSetIntVal,
  opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetStrVal, opcNNewNimNode,
  opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym, opcNccValue, opcNccInc,
  opcNcsAdd, opcNcsIncl, opcNcsLen, opcNcsAt, opcNctPut, opcNctLen, opcNctGet,
  opcNctHasNext, opcNctNext, opcNodeId, opcSlurp, opcGorge, opcParseExprToAst,
  opcParseExprToAstFile, opcParseStmtToAst, opcParseStmtToAstFile,
  opcQueryErrorFlag, opcNError, opcNWarning, opcNHint, opcNGetLineInfo,
  opcNCopyLineInfo, opcNSetLineInfoLine, opcNSetLineInfoColumn,
  opcNSetLineInfoFile, opcEqIdent, opcEqIdentSN, opcEqIdentNS, opcEqIdentSS,
  opcStrToIdent, opcGetImpl, opcGetImplTransf, opcEqNimNode, opcSameNodeType,
  opcTypeTrait, opcSymOwner, opcSymIsInstantiationOf, opcSymCustomPragmas,
  opcNBindSym, opcNDynBindSym, opcNChild, opcNSetChild, opcCallSite, opcEcho,
  opcIndCall, opcFfiCall, opcRaise, opcTJmp, opcFJmp, opcJmp, opcJmpBack,
  opcBranch, opcTry, opcExcept, opcFinally, opcFinallyEnd, opcTypeLit
Source   Edit  
TPosition = distinct int
Source   Edit  
TRegister = range[0 .. 65535'u64.int]
Source   Edit  
TryInfo = object
  fin*: PNode
  hasSafePoint*: bool
Source   Edit  
TSandboxFlag = enum
  allowCast,                ## allow unsafe language feature: 'cast'
  allowInfiniteLoops,       ## allow endless loops
  allowInfiniteRecursion     ## allow infinite recursion
what the evaluation engine should allow Source   Edit  
TStackFrame {.acyclic.} = object
  prc*: PSym
  fp*: Address
  mark*: StackMark
  next*: PStackFrame
  comesFrom*: int
  top*: StackMark
  resultDest*: Address
  resultSize*: int
  disposeOnReturn*: Address
  disposeAlign*: int
  safePoints*: seq[int]
Source   Edit  
VmArgs = object
  ctxp*: pointer
  args*: Address
  res*: Address
  shape*: ptr CallShape
  currentException*: Address
  currentLineInfo*: TLineInfo
the arguments of a callback. See vmhooks for how to access them. Source   Edit  
VmCallback = proc (args: VmArgs) {.closure.}
Source   Edit  
VmProcInfo = object
  pc*: int32
  frameSlots*: int32
  resultSlots*: int32
  paramSlots*: int32
  envSlot*: int32
  bigResult*: bool
  genericParamSlots*: seq[int32]
Source   Edit  

Consts

byteExcess = 128
Source   Edit  
firstABxInstr = opcTJmp
Source   Edit  
largeInstrs = {opcLdImm, opcAddrOffW, opcCopyMem, opcZeroMem, opcIdxArr,
               opcIdxSeq, opcIdxOpenArr, opcIdxPtr, opcFloatToInt, opcToStr,
               opcBSetIncl, opcBSetExcl, opcBSetInclRange, opcBSetContains,
               opcBSetCard, opcBSetUnion, opcBSetInter, opcBSetDiff, opcBSetXor,
               opcBSetEq, opcBSetLe, opcBSetLt, opcSeqNew, opcSeqSetLen,
               opcSeqGrowOne, opcSeqData, opcSeqCopyPayload, opcNewRef,
               opcInitObj, opcOf, opcIs, opcRepr, opcSlice, opcNDynBindSym,
               opcToNode, opcFromNode, opcUnshare, opcAllocTemp,
               opcDestroyValue, opcCopyValue, opcSinkValue, opcNctNext,
               opcInvalidField, opcFfiCall}
Source   Edit  
MaxFrameSlots = 65536
Source   Edit  
NoVmProcInfo = (pc: 0'i32, frameSlots: -1'i32, resultSlots: 0'i32,
                paramSlots: 0'i32, envSlot: 0'i32, bigResult: false,
                genericParamSlots: [])
Source   Edit  
regAMask = 65535'u64
Source   Edit  
regAShift = 16'u64
Source   Edit  
regBMask = 65535'u64
Source   Edit  
regBShift = 32'u64
Source   Edit  
regBxMask = 16777215'u64
Source   Edit  
regBxMax = 8388607
Source   Edit  
regBxMin = -8388607
Source   Edit  
regBxShift = 32'u64
Source   Edit  
regCMask = 65535'u64
Source   Edit  
regCShift = 48'u64
Source   Edit  
regOMask = 65535'u64
Source   Edit  
regOShift = 0'u
Source   Edit  
relativeJumps = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
Source   Edit  
SlotSize = 8
size of a register in bytes Source   Edit  
wordExcess = 8388608
Source   Edit  

Procs

proc ldOpc(k: MemKind): TOpcode {....raises: [], tags: [], forbids: [].}
the load instruction for a scalar stored as k Source   Edit  
proc ldSlotOpc(k: MemKind): TOpcode {....raises: [], tags: [], forbids: [].}
like ldOpc for a slot; opcMov if no widening is required Source   Edit  
proc newCtx(module: PSym; cache: IdentCache; g: ModuleGraph; idgen: IdGenerator): PCtx {.
    ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc refresh(c: PCtx; module: PSym; idgen: IdGenerator) {....raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc registerCallback(c: PCtx; name: string; callback: VmCallback): int {.
    discardable, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc slotsFor(size: int): int {.inline, ...raises: [], tags: [], forbids: [].}
number of registers that a value of size bytes occupies. Source   Edit  
proc stOpc(k: MemKind): TOpcode {....raises: [], tags: [], forbids: [].}
the store instruction for a scalar stored as k Source   Edit  
proc stSlotOpc(k: MemKind): TOpcode {....raises: [], tags: [], forbids: [].}
like stOpc for a slot; opcMov if no narrowing is required Source   Edit  

Templates

template jmpDiff(x: TInstr): int
Source   Edit  
template opcode(x: TInstr): TOpcode
Source   Edit  
template regA(x: TInstr): TRegister
Source   Edit  
template regB(x: TInstr): TRegister
Source   Edit  
template regBx(x: TInstr): int
Source   Edit  
template regC(x: TInstr): TRegister
Source   Edit