Skip to content

Virtual Machine Memory Layout

View as Markdown

The Thru virtual machine uses a 48-bit segmented address space designed to provide memory isolation and efficient access to different types of data during program execution. The address format follows a three-component structure that enables both type safety and performance optimization.

Each virtual address is composed of three fields packed into a 48-bit value:

Bits: 47-40 | 39-24 | 23-0
seg_type| seg_idx | offset
(8 bits) |(16 bits) |(24 bits)
  • Segment Type (8 bits): Determines the memory region type and access permissions
  • Segment Index (16 bits): Identifies the specific segment within the type
  • Offset (24 bits): Byte offset within the segment (up to 16MB per segment)

Contains immutable data that programs can read but never modify.

Segment IndexNamePurposeNotes
0x0000NULLInvalid/null segmentAlways causes access violation
0x0001TXN_DATATransaction dataContains serialized transaction
0x0002SHADOW_STACKVM shadow stackCall frame metadata (public portion) - see Shadow Stack Frame Structure
0x0003PROGRAMProgram bytecodeExecutable RISC-V code
0x0004BLOCK_CTXBlock contextBlock metadata and timing info

The block context segment exposes a rolling window of recent blocks, spaced evenly within the segment to allow direct pointer math from contracts.

ConceptValueDetails
Addressingoffset = blocks_ago * 0x1000blocks_ago = 0 is the current block
Per-block stride0x1000 bytes (TN_VM_BLOCK_CTX_SPACING)Each context is aligned by 4096 bytes
History window512 blocks (TN_RUNTIME_CTX_BLOCK_SPAN)Accessing further back or before slot 0 faults

Context structure (offsets relative to the start of a block’s window):

OffsetFieldTypeDescription
0x00slotulongSlot number of the block
0x08block_timeulongUnix time in nanoseconds
0x10block_priceulongBlock price
0x18state_rootfd_hash_t (32B)State Merkle root
0x38cur_block_hashfd_hash_t (32B)Block hash
0x58block_producerfd_pubkey_t (32B)Producer public key

Any access beyond this layout or outside the history window triggers an access violation.

The shadow stack segment (0x0002) provides read-only access to call frame metadata, enabling cross-program communication and state inspection during execution. Each call frame stores information about the current program invocation context.

The shadow stack maintains metadata for up to 17 frames:

  • Frame 0: Reserved frame (frame -1 in implementation) containing all zeros
  • Frames 1-16: Active call frames for program invocations (call depths 0-15)

Programs access frame data using the shadow stack segment with the frame index encoded in the offset.

Each shadow stack frame contains the following fields:

OffsetFieldTypeSizeDescription
0x00program_acc_idxushort2 bytesAccount index of the program for this frame
0x02stack_pagesushort2 bytesTotal size of stack region in pages (4KB pages)
0x04heap_pagesushort2 bytesTotal size of heap region in pages (4KB pages)
0x06padding-2 bytesAlignment padding
0x08saved_regsulong[32]256 bytesSaved register state (32 registers × 8 bytes each)

Total frame size: 264 bytes per frame

The saved_regs array stores all 32 RISC-V registers (x0-x31) at the time of program invocation.

Provides access to account metadata structures.

FieldDescriptionAccess Notes
seg_idxAccount index in transactionMust be < transaction account count
offsetByte offset in metadataLimited to TSDK_ACCOUNT_META_FOOTPRINT bytes in the public SDK view
  • Size: Exposed to programs as TSDK_ACCOUNT_META_FOOTPRINT bytes through tsdk_account_meta_t
  • Access: Read-only from VM perspective
  • Non-existent accounts: Returns pointer to zeroed metadata structure
  • Invalid access: Access violations occur for out-of-bounds or invalid account indices

Page-based access to account data with copy-on-write semantics.

Address fields

FieldDescriptionConstraints
seg_idxAccount index in transactionMust be < transaction account count
offsetByte offset into account dataSingle memory access must not span across a 4KB page boundary. For example, reading 8 bytes at offset 4093 would fault as it spans across 4096.
FeatureDetails
Page Size4096 bytes
AlignmentEnforced at page boundaries for cross-page access
Write AccessRequires account to be writable by current program
COW PagesAutomatic copy-on-write for modifications

