Skip to content

Commit

Permalink
Switch jl_typemap_t from unions to bare pointers
Browse files Browse the repository at this point in the history
The clang static analyzer has very poor support for unions.
Thus in an attempt to get the GC analysis through without
any false positives, stop using unions for typemaps.
This commit should have no changes other than that.
GC annotations for this code will come after I rip
out the hacks to support unions from the static analyzer.
  • Loading branch information
Keno committed Aug 22, 2018
1 parent 81850b6 commit f2f1f43
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 151 deletions.
2 changes: 1 addition & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ static void add_builtin(const char *name, jl_value_t *v)
jl_fptr_args_t jl_get_builtin_fptr(jl_value_t *b)
{
assert(jl_isa(b, (jl_value_t*)jl_builtin_type));
return jl_gf_mtable(b)->cache.leaf->func.linfo->specptr.fptr1;
return ((jl_typemap_entry_t*)jl_gf_mtable(b)->cache)->func.linfo->specptr.fptr1;
}

static void add_builtin_func(const char *name, jl_fptr_args_t fptr)
Expand Down
19 changes: 9 additions & 10 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4861,15 +4861,14 @@ static Function *jl_cfunction_object(jl_value_t *ff, jl_value_t *declrt, jl_tupl
// first split on `ft` using a simple eqtable
// then use the typemap to split on argt
// and finally, pick declrt from the pair-list
union jl_typemap_t cache_l2 = { NULL };
// cache_l2.unknown = NULL;
jl_typemap_t *cache_l2 = NULL;
jl_typemap_entry_t *cache_l3 = NULL;
if (!jl_cfunction_list) {
jl_cfunction_list = jl_alloc_vec_any(16);
}
else {
cache_l2.unknown = jl_eqtable_get(jl_cfunction_list, ft, NULL);
if (cache_l2.unknown) {
cache_l2 = jl_eqtable_get(jl_cfunction_list, ft, NULL);
if (cache_l2) {
cache_l3 = jl_typemap_assoc_by_type(cache_l2, (jl_value_t*)argt, NULL,
/*subtype*/0, /*offs*/0, /*world*/1, /*max_world_mask*/0);
if (cache_l3) {
Expand All @@ -4886,13 +4885,13 @@ static Function *jl_cfunction_object(jl_value_t *ff, jl_value_t *declrt, jl_tupl
}

if (cache_l3 == NULL) {
union jl_typemap_t insert = cache_l2;
if (!insert.unknown)
insert.unknown = jl_nothing;
cache_l3 = jl_typemap_insert(&insert, (jl_value_t*)insert.unknown, (jl_tupletype_t*)argt,
jl_typemap_t *insert = cache_l2;
if (!insert)
insert = jl_nothing;
cache_l3 = jl_typemap_insert(&insert, (jl_value_t*)insert, (jl_tupletype_t*)argt,
NULL, jl_emptysvec, (jl_value_t*)jl_emptysvec, /*offs*/0, &cfunction_cache, 1, ~(size_t)0, NULL);
if (insert.unknown != cache_l2.unknown)
jl_cfunction_list = jl_eqtable_put(jl_cfunction_list, ft, insert.unknown, NULL);
if (insert != cache_l2)
jl_cfunction_list = jl_eqtable_put(jl_cfunction_list, ft, insert, NULL);
}

// compute / validate return type
Expand Down
4 changes: 2 additions & 2 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo
jl_methtable_type);
mt->name = jl_demangle_typename(name);
mt->module = module;
mt->defs.unknown = jl_nothing;
mt->cache.unknown = jl_nothing;
mt->defs = jl_nothing;
mt->cache = jl_nothing;
mt->max_args = 0;
mt->kwsorter = NULL;
mt->backedges = NULL;
Expand Down
19 changes: 9 additions & 10 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
arraylist_push(&reinit_list, (void*)pos);
arraylist_push(&reinit_list, (void*)3);
}
if (jl_is_method(v) && jl_typeof(((jl_method_t*)v)->specializations.unknown) == (jl_value_t*)jl_typemap_level_type) {
if (jl_is_method(v) && jl_typeof(((jl_method_t*)v)->specializations) == (jl_value_t*)jl_typemap_level_type) {
arraylist_push(&reinit_list, (void*)pos);
arraylist_push(&reinit_list, (void*)4);
}
Expand Down Expand Up @@ -781,8 +781,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)m->sig);
assert(jl_is_datatype(gf) && gf->name->mt);
external_mt = !module_in_worklist(gf->name->mt->module);
union jl_typemap_t *tf = &m->specializations;
jl_serialize_value(s, tf->unknown);
jl_serialize_value(s, m->specializations);
jl_serialize_value(s, (jl_value_t*)m->name);
jl_serialize_value(s, (jl_value_t*)m->file);
write_int32(s->s, m->line);
Expand All @@ -801,7 +800,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
jl_serialize_value(s, (jl_value_t*)m->source);
jl_serialize_value(s, (jl_value_t*)m->unspecialized);
jl_serialize_value(s, (jl_value_t*)m->generator);
jl_serialize_value(s, (jl_value_t*)m->invokes.unknown);
jl_serialize_value(s, (jl_value_t*)m->invokes);
}
else if (jl_is_method_instance(v)) {
write_uint8(s->s, TAG_METHOD_INSTANCE);
Expand Down Expand Up @@ -999,7 +998,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
jl_serialize_value(s, jl_nothing);
jl_serialize_value(s, node->targ.values);
jl_serialize_value(s, node->linear);
jl_serialize_value(s, node->any.unknown);
jl_serialize_value(s, node->any);
jl_serialize_value(s, node->key);
return;
}
Expand Down Expand Up @@ -1638,8 +1637,8 @@ static jl_value_t *jl_deserialize_value_method(jl_serializer_state *s, jl_value_
arraylist_push(&flagref_list, (void*)pos);
return (jl_value_t*)m;
}
m->specializations.unknown = jl_deserialize_value(s, (jl_value_t**)&m->specializations);
jl_gc_wb(m, m->specializations.unknown);
m->specializations = jl_deserialize_value(s, (jl_value_t**)&m->specializations);
jl_gc_wb(m, m->specializations);
m->name = (jl_sym_t*)jl_deserialize_value(s, NULL);
jl_gc_wb(m, m->name);
m->file = (jl_sym_t*)jl_deserialize_value(s, NULL);
Expand Down Expand Up @@ -1668,8 +1667,8 @@ static jl_value_t *jl_deserialize_value_method(jl_serializer_state *s, jl_value_
m->generator = jl_deserialize_value(s, (jl_value_t**)&m->generator);
if (m->generator)
jl_gc_wb(m, m->generator);
m->invokes.unknown = jl_deserialize_value(s, (jl_value_t**)&m->invokes);
jl_gc_wb(m, m->invokes.unknown);
m->invokes = jl_deserialize_value(s, (jl_value_t**)&m->invokes);
jl_gc_wb(m, m->invokes);
m->traced = 0;
JL_MUTEX_INIT(&m->writelock);
return (jl_value_t*)m;
Expand Down Expand Up @@ -2330,7 +2329,7 @@ static void jl_finalize_serializer(jl_serializer_state *s)
write_int32(s->s, -1);
}

void jl_typemap_rehash(union jl_typemap_t ml, int8_t offs);
void jl_typemap_rehash(jl_typemap_t *ml, int8_t offs);
static void jl_reinit_item(jl_value_t *v, int how, arraylist_t *tracee_list)
{
jl_ptls_t ptls = jl_get_ptls_states();
Expand Down
34 changes: 17 additions & 17 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ static void update_world_bound(jl_method_instance_t *replaced, jl_typemap_visito
// update the world-valid in the specializations caches
jl_typemap_visitor(m->specializations, fptr, (void*)&update);
// update the world-valid in the invoke cache
if (m->invokes.unknown != NULL)
if (m->invokes != NULL)
jl_typemap_visitor(m->invokes, fptr, (void*)&update);
// update the world-valid in the gf cache
jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)m->sig);
Expand Down Expand Up @@ -510,8 +510,8 @@ void jl_foreach_reachable_mtable(void (*visit)(jl_methtable_t *mt, void *env), v
static void reset_mt_caches(jl_methtable_t *mt, void *env)
{
// removes all method caches
if (mt->defs.unknown != jl_nothing) // make sure not to reset builtin functions
mt->cache.unknown = jl_nothing;
if (mt->defs != jl_nothing) // make sure not to reset builtin functions
mt->cache = jl_nothing;
jl_typemap_visitor(mt->defs, get_method_unspec_list, env);
}

Expand Down Expand Up @@ -576,7 +576,7 @@ jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i)
// return 1;
//}

static jl_value_t *ml_matches(union jl_typemap_t ml, int offs,
static jl_value_t *ml_matches(jl_typemap_t *ml, int offs,
jl_tupletype_t *type, int lim, int include_ambiguous,
size_t world, size_t *min_valid, size_t *max_valid);

Expand Down Expand Up @@ -921,7 +921,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig(
}

static jl_method_instance_t *cache_method(
jl_methtable_t *mt, union jl_typemap_t *cache, jl_value_t *parent JL_PROPAGATES_ROOT,
jl_methtable_t *mt, jl_typemap_t **cache, jl_value_t *parent JL_PROPAGATES_ROOT,
jl_tupletype_t *tt, // the original tupletype of the signature
jl_method_t *definition,
size_t world,
Expand Down Expand Up @@ -1152,7 +1152,7 @@ void print_func_loc(JL_STREAM *s, jl_method_t *m)
*/
struct ambiguous_matches_env {
struct typemap_intersection_env match;
union jl_typemap_t defs;
jl_typemap_t *defs;
jl_typemap_entry_t *newentry;
jl_value_t *shadowed;
int after;
Expand All @@ -1167,7 +1167,7 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_
}
if (oldentry->max_world < ~(size_t)0)
return 1;
union jl_typemap_t map = closure->defs;
jl_typemap_t *map = closure->defs;
jl_tupletype_t *type = (jl_tupletype_t*)closure->match.type;
jl_method_t *m = closure->newentry->func.method;
jl_tupletype_t *sig = oldentry->sig;
Expand Down Expand Up @@ -1248,7 +1248,7 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_
return 1;
}

static jl_value_t *check_ambiguous_matches(union jl_typemap_t defs, jl_typemap_entry_t *newentry, jl_typemap_intersection_visitor_fptr fptr)
static jl_value_t *check_ambiguous_matches(jl_typemap_t *defs, jl_typemap_entry_t *newentry, jl_typemap_intersection_visitor_fptr fptr)
{
jl_tupletype_t *type = newentry->sig;
jl_tupletype_t *ttypes = (jl_tupletype_t*)jl_unwrap_unionall((jl_value_t*)type);
Expand Down Expand Up @@ -1401,7 +1401,7 @@ static int invalidate_backedges(jl_typemap_entry_t *oldentry, struct typemap_int
jl_method_t *m = def.replaced->def.method;

// truncate the max-valid in the invoke cache
if (m->invokes.unknown != NULL)
if (m->invokes != NULL)
jl_typemap_visitor(m->invokes, set_max_world2, (void*)&def);
// invalidate mt cache entries
jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)m->sig);
Expand Down Expand Up @@ -2231,7 +2231,7 @@ jl_value_t *jl_gf_invoke(jl_value_t *types0, jl_value_t **args, size_t nargs)
jl_method_t *method = entry->func.method;
jl_method_instance_t *mfunc = NULL;
jl_typemap_entry_t *tm = NULL;
if (method->invokes.unknown != NULL)
if (method->invokes != NULL)
tm = jl_typemap_assoc_exact(method->invokes, args, nargs, jl_cachearg_offset(mt), world);
if (tm) {
mfunc = tm->func.linfo;
Expand All @@ -2244,8 +2244,8 @@ jl_value_t *jl_gf_invoke(jl_value_t *types0, jl_value_t **args, size_t nargs)
assert(sub); (void)sub;
}

if (method->invokes.unknown == NULL)
method->invokes.unknown = jl_nothing;
if (method->invokes == NULL)
method->invokes = jl_nothing;

mfunc = cache_method(mt, &method->invokes, entry->func.value, tt, method, world, tpenv, 1);
JL_UNLOCK(&method->writelock);
Expand All @@ -2265,7 +2265,7 @@ JL_DLLEXPORT jl_value_t *jl_get_invoke_lambda(jl_methtable_t *mt,

jl_method_t *method = entry->func.method;
jl_typemap_entry_t *tm = NULL;
if (method->invokes.unknown != NULL) {
if (method->invokes != NULL) {
tm = jl_typemap_assoc_by_type(method->invokes, tt, NULL, /*subtype*/1,
jl_cachearg_offset(mt), world, /*max_world_mask*/0);
if (tm) {
Expand All @@ -2274,7 +2274,7 @@ JL_DLLEXPORT jl_value_t *jl_get_invoke_lambda(jl_methtable_t *mt,
}

JL_LOCK(&method->writelock);
if (method->invokes.unknown != NULL) {
if (method->invokes != NULL) {
tm = jl_typemap_assoc_by_type(method->invokes, tt, NULL, /*subtype*/1,
jl_cachearg_offset(mt), world, /*max_world_mask*/0);
if (tm) {
Expand All @@ -2292,8 +2292,8 @@ JL_DLLEXPORT jl_value_t *jl_get_invoke_lambda(jl_methtable_t *mt,
(void)ti;
}

if (method->invokes.unknown == NULL)
method->invokes.unknown = jl_nothing;
if (method->invokes == NULL)
method->invokes = jl_nothing;

jl_method_instance_t *mfunc = cache_method(mt, &method->invokes, entry->func.value,
(jl_tupletype_t*)tt, method, world, tpenv, 1);
Expand Down Expand Up @@ -2488,7 +2488,7 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio
//
// Returns a match as an array of svec(argtypes, static_params, Method).
// See below for the meaning of lim.
static jl_value_t *ml_matches(union jl_typemap_t defs, int offs,
static jl_value_t *ml_matches(jl_typemap_t *defs, int offs,
jl_tupletype_t *type, int lim, int include_ambiguous,
size_t world, size_t *min_valid, size_t *max_valid)
{
Expand Down
26 changes: 14 additions & 12 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,7 @@ struct _jl_method_instance_t;
// when key is a leaftype, (but only when the tree has enough entries for this to be
// more efficient than storing them sorted linearly)
// otherwise the leaf entries are stored sorted, linearly
union jl_typemap_t {
struct _jl_typemap_level_t *node;
struct _jl_typemap_entry_t *leaf;
struct _jl_value_t *unknown; // nothing
};
typedef jl_value_t jl_typemap_t;

typedef jl_value_t *(jl_call_t)(struct _jl_method_instance_t*, jl_value_t**, uint32_t);
typedef jl_call_t *jl_callptr_t;
Expand Down Expand Up @@ -269,7 +265,7 @@ typedef struct _jl_method_t {
jl_value_t *ambig;

// table of all argument types for which we've inferred or compiled this code
union jl_typemap_t specializations;
jl_typemap_t *specializations;

jl_svec_t *sparam_syms; // symbols giving static parameter names
jl_value_t *source; // original code template (jl_code_info_t, but may be compressed), null for builtins
Expand All @@ -280,7 +276,7 @@ typedef struct _jl_method_t {
// cache of specializations of this method for invoke(), i.e.
// cases where this method was called even though it was not necessarily
// the most specific for the argument types.
union jl_typemap_t invokes;
jl_typemap_t *invokes;

int32_t nargs;
int32_t called; // bit flags: whether each of the first 8 arguments is called
Expand Down Expand Up @@ -478,23 +474,23 @@ typedef struct _jl_typemap_entry_t {
// indexed by key if it is a sublevel in an array
struct jl_ordereddict_t {
jl_array_t *indices; // Array{Int{8,16,32}}
jl_array_t *values; // Array{union jl_typemap_t}
jl_array_t *values; // Array{jl_typemap_t*}
};
typedef struct _jl_typemap_level_t {
JL_DATA_TYPE
struct jl_ordereddict_t arg1;
struct jl_ordereddict_t targ;
jl_typemap_entry_t *linear; // union jl_typemap_t (but no more levels)
union jl_typemap_t any; // type at offs is Any
jl_typemap_entry_t *linear; // jl_typemap_t * (but no more levels)
jl_typemap_t *any; // type at offs is Any
jl_value_t *key; // [nullable]
} jl_typemap_level_t;

// contains the TypeMap for one Type
typedef struct _jl_methtable_t {
JL_DATA_TYPE
jl_sym_t *name;
union jl_typemap_t defs;
union jl_typemap_t cache;
jl_typemap_t *defs;
jl_typemap_t *cache;
intptr_t max_args; // max # of non-vararg arguments in a signature
jl_value_t *kwsorter; // keyword argument sorter function
jl_module_t *module; // used for incremental serialization to locate original binding
Expand Down Expand Up @@ -1107,6 +1103,12 @@ STATIC_INLINE int jl_is_concrete_type(jl_value_t *v) JL_NOTSAFEPOINT
return jl_is_datatype(v) && ((jl_datatype_t*)v)->isconcretetype;
}

STATIC_INLINE jl_value_t *jl_typemap_entry_sig(jl_typemap_t *tmap) JL_NOTSAFEPOINT
{
assert(jl_typeof(tmap) == (jl_value_t*)jl_typemap_entry_type);
return (jl_value_t*)((jl_typemap_entry_t*)tmap)->sig;
}

// type constructors
JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule);
JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub);
Expand Down
20 changes: 11 additions & 9 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ struct jl_typemap_info {
jl_datatype_t **jl_contains; // the type that is being put in this
};

jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache,
jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache,
jl_value_t *parent JL_PROPAGATES_ROOT,
jl_tupletype_t *type,
jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
Expand All @@ -870,27 +870,29 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache,
jl_value_t **overwritten);

jl_typemap_entry_t *jl_typemap_assoc_by_type(
union jl_typemap_t ml_or_cache JL_PROPAGATES_ROOT,
jl_typemap_t *ml_or_cache JL_PROPAGATES_ROOT,
jl_value_t *types, jl_svec_t **penv,
int8_t subtype, int8_t offs, size_t world, size_t max_world_mask);
jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs, size_t world);
jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *mn, jl_value_t **args, size_t n, size_t world);
STATIC_INLINE jl_typemap_entry_t *jl_typemap_assoc_exact(
union jl_typemap_t ml_or_cache JL_PROPAGATES_ROOT,
jl_typemap_t *ml_or_cache JL_PROPAGATES_ROOT,
jl_value_t **args, size_t n, int8_t offs, size_t world)
{
// NOTE: This function is a huge performance hot spot!!
if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_entry_type) {
return jl_typemap_entry_assoc_exact(ml_or_cache.leaf, args, n, world);
if (jl_typeof(ml_or_cache) == (jl_value_t *)jl_typemap_entry_type) {
return jl_typemap_entry_assoc_exact(
(jl_typemap_entry_t *)ml_or_cache, args, n, world);
}
else if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) {
return jl_typemap_level_assoc_exact(ml_or_cache.node, args, n, offs, world);
else if (jl_typeof(ml_or_cache) == (jl_value_t*)jl_typemap_level_type) {
return jl_typemap_level_assoc_exact(
(jl_typemap_level_t *)ml_or_cache, args, n, offs, world);
}
return NULL;
}

typedef int (*jl_typemap_visitor_fptr)(jl_typemap_entry_t *l, void *closure);
int jl_typemap_visitor(union jl_typemap_t a, jl_typemap_visitor_fptr fptr, void *closure);
int jl_typemap_visitor(jl_typemap_t *a, jl_typemap_visitor_fptr fptr, void *closure);

struct typemap_intersection_env;
typedef int (*jl_typemap_intersection_visitor_fptr)(jl_typemap_entry_t *l, struct typemap_intersection_env *closure);
Expand All @@ -904,7 +906,7 @@ struct typemap_intersection_env {
jl_svec_t *env; // intersection env (initialize to null to perform intersection without an environment)
int issubty; // if `a <: b` is true in `intersect(a,b)`
};
int jl_typemap_intersection_visitor(union jl_typemap_t a, int offs, struct typemap_intersection_env *closure);
int jl_typemap_intersection_visitor(jl_typemap_t *a, int offs, struct typemap_intersection_env *closure);

unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *field_type);

Expand Down
Loading

0 comments on commit f2f1f43

Please sign in to comment.