cemc 0.1.2

Cem language compiler - A concatenative language with green threads and linear types
Documentation
/**
 * Cem Runtime - x86-64 Context Switching (Linux)
 *
 * This file implements fast context switching for x86-64 (AMD64).
 * It saves and restores callee-saved registers according to the
 * System V AMD64 ABI.
 *
 * Calling convention reference:
 * - https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
 *
 * Register usage:
 * - rax, rcx, rdx, rsi, rdi, r8-r11: Caller-saved (not preserved)
 * - rbx, rbp, r12-r15: Callee-saved (must be preserved)
 * - rsp: Stack pointer - callee-saved
 * - XMM0-XMM15: FP registers - caller-saved
 * - MXCSR: FP control/status - callee-saved (good practice)
 */

.text
.align 16

/**
 * void cem_swapcontext(cem_context_t* save_ctx, const cem_context_t* restore_ctx)
 *
 * Save current context to save_ctx and restore restore_ctx.
 *
 * Arguments (System V AMD64 calling convention):
 *   rdi = save_ctx (pointer to cem_context_t)
 *   rsi = restore_ctx (pointer to cem_context_t)
 *
 * Context layout (matches cem_context_t in context.h):
 *   Offset  Register
 *   0x00    rbx
 *   0x08    rbp
 *   0x10    r12
 *   0x18    r13
 *   0x20    r14
 *   0x28    r15
 *   0x30    rsp
 *   0x38    mxcsr (32-bit)
 */
.globl cem_swapcontext
.type cem_swapcontext, @function
cem_swapcontext:
    // Save current context to save_ctx (rdi)
    
    // Save callee-saved registers
    mov     %rbx, 0x00(%rdi)
    mov     %rbp, 0x08(%rdi)
    mov     %r12, 0x10(%rdi)
    mov     %r13, 0x18(%rdi)
    mov     %r14, 0x20(%rdi)
    mov     %r15, 0x28(%rdi)
    
    // Save stack pointer
    // Note: We save the SP *after* this function was called
    // (i.e., pointing to the return address on the stack)
    mov     %rsp, 0x30(%rdi)
    
    // Save MXCSR (floating point control/status)
    stmxcsr 0x38(%rdi)
    
    // Restore context from restore_ctx (rsi)
    
    // Restore callee-saved registers
    mov     0x00(%rsi), %rbx
    mov     0x08(%rsi), %rbp
    mov     0x10(%rsi), %r12
    mov     0x18(%rsi), %r13
    mov     0x20(%rsi), %r14
    mov     0x28(%rsi), %r15
    
    // Restore stack pointer
    mov     0x30(%rsi), %rsp
    
    // Restore MXCSR
    ldmxcsr 0x38(%rsi)
    
    // Return to the address on the stack
    // The return address was pushed by the caller when calling us,
    // and we just restored rsp to point to that address
    ret

.size cem_swapcontext, .-cem_swapcontext

/**
 * Notes on x86-64 vs ARM64:
 *
 * 1. Return address handling:
 *    - ARM64: Stored in x30 (LR) register
 *    - x86-64: Stored on the stack, popped by 'ret'
 *    - When we save rsp, we're saving the location of the return address
 *
 * 2. Stack alignment:
 *    - Must be 16-byte aligned before 'call'
 *    - After 'call', rsp points to return address (8 bytes)
 *    - So at function entry, rsp is misaligned by 8 (this is expected)
 *    - Our SP save/restore maintains this
 *
 * 3. Red zone:
 *    - 128 bytes below rsp can be used without adjustment
 *    - We don't use it here since we're saving state
 *
 * 4. For makecontext:
 *    - We need to set up the stack with a return address
 *    - The stack should have: [function_ptr] at top
 *    - When swapcontext restores rsp and executes 'ret',
 *      it will pop and jump to function_ptr
 *
 * 5. Thread-safety considerations for future work-stealing:
 *    - This implementation is thread-safe at the register level
 *    - Each strand has its own context and stack (no shared state here)
 *    - The scheduler will need atomic operations for work-stealing queues
 *    - Stack pointers and contexts are completely independent per-strand
 *    - Migration between OS threads is safe as long as:
 *      a) The strand's context is fully saved before migration
 *      b) The strand's stack memory remains valid (heap-allocated)
 *      c) Scheduler uses proper synchronization for queue operations
 */