⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gcompact.asm

📁 dos 1.0 其中包含quick basic源代码、内存管理himem emm386 发展历史
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;*
;*	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 + -