Skip to content

Commit 0043065

Browse files
authored
Record hidden ptr in layout (#92)
* Add fields about hidden pointers in jl_datatype_layout_t * Record hidden pointer in layout * Move the new field to the end of the struct
1 parent 1a472bb commit 0043065

File tree

5 files changed

+202
-23
lines changed

5 files changed

+202
-23
lines changed

base/runtime_internals.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,9 @@ struct DataTypeLayout
521521
size::UInt32
522522
nfields::UInt32
523523
npointers::UInt32
524+
nhidden_pointers::UInt32
524525
firstptr::Int32
526+
firsthiddenptr::Int32
525527
alignment::UInt16
526528
flags::UInt16
527529
# haspadding : 1;

src/datatype.c

Lines changed: 124 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu
8080
tn->partial = NULL;
8181
tn->atomicfields = NULL;
8282
tn->constfields = NULL;
83+
tn->hiddenptrfields = NULL;
8384
tn->max_methods = 0;
8485
tn->constprop_heustic = 0;
8586
return tn;
@@ -126,6 +127,7 @@ static uint32_t _hash_djb2(uint32_t hash, const char *mem, size_t s) JL_NOTSAFEP
126127
return hash;
127128
}
128129

130+
129131
static uint32_t _hash_layout_djb2(uintptr_t _layout, void *unused) JL_NOTSAFEPOINT
130132
{
131133
(void)unused;
@@ -138,11 +140,20 @@ static uint32_t _hash_layout_djb2(uintptr_t _layout, void *unused) JL_NOTSAFEPOI
138140
const char *pointers = jl_dt_layout_ptrs(layout);
139141
assert(pointers);
140142
size_t pointers_size = layout->first_ptr < 0 ? 0 : (layout->npointers << layout->flags.fielddesc_type);
143+
const char *hidden_pointers = NULL;
144+
size_t hidden_ptrs_size = 0;
145+
if (layout->first_hidden_ptr >= 0) {
146+
hidden_pointers = jl_dt_layout_hidden_ptrs(layout);
147+
hidden_ptrs_size = layout->nhidden_pointers << layout->flags.fielddesc_type;
148+
}
141149

142150
uint_t hash = 5381;
143151
hash = _hash_djb2(hash, (char *)layout, own_size);
144152
hash = _hash_djb2(hash, fields, fields_size);
145153
hash = _hash_djb2(hash, pointers, pointers_size);
154+
if (hidden_ptrs_size > 0) {
155+
hash = _hash_djb2(hash, hidden_pointers, hidden_ptrs_size);
156+
}
146157
return hash;
147158
}
148159

@@ -163,6 +174,13 @@ static int layout_eq(void *_l1, void *_l2, void *unused) JL_NOTSAFEPOINT
163174
size_t pointers_size = l1->first_ptr < 0 ? 0 : (l1->npointers << l1->flags.fielddesc_type);
164175
if (memcmp(p1, p2, pointers_size))
165176
return 0;
177+
if (l1->first_hidden_ptr >= 0 && l2->first_hidden_ptr >= 0) {
178+
const char *h1 = jl_dt_layout_hidden_ptrs(l1);
179+
const char *h2 = jl_dt_layout_hidden_ptrs(l2);
180+
size_t hidden_ptrs_size = l1->nhidden_pointers << l1->flags.fielddesc_type;
181+
if (memcmp(h1, h2, hidden_ptrs_size))
182+
return 0;
183+
}
166184
return 1;
167185
}
168186

@@ -174,15 +192,18 @@ HTIMPL_R(layoutcache, _hash_layout_djb2, layout_eq)
174192
static htable_t layoutcache;
175193
static int layoutcache_initialized = 0;
176194

