// f(::Union{...}, ...) is a common pattern // and expanding the Union may give a leaf function static void _compile_all_union(jl_value_t *sig) { jl_tupletype_t *sigbody = (jl_tupletype_t*)jl_unwrap_unionall(sig); size_t count_unions = 0; size_t i, l = jl_svec_len(sigbody->parameters); jl_svec_t *p = NULL; jl_value_t *methsig = NULL; for (i = 0; i < l; i++) { jl_value_t *ty = jl_svecref(sigbody->parameters, i); if (jl_is_uniontype(ty)) ++count_unions; else if (ty == jl_bottom_type) return; // why does this method exist? } if (count_unions == 0) { _compile_all_tvar_union(sig); return; } int *idx = (int*)alloca(sizeof(int) * count_unions); for (i = 0; i < count_unions; i++) { idx[i] = 0; } JL_GC_PUSH2(&p, &methsig); int idx_ctr = 0, incr = 0; while (!incr) { jl_svec_t *p = jl_alloc_svec_uninit(l); for (i = 0, idx_ctr = 0, incr = 1; i < l; i++) { jl_value_t *ty = jl_svecref(sigbody->parameters, i); if (jl_is_uniontype(ty)) { size_t l = jl_count_union_components(ty); size_t j = idx[idx_ctr]; jl_svecset(p, i, jl_nth_union_component(ty, j)); ++j; if (incr) { if (j == l) { idx[idx_ctr] = 0; } else { idx[idx_ctr] = j; incr = 0; } } ++idx_ctr; } else { jl_svecset(p, i, ty); } } methsig = (jl_value_t*)jl_apply_tuple_type(p); methsig = jl_rewrap_unionall(methsig, sig); _compile_all_tvar_union(methsig); } JL_GC_POP(); }
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 jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na) { jl_ptls_t ptls = jl_get_ptls_states(); if (type->instance != NULL) return type->instance; size_t nf = jl_datatype_nfields(type); jl_value_t *jv = jl_gc_alloc(ptls, jl_datatype_size(type), type); JL_GC_PUSH1(&jv); for (size_t i = 0; i < na; i++) { jl_value_t *ft = jl_field_type(type, i); if (!jl_isa(args[i], ft)) jl_type_error("new", ft, args[i]); jl_set_nth_field(jv, i, args[i]); } for(size_t i=na; i < nf; i++) { if (jl_field_isptr(type, i)) { *(jl_value_t**)((char*)jl_data_ptr(jv)+jl_field_offset(type,i)) = NULL; } else { jl_value_t *ft = jl_field_type(type, i); if (jl_is_uniontype(ft)) { uint8_t *psel = &((uint8_t *)jv)[jl_field_offset(type, i) + jl_field_size(type, i) - 1]; *psel = 0; } } } JL_GC_POP(); return jv; }
static int jl_typemap_intersection_array_visitor(struct jl_ordereddict_t *a, jl_value_t *ty, int tparam, int offs, struct typemap_intersection_env *closure) { size_t i, l = jl_array_len(a->values); union jl_typemap_t *data = (union jl_typemap_t*)jl_array_data(a->values); for (i = 0; i < l; i++) { union jl_typemap_t ml = data[i]; if (ml.unknown == jl_nothing) continue; jl_value_t *t; if (jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_level_type) { t = ml.node->key; } else { t = jl_field_type(ml.leaf->sig, offs); if (tparam) t = jl_tparam0(t); } if (ty == (jl_value_t*)jl_any_type || // easy case: Any always matches (tparam ? // need to compute `ty <: Type{t}` (jl_is_uniontype(ty) || // punt on Union{...} right now jl_typeof(t) == ty || // deal with kinds (e.g. ty == DataType && t == Type{t}) (jl_is_type_type(ty) && (jl_is_typevar(jl_tparam0(ty)) ? jl_subtype(t, ((jl_tvar_t*)jl_tparam0(ty))->ub, 0) : // deal with ty == Type{<:T} jl_subtype(t, jl_tparam0(ty), 0)))) // deal with ty == Type{T{#<:T}} : jl_subtype(t, ty, 0))) // `t` is a leaftype, so intersection test becomes subtype if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; } return 1; }
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); } }
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); }
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; }
// own_buffer != 0 iff GC should call free() on this pointer eventually JL_DLLEXPORT jl_array_t *jl_ptr_to_array_1d(jl_value_t *atype, void *data, size_t nel, int own_buffer) { jl_ptls_t ptls = jl_get_ptls_states(); jl_array_t *a; jl_value_t *eltype = jl_tparam0(atype); int isunboxed = jl_array_store_unboxed(eltype); size_t elsz; unsigned align; if (isunboxed && jl_is_uniontype(eltype)) jl_exceptionf(jl_argumenterror_type, "unsafe_wrap: unspecified layout for union element type"); if (isunboxed) { elsz = jl_datatype_size(eltype); align = jl_datatype_align(eltype); } else { align = elsz = sizeof(void*); } if (((uintptr_t)data) & (align - 1)) jl_exceptionf(jl_argumenterror_type, "unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align); int ndimwords = jl_array_ndimwords(1); int tsz = JL_ARRAY_ALIGN(sizeof(jl_array_t) + ndimwords*sizeof(size_t), JL_CACHE_BYTE_ALIGNMENT); a = (jl_array_t*)jl_gc_alloc(ptls, tsz, atype); // No allocation or safepoint allowed after this a->flags.pooled = tsz <= GC_MAX_SZCLASS; a->data = data; #ifdef STORE_ARRAY_LEN a->length = nel; #endif a->elsize = elsz; a->flags.ptrarray = !isunboxed; a->flags.ndims = 1; a->flags.isshared = 1; a->flags.isaligned = 0; // TODO: allow passing memalign'd buffers if (own_buffer) { a->flags.how = 2; jl_gc_track_malloced_array(ptls, a); jl_gc_count_allocd(nel*elsz + (elsz == 1 ? 1 : 0)); } else { a->flags.how = 0; } a->nrows = nel; a->maxsize = nel; a->offset = 0; return a; }
static inline jl_array_t *_new_array(jl_value_t *atype, uint32_t ndims, size_t *dims) { jl_value_t *eltype = jl_tparam0(atype); size_t elsz = 0, al = 0; if (!jl_is_kind(jl_typeof(eltype))) jl_type_error_rt("Array", "element type", (jl_value_t*)jl_type_type, eltype); int isunboxed = jl_islayout_inline(eltype, &elsz, &al); int isunion = jl_is_uniontype(eltype); if (!isunboxed) { elsz = sizeof(void*); al = elsz; } return _new_array_(atype, ndims, dims, isunboxed, isunion, elsz); }
JL_DLLEXPORT jl_value_t *jl_arrayref(jl_array_t *a, size_t i) { if (a->flags.ptrarray) return jl_ptrarrayref(a, i); assert(i < jl_array_len(a)); jl_value_t *eltype = (jl_value_t*)jl_tparam0(jl_typeof(a)); if (jl_is_uniontype(eltype)) { // isbits union selector bytes are always stored directly after the last array element uint8_t sel = jl_array_typetagdata(a)[i]; eltype = jl_nth_union_component(eltype, sel); if (jl_is_datatype_singleton((jl_datatype_t*)eltype)) return ((jl_datatype_t*)eltype)->instance; } return jl_new_bits(eltype, &((char*)a->data)[i * a->elsize]); }
JL_DLLEXPORT jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); assert(i < jl_datatype_nfields(st)); size_t offs = jl_field_offset(st, i); if (jl_field_isptr(st, i)) { return *(jl_value_t**)((char*)v + offs); } jl_value_t *ty = jl_field_type(st, i); if (jl_is_uniontype(ty)) { uint8_t sel = ((uint8_t*)v)[offs + jl_field_size(st, i) - 1]; ty = jl_nth_union_component(ty, sel); if (jl_is_datatype_singleton((jl_datatype_t*)ty)) return ((jl_datatype_t*)ty)->instance; } return jl_new_bits(ty, (char*)v + offs); }
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; }
JL_DLLEXPORT jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); if (i >= jl_datatype_nfields(st)) jl_bounds_error_int(v, i + 1); size_t offs = jl_field_offset(st, i); if (jl_field_isptr(st, i)) { jl_value_t *fval = *(jl_value_t**)((char*)v + offs); if (fval == NULL) jl_throw(jl_undefref_exception); return fval; } jl_value_t *ty = jl_field_type(st, i); if (jl_is_uniontype(ty)) { size_t fsz = jl_field_size(st, i); uint8_t sel = ((uint8_t*)v)[offs + fsz - 1]; ty = jl_nth_union_component(ty, sel); if (jl_is_datatype_singleton((jl_datatype_t*)ty)) return ((jl_datatype_t*)ty)->instance; } return jl_new_bits(ty, (char*)v + offs); }
static int references_name(jl_value_t *p, jl_typename_t *name) { if (jl_is_uniontype(p)) return references_name(((jl_uniontype_t*)p)->a, name) || references_name(((jl_uniontype_t*)p)->b, name); if (jl_is_unionall(p)) return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name) || references_name(((jl_unionall_t*)p)->body, name); if (jl_is_typevar(p)) return references_name(((jl_tvar_t*)p)->ub, name) || references_name(((jl_tvar_t*)p)->lb, name); if (jl_is_datatype(p)) { if (((jl_datatype_t*)p)->name == name) return 1; size_t i, l = jl_nparams(p); for (i = 0; i < l; i++) { if (references_name(jl_tparam(p, i), name)) return 1; } } return 0; }
static unsigned union_isbits(jl_value_t *ty, size_t *nbytes, size_t *align) { if (jl_is_uniontype(ty)) { unsigned na = union_isbits(((jl_uniontype_t*)ty)->a, nbytes, align); if (na == 0) return 0; unsigned nb = union_isbits(((jl_uniontype_t*)ty)->b, nbytes, align); if (nb == 0) return 0; return na + nb; } if (jl_isbits(ty)) { size_t sz = jl_datatype_size(ty); size_t al = jl_datatype_align(ty); if (*nbytes < sz) *nbytes = sz; if (*align < al) *align = al; return 1; } return 0; }
JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t i, jl_value_t *rhs) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); size_t offs = jl_field_offset(st, i); if (jl_field_isptr(st, i)) { *(jl_value_t**)((char*)v + offs) = rhs; if (rhs != NULL) jl_gc_wb(v, rhs); } else { jl_value_t *ty = jl_field_type(st, i); if (jl_is_uniontype(ty)) { uint8_t *psel = &((uint8_t*)v)[offs + jl_field_size(st, i) - 1]; unsigned nth = 0; if (!jl_find_union_component(ty, jl_typeof(rhs), &nth)) assert(0 && "invalid field assignment to isbits union"); *psel = nth; if (jl_is_datatype_singleton((jl_datatype_t*)jl_typeof(rhs))) return; } jl_assign_bits((char*)v + offs, rhs); } }
// See comment above for an explanation of NOINLINE. static int NOINLINE compare_fields(jl_value_t *a, jl_value_t *b, jl_datatype_t *dt) { size_t f, nf = jl_datatype_nfields(dt); for (f = 0; f < nf; f++) { size_t offs = jl_field_offset(dt, f); char *ao = (char*)jl_data_ptr(a) + offs; char *bo = (char*)jl_data_ptr(b) + offs; if (jl_field_isptr(dt, f)) { jl_value_t *af = *(jl_value_t**)ao; jl_value_t *bf = *(jl_value_t**)bo; if (af != bf) { if (af == NULL || bf == NULL) return 0; if (!jl_egal(af, bf)) return 0; } } else { jl_datatype_t *ft = (jl_datatype_t*)jl_field_type(dt, f); if (jl_is_uniontype(ft)) { uint8_t asel = ((uint8_t*)ao)[jl_field_size(dt, f) - 1]; uint8_t bsel = ((uint8_t*)bo)[jl_field_size(dt, f) - 1]; if (asel != bsel) return 0; ft = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)ft, asel); } if (!ft->layout->haspadding) { if (!bits_equal(ao, bo, ft->size)) return 0; } else { assert(jl_datatype_nfields(ft) > 0); if (!compare_fields((jl_value_t*)ao, (jl_value_t*)bo, ft)) return 0; } } } return 1; }
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; }
// f{<:Union{...}}(...) is a common pattern // and expanding the Union may give a leaf function static void _compile_all_tvar_union(jl_value_t *methsig) { if (!jl_is_unionall(methsig) && jl_is_leaf_type(methsig)) { // usually can create a specialized version of the function, // if the signature is already a leaftype if (jl_compile_hint((jl_tupletype_t*)methsig)) return; } int tvarslen = jl_subtype_env_size(methsig); jl_value_t *sigbody = methsig; jl_value_t **env; JL_GC_PUSHARGS(env, 2 * tvarslen); int *idx = (int*)alloca(sizeof(int) * tvarslen); int i; for (i = 0; i < tvarslen; i++) { assert(jl_is_unionall(sigbody)); idx[i] = 0; env[2 * i] = (jl_value_t*)((jl_unionall_t*)sigbody)->var; env[2 * i + 1] = jl_bottom_type; // initialize the list with Union{}, since T<:Union{} is always a valid option sigbody = ((jl_unionall_t*)sigbody)->body; } for (i = 0; i < tvarslen; /* incremented by inner loop */) { jl_value_t *sig; JL_TRY { // TODO: wrap in UnionAll for each tvar in env[2*i + 1] ? // currently doesn't matter much, since jl_compile_hint doesn't work on abstract types sig = (jl_value_t*)jl_instantiate_type_with(sigbody, env, tvarslen); } JL_CATCH { goto getnext; // sigh, we found an invalid type signature. should we warn the user? } assert(jl_is_tuple_type(sig)); if (sig == jl_bottom_type || tupletype_any_bottom(sig)) goto getnext; // signature wouldn't be callable / is invalid -- skip it if (jl_is_leaf_type(sig)) { if (jl_compile_hint((jl_tupletype_t*)sig)) goto getnext; // success } getnext: for (i = 0; i < tvarslen; i++) { jl_tvar_t *tv = (jl_tvar_t*)env[2 * i]; if (jl_is_uniontype(tv->ub)) { size_t l = jl_count_union_components(tv->ub); size_t j = idx[i]; if (j == l) { env[2 * i + 1] = jl_bottom_type; idx[i] = 0; } else { jl_value_t *ty = jl_nth_union_component(tv->ub, j); if (!jl_is_leaf_type(ty)) ty = (jl_value_t*)jl_new_typevar(tv->name, tv->lb, ty); env[2 * i + 1] = ty; idx[i] = j + 1; break; } } else { env[2 * i + 1] = (jl_value_t*)tv; } } } JL_GC_POP(); }
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 f, nf = jl_datatype_nfields(dt); if (nf == 0) return bits_hash(jl_data_ptr(v), sz) ^ h; if (dt == jl_unionall_type) return type_object_id_(v, NULL); for (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); if (jl_is_uniontype(fieldtype)) { uint8_t sel = ((uint8_t*)vo)[jl_field_size(dt, f) - 1]; fieldtype = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)fieldtype, sel); } 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, fieldtype->size); } h = bitmix(h, u); } return h; }
void jl_compute_field_offsets(jl_datatype_t *st) { size_t sz = 0, alignm = 1; int homogeneous = 1; jl_value_t *lastty = NULL; uint64_t max_offset = (((uint64_t)1) << 32) - 1; uint64_t max_size = max_offset >> 1; if (st->name->wrapper) { jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper); // compute whether this type can be inlined // based on whether its definition is self-referential if (w->types != NULL) { st->isbitstype = st->isconcretetype && !st->mutabl; size_t i, nf = jl_field_count(st); for (i = 0; i < nf; i++) { jl_value_t *fld = jl_field_type(st, i); if (st->isbitstype) st->isbitstype = jl_is_datatype(fld) && ((jl_datatype_t*)fld)->isbitstype; if (!st->zeroinit) st->zeroinit = (jl_is_datatype(fld) && ((jl_datatype_t*)fld)->isinlinealloc) ? ((jl_datatype_t*)fld)->zeroinit : 1; } if (st->isbitstype) { st->isinlinealloc = 1; size_t i, nf = jl_field_count(w); for (i = 0; i < nf; i++) { jl_value_t *fld = jl_field_type(w, i); if (references_name(fld, w->name)) { st->isinlinealloc = 0; st->isbitstype = 0; st->zeroinit = 1; break; } } } } // If layout doesn't depend on type parameters, it's stored in st->name->wrapper // and reused by all subtypes. if (st != w && // this check allows us to re-compute layout for some types during init w->layout) { st->layout = w->layout; st->size = w->size; jl_allocate_singleton_instance(st); return; } } if (st->types == NULL || (jl_is_namedtuple_type(st) && !jl_is_concrete_type((jl_value_t*)st))) return; uint32_t nfields = jl_svec_len(st->types); if (nfields == 0) { if (st == jl_sym_type || st == jl_string_type) { // opaque layout - heap-allocated blob static const jl_datatype_layout_t opaque_byte_layout = {0, 1, 0, 1, 0}; st->layout = &opaque_byte_layout; } else if (st == jl_simplevector_type || st->name == jl_array_typename) { static const jl_datatype_layout_t opaque_ptr_layout = {0, sizeof(void*), 0, 1, 0}; st->layout = &opaque_ptr_layout; } else { // reuse the same layout for all singletons static const jl_datatype_layout_t singleton_layout = {0, 1, 0, 0, 0}; st->layout = &singleton_layout; jl_allocate_singleton_instance(st); } return; } if (!jl_is_concrete_type((jl_value_t*)st)) { // compute layout whenever field types have no free variables for (size_t i = 0; i < nfields; i++) { if (jl_has_free_typevars(jl_field_type(st, i))) return; } } size_t descsz = nfields * sizeof(jl_fielddesc32_t); jl_fielddesc32_t *desc; if (descsz < jl_page_size) desc = (jl_fielddesc32_t*)alloca(descsz); else desc = (jl_fielddesc32_t*)malloc(descsz); int haspadding = 0; assert(st->name == jl_tuple_typename || st == jl_sym_type || st == jl_simplevector_type || nfields != 0); for (size_t i = 0; i < nfields; i++) { jl_value_t *ty = jl_field_type(st, i); size_t fsz = 0, al = 0; if (jl_islayout_inline(ty, &fsz, &al)) { if (__unlikely(fsz > max_size)) // Should never happen goto throw_ovf; desc[i].isptr = 0; if (jl_is_uniontype(ty)) { haspadding = 1; fsz += 1; // selector byte } else { // isbits struct if (((jl_datatype_t*)ty)->layout->haspadding) haspadding = 1; } } else { fsz = sizeof(void*); if (fsz > MAX_ALIGN) fsz = MAX_ALIGN; al = fsz; desc[i].isptr = 1; } assert(al <= JL_HEAP_ALIGNMENT && (JL_HEAP_ALIGNMENT % al) == 0); if (al != 0) { size_t alsz = LLT_ALIGN(sz, al); if (sz & (al - 1)) haspadding = 1; sz = alsz; if (al > alignm) alignm = al; } homogeneous &= lastty==NULL || lastty==ty; lastty = ty; desc[i].offset = sz; desc[i].size = fsz; if (__unlikely(max_offset - sz < fsz)) goto throw_ovf; sz += fsz; } if (homogeneous && lastty != NULL && jl_is_tuple_type(st)) { // Some tuples become LLVM vectors with stronger alignment than what was calculated above. unsigned al = jl_special_vector_alignment(nfields, lastty); assert(al % alignm == 0); // JL_HEAP_ALIGNMENT is the biggest alignment we can guarantee on the heap. if (al > JL_HEAP_ALIGNMENT) alignm = JL_HEAP_ALIGNMENT; else if (al) alignm = al; } st->size = LLT_ALIGN(sz, alignm); if (st->size > sz) haspadding = 1; st->layout = jl_get_layout(nfields, alignm, haspadding, desc); if (descsz >= jl_page_size) free(desc); jl_allocate_singleton_instance(st); return; throw_ovf: if (descsz >= jl_page_size) free(desc); jl_errorf("type %s has field offset %d that exceeds the page size", jl_symbol_name(st->name->name), descsz); }
JL_DLLEXPORT jl_array_t *jl_ptr_to_array(jl_value_t *atype, void *data, jl_value_t *_dims, int own_buffer) { jl_ptls_t ptls = jl_get_ptls_states(); size_t nel = 1; jl_array_t *a; size_t ndims = jl_nfields(_dims); wideint_t prod; assert(is_ntuple_long(_dims)); size_t *dims = (size_t*)_dims; for (size_t i = 0; i < ndims; i++) { prod = (wideint_t)nel * (wideint_t)dims[i]; if (prod > (wideint_t) MAXINTVAL) jl_error("invalid Array dimensions"); nel = prod; } if (__unlikely(ndims == 1)) return jl_ptr_to_array_1d(atype, data, nel, own_buffer); jl_value_t *eltype = jl_tparam0(atype); int isunboxed = jl_array_store_unboxed(eltype); size_t elsz; unsigned align; if (isunboxed && jl_is_uniontype(eltype)) jl_exceptionf(jl_argumenterror_type, "unsafe_wrap: unspecified layout for union element type"); if (isunboxed) { elsz = jl_datatype_size(eltype); align = jl_datatype_align(eltype); } else { align = elsz = sizeof(void*); } if (((uintptr_t)data) & (align - 1)) jl_exceptionf(jl_argumenterror_type, "unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align); int ndimwords = jl_array_ndimwords(ndims); int tsz = JL_ARRAY_ALIGN(sizeof(jl_array_t) + ndimwords*sizeof(size_t), JL_CACHE_BYTE_ALIGNMENT); a = (jl_array_t*)jl_gc_alloc(ptls, tsz, atype); // No allocation or safepoint allowed after this a->flags.pooled = tsz <= GC_MAX_SZCLASS; a->data = data; #ifdef STORE_ARRAY_LEN a->length = nel; #endif a->elsize = elsz; a->flags.ptrarray = !isunboxed; a->flags.ndims = ndims; a->offset = 0; a->flags.isshared = 1; a->flags.isaligned = 0; if (own_buffer) { a->flags.how = 2; jl_gc_track_malloced_array(ptls, a); jl_gc_count_allocd(nel*elsz + (elsz == 1 ? 1 : 0)); } else { a->flags.how = 0; } assert(ndims != 1); // handled above memcpy(&a->nrows, dims, ndims * sizeof(size_t)); return a; }
static jl_array_t *_new_array_(jl_value_t *atype, uint32_t ndims, size_t *dims, int isunboxed, int isunion, int elsz) { jl_ptls_t ptls = jl_get_ptls_states(); size_t i, tot, nel=1; void *data; jl_array_t *a; for(i=0; i < ndims; i++) { size_t di = dims[i]; wideint_t prod = (wideint_t)nel * (wideint_t)di; if (prod > (wideint_t) MAXINTVAL || di > MAXINTVAL) jl_error("invalid Array dimensions"); nel = prod; } assert(atype == NULL || isunion == jl_is_uniontype(jl_tparam0(atype))); if (isunboxed) { wideint_t prod = (wideint_t)elsz * (wideint_t)nel; if (prod > (wideint_t) MAXINTVAL) jl_error("invalid Array size"); tot = prod; if (elsz == 1 && !isunion) { // extra byte for all julia allocated byte arrays tot++; } if (isunion) { // an extra byte for each isbits union array element, stored after a->maxsize tot += nel; } } else { wideint_t prod = (wideint_t)sizeof(void*) * (wideint_t)nel; if (prod > (wideint_t) MAXINTVAL) jl_error("invalid Array size"); tot = prod; } int ndimwords = jl_array_ndimwords(ndims); int tsz = JL_ARRAY_ALIGN(sizeof(jl_array_t) + ndimwords*sizeof(size_t), JL_CACHE_BYTE_ALIGNMENT); if (tot <= ARRAY_INLINE_NBYTES) { if (isunboxed && elsz >= 4) tsz = JL_ARRAY_ALIGN(tsz, JL_SMALL_BYTE_ALIGNMENT); // align data area size_t doffs = tsz; tsz += tot; tsz = JL_ARRAY_ALIGN(tsz, JL_SMALL_BYTE_ALIGNMENT); // align whole object a = (jl_array_t*)jl_gc_alloc(ptls, tsz, atype); // No allocation or safepoint allowed after this a->flags.how = 0; data = (char*)a + doffs; if ((tot > 0 && !isunboxed) || isunion) memset(data, 0, tot); } else { tsz = JL_ARRAY_ALIGN(tsz, JL_CACHE_BYTE_ALIGNMENT); // align whole object data = jl_gc_managed_malloc(tot); // Allocate the Array **after** allocating the data // to make sure the array is still young a = (jl_array_t*)jl_gc_alloc(ptls, tsz, atype); // No allocation or safepoint allowed after this a->flags.how = 2; jl_gc_track_malloced_array(ptls, a); if (!isunboxed || isunion) // need to zero out isbits union array selector bytes to ensure a valid type index memset(data, 0, tot); } a->flags.pooled = tsz <= GC_MAX_SZCLASS; a->data = data; if (JL_ARRAY_IMPL_NUL && elsz == 1) ((char*)data)[tot - 1] = '\0'; #ifdef STORE_ARRAY_LEN a->length = nel; #endif a->flags.ndims = ndims; a->flags.ptrarray = !isunboxed; a->elsize = elsz; a->flags.isshared = 0; a->flags.isaligned = 1; a->offset = 0; if (ndims == 1) { a->nrows = nel; a->maxsize = nel; } else { size_t *adims = &a->nrows; for(i=0; i < ndims; i++) adims[i] = dims[i]; } return a; }
// f(::Union{...}, ...) is a common pattern // and expanding the Union may give a leaf function static void _compile_all_union(jl_value_t *sig) { jl_tupletype_t *sigbody = (jl_tupletype_t*)jl_unwrap_unionall(sig); size_t count_unions = 0; size_t i, l = jl_svec_len(sigbody->parameters); jl_svec_t *p = NULL; jl_value_t *methsig = NULL; for (i = 0; i < l; i++) { jl_value_t *ty = jl_svecref(sigbody->parameters, i); if (jl_is_uniontype(ty)) ++count_unions; else if (ty == jl_bottom_type) return; // why does this method exist? else if (jl_is_datatype(ty) && !jl_has_free_typevars(ty) && ((!jl_is_kind(ty) && ((jl_datatype_t*)ty)->isconcretetype) || ((jl_datatype_t*)ty)->name == jl_type_typename)) return; // no amount of union splitting will make this a leaftype signature } if (count_unions == 0 || count_unions >= 6) { _compile_all_tvar_union(sig); return; } int *idx = (int*)alloca(sizeof(int) * count_unions); for (i = 0; i < count_unions; i++) { idx[i] = 0; } JL_GC_PUSH2(&p, &methsig); int idx_ctr = 0, incr = 0; while (!incr) { p = jl_alloc_svec_uninit(l); for (i = 0, idx_ctr = 0, incr = 1; i < l; i++) { jl_value_t *ty = jl_svecref(sigbody->parameters, i); if (jl_is_uniontype(ty)) { assert(idx_ctr < count_unions); size_t l = jl_count_union_components(ty); size_t j = idx[idx_ctr]; jl_svecset(p, i, jl_nth_union_component(ty, j)); ++j; if (incr) { if (j == l) { idx[idx_ctr] = 0; } else { idx[idx_ctr] = j; incr = 0; } } ++idx_ctr; } else { jl_svecset(p, i, ty); } } methsig = (jl_value_t*)jl_apply_tuple_type(p); methsig = jl_rewrap_unionall(methsig, sig); _compile_all_tvar_union(methsig); } JL_GC_POP(); }
// `v` might be pointing to a field inlined in a structure therefore // `jl_typeof(v)` may not be the same with `vt` and only `vt` should be // used to determine the type of the value. // This is necessary to make sure that this function doesn't allocate any // memory through the Julia GC static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt, struct recur_list *depth) { size_t n = 0; if ((uintptr_t)vt < 4096U) { n += jl_printf(out, "<?#%p::%p>", (void*)v, (void*)vt); } else if ((uintptr_t)v < 4096U) { n += jl_printf(out, "<?#%p::", (void*)v); n += jl_static_show_x(out, (jl_value_t*)vt, depth); n += jl_printf(out, ">"); } else if (vt == jl_method_type) { jl_method_t *m = (jl_method_t*)v; n += jl_static_show_x(out, (jl_value_t*)m->module, depth); n += jl_printf(out, ".%s(...)", jl_symbol_name(m->name)); } else if (vt == jl_method_instance_type) { jl_method_instance_t *li = (jl_method_instance_t*)v; if (jl_is_method(li->def.method)) { jl_method_t *m = li->def.method; n += jl_static_show_x(out, (jl_value_t*)m->module, depth); if (li->specTypes) { n += jl_printf(out, "."); n += jl_show_svec(out, ((jl_datatype_t*)jl_unwrap_unionall(li->specTypes))->parameters, jl_symbol_name(m->name), "(", ")"); } else { n += jl_printf(out, ".%s(?)", jl_symbol_name(m->name)); } } else { n += jl_static_show_x(out, (jl_value_t*)li->def.module, depth); n += jl_printf(out, ".<toplevel thunk> -> "); n += jl_static_show_x(out, li->inferred, depth); } } else if (vt == jl_simplevector_type) { n += jl_show_svec(out, (jl_svec_t*)v, "svec", "(", ")"); } else if (vt == jl_datatype_type) { jl_datatype_t *dv = (jl_datatype_t*)v; jl_sym_t *globname = dv->name->mt != NULL ? dv->name->mt->name : NULL; int globfunc = 0; if (globname && !strchr(jl_symbol_name(globname), '#') && !strchr(jl_symbol_name(globname), '@') && dv->name->module && jl_binding_resolved_p(dv->name->module, globname)) { jl_binding_t *b = jl_get_binding(dv->name->module, globname); if (b && jl_typeof(b->value) == v) globfunc = 1; } jl_sym_t *sym = globfunc ? globname : dv->name->name; char *sn = jl_symbol_name(sym); int hidden = !globfunc && strchr(sn, '#'); size_t i = 0; int quote = 0; if (hidden) { n += jl_printf(out, "getfield("); } else if (globfunc) { n += jl_printf(out, "typeof("); } if (dv->name->module != jl_core_module || !jl_module_exports_p(jl_core_module, sym)) { n += jl_static_show_x(out, (jl_value_t*)dv->name->module, depth); if (!hidden) { n += jl_printf(out, "."); if (globfunc && !jl_id_start_char(u8_nextchar(sn, &i))) { n += jl_printf(out, ":("); quote = 1; } } } if (hidden) { n += jl_printf(out, ", Symbol(\""); n += jl_printf(out, "%s", sn); n += jl_printf(out, "\"))"); } else { n += jl_printf(out, "%s", sn); if (globfunc) { n += jl_printf(out, ")"); if (quote) n += jl_printf(out, ")"); } } if (dv->parameters && (jl_value_t*)dv != dv->name->wrapper && (jl_has_free_typevars(v) || (jl_value_t*)dv != (jl_value_t*)jl_tuple_type)) { size_t j, tlen = jl_nparams(dv); if (tlen > 0) { n += jl_printf(out, "{"); for (j = 0; j < tlen; j++) { jl_value_t *p = jl_tparam(dv,j); n += jl_static_show_x(out, p, depth); if (j != tlen-1) n += jl_printf(out, ", "); } n += jl_printf(out, "}"); } else if (dv->name == jl_tuple_typename) { n += jl_printf(out, "{}"); } } } else if (vt == jl_intrinsic_type) { int f = *(uint32_t*)jl_data_ptr(v); n += jl_printf(out, "#<intrinsic #%d %s>", f, jl_intrinsic_name(f)); } else if (vt == jl_int64_type) { n += jl_printf(out, "%" PRId64, *(int64_t*)v); } else if (vt == jl_int32_type) { n += jl_printf(out, "%" PRId32, *(int32_t*)v); } else if (vt == jl_int16_type) { n += jl_printf(out, "%" PRId16, *(int16_t*)v); } else if (vt == jl_int8_type) { n += jl_printf(out, "%" PRId8, *(int8_t*)v); } else if (vt == jl_uint64_type) { n += jl_printf(out, "0x%016" PRIx64, *(uint64_t*)v); } else if (vt == jl_uint32_type) { n += jl_printf(out, "0x%08" PRIx32, *(uint32_t*)v); } else if (vt == jl_uint16_type) { n += jl_printf(out, "0x%04" PRIx16, *(uint16_t*)v); } else if (vt == jl_uint8_type) { n += jl_printf(out, "0x%02" PRIx8, *(uint8_t*)v); } else if (jl_is_cpointer_type((jl_value_t*)vt)) { #ifdef _P64 n += jl_printf(out, "0x%016" PRIx64, *(uint64_t*)v); #else n += jl_printf(out, "0x%08" PRIx32, *(uint32_t*)v); #endif } else if (vt == jl_float32_type) { n += jl_printf(out, "%gf", *(float*)v); } else if (vt == jl_float64_type) { n += jl_printf(out, "%g", *(double*)v); } else if (vt == jl_bool_type) { n += jl_printf(out, "%s", *(uint8_t*)v ? "true" : "false"); } else if ((jl_value_t*)vt == jl_typeof(jl_nothing)) { n += jl_printf(out, "nothing"); } else if (vt == jl_string_type) { n += jl_printf(out, "\""); jl_uv_puts(out, jl_string_data(v), jl_string_len(v)); n += jl_string_len(v); n += jl_printf(out, "\""); } else if (v == jl_bottom_type) { n += jl_printf(out, "Union{}"); } else if (vt == jl_uniontype_type) { n += jl_printf(out, "Union{"); while (jl_is_uniontype(v)) { // tail-recurse on b to flatten the printing of the Union structure in the common case n += jl_static_show_x(out, ((jl_uniontype_t*)v)->a, depth); n += jl_printf(out, ", "); v = ((jl_uniontype_t*)v)->b; } n += jl_static_show_x(out, v, depth); n += jl_printf(out, "}"); } else if (vt == jl_unionall_type) { jl_unionall_t *ua = (jl_unionall_t*)v; n += jl_static_show_x(out, ua->body, depth); n += jl_printf(out, " where "); n += jl_static_show_x(out, (jl_value_t*)ua->var, depth->prev); } else if (vt == jl_tvar_type) { // show type-var bounds only if they aren't going to be printed by UnionAll later jl_tvar_t *var = (jl_tvar_t*)v; struct recur_list *p; int showbounds = 1; for (p = depth; p != NULL; p = p->prev) { if (jl_is_unionall(p->v) && ((jl_unionall_t*)p->v)->var == var) { showbounds = 0; break; } } jl_value_t *lb = var->lb, *ub = var->ub; if (showbounds && lb != jl_bottom_type) { // show type-var lower bound if it is defined int ua = jl_is_unionall(lb); if (ua) n += jl_printf(out, "("); n += jl_static_show_x(out, lb, depth); if (ua) n += jl_printf(out, ")"); n += jl_printf(out, "<:"); } n += jl_printf(out, "%s", jl_symbol_name(var->name)); if (showbounds && (ub != (jl_value_t*)jl_any_type || lb != jl_bottom_type)) { // show type-var upper bound if it is defined, or if we showed the lower bound int ua = jl_is_unionall(ub); n += jl_printf(out, "<:"); if (ua) n += jl_printf(out, "("); n += jl_static_show_x(out, ub, depth); if (ua) n += jl_printf(out, ")"); } } else if (vt == jl_module_type) { jl_module_t *m = (jl_module_t*)v; if (m->parent != m && m->parent != jl_main_module) { n += jl_static_show_x(out, (jl_value_t*)m->parent, depth); n += jl_printf(out, "."); } n += jl_printf(out, "%s", jl_symbol_name(m->name)); } else if (vt == jl_sym_type) { char *sn = jl_symbol_name((jl_sym_t*)v); int quoted = !jl_is_identifier(sn) && jl_operator_precedence(sn) == 0; if (quoted) n += jl_printf(out, "Symbol(\""); else n += jl_printf(out, ":"); n += jl_printf(out, "%s", sn); if (quoted) n += jl_printf(out, "\")"); } else if (vt == jl_ssavalue_type) { n += jl_printf(out, "SSAValue(%" PRIuPTR ")", (uintptr_t)((jl_ssavalue_t*)v)->id); } else if (vt == jl_globalref_type) { n += jl_static_show_x(out, (jl_value_t*)jl_globalref_mod(v), depth); n += jl_printf(out, ".%s", jl_symbol_name(jl_globalref_name(v))); } else if (vt == jl_labelnode_type) { n += jl_printf(out, "%" PRIuPTR ":", jl_labelnode_label(v)); } else if (vt == jl_gotonode_type) { n += jl_printf(out, "goto %" PRIuPTR, jl_gotonode_label(v)); } else if (vt == jl_quotenode_type) { jl_value_t *qv = *(jl_value_t**)v; if (!jl_is_symbol(qv)) { n += jl_printf(out, "quote "); } else { n += jl_printf(out, ":("); } n += jl_static_show_x(out, qv, depth); if (!jl_is_symbol(qv)) { n += jl_printf(out, " end"); } else { n += jl_printf(out, ")"); } } else if (vt == jl_newvarnode_type) { n += jl_printf(out, "<newvar "); n += jl_static_show_x(out, *(jl_value_t**)v, depth); n += jl_printf(out, ">"); } else if (vt == jl_linenumbernode_type) { n += jl_printf(out, "#= "); n += jl_static_show_x(out, jl_linenode_file(v), depth); n += jl_printf(out, ":%" PRIuPTR " =#", jl_linenode_line(v)); } else if (vt == jl_expr_type) { jl_expr_t *e = (jl_expr_t*)v; if (e->head == assign_sym && jl_array_len(e->args) == 2) { n += jl_static_show_x(out, jl_exprarg(e,0), depth); n += jl_printf(out, " = "); n += jl_static_show_x(out, jl_exprarg(e,1), depth); } else { char sep = ' '; if (e->head == body_sym) sep = '\n'; n += jl_printf(out, "Expr(:%s", jl_symbol_name(e->head)); 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_x(out, jl_exprarg(e,i), depth); } n += jl_printf(out, ")::"); n += jl_static_show_x(out, e->etype, depth); } } else if (jl_is_array_type(vt)) { n += jl_static_show_x(out, (jl_value_t*)vt, depth); n += jl_printf(out, "["); size_t j, tlen = jl_array_len(v); jl_array_t *av = (jl_array_t*)v; jl_datatype_t *el_type = (jl_datatype_t*)jl_tparam0(vt); int nlsep = 0; if (av->flags.ptrarray) { // print arrays with newlines, unless the elements are probably small for (j = 0; j < tlen; j++) { jl_value_t *p = jl_array_ptr_ref(av, j); if (p != NULL && (uintptr_t)p >= 4096U) { jl_value_t *p_ty = jl_typeof(p); if ((uintptr_t)p_ty >= 4096U) { if (!jl_isbits(p_ty)) { nlsep = 1; break; } } } } } if (nlsep && tlen > 1) n += jl_printf(out, "\n "); for (j = 0; j < tlen; j++) { if (av->flags.ptrarray) { n += jl_static_show_x(out, jl_array_ptr_ref(v, j), depth); } else { char *ptr = ((char*)av->data) + j * av->elsize; n += jl_static_show_x_(out, (jl_value_t*)ptr, el_type, depth); } if (j != tlen - 1) n += jl_printf(out, nlsep ? ",\n " : ", "); } n += jl_printf(out, "]"); } else if (vt == jl_loaderror_type) { n += jl_printf(out, "LoadError(at "); n += jl_static_show_x(out, *(jl_value_t**)v, depth); // Access the field directly to avoid allocation n += jl_printf(out, " line %" PRIdPTR, ((intptr_t*)v)[1]); n += jl_printf(out, ": "); n += jl_static_show_x(out, ((jl_value_t**)v)[2], depth); n += jl_printf(out, ")"); } else if (vt == jl_errorexception_type) { n += jl_printf(out, "ErrorException("); n += jl_static_show_x(out, *(jl_value_t**)v, depth); n += jl_printf(out, ")"); } else if (jl_is_datatype(vt)) { int istuple = jl_is_tuple_type(vt); if (!istuple) n += jl_static_show_x(out, (jl_value_t*)vt, depth); n += jl_printf(out, "("); size_t nb = jl_datatype_size(vt); size_t tlen = jl_datatype_nfields(vt); if (nb > 0 && tlen == 0) { uint8_t *data = (uint8_t*)v; n += jl_printf(out, "0x"); for(int i = nb - 1; i >= 0; --i) n += jl_printf(out, "%02" PRIx8, data[i]); } else { size_t i = 0; if (vt == jl_typemap_entry_type) i = 1; for (; i < tlen; i++) { if (!istuple) { n += jl_printf(out, "%s", jl_symbol_name(jl_field_name(vt, i))); n += jl_printf(out, "="); } size_t offs = jl_field_offset(vt, i); char *fld_ptr = (char*)v + offs; if (jl_field_isptr(vt, i)) { n += jl_static_show_x(out, *(jl_value_t**)fld_ptr, depth); } else { jl_datatype_t *ft = (jl_datatype_t*)jl_field_type(vt, i); if (jl_is_uniontype(ft)) { uint8_t sel = ((uint8_t*)fld_ptr)[jl_field_size(vt, i) - 1]; ft = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)ft, sel); } n += jl_static_show_x_(out, (jl_value_t*)fld_ptr, ft, depth); } if (istuple && tlen == 1) n += jl_printf(out, ","); else if (i != tlen - 1) n += jl_printf(out, ", "); } if (vt == jl_typemap_entry_type) { n += jl_printf(out, ", next=↩︎\n "); n += jl_static_show_x(out, jl_fieldref(v, 0), depth); } } n += jl_printf(out, ")"); } else { n += jl_printf(out, "<?#%p::", (void*)v); n += jl_static_show_x(out, (jl_value_t*)vt, depth); n += jl_printf(out, ">"); } return n; }