Skip to content

Commit aff061b

Browse files
authored
Make sure ScopeStack doesn't box to IDisposable (#98396)
We allocate every time we encounter a using (ScopeStack.PushScope...) statement, which adds up to be a lot (~10mb in hello world, one of the most allocated objects). Instead, we can return the struct type directly so no boxing occurs.
1 parent fbe2b06 commit aff061b

File tree

3 files changed

+46
-29
lines changed

3 files changed

+46
-29
lines changed

src/tools/illink/src/linker/BannedSymbols.txt

+2
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ P:Mono.Cecil.Cil.MethodBody.Instructions;Use LinkContext.GetMethodIL or BannedAp
1010
P:Mono.Cecil.Cil.MethodBody.ExceptionHandlers;Use LinkContext.GetMethodIL or BannedApiExtensions.ExceptionHandlers(Mono.Linker.LinkContext) instead
1111
P:Mono.Cecil.Cil.MethodBody.Variables;Use LinkContext.GetMethodIL or BannedApiExtensions.Variables(Mono.Linker.LinkContext) instead
1212
M:Mono.Linker.Steps.ILProvider/MethodIL.Create;Use ILProvider GetMethodIL instead
13+
M:Mono.Linker.Steps.MarkScopeStack.PushScope;Use PushLocalScope instead to avoid boxing
14+
M:Mono.Linker.Steps.MarkScopeStack.PopToParent;Use PopToParentScope instead to avoid boxing

src/tools/illink/src/linker/Linker.Steps/MarkScopeStack.cs

+17-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public Scope (in MessageOrigin origin)
2222

2323
readonly Stack<Scope> _scopeStack;
2424

25-
readonly struct LocalScope : IDisposable
25+
internal readonly struct LocalScope : IDisposable
2626
{
2727
readonly MessageOrigin _origin;
2828
readonly MarkScopeStack _scopeStack;
@@ -51,7 +51,7 @@ public void Dispose ()
5151
}
5252
}
5353

54-
readonly struct ParentScope : IDisposable
54+
internal readonly struct ParentScope : IDisposable
5555
{
5656
readonly Scope _parentScope;
5757
readonly Scope _childScope;
@@ -78,6 +78,21 @@ public MarkScopeStack ()
7878
_scopeStack = new Stack<Scope> ();
7979
}
8080