195+
177196
static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
178197
uint32_t nfields,
179198
uint32_t npointers,
199+
uint32_t nhidden_pointers,
180200
uint32_t alignment,
181201
int haspadding,
182202
int isbitsegal,
183203
int arrayelem,
184204
jl_fielddesc32_t desc[],
185-
uint32_t pointers[]) JL_NOTSAFEPOINT
205+
uint32_t pointers[],
206+
uint32_t hidden_pointers[]) JL_NOTSAFEPOINT
186207
{
187208
assert(alignment); // should have been verified by caller
188209

@@ -212,11 +233,13 @@ static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
212233
}
213234
}
214235
int32_t first_ptr = (npointers > 0 ? (int32_t)pointers[0] : -1);
236+
int32_t first_hidden_ptr = (nhidden_pointers > 0 ? (int32_t)hidden_pointers[0] : -1);
215237

216238
// allocate a new descriptor, on the stack if possible.
217239
size_t fields_size = nfields * jl_fielddesc_size(fielddesc_type);
218240
size_t pointers_size = first_ptr < 0 ? 0 : (npointers << fielddesc_type);
219-
size_t flddesc_sz = sizeof(jl_datatype_layout_t) + fields_size + pointers_size;
241+
size_t hidden_ptrs_size = first_hidden_ptr < 0 ? 0 : (nhidden_pointers << fielddesc_type);
242+
size_t flddesc_sz = sizeof(jl_datatype_layout_t) + fields_size + pointers_size + hidden_ptrs_size;
220243
int should_malloc = flddesc_sz >= jl_page_size;
221244
jl_datatype_layout_t *mallocmem = (jl_datatype_layout_t *)(should_malloc ? malloc(flddesc_sz) : NULL);
222245
jl_datatype_layout_t *allocamem = (jl_datatype_layout_t *)(should_malloc ? NULL : alloca(flddesc_sz));
@@ -233,6 +256,8 @@ static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
233256
flddesc->flags.padding = 0;
234257
flddesc->npointers = npointers;
235258
flddesc->first_ptr = first_ptr;
259+
flddesc->nhidden_pointers = nhidden_pointers;
260+
flddesc->first_hidden_ptr = first_hidden_ptr;
236261

237262
// fill out the fields of the new descriptor
238263
jl_fielddesc8_t *desc8 = (jl_fielddesc8_t *)jl_dt_layout_fields(flddesc);
@@ -272,6 +297,25 @@ static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
272297
}
273298
}
274299

300+
// fill out hidden pointer descriptors
301+
if (first_hidden_ptr >= 0 && hidden_pointers) {
302+
uint8_t *hptrs8 = (uint8_t *)jl_dt_layout_hidden_ptrs(flddesc);
303+
uint16_t *hptrs16 = (uint16_t *)jl_dt_layout_hidden_ptrs(flddesc);
304+
uint32_t *hptrs32 = (uint32_t *)jl_dt_layout_hidden_ptrs(flddesc);
305+
uint32_t *src_descs = (uint32_t *)hidden_pointers;
306+
for (size_t i = 0; i < nhidden_pointers; i++) {
307+
if (fielddesc_type == 0) {
308+
hptrs8[i] = src_descs[i];
309+
}
310+
else if (fielddesc_type == 1) {
311+
hptrs16[i] = src_descs[i];
312+
}
313+
else {
314+
hptrs32[i] = src_descs[i];
315+
}
316+
}
317+
}
318+
275319
if (__unlikely(!layoutcache_initialized)) {
276320
htable_new(&layoutcache, 4096);
277321
layoutcache_initialized = 1;
@@ -299,6 +343,7 @@ static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
299343
return ret;
300344
}
301345

