home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / stdlib.zip / MEMORY.ASM < prev    next >
Assembly Source File  |  1990-07-10  |  24KB  |  841 lines

  1.         extrn    PSP:word
  2. stdlib        segment    para public 'slcode'
  3.         assume    cs:stdlib
  4. ;
  5. ; Memory allocation routines: MemInit, malloc, and free.
  6. ;
  7. ;
  8. ; Local variables:
  9. ;
  10. StartOfHeap    dw    ?
  11. SizeOfHeap    dw    ?
  12. FreeSpace    dw    ?
  13. ;
  14. ; Memory manager data structure:
  15. ;
  16. mmstruct    struc
  17. blksize        dw    ?
  18. bwdptr        dw    ?
  19. fwdptr        dw    ?
  20. refcnt        dw    ?
  21. freebwdptr    dw    ?        ;Only if in the free list.
  22. freefwdptr    dw    ?        ;Only if in the free list.
  23.         ends
  24. ;
  25. ; When using es and ds as pointers into the heap, the following equates
  26. ; come in handy.
  27. ;
  28. esptr        equ    word ptr es:[0]
  29. dsptr        equ    word ptr ds:[0]
  30. ;
  31. NIL        equ    0
  32. ;
  33. ;
  34. ; MemInit- Initializes the memory manager.
  35. ;
  36. ;    On entry- DX contains the number of paragraphs of memory to reserve
  37. ;          for other programs.  The default (in shell.asm) is 0.  If
  38. ;          you intend to execute other programs from the program you're
  39. ;          writing, you will have to reserve an appropriate amount of
  40. ;          space for that program.  If you attempt to reserve too
  41. ;          much space, then this code splits the available free memory
  42. ;          in half and gives half to the heap and reserves half for
  43. ;          other programs.  If this is desirable, simply set DX to
  44. ;          0ffffh before calling MemInit.
  45. ;
  46. ;    On Exit-  No error if carry is clear.  In such a case, CX contains
  47. ;          the number of paragraphs of memory actually allocated.
  48. ;          AX contains the starting segment address of the free
  49. ;          memory block.
  50. ;
  51. ;          If carry is set, then an error occurred, AX contains the
  52. ;          error code (DOS).
  53. ;
  54. ; WARNING: for this routine to work properly, the calling program has to
  55. ; declare (and initialize) a word variable by the name PSP which contains
  56. ; the program's program segment prefix value.  Furthermore, the last segment
  57. ; in the program must be "zzzzzzseg" and this guy should NOT contain any
  58. ; valid data.
  59. ;
  60.         public    sl_MemInit
  61. sl_MemInit    proc    far
  62.         push    bx
  63.         push    dx
  64.         push    es
  65. ;
  66. ; Compute program size, in paragraphs:
  67. ;
  68.         mov    ax, seg PSP
  69.         mov    es, ax
  70.         mov    bx, es:PSP
  71.         mov    es, bx
  72.         mov    ax, seg zzzzzzseg
  73.         sub    ax, bx
  74.         inc    bx            ;Safety margin
  75.         inc    bx
  76.         mov    ah, 4ah            ;Memory block resize opcode
  77.                 int    21h
  78. ;
  79. ; Now ask for a ridiculous amount of memory so we can find out how much is
  80. ; available.
  81. ;
  82.         mov    bx, 0ffffh
  83.         mov    ah, 48h            ;Alloc block opcode
  84.         int    21h
  85. ;
  86. ;
  87. ; Allocate storage for the heap.
  88. ;
  89.         cmp    bx, dx            ;See if DX is too large.
  90.         ja    GoodHeap
  91.         shr    bx, 1            ;Use half remaining space.
  92.         jmp    short SetNewAlloc
  93. ;
  94. GoodHeap:    sub    bx, dx            ;Make room for other apps.
  95. SetNewAlloc:    cmp    bx, 10h            ;Make sure there is some room.
  96.         jbe    ErrorAlloc2
  97.         mov    ah, 48h            ;Alloc block opcode
  98.         int    21h
  99.         jc    ErrorAlloc        ;Shouldn't happen, but...
  100. ;
  101. ; Okay, we've just allocated the block, now set up our own local variables
  102. ; so we can keep track of the data.
  103. ;
  104.         mov    cs:StartOfHeap, ax    ;Save pointer to memory.
  105.         mov    cs:FreeSpace, ax    ;Save pointer to 1st free blk.
  106.         mov    cs:SizeOfHeap, bx    ;Size of heap in paragraphs.
  107.         mov    es, ax            ;Init pointer to heap.
  108.                 xor    ax, ax
  109.         mov    esptr.blksize, bx    ;Size of this block (paras).
  110.         mov    esptr.bwdptr, ax    ;Back pointer is NIL.
  111.         mov    esptr.fwdptr, ax    ;Fwd pointer is NIL.
  112.         mov    esptr.refcnt, ax    ;Reference Count is zero.
  113.         mov    esptr.freebwdptr, ax    ;Free list bwd ptr is NIL.
  114.         mov    esptr.freefwdptr, ax    ;Free list fwd ptr is NIL.
  115.         mov    cx, bx            ;Return size in CX
  116.         mov    ax, cs:StartOfHeap
  117.         clc
  118.         jmp    MemInitDone
  119. ;
  120. ErrorAlloc2:    mov    ax, 8            ;Insufficient memory error.
  121. ErrorAlloc:    stc
  122. MemInitDone:    pop     es
  123.         pop    dx
  124.         pop    bx
  125.         ret
  126. sl_MemInit    endp
  127. ;
  128. ;
  129. ;
  130. ;
  131. ;============================================================================
  132. ;
  133. ;    *     *      *      *        *         *****       *****
  134. ;    **   **     * *     *        *        *     *     *     *
  135. ;    * * * *    *   *    *        *        *     *     *
  136. ;    *  *  *    *****    *        *        *     *     *
  137. ;    *     *    *   *    *      *        *     *     *
  138. ;    *     *    *   *    *        *        *     *     *     *
  139. ;    *     *    *   *    *****    *****     *****       *****
  140. ;
  141. ;============================================================================
  142. ;
  143. ;
  144. ; malloc-  On entry, CX contains a byte count.  Malloc allocates a block
  145. ;       of storage of the given size and returns a pointer to this block
  146. ;       in ES:DI.  The value in ES:DI is always normalized, so you can
  147. ;       compare pointers allocated via malloc as 32-bit values.  Note
  148. ;       that malloc always allocates memory in paragraph chunks.
  149. ;       Therefore, this routine returns the actual number of bytes of
  150. ;       memory allocated in the CX register (this may be as much as 15
  151. ;       greater than the actual number asked for).
  152. ;
  153. ;       Malloc returns carry clear if it allocated the storage without
  154. ;       error.  It returns carry set if it could not find a block large
  155. ;       enough to satisfy the request.
  156. ;
  157. ;
  158. ; Data structure for memory allocation blocks:
  159. ;
  160. ; offset:
  161. ;
  162. ;   0    Size of Blk
  163. ;   2   Back link
  164. ;   4   Fwd Link
  165. ;   6   Reference Count
  166. ;   8   Data, if this block is allocated, prev link if on free list.
  167. ;  10    Data, if this block is allocated, next link if on free list.
  168. ;
  169. ;
  170. ;
  171.         public    sl_malloc
  172. sl_malloc    proc    far
  173.         push    ax
  174.         push    si
  175.         push    ds
  176. ;
  177. ; Convert byte count to paragraph count, since we always allocate whole
  178. ; paragraphs.
  179. ;
  180.         add    cx, 8            ;We have six bytes of overhead!
  181.         rcr    cx, 1            ;Use rcr because of add above.
  182.         adc    cx, 0
  183.         shr    cx, 1
  184.         adc    cx, 0
  185.         shr    cx, 1
  186.         adc    cx, 0
  187.         shr    cx, 1
  188.         adc    cx, 0
  189. ;
  190. ; Go find a block in the free list which is large enough.
  191. ;
  192. ; Uses the following algorithm:
  193. ;
  194. ;
  195.         cmp    cs:FreeSpace, 0        ;See if no free space.
  196.         jz    MemoryFull
  197.         mov    ds, cs:FreeSpace
  198.         mov    ax, ds            ;In case first block is it.
  199. FindBlk:    cmp    cx, dsptr.blksize    ;See if blk is large enuf.
  200.         jbe    FoundBlk        ;Go for it!
  201.         mov     ax, dsptr.freefwdptr    ;Get ptr to next free block.
  202.         mov    ds, ax            ;Set up pointer.
  203.         or    ax, ax            ;See if NIL
  204.                 jnz    FindBlk            ;Repeat until NIL.
  205. ;
  206. ; If we drop down here, we've got some big problems.
  207. ;
  208. MemoryFull:    stc
  209.         pop    ds
  210.         pop    si
  211.         pop    ax
  212.         mov    es, cs:StartOfHeap    ;In case they use this ptr
  213.         mov    di, 8            ; anyway.
  214.         ret
  215. ;
  216. ; When we come down here, we've found a block large enough to satisfy the
  217. ; current memory request.  If necessary, split the block up into two
  218. ; pieces and return the unused half back to the free pool.
  219. ;
  220. FoundBlk:       jne    SplitBlock
  221. ;
  222. ;
  223. ;
  224. ;***************************************************************************
  225. ; Exact fit, remove this guy from the free list and go for it!
  226. ;***************************************************************************
  227. ;
  228. ; There are four cases to deal with if this is an exact fit:
  229. ;
  230. ;    1) The block we're allocating is the first block in the free list.
  231. ;       In this case, FreeSpace points at this block and the freebwdptr
  232. ;       entry is NIL.
  233. ;
  234. ;    2) The block we're allocating is neither the first or last in the
  235. ;       free list.
  236. ;
  237. ;    3) The block we're allocating is the last block in the free list.
  238. ;       In this case, the freefwdptr will be NIL.
  239. ;
  240. ;    4) The block is both the first and last (i.e., only) block in the
  241. ;       the free list.
  242. ;
  243. ; At this point, DS points at the block we're going to allocate.
  244. ;
  245.         mov    ax, dsptr.freefwdptr    ;Pointer to next free block.
  246.         cmp    dsptr.freebwdptr, NIL    ;First item in list?
  247.         jnz    NotFirst
  248. ;
  249. ; Case (1) and (4) drop down here.
  250. ;
  251. ; If this is the first free block in the free link list, point FreeSpace
  252. ; beyond this guy rather than going through the usual linked list stuff.
  253. ;
  254. ; AX contains a pointer to the next free block (after this one) if it exists.
  255. ; DS points at the current free block.
  256. ;
  257. ; Since we are removing the first free block, we need to update the FreeSpace
  258. ; pointer so that it points at the next free block in the free block list.
  259. ;
  260.         mov    cs:FreeSpace, ax    ;Note: AX may be NIL if case (4).
  261. ;
  262. ; See if there is another block after this one.  If not (case 4) then jump
  263. ; off to FixThisBlk.
  264. ;
  265.         or    ax, ax            ;Is there another free blk?
  266.         jz    FixThisBlk        ;If not, don't patch next adrs.
  267. ;
  268. ; Case (1), only, down here.  The current block is the one we want and
  269. ; there is another free block after this one.  AX Points at the next free
  270. ; block.  DS points at the current block.
  271. ;
  272.         mov    es, ax               ;Point ES at next free block.
  273.         mov    esptr.freebwdptr, NIL    ;Set next guy's back link to NIL.
  274.         jmp    short FixThisBlk
  275. ;
  276. ; If the current block is not the first free block in the free block list
  277. ; handle it down here. This corresponds to cases 2 or 3.  On entry, DS
  278. ; points at the current block, AX points at the next free block (if present).
  279. ;
  280. NotFirst:    mov    es, dsptr.freebwdptr    ;Get ptr to prev blk.
  281.         mov    esptr.freefwdptr, ax    ;Skip over current blk.
  282.         mov    ax, es            ;Load AX with prev blk adrs.
  283. ;
  284. ; Now we need to figure out if there is a next free block (is this case 2?).
  285. ;
  286.         cmp    dsptr.freefwdptr, NIL
  287.         jz    FixThisBlk
  288. ;
  289. ; Definitely Case (2) here.  Patch the next free block's prev field with
  290. ; the address of the previous block.
  291. ;
  292.         mov    es, dsptr.freefwdptr    ;Point ES at next block.
  293.         mov    esptr.freebwdptr, ax    ;Save link to prior block.
  294. ;
  295. ; All four cases converge down here to clean up things and store the
  296. ; overhead info for the newly allocated block.
  297. ;
  298. FixThisBlk:    mov    dsptr.blksize, cx    ;Save its size.
  299.         mov    dsptr.refcnt, 1        ;Reference count = 1.
  300.         mov    di, 8            ;Pointer to data area.
  301.         mov    ax, ds
  302.         mov    es, ax
  303.         shl    cx, 1            ;Convert paragraph size to
  304.         shl    cx, 1            ; bytes.
  305.         shl    cx, 1
  306.         shl    cx, 1
  307.         pop    ds
  308.         pop    si
  309.         pop    ax
  310.         clc
  311.         ret
  312. ;
  313. ;****************************************************************************
  314. ; The current free block is bigger than we need, SPLIT it in half down here.
  315. ;****************************************************************************
  316. ;
  317. ;
  318. ; If allocating this block splits a free block in half, we handle that
  319. ; down here.
  320. ;
  321. SplitBlock:     mov    ax, ds            ;Get start of block.
  322.         add    ax, dsptr.blksize    ;Add in size of block.
  323.         sub    ax, cx            ;Subtract part we're keeping.
  324.         mov    es, ax            ;Point at data block.
  325.         mov    esptr.blksize, cx    ;Save size of block
  326.         mov    esptr.bwdptr, ds    ;Save back pointer.
  327.         mov    esptr.refcnt, 1        ;Init reference count.
  328.         mov    ax, dsptr.fwdptr    ;Get prev fwd ptr.
  329.         mov    dsptr.fwdptr, es    ;Save new fwd point in free blk.
  330.         mov    esptr.fwdptr, ax    ;New forward pointer for us.
  331.         mov    si, es            ;Save ptr to this blk.
  332.         mov    es, ax            ;Point es at last blk.
  333.         mov    esptr.bwdptr, si    ;Chain it in properly.
  334.         mov    es, si            ;Restore so we can return it.
  335.         mov    ax, dsptr.blksize    ;Compute new size of free blk.
  336.         sub    ax, cx
  337.         mov    dsptr.blksize, ax
  338.         mov    di, 8            ;Init pointer to data.
  339.         shl    cx, 1            ;Convert paragraph size to
  340.         shl    cx, 1            ; bytes.
  341.         shl    cx, 1
  342.         shl    cx, 1
  343.         pop    ds
  344.         pop    si
  345.         pop    ax
  346.         clc
  347.         ret
  348. ;
  349. sl_malloc    endp
  350. ;
  351. ;
  352. ;
  353. ;===========================================================================
  354. ;
  355. ;  ******     *****       ******     ******
  356. ;  *          *    *      *          *
  357. ;  *          *    *      *          *
  358. ;  ****       * ***       ****       ****
  359. ;  *          *  *        *          *
  360. ;  *          *   *       *          *
  361. ;  *          *    *      ******     ******
  362. ;
  363. ;===========================================================================
  364. ;
  365. ; Free-    Returns a block of storage to the free list.
  366. ;
  367. ; On Entry-    ES:DI points at the block to free.
  368. ; On Exit-    Carry is clear if free was okay, set if invalid pointer.
  369. ;
  370. ;
  371.         public    sl_free
  372. sl_free        proc    far
  373.         push    ax
  374.         push    si
  375.         push    ds
  376.         push    es
  377.         mov    si, di
  378. ;
  379. ; See if this is a valid pointer:
  380. ;
  381.         cmp    si, 8
  382.         jne    BadPointer
  383.         mov    si, es            ;Make seg ptr convenient.
  384.         mov    ds, cs:StartOfHeap
  385.         cmp    si, cs:StartOfHeap    ;Special case if first block.
  386.         jne    Not1stBlock
  387. ;
  388. ; The block the user wants to free up is the very first block.  Handle that
  389. ; right here.
  390. ;
  391.         cmp    dsptr.refcnt, 0
  392.         je    BadPointer
  393.         dec    dsptr.refcnt        ;Decrement reference count.
  394.         jnz    QuitFree        ;Done if other references.
  395. ;
  396. ; Call coalesce to possibly join this block with the next block.  We do not
  397. ; have to check to see if this call joins the current block with the prev
  398. ; block because the current block is the very first block in the memory
  399. ; space.
  400. ;
  401.         call    Coalesce
  402. ;
  403. ; Adjust all the pointers as appropriate:
  404. ;
  405.         mov    dsptr.freebwdptr, NIL
  406.         mov    ax, cs:FreeSpace    ;Get and set up the fwd ptr.
  407.         mov    dsptr.freefwdptr, ax
  408.         mov    es, cs:FreeSpace
  409.         mov    esptr.freebwdptr, ds    ;Set up other back pointer.
  410.         mov    cs:FreeSpace, ds    ;Fix FreeSpace.
  411.         jmp    short QuitFree
  412. ;
  413. ;
  414. BadPointer:    stc
  415.         jmp    short Quit2
  416. ;
  417. QuitFree:    clc
  418. Quit2:        pop    es
  419.         pop    ds
  420.         pop    si
  421.         pop    ax
  422.         ret
  423. ;
  424. ; If this is not the first block in the list, see if we can coalesce any
  425. ; free blocks immediately around this guy.
  426. ;
  427. Not1stBlock:    cmp    esptr.refcnt, 0
  428.         je    BadPointer
  429.         dec    esptr.refcnt        ;Decrement reference count.
  430.         jnz    QuitFree        ;Done if other references.
  431. ;
  432.         call    Coalesce
  433.         jc    QuitFree
  434. ;
  435. ; Okay, let's put this free block back into the free list.
  436. ;
  437.         mov    ax, cs:FreeSpace
  438.         mov    esptr.freefwdptr, ax    ;Set as pointer to next item.
  439.         mov    esptr.freebwdptr, NIL    ;NIL back pointer.
  440.         mov    cs:FreeSpace, es
  441.         jmp    QuitFree
  442. ;
  443. sl_free        endp
  444. ;
  445. ;
  446. ; Coalesce routine: On entry, ES points at the block we're going to free.
  447. ; This routine coalesces the current block with any free blocks immediately
  448. ; around it and then returns ES pointing at the new free block.
  449. ; This routine returns the carry flag set if it was able to coalesce the
  450. ; current free block with a block immediately in front of it.
  451. ; It returns the carry clear if this was not the case.
  452. ;
  453. ;
  454. Coalesce    proc    near
  455.         push    ds
  456.         push    es
  457. ;
  458.         mov    ds, esptr.fwdptr        ;Get next contiguous block.
  459.         cmp    dsptr.refcnt, 0        ;Is that block free?
  460.         jnz    NextBlkNotFree
  461. ;
  462. ; If the next block is free, merge it into the current block here.
  463. ;
  464. ; Memory arrangement is currently something like this:
  465. ;
  466. ;        +------------------------+      +---------+   <-These are dbl links.
  467. ;        |                        |      |         |
  468. ;   |prevfree|     |CurFreeBlk| |FollowingBlk|   |NextFreeBlk|
  469. ;
  470. ; We want to wind up with:
  471. ;
  472. ;
  473. ;        +------------------------------------------+   <-These are dbl links.
  474. ;        |                                          |
  475. ;   |prevfree|     |CurFreeBlk| |FollowingBlk|   |NextFreeBlk|
  476. ;
  477. ;
  478. ; First, merge the current free block and the following block together.
  479. ;
  480.         mov    ax, dsptr.blksize        ;Get size of next block.
  481.         add    esptr.blksize, ax        ; Join the blocks together.
  482.         mov    ax, dsptr.fwdptr
  483.         mov    esptr.fwdptr, ax
  484.         or    ax, ax
  485.         jz    DontSetBwd
  486.         push    ds
  487.         mov    ds, ax
  488.         mov    dsptr.bwdptr, es
  489.         pop    ds
  490. ;
  491. ; Make sure that there is a |prevfree| block.
  492. ;
  493. DontSetBwd:    mov    ax, dsptr.freebwdptr
  494.         or    ax, ax
  495.         jz    SetFreeSpcPtr
  496. ;
  497. ; prevfree.fwd := following.fwd;
  498. ;
  499.         mov    es, dsptr.freebwdptr    ;Point ES at previous guy.
  500.         mov    ax, dsptr.freefwdptr
  501.         mov    esptr.freefwdptr, ax    ;Skip over current guy.
  502. ;
  503. ; If the fwd pointer is NIL, no need to continue.
  504. ;
  505.         or    ax, ax            ;See if end of list.
  506.         jz    NextBlkNotFree
  507. ;
  508. ; nextfree.bwd := following.bwd (prevfree).
  509. ;
  510.         mov    ax, es            ;Save ptr to this guy.
  511.         mov    es, dsptr.freefwdptr
  512.         mov    esptr.freebwdptr, ax
  513.         jmp    short NextBlkNotFree
  514. ;
  515. ; If FollowingBlk is the first free block in the free list, we have to
  516. ; execute the following code.
  517. ;
  518. SetFreeSpcPtr:  mov    es, dsptr.freefwdptr
  519.         mov    esptr.freebwdptr, NIL
  520.         mov    cs:FreeSpace, es
  521. ;
  522. ;
  523. ;
  524. ; After processing the block following this block, or if the next block
  525. ; was not free, come down here and check to see if the previous block
  526. ; was free.
  527. ;
  528. NextBlkNotFree:    pop    es        ;Restore pointer to current block.
  529.         push    es
  530.         mov    ax, esptr.bwdptr
  531.         or    ax, ax        ;Is it a NIL pointer
  532.         jz    NoPrevBlock
  533.         mov    ds, ax
  534.         cmp     dsptr.refcnt, 0    ;Is that block free?
  535.         jnz    NoPrevBlock
  536. ;
  537. ; Okay, the block in front is free.  Merge the current block into that one.
  538. ;
  539.         mov    ax, esptr.blksize
  540.         add    dsptr.blksize, ax
  541.         mov    ax, esptr.fwdptr
  542.         mov    dsptr.fwdptr, ax
  543.         or    ax, ax            ;See if there is a next blk.
  544.         jz    NoNextBlk
  545.         mov    es, ax
  546.         mov    esptr.bwdptr, ds
  547. NoNextBlk:    stc
  548.         pop    es
  549.         pop    ds
  550.         ret
  551. ;
  552. NoPrevBlock:    clc
  553.         pop    es
  554.         pop    ds
  555.         ret
  556. Coalesce    endp
  557. ;
  558. ;
  559. ;============================================================================
  560. ;
  561. ; *****      *******       *      *        *         *****       *****
  562. ; *    *     *            * *     *        *        *     *     *     *
  563. ; *    *     *           *   *    *        *        *     *     *
  564. ; *****      *****       *****    *        *        *     *     *
  565. ; *  *       *           *   *    *       *        *     *     *
  566. ; *   *      *           *   *    *        *        *     *     *     *
  567. ; *    *     *******     *   *    *****    *****     *****       *****
  568. ;
  569. ;============================================================================
  570. ;
  571. ;
  572. ; REALLOC - This routine expects a pointer in ES:DI and a new size in CX.
  573. ;        If the specified block is larger than the value in CX then
  574. ;        realloc shrinks the size of the block and returns the left over
  575. ;        information to the system heap.  If CX is larger than the speci-
  576. ;        fied block then realloc allocates a new block and copies the
  577. ;        data from the old block to the new block and then frees the
  578. ;        old block.  In any case, realloc returns a pointer to the
  579. ;        (possibly new) block in ES:DI.  Carry=0 on return if no error,
  580. ;        carry=1 on return if there wasn't enough room on the heap to
  581. ;        reallocate a larger block.
  582. ;
  583.         public    sl_realloc
  584. sl_realloc    proc    far
  585.         cmp    di, 8            ;Is this a realistic pointer?
  586.         jz    DoREALLOC
  587.         stc                ;Return with error, if not.
  588.         ret
  589. ;
  590. DoREALLOC:    push    ax 
  591.         push    cx
  592.         push    ds
  593.         push    si
  594. ;
  595. ;
  596. ; Convert byte count to paragraph count, since we always allocate whole
  597. ; paragraphs.
  598. ;
  599.         add    cx, 8            ;We have eight bytes of overhead!
  600.         rcr    cx, 1            ;Use rcr because of add above.
  601.         adc    cx, 0
  602.         shr    cx, 1
  603.         adc    cx, 0
  604.         shr    cx, 1
  605.         adc    cx, 0
  606.         shr    cx, 1
  607.         adc    cx, 0
  608. ;
  609. ; See if the new block size is larger or smaller than the old block size.
  610. ;
  611.         cmp    cx, esptr.BlkSize
  612.         ja    MakeBigger
  613. ;
  614. ; New desired size is less than or equal to the current size.  If no more
  615. ; than 32 bytes larger, don't even bother with the operation.
  616. ;
  617.         inc    cx
  618.         inc    cx
  619.         cmp    cx, esptr.BlkSize
  620.         jae    ReallocDone
  621.         dec    cx
  622.         dec    cx
  623. ;
  624. ; Okay, the new block size is seriously smaller here.  Turn the last group
  625. ; of bytes into a free block.
  626. ;
  627.         mov    ax, es            ;Get ptr to block
  628.         add    ax, cx            ;Add in new length
  629.         mov    ds, ax            ;Point at new block.
  630.         mov    ax, esptr.BlkSize    ;Compute the size of the
  631.         sub    ax, cx            ; new block.
  632.         mov    dsptr.BlkSize, ax    ;Save away the link.
  633.         mov    dsptr.bwdptr, es    ;Set up back pointer.
  634.         mov    ax, esptr.fwdptr    ;Copy old fwd ptr to new
  635.         mov    dsptr.fwdptr, ax    ; fwd ptr.
  636.         mov    dsptr.refcnt, 1        ;Init reference count to 1.
  637.         mov    esptr.fwdptr, ds    ;Set up new fwd ptr.
  638.         mov    esptr.BlkSize, cx    ;Set up new length.
  639.         push    es 
  640.         mov    di, 8
  641.         mov    ax, ds
  642.         mov    es, ax
  643.         call    sl_free            ;Free the new block.
  644.         mov    di, 8
  645.         pop    es            ;Get pointer to original blk
  646. ;
  647. ReAllocDone:    pop    si 
  648.         pop    ds 
  649.         pop    cx
  650.         pop    ax
  651.         clc
  652.         ret
  653. ;
  654. ;
  655. ;
  656. ; If they had the nerve to want this block larger, come down here and allocate
  657. ; a new block, copy the old data to the new block, and then free the old block.
  658. ;
  659. ;
  660. MakeBigger:    mov    ax, es            ;Preserve pointer to old blk.
  661.         mov    ds, ax
  662.         mov    si, di            ;Contains "8".
  663.         call    sl_malloc        ;Allocate new block.
  664.         jc    BadRealloc
  665. ;
  666. ; Okay, copy the old block to the new block.  Note that both SI and DI
  667. ; contain 8 at this point.  We can make this assumption here because,
  668. ; after all, this is the memory manager code and it knows the internal
  669. ; representation.
  670. ;
  671.         mov    cx, dsptr.BlkSize    ;Get original block size
  672.         shl    cx, 1            ;Convert from paragraphs
  673.         shl    cx, 1            ; to word count.
  674.         shl    cx, 1
  675.         pushf
  676.         cld
  677.     rep    movsw                ;Note we're moving words!
  678.         popf
  679. ;
  680. ; Okay, free up the old block and we're done.
  681. ;
  682.         mov    di, 8
  683.         push    es               ;Save ptr to new block.
  684.         mov    ax, ds
  685.         mov    es, ax
  686.         call    sl_free
  687.         clc
  688.         mov    di, 8            ;Restore new block ptr.
  689.         pop    es 
  690.         pop    si 
  691.         pop    ds 
  692.         pop    cx 
  693.         pop    ax
  694.         ret
  695. ;
  696. BadRealloc:    stc
  697.         pop    si 
  698.         pop    ds 
  699.         pop    cx 
  700.         pop    ax
  701.         ret
  702. sl_realloc    endp
  703. ;
  704. ;
  705. ;
  706. ;
  707. ;============================================================================
  708. ;
  709. ;   ********      *        *     ********    ********    *******   *******
  710. ;   *       *     *        *     *       *   *       *      *      *      *
  711. ;   *       *     *        *     *       *   *       *      *      *      *
  712. ;   *       *     *        *     ********    ********       *      *******
  713. ;   *       *     *        *     *           *              *      *   *
  714. ;   *       *     *        *     *           *              *      *    *
  715. ;   *       *     *        *     *           *              *      *     *
  716. ;   ********       ********      *           *              *      *      *
  717. ;
  718. ;============================================================================
  719. ;
  720. ;
  721. ; Dupptr - Bumps up the reference count for a particular pointer by one.
  722. ;       Returns carry = 1 if initial pointer is illegal, returns carry=0
  723. ;       if no error.  Returns pointer in ES:DI.  You must pass the pointer
  724. ;       to increment in ES:DI.
  725. ;
  726.         public    sl_DupPtr
  727. sl_DupPtr    proc    far
  728.         cmp    di, 8            ;See if this is a valid ptr.
  729.         je    GoodPtr
  730.         stc
  731.         ret
  732. ;
  733. GoodPtr:    inc    esptr.refcnt        ;Bump up the reference cnt.
  734.         clc
  735.         ret
  736. sl_DupPtr    endp
  737. ;
  738. ;
  739. ;============================================================================
  740. ;
  741. ; *****   *****   *****   *   *   *   *   *****     *     *****
  742. ;   *     *         *     **      *   *   *        * *    *    *
  743. ;   *      ***      *     * * *   *****   ***     *****   *    *
  744. ;   *         *     *     *  **   *   *   *       *   *   *****
  745. ;   *         *     *     *   *   *   *   *       *   *   *
  746. ; *****   *****   *****   *   *   *   *   *****   *   *   *
  747. ;
  748. ;============================================================================
  749. ;
  750. ; IsInHeap-    Returns carry clear if the pointer passed in es:di is within
  751. ;        the heap.  Returns carry set if this pointer is outside the
  752. ;        heap.
  753. ;
  754.         public    sl_IsInHeap
  755. sl_IsInHeap    proc    far
  756.         push    ax
  757.         push    bx
  758.         mov    bx, es
  759.         mov    ax, cs:StartOfHeap
  760.         cmp    bx, ax
  761.         jb    Outside
  762.         add    ax, cs:SizeOfHeap
  763.         mov    bx, es
  764.         cmp    bx, ax
  765.         ja    Outside
  766.         clc
  767.         pop    bx
  768.         pop    ax
  769.         ret
  770. ;
  771. Outside:    stc
  772.         pop    bx
  773.         pop    ax
  774.         ret
  775. sl_IsInHeap    endp
  776. ;
  777. ;
  778. ;
  779. ;
  780. ;============================================================================
  781. ;
  782. ; *****   *****   *****       *****   *****
  783. ;   *     *       *    *     *     *    *
  784. ;   *      ***    *****      *     *****
  785. ;   *         *   *          *     * *
  786. ;   *         *   *          *     *  *
  787. ; *****   *****   *          *     *   *
  788. ;
  789. ;============================================================================
  790. ;
  791. ; IsPtr-    Returns the carry flag clear if es:di points at the beginning
  792. ;        of an allocated block in the heap.  Returns with the carry
  793. ;        flag clear if es:di points at a deallocated block.
  794. ;
  795.         public    sl_IsPtr
  796. sl_IsPtr    proc    far
  797.         cmp    di, 8         ;All of our ptrs have an offset of 8.
  798.         jne    NotPtr2
  799.         push    ax
  800.         push    bx
  801.         push    es
  802.         mov    ax, es
  803. ;
  804.         mov    bx, cs:StartOfHeap
  805. CmpLoop:    cmp    bx, ax
  806.         je    MightBe
  807.         ja    NotPtr
  808.         mov    es, bx
  809.         mov    bx, esptr.fwdptr
  810.         or    bx, bx        ;See if NIL link.
  811.         jnz    CmpLoop
  812. ;
  813. NotPtr:        pop    es
  814.         pop    bx
  815.         pop    ax
  816. NotPtr2:    stc
  817.         ret
  818. ;
  819. ; Might be the pointer, let's see if this guy's allocation count is greater
  820. ; than zero.
  821. ;
  822. MightBe:    mov    es, bx
  823.         cmp    esptr.blksize, 0
  824.         je    NotPtr
  825.         clc
  826.         pop    es
  827.         pop    bx
  828.         pop    ax
  829.         ret
  830. sl_IsPtr    endp
  831. ;
  832. ;
  833. ;
  834. stdlib        ends
  835. ;
  836. ;
  837. zzzzzzseg    segment    para public 'zzzzzz'
  838. LastBytes    db    16 dup (?)
  839. zzzzzzseg    ends
  840.         end
  841.