Memory layout of Nim types inside the VM. The VM works on "packed data": values are laid out exactly like the C backend lays them out, except that the host ABI is used (64 bit pointers and int), regardless of the target. sizeof & co are folded by sem using the target's layout; this module is only about how the VM itself stores values.
Differences to the C backend's layout:
- NimNode, typedesc, typed and untyped values are NimNode handles stored in a pointer sized slot. A typedesc is represented as a nkType node.
- Proc values are proc handles stored in a pointer sized slot; closures are (procHandle, env).
- Fields with a bitsize are not packed into bit fields.
- Zero length arrays occupy no storage.
- Imported, incomplete structs are laid out from their declared fields.
Types
LayoutCache = object
- Source Edit
MemKind = enum mkBlock, ## not a scalar: copied as a block of bytes mkI8, mkI16, mkI32, mkI64, mkU8, mkU16, mkU32, mkU64, mkF32, mkF64, mkPtr, ## pointer sized: ptr, ref, cstring, proc, handles mkNode ## a NimNode/typedesc handle
- how a scalar is stored in memory; temporaries in the VM's registers are always widened to 64 bits. Source Edit
Consts
BoxThreshold = 65536
- a value bigger than this is held by its address in registers, see isBig Source Edit
FloatMemKinds = {mkF32, mkF64}
- Source Edit
PayloadCapOffset = 0
- cap field of a string or seq payload Source Edit
PayloadDataOffset = 8
- first element of a string or seq payload Source Edit
ScalarMemKinds = {mkI8..mkNode}
- Source Edit
SignedMemKinds = {mkI8..mkI64}
- Source Edit
StrLenOffset = 0
- len field of a string or seq Source Edit
StrPayloadOffset = 8
- p field of a string or seq Source Edit
TypeHeaderSize = 8
- size of the type field of an inheritable object Source Edit
UnsignedMemKinds = {mkU8..mkU64}
- Source Edit
VmMaxAlign = 8
- Source Edit
Procs
proc elemOffset(c: var LayoutCache; conf: ConfigRef; tupType: PType; i: int): int {....raises: [ KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [ ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect], forbids: [].}
- Byte offset of the i-th element of a tuple. Source Edit
proc elemSize(c: var LayoutCache; conf: ConfigRef; t: PType): int {....raises: [ KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [ ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect], forbids: [].}
- Element size of an array-like type (array, seq, string, openArray, ...). Source Edit
proc fieldOffset(c: var LayoutCache; conf: ConfigRef; objType: PType; field: PSym): int {....raises: [KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect], forbids: [].}
- Byte offset of field within an object or named tuple of type objType. Source Edit
proc hasPayloads(t: PType): bool {....raises: [KeyError, OSError, Exception, ValueError], tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
- Source Edit
proc hasTypeHeader(t: PType): bool {....raises: [KeyError, OSError, Exception, ValueError], tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
- Inheritable root objects (RootObj and friends) start with a type field. Source Edit
proc isBig(c: var LayoutCache; conf: ConfigRef; t: PType): bool {....raises: [ KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [ ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect], forbids: [].}
- a big value is not stored in registers: its register holds the address of the value instead. Results and parameters are passed by address then. Source Edit
proc memKindSize(k: MemKind): int {....raises: [], tags: [], forbids: [].}
- Source Edit
proc setSize(conf: ConfigRef; t: PType): int {....raises: [KeyError, OSError, Exception, ValueError, IOError, ERecoverableError], tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, WriteIOEffect], forbids: [].}
- Size of a set type in bytes. Sets of up to 64 elements are stored as an integer of the smallest fitting size, larger sets as a byte array. Invalid set types (with too many elements) have the size 0. Source Edit
proc skipForLayout(t: PType): PType {....raises: [KeyError, OSError, Exception, ValueError], tags: [ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect], forbids: [].}
- Source Edit