346+
302347
// Determine if homogeneous tuple with fields of type t will have
303348
// a special alignment and vector-ABI beyond normal rules for aggregates.
304349
// Return special alignment if one exists, 0 if normal alignment rules hold.
@@ -502,7 +547,7 @@ void jl_get_genericmemory_layout(jl_datatype_t *st)
502547
jl_value_t *addrspace = jl_tparam2(st);
503548
if (!jl_is_typevar(eltype) && !jl_is_type(eltype)) {
504549
// this is expected to have a layout, but since it is not constructable, we don't care too much what it is
505-
static const jl_datatype_layout_t opaque_ptr_layout = {0, 0, 1, -1, sizeof(void*), {0}};
550+
static const jl_datatype_layout_t opaque_ptr_layout = {0, 0, 1, 0, -1, -1, sizeof(void*), {0}};
506551
st->layout = &opaque_ptr_layout;
507552
st->has_concrete_subtype = 0;
508553
return;
@@ -571,7 +616,7 @@ void jl_get_genericmemory_layout(jl_datatype_t *st)
571616
else
572617
arrayelem = 0;
573618
assert(!st->layout);
574-
st->layout = jl_get_layout(elsz, nfields, npointers, al, haspadding, isbitsegal, arrayelem, NULL, pointers);
619+
st->layout = jl_get_layout(elsz, nfields, npointers, 0, al, haspadding, isbitsegal, arrayelem, NULL, pointers, NULL);
575620
st->zeroinit = zi;
576621
//st->has_concrete_subtype = 1;
577622
//st->isbitstype = 0;
@@ -630,17 +675,17 @@ void jl_compute_field_offsets(jl_datatype_t *st)
630675
// if we have no fields, we can trivially skip the rest
631676
if (st == jl_symbol_type || st == jl_string_type) {
632677
// opaque layout - heap-allocated blob
633-
static const jl_datatype_layout_t opaque_byte_layout = {0, 0, 1, -1, 1, { .haspadding = 0, .fielddesc_type=0, .isbitsegal=1, .arrayelem_isboxed=0, .arrayelem_isunion=0 }};
678+
static const jl_datatype_layout_t opaque_byte_layout = {0, 0, 1, 0, -1, -1, 1, { .haspadding = 0, .fielddesc_type=0, .isbitsegal=1, .arrayelem_isboxed=0, .arrayelem_isunion=0 }};
634679
st->layout = &opaque_byte_layout;
635680
return;
636681
}
637682
else if (st == jl_simplevector_type || st == jl_module_type) {
638-
static const jl_datatype_layout_t opaque_ptr_layout = {0, 0, 1, -1, sizeof(void*), { .haspadding = 0, .fielddesc_type=0, .isbitsegal=1, .arrayelem_isboxed=0, .arrayelem_isunion=0 }};
683+
static const jl_datatype_layout_t opaque_ptr_layout = {0, 0, 1, 0, -1, -1, sizeof(void*), { .haspadding = 0, .fielddesc_type=0, .isbitsegal=1, .arrayelem_isboxed=0, .arrayelem_isunion=0 }};
639684
st->layout = &opaque_ptr_layout;
640685
return;
641686
}
642687
else {
643-
static const jl_datatype_layout_t singleton_layout = {0, 0, 0, -1, 1, { .haspadding = 0, .fielddesc_type=0, .isbitsegal=1, .arrayelem_isboxed=0, .arrayelem_isunion=0 }};
688+
static const jl_datatype_layout_t singleton_layout = {0, 0, 0, 0, -1, -1, 1, { .haspadding = 0, .fielddesc_type=0, .isbitsegal=1, .arrayelem_isboxed=0, .arrayelem_isunion=0 }};
644689
st->layout = &singleton_layout;
645690
}
646691
}
@@ -672,6 +717,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
672717
size_t descsz = nfields * sizeof(jl_fielddesc32_t);
673718
jl_fielddesc32_t *desc;
674719
uint32_t *pointers;
720+
uint32_t *hidden_pointers;
675721
int should_malloc = descsz >= jl_page_size;
676722
if (should_malloc)
677723
desc = (jl_fielddesc32_t*)malloc_s(descsz);
@@ -685,12 +731,22 @@ void jl_compute_field_offsets(jl_datatype_t *st)
685731
int homogeneous = 1;
686732
int needlock = 0;
687733
uint32_t npointers = 0;
734+
uint32_t nhidden_pointers = 0;
688735
jl_value_t *firstty = jl_field_type(st, 0);
689736
for (i = 0; i < nfields; i++) {
690737
jl_value_t *fld = jl_field_type(st, i);
691738
int isatomic = jl_field_isatomic(st, i);
739+
int ishiddenptr = jl_field_ishiddenptr(st, i);
692740
size_t fsz = 0, al = 1;
693-
if (jl_islayout_inline(fld, &fsz, &al) && (!isatomic || jl_is_datatype(fld))) { // aka jl_datatype_isinlinealloc
741+
if (ishiddenptr) {
742+
fsz = sizeof(void*);
743+
al = fsz;
744+
if (al > MAX_ALIGN)
745+
al = MAX_ALIGN;
746+
desc[i].isptr = 0; // Hidden pointers are stored as non-pointer fields
747+
nhidden_pointers++;
748+
}
749+
else if (jl_islayout_inline(fld, &fsz, &al) && (!isatomic || jl_is_datatype(fld))) { // aka jl_datatype_isinlinealloc
694750
if (__unlikely(fsz > max_size))
695751
// Should never happen
696752
throw_ovf(should_malloc, desc, st, fsz);
@@ -724,6 +780,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
724780
if (!zeroinit)
725781
zeroinit = ((jl_datatype_t*)fld)->zeroinit;
726782
npointers += fld_npointers;
783+
nhidden_pointers += ((jl_datatype_t*)fld)->layout->nhidden_pointers;
727784
}
728785
}
729786
else {
@@ -782,25 +839,61 @@ void jl_compute_field_offsets(jl_datatype_t *st)
782839
pointers = (uint32_t*)malloc_s(npointers * sizeof(uint32_t));
783840
else
784841
pointers = (uint32_t*)alloca(npointers * sizeof(uint32_t));
842+
if (should_malloc && nhidden_pointers) {
843+
hidden_pointers = (uint32_t*)malloc_s(nhidden_pointers * sizeof(uint32_t));
844+
} else {
845+
hidden_pointers = (uint32_t*)alloca(nhidden_pointers * sizeof(uint32_t));
846+
}
785847
size_t ptr_i = 0;
848+
size_t hptr_i = 0;
786849
for (i = 0; i < nfields; i++) {
787850
jl_value_t *fld = jl_field_type(st, i);
788851
uint32_t offset = desc[i].offset / sizeof(jl_value_t**);
789-
if (desc[i].isptr)
852+
int ishiddenptr = jl_field_ishiddenptr(st, i);
853+
if (ishiddenptr) {
854+
// Direct hidden pointer field
855+
hidden_pointers[hptr_i] = offset;
856+
hptr_i++;
857+
}
858+
else if (desc[i].isptr)
790859
pointers[ptr_i++] = offset;
791860
else if (jl_is_datatype(fld)) {
861+
// Handle nested datatype with regular/hidden pointers
792862
int j, npointers = ((jl_datatype_t*)fld)->layout->npointers;
793863
for (j = 0; j < npointers; j++) {
794864
pointers[ptr_i++] = offset + jl_ptr_offset((jl_datatype_t*)fld, j);
795865
}
866+
// Copy hidden pointers from nested field
867+
int nhidden = ((jl_datatype_t*)fld)->layout->nhidden_pointers;
868+
for (j = 0; j < nhidden; j++) {
869+
hidden_pointers[hptr_i] = offset + jl_hidden_ptr_offset((jl_datatype_t*)fld, j);
870+
hptr_i++;
871+
}
796872
}
797873
}
798874
assert(ptr_i == npointers);
799-
st->layout = jl_get_layout(sz, nfields, npointers, alignm, haspadding, isbitsegal, 0, desc, pointers);
875+
assert(hptr_i == nhidden_pointers);
876+
st->layout = jl_get_layout(sz, nfields, npointers, nhidden_pointers, alignm, haspadding, isbitsegal, 0, desc, pointers, hidden_pointers);
877+
878+
// Validation: Ensure no overlap between pointer and hidden pointer offsets
879+
if (npointers > 0 && nhidden_pointers > 0) {
880+
for (size_t p = 0; p < npointers; p++) {
881+
for (size_t hp = 0; hp < nhidden_pointers; hp++) {
882+
if (pointers[p] == hidden_pointers[hp]) {
883+
jl_errorf("Field offset conflict: field at offset %u appears in both regular pointer offsets and hidden pointer offsets",
884+
pointers[p]);
885+
}
886+
}
887+
}
888+
}
889+
890+
// All hidden pointers are assumed to be PtrOrOffset type
800891
if (should_malloc) {
801892
free(desc);
802893
if (npointers)
803894
free(pointers);
895+
if (nhidden_pointers)
896+
free(hidden_pointers);
804897
}
805898
st->zeroinit = zeroinit;
806899
}
@@ -813,7 +906,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
813906
return;
814907
}
815908

816-
JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
909+
JL_DLLEXPORT jl_datatype_t *jl_new_datatype_with_hiddenptrs(
817910
jl_sym_t *name,
818911
jl_module_t *module,
819912
jl_datatype_t *super,
@@ -822,7 +915,8 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
822915
jl_svec_t *ftypes,
823916
jl_svec_t *fattrs,
824917
int abstract, int mutabl,
825-
int ninitialized)
918+
int ninitialized,
919+
uint32_t* hiddenptrfields)
826920
{
827921
jl_datatype_t *t = NULL;
828922
jl_typename_t *tn = NULL;
@@ -912,6 +1006,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
9121006
}
9131007
tn->atomicfields = atomicfields;
9141008
tn->constfields = constfields;
1009+
tn->hiddenptrfields = hiddenptrfields;
9151010

9161011
if (t->name->wrapper == NULL) {
9171012
t->name->wrapper = (jl_value_t*)t;
@@ -933,6 +1028,22 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
9331028
return t;
9341029
}
9351030

1031+
JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
1032+
jl_sym_t *name,
1033+
jl_module_t *module,
1034+
jl_datatype_t *super,
1035+
jl_svec_t *parameters,
1036+
jl_svec_t *fnames,
1037+
jl_svec_t *ftypes,
1038+
jl_svec_t *fattrs,
1039+
int abstract, int mutabl,
1040+
int ninitialized)
1041+
{
1042+
return jl_new_datatype_with_hiddenptrs(
1043+
name, module, super, parameters, fnames, ftypes, fattrs,
1044+
abstract, mutabl, ninitialized, NULL);
1045+
}
1046+
9361047
JL_DLLEXPORT jl_datatype_t *jl_new_primitivetype(jl_value_t *name, jl_module_t *module,
9371048
jl_datatype_t *super,
9381049
jl_svec_t *parameters, size_t nbits)
@@ -962,7 +1073,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_primitivetype(jl_value_t *name, jl_module_t *
9621073
bt->ismutationfree = 1;
9631074
bt->isidentityfree = 1;
9641075
bt->isbitstype = (parameters == jl_emptysvec);
965-
bt->layout = jl_get_layout(nbytes, 0, 0, alignm, 0, 1, 0, NULL, NULL);
1076+
bt->layout = jl_get_layout(nbytes, 0, 0, 0, alignm, 0, 1, 0, NULL, NULL, NULL);
9661077
bt->instance = NULL;
9671078
return bt;
9681079
}

