1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-09 18:06:35 +03:00
mal/impls/nasm/exceptions.asm

139 lines
3.7 KiB
NASM
Raw Normal View History

;; ----------------------------------------------
;;
;; Error handling
;;
;; A handler consists of:
;; - A stack pointer address to reset to
;; - An address to jump to
;; - An optional data structure to pass
;;
;; When jumped to, an error handler will be given:
;; - the object thrown in RSI
;; - the optional data structure in RDI
;;
section .bss
;; Error handler list
error_handler: resq 1
section .text
;; Add an error handler to the front of the list
;;
;; Input: RSI - Stack pointer
;; RDI - Address to jump to
;; RCX - Data structure. Set to zero for none.
;; If not zero, reference count incremented
;;
;; Modifies registers:
;; RAX
;; RBX
error_handler_push:
call alloc_cons
; car will point to a list (stack, addr, data)
; cdr will point to the previous handler
mov [rax], BYTE (block_cons + container_list + content_pointer)
mov rbx, [error_handler]
cmp rbx, 0 ; Check if previous handler was zero
je .create_handler ; Zero, so leave null
; Not zero, so create pointer to it
mov [rax + Cons.typecdr], BYTE content_pointer
mov [rax + Cons.cdr], rbx
; note: not incrementing reference count, since
; we're replacing one reference with another
.create_handler:
mov [error_handler], rax ; new error handler
mov rdx, rax
call alloc_cons
mov [rdx + Cons.car], rax
; Store stack pointer
mov [rax], BYTE (block_cons + container_list + content_function)
mov [rax + Cons.car], rsi ; stack pointer
mov rdx, rax
call alloc_cons
mov [rdx + Cons.typecdr], BYTE content_pointer
mov [rdx + Cons.cdr], rax
; Store function pointer to jump to
; Note: This can't use content_pointer or release
; will try to release this memory address
mov [rax], BYTE (block_cons + container_list + content_function)
mov [rax + Cons.car], rdi
; Check if there is an object to pass to handler
cmp rcx, 0
je .done
; Set the final CDR to point to the object
mov [rax + Cons.typecdr], BYTE content_pointer
mov [rax + Cons.cdr], rcx
mov rsi, rcx
call incref_object
.done:
ret
;; Removes an error handler from the list
;;
;; Modifies registers:
;; RSI
;; RAX
;; RCX
error_handler_pop:
; get the address
mov rsi, [error_handler]
cmp rsi, 0
je .done ; Nothing to remove
push rsi
mov rsi, [rsi + Cons.cdr] ; next handler
mov [error_handler], rsi
;call incref_object ; needed because releasing soon
pop rsi ; handler being removed
mov [rsi + Cons.typecdr], BYTE 0
call release_cons
.done:
ret
;; Throw an error
;; Object to pass to handler should be in RSI
error_throw:
; Get the next error handler
mov rax, [error_handler]
cmp rax, 0
je .no_handler
; Got a handler
mov rax, [rax + Cons.car] ; handler
mov rbx, [rax + Cons.car] ; stack pointer
mov rax, [rax + Cons.cdr]
mov rcx, [rax + Cons.car] ; function
mov rdi, [rax + Cons.cdr] ; data structure
; Reset stack
mov rsp, rbx
; Jump to the handler
jmp rcx
.no_handler:
; Print the object in RSI then quit
cmp rsi, 0
je .done ; nothing to print
mov rdi, 1 ; print_readably
call pr_str
mov rsi, rax
call print_string
.done:
jmp quit_error