@@ -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+
129131static 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)
174192static htable_t layoutcache ;
175193static int layoutcache_initialized = 0 ;
176194
195+
177196static 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+
9361047JL_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}
0 commit comments