src/jltypes.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3007,27 +3007,29 @@ void jl_init_types(void) JL_GC_DISABLED
30073007
jl_typename_type->name->mt = jl_nonfunction_mt;
30083008
jl_typename_type->super = jl_any_type;
30093009
jl_typename_type->parameters = jl_emptysvec;
3010-
jl_typename_type->name->n_uninitialized = 16 - 2;
3011-
jl_typename_type->name->names = jl_perm_symsvec(16, "name", "module",
3010+
jl_typename_type->name->n_uninitialized = 17 - 2;
3011+
jl_typename_type->name->names = jl_perm_symsvec(17, "name", "module",
30123012
"names", "atomicfields", "constfields",
30133013
"wrapper", "Typeofwrapper", "cache", "linearcache",
30143014
"mt", "partial",
30153015
"hash", "n_uninitialized",
30163016
"flags", // "abstract", "mutable", "mayinlinealloc",
3017-
"max_methods", "constprop_heuristic");
3017+
"max_methods", "constprop_heuristic",
3018+
"hiddenptrfields");
30183019
const static uint32_t typename_constfields[1] = { 0x00003a27 }; // (1<<0)|(1<<1)|(1<<2)|(1<<5)|(1<<9)|(1<<11)|(1<<12)|(1<<13) ; TODO: put back (1<<3)|(1<<4) in this list
30193020
const static uint32_t typename_atomicfields[1] = { 0x00000180 }; // (1<<7)|(1<<8)
30203021
jl_typename_type->name->constfields = typename_constfields;
30213022
jl_typename_type->name->atomicfields = typename_atomicfields;
30223023
jl_precompute_memoized_dt(jl_typename_type, 1);
3023-
jl_typename_type->types = jl_svec(16, jl_symbol_type, jl_any_type /*jl_module_type*/,
3024+
jl_typename_type->types = jl_svec(17, jl_symbol_type, jl_any_type /*jl_module_type*/,
30243025
jl_simplevector_type, jl_any_type/*jl_voidpointer_type*/, jl_any_type/*jl_voidpointer_type*/,
30253026
jl_type_type, jl_type_type, jl_simplevector_type, jl_simplevector_type,
30263027
jl_methtable_type, jl_any_type,
30273028
jl_any_type /*jl_long_type*/, jl_any_type /*jl_int32_type*/,
30283029
jl_any_type /*jl_uint8_type*/,
30293030
jl_any_type /*jl_uint8_type*/,
3030-
jl_any_type /*jl_uint8_type*/);
3031+
jl_any_type /*jl_uint8_type*/,
3032+
jl_any_type/*jl_voidpointer_type*/);
30313033

