diff --git a/asm/lumbda.s b/asm/lumbda.s index c258ead..c58459a 100644 --- a/asm/lumbda.s +++ b/asm/lumbda.s @@ -38,6 +38,10 @@ .equ SYS_SENDFILE, 40 .equ SYS_CLOCK_GETTIME, 228 .equ CLOCK_REALTIME, 0 +.equ SYS_PIPE2, 293 +.equ SYS_FORK, 57 +.equ SYS_EXECVE,59 +.equ SYS_DUP2, 33 .equ AF_INET, 2 .equ SOCK_STREAM,1 @@ -206,15 +210,17 @@ .equ BI_EXIT, 118 .equ BI_VALUES, 119 .equ BI_CWV, 120 +.equ BI_SPAWNPROC, 121 +.equ BI_FLUSHPORT, 122 .ifdef GC_NAIVE -.equ BI_GC_COLLECT, 121 -.equ BI_GC_STATS, 122 -.equ BI_WITH_ARENA, 123 -.equ BI_ARENA_STATS, 124 -.equ BI_ARENA_SET_MODE, 125 -.equ BI_COUNT, 126 +.equ BI_GC_COLLECT, 123 +.equ BI_GC_STATS, 124 +.equ BI_WITH_ARENA, 125 +.equ BI_ARENA_STATS, 126 +.equ BI_ARENA_SET_MODE, 127 +.equ BI_COUNT, 128 .else -.equ BI_COUNT, 121 +.equ BI_COUNT, 123 .endif # ============================================================ @@ -343,6 +349,8 @@ bn_tcprecv: .byte 8; .ascii "tcp-recv" bn_tcpsend: .byte 8; .ascii "tcp-send" bn_tcpclose: .byte 9; .ascii "tcp-close" bn_tcpsendfile: .byte 12; .ascii "tcp-sendfile" +bn_spawnproc: .byte 19; .ascii "spawn-process-stdio" +bn_flushport: .byte 10; .ascii "flush-port" bn_heapsnap: .byte 13; .ascii "heap-snapshot" bn_heaprest: .byte 12; .ascii "heap-restore" bn_curtime: .byte 15; .ascii "current-time-ms" @@ -487,6 +495,7 @@ bi_names: .quad bn_randomseed, bn_randomint, bn_randomstate, bn_randomstateset .quad bn_randomseedfromos .quad bn_cadr, bn_sort, bn_gensym, bn_exit, bn_values, bn_cwv + .quad bn_spawnproc, bn_flushport .ifdef GC_NAIVE .quad bn_gccollect, bn_gcstats, bn_witharena, bn_arenastats, bn_arenamode .endif @@ -4273,6 +4282,10 @@ eval_list: je bi_hash_set_to_list cmpq $BI_TCPSENDFILE, %rax je bi_tcp_sendfile + cmpq $BI_SPAWNPROC, %rax + je bi_spawn_process_stdio + cmpq $BI_FLUSHPORT, %rax + je bi_flush_port .ifdef GC_NAIVE cmpq $BI_GC_COLLECT, %rax je bi_gc_collect_user @@ -8647,6 +8660,184 @@ bi_tcp_sendfile: movq $VAL_FALSE, %rax RET_VAL +# ============================================================ +# bi_spawn_process_stdio: (spawn-process-stdio "path" '("arg1" ...)) +# → (stdin-port . stdout-port) or #f +# +# %r15 is lumbda's heap bump pointer — DO NOT clobber. +# Scratch base lives in %rbp (callee-saved; RET_VAL restores it). +# +# Stack scratch layout (4 KB): +# 0..15 = in_pipe + out_pipe (4 × int32 fds) +# 16..143 = argv[] (16 ptrs × 8 B) +# 144..399 = path buf (256 B, null-term) +# 400..2447 = arg bufs (8 args × 256 B) +# +# Limits: ≤ 8 args, ≤ 255 bytes each. Strings only. +# ============================================================ +bi_spawn_process_stdio: + pushq %r13 + pushq %r14 + subq $4104, %rsp # 4096 + 8 to re-align rsp to 16 + movq %rsp, %rbp # %rbp = scratch base + + # ── arg 0: path → copy to scratch+144 ── + GETARG %rdi + andq $-8, %rdi + movq (%rdi), %rcx + leaq 8(%rdi), %rdi + leaq 144(%rbp), %rsi + call copy_fname_to_stack + leaq 144(%rbp), %rax + movq %rax, 16(%rbp) # argv[0] = path + + # ── arg 1: args list → argv[1..N] ── + GETARG %r14 + xorq %r13, %r13 + incq %r13 # %r13 = arg index, start at 1 +.sps_arg_loop: + cmpq $VAL_NIL, %r14 + je .sps_args_done + cmpq $9, %r13 + jge .sps_args_done + + movq %r14, %rax + andq $-8, %rax + movq (%rax), %rdi # car + movq 8(%rax), %r14 # cdr + + andq $-8, %rdi + movq (%rdi), %rcx + leaq 8(%rdi), %rdi + # arg buf addr = rbp + 400 + (i-1)*256 + movq %r13, %rax + decq %rax + shlq $8, %rax + addq $400, %rax + addq %rbp, %rax + movq %rax, %rsi + pushq %r13 + pushq %r14 + call copy_fname_to_stack + popq %r14 + popq %r13 + # argv[i] = arg buf addr (recomputed) + movq %r13, %rax + shlq $3, %rax + addq $16, %rax + addq %rbp, %rax + movq %r13, %rdx + decq %rdx + shlq $8, %rdx + addq $400, %rdx + addq %rbp, %rdx + movq %rdx, (%rax) + incq %r13 + jmp .sps_arg_loop +.sps_args_done: + movq %r13, %rax + shlq $3, %rax + addq $16, %rax + addq %rbp, %rax + movq $0, (%rax) # argv[N] = NULL + + # ── pipe2(in_pipe, 0) ── + movq $SYS_PIPE2, %rax + movq %rbp, %rdi + xorq %rsi, %rsi + syscall + testq %rax, %rax + js .sps_fail + # ── pipe2(out_pipe, 0) ── + movq $SYS_PIPE2, %rax + leaq 8(%rbp), %rdi + xorq %rsi, %rsi + syscall + testq %rax, %rax + js .sps_close_in + # ── fork() ── + movq $SYS_FORK, %rax + syscall + testq %rax, %rax + js .sps_close_both + jz .sps_child + + # ── parent ── + movl 0(%rbp), %edi # close in_pipe[0] + movq $SYS_CLOSE, %rax + syscall + movl 12(%rbp), %edi # close out_pipe[1] + movq $SYS_CLOSE, %rax + syscall + movl 4(%rbp), %edi # in_pipe[1] → parent writes + call encode_port + movq %rax, %r13 # save stdin-port + movl 8(%rbp), %edi # out_pipe[0] → parent reads + call encode_port + movq %rax, %rsi # cdr + movq %r13, %rdi # car + call make_pair + addq $4104, %rsp + popq %r14 + popq %r13 + RET_VAL + +.sps_child: + movl 0(%rbp), %edi + xorq %rsi, %rsi + movq $SYS_DUP2, %rax + syscall + movl 12(%rbp), %edi + movq $1, %rsi + movq $SYS_DUP2, %rax + syscall + movl 0(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall + movl 4(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall + movl 8(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall + movl 12(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall + leaq 144(%rbp), %rdi + leaq 16(%rbp), %rsi + xorq %rdx, %rdx + movq $SYS_EXECVE, %rax + syscall + movq $127, %rdi + movq $SYS_EXIT, %rax + syscall + +.sps_close_both: + movl 8(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall + movl 12(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall +.sps_close_in: + movl 0(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall + movl 4(%rbp), %edi + movq $SYS_CLOSE, %rax + syscall +.sps_fail: + movq $VAL_FALSE, %rax + addq $4104, %rsp + popq %r14 + popq %r13 + RET_VAL + +# bi_flush_port: asm tier uses raw fds — no userspace buffering, no-op. +bi_flush_port: + movq $VAL_VOID, %rax + RET_VAL + # ============================================================ # list_reverse: %rdi = list -> %rax = reversed list # ============================================================