; =====> SOBJHASH.ASM ;*************************************** ;* TIPC Scheme Runtime Support * ;* Object Hashing Routines * ;* * ;* (C) Copyright 1985 by Texas * ;* Instruments Incorporated. * ;* All rights reserved. * ;* * ;* Date Written: 25 June 1985 * ;* Last Modification: 3 November 1985 * ;*************************************** include scheme.equ DGROUP group data XGROUP group PROGX PGROUP group prog data segment word public 'DATA' assume DS:DGROUP obj_cntr dw OHT_SIZE dup (1) branchtab dw ogc_list ; [0] List cells dw ogc_mark ; [1] Fixnums dw ogc_var ; [2] Flonums dw ogc_var ; [3] Bignums dw ogc_var ; [4] Symbols dw ogc_var ; [5] Strings dw ogc_var ; [6] Arrays dw ogc_var ; [7] Continuations dw ogc_var ; [8] Closures dw ogc_mark ; [9] Free page dw ogc_var ; [10] Code page dw ogc_mark ; [11] Reference cells dw ogc_var ; [12] Port data objects dw ogc_mark ; [13] Characters dw ogc_var ; [14] Environments ret_sav1 dw 0 ; return address save area ret_sav2 dw 0 ; return address save area data ends prog segment byte public 'PROG' assume CS:PGROUP ;************************************************************************ ;* Far Linkage to "lookup" Routine * ;************************************************************************ %lookup proc far extrn lookup:near call lookup ret %lookup endp ;************************************************************************ ;* Far Linkage to "cons" Routine * ;************************************************************************ public %cons %cons proc far pop ret_sav1 pop ret_sav2 mov AX,DS ; make ES point to the data segment mov ES,AX extrn cons:near call cons push ret_sav2 push ret_sav1 ret %cons endp ;************************************************************************ ;* Far Linkage to "alloc_block" Routine * ;************************************************************************ public %allocbl %allocbl proc far pop ret_sav1 pop ret_sav2 mov AX,DS ; make ES point to the data segment mov ES,AX extrn alloc_bl:near call alloc_bl push ret_sav2 push ret_sav1 ret %allocbl endp prog ends PROGX segment byte public 'PROGX' assume CS:XGROUP ;************************************************************************ ;* Object Hash * ;************************************************************************ oh_args struc oh_key dw ? ; computed hash key oh_key3 dw ? ; computed hash key * 3 oh_disp dw ? ; page number component of a pointer oh_page dw ? ; displacement component of a pointer oh_reg dw ? ; pointer to argument register (s=d) oh_ctr dw ? ; bucket's current counter value oh_ctag db SPECFIX*2,? ; tag for counter oh_BP dw ? ; caller's BP dw ? ; caller's SI dw ? ; caller's ES dd ? ; return address (far call) dw ? ; return address (near call) oh_args ends %objhash proc far lods byte ptr ES:[SI] ; fetch operand of object-hash push ES ; save the caller's ES register push SI ; save the location counter push BP ; save the caller's BP register sub SP,offset oh_BP ; allocate local storage mov BP,SP ; establish local addressability ; load argument and compute hash index mov BX,AX ; copy dest=src register number to BX add BX,offset reg0 ; and compute the register's address mov [BP].oh_reg,BX ; save the register address ;;; ;;; Note: computing of hash value turned off 'cause relocation of ;;; pointers screws things up. For now, all objects will ;;; hash to a key of zero. (JCJ 2 OCT 85) ;;; mov DX,[BX].C_page ; load the argument's page number ;;; mov AX,[BX].C_disp ; load the argument's displacement ;;; mov CL,AH ; copy high byte of displacement ;;; xor AH,AH ;;; xor CH,CH ;;; add AX,CX ;;; add AX,DX ;;; mov CX,OHT_SIZE ; load the hash table size for divisor ;;; cwd ; convert dividend to double word ;;; div CX ; divide hash value by table size xor DX,DX ; ***TEMPORARY*** Load a hash key of zero ;;; mov [BP].oh_key,DX ; save computed hash key mov SI,DX shl DX,1 add SI,DX ; SI <- hash_key * 3 mov [BP].oh_key3,SI ; if entries exist at this hash level, search bucket for object cmp obj_ht+[SI],0 ; anyone home in this bucket? je oh_nf ; if no entries exist, jump ; call "lookup" to search a-list mov AX,[BX].C_disp ; reload object's displacement mov DX,[BX].C_page ; and page for a-list search xor BX,BX mov BL,obj_ht+[SI] %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov SI,word ptr obj_ht+[SI]+1 call %lookup ; search the a-list cmp BL,0 je oh_nf ; object found in hash bucket's chain-- return it mov AX,ES:[DI].cdr ; load the hash counter mov [BP].oh_ctr,AX ; and save it in 'oh_ctr' jmp short oh_ret ; return hash value ; make a new entry in the current hash bucket oh_nf: mov DI,[BP].oh_key shl DI,1 ; multiply hash value by 2 for index mov AX,obj_cntr+[DI] ; load obj hash counter for this bucket inc obj_cntr+[DI] ; increment the obj hash counter mov [BP].oh_ctag,SPECFIX*2 ; convert hash counter to a fixnum mov [BP].oh_ctr,AX ; pointer lea BX,[BP].oh_ctr ; load hash counter's "reg" address mov AX,[BP].oh_reg ; load object's register address mov CX,offset tmp_reg ; load offset of temporary register pushm ; push arguments to call call %cons ; cons(tmp_reg, object, hash-counter) mov BX,offset nil_reg ; load address of "nil register" mov CX,offset tmp_reg ; load address of temporary register pushm ; push arguments to cons call %cons ; cons(tmp_reg, (cons obj hash), nil) mov SP,BP ; drop arguments from stack mov DI,[BP].oh_key3 ; load hash bucket number * 3 mov BX,tmp_page ; load pointer to newest list cell mov AX,tmp_disp %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov SI,AX ; pointer is in ES:[SI] xchg obj_ht+[DI],BL ; header <- pointer to list cell xchg word ptr obj_ht+[DI]+1,AX mov ES:[SI].cdr_page,BL ; (set-cdr! list-cell chain-header) mov ES:[SI].cdr,AX ; create a bignum to hold the hash value oh_ret: mov AX,WORDINCR*2+1 ; load the size of bignum result push AX ; and push it for use as argument mov AX,BIGTYPE ; load type=bignum push AX ; and push it for use as argument push [BP].oh_reg ; push address of destination register mov AX,DS ; ES <- DS mov ES,AX call %allocbl ; allocate the bignum mov SP,BP ; drop arguments off the TIPC's stack mov BX,[BP].oh_reg ; load destination register's address mov SI,[BX].C_page ; load bignum's page number %LoadPage ES,SI ; load bignum page's paragraph address ;;; mov ES,pagetabl+[SI] ; load bignum page's paragraph address mov SI,[BX].C_disp ; load bignum's displacement mov AX,[BP].oh_key ; load hash bucket number mov ES:[SI].big_data,AX ; and store it into LSW of bignum mov AX,[BP].oh_ctr ; load counter for this object mov ES:[SI].big_2nd,AX ; and store it into MSW of bignum mov ES:[SI].big_sign,0 ; sign <- 0 (positive number) ; return to caller add SP,offset oh_BP ; deallocate local storage pop BP ; restore caller's BP register pop SI ; restore the location pointer pop ES ; restore caller's ES register ret ; return to calling procedure %objhash endp ;************************************************************************ ;* Object Unhash * ;************************************************************************ unhs_arg struc un_reg dw ? ; argument register address un_BP dw ? ; caller's BP dw ? ; caller's SI dw ? ; caller's ES dd ? ; return address (far call) dw ? ; return address (near call) unhs_arg ends %objunhs proc far lods byte ptr ES:[SI] ; load the operand for object-unhash push ES ; save the caller's ES register push SI ; save the location pointer push BP ; save the caller's BP register sub SP,offset un_BP ; allocate local storage mov BP,SP ; establish local addressability ; Begin the long process of validating the input mov SI,AX add SI,offset reg0 mov [BP].un_reg,SI mov BX,[SI].C_page cmp byte ptr ptype+[BX],BIGTYPE*2 je un_maybe ; This hash-key is invalid, or object not found-- return #!false un_false: xor AX,AX ; create a nil pointer mov SI,[BP].un_reg ; load destination register address mov byte ptr [SI].C_page,AL ; store nil pointer into mov [SI].C_disp,AX ; destination register ; Return to Scheme Interpreter un_ret: add SP,offset un_BP ; deallocate local storage pop BP ; restore caller's BP register pop SI ; restore the location pointer pop ES ; restore caller's ES register ret ; Continue checking bignum value un_maybe: mov SI,[SI].C_disp ; load bignum's offet %LoadPage ES,BX ; and paragraph address ;;; mov ES,pagetabl+[BX] ; and paragraph address cmp ES:[SI].big_sign,0 jne un_false ; if negative, not one of ours cmp ES:[SI].big_len,8 jne un_false ; if more than four bytes of data, not ours mov DI,ES:[SI].big_data ; load least significant word (bucket no.) cmp DI,OHT_SIZE jae un_false ; hash bucket index too large? if so, jump mov DX,DI ; DX <- bucket number mov AX,ES:[SI].big_2nd shl DI,1 ; DI <- bucket number * 2 cmp AX,obj_cntr+[DI] ; test against next available counter value jae un_false ; hash index too large? if so, jump ; Note: Search index (key) is in AX add DI,DX ; DI <- bucket number * 3 add DI,offset obj_ht mov DX,DS ; ES <- DS mov ES,DX ; Note: Search list whose header is in ES:[DI] call oh_search ; search "ES:[DI]" for "AX" cmp BL,0 ; was index found? je un_false ; if not found, return #!false (jump) ; Search successful-- object/hash-value pair pointed to by ES:[SI] mov DI,[BP].un_reg ; load destination register's address mov AX,ES:[SI].car ; copy car field of found pair into mov [DI].C_disp,AX ; the destination register mov AL,ES:[SI].car_page mov byte ptr [DI].C_page,AL jmp un_ret ; return to caller w/ object in dest reg %objunhs endp ;************************************************************************ ;* Local Support for Object Unhash * ;************************************************************************ oh_search proc near ; Compute pointer to current entry and save it mov BL,ES:[DI].car_page cmp BL,0 je oh_sret mov DI,ES:[DI].car %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov DX,ES ; save ES in DX ; Compute pointer to object/hash-key pair mov BL,ES:[DI].car_page mov SI,ES:[DI].car %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] ; Test cdr field (hash key) of pair for match cmp ES:[SI].cdr,AX jne oh_smore ; A match!-- Return pair address in ES:[SI] oh_sret: ret oh_smore: mov ES,DX ; restore ES add DI,PTRSIZE ; adjust pointer to cdr field of curr entry jmp oh_search ; iterate oh_search endp ;************************************************************************ ;* Object Hash Table Garbage Collection * ;************************************************************************ gc_args struc prev_ES dw ? ; ES for previous entry prev_off dw ? ; offset for previous entry curr_PG dw ? ; ES for current entry curr_off dw ? ; offset for current entry pair_PG dw ? ; ES for object/hash-key pair pair_off dw ? ; offset for object/hash-key pair gc_BP dw ? ; caller's BP dw ? ; caller's ES dd ? ; return address (far call) dw ? ; return address (near call) gc_args ends %gc_oht proc far push ES ; save caller's ES register push BP ; save caller's BP register sub SP,offset gc_BP ; allocate local storage mov BP,SP ; establish addressibility for local storage ; Initialize parameters mov SI,offset obj_ht ; load address of object hash table mov CX,OHT_SIZE ; load number of entries in obj hash table gc_loop: mov AX,DS ; ES <- DS mov ES,AX push SI ; load current object hash table offset push CX ; save iteration counter call gc_nxt ; follow this entries chain pop CX ; restore iteration counter pop SI ; restore obj hash table offset add SI,PTRSIZE ; advance offset pointer loop gc_loop ; continue 'til all buckets processed ; Return to caller gc_xit: add SP,offset gc_BP ; release local storage pop BP ; restore the caller's BP register pop ES ; restore the caller's ES register ret ; return %gc_oht endp ;************************************************************************ ;* Local Support for Object Hash Table Garbage Collection * ;************************************************************************ gc_nxt proc near xor BX,BX ; clear register BX mov BL,ES:[SI].car_page ; load page number for next entry cmp BL,0 ; does entry exist? jne ogc_010 ; if null pointer, jump to exit ret ; return to gc_oht ; save pointer to previous cell ogc_010: mov [BP].prev_ES,ES mov [BP].prev_off,SI ; compute and save pointer to current cell mov DI,ES:[SI].car %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov [BP].curr_PG,BX mov [BP].curr_off,DI ; compute and save pointer to object/hash-key pair mov BL,ES:[DI].car_page mov SI,ES:[DI].car test SI,08000h ; is current cell marked as referenced? jnz ogc_skip ; if marked, GC during OBJECT-HASH (jump) %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov [BP].pair_PG,BX mov [BP].pair_off,SI ; see what object pointer points to mov BL,ES:[SI].car_page cmp BL,DEDPAGES*PAGEINCR ; is object a "special" one? jb ogc_mark ; if a non-gc'ed page, must keep entry mov SI,ES:[SI].car ; load object offset %LoadPage ES,BX ;;; mov ES,pagetabl+[BX] ; load object's paragraph address mov DI,ptype+[BX] ; load type code for object jmp branchtab+[DI] ; jump to appropriate routine ; object is a list cell-- test to see if it's marked ogc_list: test byte ptr ES:[SI].list_gc,GC_BIT jnz ogc_mark jmp short ogc_del ; Variable length object ogc_var: test byte ptr ES:[SI].vec_gc,GC_BIT jnz ogc_mark ; Object not referenced-- delete object hash table entry for it ogc_del: %LoadPage ES,[BP].curr_PG ; reload pointer to current entry mov SI,[BP].curr_off mov AX,ES:[SI].cdr ; load cdr field of current entry mov BL,ES:[SI].cdr_page mov ES,[BP].prev_ES ; reload pointer to previous entry mov SI,[BP].prev_off mov ES:[SI].car,AX ; store cdr field of current entry into mov ES:[SI].car_page,BL ; previous entry jmp gc_nxt ; process next entry ; Object is marked as referenced-- mark obj hash table cells as referenced ogc_mark: %LoadPage ES,[BP].pair_PG ; load pointer to object/hash-key pair mov SI,[BP].pair_off or byte ptr ES:[SI].list_gc,GC_BIT ; mark pair entry referenced ogc_skip: %LoadPage ES,[BP].curr_PG ; load pointer to current entry mov SI,[BP].curr_off or byte ptr ES:[SI].list_gc,GC_BIT ; mark curr entry referenced add SI,PTRSIZE ; advance pointer to cdr field of curr entry jmp gc_nxt ; process next entry gc_nxt endp PROGX ends prog segment byte public 'PROG' assume CS:PGROUP ;************************************************************************ ;* Linkage to Object Hash Routine * ;************************************************************************ public obj_hash obj_hash proc near call %objhash extrn next:near jmp next ; return to the Scheme interpreter obj_hash endp public obj_unhs obj_unhs proc near call %objunhs jmp next ; return to the Scheme interpreter obj_unhs endp public gc_oht gc_oht proc near call %gc_oht ret gc_oht endp prog ends end