static jl_typemap_entry_t *jl_typemap_lookup_by_type_(jl_typemap_entry_t *ml, jl_value_t *types, size_t world, size_t max_world_mask) { for (; ml != (void*)jl_nothing; ml = ml->next) { if (world < ml->min_world || world > (ml->max_world | max_world_mask)) continue; // unroll the first few cases here, to the extent that is possible to do fast and easily jl_value_t *a = jl_unwrap_unionall(types); jl_value_t *b = jl_unwrap_unionall((jl_value_t*)ml->sig); size_t na = jl_nparams(a); size_t nb = jl_nparams(b); int va_a = na > 0 && jl_is_vararg_type(jl_tparam(a, na - 1)); int va_b = nb > 0 && jl_is_vararg_type(jl_tparam(b, nb - 1)); if (!va_a && !va_b) { if (na != nb) continue; } if (na - va_a > 0 && nb - va_b > 0) { if (jl_obviously_unequal(jl_tparam(a, 0), jl_tparam(b, 0))) continue; if (na - va_a > 1 && nb - va_b > 1) { if (jl_obviously_unequal(jl_tparam(a, 1), jl_tparam(b, 1))) continue; if (na - va_a > 2 && nb - va_b > 2) { if (jl_obviously_unequal(jl_tparam(a, 2), jl_tparam(b, 2))) continue; } } } if (jl_types_equal((jl_value_t*)types, (jl_value_t*)ml->sig)) return ml; } return NULL; }
/* Method caches are divided into three parts: one for signatures where the first argument is a singleton kind (Type{Foo}), one indexed by the UID of the first argument's type in normal cases, and a fallback table of everything else. Note that the "primary key" is the type of the first *argument*, since there tends to be lots of variation there. The type of the 0th argument (the function) is always the same for most functions. */ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_value_t *types, jl_svec_t **penv, size_t world, size_t max_world_mask) { jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); int isua = jl_is_unionall(types); size_t n = jl_field_count(unw); int typesisva = n == 0 ? 0 : jl_is_vararg_type(jl_tparam(unw, n-1)); for (; ml != (void*)jl_nothing; ml = ml->next) { if (world < ml->min_world || world > (ml->max_world | max_world_mask)) continue; // ignore replaced methods size_t lensig = jl_field_count(jl_unwrap_unionall((jl_value_t*)ml->sig)); if (lensig == n || (ml->va && lensig <= n+1)) { int resetenv = 0, ismatch = 1; if (ml->simplesig != (void*)jl_nothing && !isua) { size_t lensimplesig = jl_field_count(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) ismatch = sig_match_by_type_simple(jl_svec_data(((jl_datatype_t*)types)->parameters), n, ml->simplesig, lensimplesig, isva); else ismatch = 0; } if (ismatch == 0) ; // nothing else if (ml->isleafsig && !typesisva && !isua) ismatch = sig_match_by_type_leaf(jl_svec_data(((jl_datatype_t*)types)->parameters), ml->sig, lensig); else if (ml->issimplesig && !typesisva && !isua) ismatch = sig_match_by_type_simple(jl_svec_data(((jl_datatype_t*)types)->parameters), n, ml->sig, lensig, ml->va); else { ismatch = jl_subtype_matching(types, (jl_value_t*)ml->sig, penv); if (ismatch && penv) resetenv = 1; } if (ismatch) { size_t i, l; for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { // see corresponding code in jl_typemap_entry_assoc_exact if (jl_subtype(types, jl_svecref(ml->guardsigs, i))) { ismatch = 0; break; } } if (ismatch) return ml; } if (resetenv) *penv = jl_emptysvec; } } return NULL; }
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); } }
// 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); } }
static int has_unions(jl_tupletype_t *type) { int i; for (i = 0; i < jl_nparams(type); i++) { jl_value_t *t = jl_tparam(type, i); if (jl_is_uniontype(t) || (jl_is_vararg_type(t) && jl_is_uniontype(jl_tparam0(t)))) return 1; } return 0; }
static int has_unions(jl_value_t *type) { type = jl_unwrap_unionall(type); int i; for (i = 0; i < jl_nparams(type); i++) { jl_value_t *t = jl_tparam(type, i); if (jl_is_uniontype(t) || (jl_is_vararg_type(t) && jl_is_uniontype(jl_unwrap_vararg(t)))) return 1; } return 0; }
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; }
static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, const struct jl_typemap_info *tparams) { jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)newrec->sig); size_t l = jl_field_count(ttypes); // compute the type at offset `offs` into `sig`, which may be a Vararg jl_value_t *t1 = NULL; int isva = 0; if (l <= offs + 1) { t1 = jl_tparam(ttypes, l - 1); if (jl_is_vararg_type(t1)) { isva = 1; t1 = jl_unwrap_vararg(t1); } else if (l <= offs) { t1 = NULL; } } else if (l > offs) { t1 = jl_tparam(ttypes, offs); } // If the type at `offs` is Any, put it in the Any list if (t1 && jl_is_any(t1)) { jl_typemap_insert_generic(&cache->any, (jl_value_t*)cache, newrec, (jl_value_t*)jl_any_type, offs+1, tparams); return; } // Don't put Varargs in the optimized caches (too hard to handle in lookup and bp) if (t1 && !isva) { // if t1 != jl_typetype_type and the argument is Type{...}, this // method has specializations for singleton kinds and we use // the table indexed for that purpose. if (t1 != (jl_value_t*)jl_typetype_type && jl_is_type_type(t1)) { jl_value_t *a0 = jl_tparam0(t1); if (jl_typemap_array_insert_(&cache->targ, a0, newrec, (jl_value_t*)cache, 1, offs, tparams)) return; } if (jl_typemap_array_insert_(&cache->arg1, t1, newrec, (jl_value_t*)cache, 0, offs, tparams)) return; } jl_typemap_list_insert_(&cache->linear, (jl_value_t*)cache, newrec, tparams); }
jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_value_t **args, size_t n) { // some manually-unrolled common special cases while (ml->simplesig == (void*)jl_nothing && ml->guardsigs == jl_emptysvec && ml->isleafsig) { // use a tight loop for a long as possible if (n == jl_field_count(ml->sig) && jl_typeof(args[0]) == jl_tparam(ml->sig, 0)) { if (n == 1) return ml; if (n == 2) { if (jl_typeof(args[1]) == jl_tparam(ml->sig, 1)) return ml; } else if (n == 3) { if (jl_typeof(args[1]) == jl_tparam(ml->sig, 1) && jl_typeof(args[2]) == jl_tparam(ml->sig, 2)) return ml; } else { if (sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n)) return ml; } } ml = ml->next; if (ml == (void*)jl_nothing) return NULL; } while (ml != (void*)jl_nothing) { size_t lensig = jl_field_count(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { if (ml->simplesig != (void*)jl_nothing) { size_t lensimplesig = jl_field_count(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) { if (!sig_match_simple(args, n, jl_svec_data(ml->simplesig->parameters), isva, lensimplesig)) goto nomatch; } else { goto nomatch; } } if (ml->isleafsig) { if (!sig_match_leaf(args, jl_svec_data(ml->sig->parameters), n)) goto nomatch; } else if (ml->issimplesig) { if (!sig_match_simple(args, n, jl_svec_data(ml->sig->parameters), ml->va, lensig)) goto nomatch; } else { if (!jl_tuple_subtype(args, n, ml->sig, 1)) goto nomatch; } size_t i, l; if (ml->guardsigs != jl_emptysvec) { for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { // checking guard entries require a more // expensive subtype check, since guard entries added for ANY might be // abstract. this fixed issue #12967. if (jl_tuple_subtype(args, n, (jl_tupletype_t*)jl_svecref(ml->guardsigs, i), 1)) { goto nomatch; } } } return ml; } nomatch: ml = ml->next; } return NULL; }
/* Method caches are divided into three parts: one for signatures where the first argument is a singleton kind (Type{Foo}), one indexed by the UID of the first argument's type in normal cases, and a fallback table of everything else. Note that the "primary key" is the type of the first *argument*, since there tends to be lots of variation there. The type of the 0th argument (the function) is always the same for most functions. */ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t inexact, jl_svec_t **penv) { size_t n = jl_field_count(types); while (ml != (void*)jl_nothing) { size_t lensig = jl_field_count(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { int resetenv = 0, ismatch = 1; if (ml->simplesig != (void*)jl_nothing) { size_t lensimplesig = jl_field_count(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) ismatch = sig_match_by_type_simple(jl_svec_data(types->parameters), n, ml->simplesig, lensimplesig, isva); else ismatch = 0; } if (ismatch == 0) ; // nothing else if (ml->isleafsig) ismatch = sig_match_by_type_leaf(jl_svec_data(types->parameters), ml->sig, lensig); else if (ml->issimplesig) ismatch = sig_match_by_type_simple(jl_svec_data(types->parameters), n, ml->sig, lensig, ml->va); else if (ml->tvars == jl_emptysvec) ismatch = jl_tuple_subtype(jl_svec_data(types->parameters), n, ml->sig, 0); else if (penv == NULL) { ismatch = jl_type_match((jl_value_t*)types, (jl_value_t*)ml->sig) != (jl_value_t*)jl_false; } else { // TODO: this is missing the actual subtype test, // which works currently because types is typically a leaf tt, // or inexact is set (which then does a sort of subtype test via jl_types_equal) // but this isn't entirely general jl_value_t *ti = jl_lookup_match((jl_value_t*)types, (jl_value_t*)ml->sig, penv, ml->tvars); resetenv = 1; ismatch = (ti != (jl_value_t*)jl_bottom_type); if (ismatch) { // parametric methods only match if all typevars are matched by // non-typevars. size_t i, l; for (i = 0, l = jl_svec_len(*penv); i < l; i++) { if (jl_is_typevar(jl_svecref(*penv, i))) { if (inexact) { // "inexact" means the given type is compile-time, // where a failure to determine the value of a // static parameter is inconclusive. // this is issue #3182, see test/core.jl return INEXACT_ENTRY; } ismatch = 0; break; } } if (inexact) { // the compiler might attempt jl_get_specialization on e.g. // convert(::Type{Type{Int}}, ::DataType), which is concrete but might not // equal the run time type. in this case ti would be {Type{Type{Int}}, Type{Int}} // but tt would be {Type{Type{Int}}, DataType}. JL_GC_PUSH1(&ti); ismatch = jl_types_equal(ti, (jl_value_t*)types); JL_GC_POP(); if (!ismatch) return INEXACT_ENTRY; } } } if (ismatch) { size_t i, l; for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { // see corresponding code in jl_typemap_assoc_exact if (jl_subtype((jl_value_t*)types, jl_svecref(ml->guardsigs, i), 0)) { ismatch = 0; break; } } if (ismatch) return ml; } if (resetenv) *penv = jl_emptysvec; } ml = ml->next; } return NULL; }
jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *parent, jl_tupletype_t *type, jl_svec_t *tvars, jl_tupletype_t *simpletype, jl_svec_t *guardsigs, jl_value_t *newvalue, int8_t offs, const struct jl_typemap_info *tparams, jl_value_t **overwritten) { jl_ptls_t ptls = jl_get_ptls_states(); assert(jl_is_tuple_type(type)); if (!simpletype) { simpletype = (jl_tupletype_t*)jl_nothing; } if ((jl_value_t*)simpletype == jl_nothing) { jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*cache, type, NULL, 1, 0, offs); if (ml && ml->simplesig == (void*)jl_nothing) { if (overwritten != NULL) *overwritten = ml->func.value; if (newvalue == NULL) // don't overwrite with guard entries return ml; // sigatomic begin ml->sig = type; jl_gc_wb(ml, ml->sig); ml->simplesig = simpletype; jl_gc_wb(ml, ml->simplesig); ml->tvars = tvars; jl_gc_wb(ml, ml->tvars); ml->va = jl_is_va_tuple(type); // TODO: `l->func` or `l->func->roots` might need to be rooted ml->func.value = newvalue; if (newvalue) jl_gc_wb(ml, newvalue); // sigatomic end return ml; } } if (overwritten != NULL) *overwritten = NULL; jl_typemap_entry_t *newrec = (jl_typemap_entry_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_entry_t), jl_typemap_entry_type); newrec->sig = type; newrec->simplesig = simpletype; newrec->tvars = tvars; newrec->func.value = newvalue; newrec->guardsigs = guardsigs; newrec->next = (jl_typemap_entry_t*)jl_nothing; // compute the complexity of this type signature newrec->va = jl_is_va_tuple(type); newrec->issimplesig = (tvars == jl_emptysvec); // a TypeVar environment needs an complex matching test newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted JL_GC_PUSH1(&newrec); size_t i, l; for (i = 0, l = jl_field_count(type); i < l && newrec->issimplesig; i++) { jl_value_t *decl = jl_field_type(type, i); if (decl == (jl_value_t*)jl_datatype_type) newrec->isleafsig = 0; // Type{} may have a higher priority than DataType else if (decl == (jl_value_t*)jl_typector_type) newrec->isleafsig = 0; // Type{} may have a higher priority than TypeConstructor else if (jl_is_type_type(decl)) newrec->isleafsig = 0; // Type{} may need special processing to compute the match else if (jl_is_vararg_type(decl)) newrec->isleafsig = 0; // makes iteration easier when the endpoints are the same else if (decl == (jl_value_t*)jl_any_type) newrec->isleafsig = 0; // Any needs to go in the general cache else if (!jl_is_leaf_type(decl)) // anything else can go through the general subtyping test newrec->isleafsig = newrec->issimplesig = 0; } // TODO: assert that guardsigs == jl_emptysvec && simplesig == jl_nothing if isleafsig and optimize with that knowledge? jl_typemap_insert_generic(cache, parent, newrec, NULL, offs, tparams); JL_GC_POP(); return newrec; }
// ccall(pointer, rettype, (argtypes...), args...) static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { JL_NARGSV(ccall, 3); jl_value_t *ptr=NULL, *rt=NULL, *at=NULL; Value *jl_ptr=NULL; JL_GC_PUSH(&ptr, &rt, &at); ptr = static_eval(args[1], ctx, true); if (ptr == NULL) { jl_value_t *ptr_ty = expr_type(args[1], ctx); Value *arg1 = emit_unboxed(args[1], ctx); if (!jl_is_cpointer_type(ptr_ty)) { emit_typecheck(arg1, (jl_value_t*)jl_voidpointer_type, "ccall: function argument not a pointer or valid constant", ctx); } jl_ptr = emit_unbox(T_size, T_psize, arg1); } rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); if (jl_is_tuple(rt)) { std::string msg = "in " + ctx->funcName + ": ccall: missing return type"; jl_error(msg.c_str()); } at = jl_interpret_toplevel_expr_in(ctx->module, args[3], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); void *fptr=NULL; char *f_name=NULL, *f_lib=NULL; if (ptr != NULL) { if (jl_is_tuple(ptr) && jl_tuple_len(ptr)==1) { ptr = jl_tupleref(ptr,0); } if (jl_is_symbol(ptr)) f_name = ((jl_sym_t*)ptr)->name; else if (jl_is_byte_string(ptr)) f_name = jl_string_data(ptr); if (f_name != NULL) { // just symbol, default to JuliaDLHandle #ifdef __WIN32__ //TODO: store the f_lib name instead of fptr fptr = jl_dlsym_win32(f_name); #else // will look in process symbol table #endif } else if (jl_is_cpointer_type(jl_typeof(ptr))) { fptr = *(void**)jl_bits_data(ptr); } else if (jl_is_tuple(ptr) && jl_tuple_len(ptr)>1) { jl_value_t *t0 = jl_tupleref(ptr,0); jl_value_t *t1 = jl_tupleref(ptr,1); if (jl_is_symbol(t0)) f_name = ((jl_sym_t*)t0)->name; else if (jl_is_byte_string(t0)) f_name = jl_string_data(t0); else JL_TYPECHK(ccall, symbol, t0); if (jl_is_symbol(t1)) f_lib = ((jl_sym_t*)t1)->name; else if (jl_is_byte_string(t1)) f_lib = jl_string_data(t1); else JL_TYPECHK(ccall, symbol, t1); } else { JL_TYPECHK(ccall, pointer, ptr); } } if (f_name == NULL && fptr == NULL && jl_ptr == NULL) { JL_GC_POP(); emit_error("ccall: null function pointer", ctx); return literal_pointer_val(jl_nothing); } JL_TYPECHK(ccall, type, rt); JL_TYPECHK(ccall, tuple, at); JL_TYPECHK(ccall, type, at); jl_tuple_t *tt = (jl_tuple_t*)at; std::vector<Type *> fargt(0); std::vector<Type *> fargt_sig(0); Type *lrt = julia_type_to_llvm(rt); if (lrt == NULL) { JL_GC_POP(); return literal_pointer_val(jl_nothing); } size_t i; bool haspointers = false; bool isVa = false; size_t nargt = jl_tuple_len(tt); std::vector<AttributeWithIndex> attrs; for(i=0; i < nargt; i++) { jl_value_t *tti = jl_tupleref(tt,i); if (jl_is_vararg_type(tti)) { isVa = true; tti = jl_tparam0(tti); } if (jl_is_bits_type(tti)) { // see pull req #978. need to annotate signext/zeroext for // small integer arguments. jl_bits_type_t *bt = (jl_bits_type_t*)tti; if (bt->nbits < 32) { if (jl_signed_type == NULL) { jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); } #ifdef LLVM32 Attributes::AttrVal av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attributes::SExt; else av = Attributes::ZExt; attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1, ArrayRef<Attributes::AttrVal>(&av, 1))); #else Attribute::AttrConst av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attribute::SExt; else av = Attribute::ZExt; attrs.push_back(AttributeWithIndex::get(i+1, av)); #endif } } Type *t = julia_type_to_llvm(tti); if (t == NULL) { JL_GC_POP(); return literal_pointer_val(jl_nothing); } fargt.push_back(t); if (!isVa) fargt_sig.push_back(t); } // check for calling convention specifier CallingConv::ID cc = CallingConv::C; jl_value_t *last = args[nargs]; if (jl_is_expr(last)) { jl_sym_t *lhd = ((jl_expr_t*)last)->head; if (lhd == jl_symbol("stdcall")) { cc = CallingConv::X86_StdCall; nargs--; } else if (lhd == jl_symbol("cdecl")) { cc = CallingConv::C; nargs--; } else if (lhd == jl_symbol("fastcall")) { cc = CallingConv::X86_FastCall; nargs--; } else if (lhd == jl_symbol("thiscall")) { cc = CallingConv::X86_ThisCall; nargs--; } } if ((!isVa && jl_tuple_len(tt) != (nargs-2)/2) || ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2)) jl_error("ccall: wrong number of arguments to C function"); // some special functions if (fptr == &jl_array_ptr) { Value *ary = emit_expr(args[4], ctx); JL_GC_POP(); return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt), rt); } // see if there are & arguments for(i=4; i < nargs+1; i+=2) { jl_value_t *argi = args[i]; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { haspointers = true; break; } } // make LLVM function object for the target Value *llvmf; FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); if (jl_ptr != NULL) { null_pointer_check(jl_ptr,ctx); Type *funcptype = PointerType::get(functype,0); llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); } else if (fptr != NULL) { Type *funcptype = PointerType::get(functype,0); llvmf = literal_pointer_val(fptr, funcptype); } else { void *symaddr; if (f_lib != NULL) symaddr = add_library_sym(f_name, f_lib); else symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name); if (symaddr == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: could not find function "; msg << f_name; if (f_lib != NULL) { msg << " in library "; msg << f_lib; } emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } llvmf = jl_Module->getOrInsertFunction(f_name, functype); } // save temp argument area stack pointer Value *saveloc=NULL; Value *stacksave=NULL; if (haspointers) { // TODO: inline this saveloc = builder.CreateCall(save_arg_area_loc_func); stacksave = builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stacksave)); } // emit arguments Value *argvals[(nargs-3)/2]; int last_depth = ctx->argDepth; int nargty = jl_tuple_len(tt); for(i=4; i < nargs+1; i+=2) { int ai = (i-4)/2; jl_value_t *argi = args[i]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Type *largty; jl_value_t *jargty; if (isVa && ai >= nargty-1) { largty = fargt[nargty-1]; jargty = jl_tparam0(jl_tupleref(tt,nargty-1)); } else { largty = fargt[ai]; jargty = jl_tupleref(tt,ai); } Value *arg; if (largty == jl_pvalue_llvmt) { arg = emit_expr(argi, ctx, true); } else { arg = emit_unboxed(argi, ctx); if (jl_is_bits_type(expr_type(argi, ctx))) { if (addressOf) arg = emit_unbox(largty->getContainedType(0), largty, arg); else arg = emit_unbox(largty, PointerType::get(largty,0), arg); } } /* #ifdef JL_GC_MARKSWEEP // make sure args are rooted if (largty->isPointerTy() && (largty == jl_pvalue_llvmt || !jl_is_bits_type(expr_type(args[i], ctx)))) { make_gcroot(boxed(arg), ctx); } #endif */ argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf, ai+1, ctx); } // the actual call Value *result = builder.CreateCall(llvmf, ArrayRef<Value*>(&argvals[0],(nargs-3)/2)); if (cc != CallingConv::C) ((CallInst*)result)->setCallingConv(cc); #ifdef LLVM32 ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs))); #else ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size())); #endif // restore temp argument area stack pointer if (haspointers) { assert(saveloc != NULL); builder.CreateCall(restore_arg_area_loc_func, saveloc); assert(stacksave != NULL); builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stackrestore), stacksave); } ctx->argDepth = last_depth; if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall #ifdef LLVM32 ctx->f->addFnAttr(Attributes::StackProtectReq); #else ctx->f->addFnAttr(Attribute::StackProtectReq); #endif } JL_GC_POP(); if (lrt == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); return mark_julia_type(result, rt); }
// ccall(pointer, rettype, (argtypes...), args...) static Value *emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) { JL_NARGSV(ccall, 3); jl_value_t *rt=NULL, *at=NULL; JL_GC_PUSH2(&rt, &at); native_sym_arg_t symarg = interpret_symbol_arg(args[1], ctx, "ccall"); Value *jl_ptr=NULL; void *fptr = NULL; char *f_name = NULL, *f_lib = NULL; jl_ptr = symarg.jl_ptr; fptr = symarg.fptr; f_name = symarg.f_name; f_lib = symarg.f_lib; if (f_name == NULL && fptr == NULL && jl_ptr == NULL) { JL_GC_POP(); emit_error("ccall: null function pointer", ctx); return literal_pointer_val(jl_nothing); } rt = jl_interpret_toplevel_expr_in(ctx->module, args[2], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); if (jl_is_tuple(rt)) { std::string msg = "in " + ctx->funcName + ": ccall: missing return type"; jl_error(msg.c_str()); } if (rt == (jl_value_t*)jl_pointer_type) jl_error("ccall: return type Ptr should have an element type, Ptr{T}"); at = jl_interpret_toplevel_expr_in(ctx->module, args[3], &jl_tupleref(ctx->sp,0), jl_tuple_len(ctx->sp)/2); JL_TYPECHK(ccall, type, rt); JL_TYPECHK(ccall, tuple, at); JL_TYPECHK(ccall, type, at); jl_tuple_t *tt = (jl_tuple_t*)at; std::vector<Type *> fargt(0); std::vector<Type *> fargt_sig(0); Type *lrt = julia_struct_to_llvm(rt); if (lrt == NULL) { JL_GC_POP(); emit_error("ccall: return type doesn't correspond to a C type", ctx); return literal_pointer_val(jl_nothing); } size_t i; bool isVa = false; size_t nargt = jl_tuple_len(tt); std::vector<AttributeWithIndex> attrs; for(i=0; i < nargt; i++) { jl_value_t *tti = jl_tupleref(tt,i); if (tti == (jl_value_t*)jl_pointer_type) jl_error("ccall: argument type Ptr should have an element type, Ptr{T}"); if (jl_is_vararg_type(tti)) { isVa = true; tti = jl_tparam0(tti); } if (jl_is_bitstype(tti)) { // see pull req #978. need to annotate signext/zeroext for // small integer arguments. jl_datatype_t *bt = (jl_datatype_t*)tti; if (bt->size < 4) { if (jl_signed_type == NULL) { jl_signed_type = jl_get_global(jl_core_module,jl_symbol("Signed")); } #ifdef LLVM32 Attributes::AttrVal av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attributes::SExt; else av = Attributes::ZExt; attrs.push_back(AttributeWithIndex::get(getGlobalContext(), i+1, ArrayRef<Attributes::AttrVal>(&av, 1))); #else Attribute::AttrConst av; if (jl_signed_type && jl_subtype(tti, jl_signed_type, 0)) av = Attribute::SExt; else av = Attribute::ZExt; attrs.push_back(AttributeWithIndex::get(i+1, av)); #endif } } Type *t = julia_struct_to_llvm(tti); if (t == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: the type of argument "; msg << i+1; msg << " doesn't correspond to a C type"; emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } fargt.push_back(t); if (!isVa) fargt_sig.push_back(t); } // check for calling convention specifier CallingConv::ID cc = CallingConv::C; jl_value_t *last = args[nargs]; if (jl_is_expr(last)) { jl_sym_t *lhd = ((jl_expr_t*)last)->head; if (lhd == jl_symbol("stdcall")) { cc = CallingConv::X86_StdCall; nargs--; } else if (lhd == jl_symbol("cdecl")) { cc = CallingConv::C; nargs--; } else if (lhd == jl_symbol("fastcall")) { cc = CallingConv::X86_FastCall; nargs--; } else if (lhd == jl_symbol("thiscall")) { cc = CallingConv::X86_ThisCall; nargs--; } } if ((!isVa && jl_tuple_len(tt) != (nargs-2)/2) || ( isVa && jl_tuple_len(tt)-1 > (nargs-2)/2)) jl_error("ccall: wrong number of arguments to C function"); // some special functions if (fptr == &jl_array_ptr) { assert(lrt->isPointerTy()); Value *ary = emit_expr(args[4], ctx); JL_GC_POP(); return mark_julia_type(builder.CreateBitCast(emit_arrayptr(ary),lrt), rt); } if (fptr == &jl_value_ptr) { assert(lrt->isPointerTy()); jl_value_t *argi = args[4]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Value *ary = boxed(emit_expr(argi, ctx)); JL_GC_POP(); return mark_julia_type( builder.CreateBitCast(emit_nthptr_addr(ary, addressOf?1:0),lrt), rt); } // make LLVM function object for the target Value *llvmf; FunctionType *functype = FunctionType::get(lrt, fargt_sig, isVa); if (jl_ptr != NULL) { null_pointer_check(jl_ptr,ctx); Type *funcptype = PointerType::get(functype,0); llvmf = builder.CreateIntToPtr(jl_ptr, funcptype); } else if (fptr != NULL) { Type *funcptype = PointerType::get(functype,0); llvmf = literal_pointer_val(fptr, funcptype); } else { void *symaddr; if (f_lib != NULL) symaddr = add_library_sym(f_name, f_lib); else symaddr = sys::DynamicLibrary::SearchForAddressOfSymbol(f_name); if (symaddr == NULL) { JL_GC_POP(); std::stringstream msg; msg << "ccall: could not find function "; msg << f_name; if (f_lib != NULL) { msg << " in library "; msg << f_lib; } emit_error(msg.str(), ctx); return literal_pointer_val(jl_nothing); } llvmf = jl_Module->getOrInsertFunction(f_name, functype); } // save place before arguments, for possible insertion of temp arg // area saving code. Value *saveloc=NULL; Value *stacksave=NULL; BasicBlock::InstListType &instList = builder.GetInsertBlock()->getInstList(); Instruction *savespot; if (instList.empty()) { savespot = NULL; } else { // hey C++, there's this thing called pointers... Instruction &_savespot = builder.GetInsertBlock()->back(); savespot = &_savespot; } // emit arguments Value *argvals[(nargs-3)/2]; int last_depth = ctx->argDepth; int nargty = jl_tuple_len(tt); bool needTempSpace = false; for(i=4; i < nargs+1; i+=2) { int ai = (i-4)/2; jl_value_t *argi = args[i]; bool addressOf = false; if (jl_is_expr(argi) && ((jl_expr_t*)argi)->head == amp_sym) { addressOf = true; argi = jl_exprarg(argi,0); } Type *largty; jl_value_t *jargty; if (isVa && ai >= nargty-1) { largty = fargt[nargty-1]; jargty = jl_tparam0(jl_tupleref(tt,nargty-1)); } else { largty = fargt[ai]; jargty = jl_tupleref(tt,ai); } Value *arg; if (largty == jl_pvalue_llvmt || largty->isStructTy()) { arg = emit_expr(argi, ctx, true); } else { arg = emit_unboxed(argi, ctx); if (jl_is_bitstype(expr_type(argi, ctx))) { if (addressOf) arg = emit_unbox(largty->getContainedType(0), largty, arg); else arg = emit_unbox(largty, PointerType::get(largty,0), arg); } } /* #ifdef JL_GC_MARKSWEEP // make sure args are rooted if (largty->isPointerTy() && (largty == jl_pvalue_llvmt || !jl_is_bits_type(expr_type(args[i], ctx)))) { make_gcroot(boxed(arg), ctx); } #endif */ bool mightNeed=false; argvals[ai] = julia_to_native(largty, jargty, arg, argi, addressOf, ai+1, ctx, &mightNeed); needTempSpace |= mightNeed; } if (needTempSpace) { // save temp argument area stack pointer // TODO: inline this saveloc = CallInst::Create(save_arg_area_loc_func); stacksave = CallInst::Create(Intrinsic::getDeclaration(jl_Module, Intrinsic::stacksave)); if (savespot) instList.insertAfter(savespot, (Instruction*)saveloc); else instList.push_front((Instruction*)saveloc); instList.insertAfter((Instruction*)saveloc, (Instruction*)stacksave); } // the actual call Value *result = builder.CreateCall(llvmf, ArrayRef<Value*>(&argvals[0],(nargs-3)/2)); if (cc != CallingConv::C) ((CallInst*)result)->setCallingConv(cc); #ifdef LLVM32 ((CallInst*)result)->setAttributes(AttrListPtr::get(getGlobalContext(), ArrayRef<AttributeWithIndex>(attrs))); #else ((CallInst*)result)->setAttributes(AttrListPtr::get(attrs.data(),attrs.size())); #endif if (needTempSpace) { // restore temp argument area stack pointer assert(saveloc != NULL); builder.CreateCall(restore_arg_area_loc_func, saveloc); assert(stacksave != NULL); builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::stackrestore), stacksave); } ctx->argDepth = last_depth; if (0) { // Enable this to turn on SSPREQ (-fstack-protector) on the function containing this ccall #ifdef LLVM32 ctx->f->addFnAttr(Attributes::StackProtectReq); #else ctx->f->addFnAttr(Attribute::StackProtectReq); #endif } JL_GC_POP(); if (lrt == T_void) return literal_pointer_val((jl_value_t*)jl_nothing); if (lrt->isStructTy()) { //fprintf(stderr, "ccall rt: %s -> %s\n", f_name, ((jl_tag_type_t*)rt)->name->name->name); assert(jl_is_structtype(rt)); Value *strct = builder.CreateCall(jlallocobj_func, ConstantInt::get(T_size, sizeof(void*)+((jl_datatype_t*)rt)->size)); builder.CreateStore(literal_pointer_val((jl_value_t*)rt), emit_nthptr_addr(strct, (size_t)0)); builder.CreateStore(result, builder.CreateBitCast( emit_nthptr_addr(strct, (size_t)1), PointerType::get(lrt,0))); return mark_julia_type(strct, rt); } return mark_julia_type(result, rt); }
jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *parent, jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs, jl_value_t *newvalue, int8_t offs, const struct jl_typemap_info *tparams, size_t min_world, size_t max_world, jl_value_t **overwritten) { jl_ptls_t ptls = jl_get_ptls_states(); assert(min_world > 0 && max_world > 0); if (!simpletype) simpletype = (jl_tupletype_t*)jl_nothing; jl_value_t *ttype = jl_unwrap_unionall((jl_value_t*)type); if ((jl_value_t*)simpletype == jl_nothing) { jl_typemap_entry_t *ml = jl_typemap_assoc_by_type(*cache, (jl_value_t*)type, NULL, 0, offs, min_world, 0); if (ml && ml->simplesig == (void*)jl_nothing) { if (overwritten != NULL) *overwritten = ml->func.value; if (newvalue == ml->func.value) // no change. TODO: involve world in computation! return ml; if (newvalue == NULL) // don't overwrite with guard entries return ml; ml->max_world = min_world - 1; } } jl_typemap_entry_t *newrec = (jl_typemap_entry_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_entry_t), jl_typemap_entry_type); newrec->sig = type; newrec->simplesig = simpletype; newrec->func.value = newvalue; newrec->guardsigs = guardsigs; newrec->next = (jl_typemap_entry_t*)jl_nothing; newrec->min_world = min_world; newrec->max_world = max_world; // compute the complexity of this type signature newrec->va = jl_is_va_tuple((jl_datatype_t*)ttype); newrec->issimplesig = !jl_is_unionall(type); // a TypeVar environment needs a complex matching test newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted JL_GC_PUSH1(&newrec); assert(jl_is_tuple_type(ttype)); size_t i, l; for (i = 0, l = jl_field_count(ttype); i < l && newrec->issimplesig; i++) { jl_value_t *decl = jl_field_type(ttype, i); if (jl_is_kind(decl)) newrec->isleafsig = 0; // Type{} may have a higher priority than a kind else if (jl_is_type_type(decl)) newrec->isleafsig = 0; // Type{} may need special processing to compute the match else if (jl_is_vararg_type(decl)) newrec->isleafsig = 0; // makes iteration easier when the endpoints are the same else if (decl == (jl_value_t*)jl_any_type) newrec->isleafsig = 0; // Any needs to go in the general cache else if (!jl_is_concrete_type(decl)) // anything else needs to go through the general subtyping test newrec->isleafsig = newrec->issimplesig = 0; } // TODO: assert that guardsigs == jl_emptysvec && simplesig == jl_nothing if isleafsig and optimize with that knowledge? jl_typemap_insert_generic(cache, parent, newrec, NULL, offs, tparams); JL_GC_POP(); return newrec; }
// this is the general entry point for looking up a type in the cache // as a subtype, or with type_equal jl_typemap_entry_t *jl_typemap_assoc_by_type(union jl_typemap_t ml_or_cache, jl_value_t *types, jl_svec_t **penv, int8_t subtype, int8_t offs, size_t world, size_t max_world_mask) { 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; jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)types); assert(jl_is_datatype(ttypes)); size_t l = jl_field_count(ttypes); int isva = 0; // compute the type at offset `offs` into `types`, which may be a Vararg if (l <= offs + 1) { ty = jl_tparam(ttypes, l - 1); if (jl_is_vararg_type(ty)) { ty = jl_unwrap_vararg(ty); isva = 1; } else if (l <= offs) { ty = NULL; } } else if (l > offs) { ty = jl_tparam(ttypes, offs); } // If there is a type at offs, look in the optimized caches if (!subtype) { if (ty && jl_is_any(ty)) return jl_typemap_assoc_by_type(cache->any, types, penv, subtype, offs + 1, world, max_world_mask); if (isva) // in lookup mode, want to match Vararg exactly, not as a subtype ty = NULL; } if (ty) { if (jl_is_type_type(ty)) { jl_value_t *a0 = jl_tparam0(ty); if (cache->targ.values != (void*)jl_nothing && 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, offs + 1, world, max_world_mask); if (li) return li; } } if (!subtype && is_cache_leaf(a0)) return NULL; } if (cache->arg1.values != (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, offs + 1, world, max_world_mask); if (li) return li; } } if (!subtype && is_cache_leaf(ty)) return NULL; } // 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, penv, world, max_world_mask); if (li) return li; return jl_typemap_assoc_by_type(cache->any, types, penv, subtype, offs + 1, world, max_world_mask); } else { return jl_typemap_lookup_by_type_(cache->linear, types, world, max_world_mask); } } else { return subtype ? jl_typemap_assoc_by_type_(ml_or_cache.leaf, types, penv, world, max_world_mask) : jl_typemap_lookup_by_type_(ml_or_cache.leaf, types, world, max_world_mask); } }
DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) { // mimic jl_show, but never calling a julia method size_t n = 0; if (v == NULL) { n += JL_PRINTF(out, "<null>"); } else if (jl_is_lambda_info(v)) { jl_lambda_info_t *li = (jl_lambda_info_t*)v; n += jl_static_show(out, (jl_value_t*)li->module); n += JL_PRINTF(out, ".%s", li->name->name); if (li->specTypes) { n += jl_static_show(out, (jl_value_t*)li->specTypes); } else { n += JL_PRINTF(out, "(?)"); } } else if (jl_is_tuple(v)) { n += jl_show_tuple(out, (jl_tuple_t*)v, "(", ")", 1); } else if (jl_is_vararg_type(v)) { n += jl_static_show(out, jl_tparam0(v)); n += JL_PRINTF(out, "..."); } else if (jl_is_datatype(v)) { jl_datatype_t *dv = (jl_datatype_t*)v; if (dv->name->module != jl_core_module) { n += jl_static_show(out, (jl_value_t*)dv->name->module); JL_PUTS(".", out); n += 1; } n += JL_PRINTF(out, "%s", dv->name->name->name); if (dv->parameters) { size_t j, tlen = jl_tuple_len(dv->parameters); if (tlen > 0) { n += JL_PRINTF(out, "{"); for (j = 0; j < tlen; j++) { jl_value_t *p = jl_tupleref(dv->parameters,j); n += jl_static_show(out, p); if (j != tlen-1) n += JL_PRINTF(out, ", "); } n += JL_PRINTF(out, "}"); } } } else if (jl_is_func(v)) { if (jl_is_gf(v)) { n += JL_PRINTF(out, "%s", jl_gf_name(v)->name); } else { n += JL_PRINTF(out, "<# function>"); } } else if (jl_typeis(v, jl_intrinsic_type)) { n += JL_PRINTF(out, "<# intrinsic function %d>", *(uint32_t*)jl_data_ptr(v)); } else if (jl_is_int64(v)) { n += JL_PRINTF(out, "%d", jl_unbox_int64(v)); } else if (jl_is_int32(v)) { n += JL_PRINTF(out, "%d", jl_unbox_int32(v)); } else if (jl_typeis(v,jl_int16_type)) { n += JL_PRINTF(out, "%d", jl_unbox_int16(v)); } else if (jl_typeis(v,jl_int8_type)) { n += JL_PRINTF(out, "%d", jl_unbox_int8(v)); } else if (jl_is_uint64(v)) { n += JL_PRINTF(out, "0x%016x", jl_unbox_uint64(v)); } else if (jl_is_uint32(v)) { n += JL_PRINTF(out, "0x%08x", jl_unbox_uint32(v)); } else if (jl_typeis(v,jl_uint16_type)) { n += JL_PRINTF(out, "0x%04x", jl_unbox_uint16(v)); } else if (jl_typeis(v,jl_uint8_type)) { n += JL_PRINTF(out, "0x%02x", jl_unbox_uint8(v)); } else if (jl_is_cpointer(v)) { #ifdef _P64 n += JL_PRINTF(out, "0x%016x", jl_unbox_voidpointer(v)); #else n += JL_PRINTF(out, "0x%08x", jl_unbox_voidpointer(v)); #endif } else if (jl_is_float32(v)) { n += JL_PRINTF(out, "%g", jl_unbox_float32(v)); } else if (jl_is_float64(v)) { n += JL_PRINTF(out, "%g", jl_unbox_float64(v)); } else if (v == jl_true) { n += JL_PRINTF(out, "true"); } else if (v == jl_false) { n += JL_PRINTF(out, "false"); } else if (jl_is_byte_string(v)) { n += JL_PRINTF(out, "\"%s\"", jl_iostr_data(v)); } else if (v == jl_bottom_type) { n += JL_PRINTF(out, "Void"); } else if (jl_is_uniontype(v)) { n += JL_PRINTF(out, "Union"); n += jl_static_show(out, (jl_value_t*)((jl_uniontype_t*)v)->types); } else if (jl_is_typector(v)) { n += jl_static_show(out, ((jl_typector_t*)v)->body); } else if (jl_is_typevar(v)) { n += JL_PRINTF(out, "%s", ((jl_tvar_t*)v)->name->name); } else if (jl_is_module(v)) { jl_module_t *m = (jl_module_t*)v; if (m->parent != m && m->parent != jl_main_module) { n += jl_static_show(out, (jl_value_t*)m->parent); n += JL_PRINTF(out, "."); } n += JL_PRINTF(out, "%s", m->name->name); } else if (jl_is_symbol(v)) { n += JL_PRINTF(out, ":%s", ((jl_sym_t*)v)->name); } else if (jl_is_symbolnode(v)) { n += JL_PRINTF(out, "%s::", jl_symbolnode_sym(v)->name); n += jl_static_show(out, jl_symbolnode_type(v)); } else if (jl_is_getfieldnode(v)) { n += jl_static_show(out, jl_getfieldnode_val(v)); n += JL_PRINTF(out, ".%s", jl_getfieldnode_name(v)->name); n += JL_PRINTF(out, "::"); n += jl_static_show(out, jl_getfieldnode_type(v)); } else if (jl_is_labelnode(v)) { n += JL_PRINTF(out, "%d:", jl_labelnode_label(v)); } else if (jl_is_gotonode(v)) { n += JL_PRINTF(out, "goto %d", jl_gotonode_label(v)); } else if (jl_is_quotenode(v)) { n += JL_PRINTF(out, "quote "); n += jl_static_show(out, jl_fieldref(v,0)); n += JL_PRINTF(out, " end"); } else if (jl_is_newvarnode(v)) { n += JL_PRINTF(out, "<newvar "); n += jl_static_show(out, jl_fieldref(v,0)); n += JL_PRINTF(out, ">"); } else if (jl_is_topnode(v)) { n += JL_PRINTF(out, "top("); n += jl_static_show(out, jl_fieldref(v,0)); n += JL_PRINTF(out, ")"); } else if (jl_is_linenode(v)) { n += JL_PRINTF(out, "# line %d", jl_linenode_line(v)); } else if (jl_is_expr(v)) { jl_expr_t *e = (jl_expr_t*)v; if (e->head == assign_sym && jl_array_len(e->args) == 2) { n += jl_static_show(out, jl_exprarg(e,0)); n += JL_PRINTF(out, " = "); n += jl_static_show(out, jl_exprarg(e,1)); } else { char sep = ' '; if (e->head == body_sym) sep = '\n'; n += JL_PRINTF(out, "Expr(:%s", e->head->name); size_t i, len = jl_array_len(e->args); for (i = 0; i < len; i++) { n += JL_PRINTF(out, ",%c", sep); n += jl_static_show(out, jl_exprarg(e,i)); } n += JL_PRINTF(out, ")::"); n += jl_static_show(out, e->etype); } } else if (jl_is_array(v)) { n += jl_static_show(out, jl_typeof(v)); n += JL_PRINTF(out, "["); size_t j, tlen = jl_array_len(v); for (j = 0; j < tlen; j++) { n += jl_static_show(out, jl_arrayref((jl_array_t*)v,j)); if (j != tlen-1) n += JL_PRINTF(out, ", "); } n += JL_PRINTF(out, "]"); } else if (jl_typeis(v,jl_loaderror_type)) { n += JL_PRINTF(out, "LoadError(at "); n += jl_static_show(out, jl_fieldref(v, 0)); n += JL_PRINTF(out, " line "); n += jl_static_show(out, jl_fieldref(v, 1)); n += JL_PRINTF(out, ": "); n += jl_static_show(out, jl_fieldref(v, 2)); n += JL_PRINTF(out, ")"); } else if (jl_typeis(v,jl_errorexception_type)) { n += JL_PRINTF(out, "ErrorException("); n += jl_static_show(out, jl_fieldref(v, 0)); n += JL_PRINTF(out, ")"); } else if (jl_is_datatype(jl_typeof(v))) { jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v); n += jl_static_show(out, (jl_value_t*)t); n += JL_PRINTF(out, "("); size_t nb = jl_datatype_size(t); size_t tlen = jl_tuple_len(t->names); if (nb > 0 && tlen == 0) { char *data = (char*)jl_data_ptr(v); n += JL_PRINTF(out, "0x"); for(int i=nb-1; i >= 0; --i) n += JL_PRINTF(out, "%02hhx", data[i]); } else { jl_value_t *fldval=NULL; JL_GC_PUSH1(&fldval); for (size_t i = 0; i < tlen; i++) { n += JL_PRINTF(out, ((jl_sym_t*)jl_tupleref(t->names, i))->name); //jl_fielddesc_t f = t->fields[i]; n += JL_PRINTF(out, "="); fldval = jl_get_nth_field(v, i); n += jl_static_show(out, fldval); if (i != tlen-1) n += JL_PRINTF(out, ", "); } JL_GC_POP(); } n += JL_PRINTF(out, ")"); } else { n += JL_PRINTF(out, "<?::"); n += jl_static_show(out, jl_typeof(v)); n += JL_PRINTF(out, ">"); } return n; }