static uintptr_t jl_object_id_(jl_value_t *tv, jl_value_t *v) { if (tv == (jl_value_t*)jl_sym_type) return ((jl_sym_t*)v)->hash; if (tv == (jl_value_t*)jl_simplevector_type) return hash_svec((jl_svec_t*)v); jl_datatype_t *dt = (jl_datatype_t*)tv; if (dt == jl_datatype_type) { jl_datatype_t *dtv = (jl_datatype_t*)v; // `name->wrapper` is cacheable even though it contains TypeVars // that don't have stable IDs. //if (jl_egal(dtv->name->wrapper, v)) // return bitmix(~dtv->name->hash, 0xaa5566aa); return bitmix(~dtv->name->hash, hash_svec(dtv->parameters)); } if (dt == jl_typename_type) return ((jl_typename_t*)v)->hash; #ifdef _P64 if (v == jl_ANY_flag) return 0x31c472f68ee30bddULL; #else if (v == jl_ANY_flag) return 0x8ee30bdd; #endif if (dt == jl_string_type) { #ifdef _P64 return memhash_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677); #else return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677); #endif } if (dt->mutabl) return inthash((uintptr_t)v); size_t sz = jl_datatype_size(tv); uintptr_t h = jl_object_id(tv); if (sz == 0) return ~h; size_t nf = jl_datatype_nfields(dt); if (nf == 0) { return bits_hash(jl_data_ptr(v), sz) ^ h; } for (size_t f=0; f < nf; f++) { size_t offs = jl_field_offset(dt, f); char *vo = (char*)jl_data_ptr(v) + offs; uintptr_t u; if (jl_field_isptr(dt, f)) { jl_value_t *f = *(jl_value_t**)vo; u = f==NULL ? 0 : jl_object_id(f); } else { jl_datatype_t *fieldtype = (jl_datatype_t*)jl_field_type(dt, f); assert(jl_is_datatype(fieldtype) && !fieldtype->abstract && !fieldtype->mutabl); if (fieldtype->layout->haspadding) u = jl_object_id_((jl_value_t*)fieldtype, (jl_value_t*)vo); else u = bits_hash(vo, jl_field_size(dt, f)); } h = bitmix(h, u); } return h; }
JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *module) { jl_ptls_t ptls = jl_get_ptls_states(); jl_typename_t *tn = (jl_typename_t*)jl_gc_alloc(ptls, sizeof(jl_typename_t), jl_typename_type); tn->name = name; tn->module = module; tn->wrapper = NULL; tn->cache = jl_emptysvec; tn->linearcache = jl_emptysvec; tn->names = NULL; tn->hash = bitmix(bitmix(module ? module->build_id : 0, name->hash), 0xa1ada1da); tn->mt = NULL; return tn; }
DLLEXPORT uptrint_t jl_object_id(jl_value_t *v) { if (jl_is_symbol(v)) return ((jl_sym_t*)v)->hash; jl_value_t *tv = (jl_value_t*)jl_typeof(v); if (tv == (jl_value_t*)jl_tuple_type) { uptrint_t h = 0; size_t l = jl_tuple_len(v); for(size_t i = 0; i < l; i++) { uptrint_t u = jl_object_id(jl_tupleref(v,i)); h = bitmix(h, u); } return h; } jl_datatype_t *dt = (jl_datatype_t*)tv; if (dt == jl_datatype_type) { jl_datatype_t *dtv = (jl_datatype_t*)v; uptrint_t h = inthash((uptrint_t)tv); return bitmix(bitmix(h, jl_object_id((jl_value_t*)dtv->name)), jl_object_id((jl_value_t*)dtv->parameters)); } if (dt->mutabl) return inthash((uptrint_t)v); size_t sz = jl_datatype_size(tv); uptrint_t h = inthash((uptrint_t)tv); if (sz == 0) return ~h; size_t nf = jl_tuple_len(dt->names); if (nf == 0) { return bits_hash(jl_data_ptr(v), sz) ^ h; } for (size_t f=0; f < nf; f++) { size_t offs = dt->fields[f].offset; char *vo = (char*)jl_data_ptr(v) + offs; uptrint_t u; if (dt->fields[f].isptr) { jl_value_t *f = *(jl_value_t**)vo; u = f==NULL ? 0 : jl_object_id(f); } else { u = bits_hash(vo, dt->fields[f].size); } h = bitmix(h, u); } return h; }
static uintptr_t NOINLINE hash_svec(jl_svec_t *v) { uintptr_t h = 0; size_t i, l = jl_svec_len(v); for (i = 0; i < l; i++) { jl_value_t *x = jl_svecref(v, i); uintptr_t u = (x == NULL) ? 0 : jl_object_id(x); h = bitmix(h, u); } return h; }
DLLEXPORT uptrint_t jl_object_id(jl_value_t *v) { if (jl_is_symbol(v)) return ((jl_sym_t*)v)->hash; jl_value_t *tv = (jl_value_t*)jl_typeof(v); if (jl_is_bits_type(tv)) { size_t nb = jl_bitstype_nbits(tv)/8; uptrint_t h = inthash((uptrint_t)tv); switch (nb) { case 1: return int32hash(*(int8_t*)jl_bits_data(v) ^ h); case 2: return int32hash(*(int16_t*)jl_bits_data(v) ^ h); case 4: return int32hash(*(int32_t*)jl_bits_data(v) ^ h); case 8: return hash64(*(int64_t*)jl_bits_data(v) ^ h); default: #ifdef __LP64__ return h ^ memhash((char*)jl_bits_data(v), nb); #else return h ^ memhash32((char*)jl_bits_data(v), nb); #endif } } if (tv == (jl_value_t*)jl_union_kind) { #ifdef __LP64__ return jl_object_id(jl_fieldref(v,0))^0xA5A5A5A5A5A5A5A5L; #else return jl_object_id(jl_fieldref(v,0))^0xA5A5A5A5; #endif } if (jl_is_struct_type(tv)) return inthash((uptrint_t)v); assert(jl_is_tuple(v)); uptrint_t h = 0; size_t l = jl_tuple_len(v); for(size_t i = 0; i < l; i++) { uptrint_t u = jl_object_id(jl_tupleref(v,i)); h = bitmix(h, u); } return h; }
static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) { if (v == NULL) return 0; jl_datatype_t *tv = (jl_datatype_t*)jl_typeof(v); if (tv == jl_tvar_type) { jl_varidx_t *pe = env; int i = 0; while (pe != NULL) { if (pe->var == (jl_tvar_t*)v) return (i<<8) + 42; i++; pe = pe->prev; } return inthash((uintptr_t)v); } if (tv == jl_uniontype_type) { return bitmix(bitmix(jl_object_id((jl_value_t*)tv), type_object_id_(((jl_uniontype_t*)v)->a, env)), type_object_id_(((jl_uniontype_t*)v)->b, env)); } if (tv == jl_unionall_type) { jl_unionall_t *u = (jl_unionall_t*)v; uintptr_t h = u->var->name->hash; h = bitmix(h, type_object_id_(u->var->lb, env)); h = bitmix(h, type_object_id_(u->var->ub, env)); jl_varidx_t e = { u->var, env }; return bitmix(h, type_object_id_(u->body, &e)); } if (tv == jl_datatype_type) { uintptr_t h = ~((jl_datatype_t*)v)->name->hash; size_t i, l = jl_nparams(v); for (i = 0; i < l; i++) { h = bitmix(h, type_object_id_(jl_tparam(v, i), env)); } return h; } return jl_object_id_((jl_value_t*)tv, v); }