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

📄 mem.asm

📁 还是一个词法分析程序
💻 ASM
📖 第 1 页 / 共 3 页
字号:
page 75,132
%title "Object Oriented Memory Management System - TASM 3.0"
; Copyright (c) 1991 by Borland International

ifndef MDL
    display "Error: This module requires that you provide a memory model"
    display "    definition on the command line. I.E. /dMDL=SMALL."
    display "Also, /M must be given on the command line to enable multiple"
    display "    passes."
MDL equ <SMALL>
endif

ModuleVersion EQU "0.33"

COMMENT ~

This memory management system shows how to use TASM 3.0 objected oriented
extensions to create a heap management system. Some features of this heap
management system are:
    - Extensive use of objects for the heap manager and also individual
      blocks of memory
    - Extensibility to allow changing the structure of heap blocks without
      drastic changes to the heap manager
    - Ability to mix many different types of blocks in the same heap,
      for example, disk heap objects interspersed with regular memory
      blocks.
    - Extensive optimizations

The memory management system is implemented by several object classes.
All memory accesses are based on requesting a block of memory whose size
is given in paragraphs. Users of the memory system only need to store
segment offsets of the memory blocks that are returned. All memory blocks
can return the offset, where the user may begin storing information,
whenever needed at a later time.

memory_system   is the master heap object. It is responsible for allocating
                a block of memory to be managed as a heap. This block of
                memory may be smaller than the maximum amount of available
                memory, enabling the user of this system to setup multiple
                heaps if desired.

memory_block    is the object that has the methods for the operations of
                individual blocks in the heap. It may be used for blocks
                that are used, or unused. Although extensive checks
                of IsFree are made in routines that are not allowed on used
                blocks of memory, (for example splitting a block apart to
                create a smaller block to satisfy an allocation request),
                there are more specialized blocks objects available to
                handle used blocks and the endblock at the end of the heap.
                Consequently, the _DO_ISFREE_ equate may be disabled, and
                routines within memory_block will rely on the method
                overrides in the memory_usedblock class to filter out calls
                that should not happen to memory_blocks. This alone results
                in a 20% speed increase of the memory manager in the
                set of testing benchmarks!

memory_usedblock is an object that handles the operations for blocks on the
                heap that are in use. It is a descendant of the memory_block
                object. It is not strictly necessary that blocks on the heap
                be retyped as memory_usedblock, (by changing the VMT), but
                it should allow faster operations since the usedblock
                automatically traps out routines that it shouldn't be allowed
                to do, thus eliminating the need to check IsFree.

memory_endblock is a specialized object that is placed at the end of the
                heap. It is a descendant of the memory_usedblock object.
                It should have no size, and is strictly a placemarker so
                that all other blocks will have a next pointer other than
                zero, so they will all be able to use segment arithmetic
                to calculate their sizes.


     Object Hierarchy:

        MEMORY_SYSTEM



        MEMORY_BLOCK
            :
            :
      MEMORY_USEDBLOCK
            :
            :
       MEMORY_ENDBLOCK




For compatibility with future memory_block object descendants, a LockBlock
call should be given for all memory blocks prior to usage, and an UnLockBlock
call should be given whenever the object is free to move about. When a
LockBlock call is given, DS:SI will be set on return to point to an actual
memory address that should be used for operating on the area of memory. The
UnLockBlock call must give this same memory address. UnlockBlock returns
a value in DS:SI that can be used for the next LockBlock call.

The ALLOC operation of the memory_system always locks it's block prior to
returning. Therefore it always returns a real memory pointer. When the memory
area has been initialized, it may be unlocked, and the return of the
UnLockBlock call may be stored for future accesses to the memory region.

This convention can allow implementing a special kind of memory block that
knows how to swap itself to offline storage when it is not in use.
In practice, this system may be implemented by having objects on the heap
that represent unlocked blocks of memory. When this block recieves a lock
call, it creates a region in memory to recieve the memory contents and then
it loads the actual memory contents from offline storage. A pointer to this
new block is returned. Later, when this new block is freed, the old lock
block is informed and the lock block may swap the memory area to disk.

Normal memory_blocks, and memory_usedblocks, do not process the LockBlock or
UnLockBlock calls in any way. So how do blocks that implement swapping come
to be included in the memory system?  A process outside the memory_system,
a caller of memory_system, can implement this. The process calls the
memory_system to give it a block of memory. (This block of memory will
probably be the size of the swapping_block object.) This block of memory
can then be retyped by changing it's VMT. The new VMT will then point to
the method table for a different class of object that implements swapping
of it's memory region. (The outside process might make another call to
the swapping_block object that informs the swapping block how big of an
area it is managing.) As long as the memory_block can respond to normal
requests that the memory_system makes, (it will probably respond with the
methods of the memory_usedblock, while any special messages that it takes
are added to the end of the memory_usedblock VMT), the existance of the
block will not cause any problems. It can transparently handle LockBlock and
UnLockBlock calls by creating and destroying new blocks of memory within
the memory_system that it belongs to, because the outside process would
have passed it a handle to the memory_system, and also any handles or
information that it needs for accessing the offline virtual storage that
it swaps information in and out of.

Of course, it is possible that the memory_system itself might be able to
transparently create these new types of memory_blocks. If the memory_system
is passed a pointer to the init method for a new type of block, then
it would automatically deal with the new type of block. The init method
for memory_blocks requires the size of the block to be passed. Currently
this is set to be the same size as the block that the memory_system
selected.

~
jumps
page
locals @@

; Define the following to enable the optimization of the rover pointer
; to shorten time to find a free heap area.
_USE_ROVER_ =1


; Define the following to enable a freed block to be combined with
; any free block that might be immediately before it.
; Defining this equate causes a tremendous slow down in the deallocation
; process, since a scan for previous must be done for every free operation.
; This scan for previous has to walk the entire memory block chain up to
; the item that is being freed in order to find the previous block and see
; if it is free.
; Logic has been added instead to the alloc routine to combine adjacent
; free blocks that it finds while it is walking forward through the
; chain of memory blocks.
;_COMBINE_PREV_=1

; The PREV pointer for unused blocks is not always accurate, since
; scanprev is not done during dealloc. Do not define the following.
;_DO_SETPREV_ = 1


; Since used blocks have a different VMT pointer than unused blocks,
; routines that are not valid for used blocks, (e.g. setprev and setsize),
; can be trapped out from the default routine in the memory_block object.
; Then those memory block objects can assume that they were called because
; the block is free. If this equate is not defined, it is important that
; all used blocks, (and end blocks), are not left as regular memory_blocks,
; but are instead retyped as what they are by changing the VMT.
;__DO_ISFREE_ = 1


% .model MDL,pascal
.code

; Int 21 DOS calls
DOSINT             =   21H
DOSGETMEMBLOCK     =   48H
DOSRELEASEBLOCK    =   49H
DOSRESIZEBLOCK     =   4AH
DOSTERMINATE       =   4CH


; Include the utility macros that ease dealing with
; the Virtual Method Tables.
include vmtutil.inc

IsZero macro reg
       or reg,reg
       endm

; Include the names of routines that handle display of numbers.
include display.inc


; Cause the VMT tables to be defined as a part of this module.
_MAKE_MEMVMT_ = 1
   include mem.inc


PAGE
;************************************ Routines for MEMORY_BLOCK

memory_block_reserved_size proc
         mov  bx,offset @memory_block_used_start
         ret
memory_block_reserved_size endp



; AX has size of block to allocate into the chain.
memory_block_initget proc pascal previousblock:word,nextblock:word

         ret
memory_block_initget endp



memory_block_init proc pascal uses ax,\
                              previousblock:word,nextblock:word,\
                              bsize:word

         ; Set the VMT PTR within this block!
         mov  ds:[si.@Mptr_memory_block],offset @TableAddr_memory_block
;if @CodeSize eq 1
;         mov  word ptr ds:[si.@Mptr_memory_block+2],seg @TableAddr_memory_block
;endif

ifdef _DO_SETPREV_
         mov  ax,[previousbLock]
         mov  word ptr ds:[si.prev],ax
endif

         mov  ax,FREE_BLOCK
         mov  word ptr ds:[si.next],ax
         mov  ax,[nextblock]
         mov  word ptr ds:[si.next2],ax
         mov  ax,[bsize]
         mov  ds:[si.blksize],ax
         xor  ax,ax

         ; Zero out the unused high words
         mov  word ptr ds:[si.next+2],ax
         mov  word ptr ds:[si.next2+2],ax
ifdef _DO_SETPREV_
         mov  word ptr ds:[si.prev+2],ax
endif
         ret
memory_block_init endp



memory_block_deinit proc
         ret
