@@ -39,20 +39,24 @@ extern "C" {
39
39
// Union type decision points are discovered while the algorithm works.
40
40
// If a new Union decision is encountered, the `more` flag is set to tell
41
41
// the forall/exists loop to grow the stack.
42
- // TODO: the stack probably needs to be artificially large because of some
43
- // deeper problem (see #21191) and could be shrunk once that is fixed
42
+
43
+ typedef struct jl_bits_stack_t {
44
+ uint32_t data [16 ];
45
+ struct jl_bits_stack_t * next ;
46
+ } jl_bits_stack_t ;
47
+
44
48
typedef struct {
45
49
int16_t depth ;
46
50
int16_t more ;
47
51
int16_t used ;
48
- uint32_t stack [ 100 ]; // stack of bits represented as a bit vector
52
+ jl_bits_stack_t stack ;
49
53
} jl_unionstate_t ;
50
54
51
55
typedef struct {
52
56
int16_t depth ;
53
57
int16_t more ;
54
58
int16_t used ;
55
- void * stack ;
59
+ uint8_t * stack ;
56
60
} jl_saved_unionstate_t ;
57
61
58
62
// Linked list storing the type variable environment. A new jl_varbinding_t
@@ -131,37 +135,111 @@ static jl_varbinding_t *lookup(jl_stenv_t *e, jl_tvar_t *v) JL_GLOBALLY_ROOTED J
131
135
}
132
136
#endif
133
137
138
+ // union-stack tools
139
+
134
140
static int statestack_get (jl_unionstate_t * st , int i ) JL_NOTSAFEPOINT
135
141
{
136
- assert (i >= 0 && i < sizeof ( st -> stack ) * 8 );
142
+ assert (i >= 0 && i <= 32767 ); // limited by the depth bit.
137
143
// get the `i`th bit in an array of 32-bit words
138
- return (st -> stack [i >>5 ] & (1u <<(i & 31 ))) != 0 ;
144
+ jl_bits_stack_t * stack = & st -> stack ;
145
+ while (i >= sizeof (stack -> data ) * 8 ) {
146
+ // We should have set this bit.
147
+ assert (stack -> next );
148
+ stack = stack -> next ;
149
+ i -= sizeof (stack -> data ) * 8 ;
150
+ }
151
+ return (stack -> data [i >>5 ] & (1u <<(i & 31 ))) != 0 ;
139
152
}
140
153
141
154
static void statestack_set (jl_unionstate_t * st , int i , int val ) JL_NOTSAFEPOINT
142
155
{
143
- assert (i >= 0 && i < sizeof (st -> stack ) * 8 );
156
+ assert (i >= 0 && i <= 32767 ); // limited by the depth bit.
157
+ jl_bits_stack_t * stack = & st -> stack ;
158
+ while (i >= sizeof (stack -> data ) * 8 ) {
159
+ if (__unlikely (stack -> next == NULL )) {
160
+ stack -> next = (jl_bits_stack_t * )malloc (sizeof (jl_bits_stack_t ));
161
+ stack -> next -> next = NULL ;
162
+ }
163
+ stack = stack -> next ;
164
+ i -= sizeof (stack -> data ) * 8 ;
165
+ }
144
166
if (val )
145
- st -> stack [i >>5 ] |= (1u <<(i & 31 ));
167
+ stack -> data [i >>5 ] |= (1u <<(i & 31 ));
146
168
else
147
- st -> stack [i >>5 ] &= ~(1u <<(i & 31 ));
169
+ stack -> data [i >>5 ] &= ~(1u <<(i & 31 ));
148
170
}
149
171
150
- #define push_unionstate (saved , src ) \
151
- do { \
152
- (saved)->depth = (src)->depth; \
153
- (saved)->more = (src)->more; \
154
- (saved)->used = (src)->used; \
155
- (saved)->stack = alloca(((src)->used+7)/8); \
156
- memcpy((saved)->stack, &(src)->stack, ((src)->used+7)/8); \
172
+ #define has_next_union_state (e , R ) ((((R) ? &(e)->Runions : &(e)->Lunions)->more) != 0)
173
+
174
+ static int next_union_state (jl_stenv_t * e , int8_t R ) JL_NOTSAFEPOINT
175
+ {
176
+ jl_unionstate_t * state = R ? & e -> Runions : & e -> Lunions ;
177
+ if (state -> more == 0 )
178
+ return 0 ;
179
+ // reset `used` and let `pick_union_decision` clean the stack.
180
+ state -> used = state -> more ;
181
+ statestack_set (state , state -> used - 1 , 1 );
182
+ return 1 ;
183
+ }
184
+
185
+ static int pick_union_decision (jl_stenv_t * e , int8_t R ) JL_NOTSAFEPOINT
186
+ {
187
+ jl_unionstate_t * state = R ? & e -> Runions : & e -> Lunions ;
188
+ if (state -> depth >= state -> used ) {
189
+ statestack_set (state , state -> used , 0 );
190
+ state -> used ++ ;
191
+ }
192
+ int ui = statestack_get (state , state -> depth );
193
+ state -> depth ++ ;
194
+ if (ui == 0 )
195
+ state -> more = state -> depth ; // memorize that this was the deepest available choice
196
+ return ui ;
197
+ }
198
+
199
+ static jl_value_t * pick_union_element (jl_value_t * u JL_PROPAGATES_ROOT , jl_stenv_t * e , int8_t R ) JL_NOTSAFEPOINT
200
+ {
201
+ do {
202
+ if (pick_union_decision (e , R ))
203
+ u = ((jl_uniontype_t * )u )-> b ;
204
+ else
205
+ u = ((jl_uniontype_t * )u )-> a ;
206
+ } while (jl_is_uniontype (u ));
207
+ return u ;
208
+ }
209
+
210
+ #define push_unionstate (saved , src ) \
211
+ do { \
212
+ (saved)->depth = (src)->depth; \
213
+ (saved)->more = (src)->more; \
214
+ (saved)->used = (src)->used; \
215
+ jl_bits_stack_t *srcstack = &(src)->stack; \
216
+ int pushbits = ((saved)->used+7)/8; \
217
+ (saved)->stack = (uint8_t *)alloca(pushbits); \
218
+ for (int n = 0; n < pushbits; n += sizeof(srcstack->data)) { \
219
+ assert(srcstack != NULL); \
220
+ int rest = pushbits - n; \
221
+ if (rest > sizeof(srcstack->data)) \
222
+ rest = sizeof(srcstack->data); \
223
+ memcpy(&(saved)->stack[n], &srcstack->data, rest); \
224
+ srcstack = srcstack->next; \
225
+ } \
157
226
} while (0);
158
227
159
- #define pop_unionstate (dst , saved ) \
160
- do { \
161
- (dst)->depth = (saved)->depth; \
162
- (dst)->more = (saved)->more; \
163
- (dst)->used = (saved)->used; \
164
- memcpy(&(dst)->stack, (saved)->stack, ((saved)->used+7)/8); \
228
+ #define pop_unionstate (dst , saved ) \
229
+ do { \
230
+ (dst)->depth = (saved)->depth; \
231
+ (dst)->more = (saved)->more; \
232
+ (dst)->used = (saved)->used; \
233
+ jl_bits_stack_t *dststack = &(dst)->stack; \
234
+ int popbits = ((saved)->used+7)/8; \
235
+ for (int n = 0; n < popbits; n += sizeof(dststack->data)) { \
236
+ assert(dststack != NULL); \
237
+ int rest = popbits - n; \
238
+ if (rest > sizeof(dststack->data)) \
239
+ rest = sizeof(dststack->data); \
240
+ memcpy(&dststack->data, &(saved)->stack[n], rest); \
241
+ dststack = dststack->next; \
242
+ } \
165
243
} while (0);
166
244
167
245
static int current_env_length (jl_stenv_t * e )
@@ -264,6 +342,18 @@ static void free_env(jl_savedenv_t *se) JL_NOTSAFEPOINT
264
342
se -> buf = NULL ;
265
343
}
266
344
345
+ static void free_stenv (jl_stenv_t * e ) JL_NOTSAFEPOINT
346
+ {
347
+ for (int R = 0 ; R < 2 ; R ++ ) {
348
+ jl_bits_stack_t * temp = R ? e -> Runions .stack .next : e -> Lunions .stack .next ;
349
+ while (temp != NULL ) {
350
+ jl_bits_stack_t * next = temp -> next ;
351
+ free (temp );
352
+ temp = next ;
353
+ }
354
+ }
355
+ }
356
+
267
357
static void restore_env (jl_stenv_t * e , jl_savedenv_t * se , int root ) JL_NOTSAFEPOINT
268
358
{
269
359
jl_value_t * * roots = NULL ;
@@ -587,44 +677,6 @@ static jl_value_t *simple_meet(jl_value_t *a, jl_value_t *b, int overesi)
587
677
588
678
static int subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , int param );
589
679
590
- #define has_next_union_state (e , R ) ((((R) ? &(e)->Runions : &(e)->Lunions)->more) != 0)
591
-
592
- static int next_union_state (jl_stenv_t * e , int8_t R ) JL_NOTSAFEPOINT
593
- {
594
- jl_unionstate_t * state = R ? & e -> Runions : & e -> Lunions ;
595
- if (state -> more == 0 )
596
- return 0 ;
597
- // reset `used` and let `pick_union_decision` clean the stack.
598
- state -> used = state -> more ;
599
- statestack_set (state , state -> used - 1 , 1 );
600
- return 1 ;
601
- }
602
-
603
- static int pick_union_decision (jl_stenv_t * e , int8_t R ) JL_NOTSAFEPOINT
604
- {
605
- jl_unionstate_t * state = R ? & e -> Runions : & e -> Lunions ;
606
- if (state -> depth >= state -> used ) {
607
- statestack_set (state , state -> used , 0 );
608
- state -> used ++ ;
609
- }
610
- int ui = statestack_get (state , state -> depth );
611
- state -> depth ++ ;
612
- if (ui == 0 )
613
- state -> more = state -> depth ; // memorize that this was the deepest available choice
614
- return ui ;
615
- }
616
-
617
- static jl_value_t * pick_union_element (jl_value_t * u JL_PROPAGATES_ROOT , jl_stenv_t * e , int8_t R ) JL_NOTSAFEPOINT
618
- {
619
- do {
620
- if (pick_union_decision (e , R ))
621
- u = ((jl_uniontype_t * )u )-> b ;
622
- else
623
- u = ((jl_uniontype_t * )u )-> a ;
624
- } while (jl_is_uniontype (u ));
625
- return u ;
626
- }
627
-
628
680
static int local_forall_exists_subtype (jl_value_t * x , jl_value_t * y , jl_stenv_t * e , int param , int limit_slow );
629
681
630
682
// subtype for variable bounds consistency check. needs its own forall/exists environment.
@@ -1728,6 +1780,8 @@ static void init_stenv(jl_stenv_t *e, jl_value_t **env, int envsz)
1728
1780
e -> Lunions .depth = 0 ; e -> Runions .depth = 0 ;
1729
1781
e -> Lunions .more = 0 ; e -> Runions .more = 0 ;
1730
1782
e -> Lunions .used = 0 ; e -> Runions .used = 0 ;
1783
+ e -> Lunions .stack .next = NULL ;
1784
+ e -> Runions .stack .next = NULL ;
1731
1785
}
1732
1786
1733
1787
// subtyping entry points
@@ -2157,6 +2211,7 @@ JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env,
2157
2211
}
2158
2212
init_stenv (& e , env , envsz );
2159
2213
int subtype = forall_exists_subtype (x , y , & e , 0 );
2214
+ free_stenv (& e );
2160
2215
assert (obvious_subtype == 3 || obvious_subtype == subtype || jl_has_free_typevars (x ) || jl_has_free_typevars (y ));
2161
2216
#ifndef NDEBUG
2162
2217
if (obvious_subtype == 0 || (obvious_subtype == 1 && envsz == 0 ))
@@ -2249,6 +2304,7 @@ JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b)
2249
2304
{
2250
2305
init_stenv (& e , NULL , 0 );
2251
2306
int subtype = forall_exists_subtype (a , b , & e , 0 );
2307
+ free_stenv (& e );
2252
2308
assert (subtype_ab == 3 || subtype_ab == subtype || jl_has_free_typevars (a ) || jl_has_free_typevars (b ));
2253
2309
#ifndef NDEBUG
2254
2310
if (subtype_ab != 0 && subtype_ab != 1 ) // ensures that running in a debugger doesn't change the result
@@ -2265,6 +2321,7 @@ JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b)
2265
2321
{
2266
2322
init_stenv (& e , NULL , 0 );
2267
2323
int subtype = forall_exists_subtype (b , a , & e , 0 );
2324
+ free_stenv (& e );
2268
2325
assert (subtype_ba == 3 || subtype_ba == subtype || jl_has_free_typevars (a ) || jl_has_free_typevars (b ));
2269
2326
#ifndef NDEBUG
2270
2327
if (subtype_ba != 0 && subtype_ba != 1 ) // ensures that running in a debugger doesn't change the result
@@ -4230,7 +4287,9 @@ static jl_value_t *intersect_types(jl_value_t *x, jl_value_t *y, int emptiness_o
4230
4287
init_stenv (& e , NULL , 0 );
4231
4288
e .intersection = e .ignore_free = 1 ;
4232
4289
e .emptiness_only = emptiness_only ;
4233
- return intersect_all (x , y , & e );
4290
+ jl_value_t * ans = intersect_all (x , y , & e );
4291
+ free_stenv (& e );
4292
+ return ans ;
4234
4293
}
4235
4294
4236
4295
JL_DLLEXPORT jl_value_t * jl_intersect_types (jl_value_t * x , jl_value_t * y )
@@ -4407,6 +4466,7 @@ jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t *
4407
4466
memset (env , 0 , szb * sizeof (void * ));
4408
4467
e .envsz = szb ;
4409
4468
* ans = intersect_all (a , b , & e );
4469
+ free_stenv (& e );
4410
4470
if (* ans == jl_bottom_type ) goto bot ;
4411
4471
// TODO: code dealing with method signatures is not able to handle unions, so if
4412
4472
// `a` and `b` are both tuples, we need to be careful and may not return a union,
0 commit comments