📄 gcompact.asm
字号:
;*
;* COW : Character Oriented Windows
;*
;* gcompact.asm : global compaction
;* * NOTE :assumes stack never moves !
TITLE GCOMPACT - Global memory compactor
.xlist
include kernel.inc
include galloc.inc
.list
;*****************************************************************************
sBegin DATA
externW <psLom>
;*************************** compact kludge ***********************
globalB fCompactLowerHeap,0
sEnd DATA
;*****************************************************************************
sBegin KERNEL
assumes CS,KERNEL
assumes DS,NOTHING ;* DS == pGlobalHeap
assumes SS,DATA
; These are all the external subroutines needed by this source file.
;
externNP <genter> ; GINTERF.ASM
externNP <gjoin,gmarkfree,gcheckfree>; GALLOC.ASM
externNP <gnotify> ; GINTERF.ASM
; These are all of the internal subroutines defined in this source file.
;
PUBLIC gcompact ;* compact global heap
PUBLIC gmovebusy
IFDEF DEBPUB
PUBLIC gmove, gmoveable, gslidecommon
PUBLIC gcmpheap, gslide, gbestfit, gdiscard
ENDIF
SUBRS PROC NEAR
; Subroutine to move a moveable block into the top part of a free block
; The low order bit of the source and destination may be either set or
; reset. If set, then this routine does NOT move the arena header paragraph.
; If the bit is reset, then the arena header is moved. Only the low order
; bit of SI is examined, and the low order bit of ES is assumed to the same.
;
; Inputs: ES:0 = address of destination block
; SI:0 = address of source block
;
gmove:
push es
push si
push di
push ax
push bx
push cx
push dx
mov dx,si ; DX = 0 if moving arena header too
and dx,1 ; and 1 if not.
push es ; Save destination
mov cx,es ; CX = client data address of dest.
or cl,1
mov ax,si ; ES:DI = arena header of source
xor ax,dx ;
mov es,ax
xor dl,1 ; DX = #paragraphs to move
add dx,ES:[di].ga_size
push dx ; Save #paragraphs
mov ax,GN_MOVE
mov bx,ES:[di].ga_handle ; BX = handle of source
or bx,bx
jnz gm1
mov bx,es
inc bx
gm1:
push es
mov dx,es:[di].ga_owner ;* set up owner for gnotify
call gnotify ; Call global notify procedure
pop cx
inc cx
pop dx ; DX = #paragraphs to move
pop di ; DI = destination
; Save DS value AFTER call to gnotify, as it might be the one
; we are moving and thus changed by the global heap notify proc.
push ds
mov ax,dx ; AX:0 = end of source
add ax,si
mov bx,dx ; BX:0 = end of destination
add bx,di
cmp si,di ; Moving up towards high memory?
jb move0a ; Yes, all set
mov ax,si ; No, start at beginning of source
mov bx,di ; ... and destination
move0a:
; AX:0 = end of source
; BX:0 = end of destination
; DX = #paragraphs left to move
;
move1:
mov cx,1000h ; Can only move 64k at a time
cmp dx,cx ; More than that left?
jae move2 ; Yes, just move 64k bytes
mov cx,dx ; No, move what is left then
jcxz move3 ; All done if nothing left to move
move2:
sub dx,cx ; DX = #paragraphs left after this xfer
mov si,cx
shl cx,1 ; CX = #words to move
shl cx,1
shl cx,1
cmp ax,bx ; Moving up towards high memory?
jb move2a ; Yes, handle separately
cld
mov ds,ax ; DS:SI = first word in source block
mov es,bx ; ES:DI = first word in dest. block
add ax,si ; AX:0 = end of source block this xfer
add bx,si ; BX:0 = end of dest. block this xfer
xor si,si
jmp short move2b
move2a:
std
sub ax,si ; AX:0 = beginning of source block this xfer
sub bx,si ; BX:0 = beginning of dest. block this xfer
mov si,cx
dec si
shl si,1
mov ds,ax ; DS:SI = last word in source block
mov es,bx ; ES:DI = last word in dest. block
move2b:
mov di,si
rep movsw ; move this section
jmp move1 ; Back for more
move3:
pop ds ; Restore DS (it might be different)
pop dx ; Restore registers
pop cx
pop bx
pop ax
pop di
pop si
pop es
cld ; Protect people like MarkCl from themselves
ret
; Subroutine to compact the global heap
;
; Inputs: DX = minimum #contiguous bytes needed
; DS:DI = address of global heap information
;
; Outputs: AX = size of largest contiguous free block
; ES:DI = arena header of largest contiguous free block
; DX = minimum #contiguous bytes needed
;
; Destroys: CX
;
gcompact:
push si
gcompactl:
push dx ; Save requested size
cmp fCompactLowerHeap,0 ; See if only compacting lower heap
jz gcompactn ; no normal compact
mov es,[di].hi_first ; Yes, compact lower heap
mov bx,ga_next
jmp short gcompact1a ; Now see any special flags
gcompactn:
cmp [di].gi_reserve,di ; Is there a reserve swap area?
je gcompact1 ; No, then dont compact lower heap
mov es,[di].hi_first ; Yes, compact lower heap
mov bx,ga_next
push dx
call gcmpheap
pop dx
gcompact1:
mov es,[di].hi_last ; Compact upper heap
mov bx,ga_prev
gcompact1a:
call gcmpheap
pop dx ; Get requested size
mov es,ax ; ES points to largest free block
or ax,ax ; Did we find a free block?
jz gcompact2 ; No, try discarding
call gcheckfree ; Yes, see if block big enough
jae gcompactx ; Yes, all done
gcompact2: ; Discarding allowed?
test byte ptr [di].gi_cmpflags,GA_NODISCARD+GA_NOCOMPACT
jnz gcompactx ; No, return
call gdiscard ; No, try discarding
jnz gcompactl ; Compact again if something discarded
gcompactx:
pop si ; Restore SI
ret
gcmpheap:
mov cx,[di].hi_count
xor ax,ax ; Nothing found yet
push ax ; Save largest free block so far
gchloop:
cmp es:[di].ga_owner,di
je gchfreefnd
gchnext:
mov es,es:[bx]
loop gchloop
pop ax ; Return largest free block in AX
ret
gchfreefnd: ; Compaction allowed?
test byte ptr [di].gi_cmpflags,GA_NOCOMPACT
jnz gchmaxfree ; No, just compute max free.
;* * if compacting upper heap, the free block must be just before another
;* * code block (or the end of the heap)
push es
cmp bl,ga_prev ;* upper heap ??
jne no_hack ;* lower heap normal
test byte ptr ds:[di].gi_cmpflags,GA_DISCCODE
jz no_hack ;* hack is only for discardable code
cmp dx,es:[di].ga_size
ja no_hack ;* to small to fit anyway
mov es,es:[di].ga_next ;* next block (CODE or END)
test es:[di].ga_flags,GA_DISCCODE
jnz hack ;* it is code, we can use it
mov ax,es
cmp ax,ds:[di].hi_last
je hack
;* * we are looking for code in the upper heap but the only free block
;* * that is available is not connected to the upper heap, hence we
;* * can't use it.
pop es
pop ax
xor ax,ax ;* fail, try to discard to get
;* legitimate space out of the code
;* swap area.
ret
hack:
pop es
pop ax
mov ax,es ;* use this block only
ret
no_hack:
pop es ;* restore es from hack check
call gslide
jnz gchfreefnd
call gbestfit
jnz gchfreefnd
gchmaxfree:
cmp bl,ga_prev ; Compacting upper heap?
jne gchnext ; No, then dont compute largest free block
pop si ; Recover largest free block so far
mov ax,es ; AX = current free block
cmp si,ax ; Same as current?
je gchmf2 ; Yes, no change then
cmp ES:[di].ga_owner,di ; No, is current free?
jne gchmf2 ; No, ignore it then
or si,si ; Yes, First time?
jz gchmf1 ; Yes, special case
cmp ds:[di].gi_reserve,di ; Is there a code reserve area?
je gchmf0 ; No, continue
test byte ptr ds:[di].gi_cmpflags,GA_DISCCODE ; Yes, use only first free
jnz gchmf2 ; block if allocating discardable code
gchmf0:
push es
mov es,si
mov ax,ES:[di].ga_size ; No, get size of largest free block
pop es ; Compare with size of this free block
cmp ES:[di].ga_size,ax ; Is it bigger?
jb gchmf2 ; No, do nothing
gchmf1: mov si,es ; Yes, remember biggest free block
gchmf2: push si ; Save largest free block so far
jmp gchnext ; Go process next block
; Subroutine to test if an object is moveable
;
; Inputs: ES:DI = arena header of object
; DS:DI = address of global heap information
; BX = ga_next or ga_prev
;
; Outputs: Z flag clear if object moveable
; Z flag set if object not moveable
;
; Destroys: SI
;
gmoveable:
mov si,es:[di].ga_handle
or si,si ; If no handle then fixed
jz gmfixed
cmp [si].he_count,bh ; If locked then fixed
jne gmfixed
;**** compact kludge ****
cmp fCompactLowerHeap,bh ; see if in special mode
jnz gmokay ; Yes allow anything to move
test es:[di].ga_flags,GA_DISCCODE ; If discardable code
jz gmnotcode
cmp bl,ga_next ; Discardable code can only
ret ; move up in memory
gmnotcode:
cmp [di].gi_reserve,di ; If no reserved code area?
je gmokay ; Then anything can move up
cmp bl,ga_prev ; Otherwise can only move down
ret ; in memory
gmfixed:
xor si,si ; Return zero if fixed
gmokay:
or si,si ; Return with Z flag set if
ret ; not moveable
; Subroutine to see if next/previous block can slide into 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 clear if block found and moved into passed free
; block and ES:DI point to new free block
;
; Z flag set if no block found and ES:DI points to
; original free block
;
; Destroys: AX,DX,SI
;
gslide:
push es
mov es,es:[bx]
mov ax,es
mov dx,es:[di].ga_size
call gmoveable
pop es
jnz gslidecommon
ret
gslidecommon: ; Enter here from gbestfit
; moving non-contiguous blocks
mov si,ax ; Source is busy block
inc dx ; DX = busy.ga_size + 1
cmp bl,ga_next
je gslidedown
; Here to slide moveable block up to high end of free block.
;
; Free and busy block adjacent
; 0000:0 | | | |
; |-----------| a -> |-----------|
; | busy | | free ? |
; |-----------| | |
; | free | b -> |-----------|
; | | | ? busy ? |
; |-----------| c -> |-----------|
; FFFF:0 | | | ? |
;
;
; a = busy
; b = free.ga_next - busy.ga_size - 1
; c = free.ga_next
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -