compiler/vm/vm

  Source   Edit

This file implements the new evaluation engine for Nim code. An instruction is 1-3 int32s in memory, it is a register based VM. # TODO: update the above -- it doesn't reflect reality anymore

To use the VM once has to first set up an execution environment, which is represented by TCtx. In order to execute something, a VmThread instance is required and can be created with initVmThread. Only a single thread may exist for a given TCtx at a time -- creating multiple ones, even if the others are not used, is not allowed.

Types

VmThread = object
  pc: int                    ## the program counter. Points to the instruction to execute next
  regs*: seq[TFullReg]       ## all registers beloning to the thread. Each frame owns a slice of it
  sframes: seq[TStackFrame]  ## stack frames
  loopIterations: int        ## the number of remaining jumps backwards
  currentException: HeapSlotHandle ## the exception ref that's returned when querying the current exception
  ehStack: seq[tuple[ex: VmException, pc: uint32]] ## the stack of currently executed EH threads. A stack is needed since
                                                   ## exceptions can be raised while another exception is in flight
  
This is beginning of splitting up TCtx. A VmThread is meant to encapsulate the state that makes up a single execution. This includes things like the program counter, stack frames, active exception, etc.   Source   Edit
YieldReason = object
  case kind*: YieldReasonKind
  of yrkDone:
      reg*: Option[TRegister] ## the register that holds the result, or
                              ## 'none', if there is no result
    
  of yrkError:
      error*: VmEvent

  of yrkQuit:
      exitCode*: int

  of yrkMissingProcedure:
      entry*: FunctionIndex  ## the entry of the procedure that is a stub
    
  of yrkEcho:
      strs*: seq[string]     ## strings to be echo'd, at least one item
    
  
The result of a single execution step (i.e. a call to execute)   Source   Edit
YieldReasonKind = enum
  yrkDone,                  ## execution is done. There is no more code to execute
  yrkError, ## an error occurred. No clear distinction between fatal (the thread
             ## must not be resumed) and non-fatal (the thread may be resumed) is
             ## made yet, so all errors should be treated as fatal
  yrkQuit,                  ## a call to ``quit`` was executed. The thread can't be resumed
  yrkMissingProcedure, ## a procedure stub was called. The stub has to be resolved before
                        ## 
                        ## continuing execution
  yrkEcho ## "syscall" of echo, the VM expects the code executing it to handle the
          ## echo and then resume execution
  Source   Edit

Procs

proc `=copy`(x: var VmThread; y: VmThread) {.error.}
  Source   Edit
proc createStackTrace(c: TCtx; thread: VmThread; recursionLimit: int = 100): VmStackTrace {.
    ...raises: [], tags: [].}
Generates a stack-trace report starting at frame sframe (inclusive). The amount of entries in the trace is limited to recursionLimit, further entries are skipped, though the entry function is always included in the trace   Source   Edit
proc dispose(c: var TCtx; t: sink VmThread) {....raises: [Exception],
    tags: [RootEffect].}
Cleans up and frees all VM data owned by t.   Source   Edit
func ensureKind(n: var TFullReg; k: TRegisterKind; mm: var VmMemoryManager) {.
    inline, ...raises: [Exception], tags: [RootEffect].}
  Source   Edit
proc execute(c: var TCtx; thread: var VmThread): YieldReason {.inline, ...raises: [
    Exception, IOError, ResultErrorRef[system.void], KeyError,
    ERecoverableError, ValueError, ResultErrorRef[vm.VmException]],
    tags: [RootEffect, TimeEffect, ReadDirEffect, ReadIOEffect].}
Executes the VM thread until it yields. The reason for yielding together with associated data is returned as a YieldReason object   Source   Edit
func initLocReg(r: var TFullReg; typ: PVmType; mm: var VmMemoryManager) {.
    ...raises: [Exception], tags: [RootEffect].}
Transitions r to a location register storing a location of type typ   Source   Edit
proc initVmThread(c: var TCtx; pc: PrgCtr; numRegisters: int; sym: PSym): VmThread {.
    ...raises: [], tags: [].}
Sets up a VmThread instance that will start execution at pc and that has numRegisters as the initial amount of registers. sym is the symbol to associate the initial stack-frame with. It may be nil.   Source   Edit
func loadEmptyReg(r: var TFullReg; typ: PVmType; info: TLineInfo;
                  mm: var VmMemoryManager): bool {....raises: [Exception],
    tags: [RootEffect].}
If a value of typ fits into a register, transitions r to the correct state, loads the default value and returns true. Returns false otherwise   Source   Edit
proc regToNode(c: TCtx; x: TFullReg; typ: PType; info: TLineInfo): PNode {.
    ...raises: [Exception], tags: [RootEffect].}
Deserializes the value stored by x to a PNode of type typ   Source   Edit
func vmEventToAstDiagVmError(evt: VmEvent): AstDiagVmError {.inline, ...raises: [],
    tags: [].}
  Source   Edit

Templates

template `[]`(t: VmThread; i: Natural): TStackFrame
Returns t's stack frame at index i.   Source   Edit
template source(c: TCtx; t: VmThread): TLineInfo
Gets the source-code information for the instruction the program counter of t currently points to   Source   Edit
template strVal(r: TFullReg): untyped
  Source   Edit
template strVal=(r: TFullReg; s: string)
  Source   Edit
template strVal=(r: TFullReg; s: VmString)
  Source   Edit