741 lines
18 KiB
NASM
741 lines
18 KiB
NASM
section .rdata
|
|
INIT_CAPACITY equ 4096
|
|
|
|
section .text
|
|
extern memcpy
|
|
extern memmove
|
|
extern memswap
|
|
extern oom
|
|
extern panic
|
|
extern eprint_str
|
|
extern allocate
|
|
|
|
global vec_init
|
|
global vec_init_with
|
|
global vec_extend
|
|
global vec_push
|
|
global vec_pop
|
|
global vec_drop_last
|
|
global vec_swap
|
|
global vec_remove
|
|
global vec_get
|
|
global vec_get_or
|
|
global vec_drop
|
|
global vec_find
|
|
global vec_insert
|
|
global vec_insert_many
|
|
global vec_insert_sorted
|
|
global vec_binary_search_by
|
|
|
|
global vec_tests
|
|
|
|
|
|
;; Byte vector structure
|
|
;; start-structs
|
|
;; struct BlobVec {
|
|
;; data: *mut u8,
|
|
;; len: usize,
|
|
;; cap: usize,
|
|
;; elem_size: usize,
|
|
;; drop: Option<extern "C" fn(*mut u8)>,
|
|
;; }
|
|
;; end-structs
|
|
;; size: 40 bytes
|
|
;; align: 8 bytes
|
|
|
|
|
|
;; Initialize a new vector
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: item_size
|
|
;; rdx: drop function pointer
|
|
;; fn vec_init(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>)
|
|
vec_init:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push rdx
|
|
push rsi
|
|
push rdi
|
|
; (*vec).data = allocate(INIT_CAPACITY);
|
|
mov rdi, INIT_CAPACITY
|
|
call allocate
|
|
pop r15
|
|
mov [r15], rax
|
|
; (*vec).len = 0;
|
|
mov qword [r15 + 8], 0
|
|
pop rsi
|
|
mov qword [r15 + 24], rsi ; item_size
|
|
; (*vec).capacity = INIT_CAPACITY / item_size;
|
|
mov rax, INIT_CAPACITY
|
|
xor rdx, rdx
|
|
div rsi
|
|
mov qword [r15 + 16], rax
|
|
pop rdx
|
|
mov qword [r15 + 32], rdx ; drop
|
|
pop rbp
|
|
ret
|
|
|
|
;; Initialize a new vector
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: item_size
|
|
;; rdx: drop function pointer
|
|
;; rcx: capacity
|
|
;; fn vec_init_with(vec: *mut Vec, item_size: usize, drop: Option<fn(*mut u8)>, capacity: usize)
|
|
vec_init_with:
|
|
push rbp
|
|
mov rbp, rsp
|
|
sub rsp, 0x20
|
|
mov [rsp], rdx ; save drop
|
|
mov [rsp + 8], rsi ; save item_size
|
|
mov [rsp + 16], rcx ; save capacity
|
|
push rdi
|
|
; (*vec).data = allocate(INIT_CAPACITY);
|
|
|
|
xor rdx, rdx
|
|
mov rax, rcx
|
|
mul rsi ; capacity * item_size
|
|
mov rdi, rax
|
|
call allocate
|
|
pop r15
|
|
mov [r15], rax
|
|
; (*vec).len = 0;
|
|
mov qword [r15 + 8], 0
|
|
mov rax, [rsp + 8]
|
|
mov qword [r15 + 24], rax ; item_size
|
|
mov rax, [rsp + 16]
|
|
mov qword [r15 + 16], rax ; capacity
|
|
mov rax, [rsp]
|
|
mov qword [r15 + 32], rax ; drop
|
|
add rsp, 0x20
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: index
|
|
;; rdx: pointer to default value
|
|
;; fn vec_get(vec: *mut Vec, index: usize, default: *mut u8) -> *mut u8
|
|
vec_get_or:
|
|
push rbp
|
|
mov rbp, rsp
|
|
; if (index >= vec.len) panic();
|
|
mov rax, [rdi + 8] ; len
|
|
cmp rsi, rax
|
|
jge .default
|
|
; return &mut vec.data[index * vec.item_size];
|
|
mov rax, [rdi + 24] ; item_size
|
|
mul rsi ; index * item_size
|
|
mov rsi, [rdi] ; data
|
|
add rax, rsi ; data + index * item_size
|
|
pop rbp
|
|
ret
|
|
.default:
|
|
mov rax, rdx
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: index
|
|
;; fn vec_get(vec: *mut Vec, index: usize) -> *mut u8
|
|
vec_get:
|
|
push rbp
|
|
mov rbp, rsp
|
|
; if (index >= vec.len) panic();
|
|
mov rax, [rdi + 8] ; len
|
|
cmp rsi, rax
|
|
jge .panic
|
|
; return &mut vec.data[index * vec.item_size];
|
|
mov rax, [rdi + 24] ; item_size
|
|
mul rsi ; index * item_size
|
|
mov rsi, [rdi] ; data
|
|
add rax, rsi ; data + index * item_size
|
|
pop rbp
|
|
ret
|
|
.panic:
|
|
call panic
|
|
pop rbp
|
|
ret
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: pointer to data to push
|
|
;; fn vec_push(vec: *mut Vec, data: &[u8])
|
|
vec_push:
|
|
push rbp
|
|
mov rbp, rsp
|
|
; let vec, ptr, size;
|
|
sub rsp, 24
|
|
mov [rsp], rdi ; save vec
|
|
mov [rsp + 8], rsi ; save data ptr
|
|
; vec_try_grow(vec, size);
|
|
mov rsi, [rdi + 8]
|
|
inc rsi
|
|
call vec_try_grow
|
|
; memcpy(&vec.data[vec.len], data, size);
|
|
mov rax, [rsp] ; vec
|
|
mov rcx, [rax] ; vec.data
|
|
mov rdi, [rax + 8] ; vec.len
|
|
mov rax, [rax + 24] ; vec.item_size
|
|
mul rdi ; len * item_size
|
|
add rax, rcx ; data + len * item_size
|
|
mov rdi, rax ; dest ptr
|
|
mov rsi, [rsp + 8] ; data ptr
|
|
mov rax, [rsp] ; vec
|
|
mov rdx, [rax + 24] ; item_size
|
|
call memcpy
|
|
; vec.len += 1;
|
|
mov rax, [rsp] ; vec
|
|
add qword [rax + 8], 1
|
|
add rsp, 24
|
|
pop rbp
|
|
ret
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; fn vec_pop(vec: *mut Vec)
|
|
vec_pop:
|
|
push rbp
|
|
mov rbp, rsp
|
|
; if vec.len == 0 panic();
|
|
mov rax, [rdi + 8] ; len
|
|
test rax, rax
|
|
je .underflow
|
|
; vec.len -= 1;
|
|
sub rax, 1
|
|
mov [rdi + 8], rax
|
|
pop rbp
|
|
ret
|
|
; }
|
|
.underflow:
|
|
call panic
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; fn vec_pop(vec: *mut Vec)
|
|
vec_drop_last:
|
|
push rbp
|
|
mov rbp, rsp
|
|
; if vec.len == 0 panic();
|
|
mov rax, [rdi + 8] ; len
|
|
test rax, rax
|
|
je .underflow
|
|
; vec.len -= 1;
|
|
sub rax, 1
|
|
mov [rdi + 8], rax
|
|
; if let Some(drop) = vec.drop {
|
|
mov r8, [rdi + 32]
|
|
test r8, r8
|
|
je .ret
|
|
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
|
|
xor rdx, rdx
|
|
mul qword [rdi + 24] ; len * item_size
|
|
mov rdi, [rdi] ; data
|
|
add rdi, rax ; data + len * item_size
|
|
call r8
|
|
.ret:
|
|
pop rbp
|
|
ret
|
|
; }
|
|
.underflow:
|
|
call panic
|
|
pop rbp
|
|
ret
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: index a
|
|
;; rdx: index b
|
|
;; fn vec_swap(vec: *mut Vec, a: usize, b: usize)
|
|
vec_swap:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push rbx
|
|
; let vec, a, b;
|
|
sub rsp, 24
|
|
mov [rsp], rdi ; save vec
|
|
; let max_index = max(a, b);
|
|
mov rbx, rsi
|
|
cmp rbx, rdx
|
|
cmovl rbx, rdx
|
|
; if (max_index >= vec.len) panic();
|
|
mov rax, [rdi + 8] ; vec.len
|
|
cmp rbx, rax
|
|
jge .panic
|
|
|
|
; a = a * item_size;
|
|
mov rbx, [rdi + 24] ; item_size
|
|
mov rax, rdx
|
|
xor rdx, rdx
|
|
mul rbx ; b * item_size
|
|
mov [rsp + 16], rax
|
|
; b = b * item_size;
|
|
mov rax, rsi
|
|
xor rdx, rdx
|
|
mul rbx ; a * item_size
|
|
mov [rsp + 8], rax
|
|
|
|
; // SAFETY: a and b must not overlap
|
|
; memswap(&mut vec.data.add(a), &mut vec.data.add(b), vec.item_size);
|
|
mov rdx, [rdi + 24] ; item_size
|
|
mov rdi, [rdi] ; vec.data
|
|
mov rsi, rdi
|
|
add rdi, [rsp + 16] ; data + a
|
|
add rsi, [rsp + 8] ; data + b
|
|
call memswap
|
|
add rsp, 24
|
|
pop rbx
|
|
pop rbp
|
|
ret
|
|
.panic:
|
|
call panic
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: index
|
|
;; fn vec_remove(vec: *mut Vec, index: usize)
|
|
vec_remove:
|
|
push rbp
|
|
mov rbp, rsp
|
|
sub rsp, 0x10
|
|
mov [rsp], rdi ; save vec
|
|
mov [rsp + 8], rsi ; save index
|
|
|
|
; if (index >= vec.len) panic();
|
|
mov rax, [rdi + 8] ; len
|
|
cmp rsi, rax
|
|
jge .panic
|
|
; if (vec.len - 1 != index {
|
|
sub rax, 1
|
|
cmp rsi, rax
|
|
je .remove_last
|
|
; vec_swap(vec, index, vec.len - 1);
|
|
mov rdx, rax ; len - 1
|
|
call vec_swap
|
|
; }
|
|
; vec.len -= 1;
|
|
.remove_last:
|
|
mov rdi, [rsp] ; vec
|
|
mov rax, [rdi + 8] ; len
|
|
sub rax, 1
|
|
mov [rdi + 8], rax
|
|
; if let Some(drop) = vec.drop {
|
|
mov r8, [rdi + 32]
|
|
test r8, r8
|
|
je .ret
|
|
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
|
|
mul qword [rdi + 24] ; len * item_size
|
|
mov rdi, [rdi] ; data
|
|
add rdi, rax ; data + len * item_size
|
|
call r8
|
|
; }
|
|
.ret:
|
|
add rsp, 0x10
|
|
pop rbp
|
|
ret
|
|
.panic:
|
|
call panic
|
|
|
|
;; essentially a reserve() function
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: desired size
|
|
;; fn vec_try_grow(vec: *mut Vec, new_size: usize) -> bool
|
|
vec_try_grow:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push rbx
|
|
mov rax, [rdi + 16] ; capacity
|
|
mov rbx, [rdi + 8] ; len
|
|
cmp rsi, rax
|
|
jge .grow ; grow if new_size >= capacity
|
|
pop rbx
|
|
xor rax, rax
|
|
pop rbp
|
|
ret
|
|
.grow:
|
|
; let vec;
|
|
; let new_capacity;
|
|
; let new_data;
|
|
sub rsp, 24
|
|
mov [rsp], rdi
|
|
; new_capacity = max(capacity * 2, len + 1)
|
|
mov rcx, [rdi + 16] ; capacity
|
|
shl rcx, 1 ; capacity * 2
|
|
cmp rcx, rbx
|
|
cmovl rcx, rbx ; rcx = new_capacity
|
|
mov [rsp + 8], rcx
|
|
mov rax, rcx
|
|
mul qword [rdi + 24] ; new_capacity * item_size
|
|
; new_data = allocate(new_capacity);
|
|
mov rdi, rax
|
|
call allocate
|
|
mov [rsp + 16], rax
|
|
mov rdi, [rsp]
|
|
; memcpy(new_data, old_data, len * vec.item_size);
|
|
mov rax, [rdi + 8] ; len
|
|
mul qword [rdi + 24] ; len * item_size
|
|
mov rdx, rax ; len
|
|
mov rsi, [rdi] ; old_data
|
|
mov rdi, [rsp + 16] ; new_data
|
|
call memcpy
|
|
; free(old_data) // TODO
|
|
; update vec
|
|
mov rdi, [rsp]
|
|
mov rax, [rsp + 16]
|
|
mov [rdi], rax ; data = new_data
|
|
mov rcx, [rsp + 8]
|
|
mov [rdi + 16], rcx ; capacity = new_capacity
|
|
add rsp, 24
|
|
pop rbx
|
|
xor rax, rax
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: pointer to Vec struct
|
|
vec_drop:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push rdi
|
|
; if let Some(drop) = vec.drop {
|
|
mov r12, [rdi + 32]
|
|
test r12, r12
|
|
je .ret
|
|
; for i in 0..vec.len {
|
|
xor r13, r13
|
|
mov r14, [rdi + 8] ; len
|
|
.loop:
|
|
cmp r13, r14
|
|
jge .ret
|
|
mov rdi, [rsp]
|
|
; drop(&mut vec.data[i * vec.item_size..(i + 1) * vec.item_size]);
|
|
mov rax, r13
|
|
mul qword [rdi + 24] ; i * item_size
|
|
mov rdi, [rdi] ; data
|
|
add rdi, rax
|
|
call r12
|
|
inc r13
|
|
jmp .loop
|
|
; }
|
|
; }
|
|
; free(vec.data);
|
|
.ret:
|
|
pop rdi
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop rbp
|
|
ret
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: poiter to object to find
|
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> bool
|
|
;; rcx: compare_fn context
|
|
vec_find:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push r12
|
|
sub rsp, 0x28
|
|
mov [rsp], rdi ; save vec
|
|
mov [rsp + 8], rsi ; save object ptr
|
|
mov [rsp + 0x10], rdx ; save compare fn
|
|
mov rax, [rdi + 24] ; item_size
|
|
mov [rsp + 0x18], rax ; save size
|
|
mov [rsp + 0x20], rcx ; save compare fn context
|
|
|
|
xor r12, r12
|
|
.loop:
|
|
mov rcx, [rsp]
|
|
mov rcx, [rcx + 8]
|
|
cmp r12, rcx
|
|
jge .not_found
|
|
; if compare(&vec.data[i], object) {
|
|
mov rdi, [rsp + 0x20] ; compare fn context
|
|
mov rsi, [rsp + 0x8]
|
|
mov rax, [rsp + 0x18] ; size
|
|
xor rdx, rdx
|
|
mul r12 ; i * item_size
|
|
mov rdx, [rsp] ; vec
|
|
mov rdx, [rdx] ; vec.data
|
|
add rdx, rax ; vec.data + i * item_size
|
|
mov rax, [rsp + 0x10] ; compare fn
|
|
call rax
|
|
test rax, rax
|
|
jne .found
|
|
; }
|
|
inc r12
|
|
jmp .loop
|
|
|
|
.not_found:
|
|
mov rax, -1
|
|
jmp .epilogue
|
|
.found:
|
|
mov rax, r12
|
|
|
|
.epilogue:
|
|
add rsp, 0x28
|
|
pop r12
|
|
pop rbp
|
|
ret
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi : index
|
|
;; rdx: pointer to data to insert
|
|
;; fn vec_insert(vec: *mut Vec, index: usize, data: *const T)
|
|
vec_insert:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push r12
|
|
push rbx
|
|
sub rsp, 0x20
|
|
mov [rsp], rdi ; save vec
|
|
mov [rsp + 8], rsi ; save index
|
|
mov [rsp + 0x10], rdx ; save data ptr
|
|
|
|
mov rsi, [rdi + 8]
|
|
inc rsi
|
|
call vec_try_grow
|
|
|
|
mov rbx, [rsp] ; vec
|
|
mov rdi, [rbx] ; vec.data
|
|
mov rcx, [rbx + 24] ; item_size
|
|
mov rdx, [rbx + 8] ; len
|
|
sub rdx, [rsp + 8] ; len - index
|
|
mov rax, rdx
|
|
mul rcx ; (len - index) * item_size
|
|
mov r12, rax ; number of bytes to move
|
|
mov rsi, [rbx] ; vec.data
|
|
mov rax, [rsp + 8] ; index
|
|
mov rcx, [rbx + 24] ; item_size
|
|
mul rcx ; index * item_size
|
|
add rsi, rax ; src ptr
|
|
mov rdi, rsi
|
|
add rdi, rcx ; dst ptr
|
|
mov rdx, r12 ; number of bytes to move
|
|
call memmove
|
|
|
|
mov rdi, rsi
|
|
mov rsi, [rsp + 0x10]
|
|
mov rdx, [rbx + 24] ; item_size
|
|
call memcpy
|
|
|
|
mov rax, [rbx + 8] ; len
|
|
inc rax
|
|
mov [rbx + 8], rax
|
|
|
|
add rsp, 32
|
|
pop rbx
|
|
pop r12
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi : index
|
|
;; rdx: pointer to data to insert
|
|
;; rcx: count
|
|
;; define-fn: fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize)
|
|
vec_insert_many:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push r12
|
|
push rbx
|
|
sub rsp, 0x20
|
|
mov [rsp], rdi ; save vec
|
|
mov [rsp + 8], rsi ; save index
|
|
mov [rsp + 0x10], rdx ; save data ptr
|
|
mov [rsp + 0x18], rcx ; save count
|
|
|
|
mov rsi, [rdi + 8]
|
|
add rsi, rcx ; len + count
|
|
call vec_try_grow
|
|
|
|
mov rbx, [rsp] ; vec
|
|
mov rdi, [rbx] ; vec.data
|
|
mov rcx, [rbx + 24] ; item_size
|
|
mov rdx, [rbx + 8] ; len
|
|
sub rdx, [rsp + 8] ; len - index
|
|
mov rax, rdx
|
|
mul rcx ; (len - index) * item_size
|
|
mov r12, rax ; number of bytes to move
|
|
mov rsi, [rbx] ; vec.data
|
|
mov rax, [rsp + 8] ; index
|
|
mov rcx, [rbx + 24] ; item_size
|
|
mul rcx ; index * item_size
|
|
add rsi, rax ; src ptr
|
|
mov rdi, rsi
|
|
|
|
mov rax, [rsp + 0x18] ; count
|
|
mul rcx ; count * item_size
|
|
add rdi, rax ; dst ptr
|
|
mov rdx, r12 ; number of bytes to move
|
|
call memmove
|
|
|
|
mov rdi, rsi
|
|
mov rsi, [rsp + 0x10]
|
|
mov rcx, [rsp + 0x18] ; count
|
|
mov rax, [rbx + 24] ; item_size
|
|
mul rcx ; count * item_size
|
|
mov rdx, rax
|
|
call memcpy
|
|
|
|
mov rax, [rbx + 8] ; len
|
|
add rax, [rsp + 0x18] ; len += count
|
|
mov [rbx + 8], rax
|
|
|
|
add rsp, 32
|
|
pop rbx
|
|
pop r12
|
|
pop rbp
|
|
ret
|
|
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: pointer to key
|
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
|
|
;; rcx: compare_fn context
|
|
;;fn vec_binary_search_by(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
|
|
vec_binary_search_by:
|
|
push rbp
|
|
mov rbp, rsp
|
|
sub rsp, 0x40
|
|
mov [rsp], rdi ; save vec
|
|
mov [rsp + 0x8], rsi ; save key
|
|
mov [rsp + 0x10], rdx ; save compare fn
|
|
mov [rsp + 0x18], rcx ; save compare fn context
|
|
|
|
mov rax, [rdi + 8] ; len
|
|
dec rax ; high
|
|
mov qword [rsp + 0x20], 0 ; low
|
|
mov qword [rsp + 0x28], 0 ; mid
|
|
mov [rsp + 0x30], rax ; high
|
|
mov rax, [rdi + 24] ; item_size
|
|
mov [rsp + 0x38], rax ; item_size
|
|
|
|
.loop:
|
|
mov rax, [rsp + 0x20] ; low
|
|
mov rcx, [rsp + 0x30] ; high
|
|
cmp rax, rcx
|
|
jg .not_found
|
|
; mid = (low + high) / 2
|
|
sub rcx, rax
|
|
shr rcx, 1
|
|
add rax, rcx
|
|
mov [rsp + 0x28], rax ; mid
|
|
|
|
mov rcx, [rsp] ; vec
|
|
mov rcx, [rcx] ; vec.data
|
|
mov rdx, [rsp + 0x38] ; item_size
|
|
mul rdx ; mid * item_size
|
|
add rax, rcx ; vec.data + mid * item_size
|
|
mov rdi, [rsp + 0x18] ; compare ctx
|
|
mov rsi, [rsp + 0x8] ; key
|
|
mov rdx, rax
|
|
mov rax, [rsp + 0x10] ; compare fn
|
|
call rax
|
|
cmp eax, 0
|
|
je .found
|
|
jl .less
|
|
; greater
|
|
mov rax, [rsp + 0x28] ; mid
|
|
inc rax
|
|
mov [rsp + 0x28], rax ; mid
|
|
mov [rsp + 0x20], rax ; low = mid + 1
|
|
jmp .loop
|
|
.less:
|
|
mov rax, [rsp + 0x28] ; mid
|
|
cmp rax, 0
|
|
je .not_found ; if mid == 0, not found
|
|
dec rax
|
|
mov [rsp + 0x30], rax ; high = mid - 1
|
|
jmp .loop
|
|
.found:
|
|
mov rax, [rsp + 0x28]
|
|
xor rdx, rdx
|
|
jmp .epilogue
|
|
.not_found:
|
|
mov rax, [rsp + 0x28]
|
|
mov rdx, 1
|
|
|
|
.epilogue:
|
|
add rsp, 0x40
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: pointer to Vec struct
|
|
;; rsi: pointer to key
|
|
;; rdx: compare function fn(ctx: *const (), a: *const T, b: *const T) -> i32
|
|
;; rcx: compare_fn context
|
|
;;fn vec_insert_sorted(vec: *mut Vec, key: *const T, compare: fn(ctx: *const (), a: *const T, b: *const T) -> i32, ctx: *const ()) -> (usize, bool)
|
|
vec_insert_sorted:
|
|
push rbp
|
|
mov rbp, rsp
|
|
sub rsp, 0x18
|
|
mov [rsp], rdi ; vec
|
|
mov [rsp + 8], rsi ; element ptr
|
|
call vec_binary_search_by
|
|
test rdx, rdx
|
|
jnz .insert
|
|
; element already exists
|
|
jmp .epilogue
|
|
.insert:
|
|
mov [rsp + 0x10], rax ; index
|
|
mov rdi, [rsp] ; vec
|
|
mov rsi, rax ; index
|
|
mov rdx, [rsp + 8] ; element ptr
|
|
call vec_insert
|
|
mov rax, [rsp + 0x10] ; index
|
|
mov rdx, 1 ; indicate inserted
|
|
|
|
.epilogue:
|
|
add rsp, 0x18
|
|
pop rbp
|
|
ret
|
|
|
|
;; rdi: *Vec
|
|
;; rsi: *const u8
|
|
;; rdx: number of elements
|
|
;; define-fn: fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> ()
|
|
vec_extend:
|
|
push rbp
|
|
mov rbp, rsp
|
|
|
|
; bytes [24..32]
|
|
; count [16..24]
|
|
; elements [8..16]
|
|
; vec [0..8]
|
|
sub rsp, 32
|
|
|
|
mov [rsp], rdi ; vec
|
|
mov [rsp + 8], rsi ; elements
|
|
mov [rsp + 16], rdx ; count
|
|
|
|
mov rax, [rdi + 24] ; item_size
|
|
mul rdx ; count * item_size
|
|
|
|
mov [rsp + 24], rax ; bytes
|
|
|
|
mov rsi, [rsp + 16] ; count
|
|
add rsi, [rdi + 8] ; vec.len + count
|
|
call vec_try_grow
|
|
|
|
mov rdi, [rsp] ; vec
|
|
mov rsi, [rdi + 8] ; vec.len
|
|
mov rax, [rdi + 24] ; item_size
|
|
mul rsi ; vec.len * item_size
|
|
add rax, [rdi] ; vec.data + vec.len * item_size
|
|
mov rdi, rax ; dest
|
|
mov rsi, [rsp + 8] ; elements
|
|
mov rdx, [rsp + 24] ; bytes
|
|
call memcpy
|
|
|
|
mov rdi, [rsp] ; vec
|
|
mov rax, [rdi + 8] ; vec.len
|
|
add rax, [rsp + 16] ; vec.len + count
|
|
mov [rdi + 8], rax
|
|
|
|
add rsp, 32
|
|
pop rbp
|
|
ret
|