Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only compute if method returns a constant when needed #1734

Merged
merged 17 commits into from
Jan 11, 2021
Merged
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 45 additions & 55 deletions src/linker/Linker.Steps/RemoveUnreachableBlocksStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,81 +17,68 @@ namespace Mono.Linker.Steps
public class RemoveUnreachableBlocksStep : BaseStep
{
Dictionary<MethodDefinition, Instruction> constExprMethods;
int constExprMethodsAdded;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot this be bool value?

MethodDefinition IntPtrSize, UIntPtrSize;

protected override void Process ()
{
var assemblies = Context.Annotations.GetAssemblies ().ToArray ();

constExprMethods = new Dictionary<MethodDefinition, Instruction> ();
foreach (var assembly in assemblies) {
FindConstantExpressionsMethods (assembly.MainModule.Types);
}

if (constExprMethods.Count == 0)
return;

int constExprMethodsCount;
do {
//
// Body rewriting can produce more methods with constant expression
//
constExprMethodsCount = constExprMethods.Count;
constExprMethodsAdded = 0;

foreach (var assembly in assemblies) {
if (Annotations.GetAction (assembly) != AssemblyAction.Link)
continue;

RewriteBodies (assembly.MainModule.Types);
}
} while (constExprMethodsCount < constExprMethods.Count);
} while (constExprMethodsAdded > 0);
}

void FindConstantExpressionsMethods (Collection<TypeDefinition> types)
bool TryGetConstantResultInstructionForMethod (MethodDefinition method, out Instruction constantResultInstruction)
{
foreach (var type in types) {
if (type.IsInterface)
continue;
if (constExprMethods.TryGetValue (method, out constantResultInstruction))
return constantResultInstruction != null;

if (!type.HasMethods)
continue;

foreach (var method in type.Methods) {
if (!method.HasBody)
continue;
constantResultInstruction = GetConstantResultInstructionForMethod (method);
constExprMethods.Add (method, constantResultInstruction);

if (method.ReturnType.MetadataType == MetadataType.Void)
continue;

switch (Annotations.GetAction (method)) {
case MethodAction.ConvertToThrow:
continue;
case MethodAction.ConvertToStub:
var instruction = CodeRewriterStep.CreateConstantResultInstruction (Context, method);
if (instruction != null)
constExprMethods[method] = instruction;
return constantResultInstruction != null;
}

continue;
}
Instruction GetConstantResultInstructionForMethod (MethodDefinition method)
{
if (!method.HasBody)
return null;

if (method.IsIntrinsic () || method.NoInlining)
continue;
if (method.ReturnType.MetadataType == MetadataType.Void)
return null;

if (constExprMethods.ContainsKey (method))
continue;
switch (Annotations.GetAction (method)) {
case MethodAction.ConvertToThrow:
return null;
case MethodAction.ConvertToStub:
return CodeRewriterStep.CreateConstantResultInstruction (Context, method);
}

if (!Context.IsOptimizationEnabled (CodeOptimizations.IPConstantPropagation, method))
continue;
if (method.IsIntrinsic () || method.NoInlining)
return null;

var analyzer = new ConstantExpressionMethodAnalyzer (method);
if (analyzer.Analyze ()) {
constExprMethods[method] = analyzer.Result;
}
}
if (!Context.IsOptimizationEnabled (CodeOptimizations.IPConstantPropagation, method))
return null;

if (type.HasNestedTypes)
FindConstantExpressionsMethods (type.NestedTypes);
var analyzer = new ConstantExpressionMethodAnalyzer (method);
if (analyzer.Analyze ()) {
return analyzer.Result;
}

return null;
}

void RewriteBodies (Collection<TypeDefinition> types)
Expand All @@ -115,7 +102,6 @@ void RewriteBodies (Collection<TypeDefinition> types)
case MetadataType.FunctionPointer:
continue;
}

RewriteBody (method);
}

Expand Down Expand Up @@ -148,12 +134,15 @@ void RewriteBody (MethodDefinition method)
if (method.ReturnType.MetadataType == MetadataType.Void)
return;

//
// Re-run the analyzer in case body change rewrote it to constant expression
//
var analyzer = new ConstantExpressionMethodAnalyzer (method, reducer.FoldedInstructions);
if (analyzer.Analyze ()) {
constExprMethods[method] = analyzer.Result;
if (!constExprMethods.TryGetValue (method, out var constInstruction) || constInstruction == null) {
//
// Re-run the analyzer in case body change rewrote it to constant expression
//
var analyzer = new ConstantExpressionMethodAnalyzer (method, reducer.FoldedInstructions);
if (analyzer.Analyze ()) {
constExprMethods[method] = analyzer.Result;
constExprMethodsAdded++;
}
}
}

Expand All @@ -174,9 +163,6 @@ bool TryInlineBodyDependencies (ref BodyReducer reducer)
if (md == null)
break;

if (!constExprMethods.TryGetValue (md, out targetResult))
break;

if (md.CallingConvention == MethodCallingConvention.VarArg)
break;

Expand Down Expand Up @@ -208,8 +194,12 @@ bool TryInlineBodyDependencies (ref BodyReducer reducer)
break;
}

if (!TryGetConstantResultInstructionForMethod (md, out targetResult))
break;

reducer.Rewrite (i, targetResult);
changed = true;

break;

case Code.Ldsfld:
Expand Down Expand Up @@ -244,7 +234,7 @@ bool TryInlineBodyDependencies (ref BodyReducer reducer)
sizeOfImpl = (IntPtrSize ??= FindSizeMethod (operand.Resolve ()));
}

if (sizeOfImpl != null && constExprMethods.TryGetValue (sizeOfImpl, out targetResult)) {
if (sizeOfImpl != null && TryGetConstantResultInstructionForMethod (sizeOfImpl, out targetResult)) {
reducer.Rewrite (i, targetResult);
changed = true;
}
Expand Down