asm {
//************************************
SYS_HASH_STR::
// IN:  RSI = Addr of string
// OUT: RAX
                                XOR             RAX, RAX
                                TEST            RSI, RSI
                                JZ                      @@15

                                PUSH            RSI
                                PUSH            RBX
                                XOR             RBX, RBX
                                JMP             @@10

@@05:                   SHL1            RBX
                                ADC             RBX, RAX
@@10:                   LODSB
                                TEST            AL, AL
                                JNZ             @@05

                                MOV             RAX, RBX
                                SHR             RBX, 16
                                ADC             RAX, RBX
                                POP             RBX
                                POP             RSI

@@15:                   RET

//************************************
SYS_HASH_SINGLE_TABLE_FIND1::
// IN:  RAX = HASHED STRING VAL
//              RSI = STR
//              RBX = TYPE MASK
//              RDI = TABLE
//              RCX = INSTANCE, NOT ZERO
// OUT: RAX = ENTRY OR ZERO NOT FOUND
//              RDX = POINTER TO POINTER TO ENTRY
//              RCX IF NOT FOUND ENOUGH, DECREMENTED BY NUM MATCHES
//              ZERO FLAG SET NOT FOUND
                                MOV             RCX, 1
SYS_HASH_SINGLE_TABLE_FIND::
                                TEST            RCX, RCX
                                JNZ             @@05
                                XOR             RAX, RAX
                                RET
@@05:                   AND             RAX, U64 CHashTable.mask[RDI]
                                MOV             RDX, U64 CHashTable.body[RDI]
                                LEA             RDX, U64 [RDX + RAX * 8]
@@10:                   MOV             RAX, U64 [RDX]
                                TEST            RAX, RAX
                                JNZ             @@15
                                RET

@@15:                   TEST            U32 CHash.type[RAX], EBX
                                JZ                      @@30
                                PUSH            RAX
                                PUSH            RDI
                                PUSH            RSI
                                MOV             RDI, U64 CHash.str[RAX]
@@20:                   LODSB
                                CMP             U8 [RDI], AL
                                JNE             @@25
                                INC             RDI
                                TEST            AL, AL
                                JNZ             @@20
                                POP             RSI
                                POP             RDI
                                POP             RAX
                                LOOP            @@30
                                INC             U32 CHash.use_count[RAX]
                                TEST            RAX, RAX
                                RET

@@25:                   POP             RSI
                                POP             RDI
                                POP             RAX

@@30:                   LEA             RDX, U64 CHash.next[RAX]
                                JMP             @@10

//************************************
SYS_HASH_FIND1::
// IN:  RSI = STR
//              RBX = TYPE MASK
//              RDI = TABLE
//              RCX = INSTANCE NUM
// OUT: RAX = ENTRY OR ZERO NOT FOUND
//              ZERO FLAG SET NOT FOUND
                                MOV             RCX, 1
SYS_HASH_FIND::
                                PUSH            RDI
                                CALL            SYS_HASH_STR
 
@@05:                   PUSH            RAX
                                CALL            SYS_HASH_SINGLE_TABLE_FIND
                                JNZ             @@15
                                POP             RAX
@@10:                   MOV             RDI, U64 CHashTable.next[RDI]
                                TEST            RDI, RDI
                                JNZ             @@05
                                POP             RDI
                                XOR             RAX, RAX
                                RET

@@15:                   ADD             RSP, 8
                                POP             RDI
                                TEST            RAX, RAX
                                RET

//************************************
SYS_HASH_BUCKET_FIND::
// IN:  RSI = STR
//              RDI = TABLE
// OUT: RAX = BUCKET
                                PUSH            RDX
                                CALL            SYS_HASH_STR
                                AND             RAX, U64 CHashTable.mask[RDI]
                                MOV             RDX, U64 CHashTable.body[RDI]
                                LEA             RAX, U64 [RDX+RAX * 8]
                                POP             RDX
                                RET
_HASH_STR::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RSI
                                MOV             RSI, U64 SF_ARG1[RBP]
                                CALL            SYS_HASH_STR
                                POP             RSI
                                POP             RBP
                                RET1            8
_HASH_FIND::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RSI
                                PUSH            RDI
                                MOV             RSI, U64 SF_ARG1[RBP]
                                MOV             RDI, U64 SF_ARG2[RBP]
                                MOV             RBX, U64 SF_ARG3[RBP]
                                MOV             RCX, U64 SF_ARG4[RBP]
                                CALL            SYS_HASH_FIND
                                POP             RDI
                                POP             RSI
                                POP             RBP
                                RET1            32
_HASH_SINGLE_TABLE_FIND::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RSI
                                PUSH            RDI
                                MOV             RSI, U64 SF_ARG1[RBP]
                                MOV             RDI, U64 SF_ARG2[RBP]
                                MOV             RBX, U64 SF_ARG3[RBP]
                                MOV             RCX, U64 SF_ARG4[RBP]
                                CALL            SYS_HASH_STR
                                CALL            SYS_HASH_SINGLE_TABLE_FIND
                                POP             RDI
                                POP             RSI
                                POP             RBP
                                RET1            32
_HASH_BUCKET_FIND::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RSI
                                PUSH            RDI
                                MOV             RSI, U64 SF_ARG1[RBP]
                                MOV             RDI, U64 SF_ARG2[RBP]
                                CALL            SYS_HASH_BUCKET_FIND
                                POP             RDI
                                POP             RSI
                                POP             RBP
                                RET1            16
_HASH_ADD::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RSI
                                PUSH            RDI
                                MOV             RCX, U64 SF_ARG1[RBP]
                                MOV             RSI, U64 CHash.str[RCX]
                                MOV             RDI, U64 SF_ARG2[RBP]
                                CALL            SYS_HASH_BUCKET_FIND
                                MOV             RCX, U64 SF_ARG1[RBP]
                                PUSHFD
                                CLI
                                MOV             RBX, U64 [RAX]
                                MOV             U64 CHash.next[RCX], RBX
                                MOV             U64 [RAX], RCX

                                POPFD
                                POP             RDI
                                POP             RSI
                                POP             RBP
                                RET1            16
_HASH_ADD_AFTER::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RDI
                                MOV             RCX, U64 SF_ARG1[RBP]
                                MOV             RDI, U64 SF_ARG3[RBP]
                                PUSHFD
                                CLI
                                MOV             RAX, SF_ARG2[RBP]
                                MOV             RBX, U64 [RAX]
                                MOV             U64 CHash.next[RCX], RBX
                                MOV             U64 [RAX], RCX

                                POPFD
                                POP             RDI
                                POP             RBP
                                RET1            24
_HASH_REM_DEL::
                                PUSH            RBP
                                MOV             RBP, RSP
                                PUSH            RSI
                                PUSH            RDI
                                MOV             RCX, U64 SF_ARG1[RBP]
                                TEST            RCX, RCX
                                JZ                      @@10
                                MOV             RSI, U64 CHash.str[RCX]
                                XOR             RBX, RBX
                                MOV             EBX, U32 CHash.type[RCX]
                                AND             EBX, ~HTG_FLAGS_MASK & 0xFFFFFFFF
                                MOV             RDI, U64 SF_ARG2[RBP]
                                MOV             RCX, U64 SF_ARG3[RBP]
                                CALL            SYS_HASH_STR

                                PUSHFD
                                CLI
                                CALL            SYS_HASH_SINGLE_TABLE_FIND
                                JZ                      @@05
                                CMP             RAX, U64 SF_ARG1[RBP]
                                JNE             @@05

                                MOV             RBX, U64 CHash.next[RAX]
                                MOV             U64 [RDX], RBX

                                POPFD

                                PUSH_C_REGS
                                PUSH            RAX
                                CALL            &HashDel
                                POP_C_REGS

                                POP             RDI
                                POP             RSI
                                MOV             RAX, 1
                                POP             RBP
                                RET1            24

@@05:                   POPFD
@@10:                   POP             RDI
                                POP             RSI
                                XOR             RAX, RAX
                                POP             RBP
                                RET1            24
}

// Hash a string.
_extern _HASH_STR                               I64             HashStr(U8 *st);
// Find string in hash table.
_extern _HASH_FIND                              CHash  *HashFind(U8 *needle_str, CHashTable *haystack_table, I64 mask, I64 instance=1);
// Find string in single hash table.
_extern _HASH_SINGLE_TABLE_FIND CHash  *HashSingleTableFind(U8 *needle_str, CHashTable *haystack_table,
                                                                                                                        I64 mask, I64 instance=1);
// Find hash bucket.
_extern _HASH_BUCKET_FIND               CHash **HashBucketFind(U8 *needle_str, CHashTable *haystack_table);
// Add entry to hash table.
_extern _HASH_ADD                               U0              HashAdd(CHash *tmph, CHashTable *table);
// Remove hash entry and del. Instance must match.
_extern _HASH_REM_DEL                   Bool    HashRemDel(CHash *tmph, CHashTable *table, I64 instance=1);