vmmem

Search:
Group by:
Source   Edit  

The memory of the VM. All VM values live in memory that is owned by the VM and that is tracked as a set of regions. Every access through a pointer that the VM cannot prove to be valid is checked against the regions so that a bogus cast produces a VM error instead of crashing the compiler.

There are different kinds of regions:

  • the VM stack: frames are bump allocated from stack segments.
  • the globals segment: compile-time globals; never freed.
  • the const segment: constant data (string literals, const values); read-only and never freed.
  • heap chunks: blocks for new, string and seq payloads, alloc.
  • big blocks: heap blocks too large for a chunk get a region of their own.
  • foreign regions: memory handed to the VM by FFI calls.

Regions never move, so addresses are stable and the VM can use real host pointers for ptr, ref, var etc.

NimNode and typedesc values are represented by 32 bit handles: indexes into tables of this module. Handle 0 always means nil. NimNode handles are reference counted: the VM code got destructors for them injected (see liftdestructors), a handle whose count drops to zero is freed and its slot is reused. A handle that is part of the VM's code (a NimNode literal) is pinned: it is never freed. Procs are represented by addresses within proc regions: these addresses are unique, so they can be told apart from integers that are cast to a proc type, yet they cannot be read or written.

Types

Address = uint64
a raw VM address; the VM uses host pointers, but stores them in 8 bytes even on a 32 bit host, see VmPtrSize Source   Edit  
Region = object
  start*, size*: Address
  kind*: RegionKind
Source   Edit  
RegionKind = enum
  rgStack, rgGlobals, rgConst, rgHeapChunk, rgBigBlock, rgForeign, rgProcs
Source   Edit  
StackMark = object
  seg*, used*: int
  boxes*: int
position of the stack pointer; restore it to pop frames. Source   Edit  
VmMemory = object
  bytesInUse*: int
  nodes*: seq[PNode]
  types*: seq[PType]
  procs*: seq[PSym]
Source   Edit  

Consts

BlockAlign = 16
Source   Edit  
BlockHeaderSize = 16
Source   Edit  
RcImmortal = 4611686018427387904'i64
rc flag of a ref cell in constant memory: never counted, never freed. Source   Edit  
RefHeaderSize = 8
the refcount precedes the object directly Source   Edit  
StackSegmentSize = 2097152
Source   Edit  
StrlitFlag = 4611686018427387904'i64
cap flag of a string or seq payload that lives in constant memory and must not be freed or mutated. Same value as the 64 bit runtime's NIM_STRLIT_FLAG. Source   Edit  

Procs

proc allocBox(m: var VmMemory; size: int): Address {....raises: [], tags: [],
    forbids: [].}
a zeroed heap block for a big value that the current frame owns: it is freed when the frame is popped. Source   Edit  
proc allocConst(m: var VmMemory; size, align: int): Address {....raises: [],
    tags: [], forbids: [].}
storage for constant data; read-only for VM code. Source   Edit  
proc allocGlobal(m: var VmMemory; size, align: int): Address {....raises: [],
    tags: [], forbids: [].}
storage for a compile-time global; zeroed, never freed, never moved. Source   Edit  
proc blockSize(m: var VmMemory; p: Address): int {....raises: [], tags: [],
    forbids: [].}
usable size of the heap block p. Source   Edit  
proc canRead(m: var VmMemory; a: Address; size: int): bool {....raises: [],
    tags: [], forbids: [].}
true if size bytes at a are VM memory. Source   Edit  
proc canWrite(m: var VmMemory; a: Address; size: int): bool {....raises: [],
    tags: [], forbids: [].}
true if size bytes at a are mutable VM memory. Source   Edit  
proc decNodeRef(m: var VmMemory; h: int64) {....raises: [], tags: [], forbids: [].}
Source   Edit  
proc decRefIsLast(p: Address): bool {.inline, ...raises: [], tags: [], forbids: [].}
nimDecRefIsLast: true if this was the last reference; the object then has to be destroyed and disposed. Source   Edit  
proc disposeRef(m: var VmMemory; p: Address; align: int): bool {....raises: [],
    tags: [], forbids: [].}
nimRawDispose: frees the memory of a ref. Returns false for an invalid pointer. Source   Edit  
proc findRegion(m: var VmMemory; a: Address): int {....raises: [], tags: [],
    forbids: [].}
