📄 gcompact.asm
字号:
; destination = b
;
; Free and busy block NOT adjacent
; 0000:0 | | | |
; |-----------| |-----------|
; | busy | | free |
; |-----------| |-----------|
; | | | |
; |-----------| a -> |-----------|
; | free | | free ? |
; | | b -> |-----------|
; | | | ? busy ? |
; |-----------| c -> |-----------|
; FFFF:0 | | | ? |
;
;
; a = free
; b = free.ga_next - busy.ga_size - 1
; c = free.ga_next
; destination = b
;
gslideup:
mov ax,es:[di].ga_next
push ax ; Save c
sub ax,dx
push ax ; Save b
cmp es:[bx],si ; Are blocks adjacent?
je gslideup1
push es ; No, a = free
jmp short gslideup2
gslideup1:
push si ; Yes, a = busy
gslideup2:
mov es,ax ; Destination is b
xor ax,ax ; a.ga_prev will remain valid
jmp short gslidemove
; Here to slide moveable block down to low end of free block.
;
; Free and busy block adjacent
; 0000:0 | | | |
; |-----------| a -> |-----------|
; | free | | ? busy ? |
; | | b -> |-----------|
; |-----------| | ? free ? |
; | busy | | |
; |-----------| c -> |-----------|
; FFFF:0 | | | ? |
;
; a = free
; b = free + busy.ga_size + 1
; c = busy.ga_next
; destination = free
;
; Free and busy block NOT adjacent
; 0000:0 | | | |
; |-----------| a -> |-----------|
; | free | | ? busy ? |
; | | b -> |-----------|
; | | | ? free ? |
; |-----------| c -> |-----------|
; | | | ? |
; |-----------| |-----------|
; | busy | | free |
; |-----------| |-----------|
; FFFF:0 | | | |
;
;
; a = free
; b = free + busy.ga_size + 1
; c = free.ga_next
; destination = free
;
gslidedown:
cmp es:[bx],si ; Are blocks adjacent?
je gslidedn1
push es:[di].ga_next ; No, c = free.ga_next
jmp short gslidedn2
gslidedn1:
add ax,dx ; Yes, c = busy.ga_next
push ax
gslidedn2:
mov ax,es
add ax,dx
push ax ; Save b
push es ; Save a
mov ax,es:[di].ga_prev ; a.ga_prev must be restored after move
gslidemove:
call gmove
mov si,es ; Save new busy block location
pop es ; ES = a
or ax,ax ; Does a.prev need to be restored?
jz gslide1 ; No, continue
mov es:[di].ga_prev,ax ; Yes, do it
gslide1:
pop ax
mov es:[di].ga_next,ax ; a.ga_next = b
mov dx,es
mov es,ax
mov es:[di].ga_prev,dx ; b.ga_prev = a
pop ax
mov es:[di].ga_next,ax ; b.ga_next = c
mov dx,es
mov es,ax
mov es:[di].ga_prev,dx ; c.ga_prev = b
mov es,si ; ES = new busy block
mov si,es:[di].ga_handle ; SI = handle
or si,si
jz gslide2
mov ax,es
inc ax
mov ds:[si].he_address,ax ; Update client address
gslide2:
mov es,es:[bx] ; Move to new free block
mov ax,es:[di].ga_next ; Set size and signature
mov si,es ; byte fields of new free block
sub ax,si
dec ax
mov es:[di].ga_size,ax
mov es:[di].ga_sig,GA_SIGNATURE
mov es:[di].ga_flags,0
mov es:[di].ga_handle,di
call gmarkfree ; Coelesce new free block
or ax,ax
ret
; Subroutine to search for the largest moveable block that
; will fit in the passed free block.
;
; Inputs: ES:DI = free block
; DS:DI = address of global heap information
; CX = #arena entries left to examine
; BX = ga_next or ga_prev
;
; Outputs: Z flag set if block found and moved into passed free
; block with no extra room.
; ES:DI = busy block before/after new busy block.
;
; Z flag clear if ES:DI points to a free block, either the
; original one or what is left over after moving a block
; into it.
;
; Destroys: DX,SI
;
gbestfit:
push es
push cx
xor si,si ; Have not found anything yet
mov dx,ES:[di].ga_size ; Compute max size to look for
gbfloop:
cmp ES:[di].ga_owner,di ; Is this block busy?
je gbfnext ; No, continue
push si
call gmoveable ; Yes, is it moveable
pop si
jz gbfnext ; No, continue
cmp ES:[di].ga_size,dx ; Yes, is block bigger than max size?
ja gbfnext ; Yes, continue
or si,si ; First block we have found?
jz gbf1st ; Yes, special case
push es
mov es,si
mov ax,ES:[di].ga_size ; No, get size of largest block so far
pop es ; Compare with this block
cmp ES:[di].ga_size,ax ; Is it bigger than the largest so far?
jbe gbfnext ; No, continue
gbf1st:
mov si,es ; Yes, remember biggest block
mov ax,ES:[di].ga_size ; ...and size
gbfnext:
mov es,ES:[bx] ; Skip past this block
loop gbfloop
pop cx ; All done looking
pop es
or si,si ; Did we find a block?
jz gbestfit1 ; No, return with Z flag
call gmovebusy ; Yes, move it into free block
gbestfit1:
ret
; Subroutine to move a busy block to a free block of the same size,
; preserving the appropriate arena header fields, freeing the old
; busy block and updating the handle table entry to point to the
; new location of the block
;
; Inputs: SI = old busy block location
; ES:DI = new busy block location
; DS:DI = address of global heap information
;
; Outputs: ES:DI = points to new busy block arena header
;
; Destroys: AX,SI
;
gmovebusy:
push cx
push dx
mov ax,es
mov cx,es:[di].ga_size ; CX = size of destination
cmp es:[di].ga_owner,di ; Is destination busy?
mov es,si
mov dx,es:[di].ga_size ; DX = size of source
jne gmbexactfit ; Yes, then dont create extra block
cmp cx,dx ; No, are source and destination same size?
je gmbexactfit ; Yes, then dont create extra block
mov es,ax ; ES = destination
mov ax,si ; AX = source
push si ; Save busy block address
call gslidecommon ; Call common code to do the move
inc [di].hi_count ; Just created a new arena entry
mov ax,es ; Save new free block address
pop es ; Get old busy block address
call gmarkfree ; Mark as free and coalesce
mov es,ax ; Restore new free block address
or ax,ax ; Return with Z flag clear.
jmp gmbexit
gmbexactfit:
inc si ; SI = old client data address
mov cl,ES:[di].ga_flags
push ES:[di].ga_owner
mov es,ax
pop ES:[di].ga_owner ; Copy client words to new header
mov ES:[di].ga_flags,cl
inc ax
mov es,ax ; ES = new client data address
call gmove ; Move the client data
dec si
mov es,si ; ES:DI = old arena header
call gmarkfree ; Free old block
dec ax
mov es,ax ; ES:DI = new arena header
inc ax
or si,si
jz gmb1
mov [si].he_address,ax ; Set new client data address
mov ES:[di].ga_handle,si ; Set back link to handle in new block
xor si,si ; Set Z flag
gmb1:
gmbexit:
pop dx
pop cx
ret
; Subroutine to walk segment list, discarding objects until the #paras
; discarded, plus the biggest free block is greater than the #paras
; we are looking for.
;
; Inputs: ES:DI = largest free block
; AX = size of largest free block
; DX = minimum #paras needed
; DS:DI = address of global heap information
;
; Outputs: Z flag clear if one or more objects discarded.
;
; Z flag set if no objects discarded.
;
; Destroys: BX,CX,SI
;
gdiscard:
push es
push ax
push dx
mov [di].hi_ncompact,0 ; Clear compaction flag
sub dx,ax ; How much to discard before
mov [di].hi_distotal,dx ; compacting again.
mov es,ds:[di].hi_last
mov cx,es ; Assume no discard fence
cmp ds:[di].gi_reserve,di ; True if no reserve area
je gdstart
test byte ptr ds:[di].gi_cmpflags,GA_DISCCODE ; or code request
jnz gdstart
gdloop0:
mov es,es:[di].ga_prev
cmp es:[di].ga_owner,di
je gdfence
test es:[di].ga_flags,GA_DISCCODE
jnz gdloop0
gdfence:
sub cx,ds:[di].gi_reserve ; Compute beginning of reserve area
cmp cx,es:[di].ga_next ; Does all disc. code lie within it?
jbe gdstart ; Yes, set discard fence
mov cx,ds:[di].hi_last ; No, then no discard fence
gdstart:
mov ds:[di].gi_disfence,cx ; Set the discard fence
gdloop:
call ggetlru ;* get least recently used code handle
jz gdexit ; No, more see if we discarded anything
;* ignore items below swap fence
IFDEF DEBUG
cmp [si].he_count,0 ; Is this handle locked?
je gd_not_locked
cCall CowAssertFailed ;* we do not support code locking
gd_not_locked:
ENDIF ;DEBUG
mov bx,[si].he_address
dec bx
mov es,bx ;* es:0 => arena
mov bx,si ; BX = handle
mov al,GN_DISCARD ; AX = GN_DISCARD
mov dx,es:[di].ga_owner ;* set up owner for gnotify
push dx ;* save owner
push [si].he_address ;* save original address
call gnotify
pop ax ;* original address
dec ax
mov es,ax ; ES:DI = address of block to free
mov dx,es:[di].ga_size ; Save size !!!
call gmarkfree ; Free the block associated with this handle
;* DX not trashed !!
pop [si].he_address ; Remember owner in handle table entry
or [si].he_flags,HE_DISCARDED ; ...and mark discarded
mov [di].hi_ncompact,1 ; Remember we discarded something
sub [di].hi_distotal,dx ; Have we discarded enough yet?
ja gdloop ; No, look at next handle
gdexit:
cmp [di].hi_ncompact,0 ; Return with Z flag set or clear
pop dx
pop ax
pop es
ret
;********** ggetlru **********
;* entry : DI = 0
;* * scan LRU table, return handle to code segment to discard
;* * Note : this is a simple scan to find the maximum segref
;* * (later on make more efficient depending on code requirements needed).
;* * NOTE : ignores items that are above swap fence
;* (swap fence (gi_disfence) should not be set for GA_DISCCODE
;* allocations).
;* exit : Z => no more left
;* else SI = handle
ggetlru:
push bp
mov bp,ds:[di].gi_disfence ;* swap fence limit
mov es,psLom
mov cx,es:[neLom.ne_cseg]
dec cx ;* count of code segments
mov si,es:[neLom.ne_psegrefbytes]
mov di,es:[neLom.ne_segtab] ;* point to segtab
;* * note : DI != 0
xor dx,dx ;* null return (handle)
xor ah,ah ;* see if you can beat or match 0
gget_loop:
lods byte ptr es:[si] ;* al = segref
cmp al,ah
jl gget_next ;* too small
;* * test to see if below swap fence
mov bx,es:[di].ns_handle ;* get handle
cmp [bx].he_address,bp ;* above swap fence ?
jae gget_next ;* above => don't discard.
;* * the new maximum (so far)
mov dx,bx ;* new handle
mov ah,al ;* new maximum segref
gget_next:
add di,SIZE NEW_SEG1
loop gget_loop
;* * dx = handle of discardable segment with largest seg-ref (lru)
mov si,dx
xor di,di ;* restore DI
or si,si ;* z=> none found
pop bp
ret
SUBRS ENDP
;*****************************************************************************
sEnd KERNEL
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -