bdmgr.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:46k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. TITLE BdMgr.asm - Buffer Descriptor Management Routines
  2. COMMENT
  3. --------- --- ---- -- ---------- ----
  4. COPYRIGHT (C) 1985 BY MICROSOFT, INC.
  5. --------- --- ---- -- ---------- ----
  6. ;============================================================================
  7. ; Module: BdMgr.asm - Buffer Descriptor Management Routines
  8. ; This is a layer of routines which depends on the BASCOM Runtime Heap
  9. ; Management routines in source file (strutl.asm).
  10. ; It manages entries in the Interpreter and Far heap.
  11. ; System: Quick BASIC Interpreter
  12. ;============================================================================
  13. .xlist
  14. include version.inc
  15. BDMGR_ASM = ON
  16. includeOnce architec
  17. includeOnce context
  18. includeOnce heap
  19. includeOnce parser
  20. includeOnce txtmgr
  21. includeOnce util
  22. .list
  23. ; .sall
  24. assumes DS,DATA
  25. assumes ES,DATA
  26. assumes SS,DATA
  27. sBegin DATA
  28. ; HMEM_ constants used by SBMGR allocation routines
  29. HMEM_FIXED EQU 0000H
  30. HMEM_MOVEABLE EQU 0002H
  31. HMEM_NOCOMPACT EQU 0010H
  32. HMEM_ZEROINIT EQU 0040H
  33. HMEM_DISCARDABLE EQU 0F00H
  34. externW b$fVarHeapActive ;non-0 when variable heap is active
  35. DbOMCnt MACRO label
  36. ENDM
  37. sEnd DATA
  38. EXTRN AdjustCommon:FAR
  39. EXTRN AdjustVarTable:FAR
  40. sBegin RT
  41. assumes CS,RT
  42. EXTRN B$ILHALC:NEAR
  43. EXTRN B$LHREALC:NEAR
  44. EXTRN B$LHDALC:NEAR
  45. EXTRN B$LHChgBakPtr:NEAR
  46. EXTRN B$ILHADJ:NEAR
  47. EXTRN B$LHForEachEntry:NEAR
  48. EXTRN B$NHCPCT:NEAR
  49. EXTRN B$TglHeapSpt:FAR
  50. EXTRN B$IFHAlloc:NEAR 
  51. EXTRN B$FHDealloc:NEAR
  52. EXTRN B$FHRealloc:NEAR
  53. EXTRN B$FHAdjDesc:NEAR
  54. EXTRN B$FHAdjOneDesc:NEAR
  55. CBBUFBLOCK equ 512 ;Never grow a near heap by less than this
  56. ; number of bytes to reduce heap thrashing.
  57. VAR_EXTRA equ 30 ;we want to keep up to this much free space beyond
  58. ; cbLogical in IT_VAR (variable) tables when compressing
  59. ; other bd's all the way back to cbLogical. This is to
  60. ; help the user's chances of edit and CONTinuing.
  61. ;------------------------------------------------------------
  62. ;---  Interpreter Buffer Descriptor Management Routines   ---
  63. ;------------------------------------------------------------
  64. ;***
  65. ;B$IHeapEntryMoved - handle movement of Interpreter-specific Heap entry
  66. ;Purpose:
  67. ; This routine is called by the Runtime Heap management
  68. ; code just before it moves an Interpreter-specific Heap entry.
  69. ; This routine performs any updating necessary due to
  70. ; the movement of an Interpreter-specific Heap entry
  71. ; it does not need to update entry pointer in the bd[p] for
  72. ; the entry being moved; it just dispatches based on the
  73. ; heap entry type to a routine which finds all string/heap
  74. ; owners within the heap entry being moved, and calls the heap
  75. ; management code to update the backpointers. Note that each 
  76. ; such routine will be located in it's own component; these 
  77. ; routines will call the runtime heap manager directly, but
  78. ; will do so via a macro to keep runtime heap interface knowledge
  79. ; confined to this module and associated header files.
  80. ;Entry:
  81. ; AX = number of bytes the heap entry has moved.
  82. ;        A positive number indicates the entry has moved
  83. ;        to a higher address.
  84. ; BX = pointer to the bd[p].pb field of the buffer descriptor for
  85. ; the heap entry being moved.
  86. ; CL = type constant for the heap type being moved (IT_MRS, ... etc.)
  87. ;
  88. ;Exit:
  89. ; none.
  90. ;Modifies:
  91. ; May modify BX, CX, or PSW - no others
  92. ;***************************************************************************
  93. cProc B$IHeapEntryMoved,<PUBLIC,NEAR,NODATA>,<AX,DX,ES,SI,DI>
  94. cBegin
  95. mov si,bx
  96. cmp cl,IT_NO_OWNERS_BDP ;a bdp entry being moved?
  97. jnz Not_Bdp ;brif not
  98. add [bx.BDP_pbCur-2],ax ;adjust the pbCur field
  99. jmp short Entry_Moved_Exit ;that's all, folks
  100. Not_Bdp:
  101. mov di,ax ;communicate adjustment factor in DI
  102. mov ax,[bx-2] ;put cbLogical (table end offset) in ax
  103. mov bx,[bx]
  104. push ax ;save until Entry_Moved_Cont
  105. push bx ;save until Entry_Moved_Cont
  106. push cx ;save until Entry_Moved_Cont
  107. cmp cl,IT_COMMON_VALUE
  108. jae Update_Stack_Ptrs ;brif we have to update stack ptrs, or
  109. ;var or common table
  110. cmp cl,IT_PRS ; no bd's in prs tables
  111. jz Entry_Moved_Cont ; brif prs table
  112. cCall AdjustITable,<bx,ax,cx> ;adjust the table, whatever it is.
  113. Entry_Moved_Cont:
  114. pop cx ;restore type constant
  115. pop bx ;restore start of range
  116. pop dx
  117. FHD_TBL EQU NOT IT_M_INTERP AND (IT_MRS OR IT_PRS OR IT_COMMON_VALUE OR IT_VAR)
  118. test cl,FHD_TBL
  119. jz Entry_Moved_Exit ;brif entry can't contain far heap desc.
  120. ;prs and mrs tables contain bdl's - - - get far heap to update these
  121. add dx,bx ;dx is now end of range
  122. mov ax,di ;adjustment factor
  123. call B$FHAdjDesc
  124. Entry_Moved_Exit:
  125. cEnd
  126. Update_Stack_Ptrs:
  127. jnz Upd_Stk_Ptrs_Cont ;brif cl != IT_COMMON_VALUE
  128. call AdjustCommon ;update backpointers to any string 
  129. ;descriptors or string array descriptors
  130. ;in given IT_COMMON_VALUE heap entry
  131. jmp short Entry_Moved_Cont
  132. Upd_Stk_Ptrs_Cont:
  133. DbAssertRelB  cl,z,IT_VAR,RT,<B$IHeapEntryMoved: cl == IT_VAR expected>
  134. call AdjustVarTable ;update backpointers to any string 
  135. ;descriptors or string array descriptors
  136. ;in given IT_VAR heap entry
  137. jmp short Entry_Moved_Cont
  138. ;***
  139. ;BdCompress - Compress a Runtime Heap entry
  140. ;Purpose:
  141. ; Call B$LhRealloc to reduce cbPhysical to cbLogical for a Bd whose
  142. ; pb field is at a given location.
  143. ; Called via B$LHForEachEntry by BdCompressAll.
  144. ;
  145. ; Note that variable tables are handled specially - - they're trimmed
  146. ; back so that they keep up to VAR_EXTRA free space at the end of the
  147. ; table to maximize the change of CONTinuing after variables are added.
  148. ;Entry:
  149. ; BX = pointer to owner of a local heap entry - - - for interpreter
  150. ; buffers, that amounts to a pointer to the 'pb' field of the
  151. ; owning bd.
  152. ; DL = heap entry type.
  153. ;Exit:
  154. ; none.
  155. ;Preserves:
  156. ; CX,SI
  157. ;Exceptions:
  158. ; none.
  159. ;
  160. ;***************************************************************************
  161. cProc BdCompress,<NEAR,NODATA>
  162. cBegin BdCompress
  163. DbChk Heaps ;ife RELEASE & checking enabled, check
  164. ; Local & Far Heaps for problems
  165. test dl,IT_M_INTERP ;is this an interpreter buffer?
  166. jz BdCompress_Exit
  167. dec bx ;turn bx into a real pBd (for cmp below)
  168. dec bx
  169. mov ax,[bx.BD_cbLogical]
  170. cmp dl,IT_VAR ;is this a variable table?
  171. jnz BdCompress_Cont ;  brif not
  172. add ax,VAR_EXTRA ;want to have up to VAR_EXTRA bytes
  173. ;  left in each var table to improve
  174. ;  chances of user adding a few 
  175. ;  variables and still CONTinuing
  176. cmp ax,[bx.BD_cbPhysical]
  177. jae BdCompress_Exit ;brif cbPhysical <= size we want buffer
  178. ;  to be - - - leave buffer alone
  179. BdCompress_Cont:
  180. lea dx,[ps.PS_bdpDst.BDP_cbLogical]
  181. cmp bx,dx ;brif not special parser buffer that 
  182. jnz BdCompress_Cont1 ;  must always have a minimal amount
  183. cmp ax,CB_PCODE_MIN ;never trim below this minimum
  184. ja BdCompress_Cont1 ;brif cbLogical > Minimum required
  185. DbAssertRel [bx.BD_cbPhysical],ae,CB_PCODE_MIN,RT,<BdCompress:Parser buffer is too small>
  186. mov ax,CB_PCODE_MIN
  187. BdCompress_Cont1:
  188. push cx ;preserve for caller
  189. push si ;preserve for caller
  190. mov [bx.BD_cbPhysical],ax ;set new desired cbPhysical
  191. mov si,[bx.BD_pb] ;pointer to start of data in buffer
  192. call B$LHREALC ;reduce entry to cbLogical size
  193. ;  MUST succeed and CANNOT cause
  194. ;  heap movement, because it is either
  195. ;  reducing entry size or doing nothing
  196. pop si
  197. pop cx
  198. BdCompress_Exit:
  199. cEnd BdCompress
  200. ;***
  201. ;BdCompressHeap - Compress all Runtime Heap entries in currently active heap
  202. ;Purpose:
  203. ; Same as BdCompressAll (below), but only crunches bd's in the currently
  204. ; active heap (either the local heap or the variable heap).
  205. ;Input:
  206. ; none.
  207. ;Output:
  208. ; none.
  209. ;Modifies:
  210. ; no permanent registers.
  211. ;Exceptions:
  212. ; Chance of string space corrupt.
  213. ;***************************************************************************
  214. cProc BdCompressHeap,<NEAR,NODATA>
  215. cBegin
  216. mov cx,RTOFFSET BdCompress
  217. call B$LHForEachEntry ;compress all bd's down to cbLogical
  218. ;  (effect is to create free blocks
  219. ;   out of extraneous space in bd's)
  220. cmp [b$fVarHeapActive],FALSE
  221. jnz BdCompressHeap_Exit ;don't compact the variable heap
  222. ;  only runtime init. does that - - 
  223. ;  B$NHCPCT assumes local heap active.
  224. call B$NHCPCT ;compact Local Heap and String Space
  225. BdCompressHeap_Exit:
  226. DbChk Heaps
  227. cEnd
  228. ;***
  229. ;BdCompressAll - Compress all Runtime Heap entries
  230. ;Purpose:
  231. ; To increase the speed of BdGrow, we keep a little free
  232. ; space at the end of each heap entry.  When the program
  233. ; begins execution, this routine is called to
  234. ; release all this space and compact interpreter-specific entries
  235. ; to the top of the Runtime Heap. 
  236. ; Note that this routine is ONLY called by interpreter code, 
  237. ; and never by the shared-runtime code.
  238. ;
  239. ; NOTE: after this operation is complete, the 'pbCurrent' field in
  240. ; bdp's will still be correct and useable, assuming that
  241. ; such pointers weren't pointing beyond cbLogical ...
  242. ;Input:
  243. ; none.
  244. ;Output:
  245. ; none.
  246. ;Modifies:
  247. ; no permanent registers.
  248. ;Exceptions:
  249. ; Chance of string space corrupt.
  250. ;
  251. ;***************************************************************************
  252. cProc BdCompressAll,<PUBLIC,FAR,NODATA>
  253. cBegin
  254. call BdCompressHeap ;compress the active heap
  255. call B$TglHeapSpt ;activate the other heap
  256. call BdCompressHeap ;compress the active heap
  257. call B$TglHeapSpt ;reactivate the originally active heap
  258. cEnd
  259. ;***
  260. ;BdAdjust(pBd)
  261. ; This routine takes a pointer to a bd as a parameter and assumes
  262. ; that an adjustment factor (the bd is being moved) is in DI.
  263. ; It calls a heap manager routine which updates the entry backpointer,
  264. ; if the bd is an owner (i.e., if the pb field is not NULL).
  265. ;Entry:
  266. ; pBd - pointer to a bd that's being moved
  267. ; DI contains adjustment factor it's being moved by
  268. ;Exit:
  269. ; none.
  270. ;Modifies:
  271. ; none. (no permanent registers)
  272. ;Exceptions:
  273. ; if anything wrong with heap entry for this bd, can end up calling
  274. ; the non-trapable "String Space Corrupt" error.
  275. ;***************************************************************************
  276. cProc BdAdjust,<PUBLIC,FAR,NODATA>
  277. parmW pBd
  278. cBegin BdAdjust
  279. mov bx,[pBd]
  280. mov ax,[bx.BD_pb]
  281. cmp ax,NULL
  282. jz BdAdjust_Done
  283. call B$ILHADJ ;get heap manager to do adjustment
  284. BdAdjust_Done:
  285. cEnd BdAdjust
  286. page
  287. ;***
  288. ;BdAllocVar - Allocate a Runtime Heap entry in the variable heap
  289. ;Purpose:
  290. ; Allocate an Interpreter-specific Heap entry from the variable heap.
  291. ; Uses the same interface and BdAlloc (see below).
  292. ;Entry, Exit, Modifies:
  293. ; Same as BdAlloc (see below).
  294. ;Note: Shares and exits via BdAlloc, below
  295. ;***************************************************************************
  296. cProc BdAllocVar,<PUBLIC,FAR,NODATA>
  297. cBegin <nogen>
  298. DbAssertRel grs.GRS_otxCONT,z,UNDEFINED,RT,<BdAllocVar: CAN continue>
  299. call B$TglHeapSpt ;make variable heap the active one
  300. cEnd <nogen> ;fall into BdAlloc, below
  301. ;***
  302. ;BdAlloc - Allocate a Runtime Heap entry
  303. ;Purpose:
  304. ; Allocate an Interpreter-specific Heap entry from the Runtime
  305. ; Heap.
  306. ; Note that this routine should ask for only the amount of space asked
  307. ; for; growing a buffer will increase requests to some minimal block size,
  308. ; but many buffers need to be initially allocated to some minimal 
  309. ; (possibly zero) size.
  310. ; NOTE: current heap manager interface demands that the owner-to-be
  311. ; should not be subject to heap movement (i.e., not in heap, or
  312. ; heap locked). 
  313. ;Entry:
  314. ; parm: bd *pbdOwner - points to owner-to-be of new heap entry
  315. ; parm: ushort cbSize - number of bytes needed
  316. ;if NOT FV_LMEM
  317. ; parm: char interpType - type of interp. table (IT_VALUE etc)
  318. ;endif
  319. ;Exit:
  320. ; if entry was successfully allocated:
  321. ;    pbdOwner->cbLogical = cbSize
  322. ;if FV_LMEM
  323. ;    pbdOwner->ppb = ptr to ptr to new heap entry (and is now owner)
  324. ;else
  325. ;    pbdOwner->pb = pointer to new heap entry (and is now a heap owner)
  326. ;    pbdOwner->cbPhysical = cbSize
  327. ;endif
  328. ;    [AX] = TRUE (non-zero)
  329. ; else
  330. ;    [AX] = FALSE (0) (Out of memory)
  331. ;Modifies:
  332. ; none  (NOTE: DOES modify ES)
  333. ;
  334. ;***************************************************************************
  335. cProc BdAlloc,<PUBLIC,FAR,NODATA>,<SI>
  336. parmW pbdOwner
  337. parmW cbSize
  338. parmB interpType
  339. cBegin
  340. DbShiftLH ;ife RELEASE cause some heap movement
  341. DbChk Heaps
  342. mov dl,[interpType]
  343. mov cx,[cbSize]
  344. mov bx,[pbdOwner]
  345. DbChk BdNotOwner,bx ;ensure that given bd isn't an owner now
  346. mov [bx.BD_pb],NULL ;in case allocation fails and caller
  347. ;  blindly calls BdFree with this bd
  348. DbOMCnt BD_END
  349. xchg bx,cx ;input order required by B$ILHALC
  350. inc cx ;'owner' to heap manager is the actual
  351. inc cx ;  pointer to the heap entry, not a pbd
  352. call B$ILHALC ;call heap manager to allocate memory
  353. jc BD_Crunch_BDs ;brif OM return; trim bd's, try again
  354. BdAlloc_Success:
  355. mov bx,[pbdOwner] ;assumes bdOwner not moved by allocation
  356. mov [bx.BD_pb],si ;SI is data ptr returned from B$ILHALC
  357. mov ax,[cbSize] ;save requested size as both logical
  358. mov [bx.BD_cbLogical],ax ;  and physical size, and return it as
  359. mov [bx.BD_cbPhysical],ax ;  our non-zero (i.e., 'TRUE') result
  360. mov al,TRUE ;in case input size was zero
  361. BD_END:
  362. cmp [b$fVarHeapActive],FALSE
  363. jz BdAlloc_Exit ;brif variable heap not active
  364. call B$TglHeapSpt ;reactivate the local heap
  365. BdAlloc_Exit:
  366. cEnd
  367. BD_Crunch_BDs:
  368. push dx
  369. push cx
  370. call far ptr BdCompressAll ;trim bd's, compress heap space
  371. pop cx
  372. pop dx
  373. call B$ILHALC ;try allocation again
  374. jnc BdAlloc_Success ;  brif it worked this time
  375. xor ax,ax ;OM error return
  376. jmp short BD_END
  377. ;***
  378. ;BdFree(pbdOwner) - Release a Heap entry
  379. ;Purpose:
  380. ; Release a Runtime Heap entry. If pbdOwner.BD_pb is NULL,
  381. ; just return (as input wasn't really an owner).
  382. ;Entry:
  383. ; parm: bd *pbdOwner - points to owner of new heap entry
  384. ;
  385. ;***************************************************************************
  386. cProc BdFree,<PUBLIC,FAR,NODATA>,<SI>
  387. parmW pbdOwner
  388. cBegin
  389. mov bx,[pbdOwner]
  390. mov si,[bx.BD_pb]
  391. cmp si,NULL
  392. jz BdFree_Exit ;brif bd isn't an owner
  393. mov [bx.BD_pb],NULL
  394. call B$LHDALC
  395. BdFree_Exit:
  396. cEnd
  397. ;***
  398. ;BdChgContents(pbd, psdNew) - Change contents of a buffer
  399. ;Purpose:
  400. ; Change the contents of a given buffer. Note that the buffer may or
  401. ; may not be an owner already; if it is an owner, it will be Free'd.
  402. ; The buffer will then be allocated, and the input sd contents copied in.
  403. ;
  404. ; NOTE: psdNew must not point into a heap entry!
  405. ;Entry:
  406. ; parm: bd *pbd - points to current owner of heap entry
  407. ; parm: bd *psdNew -   points to sd, contents of which are to be put
  408. ; in the input bd.
  409. ;Exit:
  410. ; if operation successful
  411. ; [AX] = TRUE (non-zero)
  412. ; else
  413. ; [AX] = FALSE (0) (Out of memory), and the original contents
  414. ; of the bd are lost.
  415. ;***************************************************************************
  416. cProc BdChgContents,<PUBLIC,FAR,NODATA>,<SI,DI>
  417. parmW pbd
  418. parmW psdNew
  419. cBegin
  420. mov si,[pbd]
  421. cCall BdFree,<si> ;free original contents if any
  422. mov di,[psdNew]
  423. DbChk PtrNotInHeap,di
  424. mov cx,[di.SD_cb]
  425. push cx ;save across call
  426. push si
  427. push cx
  428. PUSHI dx,IT_NO_OWNERS
  429. call BdAlloc ;alloc to size of desired contents
  430. pop cx
  431. or ax,ax
  432. jz BdChgContents_Exit ;brif OM error on allocation
  433. mov ax,[si.BD_pb]
  434. mov bx,[di.SD_pb]
  435. cCall CopyBlk,<bx,ax,cx> ;copy sd contents into bd
  436. BdChgContents_Exit:
  437. cEnd
  438. ;***
  439. ;BdChgOwner(pbdOwner, pbdNew) - Change the owner of a Heap entry
  440. ;BdChgOwner_NoCopy(pbdOwner, pbdNew) - Change the owner of a Heap entry
  441. ;Purpose:
  442. ; Change the owner of an Interpreter-specific Heap entry. If 
  443. ; pbdOwner.BD_pb is NULL, just return (as it wasn't really an owner to 
  444. ; begin with).
  445. ; BdChgOwner copies the bd contents to the new bd.
  446. ; BdChgOwner_NoCopy is provided as a speed improvement, and should be
  447. ; called in cases where the bd has already been copied BEFORE
  448. ; this routine is called.
  449. ;
  450. ; NOTE: This routine is guaranteed not to cause heap movement to occur.
  451. ;
  452. ; NOTE: This routine must be called AFTER a block containing the bd is
  453. ; moved if such movement is to take place, because this routine
  454. ; changes the contents of bdOwner to indicate that it's no longer
  455. ; an owner.
  456. ;Entry:
  457. ; parm: bd *pbdOwner - points to current owner of heap entry
  458. ; parm: bd *pbdNew -   points to new owner of heap entry
  459. ;
  460. ;***************************************************************************
  461. PUBLIC BdChgOwner
  462. BdChgOwner:
  463. mov cx,SIZE BD ;non-zero - - - do the copy
  464. SKIP2_PSW ;skip to start of common code
  465. PUBLIC BdChgOwner_NoCopy
  466. BdChgOwner_NoCopy:
  467. xor cx,cx
  468. cProc Chg_The_Owner,<FAR,NODATA>,<SI>
  469. parmW pbdOwner
  470. parmW pbdNew
  471. cBegin
  472. mov si,[pbdOwner]
  473. cmp [si.BD_pb],NULL
  474. jz BdChg_Exit
  475. DbChk BdOwner,si ;ensure that given bd is an owner
  476. jcxz BdChg_CopyDone ;brif caller already did this copy
  477. push si
  478. push pbdNew
  479. push cx ;set to SIZE BD for BdChgOwner
  480. call CopyBlk
  481. BdChg_CopyDone:
  482. mov cx,[pbdNew]
  483. inc cx ;to heap manager, 'owner' is the actual
  484. inc cx ;  pointer to heap data, not a pbd
  485. push si ;si is an input to B$LHChgBakPtr
  486. mov si,[si.BD_pb]
  487. call B$LHChgBakPtr
  488. pop si ;so we can set bd.pb to NULL
  489. mov [si.BD_pb],NULL ;mark that this is no longer an owner
  490. BdChg_Exit:
  491. cEnd
  492. ;***
  493. ;EnsPhysicalSize - ensure physical size of near heap >= ax
  494. ;Purpose:
  495. ; Change physical size of an Interpreter-specific Heap entry if necessary.
  496. ; This is used by BdGrow and BdCheckFree. 
  497. ; Note that this is not an external entry point, only for use
  498. ; within this module, and can thus use register calling conventions.
  499. ;
  500. ; NOTE: current heap manager interface demands that the owner
  501. ; should not be subject to heap movement. 
  502. ;Entry:
  503. ; [di] - points to owner of heap entry
  504. ; [ax] = new total size requested for the buffer (i.e., new minimum
  505. ; cbPhysical desired).
  506. ;Exit:
  507. ; if enough memory is available:
  508. ;          [ax] = TRUE (non-zero)
  509. ;    [bx] = new value for cbLogical (i.e., [ax] exit = entry)
  510. ; otherwise,
  511. ;    [ax] = 0
  512. ;
  513. ;***************************************************************************
  514. EnsPhysicalSize PROC NEAR
  515. DbChk BdOwner,di ;ensure that given bd is an owner
  516. DbChk Heaps
  517. push ax ;save input requested size
  518. DbOMCnt Ens_End2
  519. cmp ax,[di.BD_cbPhysical]
  520. jbe NoChange ;branch if already big enough
  521. push si ;save caller's si
  522. push ax ;in case initial try fails
  523. sub ax,[di.BD_cbPhysical] ;ax=amount to grow
  524. cmp ax,CBBUFBLOCK
  525. jae Big_Enough ;branch if growing by significant amount
  526. mov ax,CBBUFBLOCK ;never grow by less than this amount
  527. Big_Enough:
  528. add ax,[di.BD_cbPhysical] ;ax=(hopefully) new cbPhysical
  529. push ax ;save (hopefully) new cbPhysical
  530. mov si,[di.BD_pb]
  531. call B$LHREALC ;call heap manager to realloc
  532. pop bx ;size we realloced to
  533. or ax,ax ;test result
  534. jz Ens_Crunch_BDs ;brif realloc failed
  535. pop cx ;clean stack
  536. Ens_Phy_Success:
  537. mov [di.BD_cbPhysical],bx
  538. mov [di.BD_pb],si ;in case realloc moved the entry
  539. Ens_End1:
  540. pop si ;restore caller's si
  541. Ens_End2:
  542. pop bx ;restore input size for retval
  543. ret
  544. NoChange:
  545. mov al,TRUE ;ensure TRUE return, even if passed ax=0
  546. jmp short Ens_End2
  547. EnsPhysicalSize ENDP
  548. Ens_Crunch_BDs:
  549. call far ptr BdCompressAll ;trim all bd's, compress heaps
  550. pop ax ;input to B$LHREALC
  551. push ax ;save for return
  552. mov si,[di.BD_pb] ;may be trashed on error return
  553. call B$LHREALC
  554. pop bx ;cb we tried to realloc to
  555. or ax,ax ;did we succeed this time?
  556. jz Ens_End1 ;  brif not
  557. jmp short Ens_Phy_Success ;succeeded this time - - go wrap up
  558. ;***
  559. ;BdGrowVar - Grow a Runtime Heap entry in the variable heap
  560. ;Purpose:
  561. ; Same as BdGrow (below), but for an entry in the variable heap.
  562. ; Uses the same interface and BdGrow (see below).
  563. ;Entry, Exit, Modifies:
  564. ; Same as BdGrow (see below).
  565. ;Note: Shares and exits via BdGrow, below
  566. ;***************************************************************************
  567. cProc BdGrowVar,<PUBLIC,FAR,NODATA>
  568. cBegin <nogen>
  569. DbAssertRel grs.GRS_otxCONT,z,UNDEFINED,RT,<BdlGrowVar: CAN continue>
  570. call B$TglHeapSpt ;make variable heap the active one
  571. cEnd <nogen> ;fall into BdGrow, below
  572. ;***
  573. ;BdGrow - Increase the logical size of a Heap entry
  574. ;Purpose:
  575. ; Change logical size of an Interpreter-specific Heap entry.  This can
  576. ; result in the movement of this and other heap entries as well
  577. ; as strings.  
  578. ; When this routine actually needs to grow the physical size
  579. ; of the heap, it grows more than needed for this request, to
  580. ; reduce heap thrashing.
  581. ;
  582. ; NOTE: current heap manager interface demands that the owner
  583. ; should not be subject to heap movement. 
  584. ;Entry:
  585. ; parm: bd *pbdOwner - points to owner of heap entry
  586. ; parm: ushort cbGrow - number of bytes needed
  587. ;Exit:
  588. ; if enough memory is available:
  589. ;    pbdOwner->cbLogical += cbGrow,
  590. ;    pbdOwner->cbPhysical >= pbdOwner->cbLogical
  591. ;    [AX] = TRUE (non-zero)
  592. ; else
  593. ;    [AX] = FALSE (0) (Out of memory)
  594. ;
  595. ;***************************************************************************
  596. cProc BdGrow,<PUBLIC,FAR,NODATA>,<di>
  597. parmW pbdOwner
  598. parmW cbGrow
  599. cBegin
  600. mov di,[pbdOwner] ;di points to bd descriptor
  601. mov ax,[cbGrow] ;[AX] == increase desired
  602. add ax,[di.BD_cbLogical] ;[AX] == new logical size
  603. jc GrowOmErr ;branch if overflow (can't grow > 64k)
  604. ;*****************************
  605. ;NOTE: BdRealloc jumps in here
  606. ;*****************************
  607. BdRealloc1:
  608. call EnsPhysicalSize ;change physical size (inputs ax & di)
  609. or ax,ax ;test boolean result
  610. jz BdGrow_End ;brif out-of-memory case
  611. mov [di.BD_cbLogical],bx ;new cbLogical - successful return
  612. BdGrow_End:
  613. cmp [b$fVarHeapActive],FALSE
  614. jz BdGrow_Exit ;brif variable heap not active
  615. call B$TglHeapSpt ;reactivate the local heap
  616. BdGrow_Exit:
  617. cEnd
  618. GrowOmErr:
  619. xor ax,ax
  620. jmp short BdGrow_End
  621. ;***
  622. ;BdRealloc - Change the logical size of a Heap entry
  623. ;Purpose:
  624. ; Change logical size of an Interpreter-specific Heap entry.  This can
  625. ; result in the movement of this and other heap entries as well
  626. ; as strings.  
  627. ; When this routine actually needs to grow the physical size
  628. ; of the heap, it grows more than needed for this request, to
  629. ; reduce heap thrashing.
  630. ;
  631. ; NOTE: current heap manager interface demands that the owner
  632. ; should not be subject to heap movement. 
  633. ;Entry:
  634. ; parm: bd *pbdOwner - points to owner of heap entry
  635. ; parm: ushort cbLogicalNew - new size of heap entry
  636. ;Exit:
  637. ; if enough memory is available:
  638. ;    pbdOwner->cbLogical = cbLogicalNew,
  639. ;    pbdOwner->cbPhysical >= pbdOwner->cbLogical
  640. ;    [AX] = TRUE (non-zero)
  641. ; else
  642. ;    pbdOwner->cbLogical is unchanged
  643. ;    [AX] = FALSE (0) (Out of memory)
  644. ;
  645. ;***************************************************************************
  646. cProc BdRealloc,<PUBLIC,FAR,NODATA>,<di>
  647. parmW pbdOwner
  648. parmW cbNew
  649. cBegin
  650. mov di,[pbdOwner] ;di points to bd descriptor
  651. mov ax,[cbNew] ;[AX] == increase desired
  652. jmp SHORT BdRealloc1
  653. cEnd <nogen>
  654. ;***
  655. ;BdCheckFree - Make sure buffer has some free space
  656. ;Purpose:
  657. ; This is identical to BdGrow, but it does not alter the
  658. ; descriptor's cbLogical field.  Some typical cases when it is
  659. ; called include:
  660. ; 1-  Before calling BdAppend to copy from one bd to another.
  661. ;     By calling this first, we know BdAppend won't have to
  662. ;     grow the heap entry, causing movement, which could invalidate
  663. ;     BdAppend's pb argument.
  664. ; 2-  When the caller is about to do an operation which will
  665. ;     append information to a bd, but the caller doesn't know
  666. ;     exactly how many bytes will be added, but an upper limit is known.
  667. ;
  668. ; NOTE: current heap manager interface demands that the owner
  669. ; should not be subject to heap movement. 
  670. ;Entry:
  671. ; parm: bd *pbdOwner - points to owner of heap entry
  672. ; parm: ushort cbFree - number of free bytes needed
  673. ;Exit:
  674. ; pbdOwner->cbLogical is ALWAYS UNCHANGED
  675. ; If enough memory is available:
  676. ;    pbdOwner->cbPhysical >= pbdOwner->cbLogical + cbFree
  677. ;    [AX] = TRUE (non-zero)
  678. ; else
  679. ;    [AX] = FALSE (0) (Out of memory)
  680. ;
  681. ;***************************************************************************
  682. cProc BdCheckFree,<PUBLIC,FAR,NODATA>,<DI>
  683. parmW pbdOwner
  684. parmW cbFree
  685. cBegin
  686. mov di,[pbdOwner] ;di points to bd descriptor
  687. mov ax,[cbFree] ;[AX] == increase desired
  688. add ax,[di.BD_cbLogical] ;[AX] == resulting size
  689. jc CheckOmErr ;branch if overflow (can't grow > 64k)
  690. call EnsPhysicalSize ;change physical size (inputs ax & di)
  691. BdCheck_End:
  692. cEnd
  693. CheckOmErr:
  694. xor ax,ax
  695. jmp short BdCheck_End
  696. ;***
  697. ; boolean BdShiftRight(pbd, obStart, cb)
  698. ;
  699. ; Purpose:
  700. ; Grow the buffer descriptor, and shift its contents right
  701. ; (copying content to higher addresses) starting at offset
  702. ; obStart until the end of the buffer.
  703. ;
  704. ; NOTE: current heap manager interface demands that the owner
  705. ; should not be subject to heap movement. 
  706. ;
  707. ; Entry:
  708. ; parmW pbd points to the buffer descriptor
  709. ; parmW obStart = byte offset for 1st byte to be shifted right
  710. ; parmW cb = number of bytes each byte is to be shifted
  711. ;
  712. ; Exit:
  713. ; If not enough memory can be obtained,
  714. ; [AX] = FALSE
  715. ; else
  716. ; pbdDst->cbLogical is updated
  717. ; [AX] = TRUE
  718. ;
  719. ;   Before BdShiftRight(pbd, 2, 2):
  720. ; high memory 
  721. ;   pbd->cbLogical------->+-----+
  722. ; |  E  |
  723. ; |  D  |
  724. ; |  C  |
  725. ; |  B  |
  726. ; |  A  |
  727. ; low memory +-----+
  728. ;
  729. ;   After:
  730. ; high memory 
  731. ;   pbd->cbLogical------->+-----+
  732. ; |  E  |
  733. ; |  D  |
  734. ; |  C  |
  735. ; |  D  |
  736. ; |  C  |
  737. ; |  B  |
  738. ; |  A  |
  739. ; low memory +-----+
  740. ;
  741. ;***************************************************************************
  742. cProc BdShiftRight,<PUBLIC,FAR,NODATA>,<SI,DI>
  743. parmW pbd
  744. parmW obStart
  745. parmW cb
  746. cBegin
  747. push pbd
  748. push cb
  749. call BdCheckFree ;1st grow the buffer
  750. or ax,ax
  751. je BdShiftExit ;branch if out-of-memory, return 0
  752. mov bx,pbd ;bx -> descriptor
  753. mov cx,[bx.BD_cbLogical] ;[CX] = current size of buffer
  754. mov si,[bx.BD_pb] ;si points to start of buffer
  755. add si,cx ;si points beyond end of current content
  756. dec si ;si points to 1st byte to copy
  757. mov di,si
  758. mov ax,cb
  759. add di,ax ;di points to dst for 1st byte to copy
  760. add [bx.BD_cbLogical],ax ;update size of buffer
  761. sub cx,obStart ;[CX] = number of bytes to copy
  762. jcxz Copy0Bytes
  763. push ds
  764. pop es ;es=ds
  765. std ;copy from high to low address
  766. rep movsb ;do the block copy
  767. cld
  768. Copy0Bytes:
  769. mov ax,TRUE
  770. BdShiftExit:
  771. cEnd
  772. ;***
  773. ; boolean BdShiftLeft(pbd, obStart, cb)
  774. ;
  775. ; Purpose:
  776. ; Shrink the buffer descriptor, and shift its contents left
  777. ; (copying content to lower addresses) starting at offset
  778. ; obStart until the end of the buffer.
  779. ;
  780. ; Entry:
  781. ; parmW pbd points to the buffer descriptor
  782. ; parmW obStart = byte offset for 1st byte to be deleted
  783. ; parmW cb = number of bytes to be deleted
  784. ;
  785. ; Exit:
  786. ; pbdDst->cbLogical is updated
  787. ; no return value
  788. ;
  789. ;   Before BdShiftLeft(pbd, 2, 2):
  790. ; high memory 
  791. ;   pbd->cbLogical------->+-----+
  792. ; |  E  |
  793. ; |  D  |
  794. ; |  C  |
  795. ; |  B  |
  796. ; |  A  |
  797. ; low memory +-----+
  798. ;
  799. ;   After:
  800. ; high memory 
  801. ;   pbd->cbLogical------->+-----+
  802. ; |  E  |
  803. ; |  B  |
  804. ; |  A  |
  805. ; low memory +-----+
  806. ;
  807. ;***************************************************************************
  808. cProc BdShiftLeft,<PUBLIC,FAR,NODATA>,<SI,DI>
  809. parmW pbd
  810. parmW obStart
  811. parmW cb
  812. cBegin
  813. mov bx,pbd ;bx -> descriptor
  814. mov di,[bx.BD_pb] ;di points to start of buffer
  815. add di,obStart ;di points to 1st byte to delete
  816. mov si,di
  817. add si,cb ;si points beyond last byte to delete
  818. mov cx,[bx.BD_cbLogical] ;[CX] = current size of buffer
  819. sub cx,cb ;cx = new size of buffer
  820. mov [bx.BD_cbLogical],cx ;update descriptor
  821. sub cx,obStart ;cx = # bytes to copy
  822. jcxz LeftExit ;brif 0 bytes to copy
  823. push ds
  824. pop es ;es=ds
  825. rep movsb ;do the block copy
  826. LeftExit:
  827. cEnd
  828. ;***
  829. ; boolean BdAppend(pbdDst, pbSrc, cb)
  830. ;
  831. ; Purpose:
  832. ; Append a string of bytes to a Buffer Descriptor.
  833. ; If this is preceeded by a call to BdCheckFree(pbdDst, cb)
  834. ; then pbSrc can point within another heap entry with no
  835. ; fear of movement before the copy is complete.  Otherwise,
  836. ; pbSrc had better not point within a heap entry.
  837. ;
  838. ; NOTE: current heap manager interface demands that the owner
  839. ; should not be subject to heap movement. 
  840. ;
  841. ; Entry:
  842. ; parmW pbdDst points to the destination buffer descriptor
  843. ; parmW pbSrc points to 1st byte to be copied into buffer
  844. ; parmW cb = number of bytes to be copied
  845. ;
  846. ; Exit:
  847. ; If not enough memory can be obtained,
  848. ; [AX] = FALSE
  849. ; else
  850. ; pbdDst->cbLogical is updated
  851. ; [AX] = TRUE
  852. ;
  853. ;***************************************************************************
  854. cProc BdAppend,<PUBLIC,FAR,NODATA>,<SI,DI>
  855. parmW pbdDst
  856. parmW pbSrc
  857. parmW cb
  858. localW pbDst
  859. localW cbTemp
  860. cBegin
  861. push pbdDst
  862. push cb
  863. call BdCheckFree
  864. or ax,ax
  865. je BdAppendExit ;branch if out-of-memory, return 0
  866. mov cx,cb ;[CX] = # bytes to copy
  867. mov di,pbdDst ;di -> destination descriptor
  868. mov ax,[di.BD_cbLogical] ;ax = current size of buffer
  869. add [di.BD_cbLogical],cx ;update size of buffer
  870. mov di,[di.BD_pb] ;di points to start of dest buffer
  871. add di,ax ;add new bytes at end of buffer
  872. mov si,pbSrc ;si = source byte ptr
  873. push ds
  874. pop es ;es=ds
  875. rep movsb ;do the block copy
  876. mov ax,TRUE
  877. BdAppendExit:
  878. cEnd
  879. ;-----------------------------------------------------------------
  880. ;---   Large Far Heap Buffer Descriptor Management Routines    ---
  881. ;-----------------------------------------------------------------
  882. FAR_EXTRA = 512 ;never grow a far heap entry by less than 512 bytes
  883. ;***
  884. ;AllocBdl - Allocate a Far Heap entry (workhorse for BdlAlloc)
  885. ;AllocBdl_Sb - same, but allocates a given sb for this
  886. ;Purpose:
  887. ; Allocate a Heap entry from the Far Heap.  This can cause
  888. ; movement of Runtime and String heap entries.
  889. ; Note that this routine should ask for only the amount of space asked
  890. ; for; growing a buffer will increase requests to some minimal block size,
  891. ; but many buffers need to be initially allocated to some minimal 
  892. ; (possibly zero) size.
  893. ;Entry:
  894. ; di = pbdlOwner - points to owner of new heap entry
  895. ; si = cbSize - number of bytes needed
  896. ; For EB versions, bx = type constant for type of bdl buffer
  897. ; For AllocBdl_Sb, cx = sb to use
  898. ;Exit:
  899. ; if entry was successfully allocated:
  900. ;    pbdlOwner->cbLogical = cbSize
  901. ;    pbdlOwner->cbPhysical = cbSize
  902. ;    [AX] = TRUE (non-zero)
  903. ;    pbdlOwner->status != NOT_OWNER
  904. ; else
  905. ;    [AX] = FALSE (0) (Out of memory)
  906. ; PSW.Z is set on exit based on an 'OR AX,AX' instruction
  907. ;
  908. ;***************************************************************************
  909. cProc AllocBdl,<NEAR,NODATA>
  910. cBegin <nogen>
  911. mov cx,0 ; use any sb that's free
  912. cEnd <nogen>
  913. cProc AllocBdl_Sb,<NEAR,NODATA>
  914. cBegin
  915. mov ax,si
  916. DbAssertRel ax,be,0FFF0H,RT,<BdlAlloc: caller asked for more than FFF0H>
  917. ;The above assertion is based on the problem where a request to
  918. ;   B$IFHAlloc for greater than 0FFF0H bytes will be rounded UP to past
  919. ;   64k, with no error reported.
  920. xor dx,dx ;DX:AX is input size to B$IFHAlloc
  921. mov bx,di
  922. DbChk BdlNotOwner,di
  923. mov [bx.BDL_cbLogical],ax
  924. call B$IFHAlloc ;allocate a far heap entry (0 if can't)
  925. or ax,ax ;set zero flag for caller
  926. cEnd AllocBdl
  927. ;***
  928. ;BdlAlloc - Allocate a Far Heap entry
  929. ;Purpose:
  930. ; Allocate a Heap entry from the Far Heap.  This can cause
  931. ; movement of Runtime and String heap entries.
  932. ; Note that this routine should ask for only the amount of space asked
  933. ; for; growing a buffer will increase requests to some minimal block size,
  934. ; but many buffers need to be initially allocated to some minimal 
  935. ; (possibly zero) size.
  936. ;
  937. ; [5] Note that at least some callers depend on the new block being zero-
  938. ; [5] filled (EB varmgr code, for one).
  939. ;Entry:
  940. ; parm: bdl *pbdlOwner - points to owner of new heap entry
  941. ; parm: ushort cbSize - number of bytes needed
  942. ;Exit:
  943. ; if entry was successfully allocated:
  944. ;    pbdlOwner->cbLogical = cbSize
  945. ;    pbdlOwner->cbPhysical = cbSize
  946. ;    [AX] = TRUE (non-zero)
  947. ;    pbdlOwner->status != NOT_OWNER
  948. ; else
  949. ;    [AX] = FALSE (0) (Out of memory)
  950. ;
  951. ;***************************************************************************
  952. cProc BdlAlloc,<PUBLIC,FAR,NODATA>,<si,di>
  953. parmW pbdlOwner
  954. parmW cbSize
  955. cBegin
  956. DbOMCnt BdlAlloc_Exit
  957. mov di,[pbdlOwner]
  958. mov si,[cbSize]
  959. cCall AllocBdl
  960. jnz BdlAlloc_Exit ;brif success
  961. call far ptr BdCompressAll ;trim bd's, compress heap space
  962. cCall AllocBdl
  963. BdlAlloc_Exit:
  964. cEnd
  965. ;***
  966. ;BdlAllocSb - Allocate a Far Heap entry, given a desired sb
  967. ;Purpose:
  968. ; Same as BdlAlloc, but accepts as a third parm the sb value that
  969. ; is to be used.
  970. ; Added as revision [13].
  971. ;Entry:
  972. ; parm: bdl *pbdlOwner - points to owner of new heap entry
  973. ; parm: ushort cbSize - number of bytes needed
  974. ; parm: ushort sbInput - sb we must use for this allocation
  975. ; (caller guarantees this is unallocated).
  976. ;Exit:
  977. ; if entry was successfully allocated:
  978. ;    pbdlOwner->cbLogical = cbSize
  979. ;    pbdlOwner->cbPhysical = cbSize
  980. ;    [AX] = TRUE (non-zero)
  981. ;    pbdlOwner->status != NOT_OWNER
  982. ; else
  983. ;    [AX] = FALSE (0) (Out of memory)
  984. ;
  985. ;***************************************************************************
  986. cProc BdlAllocSb,<PUBLIC,FAR,NODATA>,<si,di>
  987. parmW pbdlOwner
  988. parmW cbSize
  989. parmW sbInput
  990. cBegin
  991. DbOMCnt BdlAllocSb_Exit
  992. mov di,[pbdlOwner]
  993. mov si,[cbSize]
  994. mov cx,[sbInput]
  995. cCall AllocBdl_Sb
  996. BdlAllocSb_Exit:
  997. cEnd
  998. ;***
  999. ;BdlFree - Release a far Heap entry
  1000. ;Purpose:
  1001. ; Release a far Heap entry. If bdl is not an owner, this routine just
  1002. ; returns, with no error.
  1003. ;Entry:
  1004. ; parm: bdl *pbdlOwner - points to owner of new heap entry
  1005. ;Exit:
  1006. ; bdl is released; pbdlOwner->status = NOT_OWNER
  1007. ;
  1008. ;***************************************************************************
  1009. cProc BdlFree,<PUBLIC,FAR,NODATA>
  1010. parmW pbdlOwner
  1011. cBegin
  1012. mov bx,[pbdlOwner]
  1013. cmp [bx.BDL_status],NOT_OWNER
  1014. jz BdlFree_Exit ;brif bdl already free
  1015. DbChk BdlOwner,bx ;ensure that given bdl is an owner
  1016. push bx
  1017. call B$FHDealloc ;free an allocated far heap entry
  1018. pop bx
  1019. mov [bx.BDL_status],NOT_OWNER ;indicate that bdl is not an owner
  1020. BdlFree_Exit:
  1021. cEnd
  1022. ;***
  1023. ;BdlChgOwner(pbdlOwner, pbdlNew) - Change the owner of a Far Heap entry
  1024. ;Purpose:
  1025. ; Change the owner of a Far Heap entry. If pbdlOwner.BDL_status is 
  1026. ; NOT_OWNER, just return (as it wasn't really an owner to begin with).
  1027. ;
  1028. ; NOTE: This routine is guaranteed not to cause heap movement to occur.
  1029. ;
  1030. ; NOTE: This routine must be called AFTER a block containing the bdl is
  1031. ; copied, as the far heap manager modifies the FHD according to
  1032. ; its original location. This copy MUST be done by the caller
  1033. ; prior to this routine being called.
  1034. ; Note also that it is NOT safe to block copy a range containing
  1035. ; multiple bdl's and then call this routine once per bdl - - -
  1036. ; Since the far heap code chains all bdl's together, a call to
  1037. ; BdlChgOwner can cause another bdl to be modified (in the 
  1038. ; 'status' a.k.a. 'pNext' field).
  1039. ;Entry:
  1040. ; parm: bdl *pbdlOwner - points to current owner of far heap entry
  1041. ; parm: bdl *pbdlNew -   points to new owner of far heap entry
  1042. ;Exit:
  1043. ; none.
  1044. ;
  1045. ;***************************************************************************
  1046. cProc BdlChgOwner,<PUBLIC,FAR,NODATA>,<SI>
  1047. parmW pbdlOwner
  1048. parmW pbdlNew
  1049. cBegin
  1050. mov si,[pbdlOwner]
  1051. cmp [si.BDL_status],NOT_OWNER
  1052. jz BdlChg_Exit ;brif bdl wasn't an owner
  1053. DbChk BdlOwner,si ;ensure that bdlOwner is an owner
  1054. mov dx,si ;pFHD for FHD that's being moved
  1055. mov cx,[pbdlNew]
  1056. sub cx,si ;cx = pNew - pOld (adjustment factor)
  1057. call B$FHAdjOneDesc
  1058. mov [si.BDL_status],NOT_OWNER
  1059. BdlChg_Exit:
  1060. cEnd
  1061. ;***
  1062. ;BdlRealloc - reallocate a Far Heap entry
  1063. ;Purpose:
  1064. ; reallocate a Heap entry from the Far Heap.  This can cause
  1065. ; movement of String and Runtime heap entries.
  1066. ;
  1067. ; [5] Note that at least some callers depend on additional space being
  1068. ; [5] zero-filled (EB varmgr code, for one).
  1069. ;Entry:
  1070. ; parm: bdl *pbdlOwner - points to owner of heap entry
  1071. ; parm: ushort cbNew - new buffer size desired
  1072. ;Exit:
  1073. ; if entry was successfully reallocated:
  1074. ;    pbdlOwner->cbLogical = cbNew
  1075. ;    pbdlOwner->cbPhysical >= cbNew
  1076. ;    [AX] = TRUE (non-zero)
  1077. ; else
  1078. ;    [AX] = FALSE (0) (Out of memory)
  1079. ;
  1080. ;***************************************************************************
  1081. cProc BdlRealloc,<PUBLIC,FAR,NODATA>,<di>
  1082. parmW pbdlOwner
  1083. parmW cbNew
  1084. localB fTryAgain
  1085. cBegin
  1086. mov [fTryAgain],TRUE
  1087. DbOMCnt BdlRealloc_Exit
  1088. mov di,[pbdlOwner]
  1089. mov bx,[di.BDL_cPhysical]
  1090. SHIFT H,L,bx,4 ;shift left to convert cPara to cbytes
  1091. mov ax,[cbNew]
  1092. cmp bx,ax
  1093. jae Change_cbLogical ;brif physical size is big enough
  1094. cmp ax,0FFE0H ;if ask far heap for > FFE0H, it will
  1095. ;  round request up to para boundary ...
  1096. jbe BdlRealloc_Cont ;brif request not too large
  1097. xor ax,ax ;Out of Memory return
  1098. jmp short BdlRealloc_Exit
  1099. BdlRealloc_Crunch:
  1100. cmp [fTryAgain],FALSE
  1101. jz BdlRealloc_Exit ;brif we've already tried this - give up
  1102. mov [fTryAgain],FALSE ;remember this is the 2nd attempt
  1103. call far ptr BdCompressAll ;trim all bd's, compress heaps,
  1104. mov ax,[cbNew] ;and try again w/o blocking factor
  1105. jmp short BdlRealloc_Cont1
  1106. BdlRealloc_Cont:
  1107. add ax,FAR_EXTRA ;ax = ax + FAR_EXTRA to reduce thrashing
  1108. ;Under DOS 3, we know the heap manager actually allocates in 16-byte
  1109. ;  (paragraph) quantities, so to ensure we don't waste an average of
  1110. ;  8 bytes per bdl, pay a few bytes of code here to round up
  1111. jc RealcForMax ;brif this puts us over 64k
  1112. BdlRealloc_Cont1:
  1113. add ax,000FH ;constant for rounding up to paragraph
  1114. jnc TryToRealloc ;brif still under 64k
  1115. RealcForMax:
  1116. mov ax,0FFE0H ; try for maximum - - - note that
  1117. ;'maximum' can't be FFFFH, because
  1118. ;the far heap code will round this
  1119. ;up to the nearest paragraph boundary
  1120. TryToRealloc:
  1121. and al,0F0H  ;[9] finish rounding size up to para
  1122. mov dx,0FFE0H
  1123. cmp ax,dx ; is result > legal max?
  1124. jbe ReallocAttempt ; brif not
  1125. xchg ax,dx
  1126. ReallocAttempt:
  1127. DbChk BdlOwner,di ;ensure that bdlOwner is an owner
  1128. xor dx,dx
  1129. mov bx,di
  1130. call B$FHRealloc
  1131. or ax,ax
  1132. jz BdlRealloc_Crunch ;brif insufficient memory
  1133. mov ax,[cbNew] ;requested size
  1134. Change_cbLogical:
  1135. mov [di.BDL_cbLogical],ax ;save new logical size
  1136. mov ax,sp ;signal success (cbNew could be zero ..)
  1137. BdlRealloc_Exit:
  1138. cEnd
  1139. ;***
  1140. ;BdlCheckFree - Make sure far heap entry has some free space
  1141. ;Purpose:
  1142. ; Change size of a far Heap entry if necessary to
  1143. ; ensure that there is a certain number of free bytes at the
  1144. ; end of the entry.  This can result in the movement of this
  1145. ; and other heap entries.
  1146. ; This routine does not work with HUGE heap entries (i.e. > 64k)
  1147. ;Entry:
  1148. ; parm: bdl *pbdlOwner - points to owner of heap entry
  1149. ; parm: ushort cbFree - number of free bytes needed
  1150. ;Exit:
  1151. ; If enough memory is available:
  1152. ;    pbdlOwner->cbLogical is unchanged
  1153. ;    pbdlOwner->cbPhysical >= pbdlOwner->cbLogical + cbFree
  1154. ;    [AX] = TRUE (non-zero) (successful return)
  1155. ; else
  1156. ;    [AX] = FALSE (0) (Out of memory)
  1157. ;
  1158. ;***************************************************************************
  1159. cProc BdlCheckFree,<PUBLIC,FAR,NODATA>,<di>
  1160. parmW pbdlOwner
  1161. parmW cbFree
  1162. cBegin
  1163. DbOMCnt BdlCheckFreeExit
  1164. mov di,[pbdlOwner]
  1165. mov ax,[di.BDL_cPhysical] ;ax = current physical size
  1166. SHIFT H,L,ax,4 ;shift left to convert cPara to cbytes
  1167. push ax
  1168. sub ax,[di.BDL_cbLogical] ;ax = current free size
  1169. sub ax,cbFree ;ax = new free size
  1170. jnc SizeIsOk ;brif we're already big enough
  1171. neg ax
  1172. pop bx
  1173. add ax,bx ;ax = minimum new free size
  1174. jc BdlCheckDenied ;error if attempting to grow > 64k
  1175. push [di.BDL_cbLogical] ;save this across call to BdlRealloc
  1176. cCall BdlRealloc,<di,ax>
  1177. pop [di.BDL_cbLogical]
  1178. BdlCheckFreeExit:
  1179. cEnd
  1180. BdlCheckDenied:
  1181. xor ax,ax ;return ERROR result (zero)
  1182. SKIP1_PSW ;this 'eats' the next instruction
  1183. SizeIsOk:
  1184. pop ax ;cPhysical known to be non-zero
  1185. jmp short BdlCheckFreeExit
  1186. ;***
  1187. ;BdlGrow - Increase the logical size of a Heap entry
  1188. ;Purpose:
  1189. ; Change logical size of a bdl.  This can result in the movement of this
  1190. ; and other heap entries.
  1191. ; When this routine actually needs to grow the physical size
  1192. ; of the bdl, it grows more than needed for this request, to
  1193. ; reduce heap thrashing.
  1194. ;
  1195. ; Added as part of revision [9].
  1196. ;Entry:
  1197. ; parm: bd *pbdlOwner
  1198. ; parm: ushort cbGrow - number of additional bytes needed
  1199. ;Exit:
  1200. ; if enough memory is available:
  1201. ;    pbdlOwner->cbLogical += cbGrow,
  1202. ;    pbdlOwner->cPhysical increased to account for >= cbLogical bytes
  1203. ;    [AX] = TRUE (non-zero)
  1204. ; else
  1205. ;    [AX] = FALSE (0) (Out of memory)
  1206. ;
  1207. ;***************************************************************************
  1208. cProc BdlGrow,<PUBLIC,FAR>
  1209. parmW pbdlOwner
  1210. parmW cbGrow
  1211. cBegin
  1212. mov bx,[pbdlOwner]
  1213. mov ax,[cbGrow]
  1214. add ax,[bx.BDL_cbLogical]
  1215. cCall BdlRealloc,<bx,ax>
  1216. cEnd
  1217. ;***
  1218. ;BdlCopyFrom - Copy data from a far Heap entry to DS
  1219. ;Purpose:
  1220. ; Copy data from a far Heap entry to DS
  1221. ; Does not work with HUGE heap entries (i.e. > 64k)
  1222. ;Entry:
  1223. ; parm: bdl *pbdlOwner - points to owner of new heap entry
  1224. ; parm: ushort oSrc - 16 bit offset into bdl to source
  1225. ; parm: char *pbDst - points to 1st byte of destination
  1226. ; parm: ushort cb - number of bytes to copy
  1227. ;
  1228. ;***************************************************************************
  1229. cProc BdlCopyFrom,<PUBLIC,FAR,NODATA>,<si,di>
  1230. parmW pbdlOwner
  1231. parmW oSrc
  1232. parmW pbDst
  1233. parmW cb
  1234. cBegin
  1235. mov si,[oSrc] ;si = source offset
  1236. mov di,[pbDst] ;di = destination offset
  1237. mov bx,[pbdlOwner]
  1238. DbChk BdlOwner,bx ;ensure that bdlOwner is an owner
  1239. GETSEG ax,[bx.BDL_seg],,<SIZE,LOAD> ;[4] seg of far heap entry
  1240. mov bx,ds ;bx -> DGROUP
  1241. mov ds,ax ;set up source seg (heap entry)
  1242. mov es,bx ;set up destination seg (DGROUP)
  1243. CopyCommon:
  1244. mov cx,cb ;cx = byte count
  1245. shr cx,1 ;convert to word count
  1246. rep movsw ;transfer from ds:si to es:di
  1247. jnc CopyFrom_Even ;no carry if count was even
  1248. movsb ;move the last (odd) byte
  1249. CopyFrom_Even:
  1250. mov ds,bx ;restore ds->DGROUP
  1251. cEnd
  1252. ;***
  1253. ;BdlCopyTo - Copy data from DS into a far Heap entry
  1254. ;Purpose:
  1255. ; Copy data from DS into a far Heap entry
  1256. ; Does not work with HUGE heap entries (i.e. > 64k)
  1257. ;Entry:
  1258. ; parm: bdl *pbdlOwner - points to owner of new heap entry
  1259. ; parm: ushort oDst - 16 bit offset into bdl to destination
  1260. ; parm: char *pbSrc - points to 1st byte of source
  1261. ; parm: ushort cb - number of bytes to copy
  1262. ;
  1263. ;***************************************************************************
  1264. cProc BdlCopyTo,<PUBLIC,FAR,NODATA>,<si,di>
  1265. parmW pbdlOwner
  1266. parmW oDst
  1267. parmW pbSrc
  1268. parmW cb
  1269. cBegin
  1270. mov si,[pbSrc] ;si = source offset
  1271. mov di,[oDst] ;di = destination offset
  1272. mov bx,[pbdlOwner]
  1273. DbChk BdlOwner,bx ;ensure that bdlOwner is an owner
  1274. GETSEG ax,[bx.BDL_seg],,<SIZE,LOAD> ;[4] seg of far heap entry
  1275. mov es,ax ;set up destination seg
  1276. mov bx,ds
  1277. jmp short CopyCommon
  1278. cEnd nogen
  1279. ;***
  1280. ;BdlCopyFromTo - Copy data from one bdl to another
  1281. ;Purpose:
  1282. ; Copy data from one far heap entry into another.
  1283. ; Does not work with HUGE heap entries (i.e. > 64k)
  1284. ;
  1285. ; Added as part of revison [7]
  1286. ;Entry:
  1287. ; parm: bdl *pbdlSrc - points to source bdl
  1288. ; parm: ushort oSrc - 16 bit offset into bdl to source
  1289. ; parm: bdl *pbdlDst - points to destination bdl
  1290. ; parm: ushort oDst - 16 bit offset into bdl to destination
  1291. ; parm: ushort cb - number of bytes to copy
  1292. ;Exit:
  1293. ; none.
  1294. ;***************************************************************************
  1295. cProc BdlCopyFromTo,<PUBLIC,FAR,NODATA>,<si,di,ds>
  1296. parmW pbdlSrc
  1297. parmW oSrc
  1298. parmW pbdlDst
  1299. parmW oDst
  1300. parmW cb
  1301. cBegin
  1302. mov si,[pbdlDst]
  1303. DbChk BdlOwner,si ;ensure that bdlDst is an owner
  1304. GETSEG dx,[si.BDL_seg],,<SIZE,LOAD>  
  1305. ; dx = seg of far heap entry (dst)
  1306. mov bx,[pbdlSrc]
  1307. DbChk BdlOwner,bx ;ensure that bdlSrc is an owner
  1308. GETSEG ds,[bx.BDL_seg],,<SIZE,LOAD,NOFLUSH>
  1309. ; ds = seg of far heap entry (src)
  1310. assumes DS,NOTHING
  1311. mov es,dx
  1312. mov si,[oSrc] ;si = source offset
  1313. mov di,[oDst] ;di = destination offset
  1314. mov cx,[cb]
  1315. shr cx,1 ;convert to word count
  1316. rep movsw ;transfer from ds:si to es:di
  1317. jnc CopyFrom_Even2 ;no carry if count was even
  1318. movsb ;move the last (odd) byte
  1319. CopyFrom_Even2:
  1320. cEnd
  1321. assumes DS,DATA
  1322. ;***
  1323. ;BdlTrim - trim given bdl down to cbLogical
  1324. ;Purpose:
  1325. ; Releases excess space in a given bdl
  1326. ;Entry:
  1327. ; parm: bdl *pbdl
  1328. ;
  1329. ;***************************************************************************
  1330. cProc BdlTrim,<PUBLIC,FAR,NODATA>,<si,di>
  1331. parmW pbdl
  1332. cBegin
  1333. mov bx,[pbdl]
  1334. DbChk BdlOwner,bx ;ensure that bdlOwner is an owner
  1335. mov ax,[bx.BDL_cbLogical] ;size to realloc to
  1336. xor dx,dx
  1337. call B$FHRealloc ;must succeed; we're either reducing
  1338. ;  or asking for existing entry size
  1339. cEnd
  1340. ;seg_rt = segment address for the RT segment
  1341. ;It can be referenced from any module as follows:
  1342. ; EXTRN seg_rt:abs
  1343. ; mov ax,SEG seg_rt
  1344. PUBLIC seg_rt
  1345. seg_rt EQU SEG BdlTrim
  1346. sEnd RT
  1347. ;------------------------------------------------------------
  1348. ;---  Interpreter Buffer Descriptor Management Routines   ---
  1349. ;------------------------------------------------------------
  1350. sBegin DATA
  1351. staticB bdGrabSpace,NULL,<SIZE BD>
  1352. sEnd DATA
  1353. sBegin  CODE
  1354. assumes CS,CODE
  1355. CBNEAR_GRAB equ 2 * CBBUFBLOCK
  1356. ;***
  1357. ;GrabSpace - grab some heap space
  1358. ;Purpose:
  1359. ; Allocates CBNEAR_GRAB bytes via BdAlloc. 
  1360. ; Called to lock up a chunk of heap space so we ensure that
  1361. ; enough space exists to do simple things like CLEAR for more memory!
  1362. ;
  1363. ; NOTE: It's important that grabspace just grab space from the near
  1364. ; heap, not the far heap; if we grabbed far space instead,
  1365. ; this could allow the user to tie up all of DGROUP with
  1366. ; variable tables with plenty of DGROUP space free.
  1367. ;Entry:
  1368. ; none.
  1369. ;Exit:
  1370. ; ax = 0 if insufficient memory, else ax != 0
  1371. ;***************************************************************************
  1372. cProc GrabSpace,<PUBLIC,FAR,NODATA>
  1373. cBegin
  1374. mov ax,[bdGrabSpace.BD_pb]
  1375. or ax,ax
  1376. jnz GotSpace ;return ax<>0 if already have space
  1377. PUSHI ax,<dataOFFSET bdGrabSpace>
  1378. PUSHI ax,CBNEAR_GRAB
  1379. PUSHI ax,IT_NO_OWNERS
  1380. call BdAlloc
  1381. or ax,ax
  1382. GotSpace:
  1383. cEnd
  1384. ;***
  1385. ;ReleaseSpace - Release the space grabbed by GrabSpace
  1386. ;Purpose:
  1387. ; Deallocates the bd allocated by GrabSpace if it is currently allocated.
  1388. ; Note that it's perfectly o.k. to call this even when no space has
  1389. ; been grabbed.
  1390. ;Entry:
  1391. ; none.
  1392. ;Exit:
  1393. ; ax = 0.
  1394. ;***************************************************************************
  1395. cProc ReleaseSpace,<PUBLIC,FAR,NODATA>
  1396. cBegin
  1397. PUSHI ax,<dataOFFSET bdGrabSpace>
  1398. call BdFree ;deallocate bd if couldn't allocate bdl
  1399. cEnd
  1400. sEnd CODE
  1401. end