index of the region that contains a or -1. Source   Edit  
proc getNode(m: VmMemory; h: int64): PNode {.inline, ...raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc getProc(m: var VmMemory; a: Address): PSym {....raises: [], tags: [],
    forbids: [].}
the proc at address a, nil if a is not a proc address. Source   Edit  
proc getType(m: VmMemory; h: int64): PType {.inline, ...raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc heapAlloc(m: var VmMemory; size: int): Address {....raises: [], tags: [],
    forbids: [].}
alloc0 for the VM. Returns 0 for a size of 0. Source   Edit  
proc heapDealloc(m: var VmMemory; p: Address): bool {....raises: [], tags: [],
    forbids: [].}
frees a heap block. Returns false if p is not a live heap block (double free, interior pointer, not VM heap memory). Source   Edit  
proc heapRealloc(m: var VmMemory; p: Address; newSize: int): Address {.
    ...raises: [], tags: [], forbids: [].}
realloc0 for the VM. Returns 0 if p is not a live heap block; check with isHeapBlock first for a precise error. Source   Edit  
proc incNodeRef(m: var VmMemory; h: int64) {....raises: [], tags: [], forbids: [].}
Source   Edit  
proc incRef(p: Address) {.inline, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc isConstMemory(m: var VmMemory; a: Address): bool {....raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc isFreedBlock(m: var VmMemory; p: Address): bool {....raises: [], tags: [],
    forbids: [].}
true if p is the start of a heap block that was freed. Source   Edit  
proc isHeapBlock(m: var VmMemory; p: Address): bool {....raises: [], tags: [],
    forbids: [].}
true if p is the start of a live heap block. Source   Edit  
proc isLiteralPayload(p: Address): bool {.inline, ...raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc liveNodes(m: VmMemory): int {....raises: [], tags: [], forbids: [].}
the number of NimNode handles that are in use Source   Edit  
proc loadString(src: Address): string {....raises: [], tags: [], forbids: [].}
reads the string value at src. Assumes src was checked. Source   Edit  
proc newConstPayload(m: var VmMemory; cap, elemSize, elemAlign: int;
                     isString: bool): Address {....raises: [], tags: [],
    forbids: [].}
allocates a payload in constant memory; it is flagged with StrlitFlag. Source   Edit  
proc newConstRef(m: var VmMemory; size, align: int): Address {....raises: [],
    tags: [], forbids: [].}
Source   Edit  
proc newPayload(m: var VmMemory; cap, elemSize, elemAlign: int; isString: bool): Address {.
    ...raises: [], tags: [], forbids: [].}
allocates a zeroed payload for cap elements on the heap. Source   Edit  
proc newRef(m: var VmMemory; size, align: int): Address {....raises: [], tags: [],
    forbids: [].}
nimNewObj for the VM: returns the address of the zeroed object. Source   Edit  
proc nodeHandle(m: var VmMemory; n: PNode): int32 {....raises: [], tags: [],
    forbids: [].}
a new reference to n: the caller owns it and has to release it with decNodeRef, which the VM code's injected destructors do. Source   Edit  
proc payloadCap(p: Address): int {.inline, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc payloadDataOffset(elemAlign: int): int {.inline, ...raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc pinnedNodeHandle(m: var VmMemory; n: PNode): int32 {....raises: [], tags: [],
    forbids: [].}
a handle for n that is never freed: for NimNode literals in the VM's code. Source   Edit  
proc popFrames(m: var VmMemory; mark: StackMark) {.inline, ...raises: [], tags: [],
    forbids: [].}
pops the frames pushed after mark was taken and frees their boxes Source   Edit  
proc procAddress(m: var VmMemory; s: PSym): Address {....raises: [], tags: [],
    forbids: [].}
the VM's address of the proc s; 0 for nil. Source   Edit  
proc pushFrame(m: var VmMemory; size: int): Address {....raises: [], tags: [],
    forbids: [].}
allocates a zeroed frame of size bytes (a multiple of 8). Restore the stackMark taken before this call to pop it. Source   Edit  
proc refBlockOffset(align: int): int {.inline, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc refCount(p: Address): int64 {.inline, ...raises: [], tags: [], forbids: [].}
Source   Edit  
proc registerForeign(m: var VmMemory; p: pointer; size: int) {....raises: [],
    tags: [], forbids: [].}
makes memory that the VM did not allocate (FFI) accessible. Source   Edit  
proc stackMark(m: VmMemory): StackMark {.inline, ...raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc storeString(m: var VmMemory; dest: Address; s: string; inConst: bool) {.
    ...raises: [], tags: [], forbids: [].}
writes a string value (len, p) to dest. The empty string has no payload. Source   Edit  
proc typeHandle(m: var VmMemory; t: PType): int32 {....raises: [], tags: [],
    forbids: [].}
Source   Edit  
proc unregisterForeign(m: var VmMemory; p: pointer) {....raises: [], tags: [],
    forbids: [].}
Source   Edit  

Templates

template `+!`(a: Address; b: int): Address
Source   Edit  
template `-!`(a: Address; b: int): Address
Source   Edit  
template ld[T](a: Address): T
Source   Edit  
template ldInt(a: Address): int
Source   Edit  
template st[T](a: Address; v: T)
Source   Edit  
template stInt(a: Address; v: int)
Source   Edit  
template toAddr(p: pointer): Address
Source   Edit  
template toPtr(a: Address): pointer
Source   Edit