81+
internal LocalScope PushLocalScope (in MessageOrigin origin)
82+
{
83+
return new LocalScope (origin, this);
84+
}
85+
86+
internal LocalScope PushLocalScope (in Scope scope)
87+
{
88+
return new LocalScope (scope, this);
89+
}
90+
91+
internal ParentScope PopToParentScope ()
92+
{
93+
return new ParentScope (this);
94+
}
95+
8196
public IDisposable PushScope (in MessageOrigin origin)
8297
{
8398
return new LocalScope (origin, this);

src/tools/illink/src/linker/Linker.Steps/MarkStep.cs

+27-27
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ bool ProcessInternalsVisibleAttributes ()
297297
Debug.Assert (attr.Provider is ModuleDefinition or AssemblyDefinition);
298298
var assembly = (provider is ModuleDefinition module) ? module.Assembly : provider as AssemblyDefinition;
299299

300-
using var assemblyScope = ScopeStack.PushScope (new MessageOrigin (assembly));
300+
using var assemblyScope = ScopeStack.PushLocalScope (new MessageOrigin (assembly));
301301

302302
if (!Annotations.IsMarked (attr.Attribute) && IsInternalsVisibleAttributeAssemblyMarked (attr.Attribute)) {
303303
MarkCustomAttribute (attr.Attribute, new DependencyInfo (DependencyKind.AssemblyOrModuleAttribute, attr.Provider));
@@ -362,7 +362,7 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason)
362362

363363
// Prevent cases where there's nothing on the stack (can happen when marking entire assemblies)
364364
// In which case we would generate warnings with no source (hard to debug)
365-
using var _ = ScopeStack.CurrentScope.Origin.Provider == null ? ScopeStack.PushScope (new MessageOrigin (type)) : null;
365+
using MarkScopeStack.LocalScope? _ = ScopeStack.CurrentScope.Origin.Provider == null ? ScopeStack.PushLocalScope (new MessageOrigin (type)) : null;
366366

367367
if (!_entireTypesMarked.Add (type))
368368
return;
@@ -451,7 +451,7 @@ bool MarkFullyPreservedAssemblies ()
451451

452452
// Setup empty scope - there has to be some scope setup since we're doing marking below
453453
// but there's no "origin" right now (command line is the origin really)
454-
using var localScope = ScopeStack.PushScope (new MessageOrigin ((ICustomAttributeProvider?) null));
454+
using var localScope = ScopeStack.PushLocalScope (new MessageOrigin ((ICustomAttributeProvider?) null));
455455

456456
// Beware: this works on loaded assemblies, not marked assemblies, so it should not be tied to marking.
457457
// We could further optimize this to only iterate through assemblies if the last mark iteration loaded
@@ -488,7 +488,7 @@ bool ProcessPrimaryQueue ()
488488

489489
bool ProcessMarkedPending ()
490490
{
491-
using var emptyScope = ScopeStack.PushScope (new MessageOrigin (null as ICustomAttributeProvider));
491+
using var emptyScope = ScopeStack.PushLocalScope (new MessageOrigin (null as ICustomAttributeProvider));
492492

493493
bool marked = false;
494494
foreach (var pending in Annotations.GetMarkedPending ()) {
@@ -498,7 +498,7 @@ bool ProcessMarkedPending ()
498498
if (Annotations.IsProcessed (pending.Key))
499499
continue;
500500

501-
using var localScope = ScopeStack.PushScope (pending.Value);
501+
using var localScope = ScopeStack.PushLocalScope (pending.Value);
502502

503503
switch (pending.Key) {
504504
case TypeDefinition type:
@@ -572,7 +572,7 @@ protected virtual void EnqueueMethod (MethodDefinition method, in DependencyInfo
572572
void ProcessVirtualMethods ()
573573
{
574574
foreach ((var method, var scope) in _virtual_methods) {
575-
using (ScopeStack.PushScope (scope)) {
575+
using (ScopeStack.PushLocalScope (scope)) {
576576
ProcessVirtualMethod (method);
577577
}
578578
}
@@ -597,7 +597,7 @@ void ProcessMarkedTypesWithInterfaces ()
597597
// UnusedInterfaces optimization is turned off mark all interface implementations
598598
bool unusedInterfacesOptimizationEnabled = Context.IsOptimizationEnabled (CodeOptimizations.UnusedInterfaces, type);
599599

600-
using (ScopeStack.PushScope (scope)) {
600+
using (ScopeStack.PushLocalScope (scope)) {
601601
if (Annotations.IsInstantiated (type) || Annotations.IsRelevantToVariantCasting (type) ||
602602
!unusedInterfacesOptimizationEnabled) {
603603
MarkInterfaceImplementations (type);
@@ -685,7 +685,7 @@ void ProcessPendingBodies ()
685685
for (int i = 0; i < _unreachableBodies.Count; i++) {
686686
(var body, var scope) = _unreachableBodies[i];
687687
if (Annotations.IsInstantiated (body.Method.DeclaringType)) {
688-
using (ScopeStack.PushScope (scope))
688+
using (ScopeStack.PushLocalScope (scope))
689689
MarkMethodBody (body);
690690

691691
_unreachableBodies.RemoveAt (i--);
@@ -874,7 +874,7 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo
874874
return;
875875

876876
IMemberDefinition providerMember = (IMemberDefinition) provider; ;
877-
using (ScopeStack.PushScope (new MessageOrigin (providerMember)))
877+
using (ScopeStack.PushLocalScope (new MessageOrigin (providerMember)))
878878
foreach (var dynamicDependency in Annotations.GetLinkerAttributes<DynamicDependency> (providerMember))
879879
MarkDynamicDependency (dynamicDependency, providerMember);
880880
}
@@ -1407,7 +1407,7 @@ protected virtual void MarkAssembly (AssemblyDefinition assembly, DependencyInfo
14071407
if (CheckProcessed (assembly))
14081408
return;
14091409

1410-
using var assemblyScope = ScopeStack.PushScope (new MessageOrigin (assembly));
1410+
using var assemblyScope = ScopeStack.PushLocalScope (new MessageOrigin (assembly));
14111411

14121412
EmbeddedXmlInfo.ProcessDescriptors (assembly, Context);
14131413

@@ -1537,7 +1537,7 @@ bool ProcessLazyAttributes ()
15371537
Debug.Assert (provider is ModuleDefinition or AssemblyDefinition);
15381538
var assembly = (provider is ModuleDefinition module) ? module.Assembly : provider as AssemblyDefinition;
15391539

1540-
using var assemblyScope = ScopeStack.PushScope (new MessageOrigin (assembly));
1540+
using var assemblyScope = ScopeStack.PushLocalScope (new MessageOrigin (assembly));
15411541

15421542
var resolved = Context.Resolve (customAttribute.Constructor);
15431543
if (resolved == null) {
@@ -1607,7 +1607,7 @@ bool ProcessLateMarkedAttributes ()
16071607
}
16081608

16091609
markOccurred = true;
1610-
using (ScopeStack.PushScope (scope)) {
1610+
using (ScopeStack.PushLocalScope (scope)) {
16111611
MarkCustomAttribute (customAttribute, reason);
16121612
}
16131613
}
@@ -1788,7 +1788,7 @@ void MarkField (FieldDefinition field, in DependencyInfo reason, in MessageOrigi
17881788
// Use the original scope for marking the declaring type - it provides better warning message location
17891789
MarkType (field.DeclaringType, new DependencyInfo (DependencyKind.DeclaringType, field));
17901790

1791-
using var fieldScope = ScopeStack.PushScope (new MessageOrigin (field));
1791+
using var fieldScope = ScopeStack.PushLocalScope (new MessageOrigin (field));
17921792
MarkType (field.FieldType, new DependencyInfo (DependencyKind.FieldType, field));
17931793
MarkCustomAttributes (field, new DependencyInfo (DependencyKind.CustomAttribute, field));
17941794
MarkMarshalSpec (field, new DependencyInfo (DependencyKind.FieldMarshalSpec, field));
@@ -2007,7 +2007,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in
20072007
if (reference == null)
20082008
return null;
20092009

2010-
using var localScope = origin.HasValue ? ScopeStack.PushScope (origin.Value) : null;
2010+
using MarkScopeStack.LocalScope? localScope = origin.HasValue ? ScopeStack.PushLocalScope (origin.Value) : null;
20112011

20122012
(reference, reason) = GetOriginalType (reference, reason);
20132013

@@ -2053,7 +2053,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in
20532053
if (type.Scope is ModuleDefinition module)
20542054
MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type));
20552055

2056-
using var typeScope = ScopeStack.PushScope (new MessageOrigin (type));
2056+
using var typeScope = ScopeStack.PushLocalScope (new MessageOrigin (type));
20572057

20582058
foreach (Action<TypeDefinition> handleMarkType in MarkContext.MarkTypeActions)
20592059
handleMarkType (type);
@@ -2141,7 +2141,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in
21412141
}
21422142
}
21432143
if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) {
2144-
using (ScopeStack.PopToParent ())
2144+
using (ScopeStack.PopToParentScope ())
21452145
MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin);
21462146
}
21472147
}
@@ -2440,7 +2440,7 @@ void MarkNamedProperty (TypeDefinition type, string property_name, in Dependency
24402440
if (property.Name != property_name)
24412441
continue;
24422442

2443-
using (ScopeStack.PushScope (new MessageOrigin (property))) {
2443+
using (ScopeStack.PushLocalScope (new MessageOrigin (property))) {
24442444
// This marks methods directly without reporting the property.
24452445
MarkMethod (property.GetMethod, reason, ScopeStack.CurrentScope.Origin);
24462446
MarkMethod (property.SetMethod, reason, ScopeStack.CurrentScope.Origin);
@@ -2804,7 +2804,7 @@ void MarkGenericArguments (IGenericInstance instance)
28042804
// The only two implementations of IGenericInstance both derive from MemberReference
28052805
Debug.Assert (instance is MemberReference);
28062806

2807-
using var _ = ScopeStack.CurrentScope.Origin.Provider == null ? ScopeStack.PushScope (new MessageOrigin (((MemberReference) instance).Resolve ())) : null;
2807+
using MarkScopeStack.LocalScope? _ = ScopeStack.CurrentScope.Origin.Provider == null ? ScopeStack.PushLocalScope (new MessageOrigin (((MemberReference) instance).Resolve ())) : null;
28082808
var scanner = new GenericArgumentDataFlow (Context, this, ScopeStack.CurrentScope.Origin);
28092809
scanner.ProcessGenericArgumentDataFlow (parameter, argument);
28102810
}
@@ -2832,7 +2832,7 @@ void MarkGenericArguments (IGenericInstance instance)
28322832

28332833
void ApplyPreserveInfo (TypeDefinition type)
28342834
{
2835-
using var typeScope = ScopeStack.PushScope (new MessageOrigin (type));
2835+
using var typeScope = ScopeStack.PushLocalScope (new MessageOrigin (type));
28362836

28372837
if (Annotations.TryGetPreserve (type, out TypePreserve preserve)) {
28382838
if (!Annotations.SetAppliedPreserve (type, preserve))
@@ -3203,8 +3203,8 @@ protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo
32033203
throw new InternalErrorException ($"Unsupported method dependency {reason.Kind}");
32043204
#endif
32053205
ScopeStack.AssertIsEmpty ();
3206-
using var parentScope = ScopeStack.PushScope (new MarkScopeStack.Scope (origin));
3207-
using var methodScope = ScopeStack.PushScope (new MessageOrigin (method));
3206+
using var parentScope = ScopeStack.PushLocalScope (new MarkScopeStack.Scope (origin));
3207+
using var methodScope = ScopeStack.PushLocalScope (new MessageOrigin (method));
32083208

32093209
bool markedForCall =
32103210
reason.Kind == DependencyKind.DirectCall ||
@@ -3360,7 +3360,7 @@ protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type
33603360

33613361
Annotations.MarkInstantiated (type);
33623362

3363-
using var typeScope = ScopeStack.PushScope (new MessageOrigin (type));
3363+
using var typeScope = ScopeStack.PushLocalScope (new MessageOrigin (type));
33643364

33653365
MarkInterfaceImplementations (type);
33663366

@@ -3450,7 +3450,7 @@ bool MarkDisablePrivateReflectionAttribute ()
34503450
if (disablePrivateReflection == null)
34513451
throw new LinkerFatalErrorException (MessageContainer.CreateErrorMessage (null, DiagnosticId.CouldNotFindType, "System.Runtime.CompilerServices.DisablePrivateReflectionAttribute"));
34523452

3453-
using (ScopeStack.PushScope (new MessageOrigin (null as ICustomAttributeProvider))) {
3453+
using (ScopeStack.PushLocalScope (new MessageOrigin (null as ICustomAttributeProvider))) {
34543454
MarkType (disablePrivateReflection, DependencyInfo.DisablePrivateReflectionRequirement);
34553455

34563456
var ctor = MarkMethodIf (disablePrivateReflection.Methods, MethodDefinitionExtensions.IsDefaultConstructor, new DependencyInfo (DependencyKind.DisablePrivateReflectionRequirement, disablePrivateReflection), ScopeStack.CurrentScope.Origin);
@@ -3570,7 +3570,7 @@ protected internal void MarkProperty (PropertyDefinition prop, in DependencyInfo
35703570
if (!Annotations.MarkProcessed (prop, reason))
35713571
return;
35723572

3573-
using var propertyScope = ScopeStack.PushScope (new MessageOrigin (prop));
3573+
using var propertyScope = ScopeStack.PushLocalScope (new MessageOrigin (prop));
35743574

35753575
// Consider making this more similar to MarkEvent method?
35763576
MarkCustomAttributes (prop, new DependencyInfo (DependencyKind.CustomAttribute, prop));
@@ -3582,7 +3582,7 @@ protected internal virtual void MarkEvent (EventDefinition evt, in DependencyInf
35823582
if (!Annotations.MarkProcessed (evt, reason))
35833583
return;
35843584

3585-
using var eventScope = ScopeStack.PushScope (new MessageOrigin (evt));
3585+
using var eventScope = ScopeStack.PushLocalScope (new MessageOrigin (evt));
35863586

35873587
MarkCustomAttributes (evt, new DependencyInfo (DependencyKind.CustomAttribute, evt));
35883588

@@ -3681,7 +3681,7 @@ bool MarkAndCheckRequiresReflectionMethodBodyScanner (MethodIL methodIL)
36813681

36823682
requiresReflectionMethodBodyScanner =
36833683
ReflectionMethodBodyScanner.RequiresReflectionMethodBodyScannerForMethodBody (Context, methodIL.Method);
3684-
using var _ = ScopeStack.PushScope (new MessageOrigin (methodIL.Method));
3684+
using var _ = ScopeStack.PushLocalScope (new MessageOrigin (methodIL.Method));
36853685
foreach (Instruction instruction in methodIL.Instructions)
36863686
MarkInstruction (instruction, methodIL.Method, ref requiresReflectionMethodBodyScanner);
36873687

@@ -3832,7 +3832,7 @@ protected internal virtual void MarkInterfaceImplementation (InterfaceImplementa
38323832
return;
38333833
Annotations.MarkProcessed (iface, reason ?? new DependencyInfo (DependencyKind.InterfaceImplementationOnType, ScopeStack.CurrentScope.Origin.Provider));
38343834

3835-
using var localScope = origin.HasValue ? ScopeStack.PushScope (origin.Value) : null;
3835+
using MarkScopeStack.LocalScope? localScope = origin.HasValue ? ScopeStack.PushLocalScope (origin.Value) : null;
38363836

38373837
// Blame the type that has the interfaceimpl, expecting the type itself to get marked for other reasons.
38383838
MarkCustomAttributes (iface, new DependencyInfo (DependencyKind.CustomAttribute, iface));

0 commit comments

Comments
 (0)