asm tier: spawn-process-stdio + flush-port
Adds the two primitives lumbda's bend pattern needs to host GPU workers
on the asm tier, byte-identical to Python & C tiers shipped earlier.
(spawn-process-stdio path '(args …))
→ (stdin-port . stdout-port) or #f
Implementation:
- pipe2 + pipe2 (in_pipe, out_pipe)
- fork via SYS_FORK = 57
- parent: close child-side ends, encode_port both fds, make_pair
- child: dup2(in_pipe[0], 0); dup2(out_pipe[1], 1); close all 4;
execve(path, argv, NULL); exit(127) on failure
Stack frame: 4 KB scratch at %rbp (saved by RET_VAL via the
caller's pushq sequence). Layout:
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 per string. Symbols not yet
converted to strings (the Python & C tiers do that; asm callers
must pass actual strings).
(flush-port port)
→ void, no-op. asm tier uses raw fds with no userspace buffering
(unlike the C tier's FILE* wrappers), so there's nothing to flush.
New syscall constants:
SYS_PIPE2 = 293
SYS_FORK = 57
SYS_EXECVE= 59
SYS_DUP2 = 33
Two new BI_ codes (BI_SPAWNPROC = 121, BI_FLUSHPORT = 122) with the
GC_* renumbered to 123..127 and BI_COUNT = 128 (GC_NAIVE) / 123.
bn_spawnproc + bn_flushport added to symbol table + builtin name array.
Verified on 3090-ai:
λ> (display (spawn-process-stdio "/bin/true" (quote ())))
(#<port> . #<port>)
λ> (define p (spawn-process-stdio "/bin/echo" (quote ("hello" "from" "asm"))))
λ> (display p)
(#<port> . #<port>)
Critical debug: %r15 is lumbda asm's heap bump pointer (line 14:
"# %r15 = heap bump pointer"). Initial draft used %r15 as scratch
base — make_pair → heap_alloc segfaulted immediately. Reverted &
re-wrote with %rbp (callee-saved + RET_VAL restores it). All future
asm primitives that need a scratch register MUST avoid %r15.
Per-tier matrix now:
Python tier ✓ host + client
C tier ✓ host + client (cross-tier byte-identical to Python)
asm tier ✓ spawn-process-stdio + flush-port working;
read-line on subprocess pipe still missing
(~20 LoC asm) before asm can fully host workers.
This commit is contained in:
parent
aa428cdeb2
commit
4f03c48e56
1 changed files with 198 additions and 7 deletions
205
asm/lumbda.s
205
asm/lumbda.s
|
|
@ -38,6 +38,10 @@
|
||||||
.equ SYS_SENDFILE, 40
|
.equ SYS_SENDFILE, 40
|
||||||
.equ SYS_CLOCK_GETTIME, 228
|
.equ SYS_CLOCK_GETTIME, 228
|
||||||
.equ CLOCK_REALTIME, 0
|
.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 AF_INET, 2
|
||||||
.equ SOCK_STREAM,1
|
.equ SOCK_STREAM,1
|
||||||
|
|
@ -206,15 +210,17 @@
|
||||||
.equ BI_EXIT, 118
|
.equ BI_EXIT, 118
|
||||||
.equ BI_VALUES, 119
|
.equ BI_VALUES, 119
|
||||||
.equ BI_CWV, 120
|
.equ BI_CWV, 120
|
||||||
|
.equ BI_SPAWNPROC, 121
|
||||||
|
.equ BI_FLUSHPORT, 122
|
||||||
.ifdef GC_NAIVE
|
.ifdef GC_NAIVE
|
||||||
.equ BI_GC_COLLECT, 121
|
.equ BI_GC_COLLECT, 123
|
||||||
.equ BI_GC_STATS, 122
|
.equ BI_GC_STATS, 124
|
||||||
.equ BI_WITH_ARENA, 123
|
.equ BI_WITH_ARENA, 125
|
||||||
.equ BI_ARENA_STATS, 124
|
.equ BI_ARENA_STATS, 126
|
||||||
.equ BI_ARENA_SET_MODE, 125
|
.equ BI_ARENA_SET_MODE, 127
|
||||||
.equ BI_COUNT, 126
|
.equ BI_COUNT, 128
|
||||||
.else
|
.else
|
||||||
.equ BI_COUNT, 121
|
.equ BI_COUNT, 123
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
@ -343,6 +349,8 @@ bn_tcprecv: .byte 8; .ascii "tcp-recv"
|
||||||
bn_tcpsend: .byte 8; .ascii "tcp-send"
|
bn_tcpsend: .byte 8; .ascii "tcp-send"
|
||||||
bn_tcpclose: .byte 9; .ascii "tcp-close"
|
bn_tcpclose: .byte 9; .ascii "tcp-close"
|
||||||
bn_tcpsendfile: .byte 12; .ascii "tcp-sendfile"
|
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_heapsnap: .byte 13; .ascii "heap-snapshot"
|
||||||
bn_heaprest: .byte 12; .ascii "heap-restore"
|
bn_heaprest: .byte 12; .ascii "heap-restore"
|
||||||
bn_curtime: .byte 15; .ascii "current-time-ms"
|
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_randomseed, bn_randomint, bn_randomstate, bn_randomstateset
|
||||||
.quad bn_randomseedfromos
|
.quad bn_randomseedfromos
|
||||||
.quad bn_cadr, bn_sort, bn_gensym, bn_exit, bn_values, bn_cwv
|
.quad bn_cadr, bn_sort, bn_gensym, bn_exit, bn_values, bn_cwv
|
||||||
|
.quad bn_spawnproc, bn_flushport
|
||||||
.ifdef GC_NAIVE
|
.ifdef GC_NAIVE
|
||||||
.quad bn_gccollect, bn_gcstats, bn_witharena, bn_arenastats, bn_arenamode
|
.quad bn_gccollect, bn_gcstats, bn_witharena, bn_arenastats, bn_arenamode
|
||||||
.endif
|
.endif
|
||||||
|
|
@ -4273,6 +4282,10 @@ eval_list:
|
||||||
je bi_hash_set_to_list
|
je bi_hash_set_to_list
|
||||||
cmpq $BI_TCPSENDFILE, %rax
|
cmpq $BI_TCPSENDFILE, %rax
|
||||||
je bi_tcp_sendfile
|
je bi_tcp_sendfile
|
||||||
|
cmpq $BI_SPAWNPROC, %rax
|
||||||
|
je bi_spawn_process_stdio
|
||||||
|
cmpq $BI_FLUSHPORT, %rax
|
||||||
|
je bi_flush_port
|
||||||
.ifdef GC_NAIVE
|
.ifdef GC_NAIVE
|
||||||
cmpq $BI_GC_COLLECT, %rax
|
cmpq $BI_GC_COLLECT, %rax
|
||||||
je bi_gc_collect_user
|
je bi_gc_collect_user
|
||||||
|
|
@ -8647,6 +8660,184 @@ bi_tcp_sendfile:
|
||||||
movq $VAL_FALSE, %rax
|
movq $VAL_FALSE, %rax
|
||||||
RET_VAL
|
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
|
# list_reverse: %rdi = list -> %rax = reversed list
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue