@@ -80,6 +80,7 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu
80
80
tn -> partial = NULL ;
81
81
tn -> atomicfields = NULL ;
82
82
tn -> constfields = NULL ;
83
+ tn -> hiddenptrfields = NULL ;
83
84
tn -> max_methods = 0 ;
84
85
tn -> constprop_heustic = 0 ;
85
86
return tn ;
@@ -126,6 +127,7 @@ static uint32_t _hash_djb2(uint32_t hash, const char *mem, size_t s) JL_NOTSAFEP
126
127
return hash ;
127
128
}
128
129
130
+
129
131
static uint32_t _hash_layout_djb2 (uintptr_t _layout , void * unused ) JL_NOTSAFEPOINT
130
132
{
131
133
(void )unused ;
@@ -138,11 +140,20 @@ static uint32_t _hash_layout_djb2(uintptr_t _layout, void *unused) JL_NOTSAFEPOI
138
140
const char * pointers = jl_dt_layout_ptrs (layout );
139
141
assert (pointers );
140
142
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
+ }
141
149
142
150
uint_t hash = 5381 ;
143
151
hash = _hash_djb2 (hash , (char * )layout , own_size );
144
152
hash = _hash_djb2 (hash , fields , fields_size );
145
153
hash = _hash_djb2 (hash , pointers , pointers_size );
154
+ if (hidden_ptrs_size > 0 ) {
155
+ hash = _hash_djb2 (hash , hidden_pointers , hidden_ptrs_size );
156
+ }
146
157
return hash ;
147
158
}
148
159
@@ -163,6 +174,13 @@ static int layout_eq(void *_l1, void *_l2, void *unused) JL_NOTSAFEPOINT
163
174
size_t pointers_size = l1 -> first_ptr < 0 ? 0 : (l1 -> npointers << l1 -> flags .fielddesc_type );
164
175
if (memcmp (p1 , p2 , pointers_size ))
165
176
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
+ }
166
184
return 1 ;
167
185
}
168
186
@@ -174,15 +192,18 @@ HTIMPL_R(layoutcache, _hash_layout_djb2, layout_eq)
174
192
static htable_t layoutcache ;
175
193
static int layoutcache_initialized = 0 ;
176
194
195
+
177
196
static jl_datatype_layout_t * jl_get_layout (uint32_t sz ,
178
197
uint32_t nfields ,
179
198
uint32_t npointers ,
199
+ uint32_t nhidden_pointers ,
180
200
uint32_t alignment ,
181
201
int haspadding ,
182
202
int isbitsegal ,
183
203
int arrayelem ,
184
204
jl_fielddesc32_t desc [],
185
- uint32_t pointers []) JL_NOTSAFEPOINT
205
+ uint32_t pointers [],
206
+ uint32_t hidden_pointers []) JL_NOTSAFEPOINT
186
207
{
187
208
assert (alignment ); // should have been verified by caller
188
209
@@ -212,11 +233,13 @@ static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
212
233
}
213
234
}
214
235
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 );
215
237
216
238
// allocate a new descriptor, on the stack if possible.
217
239
size_t fields_size = nfields * jl_fielddesc_size (fielddesc_type );
218
240
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 ;
220
243
int should_malloc = flddesc_sz >= jl_page_size ;
221
244
jl_datatype_layout_t * mallocmem = (jl_datatype_layout_t * )(should_malloc ? malloc (flddesc_sz ) : NULL );
222
245
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,
233
256
flddesc -> flags .padding = 0 ;
234
257
flddesc -> npointers = npointers ;
235
258
flddesc -> first_ptr = first_ptr ;
259
+ flddesc -> nhidden_pointers = nhidden_pointers ;
260
+ flddesc -> first_hidden_ptr = first_hidden_ptr ;
236
261
237
262
// fill out the fields of the new descriptor
238
263
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,
272
297
}
273
298
}
274
299
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
+
275
319
if (__unlikely (!layoutcache_initialized )) {
276
320
htable_new (& layoutcache , 4096 );
277
321
layoutcache_initialized = 1 ;
@@ -299,6 +343,7 @@ static jl_datatype_layout_t *jl_get_layout(uint32_t sz,
299
343
return ret ;
300
344
}
301
345
346
+
302
347
// Determine if homogeneous tuple with fields of type t will have
303
348
// a special alignment and vector-ABI beyond normal rules for aggregates.
304
349
// 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)
502
547
jl_value_t * addrspace = jl_tparam2 (st );
503
548
if (!jl_is_typevar (eltype ) && !jl_is_type (eltype )) {
504
549
// 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 }};
506
551
st -> layout = & opaque_ptr_layout ;
507
552
st -> has_concrete_subtype = 0 ;
508
553
return ;
@@ -571,7 +616,7 @@ void jl_get_genericmemory_layout(jl_datatype_t *st)
571
616
else
572
617
arrayelem = 0 ;
573
618
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 );
575
620
st -> zeroinit = zi ;
576
621
//st->has_concrete_subtype = 1;
577
622
//st->isbitstype = 0;
@@ -630,17 +675,17 @@ void jl_compute_field_offsets(jl_datatype_t *st)
630
675
// if we have no fields, we can trivially skip the rest
631
676
if (st == jl_symbol_type || st == jl_string_type ) {
632
677
// 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 }};
634
679
st -> layout = & opaque_byte_layout ;
635
680
return ;
636
681
}
637
682
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 }};
639
684
st -> layout = & opaque_ptr_layout ;
640
685
return ;
641
686
}
642
687
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 }};
644
689
st -> layout = & singleton_layout ;
645
690
}
646
691
}
@@ -672,6 +717,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
672
717
size_t descsz = nfields * sizeof (jl_fielddesc32_t );
673
718
jl_fielddesc32_t * desc ;
674
719
uint32_t * pointers ;
720
+ uint32_t * hidden_pointers ;
675
721
int should_malloc = descsz >= jl_page_size ;
676
722
if (should_malloc )
677
723
desc = (jl_fielddesc32_t * )malloc_s (descsz );
@@ -685,12 +731,22 @@ void jl_compute_field_offsets(jl_datatype_t *st)
685
731
int homogeneous = 1 ;
686
732
int needlock = 0 ;
687
733
uint32_t npointers = 0 ;
734
+ uint32_t nhidden_pointers = 0 ;
688
735
jl_value_t * firstty = jl_field_type (st , 0 );
689
736
for (i = 0 ; i < nfields ; i ++ ) {
690
737
jl_value_t * fld = jl_field_type (st , i );
691
738
int isatomic = jl_field_isatomic (st , i );
739
+ int ishiddenptr = jl_field_ishiddenptr (st , i );
692
740
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
694
750
if (__unlikely (fsz > max_size ))
695
751
// Should never happen
696
752
throw_ovf (should_malloc , desc , st , fsz );
@@ -724,6 +780,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
724
780
if (!zeroinit )
725
781
zeroinit = ((jl_datatype_t * )fld )-> zeroinit ;
726
782
npointers += fld_npointers ;
783
+ nhidden_pointers += ((jl_datatype_t * )fld )-> layout -> nhidden_pointers ;
727
784
}
728
785
}
729
786
else {
@@ -782,25 +839,61 @@ void jl_compute_field_offsets(jl_datatype_t *st)
782
839
pointers = (uint32_t * )malloc_s (npointers * sizeof (uint32_t ));
783
840
else
784
841
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
+ }
785
847
size_t ptr_i = 0 ;
848
+ size_t hptr_i = 0 ;
786
849
for (i = 0 ; i < nfields ; i ++ ) {
787
850
jl_value_t * fld = jl_field_type (st , i );
788
851
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 )
790
859
pointers [ptr_i ++ ] = offset ;
791
860
else if (jl_is_datatype (fld )) {
861
+ // Handle nested datatype with regular/hidden pointers
792
862
int j , npointers = ((jl_datatype_t * )fld )-> layout -> npointers ;
793
863
for (j = 0 ; j < npointers ; j ++ ) {
794
864
pointers [ptr_i ++ ] = offset + jl_ptr_offset ((jl_datatype_t * )fld , j );
795
865
}
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
+ }
796
872
}
797
873
}
798
874
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
800
891
if (should_malloc ) {
801
892
free (desc );
802
893
if (npointers )
803
894
free (pointers );
895
+ if (nhidden_pointers )
896
+ free (hidden_pointers );
804
897
}
805
898
st -> zeroinit = zeroinit ;
806
899
}
@@ -813,7 +906,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
813
906
return ;
814
907
}
815
908
816
- JL_DLLEXPORT jl_datatype_t * jl_new_datatype (
909
+ JL_DLLEXPORT jl_datatype_t * jl_new_datatype_with_hiddenptrs (
817
910
jl_sym_t * name ,
818
911
jl_module_t * module ,
819
912
jl_datatype_t * super ,
@@ -822,7 +915,8 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
822
915
jl_svec_t * ftypes ,
823
916
jl_svec_t * fattrs ,
824
917
int abstract , int mutabl ,
825
- int ninitialized )
918
+ int ninitialized ,
919
+ uint32_t * hiddenptrfields )
826
920
{
827
921
jl_datatype_t * t = NULL ;
828
922
jl_typename_t * tn = NULL ;
@@ -912,6 +1006,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
912
1006
}
913
1007
tn -> atomicfields = atomicfields ;
914
1008
tn -> constfields = constfields ;
1009
+ tn -> hiddenptrfields = hiddenptrfields ;
915
1010
916
1011
if (t -> name -> wrapper == NULL ) {
917
1012
t -> name -> wrapper = (jl_value_t * )t ;
@@ -933,6 +1028,22 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
933
1028
return t ;
934
1029
}
935
1030
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
+
936
1047
JL_DLLEXPORT jl_datatype_t * jl_new_primitivetype (jl_value_t * name , jl_module_t * module ,
937
1048
jl_datatype_t * super ,
938
1049
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 *
962
1073
bt -> ismutationfree = 1 ;
963
1074
bt -> isidentityfree = 1 ;
964
1075
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 );
966
1077
bt -> instance = NULL ;
967
1078
return bt ;
968
1079
}
0 commit comments