* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
* Copyright (c) 2006-2010 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
* hashtable.h
*
* Hashtable support common among all hashtables
*
*/
#ifndef _HASHTABLE_H_
#define _HASHTABLE_H_ 1
* all hashtables
*/
#define HASHTABLE_SHARED 0x00000001
* FIXME: right now this is never used independently from LOCKLESS_ACCESS,
* perhaps get rid of it
*/
#define HASHTABLE_ENTRY_SHARED 0x00000002
#define HASHTABLE_LOCKLESS_ACCESS 0x00000004
#define HASHTABLE_NOT_PRIMARY_STORAGE 0x00000004
#define HASHTABLE_PERSISTENT 0x00000008
#define HASHTABLE_USE_ENTRY_STATS 0x00000010
#define HASHTABLE_RELAX_CLUSTER_CHECKS 0x00000020
* Only used for persisted coarse units.
*/
#define HASHTABLE_READ_ONLY 0x00000040
#define HASHTABLE_ALIGN_TABLE 0x00000080
* FIXME: any better way? how know when hit limit with <<?
*/
#define HASHTABLE_CUSTOM_FLAGS_START 0x00010000
#define HASHTABLE_COPY_IGNORE_FLAGS (HASHTABLE_READ_ONLY)
* tables from ibl while holding locks (we do so in a lockless manner)
*/
#define TABLE_NEEDS_LOCK(ptable) \
(TEST(HASHTABLE_SHARED, (ptable)->table_flags) && \
!TEST(HASHTABLE_READ_ONLY, (ptable)->table_flags))
#define ASSERT_TABLE_SYNCHRONIZED(ptable, RW) \
ASSERT_OWN_##RW##_LOCK(TABLE_NEEDS_LOCK(ptable) && !(ptable)->is_local && \
!INTERNAL_OPTION(single_thread_in_DR), \
&(ptable)->rwlock)
#define TABLE_RWLOCK(ptable, rw, lock) \
do { \
if (TABLE_NEEDS_LOCK(ptable)) \
d_r_##rw##_##lock(&(ptable)->rwlock); \
} while (0)
#define TABLE_MEMOP(table_flags, op) \
(TEST((table_flags), HASHTABLE_PERSISTENT) ? heap_##op : nonpersistent_heap_##op)
#define TABLE_TYPE_MEMOP(table_flags, op, dc, type, which, protected) \
(TEST((table_flags), HASHTABLE_PERSISTENT) \
? HEAP_TYPE_##op(dc, type, which, protected) \
: NONPERSISTENT_HEAP_TYPE_##op(dc, type, which))
* hash_index % (ftable->capacity - 1)
*/
#define HASH_INDEX_WRAPAROUND(hash_index, ftable) \
((hash_index) & (uint)(ftable->hash_mask >> ftable->hash_mask_offset))
#ifdef HASHTABLE_STATISTICS
# define INIT_HASHTABLE_STATS(lookup_stats) \
do { \
memset(&lookup_stats, 0, sizeof(hashtable_statistics_t)); \
ASSERT(lookup_stats.hit_stat == 0); \
} while (0)
# define HTABLE_STAT_INC(ftable, event) ftable->drlookup_stats.event##_stat++
#else
# define HTABLE_STAT_INC(ftable, event) ((void)0)
#endif
#ifdef HASHTABLE_STATISTICS
typedef struct _hashtable_statistics_t {
uint hit_stat;
uint collision_hit_stat;
uint collision_stat;
uint miss_stat;
uint overwrap_stat;
uint race_condition_stat;
uint unlinked_count_stat;
* dynamic count of indirect branches
* FIXME: case 4817 where bb's could also cache one target
* or see the CGO03 paper for multiple cached locations with similar stats
*/
uint ib_stay_on_trace_stat;
* location */
* increment is too heavy weight, should instead save last value
* assuming that some rare, yet common enough event happens
* between every 4 billion increments
*/
uint ib_stay_on_trace_stat_last;
uint ib_stay_on_trace_stat_ovfl;
uint ib_trace_last_ibl_exit;
* and add its success rate
*/
uint ib_trace_last_ibl_speculate_success;
* exit */
} hashtable_statistics_t;
typedef struct _fragment_stat_entry_t {
uint hits;
uint age;
} fragment_stat_entry_t;
#endif
* given load for the given number of entries
*/
uint
hashtable_bits_given_entries(uint entries, uint load);
* GENERIC HASHTABLE INSTANTIATION
*/
* 1) assume payload struct has tag as pointer-sized field at offs 0
* 2) wrap struct w/ tag,payload pair
* 3) pass table_t to ENTRY_TAG and _ ARE_EQUAL
* We go with #2 as it is the cleanest. If users really need to save space
* they can templatize their own hashtable code.
*/
typedef struct _generic_entry_t {
ptr_uint_t key;
void *payload;
} generic_entry_t;
#define NAME_KEY generic
#define ENTRY_TYPE generic_entry_t *
#define CUSTOM_FIELDS void (*free_payload_func)(dcontext_t *, void *);
#define HASHTABLEX_HEADER 1
#include "hashtablex.h"
#undef HASHTABLEX_HEADER
generic_table_t *
generic_hash_create(dcontext_t *dcontext, uint bits, uint load_factor_percent,
uint table_flags,
void (*free_payload_func)(dcontext_t *, void *)
_IF_DEBUG(const char *table_name));
void
generic_hash_destroy(dcontext_t *dcontext, generic_table_t *htable);
void
generic_hash_clear(dcontext_t *dcontext, generic_table_t *htable);
void *
generic_hash_lookup(dcontext_t *dcontext, generic_table_t *htable, ptr_uint_t key);
void
generic_hash_add(dcontext_t *dcontext, generic_table_t *htable, ptr_uint_t key,
void *payload);
bool
generic_hash_remove(dcontext_t *dcontext, generic_table_t *htable, ptr_uint_t key);
uint
generic_hash_range_remove(dcontext_t *dcontext, generic_table_t *htable, ptr_uint_t start,
ptr_uint_t end);
int
generic_hash_iterate_next(dcontext_t *dcontext, generic_table_t *htable, int iter,
OUT ptr_uint_t *key, OUT void **payload);
* updated iteration index to pass to generic_hash_iterate_next().
*/
int
generic_hash_iterate_remove(dcontext_t *dcontext, generic_table_t *htable, int iter,
ptr_uint_t key);
* STRING KEY HASHTABLE INSTANTIATION
*/
typedef struct _strhash_entry_t {
* The table makes no copy of its own.
*/
const char *key;
void *payload;
} strhash_entry_t;
#define NAME_KEY strhash
#define ENTRY_TYPE strhash_entry_t *
#define CUSTOM_FIELDS void (*free_payload_func)(void *);
#define HASHTABLEX_HEADER 1
#include "hashtablex.h"
#undef HASHTABLEX_HEADER
strhash_table_t *
strhash_hash_create(dcontext_t *dcontext, uint bits, uint load_factor_percent,
uint table_flags,
void (*free_payload_func)(void *) _IF_DEBUG(const char *table_name));
void
strhash_hash_destroy(dcontext_t *dcontext, strhash_table_t *htable);
void
strhash_hash_clear(dcontext_t *dcontext, strhash_table_t *htable);
void *
strhash_hash_lookup(dcontext_t *dcontext, strhash_table_t *htable, const char *key);
void
strhash_hash_add(dcontext_t *dcontext, strhash_table_t *htable, const char *key,
void *payload);
bool
strhash_hash_remove(dcontext_t *dcontext, strhash_table_t *htable, const char *key);
#ifdef HASHTABLE_STATISTICS
void
print_hashtable_stats(dcontext_t *dcontext, const char *is_final_str,
const char *is_trace_str, const char *lookup_routine_str,
const char *brtype_str, hashtable_statistics_t *lookup_stats);
#endif
#endif