static inline int sig_match_simple(jl_value_t **args, size_t n, jl_value_t **sig, int va, size_t lensig) { // NOTE: This function is a performance hot spot!! size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { jl_value_t *decl = sig[i]; jl_value_t *a = args[i]; if (decl == (jl_value_t*)jl_any_type || ((jl_value_t*)jl_typeof(a) == decl)) { /* we are only matching concrete types here, and those types are hash-consed, so pointer comparison should work. */ continue; } jl_value_t *unw = jl_is_unionall(decl) ? ((jl_unionall_t*)decl)->body : decl; if (jl_is_type_type(unw) && jl_is_type(a)) { jl_value_t *tp0 = jl_tparam0(unw); if (jl_is_typevar(tp0)) { // in the case of Type{_}, the types don't have to match exactly. // this is cached as `Type{T} where T`. if (((jl_tvar_t*)tp0)->ub != (jl_value_t*)jl_any_type && !jl_subtype(a, ((jl_tvar_t*)tp0)->ub)) return 0; } else { if (a != tp0) { if (jl_typeof(a) != jl_typeof(tp0)) return 0; jl_datatype_t *da = (jl_datatype_t*)a; jl_datatype_t *dt = (jl_datatype_t*)tp0; while (jl_is_unionall(da)) da = (jl_datatype_t*)((jl_unionall_t*)da)->body; while (jl_is_unionall(dt)) dt = (jl_datatype_t*)((jl_unionall_t*)dt)->body; if (jl_is_datatype(da) && jl_is_datatype(dt) && da->name != dt->name) return 0; if (!jl_types_equal(a, tp0)) return 0; } } } else { return 0; } } if (va) { jl_value_t *decl = sig[i]; if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n-i != jl_unbox_long(jl_tparam1(decl))) return 0; } jl_value_t *t = jl_unwrap_vararg(decl); for(; i < n; i++) { if (!jl_isa(args[i], t)) return 0; } return 1; } return 1; }
// this is the general entry point for looking up a type in the cache // (as a subtype, or with typeseq) jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_tupletype_t *types, jl_svec_t **penv, int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs) { if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; // called object is the primary key for constructors, otherwise first argument jl_value_t *ty = NULL; size_t l = jl_datatype_nfields(types); // compute the type at offset `offs` into `types`, which may be a Vararg if (l <= offs + 1) { ty = jl_tparam(types, l - 1); if (jl_is_vararg_type(ty)) ty = jl_tparam0(ty); else if (l <= offs) ty = NULL; } else if (l > offs) { ty = jl_tparam(types, offs); } // If there is a type at offs, look in the optimized caches if (ty) { if (!subtype && jl_is_any(ty)) return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); if (cache->targ != (void*)jl_nothing && jl_is_type_type(ty)) { jl_value_t *a0 = jl_tparam0(ty); if (jl_is_datatype(a0)) { union jl_typemap_t ml = mtcache_hash_lookup(cache->targ, a0, 1, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); if (li) return li; } } } if (cache->arg1 != (void*)jl_nothing && jl_is_datatype(ty)) { union jl_typemap_t ml = mtcache_hash_lookup(cache->arg1, ty, 0, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); if (li) return li; } } } // Always check the list (since offs doesn't always start at 0) if (subtype) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv, penv); if (li) return li; return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); } else { return jl_typemap_lookup_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv); } } else { return subtype ? jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv, penv) : jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv); } }
// this is a heuristic for allowing "redefining" a type to something identical static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) { if (!(jl_typeof(dta) == jl_typeof(dtb) && dta->name->name == dtb->name->name && dta->abstract == dtb->abstract && dta->mutabl == dtb->mutabl && dta->size == dtb->size && dta->ninitialized == dtb->ninitialized && jl_egal((jl_value_t*)dta->name->names, (jl_value_t*)dtb->name->names) && jl_nparams(dta) == jl_nparams(dtb) && jl_field_count(dta) == jl_field_count(dtb))) return 0; jl_value_t *a=NULL, *b=NULL; int ok = 1; size_t i, nf = jl_field_count(dta); JL_GC_PUSH2(&a, &b); a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper); b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper); if (!jl_types_equal(a, b)) goto no; JL_TRY { a = jl_apply_type(dtb->name->wrapper, jl_svec_data(dta->parameters), jl_nparams(dta)); } JL_CATCH { ok = 0; } if (!ok) goto no; assert(jl_is_datatype(a)); a = dta->name->wrapper; b = dtb->name->wrapper; while (jl_is_unionall(a)) { jl_unionall_t *ua = (jl_unionall_t*)a; jl_unionall_t *ub = (jl_unionall_t*)b; if (!jl_egal(ua->var->lb, ub->var->lb) || !jl_egal(ua->var->ub, ub->var->ub) || ua->var->name != ub->var->name) goto no; a = jl_instantiate_unionall(ua, (jl_value_t*)ub->var); b = ub->body; } assert(jl_is_datatype(a) && jl_is_datatype(b)); for (i=0; i < nf; i++) { jl_value_t *ta = jl_svecref(((jl_datatype_t*)a)->types, i); jl_value_t *tb = jl_svecref(((jl_datatype_t*)b)->types, i); if (jl_has_free_typevars(ta)) { if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb)) goto no; } else if (jl_has_free_typevars(tb) || jl_typeof(ta) != jl_typeof(tb) || !jl_types_equal(ta, tb)) { goto no; } } JL_GC_POP(); return 1; no: JL_GC_POP(); return 0; }
// count the homogeneous floating agregate size (saturating at max count of 8) unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const { size_t i, l = ty->layout->nfields; // handle homogeneous float aggregates if (l == 0) { if (ty != jl_float64_type && ty != jl_float32_type) return 9; *hva = false; if (*ty0 == NULL) *ty0 = ty; else if (*hva || ty->size != (*ty0)->size) return 9; return 1; } // handle homogeneous vector aggregates jl_datatype_t *fld0 = (jl_datatype_t*)jl_field_type(ty, 0); if (!jl_is_datatype(fld0) || ty->name == jl_vecelement_typename) return 9; if (fld0->name == jl_vecelement_typename) { if (!jl_is_primitivetype(jl_tparam0(fld0)) || jl_datatype_size(ty) > 16) return 9; if (l != 1 && l != 2 && l != 4 && l != 8 && l != 16) return 9; *hva = true; if (*ty0 == NULL) *ty0 = ty; else if (!*hva || ty->size != (*ty0)->size) return 9; for (i = 1; i < l; i++) { jl_datatype_t *fld = (jl_datatype_t*)jl_field_type(ty, i); if (fld != fld0) return 9; } return 1; } // recurse through other struct types int n = 0; for (i = 0; i < l; i++) { jl_datatype_t *fld = (jl_datatype_t*)jl_field_type(ty, i); if (!jl_is_datatype(fld) || ((jl_datatype_t*)fld)->layout == NULL) return 9; n += isHFA((jl_datatype_t*)fld, ty0, hva); if (n > 8) return 9; } return n; }
JL_DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *dt, void *data) { // data may not have the alignment required by the size // but will always have the alignment required by the datatype jl_ptls_t ptls = jl_get_ptls_states(); assert(jl_is_datatype(dt)); jl_datatype_t *bt = (jl_datatype_t*)dt; size_t nb = jl_datatype_size(bt); // some types have special pools to minimize allocations if (nb == 0) return jl_new_struct_uninit(bt); // returns bt->instance if (bt == jl_bool_type) return (1 & *(int8_t*)data) ? jl_true : jl_false; if (bt == jl_uint8_type) return jl_box_uint8(*(uint8_t*)data); if (bt == jl_int64_type) return jl_box_int64(*(int64_t*)data); if (bt == jl_int32_type) return jl_box_int32(*(int32_t*)data); if (bt == jl_int8_type) return jl_box_int8(*(int8_t*)data); if (bt == jl_int16_type) return jl_box_int16(*(int16_t*)data); if (bt == jl_uint64_type) return jl_box_uint64(*(uint64_t*)data); if (bt == jl_uint32_type) return jl_box_uint32(*(uint32_t*)data); if (bt == jl_uint16_type) return jl_box_uint16(*(uint16_t*)data); if (bt == jl_char_type) return jl_box_char(*(uint32_t*)data); jl_value_t *v = jl_gc_alloc(ptls, nb, bt); switch (nb) { case 1: *(uint8_t*) v = *(uint8_t*)data; break; case 2: *(uint16_t*)v = jl_load_unaligned_i16(data); break; case 4: *(uint32_t*)v = jl_load_unaligned_i32(data); break; case 8: *(uint64_t*)v = jl_load_unaligned_i64(data); break; case 16: memcpy(jl_assume_aligned(v, 16), data, 16); break; default: memcpy(v, data, nb); } return v; }
static void show_type(jl_value_t *st, jl_value_t *t) { uv_stream_t *s =((uv_stream_t**)st)[1]; if (jl_is_uniontype(t)) { if (t == (jl_value_t*)jl_bottom_type) { JL_WRITE(s, "None", 4); } else if (t == jl_top_type) { JL_WRITE(s, "Top", 3); } else { JL_WRITE(s, "Union", 5); jl_show_tuple(st, ((jl_uniontype_t*)t)->types, '(', ')', 0); } } else if (jl_is_vararg_type(t)) { jl_show(st, jl_tparam0(t)); JL_WRITE(s, "...", 3); } else if (jl_is_typector(t)) { jl_show(st, (jl_value_t*)((jl_typector_t*)t)->body); } else { assert(jl_is_datatype(t)); jl_datatype_t *tt = (jl_datatype_t*)t; JL_PUTS(tt->name->name->name, s); jl_tuple_t *p = tt->parameters; if (jl_tuple_len(p) > 0) jl_show_tuple(st, p, '{', '}', 0); } }
jl_typemap_entry_t *jl_typemap_level_assoc_exact(jl_typemap_level_t *cache, jl_value_t **args, size_t n, int8_t offs) { if (n > offs) { jl_value_t *a1 = args[offs]; jl_value_t *ty = (jl_value_t*)jl_typeof(a1); assert(jl_is_datatype(ty)); if (ty == (jl_value_t*)jl_datatype_type && cache->targ.values != (void*)jl_nothing) { union jl_typemap_t ml_or_cache = mtcache_hash_lookup(&cache->targ, a1, 1, offs); jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); if (ml) return ml; } if (cache->arg1.values != (void*)jl_nothing) { union jl_typemap_t ml_or_cache = mtcache_hash_lookup(&cache->arg1, ty, 0, offs); jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); if (ml) return ml; } } if (cache->linear != (jl_typemap_entry_t*)jl_nothing) { jl_typemap_entry_t *ml = jl_typemap_entry_assoc_exact(cache->linear, args, n); if (ml) return ml; } if (cache->any.unknown != jl_nothing) return jl_typemap_assoc_exact(cache->any, args, n, offs+1); return NULL; }
static void push_root(jl_value_t *v) { assert(v != NULL); if (gc_marked(v)) return; jl_value_t *vt = (jl_value_t*)jl_typeof(v); #ifdef OBJPROFILE void **bp = ptrhash_bp(&obj_counts, vt); if (*bp == HT_NOTFOUND) *bp = (void*)2; else (*((ptrint_t*)bp))++; #endif gc_setmark(v); if (vt == (jl_value_t*)jl_weakref_type || (jl_is_datatype(vt) && ((jl_datatype_t*)vt)->pointerfree)) { return; } if (mark_sp >= mark_stack_size) { size_t newsz = mark_stack_size>0 ? mark_stack_size*2 : 32000; mark_stack = (jl_value_t**)realloc(mark_stack,newsz*sizeof(void*)); if (mark_stack == NULL) exit(1); mark_stack_size = newsz; } mark_stack[mark_sp++] = v; }
// Note that this function updates len static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len) { assert(jl_is_datatype(dt)); jl_datatype_t *bt = (jl_datatype_t*)dt; size_t nb = jl_datatype_size(bt); if (nb == 0) return jl_new_struct_uninit(bt); *len = LLT_ALIGN(*len, bt->alignment); data = (char*)data + (*len); *len += nb; if (bt == jl_uint8_type) return jl_box_uint8(*(uint8_t*)data); if (bt == jl_int64_type) return jl_box_int64(*(int64_t*)data); if (bt == jl_bool_type) return (*(int8_t*)data) ? jl_true:jl_false; if (bt == jl_int32_type) return jl_box_int32(*(int32_t*)data); if (bt == jl_float64_type) return jl_box_float64(*(double*)data); jl_value_t *v = (jl_value_t*)newobj((jl_value_t*)bt, NWORDS(nb)); switch (nb) { case 1: *(int8_t*) jl_data_ptr(v) = *(int8_t*)data; break; case 2: *(int16_t*) jl_data_ptr(v) = *(int16_t*)data; break; case 4: *(int32_t*) jl_data_ptr(v) = *(int32_t*)data; break; case 8: *(int64_t*) jl_data_ptr(v) = *(int64_t*)data; break; case 16: *(bits128_t*)jl_data_ptr(v) = *(bits128_t*)data; break; default: memcpy(jl_data_ptr(v), data, nb); } return v; }
// this is the general entry point for looking up a type in the cache // (as a subtype, or with typeseq) jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_tupletype_t *types, jl_svec_t **penv, int8_t subtype_inexact__sigseq_useenv, int8_t subtype, int8_t offs) { if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; // called object is the primary key for constructors, otherwise first argument jl_value_t *ty = NULL; if (jl_datatype_nfields(types) > offs) { ty = jl_tparam(types, offs); if (cache->targ != (void*)jl_nothing && jl_is_type_type(ty)) { jl_value_t *a0 = jl_tparam0(ty); if (jl_is_datatype(a0)) { union jl_typemap_t ml = mtcache_hash_lookup(cache->targ, a0, 1, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); if (li) return li; } } } if (cache->arg1 != (void*)jl_nothing && jl_is_datatype(ty)) { union jl_typemap_t ml = mtcache_hash_lookup(cache->arg1, ty, 0, offs); if (ml.unknown != jl_nothing) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type(ml, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); if (li) return li; } } } if (subtype) { jl_typemap_entry_t *li = jl_typemap_assoc_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv, penv); if (li) return li; return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); } else { if (ty && jl_is_any(ty)) return jl_typemap_assoc_by_type(cache->any, types, penv, subtype_inexact__sigseq_useenv, subtype, offs+1); else return jl_typemap_lookup_by_type_(cache->linear, types, subtype_inexact__sigseq_useenv); } } else { return subtype ? jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv, penv) : jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, subtype_inexact__sigseq_useenv); } }
static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx) { if (jl_is_expr(e)) return ((jl_expr_t*)e)->etype; if (jl_is_symbolnode(e)) return jl_symbolnode_type(e); if (jl_is_quotenode(e)) return (jl_value_t*)jl_typeof(jl_fieldref(e,0)); if (jl_is_lambda_info(e)) return (jl_value_t*)jl_function_type; if (jl_is_getfieldnode(e)) { jl_value_t *v = static_eval(e, ctx); if (v == NULL) return jl_getfieldnode_type(e); e = v; goto type_of_constant; } if (jl_is_topnode(e)) { e = jl_fieldref(e,0); jl_binding_t *b = jl_get_binding(topmod(ctx), (jl_sym_t*)e); if (!b || !b->value) return jl_top_type; if (b->constp) { e = b->value; goto type_of_constant; } else { return (jl_value_t*)jl_any_type; } } if (jl_is_symbol(e)) { if (jl_is_symbol(e)) { if (is_global((jl_sym_t*)e, ctx)) { // look for static parameter for(size_t i=0; i < jl_tuple_len(ctx->sp); i+=2) { assert(jl_is_symbol(jl_tupleref(ctx->sp, i))); if (e == jl_tupleref(ctx->sp, i)) { e = jl_tupleref(ctx->sp, i+1); goto type_of_constant; } } } else { return (jl_value_t*)jl_any_type; } } jl_binding_t *b = jl_get_binding(ctx->module, (jl_sym_t*)e); if (!b || !b->value) return jl_top_type; if (b->constp) e = b->value; else return (jl_value_t*)jl_any_type; } type_of_constant: if (jl_is_datatype(e) || jl_is_uniontype(e) || jl_is_typector(e)) return (jl_value_t*)jl_wrap_Type(e); return (jl_value_t*)jl_typeof(e); }
jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f, jl_tuple_t *t) { jl_value_t *gf; if (bnd) { //jl_declare_constant(bnd); if (bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_datatype(gf) && ((jl_function_t*)gf)->fptr == jl_f_ctor_trampoline) { jl_add_constructors((jl_datatype_t*)gf); } if (!jl_is_gf(gf)) { jl_error("invalid method definition: not a generic function"); } } } JL_GC_PUSH1(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); for(size_t i=0; i < jl_tuple_len(argtypes); i++) { jl_value_t *elt = jl_tupleref(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_errorf("invalid type for argument %s in method definition for %s at %s:%d", jl_is_expr(li->ast) ? ((jl_sym_t*)jl_arrayref(jl_lam_args((jl_expr_t*)li->ast),i))->name : "?", name->name, li->file->name, li->line); } } for(size_t i=0; i < jl_tuple_len(t); i++) { if (!jl_is_typevar(jl_tupleref(t,i))) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, jl_tupleref(t,i)); } jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }
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; }
static int type_contains(jl_value_t *ty, jl_value_t *x) { if (ty == x) return 1; if (jl_is_uniontype(ty)) return svec_contains((jl_svec_t*)jl_fieldref(ty,0), x); if (jl_is_datatype(ty)) return svec_contains(((jl_datatype_t*)ty)->parameters, x); return 0; }
int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs, struct typemap_intersection_env *closure) { if (jl_typeof(map.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = map.node; jl_value_t *ty = NULL; jl_value_t *ttypes = jl_unwrap_unionall(closure->type); assert(jl_is_datatype(ttypes)); size_t l = jl_field_count(ttypes); if (closure->va && l <= offs + 1) { ty = closure->va; } else if (l > offs) { ty = jl_tparam(ttypes, offs); } if (ty) { if (cache->targ.values != (void*)jl_nothing) { jl_value_t *typetype = jl_is_type_type(ty) ? jl_tparam0(ty) : NULL; if (typetype && !jl_has_free_typevars(typetype)) { if (is_cache_leaf(typetype)) { // direct lookup of leaf types union jl_typemap_t ml = mtcache_hash_lookup(&cache->targ, typetype, 1, offs); if (ml.unknown != jl_nothing) { if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; } } } else { // else an array scan is required to check subtypes // first, fast-path: optimized pre-intersection test to see if `ty` could intersect with any Type if (typetype || !jl_has_empty_intersection((jl_value_t*)jl_type_type, ty)) if (!jl_typemap_intersection_array_visitor(&cache->targ, ty, 1, offs, closure)) return 0; } } if (cache->arg1.values != (void*)jl_nothing) { if (is_cache_leaf(ty)) { // direct lookup of leaf types union jl_typemap_t ml = mtcache_hash_lookup(&cache->arg1, ty, 0, offs); if (ml.unknown != jl_nothing) { if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; } } else { // else an array scan is required to check subtypes if (!jl_typemap_intersection_array_visitor(&cache->arg1, ty, 0, offs, closure)) return 0; } } } if (!jl_typemap_intersection_node_visitor(map.node->linear, closure)) return 0; return jl_typemap_intersection_visitor(map.node->any, offs+1, closure); } else { return jl_typemap_intersection_node_visitor(map.leaf, closure); } }
// run time version of pointerref intrinsic DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i) { JL_TYPECHK(pointerref, pointer, p); JL_TYPECHK(pointerref, long, i); jl_value_t *ety = jl_tparam0(jl_typeof(p)); if (!jl_is_datatype(ety)) jl_error("pointerref: invalid pointer"); size_t nb = jl_datatype_size(ety); char *pp = (char*)jl_unbox_long(p) + (jl_unbox_long(i)-1)*nb; return jl_new_bits(ety, pp); }
Type *preferred_llvm_type(jl_value_t *ty, bool isret) { // Arguments are either scalar or passed by value if (!isret || !jl_is_datatype(ty) || jl_is_abstracttype(ty)) return NULL; jl_datatype_t *dt = (jl_datatype_t*)ty; // rewrite integer sized (non-sret) struct to the corresponding integer if (!dt->nfields) return NULL; return Type::getIntNTy(jl_LLVMContext, dt->size * 8); }
CXX_WRAP_EXPORT jl_datatype_t* julia_type(const std::string& name) { for(jl_module_t* mod : {jl_base_module, g_cxx_wrap_module, jl_current_module}) { jl_value_t* gval = jl_get_global(mod, jl_symbol(name.c_str())); if(gval != nullptr && jl_is_datatype(gval)) { return (jl_datatype_t*)gval; } } throw std::runtime_error("Symbol for type " + name + " was not found"); }
jl_typemap_entry_t *jl_typemap_assoc_exact(union jl_typemap_t ml_or_cache, jl_value_t **args, size_t n, int8_t offs) { // NOTE: This function is a huge performance hot spot!! if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_level_type) { jl_typemap_level_t *cache = ml_or_cache.node; if (n > offs) { jl_value_t *a1 = args[offs]; jl_value_t *ty = (jl_value_t*)jl_typeof(a1); assert(jl_is_datatype(ty)); if (ty == (jl_value_t*)jl_datatype_type && cache->targ != (void*)jl_nothing) { ml_or_cache = mtcache_hash_lookup(cache->targ, a1, 1, offs); jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); if (ml) return ml; } if (cache->arg1 != (void*)jl_nothing) { ml_or_cache = mtcache_hash_lookup(cache->arg1, ty, 0, offs); if (jl_typeof(ml_or_cache.unknown) == (jl_value_t*)jl_typemap_entry_type && ml_or_cache.leaf->simplesig == (void*)jl_nothing && offs < 2 && n > 1) { jl_value_t *a0 = args[1-offs]; jl_value_t *t0 = (jl_value_t*)jl_typeof(a0); if (ml_or_cache.leaf->next==(void*)jl_nothing && n==2 && jl_datatype_nfields(ml_or_cache.leaf->sig)==2 && jl_tparam(ml_or_cache.leaf->sig, 1 - offs) == t0) return ml_or_cache.leaf; if (n==3) { // some manually-unrolled common special cases jl_value_t *a2 = args[2]; if (!jl_is_tuple(a2)) { // issue #6426 jl_typemap_entry_t *mn = ml_or_cache.leaf; if (jl_datatype_nfields(mn->sig)==3 && jl_tparam(mn->sig,1-offs)==t0 && jl_tparam(mn->sig,2)==(jl_value_t*)jl_typeof(a2)) return mn; mn = mn->next; if (mn!=(void*)jl_nothing && jl_datatype_nfields(mn->sig)==3 && jl_tparam(mn->sig,1-offs)==t0 && jl_tparam(mn->sig,2)==(jl_value_t*)jl_typeof(a2)) return mn; } } } jl_typemap_entry_t *ml = jl_typemap_assoc_exact(ml_or_cache, args, n, offs+1); if (ml) return ml; } } jl_typemap_entry_t *ml = jl_typemap_node_assoc_exact(cache->linear, args, n); if (ml) return ml; return jl_typemap_assoc_exact(cache->any, args, n, offs+1); } else { return jl_typemap_node_assoc_exact(ml_or_cache.leaf, args, n); } }
// run time version of pointerset intrinsic DLLEXPORT void jl_pointerset(jl_value_t *p, jl_value_t *x, jl_value_t *i) { JL_TYPECHK(pointerset, pointer, p); JL_TYPECHK(pointerset, long, i); jl_value_t *ety = jl_tparam0(jl_typeof(p)); if (!jl_is_datatype(ety)) jl_error("pointerset: invalid pointer"); size_t nb = jl_datatype_size(ety); char *pp = (char*)jl_unbox_long(p) + (jl_unbox_long(i)-1)*nb; if (jl_typeof(x) != ety) jl_error("pointerset: type mismatch in assign"); jl_assign_bits(pp, x); }
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) { if (!jl_is_datatype(super) || super == (jl_value_t*)jl_undef_type || !jl_is_abstracttype(super) || jl_subtype(super,(jl_value_t*)jl_type_type,0)) { jl_errorf("invalid subtyping in definition of %s",tt->name->name->name); } tt->super = (jl_datatype_t*)super; if (jl_tuple_len(tt->parameters) > 0) { tt->name->cache = (jl_value_t*)jl_null; jl_reinstantiate_inner_types(tt); } }
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) { if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || tt->name == ((jl_datatype_t*)super)->name || jl_subtype(super,(jl_value_t*)jl_vararg_type,0) || jl_is_tuple_type(super) || jl_subtype(super,(jl_value_t*)jl_type_type,0) || super == (jl_value_t*)jl_builtin_type) { jl_errorf("invalid subtyping in definition of %s", jl_symbol_name(tt->name->name)); } tt->super = (jl_datatype_t*)super; jl_gc_wb(tt, tt->super); }
// this is used to wrap values for generic contexts, where a // dynamically-typed value is required (e.g. argument to unknown function). // if it's already a pointer it's left alone. static Value *boxed(Value *v, jl_value_t *jt) { Type *t = v->getType(); if (t == jl_pvalue_llvmt) return v; if (t == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); if (t == T_int1) return julia_bool(v); if (jt == NULL) jt = julia_type_of(v); jl_datatype_t *jb = (jl_datatype_t*)jt; assert(jl_is_datatype(jb)); if (jb == jl_int8_type) return builder.CreateCall(box_int8_func, builder.CreateSExt(v, T_int32)); if (jb == jl_int16_type) return builder.CreateCall(box_int16_func, v); if (jb == jl_int32_type) return builder.CreateCall(box_int32_func, v); if (jb == jl_int64_type) return builder.CreateCall(box_int64_func, v); if (jb == jl_float32_type) return builder.CreateCall(box_float32_func, v); //if (jb == jl_float64_type) return builder.CreateCall(box_float64_func, v); if (jb == jl_float64_type) { // manually inline alloc & init of Float64 box. cheap, I know. #ifdef _P64 Value *newv = builder.CreateCall(jlalloc2w_func); #else Value *newv = builder.CreateCall(jlalloc3w_func); #endif return init_bits_value(newv, literal_pointer_val(jt), t, v); } if (jb == jl_uint8_type) return builder.CreateCall(box_uint8_func, builder.CreateZExt(v, T_int32)); if (jb == jl_uint16_type) return builder.CreateCall(box_uint16_func, v); if (jb == jl_uint32_type) return builder.CreateCall(box_uint32_func, v); if (jb == jl_uint64_type) return builder.CreateCall(box_uint64_func, v); if (jb == jl_char_type) return builder.CreateCall(box_char_func, v); // TODO: skip the call for constant arguments if (!jl_isbits(jt)) { assert("Don't know how to box this type" && false); return NULL; } if (!jb->abstract && jb->size == 0) { if (jb->instance == NULL) jl_new_struct_uninit(jb); assert(jb->instance != NULL); return literal_pointer_val(jb->instance); } return allocate_box_dynamic(literal_pointer_val(jt),jl_datatype_size(jt),v); }
// run time version of pointerref intrinsic (warning: i is not rooted) JL_DLLEXPORT jl_value_t *jl_pointerref(jl_value_t *p, jl_value_t *i) { JL_TYPECHK(pointerref, pointer, p); JL_TYPECHK(pointerref, long, i); jl_value_t *ety = jl_tparam0(jl_typeof(p)); if (ety == (jl_value_t*)jl_any_type) { jl_value_t **pp = (jl_value_t**)(jl_unbox_long(p) + (jl_unbox_long(i)-1)*sizeof(void*)); return *pp; } else { if (!jl_is_datatype(ety)) jl_error("pointerref: invalid pointer"); size_t nb = LLT_ALIGN(jl_datatype_size(ety), ((jl_datatype_t*)ety)->layout->alignment); char *pp = (char*)jl_unbox_long(p) + (jl_unbox_long(i)-1)*nb; return jl_new_bits(ety, pp); } }
static int type_contains(jl_value_t *ty, jl_value_t *x) { if (ty == x) return 1; if (jl_is_tuple(ty)) { size_t i, l=jl_tuple_len(ty); for(i=0; i < l; i++) { jl_value_t *e = jl_tupleref(ty,i); if (e==x || type_contains(e, x)) return 1; } } if (jl_is_uniontype(ty)) return type_contains(jl_fieldref(ty,0), x); if (jl_is_datatype(ty)) return type_contains((jl_value_t*)((jl_datatype_t*)ty)->parameters, x); return 0; }
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) { if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || tt->name == ((jl_datatype_t*)super)->name || jl_subtype(super,(jl_value_t*)jl_vararg_type,0) || jl_is_tuple_type(super) || jl_subtype(super,(jl_value_t*)jl_type_type,0)) { jl_errorf("invalid subtyping in definition of %s",tt->name->name->name); } tt->super = (jl_datatype_t*)super; jl_gc_wb(tt, tt->super); if (jl_svec_len(tt->parameters) > 0) { tt->name->cache = jl_emptysvec; tt->name->linearcache = jl_emptysvec; jl_reinstantiate_inner_types(tt); } }
static union jl_typemap_t *mtcache_hash_bp(struct jl_ordereddict_t *pa, jl_value_t *ty, int8_t tparam, int8_t offs, jl_value_t *parent) { if (jl_is_datatype(ty)) { uintptr_t uid = ((jl_datatype_t*)ty)->uid; if (!uid || is_kind(ty) || jl_has_typevars(ty)) // be careful not to put non-leaf types or DataType/TypeConstructor in the cache here, // since they should have a lower priority and need to go into the sorted list return NULL; if (pa->values == (void*)jl_nothing) { pa->indexes = jl_alloc_int_1d(0, INIT_CACHE_SIZE); jl_gc_wb(parent, pa->indexes); pa->values = jl_alloc_vec_any(0); jl_gc_wb(parent, pa->values); } while (1) { size_t slot = uid & (pa->indexes->nrows - 1); size_t idx = jl_intref(pa->indexes, slot); if (idx == 0) { jl_array_ptr_1d_push(pa->values, jl_nothing); idx = jl_array_len(pa->values); if (idx > jl_max_int(pa->indexes)) mtcache_rehash(pa, jl_array_len(pa->indexes), parent, tparam, offs); jl_intset(pa->indexes, slot, idx); return &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; } union jl_typemap_t *pml = &((union jl_typemap_t*)jl_array_data(pa->values))[idx - 1]; if (pml->unknown == jl_nothing) return pml; jl_value_t *t; if (jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_level_type) { t = pml->node->key; } else { assert(jl_typeof(pml->unknown) == (jl_value_t*)jl_typemap_entry_type); t = jl_field_type(pml->leaf->sig, offs); if (tparam) t = jl_tparam0(t); } if (t == ty) return pml; mtcache_rehash(pa, jl_array_len(pa->indexes) * 2, parent, tparam, offs); } } return NULL; }
DLLEXPORT void jl_show_any(jl_value_t *str, jl_value_t *v) { uv_stream_t *s = ((uv_stream_t**)str)[1]; // fallback for printing some other builtin types if (jl_is_tuple(v)) { jl_show_tuple(str, (jl_tuple_t*)v, '(', ')', 1); } else if (jl_is_type(v)) { show_type(str, v); } else if (jl_is_func(v)) { show_function(s, v); } else if (jl_typeis(v,jl_intrinsic_type)) { JL_PRINTF(s, "# intrinsic function %d", *(uint32_t*)jl_data_ptr(v)); } else { jl_value_t *t = (jl_value_t*)jl_typeof(v); assert(jl_is_datatype(t)); jl_datatype_t *dt = (jl_datatype_t*)t; show_type(str, t); JL_PUTC('(', s); if (jl_tuple_len(dt->names)>0 || dt->size==0) { size_t i; size_t n = jl_tuple_len(dt->names); for(i=0; i < n; i++) { jl_value_t *fval = jl_get_nth_field(v, i); if (fval == NULL) JL_PUTS("#undef", s); else jl_show(str, fval); if (i < n-1) JL_PUTC(',', s); } } else { size_t nb = jl_datatype_size(dt); char *data = (char*)jl_data_ptr(v); JL_PUTS("0x", s); for(int i=nb-1; i >= 0; --i) jl_printf(s, "%02hhx", data[i]); } JL_PUTC(')', s); } }
// run time version of pointerset intrinsic DLLEXPORT void jl_pointerset(jl_value_t *p, jl_value_t *x, jl_value_t *i) { JL_TYPECHK(pointerset, pointer, p); JL_TYPECHK(pointerset, long, i); jl_value_t *ety = jl_tparam0(jl_typeof(p)); if (ety == (jl_value_t*)jl_any_type) { jl_value_t **pp = (jl_value_t**)(jl_unbox_long(p) + (jl_unbox_long(i)-1)*sizeof(void*)); *pp = x; } else { if (!jl_is_datatype(ety)) jl_error("pointerset: invalid pointer"); size_t nb = LLT_ALIGN(jl_datatype_size(ety), ((jl_datatype_t*)ety)->alignment); char *pp = (char*)jl_unbox_long(p) + (jl_unbox_long(i)-1)*nb; if (jl_typeof(x) != ety) jl_error("pointerset: type mismatch in assign"); jl_assign_bits(pp, x); } }
JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) { jl_value_t *ftype = (jl_value_t*)jl_first_argument_datatype(type); if (ftype == NULL) return jl_static_show(s, type); size_t n = 0; if (jl_nparams(ftype)==0 || ftype == ((jl_datatype_t*)ftype)->name->wrapper) { n += jl_printf(s, "%s", jl_symbol_name(((jl_datatype_t*)ftype)->name->mt->name)); } else { n += jl_printf(s, "(::"); n += jl_static_show(s, ftype); n += jl_printf(s, ")"); } // TODO: better way to show method parameters type = jl_unwrap_unionall(type); if (!jl_is_datatype(type)) { n += jl_printf(s, " "); n += jl_static_show(s, type); return n; } size_t tl = jl_nparams(type); n += jl_printf(s, "("); size_t i; for (i = 1; i < tl; i++) { jl_value_t *tp = jl_tparam(type, i); if (i != tl - 1) { n += jl_static_show(s, tp); n += jl_printf(s, ", "); } else { if (jl_is_vararg_type(tp)) { n += jl_static_show(s, jl_unwrap_vararg(tp)); n += jl_printf(s, "..."); } else { n += jl_static_show(s, tp); } } } n += jl_printf(s, ")"); return n; }