Reserved for event emission (implementation details in event subsystem).

Stack memory segment that grows downward from high addresses to low addresses.

CharacteristicValue
Growth DirectionDownward (0xFFFFFF → 0x000000)
Page Size4096 bytes
Max Segments1 per VM instance
Size Limit16MB per segment
Permission ModelFrame-based access control

Growth Behavior: The stack segment grows downward, meaning as more memory is allocated, the segment size increases toward lower addresses. When you allocate new stack space, the valid address range expands from the bottom (higher addresses) toward the top (lower addresses), similar to traditional hardware stacks.

Address Layout:

  • Virtual address range: 0xFFFFFF down to current stack size
  • Stack pointer typically points to 0x000000 offset initially
  • As stack grows, valid addresses extend from 0xFFFFFF downward

Heap memory segment that grows upward from low addresses to high addresses.

CharacteristicValue
Growth DirectionUpward (0x000000 → 0xFFFFFF)
Page Size4096 bytes
Max Segments1 per VM instance
Size Limit16MB per segment
Permission ModelFrame-based access control

Growth Behavior: The heap segment grows upward, meaning as more memory is allocated, the segment size increases toward higher addresses. When you allocate new heap space, the valid address range expands from the base (0x000000) toward higher addresses, similar to traditional heap allocators.

The VM performs the following steps for each memory access:

  1. Address Validation

    Check if the upper 16 bits of the 64-bit address are zero (ensuring 48-bit address space).

  2. Segment Extraction

    Extract segment type, index, and offset from the address using bit manipulation.

  3. Alignment Check

    Verify that the offset is properly aligned for the requested access size.

  4. Permission Validation

    Check write permissions based on segment type and current execution context.

  5. Translation

    Convert virtual address to host address based on segment type-specific logic. If any validation fails, an access violation occurs.

Segment TypeWrite BehaviorAccess Violation Conditions
Read-Only DataAlways failsAny write attempt causes violation
Account MetadataAlways failsRuntime-managed, no direct writes allowed
Account DataConditionalViolation if program doesn’t own account
Anonymous DataConditionalViolation if frame permissions insufficient

Anonymous memory segments use a frame-based permission system:

  • Each page is tagged with the frame index (program invocation call depth) that allocated it
  • Pages can only be freed by program invocations at the same call depth or higher
  • Deeper called programs cannot free pages allocated by shallower called programs
  • Page Size: 4096 bytes (TN_RUNTIME_PAGE_SZ)
  • Allocation: Dynamic allocation from a global page pool
  • Tracking: Inverted page table for efficient management
  • Limits: Enforced at transaction level for resource control

Account data uses COW semantics:

  1. Initial State: Points to read-only account data
  2. First Write: Allocates writable page and copies original data
  3. Subsequent Writes: Operate on the writable copy
  4. Commit: Modified pages are written back during transaction commit

Memory access can fail in several ways, resulting in access violations:

Violation TypeCauseDetails
Invalid AddressMalformed address or out-of-boundsUpper 16 bits non-zero, or address exceeds segment bounds
Permission DeniedUnauthorized write accessAttempting to write to read-only segments or unowned accounts
Page Boundary CrossAccess spans multiple pagesSingle access cannot cross 4KB page boundaries
Resource ExhaustionNo free pages availableAnonymous memory allocation when page pool is exhausted
Alignment ViolationMisaligned accessOffset not aligned to required boundary for access size
Invalid SegmentUnknown segment type/indexSegment type not implemented or segment index out of range
  • Page Alignment: Design data structures to fit within 4KB pages
  • Sequential Access: Prefer sequential memory access patterns
  • Segment Locality: Group related data within the same segment type
  • COW Overhead: First write to account data incurs page allocation cost
// Stack segment at offset 0x1000
ulong stack_addr = TSDK_ADDR(TSDK_SEG_TYPE_STACK, 0x0000, 0x001000);
// Result: 0x050000001000