name.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 566 行 · 第 1/2 页

C
566
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "plusplus.h"

#include <stdio.h>
#include <limits.h>

#include "errdefns.h"
#include "memmgr.h"
#include "name.h"
#include "carve.h"
#include "initdefs.h"
#include "stats.h"
#include "pcheader.h"
#include "toggle.h"
#ifndef NDEBUG
#include "pragdefn.h"
#endif

#pragma pack(1);
typedef struct name NAME;
struct name {
    NAME                *next;
    uint_16             xhash;
    name_hash_t         hash;
    char                name[1];
};
#pragma pack();

#define NAME_TABLE_HASH NAME_HASH

static NAME *hashTable[ NAME_TABLE_HASH ];

static name_dummy_index_t nameDummyIndex;
static unsigned long nameCount;

static NAME **nameTranslateTable;

static struct {
    unsigned            no_creates_allowed : 1; // name list is frozen
} nameFlags;

ExtraRptCtr( ctr_names );
ExtraRptCtr( ctr_dummy_names );
ExtraRptCtr( ctr_chains );
ExtraRptCtr( ctr_searches );
ExtraRptCtr( ctr_probes );
ExtraRptCtr( ctr_hashes );
ExtraRptCtr( ctr_length );
ExtraRptCtr( ctr_memcmp );
ExtraRptCtr( ctr_memcmp_fail );
ExtraRptCtr( ctr_max_length );

unsigned const NameCmpMask[5] = {
    0x00000000,
    0x000000ff,
    0x0000ffff,
    0x00ffffff,
    0xffffffff,
};

int NameMemCmp( char const *t1, char const *t2, unsigned len )
/************************************************************/
{
    unsigned *s1 = (unsigned*) t1;
    unsigned *s2 = (unsigned*) t2;
    unsigned mask;
    int diff;

    // can only check for one null byte since the common length
    // may access invalid memory with the other string
    DbgAssert( t2[len-1] == 0 );
    if( len > sizeof( unsigned ) ) {
        do {
            diff = *s1 - *s2;
            if( diff != 0 ) {
                return( diff );
            }
            ++s1;
            ++s2;
            len -= sizeof( unsigned );
        } while( len > sizeof( unsigned ) );
    }
    mask = NameCmpMask[ len ];
    return( ( *s1 & mask ) - ( *s2 & mask ) );
}

unsigned NameCalcHashLen( char const *id, size_t len )
/**********************************************/
{
    unsigned *s = (unsigned*) id;
    unsigned mask;
    unsigned c;
    unsigned g;
    unsigned h;

    ExtraRptIncrementCtr( ctr_hashes );
    /* modelled on hashpjw from the Dragon book */
    /* should not be used in mangled names so that it can change in patches */
    h = len;
    c = len;
    if( len > sizeof( unsigned ) ) {
        do {
            c ^= *s;
            h = ( h << 4 ) + c;
            g = h & ~0x0ffffff;
            h ^= g;
            h ^= g >> (4+4+4+4+4);
            ++s;
            len -= sizeof( unsigned );
        } while( len > sizeof( unsigned ) );
    }
    mask = NameCmpMask[ len ];
    c ^= *s & mask;
    h = ( h << 4 ) + c;
    g = h & ~0x0ffffff;
    h ^= g;
    h ^= g >> (4+4+4+4+4);
    g = h & ~0x0fff;
    h ^= g;
    h ^= g >> (4+4+4);
    h ^= h >> (2+4);
    DbgAssert(( h % NAME_HASH ) == h );
    return( h );
}

static char *nameAdd( NAME **head, unsigned bucket, unsigned xhash,
                      char *id, size_t len )
{
    NAME *name;

#ifdef XTRA_RPT
    if( *head == NULL ) {
        ExtraRptIncrementCtr( ctr_chains );
    }
#endif
    ExtraRptIncrementCtr( ctr_names );
    DbgVerify( ! nameFlags.no_creates_allowed
             , "name create occurred during precompiled header processing" );
    name = CPermAlloc( sizeof( NAME ) + len );
    memcpy( name->name, id, len + 1 );
    name->xhash = xhash;
    name->hash = bucket;
    name->next = *head;
    *head = name;
    ++nameCount;
    return( name->name );
}


char *NameCreateLen( char *id, unsigned len )
/*******************************************/
{
    unsigned xhash;
    unsigned bucket;
    size_t cmp_len;
    NAME *name;
    NAME **head;
    NAME **prev;

    ExtraRptIncrementCtr( ctr_searches );
    xhash = NameCalcHashLen( id, len );
#if NAME_TABLE_HASH != NAME_HASH
    bucket = xhash % NAME_TABLE_HASH;
#else
    bucket = xhash;
#endif
    // xhash cannot overflow a uint_16 ( 0x0fff + 0x00ff <= 0x1fff )
    xhash += (uint_8) len;
    head = &(hashTable[ bucket ]);
    prev = head;
    cmp_len = len + 1;
    ExtraRptZeroCtr( ctr_length );
    for( name = *prev; ; name = *prev ) {
        ExtraRptIncrementCtr( ctr_probes );
        ExtraRptIncrementCtr( ctr_length );
        if( name == NULL ) break;
        if( name->xhash == xhash ) {
            ExtraRptIncrementCtr( ctr_memcmp );
            if( NameMemCmp( name->name, id, cmp_len ) == 0 ) {
                /* move name to front of list in hash table */
                *prev = name->next;
                name->next = *head;
                *head = name;
                return( name->name );
            }
            ExtraRptIncrementCtr( ctr_memcmp_fail );
        }
        prev = &(name->next);
    }
    ExtraRptMaximum( ctr_length, ctr_max_length );
    return( nameAdd( head, bucket, xhash, id, len ) );
}


char *NameCreateNoLen( char *id )
/*******************************/
{
    size_t len;
    name_dummy_index_t ni;
    unsigned xhash;
    unsigned bucket;
    NAME **head;

    len = strlen( id );
    if( id[0] != NAME_DUMMY_PREFIX_0 ) {
        return( NameCreateLen( id, len ) );
    }
    // everybody uses the same 'name' so the hash doesn't have to be generated
    // from the name contents
    ni = nameDummyIndex++;
    xhash = ni % NAME_TABLE_HASH;
    bucket = xhash;
    head = &(hashTable[ bucket ]);
    return( nameAdd( head, bucket, xhash, id, len ) );
}

name_dummy_index_t NameNextDummyIndex( void )
/*******************************************/
{
    return( nameDummyIndex++ );
}

char *NameDummy( void )
/*********************/
{
    name_dummy_index_t ni;
    unsigned xhash;
    unsigned bucket;
    size_t len;
    NAME **head;
    char buff[ 1 + 1 + sizeof( ni ) * 3 + 1 ];

    ExtraRptIncrementCtr( ctr_dummy_names );
    ni = nameDummyIndex++;
    xhash = ni % NAME_TABLE_HASH;
    bucket = xhash;
    buff[0] = NAME_DUMMY_PREFIX_0;
    buff[1] = NAME_DUMMY_PREFIX_1;
    // the contents of the name don't have to be different just the address
    // but for debugging it is handy to have unique contents
#ifndef NDEBUG
    ultoa( ni, &buff[2], 10 );
    len = strlen( buff );
#else
    buff[2] = '0';
    buff[3] = '\0';
    len = 3;
#endif
    head = &(hashTable[ bucket ]);
    return( nameAdd( head, bucket, xhash, buff, len ) );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?