📄 nhlhcore.asm
字号:
JNZ ADJLHP_ALL_FLDS ;if adjustment, then adust fielded strings
MOV [SI].LHTYPE,LOW LH_FREE ;mark the deallocated block free
CALL B$LHDALCALLFLD ; otherwise deallocate all fielded strings
JMP SHORT ADJLHP_QUIT ;jump to return to caller
; Entry contains fielded strings - adjust pointers into field buffer
ADJLHP_ALL_FLDS:
MOV CX,[SI].LHPLEN ;get size of string entry for fielded strs
SHR CX,1 ;compute number of fielded strings
PUSH SI ;preserve heap pointer
ADJ_FLD_LOOP:
MOV SI,[BX] ;get pointer to field variable
ADD [SI+2],AX ;adjust pointer into field buffer
INC BX ;move to next field variable
INC BX
LOOP ADJ_FLD_LOOP ;loop until all ptrs to field buffer have
;been adjusted
POP SI ;recover heap pointer
ADJLHP_EXIT:
JMP SHORT ADJLHP_QUIT ;jump to return to caller
; If entry is not ARRAY, then return.
ADJLHP_NOT_FILE:
CMP [SI].LHTYPE,LOW LH_ARRAY ;test if entry is ARRAY
JNE ADJLHP_INTERP ;if not, consider interp. entries (if any)
; Entry is ARRAY, first clear/adjust the array descriptor pointer.
MOV BX,[SI].LHBAKP ;get offset of array descriptor
OR AX,AX ;test if array is being deallocated
JNZ ADJLHP_ADJUST ;if just being adjusted, then jump
MOV [BX].AD_fhd.FHD_hData,AX ;deallocated - clear the descriptor
MOV [SI].LHBAKP,AX ;also clear the heap backpointer
MOV [SI].LHTYPE,LOW LH_FREE ;mark the deallocated block free
ADJLHP_ADJUST:
; Next, get pointer to start of array data and deallocate/adjust
; the backpointers of all nonnull strings in the array.
MOV CX,[SI].LHLEN ;get length of heap entry (hdr+data+backlen)
MOV BX,SI ;get copy of heap entry pointer
SUB BX,CX ;point to next heap entry
ADD BX,3 ;move past backlength to array start
SUB CX,LH_STD_HDR_LEN+2 ;data length less header and backlength
SHR CX,1 ;data length in words...
SHR CX,1 ;length in doublewords (number of descs)
; For each nonnull descriptor, deallocate/adjust the string data.
; Process null strings through B$STADJ, fielded ones must be adjusted.
ADJLHP_LOOP:
; CMP WORD PTR [BX],0 ;test if string is nonnull
; JZ ADJLHP_NEXT ;if so, then skip this entry
CALL B$STADJ ;deallocate/adjust the string at desc [BX]
ADJLHP_NEXT:
ADD BX,4 ;point to next descriptor
LOOP ADJLHP_LOOP ;loop to process the next one
ADJLHP_INTERP:
OR AX,AX
JZ ADJLHP_QUIT ;brif deallocation - the below is for adjustment
CALL B$LH_I_ADJ ;[ln] adjust backptrs to any owners in this entry
ADJLHP_DONE:
;NOTE: important to update the owner LAST, after interpreter call
; back work is done.
MOV BX,[SI].LHBAKP ;get pointer to owner
ADD [BX],AX ;add adjustment to owner pointer
CMP [SI].LHTYPE,LOW LH_ARRAY; test if entry is ARRAY
JNE ADJLHP_QUIT ; jump if not
ADD [BX].AD_oAdjusted,AX ; else update adjusted pointer
ADJLHP_QUIT:
POP CX ;restore registers...
POP BX
RET ;return to caller
B$LHADJ ENDP
assumes DS,DGROUP
assumes ES,NOTHING
;***
; B$LHDALCALLFLD - deallocate all fielded strings for heap entry
; Purpose:
; To deallocate all fielded strings associated with the heap
; entry pointed by SI. The heap backpointer string is also
; deallocated.
;
; Inputs:
; SI = pointer to heap entry
; Outputs:
; None.
; Modifies:
; None.
; Exceptions:
; None.
;****
B$LHDALCALLFLD:
ASSERT_NOT_VARHEAP NH_TEXT
PUSH AX ;save registers...
PUSH BX
PUSH CX
PUSH DI
XOR AX,AX ;clear AX to zero
MOV BX,AX ;same for BX...
MOV CX,AX ;and CX
XCHG CX,[SI].LHPLEN ;swap bkptr str len and 0
XCHG BX,[SI].LHPOFF ;swap bkptr str off and 0
INC CX ;add one for backpointer value
MOV [BX-2],CX ;free string by setting backpointer value
SHR CX,1 ;number of words to process
DALCALLFLD_LOOP:
MOV DI,[BX] ;get next word from string
MOV [DI],AX ;clear descr length
MOV [DI+2],AX ;clear descr offset
ADD BX,2 ;point to next descriptor in string
LOOP DALCALLFLD_LOOP ;if not done, then loop
POP DI ;restore registers...
POP CX
POP BX
POP AX
RET ;return to caller
;***
; B$LHFLDDESCADJ - delete/adjust descriptor in field backpointer string.
; Purpose:
; Search through the local heap FILE entries for the descriptor
; address specified in BX. If AX=0, then remove it from the
; field backpointer string. If AX<>0, then just adjust the
; backpointer string element by adding AX to it.
;
; Inputs:
; AX = adjustment factor
; AX=0 - delete descriptor BX from backpointer string.
; AX<>0 - adjust descriptor BX in backpointer string by AX.
; BX = address of descriptor to be deleted/adjusted.
; DS = segment that heap is in
; ES = segment that state vars are in
; Outputs:
; None.
; Modifies:
; SI.
; Exceptions:
; B$ERR_SSC if descriptor offset not found.
;****
B$LHFLDDESCADJ:
assumes ES,DGROUP
assumes DS,NOTHING
ASSERT_NOT_VARHEAP NH_TEXT
PUSH AX ;save registers...
PUSH BX
PUSH CX
PUSH DX
PUSH DI
XCHG DX,AX ; [DX] = adjustment factor
XCHG AX,BX ; [AX] = object of searches
XOR BX,BX ;start at beginning of heap
FLDDESCADJ_NEXT:
MOV SI,BX ;put current FDB point in for test
CALL NXTFIL_ES ;get next FILE data pointer in SI
JZ FLDDESCADJ_ERROR ;if no more entries, then done
MOV BX,SI ;save current FDB point for next time
CALL B$LH_PTR_FROM_DATA ;get heap entry pointer in SI
; Heap entry is for a file. Determine if a backpointer string
; is defined. If so, then scan string for descriptor value in AX.
MOV CX,[SI].LHPLEN ;get length of string
JCXZ FLDDESCADJ_NEXT ;if null string, then try next entry
SHR CX,1 ;make it in words
MOV DI,[SI].LHPOFF ;get offset of the string
PUSH ES ;make sure that we use the proper
PUSH DS ;segment in case that
POP ES ;we are in the middle of unwinding a CHAIN
REPNE SCASW ;scan for word in AX
POP ES ;recover correct ES = BASIC DS
JNZ FLDDESCADJ_NEXT ;if not there, try next
; Word found in string. DI is pointing just after the word
; while CX contains the number of words in the string AFTER
; the one searched. If modifying (DX<>0), just add the adjustment
; factor to the word.
ADD [DI-2],DX ;assume adjustment is made (deleted otherwise)
OR DX,DX ;test if adjustment really wanted
JNZ FLDDESCADJ_DONE ;if so, then jump to return now
; If deleting (DX=0), start at DI and move CX words left by two
; and put a null free string header where the last word of the
; string was.
SUB WORD PTR [SI].LHPLEN,2 ;string size is less by 2
JZ FLDDESCADJ_CLR ;jump if string is now empty
MOV SI,DI ;SI points to byte after
DEC DI ;point DI to...
DEC DI ;the word before (AX value)
PUSH ES ;make sure that we use the proper
PUSH DS ;segment in case that
POP ES ;we are in the middle of unwinding a CHAIN
REP MOVSW ;move the string left 2
POP ES ;recover correct ES = BASIC DS
MOV WORD PTR [DI],1 ;null string free header
JMP SHORT FLDDESCADJ_DONE ;done, jump to finish
FLDDESCADJ_CLR:
XOR DI,DI ;clear register
XCHG DI,[SI].LHPOFF ;clear descr offset, get it
MOV WORD PTR [DI-2],3 ;set ptr to empty string
FLDDESCADJ_DONE:
POP DI ;restore registers...
POP DX
POP CX
POP BX
POP AX
RET ;return to caller
FLDDESCADJ_ERROR:
JMP B$ERR_SSC ; report string space corruption
assumes DS,DGROUP
assumes ES,NOTHING
;***
; B$LHNXTFIL, NXTFIL_ES - return FDB pointer of next file in heap after [SI]
; Purpose:
; To return a pointer to the next FDB in the heap. The
; local heap is searched from the last FDB specified in SI
; (or the first if SI=0).
;
; Inputs:
; SI = pointer to FDB to start search from (0 if first FDB
; pointer is to be returned).
; Outputs:
; SI = pointer to next FDB after the one specified on routine
; entry (0 if no more FDB's in the heap).
; ZF = clear if FDB returned
; set if none returned
; Modifies:
; None.
; Exceptions:
; None.
;****
NXTFIL_ES: ;Assumes ES already set up
PUSH ES
JMP SHORT NXTFIL_COMMON
B$LHNXTFIL:
PUSH ES
PUSH DS
POP ES ;set ES = DS
NXTFIL_COMMON: ;common entry
ASSERT_NOT_VARHEAP NH_TEXT
assumes ES,DGROUP
assumes DS,NOTHING
OR SI,SI ;test if first file is to be searched
JNZ NXTFIL_NEXT ;if so, then branch
MOV SI,ES:[b$HEAP_FIRST] ;initialize to start of local heap
ADD SI,3 ;adjust to avoid extra jump
NXTFIL_NEXT:
SUB SI,3 ;move from FDB over backlength to next entry
NXTFIL_LOOP:
CMP [SI].LHTYPE,LOW LH_END ;test if last entry in heap
JE NXTFIL_END ;if so, then jump
CMP [SI].LHTYPE,LOW LH_FILE ;test if entry is file
JE NXTFIL_FILE ;if so, then jump
SUB SI,[SI].LHLEN ;point to next heap entry
JMP SHORT NXTFIL_LOOP ;and continue the search
NXTFIL_FILE:
SUB SI,[SI].LHLEN ;point to previous entry
ADD SI,3 ;move over backlength to entry FDB
assumes ES,NOTHING
POP ES
RET ;return to caller (ZF clear)
NXTFIL_END:
XOR SI,SI ;clear to show no more files
POP ES
RET ;return to caller (ZF set)
;***
;B$LH_PTR_FROM_DATA - get heap entry pointer from data pointer
;LH_PTR_FROM_BLEN - get heap entry pointer from backlength pointer
;B$LH_PTR_CHECK - check heap entry referenced by its pointer
;
;Purpose:
; From the pointer given return the heap entry data pointer. Also check the
; heap entry by matching its length and backlength values and confirming that
; the length is nonzero.
;
;Inputs:
; SI = specified pointer
;
;Outputs:
;
; SI = heap entry header pointer
;
;Modifies:
; None.
;
;Exceptions:
; If heap entry is inconsistent, jump to B$ERR_SSC.
;****
B$LH_PTR_FROM_DATA:
SUB SI,2 ;now point to entry backlength
LH_PTR_FROM_BLEN:
ADD SI,[SI] ;point to one past header entry
DEC SI ;point to header entry
B$LH_PTR_CHECK:
PUSH AX ;save registers...
PUSH DI
MOV AX,[SI].LHLEN ;get length of heap entry
MOV DI,SI ;compute offset of entry backlength...
SUB DI,AX ;by moving the pointer to before backlength
CMP [DI+1],AX ;compare entry length and backlength
JNE LH_PTR_ERROR ;if not equal, then report error
OR AX,AX ;test for illegal zero value
JZ LH_PTR_ERROR ;if so, then jump
POP DI ;restore registers...
POP AX
RET ;return to caller
LH_PTR_ERROR:
PUSH ES ;force DS = basic dgroup in case
POP DS ;we are unwinding chain
assumes DS,DGROUP
DbHalt NH_TEXT,<B$LH_PTR_CHECK found inconsistent heap entry>
JMP B$ERR_SSC ;note heap is inconsistent if ID_RELEASE version
;***
; B$LHSetFree - set free heap entry pointer
; Purpose:
; Determines if the current free heap entry is both the last
; heap entry and unallocated. If so, its current value is
; returned in DI. Otherwise, the free heap entry pointer
; [b$HEAP_FREE] is set to the heap space end and its value returned
; in DI.
;
; Inputs:
; None.
; Outputs:
; DI = pointer to free heap entry [b$HEAP_FREE].
; Modifies:
; AX.
; Exceptions:
; None.
;****
B$LHSetFree PROC NEAR
MOV DI,[b$HEAP_FREE] ;point to free heap entry
CMP [DI].LHTYPE,LOW LH_FREE ;test if entry unallocated
JNE LH_SET_END ;if allocated, then jump
MOV AX,DI ;get pointer to free entry
SUB AX,[DI].LHLEN ;point to entry after free one
CMP AX,[b$HEAP_END] ;test if free entry was last in space
JE LH_SET_RETURN ;if so, jump leaving pointer unchanged
LH_SET_END:
MOV DI,[b$HEAP_END] ;get pointer to heap end
CMP DI,[b$HEAP_FIRST] ; Empty heap?
JZ LH_SET_FREE ; then don't try anything fancy
MOV AX,DI ; [AX] = pointer to end entry
ADD AX,[DI+1] ; [AX] = pointer to entry before end
XCHG AX,DI ; [AX] = ptr to end, [DI] = entry before
CMP [DI].LHTYPE,LOW LH_FREE ; test if entry after unallocated
JZ LH_SET_FREE ; if so, that's the free entry
XCHG AX,DI ; else use end entry
LH_SET_FREE:
MOV [b$HEAP_FREE],DI ;and set the free pointer to it
LH_SET_RETURN:
RET ;return with DI pointing to free entry
B$LHSetFree ENDP
SUBTTL B$NHINIT - Initialize dynamic space
PAGE
;***
; B$NHINIT - Initialize dynamic space
; Purpose:
; Initialize the necessary pointers and structures for string and
; local heap space.
; Inputs:
; AX = first word of dynamic space.
; CX = last word of dynamic space.
; Outputs:
; None.
; Modifies:
; None.
; Exceptions:
; None.
;****
cProc B$NHINIT,<PUBLIC,NEAR>,<AX,BX,CX,SI,DI>
cBegin
MOV SI,CX ;get last word of dynamic space
INC SI ;point to last byte of space
MOV [b$HEAP_FIRST],SI ;the local heap starts here...
MOV [b$HEAP_FREE],SI ;has its free entry here...
MOV [b$HEAP_END],SI ;and ends here
MOV [SI].LHTYPE,LOW LH_END ;set the heap entry type
ADD AX,LH_STD_HDR_LEN ; dyn space starts after var heap
MOV [b$NH_first],AX
MOV BX,AX
DEC BX ; point to last byte of var heap
MOV [b$HEAP_FIRST_SWAP],BX ; the variable heap starts here...
MOV [b$HEAP_FREE_SWAP],BX ; has its free entry here...
MOV [b$HEAP_END_SWAP],BX ; and ends here
MOV [BX].LHTYPE,LOW LH_END ; set heap entry type
;Set up pointers to routine to be called when B$ILHALC needs to
; grow the appropriate heap
MOV [P_HEAP_GROW_SWAP],NH_TEXTOFFSET B$VAR_ALC_GROW ;[ln]
MOV [b$P_HEAP_GROW],NH_TEXTOFFSET LH_ALC_GROW ;[ln]
SUB SI,LH_STD_HDR_LEN+1 ;point to even address before entry
CMP b$Clearing,0 ;are we doing a CLEAR statement?
JZ NotClearing ;no, go initialize string space
CALL B$SSClean ; clean out entries, so we don't
JMP SHORT InitExit ; bash function keys
NotClearing:
CALL B$STINIT ;initialize string space
InitExit:
cEnd
sEnd NH_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -