#include "Cmm.h"
// -----------------------------------------------------------------------
// Key encoding
//
// Thread IDs are StgWord32, occupying the low 32 bits of each key slot.
// Bit 32 serves as a "detached" flag: set when the user detaches a
// context, cleared on re-attach. The probe masks this bit when
// comparing against the target tid and encodes the detached state in
// the return value so the Haskell side never touches the value array
// for detached slots.
//
// Slot hashing uses a Fibonacci/golden-ratio multiplicative hash
// to spread sequential thread IDs across cache lines, avoiding false
// sharing on the key and value arrays.
// -----------------------------------------------------------------------
#define HASH_SALT 0x9E3779B97F4A7C15
#define DETACHED_BIT 0x0000000100000000
#define KEY_MASK 0x00000000FFFFFFFF
// -----------------------------------------------------------------------
// stg_getCurrentThreadId
//
// Returns the current green thread's ID as an Int#.
// Reads StgTSO_id(CurrentTSO) directly, with no myThreadId# box
// allocation, no rts_getThreadId FFI call.
// -----------------------------------------------------------------------
stg_getCurrentThreadId()
{
return (TO_W_(StgTSO_id(CurrentTSO)));
}
// -----------------------------------------------------------------------
// stg_probeThreadSlot
//
// Fused thread ID retrieval + multiplicative-hash linear probe.
//
// Arguments:
// P_ keys : MutableByteArray# holding Int-sized keys per slot
// W_ mask : table capacity - 1 (for bitwise AND)
//
// Returns: (Int# tid, Int# slot)
// slot >= 0 -> entry found and attached at that index
// slot == -1 -> entry not found
// slot <= -2 -> entry found but detached; real index = -(slot+2)
// -----------------------------------------------------------------------
stg_probeThreadSlot(P_ keys, W_ mask)
{
W_ tid, home, slot, key, base, raw_key;
tid = TO_W_(StgTSO_id(CurrentTSO));
home = (tid * HASH_SALT) & mask;
slot = home;
base = keys + SIZEOF_StgArrBytes;
again:
key = W_[base + WDS(slot)];
raw_key = key & KEY_MASK;
if (raw_key == tid) {
if (key != tid) {
// Key matches but detached bit is set.
return (tid, 0 - slot - 2);
}
return (tid, slot);
}
if (key == 0) {
return (tid, -1);
}
slot = (slot + 1) & mask;
if (slot != home) {
goto again;
}
return (tid, -1);
}
// -----------------------------------------------------------------------
// stg_probeSlotByKey
//
// Linear probe with an explicit key (not CurrentTSO).
// Used by lookupRaw / updateRaw / adjustOnThread.
//
// Arguments:
// P_ keys : MutableByteArray# holding Int-sized keys per slot
// W_ mask : table capacity - 1
// W_ tid : the raw key to search for (lower 32 bits only)
//
// Returns: Int# slot (same encoding as stg_probeThreadSlot)
// -----------------------------------------------------------------------
stg_probeSlotByKey(P_ keys, W_ mask, W_ tid)
{
W_ home, slot, key, base, raw_key;
home = (tid * HASH_SALT) & mask;
slot = home;
base = keys + SIZEOF_StgArrBytes;
again:
key = W_[base + WDS(slot)];
raw_key = key & KEY_MASK;
if (raw_key == tid) {
if (key != tid) {
return (0 - slot - 2);
}
return (slot);
}
if (key == 0) {
return (-1);
}
slot = (slot + 1) & mask;
if (slot != home) {
goto again;
}
return (-1);
}