From c2fcaf8f8deef3a6f49a126d9d250594aa46b149 Mon Sep 17 00:00:00 2001 From: IgorCielniak Date: Tue, 3 Feb 2026 09:41:11 +0100 Subject: [PATCH] ported dynamic arrays and strlen to l2 --- stdlib/arr.sl | 303 ++++++++++++++-------------------------------- stdlib/arr_asm.sl | 248 +++++++++++++++++++++++++++++++++++++ stdlib/utils.sl | 25 ++-- 3 files changed, 344 insertions(+), 232 deletions(-) create mode 100644 stdlib/arr_asm.sl diff --git a/stdlib/arr.sl b/stdlib/arr.sl index 3f513a0..3345fe3 100644 --- a/stdlib/arr.sl +++ b/stdlib/arr.sl @@ -9,240 +9,113 @@ # Allocation: mmap; free: munmap. # Growth: allocate new block, copy elements, munmap old block. +import mem.sl + # : arr_new ( cap -- arr ) -:asm arr_new { - mov r14, [r12] ; requested cap - cmp r14, 1 - jge .cap_ok - mov r14, 1 -.cap_ok: - ; bytes = 24 + cap*8 - mov rsi, r14 - shl rsi, 3 - add rsi, 24 - - ; mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0) - xor rdi, rdi - mov rdx, 3 - mov r10, 34 - mov r8, -1 - xor r9, r9 - mov rax, 9 - syscall - - ; header - mov qword [rax], 0 - mov [rax + 8], r14 - lea rbx, [rax + 24] - mov [rax + 16], rbx - - ; replace cap with arr pointer - mov [r12], rax - ret -} -; +# Create a new array with given initial capacity (minimum 1) +word arr_new + dup 1 < if drop 1 end + dup 8 * 24 + alloc + dup 0 ! # len = 0 + over over 8 + swap ! # cap = requested cap + dup 24 + over 16 + swap ! # data = arr + 24 + nip +end # : arr_len ( arr -- len ) -:asm arr_len { - mov rax, [r12] - mov rax, [rax] - mov [r12], rax - ret -} -; +word arr_len @ end # : arr_cap ( arr -- cap ) -:asm arr_cap { - mov rax, [r12] - mov rax, [rax + 8] - mov [r12], rax - ret -} -; +word arr_cap 8 + @ end # : arr_data ( arr -- ptr ) -:asm arr_data { - mov rax, [r12] - mov rax, [rax + 16] - mov [r12], rax - ret -} -; +word arr_data 16 + @ end # : arr_free ( arr -- ) -:asm arr_free { - mov rbx, [r12] ; base - mov rcx, [rbx + 8] ; cap - mov rsi, rcx - shl rsi, 3 - add rsi, 24 - mov rdi, rbx - mov rax, 11 - syscall - add r12, 8 ; drop arr - ret -} -; +word arr_free + dup arr_cap 8 * 24 + free +end + +# Helper: copy n qwords from src to dst (dst src n --) +word arr_copy_elements + while dup 0 > do + over @ 3 pick swap ! # dst = *src + swap 8 + swap # src += 8 + rot 8 + -rot # dst += 8 + 1 - + end + drop 2drop +end # : arr_reserve ( cap arr -- arr ) # Ensures capacity >= cap; returns (possibly moved) arr pointer. -:asm arr_reserve { - mov rbx, [r12] ; arr - mov r14, [r12 + 8] ; requested cap - cmp r14, 1 - jge .req_ok - mov r14, 1 -.req_ok: - mov rdx, [rbx + 8] ; old cap - cmp rdx, r14 - jae .no_change +word arr_reserve + swap dup 1 < if drop 1 end swap # reqcap arr - ; alloc new block: bytes = 24 + reqcap*8 - mov rsi, r14 - shl rsi, 3 - add rsi, 24 - xor rdi, rdi - mov rdx, 3 - mov r10, 34 - mov r8, -1 - xor r9, r9 - mov rax, 9 - syscall + # Check: if arr_cap >= reqcap, do nothing + over over arr_cap swap + >= if + nip + else + # Allocate new block + over 8 * 24 + alloc - mov r10, rax ; new base - lea r9, [r10 + 24] ; new data + # Copy header + over arr_len over swap ! # len + 2 pick over 8 + swap ! # cap = reqcap + dup 24 + over 16 + swap ! # data = newarr + 24 - ; header - mov r8, [rbx] ; len - mov [r10], r8 - mov [r10 + 8], r14 - mov [r10 + 16], r9 + # Copy elements + dup arr_data + 2 pick arr_data + 3 pick arr_len + arr_copy_elements - ; copy elements from old data - mov r11, [rbx + 16] ; old data - xor rcx, rcx ; i -.copy_loop: - cmp rcx, r8 - je .copy_done - mov rdx, [r11 + rcx*8] - mov [r9 + rcx*8], rdx - inc rcx - jmp .copy_loop -.copy_done: - - ; munmap old block - mov rsi, [rbx + 8] - shl rsi, 3 - add rsi, 24 - mov rdi, rbx - mov rax, 11 - syscall - - ; return new arr only - mov [r12 + 8], r10 - add r12, 8 - ret - -.no_change: - ; drop cap, keep arr - mov [r12 + 8], rbx - add r12, 8 - ret -} -; + # Free old and return new + swap arr_free + nip + end +end # : arr_push ( x arr -- arr ) -:asm arr_push { - mov rbx, [r12] ; arr - mov rcx, [rbx] ; len - mov rdx, [rbx + 8] ; cap - cmp rcx, rdx - jb .have_space +# Push element onto array, growing if needed +word arr_push + dup arr_len over arr_cap >= if + dup arr_cap dup 1 < if drop 1 end 2 * + over arr_reserve + nip + end - ; grow: newcap = max(1, cap) * 2 - mov r14, rdx - cmp r14, 1 - jae .cap_ok - mov r14, 1 -.cap_ok: - shl r14, 1 + # Store x at data[len] + dup arr_data over arr_len 8 * + + rot over swap ! drop - ; alloc new block - mov rsi, r14 - shl rsi, 3 - add rsi, 24 - xor rdi, rdi - mov rdx, 3 - mov r10, 34 - mov r8, -1 - xor r9, r9 - mov rax, 9 - syscall - - mov r10, rax ; new base - lea r9, [r10 + 24] ; new data - - ; header - mov rcx, [rbx] ; len (reload; syscall clobbers rcx) - mov [r10], rcx - mov [r10 + 8], r14 - mov [r10 + 16], r9 - - ; copy old data - mov r11, [rbx + 16] ; old data - xor r8, r8 -.push_copy_loop: - cmp r8, rcx - je .push_copy_done - mov rdx, [r11 + r8*8] - mov [r9 + r8*8], rdx - inc r8 - jmp .push_copy_loop -.push_copy_done: - - ; munmap old block - mov rsi, [rbx + 8] - shl rsi, 3 - add rsi, 24 - mov rdi, rbx - mov rax, 11 - syscall - - ; switch to new base - mov rbx, r10 - -.have_space: - ; store element at data[len] - mov r9, [rbx + 16] - mov rax, [r12 + 8] ; x - mov rcx, [rbx] ; len - mov [r9 + rcx*8], rax - inc rcx - mov [rbx], rcx - - ; return arr only - mov [r12 + 8], rbx - add r12, 8 - ret -} -; + # Increment len + dup @ 1 + over swap ! +end # : arr_pop ( arr -- x arr ) -:asm arr_pop { - mov rbx, [r12] ; arr - mov rcx, [rbx] ; len - test rcx, rcx - jz .empty - dec rcx - mov [rbx], rcx - mov rdx, [rbx + 16] ; data - mov rax, [rdx + rcx*8] - jmp .push -.empty: - xor rax, rax -.push: - sub r12, 8 - mov [r12], rax - ret -} -; +# Pop element from array (returns 0 if empty) +word arr_pop + dup arr_len 0 == if + 0 swap + else + # Decrement len + dup @ 1 - over swap ! + # Get element at new len position + dup arr_data over arr_len 8 * + @ + swap + end +end + +# : arr_get ( i arr -- x ) +# Get element at index i +word arr_get + arr_data swap 8 * + @ +end + +# : arr_set ( x i arr -- ) +# Set element at index i to x +word arr_set + arr_data swap 8 * + swap ! +end diff --git a/stdlib/arr_asm.sl b/stdlib/arr_asm.sl new file mode 100644 index 0000000..48c7327 --- /dev/null +++ b/stdlib/arr_asm.sl @@ -0,0 +1,248 @@ +# Dynamic arrays (qword elements) +# +# Layout at address `arr`: +# [arr + 0] len (qword) +# [arr + 8] cap (qword) +# [arr + 16] data (qword) = arr + 24 +# [arr + 24] elements (cap * 8 bytes) +# +# Allocation: mmap; free: munmap. +# Growth: allocate new block, copy elements, munmap old block. + +# : arr_new ( cap -- arr ) +:asm arr_new { + mov r14, [r12] ; requested cap + cmp r14, 1 + jge .cap_ok + mov r14, 1 +.cap_ok: + ; bytes = 24 + cap*8 + mov rsi, r14 + shl rsi, 3 + add rsi, 24 + + ; mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0) + xor rdi, rdi + mov rdx, 3 + mov r10, 34 + mov r8, -1 + xor r9, r9 + mov rax, 9 + syscall + + ; header + mov qword [rax], 0 + mov [rax + 8], r14 + lea rbx, [rax + 24] + mov [rax + 16], rbx + + ; replace cap with arr pointer + mov [r12], rax + ret +} +; + +# : arr_len ( arr -- len ) +:asm arr_len { + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +} +; + +# : arr_cap ( arr -- cap ) +:asm arr_cap { + mov rax, [r12] + mov rax, [rax + 8] + mov [r12], rax + ret +} +; + +# : arr_data ( arr -- ptr ) +:asm arr_data { + mov rax, [r12] + mov rax, [rax + 16] + mov [r12], rax + ret +} +; + +# : arr_free ( arr -- ) +:asm arr_free { + mov rbx, [r12] ; base + mov rcx, [rbx + 8] ; cap + mov rsi, rcx + shl rsi, 3 + add rsi, 24 + mov rdi, rbx + mov rax, 11 + syscall + add r12, 8 ; drop arr + ret +} +; + +# : arr_reserve ( cap arr -- arr ) +# Ensures capacity >= cap; returns (possibly moved) arr pointer. +:asm arr_reserve { + mov rbx, [r12] ; arr + mov r14, [r12 + 8] ; requested cap + cmp r14, 1 + jge .req_ok + mov r14, 1 +.req_ok: + mov rdx, [rbx + 8] ; old cap + cmp rdx, r14 + jae .no_change + + ; alloc new block: bytes = 24 + reqcap*8 + mov rsi, r14 + shl rsi, 3 + add rsi, 24 + xor rdi, rdi + mov rdx, 3 + mov r10, 34 + mov r8, -1 + xor r9, r9 + mov rax, 9 + syscall + + mov r10, rax ; new base + lea r9, [r10 + 24] ; new data + + ; header + mov r8, [rbx] ; len + mov [r10], r8 + mov [r10 + 8], r14 + mov [r10 + 16], r9 + + ; copy elements from old data + mov r11, [rbx + 16] ; old data + xor rcx, rcx ; i +.copy_loop: + cmp rcx, r8 + je .copy_done + mov rdx, [r11 + rcx*8] + mov [r9 + rcx*8], rdx + inc rcx + jmp .copy_loop +.copy_done: + + ; munmap old block + mov rsi, [rbx + 8] + shl rsi, 3 + add rsi, 24 + mov rdi, rbx + mov rax, 11 + syscall + + ; return new arr only + mov [r12 + 8], r10 + add r12, 8 + ret + +.no_change: + ; drop cap, keep arr + mov [r12 + 8], rbx + add r12, 8 + ret +} +; + +# : arr_push ( x arr -- arr ) +:asm arr_push { + mov rbx, [r12] ; arr + mov rcx, [rbx] ; len + mov rdx, [rbx + 8] ; cap + cmp rcx, rdx + jb .have_space + + ; grow: newcap = max(1, cap) * 2 + mov r14, rdx + cmp r14, 1 + jae .cap_ok + mov r14, 1 +.cap_ok: + shl r14, 1 + + ; alloc new block + mov rsi, r14 + shl rsi, 3 + add rsi, 24 + xor rdi, rdi + mov rdx, 3 + mov r10, 34 + mov r8, -1 + xor r9, r9 + mov rax, 9 + syscall + + mov r10, rax ; new base + lea r9, [r10 + 24] ; new data + + ; header + mov rcx, [rbx] ; len (reload; syscall clobbers rcx) + mov [r10], rcx + mov [r10 + 8], r14 + mov [r10 + 16], r9 + + ; copy old data + mov r11, [rbx + 16] ; old data + xor r8, r8 +.push_copy_loop: + cmp r8, rcx + je .push_copy_done + mov rdx, [r11 + r8*8] + mov [r9 + r8*8], rdx + inc r8 + jmp .push_copy_loop +.push_copy_done: + + ; munmap old block + mov rsi, [rbx + 8] + shl rsi, 3 + add rsi, 24 + mov rdi, rbx + mov rax, 11 + syscall + + ; switch to new base + mov rbx, r10 + +.have_space: + ; store element at data[len] + mov r9, [rbx + 16] + mov rax, [r12 + 8] ; x + mov rcx, [rbx] ; len + mov [r9 + rcx*8], rax + inc rcx + mov [rbx], rcx + + ; return arr only + mov [r12 + 8], rbx + add r12, 8 + ret +} +; + +# : arr_pop ( arr -- x arr ) +:asm arr_pop { + mov rbx, [r12] ; arr + mov rcx, [rbx] ; len + test rcx, rcx + jz .empty + dec rcx + mov [rbx], rcx + mov rdx, [rbx + 16] ; data + mov rax, [rdx + rcx*8] + jmp .push +.empty: + xor rax, rax +.push: + sub r12, 8 + mov [r12], rax + ret +} +; \ No newline at end of file diff --git a/stdlib/utils.sl b/stdlib/utils.sl index 1cc6695..1f5a256 100644 --- a/stdlib/utils.sl +++ b/stdlib/utils.sl @@ -33,23 +33,14 @@ end # : strlen ( addr -- len ) # for null terminated strings - -:asm strlen { - mov rsi, [r12] ; address - xor rcx, rcx ; length counter -.strlen_loop: - mov al, [rsi] - test al, al - jz .strlen_done - inc rcx - inc rsi - jmp .strlen_loop -.strlen_done: - mov rax, rcx - mov [r12], rax ; store length on stack - ret -} -; +word strlen + 0 swap # len addr + while dup c@ 0 != do + 1 + # addr++ + swap 1 + swap # len++ + end + drop # drop addr, leave len +end word digitsN>num # ( d_{n-1} ... d0 n -- value ), digits bottom=MSD, top=LSD, length on top (MSD-most significant digit, LSD-least significant digit) 0 swap # place accumulator below length