Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2019-10-26 09:20:15 +0300
committerMarek Safar <marek.safar@gmail.com>2019-12-11 02:05:36 +0300
commit132d8afe7ac5eae64b7597f120319fd2ccca5d5a (patch)
tree195bf01f9ee9602bb0833a941b436576bafbe6c9 /test/Mono.Linker.Tests
parentb4770592e35a54823ef5705cc339bf6327229570 (diff)
Add new optimization steps to make Mark step more effective
Two new steps have been introduced BodySubstituterStep This step removes any conditional blocks when the condition or conditions are evaluated as constants. This step does not do any inlining. The conditional logic is kept but based on the known values only one branch is always taken. A simple example which can be detected by linker. ```c# class C { static void Main () { if (Result) Console.WriteLine (); // <- this call will be marked and removed } static bool Result () => false; } ``` RemoveUnreachableBlocksStep A new command-line option called `--substitutions` allow external customization of any methoda for assemblies which are linked. The syntax is same as for existing linker descriptor XML files but it add way to control body modifications. An example of XML file ```xml <linker> <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> <type fullname="Mono.Linker.Tests.Cases.Substitutions.StubBodyWithValue"> <method signature="System.String TestMethod_1()" body="stub" value="abcd"> </method> </type> </assembly> </linker> ``` The `value` attribute is optional and only required when the method stub should not fallback to default behaviour. Additional to `stub` value also `remove` value is supported to forcibly remove body of the method when the method is marked. This is useful when the conditional logic cannot be evaluated by linker and the method will be marked but never actually reached. Applicability Both steps can be combined to achieve the effect of externally customizing which conditional branches can be removed during the linking. I can illustrate that on IntPtr.Size property. With following substitution any code that has compiled in conditional logic for 64 bits handling by checking IntPtr.Size will be removed during linking. ```xml <linker> <assembly fullname="mscorlib"> <type fullname="System.IntPtr"> <method signature="System.Int32 get_Size()" body="stub" value="4"> </method> </type> </assembly> </linker> ``` Implements #752
Diffstat (limited to 'test/Mono.Linker.Tests')
-rw-r--r--test/Mono.Linker.Tests/TestCases/TestDatabase.cs10
-rw-r--r--test/Mono.Linker.Tests/TestCases/TestSuites.cs12
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/LinkerArgumentBuilder.cs9
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs2
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs17
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs4
-rw-r--r--test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs6
7 files changed, 55 insertions, 5 deletions
diff --git a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
index 893b55508..726516d21 100644
--- a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
+++ b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs
@@ -141,6 +141,16 @@ namespace Mono.Linker.Tests.TestCases
return NUnitCasesBySuiteName ("CodegenAnnotation");
}
+ public static IEnumerable<TestCaseData> UnreachableBlockTests ()
+ {
+ return NUnitCasesBySuiteName ("UnreachableBlock");
+ }
+
+ public static IEnumerable<TestCaseData> SubstitutionsTests ()
+ {
+ return NUnitCasesBySuiteName ("Substitutions");
+ }
+
public static TestCaseCollector CreateCollector ()
{
string rootSourceDirectory;
diff --git a/test/Mono.Linker.Tests/TestCases/TestSuites.cs b/test/Mono.Linker.Tests/TestCases/TestSuites.cs
index b3aa7ad50..c7d906c36 100644
--- a/test/Mono.Linker.Tests/TestCases/TestSuites.cs
+++ b/test/Mono.Linker.Tests/TestCases/TestSuites.cs
@@ -169,6 +169,18 @@ namespace Mono.Linker.Tests.TestCases
Run (testCase);
}
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.UnreachableBlockTests))]
+ public void UnreachableBlockTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.SubstitutionsTests))]
+ public void SubstitutionsTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
protected virtual void Run (TestCase testCase)
{
var runner = new TestRunner (new ObjectFactory ());
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/LinkerArgumentBuilder.cs b/test/Mono.Linker.Tests/TestCasesRunner/LinkerArgumentBuilder.cs
index 98f93d782..3a3f2a055 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/LinkerArgumentBuilder.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/LinkerArgumentBuilder.cs
@@ -111,6 +111,12 @@ namespace Mono.Linker.Tests.TestCasesRunner {
}
}
+ public virtual void AddSubstitutions (string file)
+ {
+ Append ("--substitutions");
+ Append (file);
+ }
+
public string [] ToArgs ()
{
return _arguments.ToArray ();
@@ -171,6 +177,9 @@ namespace Mono.Linker.Tests.TestCasesRunner {
AddStripResources (options.StripResources);
+ foreach (var substitutions in options.Substitutions)
+ AddSubstitutions (substitutions);
+
// Unity uses different argument format and needs to be able to translate to their format. In order to make that easier
// we keep the information in flag + values format for as long as we can so that this information doesn't have to be parsed out of a single string
foreach (var additionalArgument in options.AdditionalArguments)
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs
index f13b4eafc..5becea9ad 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseLinkerOptions.cs
@@ -17,5 +17,7 @@ namespace Mono.Linker.Tests.TestCasesRunner {
public bool StripResources;
public List<KeyValuePair<string, string[]>> AdditionalArguments = new List<KeyValuePair<string, string[]>> ();
+
+ public List<string> Substitutions = new List<string> ();
}
} \ No newline at end of file
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs
index 8aeaf9c36..1b2383a5f 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs
@@ -25,7 +25,7 @@ namespace Mono.Linker.Tests.TestCasesRunner {
throw new InvalidOperationException ($"Could not find the type definition for {_testCase.Name} in {_testCase.SourceFile}");
}
- public virtual TestCaseLinkerOptions GetLinkerOptions ()
+ public virtual TestCaseLinkerOptions GetLinkerOptions (NPath inputPath)
{
var tclo = new TestCaseLinkerOptions {
Il8n = GetOptionAttributeValue (nameof (Il8nAttribute), "none"),
@@ -36,7 +36,7 @@ namespace Mono.Linker.Tests.TestCasesRunner {
CoreAssembliesAction = GetOptionAttributeValue<string> (nameof (SetupLinkerCoreActionAttribute), null),
UserAssembliesAction = GetOptionAttributeValue<string> (nameof (SetupLinkerUserActionAttribute), null),
SkipUnresolved = GetOptionAttributeValue (nameof (SkipUnresolvedAttribute), false),
- StripResources = GetOptionAttributeValue (nameof (StripResourcesAttribute), true)
+ StripResources = GetOptionAttributeValue (nameof (StripResourcesAttribute), true),
};
foreach (var assemblyAction in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerActionAttribute)))
@@ -45,6 +45,12 @@ namespace Mono.Linker.Tests.TestCasesRunner {
tclo.AssembliesAction.Add (new KeyValuePair<string, string> ((string)ca [0].Value, (string)ca [1].Value));
}
+ foreach (var subsFile in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerSubstitutionFileAttribute))) {
+ var ca = subsFile.ConstructorArguments;
+ var file = (string)ca [0].Value;
+ tclo.Substitutions.Add (Path.Combine (inputPath, file));
+ }
+
foreach (var additionalArgumentAttr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerArgumentAttribute)))
{
var ca = additionalArgumentAttr.ConstructorArguments;
@@ -136,6 +142,13 @@ namespace Mono.Linker.Tests.TestCasesRunner {
.Select (GetSourceAndRelativeDestinationValue);
}
+ public virtual IEnumerable<SourceAndDestinationPair> GetSubstitutionFiles ()
+ {
+ return _testCaseTypeDefinition.CustomAttributes
+ .Where (attr => attr.AttributeType.Name == nameof (SetupLinkerSubstitutionFileAttribute))
+ .Select (GetSourceAndRelativeDestinationValue);
+ }
+
public virtual IEnumerable<NPath> GetExtraLinkerSearchDirectories ()
{
#if NETCOREAPP
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs
index 5ec502878..d1866881e 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs
@@ -98,6 +98,10 @@ namespace Mono.Linker.Tests.TestCasesRunner {
res.Source.FileMustExist ().Copy (InputDirectory.Combine (res.DestinationFileName));
}
+ foreach (var res in metadataProvider.GetSubstitutionFiles ()) {
+ res.Source.FileMustExist ().Copy (InputDirectory.Combine (res.DestinationFileName));
+ }
+
foreach (var compileRefInfo in metadataProvider.GetSetupCompileAssembliesBefore ())
{
var destination = BeforeReferenceSourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists ();
diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs
index b9a1cc71b..9fbec7c1e 100644
--- a/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs
+++ b/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs
@@ -104,14 +104,14 @@ namespace Mono.Linker.Tests.TestCasesRunner {
protected virtual void AddLinkOptions (TestCaseSandbox sandbox, ManagedCompilationResult compilationResult, LinkerArgumentBuilder builder, TestCaseMetadaProvider metadataProvider)
{
- var caseDefinedOptions = metadataProvider.GetLinkerOptions ();
+ var caseDefinedOptions = metadataProvider.GetLinkerOptions (sandbox.InputDirectory);
builder.AddOutputDirectory (sandbox.OutputDirectory);
foreach (var linkXmlFile in sandbox.LinkXmlFiles)
builder.AddLinkXmlFile (linkXmlFile);
- foreach (var linkXmlFile in sandbox.ResponseFiles)
- builder.AddResponseFile (linkXmlFile);
+ foreach (var rspFile in sandbox.ResponseFiles)
+ builder.AddResponseFile (rspFile);
builder.AddSearchDirectory (sandbox.InputDirectory);
foreach (var extraSearchDir in metadataProvider.GetExtraLinkerSearchDirectories ())