Category : Files from Magazines
Archive   : VOL8N13.ZIP
Filename : HEAP.ASM
page 55,132
; HEAP.ASM --- Simple Heap Manager for MASM Programs
; Copyright (C) 1989 Ziff Davis Communications
; PC Magazine * Ray Duncan
;
; To trade safety for speed, change the CHKPTRS equate.
;
; The routines in this module all assume that the
; CPU direction flag is clear!!
true equ -1
false equ 0
chkptrs equ true ; if true, HREALLOC and
; HFREE check all pointers
DGROUP group _DATA
_DATA segment word public 'DATA'
hbase dw 0 ; base address of heap
hsize dw 0 ; size of heap
_DATA ends
_TEXT segment word public 'CODE'
assume cs:_TEXT,ds:DGROUP
;
; HINIT: initialize local heap
;
; Call with: AX = size in bytes
; DS:BX = address of heap base
;
; Returns: If function successful,
; Carry = clear
;
; If function failed
; Carry = set
;
public hinit
hinit proc near
cmp ax,2 ; check heap size
jbe hinit1 ; too small, return error
cmp ax,32768
jae hinit1 ; too big, return error
push ax ; save registers
push bx
mov hsize,ax ; save heap size
mov hbase,bx ; save heap base address
sub ax,2 ; create header for block
mov [bx],ax ; containing all free space
inc ax
add bx,ax ; set Carry if segment wrap
pop bx ; restore registers
pop ax
ret ; return to caller
hinit1: stc ; bad parameter,
ret ; return Carry = set
hinit endp
;
; HALLOC: allocate block from local heap
;
; Call with: AX = requested block size
;
; Returns: If function successful
; Carry = clear
; DS:BX = address of allocated block
;
; If function unsuccessful
; Carry = set
;
public halloc
halloc proc near
call hfind ; try and allocate block
jnc hal1 ; jump if block was found
call hcoal ; coalesce free blocks
call hfind ; try again to allocate
hal1: ret ; return to caller
halloc endp
;
; HREALLOC: resize previously allocated block
;
; Call with: AX = new requested block size
; DS:BX = address of existing block
;
; Returns: If function successful
; Carry = clear
; DS:BX = address of resized block
;
; If function unsuccessful
; Carry = set
;
public hrealloc
hrealloc proc near
push ax ; save registers
push cx
push si
push di
push es
if chkptrs
call hvalid ; check if valid pointer
jnc hreal1 ; pointer is OK
jmp hreal6 ; bad pointer, exit
endif
hreal1: mov cx,ax ; save new requested size
mov si,bx ; save block base address
mov di,hbase ; get address of heap end
add di,hsize
mov ax,[si-2] ; get current block size
and ax,7fffh ; remove in-use bit
cmp cx,ax ; is block growing?
ja hreal2 ; yes, jump
je hreal5 ; no size change, exit
sub ax,cx ; block shrinking, find excess
cmp ax,2 ; enough for another header?
jb hreal5 ; no, leave block alone
mov [si-2],cx ; shrink existing block
or word ptr [si-2],8000h ; and set in-use bit
add si,cx ; create new block to hold
sub ax,2 ; the excess memory
mov [si],ax
jmp hreal5 ; now exit
hreal2: call hcoal ; coalesce free blocks
add si,ax ; get addr. of next block
cmp si,di ; reached end of heap?
je hreal4 ; yes, jump
test word ptr [si],8000h ; next block free?
jnz hreal4 ; no, must try elsewhere
add ax,[si] ; yes, are combined blocks
add ax,2 ; large enough?
cmp cx,ax
ja hreal4 ; no, jump
mov [bx-2],cx ; update block header and
or word ptr [bx-2],8000h ; set in-use flag
sub ax,cx ; find excess memory
cmp ax,2 ; large enough for header?
jb hreal3 ; no, jump
mov si,bx ; create header for block
add si,cx ; containing excess memory
sub ax,2
mov [si],ax
jmp hreal5 ; now exit
hreal3: add ax,cx ; excess is 0 or 1 bytes,
mov [bx-2],ax ; fold it into the block
or word ptr [bx-2],8000h
jmp hreal5 ; now exit
hreal4: mov ax,cx ; look elsewhere for
mov si,bx ; sufficiently large block
call hfind
jc hreal6 ; none available, exit
and word ptr [si-2],7fffh ; mark old block available
mov cx,[si-2] ; get its length for move
mov di,bx ; copy old block to new
push ds
pop es
rep movsb
hreal5: clc ; successful reallocation,
; return Carry = clear
hreal6: pop es ; restore registers
pop di
pop si
pop cx
pop ax
ret ; return to caller
hrealloc endp
;
; HFREE: release heap block
;
; Call with: DS:BX = block pointer
;
; Returns: If CHKPTRS is FALSE
; Nothing
;
; If CHKPTRS is TRUE and pointer valid
; Carry = clear
;
; If CHKPTRS is TRUE and pointer invalid
; Carry = set
;
public hfree
hfree proc near
if chkptrs
call hvalid ; check if valid pointer
jc hfree1 ; jump if bad pointer
endif
and word ptr [bx-2],07fffh ; turn off in-use flag
hfree1: ret ; back to caller
hfree endp
;
; HFIND: private subroutine for HALLOC and HREALLOC,
; finds a free block in heap
;
; Call with: AX = requested block size
;
; Returns: If function successful
; Carry = clear
; DS:BX = address of allocated block
;
; If function unsuccessful
; Carry = set
;
hfind proc near
push ax ; save registers
push cx
push si
push di
mov cx,ax ; save requested block size
mov si,hbase ; get heap base address
mov di,si
add di,hsize ; get address of heap end
hfind1: lodsw ; pick up next block header
or ax,ax ; this block free?
js hfind2 ; not free if bit 15 set, jump
cmp ax,cx ; block free, large enough?
jae hfind4 ; size is adequate, jump
hfind2: and ax,07fffh ; go to next block
add si,ax
cmp si,di ; end of heap reached?
jne hfind1 ; not yet, try next block
hfind3: stc ; couldn't allocate block,
jmp hfind7 ; return Carry = set
hfind4: mov bx,si ; save block base in BX
je hfind6 ; jump if exactly right size
sub ax,cx ; find excess amount
cmp ax,2 ; enough for another header?
jae hfind5 ; yes, jump
add ax,cx ; no, skip this block
jmp hfind2
hfind5: add si,cx ; subdivide existing block
sub ax,2 ; create header for free block
mov [si],ax ; containing excess memory
hfind6: or cx,8000h ; set block size and in-use
mov [bx-2],cx ; flag, also clear Carry
hfind7: pop di ; restore registers
pop si
pop cx
pop ax
ret ; return to caller
hfind endp
;
; HCOAL: private subroutine for HALLOC and HREALLOC,
; coalesces adjacent free blocks in heap
;
; Call with: nothing
;
; Returns: nothing
;
hcoal proc near
push ax ; save registers
push bx
push si
push di
mov bx,hbase ; get heap base address
mov di,bx
add di,hsize ; get heap end address
hcoal1: mov si,bx ; point to block header
hcoal2: lodsw ; get length from header
mov bx,ax ; calc. address of next block
and bx,7fffh
add bx,si
cmp bx,di ; end of heap reached?
je hcoal3 ; yes, exit
or ax,ax ; not last block, is it free?
js hcoal1 ; not free if bit 15 set, jump
test word ptr [bx],8000h ; next block free also?
jnz hcoal1 ; no, jump
add ax,[bx] ; merge two blocks together
add ax,2
sub si,2
mov [si],ax ; update header of 1st block
jmp hcoal2 ; try for another merge
hcoal3: pop di ; restore registers
pop si
pop bx
pop ax
ret ; return to caller
hcoal endp
if chkptrs
;
; HVALID: tests whether a heap pointer is valid
;
; Call with: DS:BX = questionable pointer to block
;
; Returns: If pointer is valid
; Carry = clear
;
; If pointer is invalid
; Carry = set
;
public hvalid
hvalid proc near
push ax ; save registers
push si
push di
test word ptr [bx-2],8000h ; make sure already allocated
je hval2 ; no, pointer invalid
mov si,hbase ; get heap base address
mov di,si
add di,hsize ; get heap end address
hval1: lodsw ; get length of this block
cmp si,bx ; do pointers match?
je hval3 ; yes, jump (carry is clear)
and ax,7fffh ; strip in-use bit and
add si,ax ; advance to next block
cmp si,di ; end of heap?
jne hval1 ; no, try again
hval2: stc ; end of heap, pointer invalid
hval3: pop di ; restore registers
pop si
pop ax
ret ; return to caller
hvalid endp
endif
_TEXT ends
end
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/