diff --git a/src/abi_x86_64.cpp b/src/abi_x86_64.cpp index 08aac96aa52cc..845401183885d 100644 --- a/src/abi_x86_64.cpp +++ b/src/abi_x86_64.cpp @@ -133,7 +133,8 @@ void classifyType(Classification& accum, jl_value_t* ty, uint64_t offset) { else if (jl_datatype_size(ty) <= 16) { size_t i; for (i = 0; i < jl_datatype_nfields(ty); ++i) { - classifyType(accum, jl_field_type(ty,i), offset + jl_field_offset(ty,i)); + classifyType(accum, jl_field_type((jl_datatype_t*)ty,i), + offset + jl_field_offset((jl_datatype_t*)ty,i)); } } else { diff --git a/src/alloc.c b/src/alloc.c index 522bbba61d5d0..c0a5c22c8fdb8 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -298,8 +298,9 @@ DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uin jl_set_nth_field(jv, i, args[i]); } for(size_t i=na; i < nf; i++) { - if (type->fields[i].isptr) + if (jl_field_isptr(type, i)) { *(jl_value_t**)((char*)jl_data_ptr(jv)+jl_field_offset(type,i)) = NULL; + } } return jv; } @@ -535,11 +536,18 @@ jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_datatype_t *super, return dt; } -jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields) +jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields, + int8_t fielddesc_type) { + // fielddesc_type is specified manually for builtin types + // and is (will be) calculated automatically for user defined types. + uint32_t fielddesc_size = jl_fielddesc_size(fielddesc_type); jl_datatype_t *t = (jl_datatype_t*) newobj((jl_value_t*)jl_datatype_type, - NWORDS(sizeof(jl_datatype_t) + nfields*sizeof(jl_fielddesc_t))); + NWORDS(sizeof(jl_datatype_t) + nfields * fielddesc_size)); + // fielddesc_type should only be assigned here. It can cause data + // corruption otherwise. + t->fielddesc_type = fielddesc_type; t->nfields = nfields; return t; } @@ -549,15 +557,22 @@ void jl_compute_field_offsets(jl_datatype_t *st) size_t sz = 0, alignm = 1; int ptrfree = 1; + assert(0 <= st->fielddesc_type && st->fielddesc_type <= 2); + + uint64_t max_offset = (((uint64_t)1) << + (1 << (3 + st->fielddesc_type))) - 1; + uint64_t max_size = max_offset >> 1; + for(size_t i=0; i < jl_datatype_nfields(st); i++) { jl_value_t *ty = jl_field_type(st, i); size_t fsz, al; if (jl_isbits(ty) && jl_is_leaf_type(ty)) { fsz = jl_datatype_size(ty); - if (__unlikely(fsz > JL_FIELD_MAX_SIZE)) + // Should never happen + if (__unlikely(fsz > max_size)) jl_throw(jl_overflow_exception); al = ((jl_datatype_t*)ty)->alignment; - st->fields[i].isptr = 0; + jl_field_setisptr(st, i, 0); if (((jl_datatype_t*)ty)->haspadding) st->haspadding = 1; } @@ -566,7 +581,7 @@ void jl_compute_field_offsets(jl_datatype_t *st) if (fsz > MAX_ALIGN) fsz = MAX_ALIGN; al = fsz; - st->fields[i].isptr = 1; + jl_field_setisptr(st, i, 1); ptrfree = 0; } if (al != 0) { @@ -577,10 +592,10 @@ void jl_compute_field_offsets(jl_datatype_t *st) if (al > alignm) alignm = al; } - if (__unlikely(sz > JL_FIELD_MAX_OFFSET)) + jl_field_setoffset(st, i, sz); + jl_field_setsize(st, i, fsz); + if (__unlikely(max_offset - sz < fsz)) jl_throw(jl_overflow_exception); - st->fields[i].offset = sz; - st->fields[i].size = fsz; sz += fsz; } st->alignment = alignm; @@ -612,7 +627,7 @@ jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, t = jl_bool_type; } if (t == NULL) - t = jl_new_uninitialized_datatype(jl_svec_len(fnames)); + t = jl_new_uninitialized_datatype(jl_svec_len(fnames), 2); // TODO else tn = t->name; // init before possibly calling jl_new_typename diff --git a/src/builtins.c b/src/builtins.c index 56b0cef763a49..7dc6319a7aa1d 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -254,11 +254,11 @@ static int NOINLINE compare_fields(jl_value_t *a, jl_value_t *b, jl_datatype_t * { size_t nf = jl_datatype_nfields(dt); for (size_t f=0; f < nf; f++) { - size_t offs = dt->fields[f].offset; + size_t offs = jl_field_offset(dt, f); char *ao = (char*)jl_data_ptr(a) + offs; char *bo = (char*)jl_data_ptr(b) + offs; int eq; - if (dt->fields[f].isptr) { + 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) eq = 1; @@ -268,7 +268,7 @@ static int NOINLINE compare_fields(jl_value_t *a, jl_value_t *b, jl_datatype_t * else { jl_datatype_t *ft = (jl_datatype_t*)jl_field_type(dt, f); if (!ft->haspadding) { - eq = bits_equal(ao, bo, dt->fields[f].size); + eq = bits_equal(ao, bo, jl_field_size(dt, f)); } else { assert(jl_datatype_nfields(ft) > 0); @@ -1178,20 +1178,20 @@ static uptrint_t jl_object_id_(jl_value_t *tv, jl_value_t *v) return bits_hash(jl_data_ptr(v), sz) ^ h; } for (size_t f=0; f < nf; f++) { - size_t offs = dt->fields[f].offset; + size_t offs = jl_field_offset(dt, f); char *vo = (char*)jl_data_ptr(v) + offs; uptrint_t u; - if (dt->fields[f].isptr) { + 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_svecref(dt->types, f); + jl_datatype_t *fieldtype = (jl_datatype_t*)jl_field_type(dt, f); assert(jl_is_datatype(fieldtype) && !fieldtype->abstract && !fieldtype->mutabl); if (fieldtype->haspadding) u = jl_object_id_((jl_value_t*)fieldtype, (jl_value_t*)vo); else - u = bits_hash(vo, dt->fields[f].size); + u = bits_hash(vo, jl_field_size(dt, f)); } h = bitmix(h, u); } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index a1181ea144ca1..df41e151d7692 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -727,7 +727,7 @@ static Type *julia_struct_to_llvm(jl_value_t *jt) for(i = 0; i < ntypes; i++) { jl_value_t *ty = jl_svecref(jst->types, i); Type *lty; - if (jst->fields[i].isptr) + if (jl_field_isptr(jst, i)) lty = jl_pvalue_llvmt; else lty = ty==(jl_value_t*)jl_bool_type ? T_int8 : julia_type_to_llvm(ty); @@ -764,8 +764,9 @@ static bool is_datatype_all_pointers(jl_datatype_t *dt) { size_t i, l = jl_datatype_nfields(dt); for(i=0; i < l; i++) { - if (!dt->fields[i].isptr) + if (!jl_field_isptr(dt, i)) { return false; + } } return true; } @@ -1848,7 +1849,7 @@ static void emit_setfield(jl_datatype_t *sty, const jl_cgval_t &strct, size_t id builder.CreateGEP(builder.CreateBitCast(strct.V, T_pint8), ConstantInt::get(T_size, jl_field_offset(sty,idx0))); jl_value_t *jfty = jl_svecref(sty->types, idx0); - if (sty->fields[idx0].isptr) { + if (jl_field_isptr(sty, idx0)) { Value *r = boxed(rhs, ctx); builder.CreateStore(r, builder.CreateBitCast(addr, jl_ppvalue_llvmt)); @@ -1912,7 +1913,7 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg } } size_t j = 0; - if (nf > 0 && sty->fields[0].isptr && nargs>1) { + if (nf > 0 && jl_field_isptr(sty, 0) && nargs>1) { // emit first field before allocating struct to save // a couple store instructions. avoids initializing // the first field to NULL, and sometimes the GC root @@ -1940,7 +1941,7 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg make_gcroot(strct, ctx); } for(size_t i=j; i < nf; i++) { - if (sty->fields[i].isptr) { + if (jl_field_isptr(sty, i)) { builder.CreateStore( V_null, builder.CreatePointerCast( @@ -1952,7 +1953,7 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg bool need_wb = false; for(size_t i=j+1; i < nargs; i++) { jl_cgval_t rhs = emit_expr(args[i],ctx); - if (sty->fields[i-1].isptr && !rhs.isboxed) { + if (jl_field_isptr(sty, i - 1) && !rhs.isboxed) { if (!needroots) { // if this struct element needs boxing and we haven't rooted // the struct, root it now. diff --git a/src/codegen.cpp b/src/codegen.cpp index 7790fce807564..41236b3b9cae5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1756,7 +1756,7 @@ static bool is_getfield_nonallocating(jl_datatype_t *ty, jl_value_t *fld) else if (jl_is_quotenode(fld) && jl_is_long(jl_fieldref(fld,0))) idx = jl_unbox_long(jl_fieldref(fld,0))-1; for(size_t i=0; i < jl_svec_len(ty->types); i++) { - if (!(ty->fields[i].isptr || (idx >= 0 && (size_t)idx != i))) + if (!(jl_field_isptr(ty,i) || (idx >= 0 && (size_t)idx != i))) return false; } return true; @@ -2570,7 +2570,7 @@ static bool emit_known_call(jl_cgval_t *ret, jl_value_t *ff, if (jl_is_leaf_type((jl_value_t*)sty) && jl_subtype(rhst, ft, 0)) { // TODO: attempt better codegen for approximate types jl_cgval_t strct = emit_expr(args[1], ctx); // emit lhs - if (sty->fields[idx].isptr) // emit rhs + if (jl_field_isptr(sty, idx)) // emit rhs *ret = emit_expr(args[3], ctx); else *ret = emit_unboxed(args[3], ctx); diff --git a/src/dump.c b/src/dump.c index 4c17fc693d385..ac223e305681d 100644 --- a/src/dump.c +++ b/src/dump.c @@ -514,6 +514,7 @@ static void jl_serialize_datatype(ios_t *s, jl_datatype_t *dt) write_int32(s, dt->size); int has_instance = !!(dt->instance != NULL); write_uint8(s, dt->abstract | (dt->mutabl<<1) | (dt->pointerfree<<2) | (has_instance<<3)); + write_int8(s, dt->fielddesc_type); if (!dt->abstract) { write_uint16(s, dt->ninitialized); if (mode != MODE_MODULE && mode != MODE_MODULE_POSTWORK) { @@ -525,7 +526,8 @@ static void jl_serialize_datatype(ios_t *s, jl_datatype_t *dt) if (nf > 0) { write_int32(s, dt->alignment); write_int8(s, dt->haspadding); - ios_write(s, (char*)&dt->fields[0], nf*sizeof(jl_fielddesc_t)); + size_t fieldsize = jl_fielddesc_size(dt->fielddesc_type); + ios_write(s, (char*)&dt->fields32[0], nf * fieldsize); jl_serialize_value(s, dt->types); } @@ -896,7 +898,7 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v) } else { for(size_t i=0; i < nf; i++) { - if (t->fields[i].size > 0) { + if (jl_field_size(t, i) > 0) { jl_serialize_value(s, jl_get_nth_field(v, i)); } } @@ -1082,6 +1084,7 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc) uint16_t nf = read_uint16(s); size_t size = read_int32(s); uint8_t flags = read_uint8(s); + uint8_t fielddesc_type = read_int8(s); jl_datatype_t *dt; if (tag == 2) dt = jl_int32_type; @@ -1090,7 +1093,7 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc) else if (tag == 4) dt = jl_int64_type; else - dt = jl_new_uninitialized_datatype(nf); + dt = jl_new_uninitialized_datatype(nf, fielddesc_type); assert(tree_literal_values==NULL && mode != MODE_AST); backref_list.items[pos] = dt; dt->size = size; @@ -1125,7 +1128,8 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos, jl_value_t **loc) if (nf > 0) { dt->alignment = read_int32(s); dt->haspadding = read_int8(s); - ios_read(s, (char*)&dt->fields[0], nf*sizeof(jl_fielddesc_t)); + size_t fieldsize = jl_fielddesc_size(fielddesc_type); + ios_read(s, (char*)&dt->fields32[0], nf * fieldsize); dt->types = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->types); jl_gc_wb(dt, dt->types); } @@ -1511,8 +1515,8 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t else { char *data = (char*)jl_data_ptr(v); for(i=0; i < nf; i++) { - if (dt->fields[i].size > 0) { - if (dt->fields[i].isptr) { + if (jl_field_size(dt,i) > 0) { + if (jl_field_isptr(dt,i)) { jl_value_t **fld = (jl_value_t**)(data+jl_field_offset(dt, i)); *fld = jl_deserialize_value(s, fld); } diff --git a/src/gc.c b/src/gc.c index 30cc8da014119..d05dd4dc11d50 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1734,21 +1734,25 @@ static int push_root(jl_value_t *v, int d, int bits) else if (gc_typeof(vt) == (jl_value_t*)jl_datatype_type) { jl_datatype_t *dt = (jl_datatype_t*)vt; size_t dtsz; - if (dt == jl_datatype_type) - dtsz = NWORDS(sizeof(jl_datatype_t) + jl_datatype_nfields(v)*sizeof(jl_fielddesc_t))*sizeof(void*); - else + if (dt == jl_datatype_type) { + size_t fieldsize = + jl_fielddesc_size(((jl_datatype_t*)v)->fielddesc_type); + dtsz = NWORDS(sizeof(jl_datatype_t) + + jl_datatype_nfields(v) * fieldsize) * sizeof(void*); + } else { dtsz = jl_datatype_size(dt); + } MARK(v, bits = gc_setmark(v, dtsz, GC_MARKED_NOESC)); int nf = (int)jl_datatype_nfields(dt); // TODO check if there is a perf improvement for objects with a lot of fields // int fdsz = sizeof(void*)*nf; // void** children = alloca(fdsz); // int ci = 0; - jl_fielddesc_t* fields = dt->fields; for(int i=0; i < nf; i++) { - if (fields[i].isptr) { + if (jl_field_isptr(dt, i)) { nptr++; - jl_value_t **slot = (jl_value_t**)((char*)v + fields[i].offset); + jl_value_t **slot = (jl_value_t**)((char*)v + + jl_field_offset(dt, i)); jl_value_t *fld = *slot; if (fld) { verify_parent2("object", v, slot, "field(%d)", i); diff --git a/src/jltypes.c b/src/jltypes.c index da8cbbfd14f7e..7e62e8d383bdb 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2059,7 +2059,7 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i } // create and initialize new type - ndt = jl_new_uninitialized_datatype(istuple ? ntp : dt->nfields); + ndt = jl_new_uninitialized_datatype(istuple ? ntp : dt->nfields, 2); // TODO // associate these parameters with the new type on // the stack, in case one of its field types references it. top.tt = (jl_datatype_t*)ndt; @@ -3148,12 +3148,12 @@ extern void jl_init_int32_int64_cache(void); void jl_init_types(void) { // create base objects - jl_datatype_type = jl_new_uninitialized_datatype(10); + jl_datatype_type = jl_new_uninitialized_datatype(10, 1); jl_set_typeof(jl_datatype_type, jl_datatype_type); - jl_typename_type = jl_new_uninitialized_datatype(7); - jl_sym_type = jl_new_uninitialized_datatype(0); + jl_typename_type = jl_new_uninitialized_datatype(7, 1); + jl_sym_type = jl_new_uninitialized_datatype(0, 1); jl_symbol_type = jl_sym_type; - jl_simplevector_type = jl_new_uninitialized_datatype(1); + jl_simplevector_type = jl_new_uninitialized_datatype(1, 1); jl_emptysvec = (jl_svec_t*)newobj((jl_value_t*)jl_simplevector_type, 1); jl_svec_set_len_unsafe(jl_emptysvec, 0); diff --git a/src/julia.h b/src/julia.h index bcfb3b1df71bf..9f1988ffcf867 100644 --- a/src/julia.h +++ b/src/julia.h @@ -252,14 +252,23 @@ typedef struct { jl_svec_t *types; } jl_uniontype_t; +typedef struct { + uint8_t offset; // offset relative to data start, excluding type tag + uint8_t size:7; + uint8_t isptr:1; +} jl_fielddesc8_t; + typedef struct { uint16_t offset; // offset relative to data start, excluding type tag uint16_t size:15; uint16_t isptr:1; -} jl_fielddesc_t; +} jl_fielddesc16_t; -#define JL_FIELD_MAX_OFFSET ((1ul << 16) - 1ul) -#define JL_FIELD_MAX_SIZE ((1ul << 15) - 1ul) +typedef struct { + uint32_t offset; // offset relative to data start, excluding type tag + uint32_t size:31; + uint32_t isptr:1; +} jl_fielddesc32_t; typedef struct _jl_datatype_t { JL_DATA_TYPE @@ -275,12 +284,17 @@ typedef struct _jl_datatype_t { int32_t ninitialized; // hidden fields: uint32_t nfields; - uint32_t alignment : 31; // strictest alignment over all fields + uint32_t alignment : 29; // strictest alignment over all fields uint32_t haspadding : 1; // has internal undefined bytes + uint32_t fielddesc_type : 2; // 0 -> 8, 1 -> 16, 2 -> 32 uint32_t uid; void *struct_decl; //llvm::Value* void *ditype; // llvm::MDNode* to be used as llvm::DIType(ditype) - jl_fielddesc_t fields[]; + union { + jl_fielddesc8_t fields8[0]; + jl_fielddesc16_t fields16[0]; + jl_fielddesc32_t fields32[0]; + }; } jl_datatype_t; typedef struct { @@ -695,14 +709,57 @@ STATIC_INLINE jl_value_t *jl_cellset(void *a, size_t i, void *x) #define jl_data_ptr(v) (((jl_value_t*)v)->fieldptr) // struct type info -#define jl_field_offset(st,i) (((jl_datatype_t*)st)->fields[i].offset) -#define jl_field_size(st,i) (((jl_datatype_t*)st)->fields[i].size) -#define jl_field_isptr(st,i) (((jl_datatype_t*)st)->fields[i].isptr) #define jl_field_name(st,i) (jl_sym_t*)jl_svecref(((jl_datatype_t*)st)->name->names, (i)) #define jl_field_type(st,i) jl_svecref(((jl_datatype_t*)st)->types, (i)) #define jl_datatype_size(t) (((jl_datatype_t*)t)->size) #define jl_datatype_nfields(t) (((jl_datatype_t*)(t))->nfields) +#define DEFINE_FIELD_ACCESSORS(f) \ + static inline uint32_t jl_field_##f(jl_datatype_t *st, int i) \ + { \ + if (st->fielddesc_type == 0) { \ + return st->fields8[i].f; \ + } \ + else if (st->fielddesc_type == 1) { \ + return st->fields16[i].f; \ + } \ + else { \ + return st->fields32[i].f; \ + } \ + } \ + static inline void jl_field_set##f(jl_datatype_t *st, int i, \ + uint32_t val) \ + { \ + if (st->fielddesc_type == 0) { \ + st->fields8[i].f = val; \ + } \ + else if (st->fielddesc_type == 1) { \ + st->fields16[i].f = val; \ + } \ + else { \ + st->fields32[i].f = val; \ + } \ + } + +DEFINE_FIELD_ACCESSORS(offset) +DEFINE_FIELD_ACCESSORS(size) +DEFINE_FIELD_ACCESSORS(isptr) + +static inline uint32_t jl_fielddesc_size(int8_t fielddesc_type) +{ + if (fielddesc_type == 0) { + return sizeof(jl_fielddesc8_t); + } + else if (fielddesc_type == 1) { + return sizeof(jl_fielddesc16_t); + } + else { + return sizeof(jl_fielddesc32_t); + } +} + +#undef DEFINE_FIELD_ACCESSORS + // basic predicates ----------------------------------------------------------- #define jl_is_nothing(v) (((jl_value_t*)(v)) == ((jl_value_t*)jl_nothing)) #define jl_is_tuple(v) (((jl_datatype_t*)jl_typeof(v))->name == jl_tuple_typename) @@ -887,7 +944,8 @@ jl_value_t *jl_apply_type_(jl_value_t *tc, jl_value_t **params, size_t n); jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_datatype_t *super, jl_svec_t *parameters); -DLLEXPORT jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields); +DLLEXPORT jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields, + int8_t fielddesc_type); DLLEXPORT jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, jl_svec_t *parameters, jl_svec_t *fnames, jl_svec_t *ftypes, diff --git a/src/sys.c b/src/sys.c index 1953f06e810b3..4d88301b8aed3 100644 --- a/src/sys.c +++ b/src/sys.c @@ -614,7 +614,7 @@ DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field) { if (field > jl_datatype_nfields(ty)) jl_error("This type does not have that many fields"); - return ty->fields[field].offset; + return jl_field_offset(ty, field); } DLLEXPORT size_t jl_get_alignment(jl_datatype_t *ty) diff --git a/test/core.jl b/test/core.jl index 363789ef9f0b3..d3b44c6bd7dee 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3357,3 +3357,12 @@ for j = 1:1 continue end end + +# PR 11888 +immutable A11888{T} + a::NTuple{16,T} +end + +typealias B11888{T} A11888{A11888{A11888{T}}} + +@test sizeof(B11888{B11888{Int64}}) == (1 << 24) * 8