30323034
jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core, 0, 1);
30333035
jl_methtable_type->name->wrapper = (jl_value_t*)jl_methtable_type;
@@ -3338,11 +3340,12 @@ void jl_init_types(void) JL_GC_DISABLED
33383340
memory_datatype->ismutationfree = 0;
33393341

33403342
jl_datatype_t *jl_memoryref_supertype = (jl_datatype_t*)jl_apply_type1((jl_value_t*)jl_ref_type, jl_svecref(tv, 1));
3343+
const static uint32_t memoryref_hiddenptrfields[1] = { 0x00000001 }; // (1<<0) - field 0 is a hidden pointer
33413344
jl_datatype_t *memoryref_datatype =
3342-
jl_new_datatype(jl_symbol("GenericMemoryRef"), core, jl_memoryref_supertype, tv,
3345+
jl_new_datatype_with_hiddenptrs(jl_symbol("GenericMemoryRef"), core, jl_memoryref_supertype, tv,
33433346
jl_perm_symsvec(2, "ptr_or_offset", "mem"),
33443347
jl_svec(2, pointer_void, memory_datatype),
3345-
jl_emptysvec, 0, 0, 2);
3348+
jl_emptysvec, 0, 0, 2, memoryref_hiddenptrfields);
33463349
jl_genericmemoryref_typename = memoryref_datatype->name;
33473350
jl_genericmemoryref_type = (jl_unionall_t*)jl_genericmemoryref_typename->wrapper;
33483351
memoryref_datatype->ismutationfree = 0;
@@ -3856,6 +3859,7 @@ void jl_init_types(void) JL_GC_DISABLED
38563859
jl_svecset(jl_typename_type->types, 13, jl_uint8_type);
38573860
jl_svecset(jl_typename_type->types, 14, jl_uint8_type);
38583861
jl_svecset(jl_typename_type->types, 15, jl_uint8_type);
3862+
jl_svecset(jl_typename_type->types, 16, jl_voidpointer_type); // hiddenptrfields
38593863
jl_svecset(jl_methtable_type->types, 4, jl_long_type);
38603864
jl_svecset(jl_methtable_type->types, 5, jl_module_type);
38613865
jl_svecset(jl_methtable_type->types, 6, jl_array_any_type);

0 commit comments

Comments
 (0)