@@ -34,18 +34,69 @@ public bool FormsCycle(TypeSystemEntity owner)
34
34
TypeDesc ownerType = ( owner as EcmaMethod ) ? . OwningType ;
35
35
return _entitiesInCycles . Contains ( owner ) || ( ownerType != null && _entitiesInCycles . Contains ( ownerType ) ) ;
36
36
}
37
+ }
38
+
39
+ private class CycleInfoHashtable : LockFreeReaderHashtable < EcmaModule , ModuleCycleInfo >
40
+ {
41
+ protected override bool CompareKeyToValue ( EcmaModule key , ModuleCycleInfo value ) => key == value . Module ;
42
+ protected override bool CompareValueToValue ( ModuleCycleInfo value1 , ModuleCycleInfo value2 ) => value1 . Module == value2 . Module ;
43
+ protected override int GetKeyHashCode ( EcmaModule key ) => key . GetHashCode ( ) ;
44
+ protected override int GetValueHashCode ( ModuleCycleInfo value ) => value . Module . GetHashCode ( ) ;
45
+
46
+ protected override ModuleCycleInfo CreateValueFromKey ( EcmaModule key )
47
+ {
48
+ GraphBuilder gb = new GraphBuilder ( key ) ;
49
+ Graph < EcmaGenericParameter > graph = gb . Graph ;
50
+
51
+ var formalsNeedingLazyGenerics = graph . ComputeVerticesInvolvedInAFlaggedCycle ( ) ;
52
+ var entitiesNeedingLazyGenerics = new HashSet < TypeSystemEntity > ( ) ;
53
+
54
+ foreach ( EcmaGenericParameter formal in formalsNeedingLazyGenerics )
55
+ {
56
+ var formalDefinition = key . MetadataReader . GetGenericParameter ( formal . Handle ) ;
57
+ if ( formal . Kind == GenericParameterKind . Type )
58
+ {
59
+ entitiesNeedingLazyGenerics . Add ( key . GetType ( formalDefinition . Parent ) ) ;
60
+ }
61
+ else
62
+ {
63
+ entitiesNeedingLazyGenerics . Add ( key . GetMethod ( formalDefinition . Parent ) ) ;
64
+ }
65
+ }
66
+
67
+ return new ModuleCycleInfo ( key , entitiesNeedingLazyGenerics ) ;
68
+ }
69
+ }
70
+
71
+ internal class GenericCycleDetector
72
+ {
73
+ private readonly CycleInfoHashtable _hashtable = new CycleInfoHashtable ( ) ;
74
+
75
+ private readonly struct EntityPair : IEquatable < EntityPair >
76
+ {
77
+ public readonly TypeSystemEntity Owner ;
78
+ public readonly TypeSystemEntity Referent ;
79
+ public EntityPair ( TypeSystemEntity owner , TypeSystemEntity referent )
80
+ => ( Owner , Referent ) = ( owner , referent ) ;
81
+ public bool Equals ( EntityPair other ) => Owner == other . Owner && Referent == other . Referent ;
82
+ public override bool Equals ( object obj ) => obj is EntityPair p && Equals ( p ) ;
83
+ public override int GetHashCode ( ) => HashCode . Combine ( Owner . GetHashCode ( ) , Referent . GetHashCode ( ) ) ;
84
+ }
85
+
86
+ // This is a set of entities that had actual problems that caused us to abort compilation
87
+ // somewhere.
88
+ // Would prefer this to be a ConcurrentHashSet but there isn't any. ModuleCycleInfo can be looked up
89
+ // from the key, but since this is a key/value pair, might as well use the value too...
90
+ private readonly ConcurrentDictionary < EntityPair , ModuleCycleInfo > _actualProblems = new ConcurrentDictionary < EntityPair , ModuleCycleInfo > ( ) ;
91
+
92
+ private readonly int _cutoffPoint ;
93
+
94
+ public GenericCycleDetector ( int cutoffPoint )
95
+ {
96
+ _cutoffPoint = cutoffPoint ;
97
+ }
37
98
38
- // Chosen rather arbitrarily. For the app that I was looking at, cutoff point of 7 compiled
39
- // more than 10 minutes on a release build of the compiler, and I lost patience.
40
- // Cutoff point of 5 produced an 1.7 GB object file.
41
- // Cutoff point of 4 produced an 830 MB object file.
42
- // Cutoff point of 3 produced an 470 MB object file.
43
- // We want this to be high enough so that it doesn't cut off too early. But also not too
44
- // high because things that are recursive often end up expanding laterally as well
45
- // through various other generic code the deep code calls into.
46
- private const int CutoffPoint = 4 ;
47
-
48
- public bool IsDeepPossiblyCyclicInstantiation ( TypeSystemEntity entity )
99
+ private bool IsDeepPossiblyCyclicInstantiation ( TypeSystemEntity entity )
49
100
{
50
101
if ( entity is TypeDesc type )
51
102
{
@@ -57,7 +108,7 @@ public bool IsDeepPossiblyCyclicInstantiation(TypeSystemEntity entity)
57
108
}
58
109
}
59
110
60
- public bool IsDeepPossiblyCyclicInstantiation ( TypeDesc type , List < TypeDesc > seenTypes = null )
111
+ private bool IsDeepPossiblyCyclicInstantiation ( TypeDesc type , List < TypeDesc > seenTypes = null )
61
112
{
62
113
switch ( type . Category )
63
114
{
@@ -80,7 +131,7 @@ public bool IsDeepPossiblyCyclicInstantiation(TypeDesc type, List<TypeDesc> seen
80
131
count ++ ;
81
132
}
82
133
83
- if ( count > CutoffPoint )
134
+ if ( count > _cutoffPoint )
84
135
{
85
136
return true ;
86
137
}
@@ -112,60 +163,6 @@ public bool IsDeepPossiblyCyclicInstantiation(MethodDesc method)
112
163
{
113
164
return IsDeepPossiblyCyclicInstantiation ( method . Instantiation ) || IsDeepPossiblyCyclicInstantiation ( method . OwningType ) ;
114
165
}
115
- }
116
-
117
- private class CycleInfoHashtable : LockFreeReaderHashtable < EcmaModule , ModuleCycleInfo >
118
- {
119
- protected override bool CompareKeyToValue ( EcmaModule key , ModuleCycleInfo value ) => key == value . Module ;
120
- protected override bool CompareValueToValue ( ModuleCycleInfo value1 , ModuleCycleInfo value2 ) => value1 . Module == value2 . Module ;
121
- protected override int GetKeyHashCode ( EcmaModule key ) => key . GetHashCode ( ) ;
122
- protected override int GetValueHashCode ( ModuleCycleInfo value ) => value . Module . GetHashCode ( ) ;
123
-
124
- protected override ModuleCycleInfo CreateValueFromKey ( EcmaModule key )
125
- {
126
- GraphBuilder gb = new GraphBuilder ( key ) ;
127
- Graph < EcmaGenericParameter > graph = gb . Graph ;
128
-
129
- var formalsNeedingLazyGenerics = graph . ComputeVerticesInvolvedInAFlaggedCycle ( ) ;
130
- var entitiesNeedingLazyGenerics = new HashSet < TypeSystemEntity > ( ) ;
131
-
132
- foreach ( EcmaGenericParameter formal in formalsNeedingLazyGenerics )
133
- {
134
- var formalDefinition = key . MetadataReader . GetGenericParameter ( formal . Handle ) ;
135
- if ( formal . Kind == GenericParameterKind . Type )
136
- {
137
- entitiesNeedingLazyGenerics . Add ( key . GetType ( formalDefinition . Parent ) ) ;
138
- }
139
- else
140
- {
141
- entitiesNeedingLazyGenerics . Add ( key . GetMethod ( formalDefinition . Parent ) ) ;
142
- }
143
- }
144
-
145
- return new ModuleCycleInfo ( key , entitiesNeedingLazyGenerics ) ;
146
- }
147
- }
148
-
149
- internal class GenericCycleDetector
150
- {
151
- private readonly CycleInfoHashtable _hashtable = new CycleInfoHashtable ( ) ;
152
-
153
- private readonly struct EntityPair : IEquatable < EntityPair >
154
- {
155
- public readonly TypeSystemEntity Owner ;
156
- public readonly TypeSystemEntity Referent ;
157
- public EntityPair ( TypeSystemEntity owner , TypeSystemEntity referent )
158
- => ( Owner , Referent ) = ( owner , referent ) ;
159
- public bool Equals ( EntityPair other ) => Owner == other . Owner && Referent == other . Referent ;
160
- public override bool Equals ( object obj ) => obj is EntityPair p && Equals ( p ) ;
161
- public override int GetHashCode ( ) => HashCode . Combine ( Owner . GetHashCode ( ) , Referent . GetHashCode ( ) ) ;
162
- }
163
-
164
- // This is a set of entities that had actual problems that caused us to abort compilation
165
- // somewhere.
166
- // Would prefer this to be a ConcurrentHashSet but there isn't any. ModuleCycleInfo can be looked up
167
- // from the key, but since this is a key/value pair, might as well use the value too...
168
- private readonly ConcurrentDictionary < EntityPair , ModuleCycleInfo > _actualProblems = new ConcurrentDictionary < EntityPair , ModuleCycleInfo > ( ) ;
169
166
170
167
public void DetectCycle ( TypeSystemEntity owner , TypeSystemEntity referent )
171
168
{
@@ -196,7 +193,7 @@ public void DetectCycle(TypeSystemEntity owner, TypeSystemEntity referent)
196
193
{
197
194
// Just the presence of a cycle is not a problem, but once we start getting too deep,
198
195
// we need to cut our losses.
199
- if ( cycleInfo . IsDeepPossiblyCyclicInstantiation ( referent ) )
196
+ if ( IsDeepPossiblyCyclicInstantiation ( referent ) )
200
197
{
201
198
_actualProblems . TryAdd ( new EntityPair ( owner , referent ) , cycleInfo ) ;
202
199
0 commit comments