Virtual Machine Memory Layout
Address Space Overview
Section titled “Address Space Overview”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.
Address Format
Section titled “Address Format”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)Address Components
Section titled “Address Components”- 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)
Memory Segment Types
Section titled “Memory Segment Types”0x00: Read-Only Data Segments
Section titled “0x00: Read-Only Data Segments”Contains immutable data that programs can read but never modify.
| Segment Index | Name | Purpose | Notes |
|---|---|---|---|
| 0x0000 | NULL | Invalid/null segment | Always causes access violation |
| 0x0001 | TXN_DATA | Transaction data | Contains serialized transaction |
| 0x0002 | SHADOW_STACK | VM shadow stack | Call frame metadata (public portion) - see Shadow Stack Frame Structure |
| 0x0003 | PROGRAM | Program bytecode | Executable RISC-V code |
| 0x0004 | BLOCK_CTX | Block context | Block metadata and timing info |
Block Context History
Section titled “Block Context History”The block context segment exposes a rolling window of recent blocks, spaced evenly within the segment to allow direct pointer math from contracts.
| Concept | Value | Details |
|---|---|---|
| Addressing | offset = blocks_ago * 0x1000 | blocks_ago = 0 is the current block |
| Per-block stride | 0x1000 bytes (TN_VM_BLOCK_CTX_SPACING) | Each context is aligned by 4096 bytes |
| History window | 512 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):
| Offset | Field | Type | Description |
|---|---|---|---|
0x00 | slot | ulong | Slot number of the block |
0x08 | block_time | ulong | Unix time in nanoseconds |
0x10 | block_price | ulong | Block price |
0x18 | state_root | fd_hash_t (32B) | State Merkle root |
0x38 | cur_block_hash | fd_hash_t (32B) | Block hash |
0x58 | block_producer | fd_pubkey_t (32B) | Producer public key |
Any access beyond this layout or outside the history window triggers an access violation.
Shadow Stack Frame Structure
Section titled “Shadow Stack Frame Structure”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.
Frame Organization
Section titled “Frame Organization”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.
Frame Structure
Section titled “Frame Structure”Each shadow stack frame contains the following fields:
| Offset | Field | Type | Size | Description |
|---|---|---|---|---|
| 0x00 | program_acc_idx | ushort | 2 bytes | Account index of the program for this frame |
| 0x02 | stack_pages | ushort | 2 bytes | Total size of stack region in pages (4KB pages) |
| 0x04 | heap_pages | ushort | 2 bytes | Total size of heap region in pages (4KB pages) |
| 0x06 | padding | - | 2 bytes | Alignment padding |
| 0x08 | saved_regs | ulong[32] | 256 bytes | Saved register state (32 registers × 8 bytes each) |
Total frame size: 264 bytes per frame
Register State
Section titled “Register State”The saved_regs array stores all 32 RISC-V registers (x0-x31) at the time of program invocation.
0x02: Account Metadata
Section titled “0x02: Account Metadata”Provides access to account metadata structures.
| Field | Description | Access Notes |
|---|---|---|
| seg_idx | Account index in transaction | Must be < transaction account count |
| offset | Byte offset in metadata | Limited to TSDK_ACCOUNT_META_FOOTPRINT bytes in the public SDK view |
- Size: Exposed to programs as
TSDK_ACCOUNT_META_FOOTPRINTbytes throughtsdk_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
0x03: Account Data
Section titled “0x03: Account Data”Page-based access to account data with copy-on-write semantics.
Address fields
| Field | Description | Constraints |
|---|---|---|
| seg_idx | Account index in transaction | Must be < transaction account count |
| offset | Byte offset into account data | Single 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. |
| Feature | Details |
|---|---|
| Page Size | 4096 bytes |
| Alignment | Enforced at page boundaries for cross-page access |
| Write Access | Requires account to be writable by current program |
| COW Pages | Automatic copy-on-write for modifications |
0x04: Event Data
Section titled “0x04: Event Data”Reserved for event emission (implementation details in event subsystem).
0x05: Stack
Section titled “0x05: Stack”Stack memory segment that grows downward from high addresses to low addresses.
| Characteristic | Value |
|---|---|
| Growth Direction | Downward (0xFFFFFF → 0x000000) |
| Page Size | 4096 bytes |
| Max Segments | 1 per VM instance |
| Size Limit | 16MB per segment |
| Permission Model | Frame-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:
0xFFFFFFdown to current stack size - Stack pointer typically points to
0x000000offset initially - As stack grows, valid addresses extend from
0xFFFFFFdownward
0x07: Heap
Section titled “0x07: Heap”Heap memory segment that grows upward from low addresses to high addresses.
| Characteristic | Value |
|---|---|
| Growth Direction | Upward (0x000000 → 0xFFFFFF) |
| Page Size | 4096 bytes |
| Max Segments | 1 per VM instance |
| Size Limit | 16MB per segment |
| Permission Model | Frame-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.
Address Translation Process
Section titled “Address Translation Process”The VM performs the following steps for each memory access:
-
Address Validation
Check if the upper 16 bits of the 64-bit address are zero (ensuring 48-bit address space).
-
Segment Extraction
Extract segment type, index, and offset from the address using bit manipulation.
-
Alignment Check
Verify that the offset is properly aligned for the requested access size.
-
Permission Validation
Check write permissions based on segment type and current execution context.
-
Translation
Convert virtual address to host address based on segment type-specific logic. If any validation fails, an access violation occurs.
Access Control and Permissions
Section titled “Access Control and Permissions”Write Access Control
Section titled “Write Access Control”| Segment Type | Write Behavior | Access Violation Conditions |
|---|---|---|
| Read-Only Data | Always fails | Any write attempt causes violation |
| Account Metadata | Always fails | Runtime-managed, no direct writes allowed |
| Account Data | Conditional | Violation if program doesn’t own account |
| Anonymous Data | Conditional | Violation if frame permissions insufficient |
Frame-Based Security
Section titled “Frame-Based Security”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
Memory Management
Section titled “Memory Management”Page Allocation
Section titled “Page Allocation”- 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
Copy-on-Write (COW)
Section titled “Copy-on-Write (COW)”Account data uses COW semantics:
- Initial State: Points to read-only account data
- First Write: Allocates writable page and copies original data
- Subsequent Writes: Operate on the writable copy
- Commit: Modified pages are written back during transaction commit
Access Violations
Section titled “Access Violations”Memory access can fail in several ways, resulting in access violations:
| Violation Type | Cause | Details |
|---|---|---|
| Invalid Address | Malformed address or out-of-bounds | Upper 16 bits non-zero, or address exceeds segment bounds |
| Permission Denied | Unauthorized write access | Attempting to write to read-only segments or unowned accounts |
| Page Boundary Cross | Access spans multiple pages | Single access cannot cross 4KB page boundaries |
| Resource Exhaustion | No free pages available | Anonymous memory allocation when page pool is exhausted |
| Alignment Violation | Misaligned access | Offset not aligned to required boundary for access size |
| Invalid Segment | Unknown segment type/index | Segment type not implemented or segment index out of range |
Performance Considerations
Section titled “Performance Considerations”- 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
Example Address Calculations
Section titled “Example Address Calculations”// Stack segment at offset 0x1000ulong stack_addr = TSDK_ADDR(TSDK_SEG_TYPE_STACK, 0x0000, 0x001000);// Result: 0x050000001000// Account index 5, offset 0x800ulong account_addr = TSDK_ADDR(TSDK_SEG_TYPE_ACCOUNT_DATA, 5, 0x800);// Result: 0x030005000800// Transaction data at offset 0x40ulong txn_addr = TSDK_ADDR(TSDK_SEG_TYPE_READONLY_DATA, TSDK_SEG_IDX_TXN_DATA, 0x40);// Result: 0x000001000040