memory_block_deinit endp



; AX has the previous block segment
; If combine is done, DS points to the previous segment.
memory_block_combine proc
ifdef _DO_ISFREE_
         call ds:[si] method memory_block:IsFree
         jnz  @@done
endif

         push cx
         mov  cx,ax   ; Save AX, so we can set it's block to point to the
                      ; next of the DS block.
         call ds:[si] method memory_block:GetNext
         mov  ds,cx
         call ds:[si] method memory_block:SetNext
         ; Also, need to update size of previous block
         ; AX still contains seg of block after one being freed.
         sub  ax,cx
         dec  ax
         call ds:[si] method memory_block:SetSize
         pop  cx

@@done:
         ret
memory_block_combine endp



mb_show proc uses ds es dx ax
.data
@@used db "Used$"
@@free db "Free" ;,"$"
@@next2 db " Next2:$"
@@prev db " Prev:$"
@@blksize db " Blksize:$"
.code
         call Show_Bracket
         call ds:[si] method memory_block:IsFree

         ; Put our pointer into   ES:SI
         push ds
         pop  es
         mov  ax,@data
         mov  ds,ax

         ; Print a USED or FREE string
         mov  ah,DOSPRINTSTRING
         jz   @@block_is_free

        ; We should never get here if memory_usedblocks are used.
         mov  dx,offset @@used
         int  DOSINT
         jmp  @@done

@@block_is_free:
         mov  dx,offset @@free

@@show_msg:
         int  DOSINT

        ; mov  ah,DOSPRINTSTRING
        ; mov  dx,offset @@next2
        ; int  DOSINT
         mov  ax,word ptr es:[si.next2]
         call ShowHexWord

ifdef _DO_SETPREV_
         mov  ah,DOSPRINTSTRING
         mov  dx,offset @@prev
         int  DOSINT
         mov  ax,word ptr es:[si.prev]
         call ShowHexWord
endif

         mov  ah,DOSPRINTSTRING
         mov  dx,offset @@blksize
         int  DOSINT
         mov  ax,word ptr es:[si.blksize]
         call ShowHexWord

@@done:
         call Show_Endbracket
         ret
mb_show endp



mb_findprev proc
         local findprevfor:word
         mov  [findprevfor],ax

@@check:
         LoadVMTSeg  es,ax
         call ds:[si] method memory_block:GetNext
         cmp  ax,[findprevfor]
         je   @@previousfound

         IsZero ax
         je   @@noprevious

         ; Load the segment of the next block, and go check it out
         mov  ds,ax
         jmp  @@check

@@previousfound:
         mov ax,ds      ; Store the segment of the current block in AX.
         jmp @@done

@@noprevious:
         xor ax,ax      ;Zero out AX to indicate no previous.
@@done:
         ret
mb_findprev endp



mb_getnext proc
ifdef _DO_ISFREE_
         mov  ax,word ptr [si.next]
         cmp  ax,FREE_BLOCK
         jne  @@done
endif
         mov  ax,word ptr [si.next2]
@@done:
         ret
mb_getnext endp



mb_isfree proc
ifdef _DO_ISFREE_
         cmp word ptr [si.next],FREE_BLOCK
else
         ; All we need to do is set the Z flag!
         cmp ax,ax
endif
         ret
mb_isfree endp



mb_setprev proc
ifdef _DO_SETPREV_
ifdef _DO_ISFREE_
         LoadVMTSeg es,bx
         call ds:[si] method memory_block:IsFree
         jnz  @@1
endif
         mov  word ptr ds:[si.prev],ax
@@1:
endif
         ret
mb_setprev endp



mb_setsize proc
ifdef _DO_ISFREE_
         LoadVMTSeg es,bx
         call ds:[si] method memory_block:IsFree
         jnz  @@1    ; short @memory_block_setsize_done
endif
         mov  word ptr ds:[si.blksize],ax
ifdef _DO_ISFREE_
@@1:
endif
         ret
mb_setsize endp



mb_setnext proc
ifdef _DO_ISFREE_
         LoadVMTSeg es,bx
         call ds:[si] method memory_block:IsFree
         jnz  short @@notfree
endif

         ; If we are here, the block is free.
         mov  word ptr ds:[si.next2],ax
ifdef _DO_ISFREE_
         jmp  short @@done

@@notfree:
         mov  word ptr ds:[si.next],ax
@@done:
endif
         ret
mb_setnext endp



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -