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

[Perf] Add IID Lookup Optimization #849

Merged
merged 32 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
38ce4d3
add GuidPatch project and starter target
j0shuams May 18, 2021
2f97489
add guid patch to nuspec and build cmd
j0shuams May 18, 2021
bfcc5dd
Update WinUI3 pkg reference in Tests
j0shuams May 20, 2021
52f5c99
Feedback
j0shuams May 21, 2021
d4baf0b
More feedback.
j0shuams May 24, 2021
2f3128c
Remove platform based logic, only run in net5, other fixes
j0shuams May 25, 2021
a2ff6b6
Fix GUID patcher to pass tests.
manodasanW Jun 1, 2021
7e5df52
Avoid invalid cast exception, props changes, some cleanup
j0shuams Jun 8, 2021
f804748
Merge branch 'master' into jlarkin/GuidPatcher
j0shuams Jun 8, 2021
0e34ccd
Merge branch 'master' into jlarkin/GuidPatcher
j0shuams Jun 9, 2021
6f5ccdf
Clean-up.
j0shuams Jun 10, 2021
ee04daa
Merge branch 'master' into jlarkin/GuidPatcher
j0shuams Jun 10, 2021
8ada065
Add tests for iidoptimizer
j0shuams Jun 11, 2021
bb21e0d
Merge branch 'master' into jlarkin/GuidPatcher
j0shuams Jun 11, 2021
c2c68e5
Merge branch 'master' into jlarkin/GuidPatcher
manodasanW Jun 12, 2021
4061d6b
Fix issue causing IID optimizer to not run and add notice file for li…
manodasanW Jun 13, 2021
455f11b
Clean up.
j0shuams Jun 14, 2021
19f8768
Update to pass parameters; remove unused class; pass logger (for now)
j0shuams Jun 22, 2021
7d72714
Update patcher exe, now resolving reference assemblies.
j0shuams Jul 8, 2021
28ffd4f
Merge branch 'master' into jlarkin/GuidPatcher
j0shuams Jul 8, 2021
9271565
Update reunion component + reunion references
j0shuams Jul 9, 2021
1eed5e3
Update cswinrt.sln
j0shuams Jul 9, 2021
787f544
More Reunion/Lifted Lifetime test updates
j0shuams Jul 13, 2021
9ea1ca6
no cruft
j0shuams Jul 13, 2021
4181a56
Updates to winui related projects
j0shuams Jul 13, 2021
76ef07e
fixups
j0shuams Jul 13, 2021
6ab01a2
fix sigemitter
j0shuams Jul 14, 2021
4142d10
Merge branch 'jlarkin/temp-patcher-fix' into jlarkin/GuidPatcher
j0shuams Jul 14, 2021
db582bf
Update IL emitter, address PR feedback
j0shuams Jul 15, 2021
dc4385d
Don't patch twice
j0shuams Jul 15, 2021
f7ace89
Feedback 2
j0shuams Jul 18, 2021
ae1fd7b
Merge branch 'master' into jlarkin/GuidPatcher
j0shuams Jul 18, 2021
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
2 changes: 2 additions & 0 deletions nuget/Microsoft.Windows.CsWinRT.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</metadata>
<files>
<file src="LICENSE"/>
<file src="NOTICE.txt"/>
<file src="$cswinrt_exe$"/>
<file src="Microsoft.Windows.CsWinRT.props" target="build"/>
<file src="Microsoft.Windows.CsWinRT.targets" target="build"/>
Expand All @@ -34,5 +35,6 @@
<file src="$winrt_host_arm$" target ="runtimes\win-arm\native"/>
<file src="$winrt_host_arm64$" target ="runtimes\win-arm64\native"/>
<file src="$winrt_shim$" target ="lib\net5.0\"/>
<file src="$guid_patch$" target ="build\tools\IIDOptimizer"/>
</files>
</package>
74 changes: 73 additions & 1 deletion nuget/Microsoft.Windows.CsWinRT.targets
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<Target Name="CsWinRTGenerateProjection" DependsOnTargets="CsWinRTPrepareProjection;CsWinRTRemoveWinMDReferences" Condition="'$(CsWinRTGenerateProjection)' == 'true'">
<PropertyGroup>
<CsWinRTResponseFile>$(CsWinRTGeneratedFilesDir)cswinrt.rsp</CsWinRTResponseFile>
<CsWinRTCommand>"$(CsWinRTExe)" %40"$(CsWinRTResponseFile)"</CsWinRTCommand>
<!-- %40 is an MSBuild escape code for the @ character;
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/msbuild/msbuild-special-characters?view=vs-2015&redirectedfrom=MSDN
-->
<CsWinRTCommand>"$(CsWinRTExe)" %40"$(CsWinRTResponseFile)"</CsWinRTCommand>
<CsWinRTWindowsMetadata Condition="'$(CsWinRTWindowsMetadata)' == ''">$(WindowsSDKVersion.TrimEnd('\'))</CsWinRTWindowsMetadata>
<CsWinRTWindowsMetadata Condition="'$(CsWinRTWindowsMetadata)' == ''">$(TargetPlatformVersion)</CsWinRTWindowsMetadata>
<CsWinRTWindowsMetadataInput Condition="'$(CsWinRTWindowsMetadata)' != ''">-input $(CsWinRTWindowsMetadata)</CsWinRTWindowsMetadataInput>
Expand Down Expand Up @@ -126,6 +129,75 @@ $(CsWinRTIncludeWinRTInterop)
</ItemGroup>
</Target>

<!-- For the IIDOptimizer to work, it needs to be given all the (reference) assemblies used during compilation
This target consolidates them based on an item group output by the CoreCompile target,
so they may be passed as an option to the IIDOptimizer in the target that invokes the tool -->
<Target Name="CsWinRTGenerateIIDOptimizerResponseFile" AfterTargets="Compile" BeforeTargets="CsWinRTInvokeGuidPatcher"
Condition="'$(CsWinRTIIDOptimizerOptOut)' != 'true'">

<PropertyGroup>
<!-- CsWinRTIIDOptimizerPath: If building in the CsWinRT Repo, then this is set already via Directory.Build.props -->
<CsWinRTIIDOptimizerPath Condition="'$(CsWinRTIIDOptimizerPath)' == ''">$(CsWinRTPath)build\tools\IIDOptimizer\</CsWinRTIIDOptimizerPath>
<!-- CsWinRTIIDOptimizerTargetAssembly: First argument to the IIDOptimizer.
We are using the output's .dll from the *obj* folder.
After linking, the output's .dll gets copied to the bin folder. These targets run before linking. -->
<CsWinRTIIDOptimizerTargetAssembly>@(BuiltProjectOutputGroupKeyOutput->'%(Identity)')</CsWinRTIIDOptimizerTargetAssembly>
<!-- IIDOptimizerInterimDir: Second argument to the IIDOptimizer.
The folder used by the IIDOptimizer to save output files -->
<IIDOptimizerInterimDir>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'IIDOptimizer'))</IIDOptimizerInterimDir>
<!-- GuidPatchTargetAssemblyReferences: third argument to the IIDOptimizer.
We use ReferencePathWithRefAssemblies as this is passed to Csc (C# Compile Task) for the TargetAssembly's References -->
<GuidPatchTargetAssemblyReferences>@(ReferencePathWithRefAssemblies->'--refs &#x0d;&#x0a; %(Identity)', '&#x0d;&#x0a;')</GuidPatchTargetAssemblyReferences>
<!-- GuidPatchParams: Used to write the response file (.rsp) when executing IIDOptimizer.
include the current dll, the folder to winrt.runtime, and the reference assemblies -->
<GuidPatchParams>
--target
$(CsWinRTIIDOptimizerTargetAssembly)
--outdir
$(IIDOptimizerInterimDir)
$(GuidPatchTargetAssemblyReferences)
</GuidPatchParams>
</PropertyGroup>

<MakeDir Directories="$(IIDOptimizerInterimDir)"/>

<PropertyGroup>
<CsWinRTIIDOptimizerResponseFile>$(IIDOptimizerInterimDir)cswinrt_iidoptimizer.rsp</CsWinRTIIDOptimizerResponseFile>
<CsWinRTIIDOptimizerCommand>"$(CsWinRTIIDOptimizerPath)IIDOptimizer.exe" %40"$(CsWinRTIIDOptimizerResponseFile)"</CsWinRTIIDOptimizerCommand>
</PropertyGroup>

<WriteLinesToFile File="$(CsWinRTIIDOptimizerResponseFile)" Lines="$(GuidPatchParams)" Overwrite="true" WriteOnlyWhenDifferent="true" />
</Target>

<!-- Run the IIDOptimizer on the projection .dll -->
<Target Name="CsWinRTInvokeGuidPatcher" AfterTargets="Compile" BeforeTargets="Link" DependsOnTargets="CsWinRTGenerateIIDOptimizerResponseFile"
Condition="'$(CsWinRTIIDOptimizerOptOut)' != 'true'">
<Message Text="$(CsWinRTIIDOptimizerCommand)" Importance="$(CsWinRTMessageImportance)" />
<Exec Command="$(CsWinRTIIDOptimizerCommand)" ConsoleToMsBuild="true" IgnoreExitCode="true">
<Output TaskParameter="ConsoleOutput" PropertyName="CsWinRTGuidPatchOutput" />
<Output TaskParameter="ExitCode" PropertyName="CsWinRTGuidPatchExitCode"/>
</Exec>
</Target>

<!-- When the IIDOptimizer succeeds, replace the input .dll with the patched version -->
<Target Name="CsWinRTReplaceForPatchedRuntime"
Condition="$(CsWinRTGuidPatchExitCode) == 0"
AfterTargets="CsWinRTInvokeGuidPatcher"
BeforeTargets="Link">

<ItemGroup>
<CsWinRTGuidPatchedFiles Include="$(IIDOptimizerInterimDir)$(AssemblyName).dll;$(IIDOptimizerInterimDir)$(AssemblyName).pdb" />
</ItemGroup>

<PropertyGroup>
<!-- Use the above .dll to find the directory we should copy to when we finish (usually "obj")-->
<CsWinRTIIDOptimizerOutputDir>$([System.IO.Directory]::GetParent($(CsWinRTIIDOptimizerTargetAssembly))) </CsWinRTIIDOptimizerOutputDir>
</PropertyGroup>

<!-- Replace the .dll in the output folder with the optimized version we just made -->
<Copy SourceFiles="@(CsWinRTGuidPatchedFiles)" DestinationFolder="$(CsWinRTIIDOptimizerOutputDir)" />
</Target>

<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Prerelease.targets" Condition="Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Prerelease.targets')"/>
<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Authoring.targets" Condition="'$(CsWinRTComponent)' == 'true'"/>

Expand Down
42 changes: 42 additions & 0 deletions nuget/NOTICE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
NOTICES AND INFORMATION
Do Not Translate or Localize

This software incorporates material from third parties.
Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
or you may send a check or money order for US $5.00, including the product name,
the open source component name, platform, and version number, to:

Source Code Compliance Team
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052
USA

Notwithstanding any other terms, you may reverse engineer this software to the extent
required to debug changes to any libraries licensed under the GNU Lesser General Public License.

---------------------------------------------------------

Mono.Cecil 0.11.4 - MIT

Copyright (c) 2008 - 2015 Jb Evain
Copyright (c) 2008 - 2011 Novell, Inc.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4 changes: 2 additions & 2 deletions src/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<UseWinmd Condition="'$(TargetFramework)' == 'netcoreapp3.1' And $(BenchmarkWinmdSupport) == true">true</UseWinmd>
<ApplicationManifest Condition="$(UseWinmd) == true">Benchmarks.manifest</ApplicationManifest>
<BenchmarkTargetFramework>$(TargetFramework)</BenchmarkTargetFramework>
<BenchmarkTargetFramework Condition="'$(BenchmarkTargetFramework)' == 'netcoreapp2.0'">netstandard2.0</BenchmarkTargetFramework>
<BenchmarkTargetFramework Condition="'$(BenchmarkTargetFramework)' != 'net5.0'">netstandard2.0</BenchmarkTargetFramework>
j0shuams marked this conversation as resolved.
Show resolved Hide resolved
<IsDotnetBuild Condition="'$(IsDotnetBuild)' == ''">false</IsDotnetBuild>
<LangVersion Condition="$(IsDotnetBuild) == true">9.0</LangVersion>
</PropertyGroup>
Expand All @@ -22,7 +22,7 @@
</ItemGroup>

<ItemGroup>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Windows\bin\x64\Release\$(BenchmarkTargetFramework)\Windows.dll"></Reference>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Windows\bin\x64\Release\$(BenchmarkTargetFramework)\Microsoft.Windows.SDK.NET.dll"></Reference>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Benchmark\bin\x64\Release\$(BenchmarkTargetFramework)\Benchmark.dll"></Reference>

<ProjectReference Include="..\Projections\Windows\Windows.csproj" Condition="$(UseWinmd) == false And $(IsDotnetBuild) == false" />
Expand Down
4 changes: 4 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<DefineConstants>$(DefineConstants);MANUAL_IUNKNOWN</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<CsWinRTIIDOptimizerPath>$(MSBuildThisFileDirectory)Perf\IIDOptimizer\bin\$(Configuration)\net5.0\</CsWinRTIIDOptimizerPath>
</PropertyGroup>

<PropertyGroup>
<VersionNumber Condition="'$(VersionNumber)'==''">0.0.0.0</VersionNumber>
<VersionString Condition="'$(VersionString)'==''">0.0.0-private.0</VersionString>
Expand Down
110 changes: 110 additions & 0 deletions src/Perf/IIDOptimizer/CecilExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Linq;

namespace GuidPatch
{
static class CecilExtensions
{
internal static Guid? ReadGuidFromAttribute(this TypeReference type, TypeReference guidAttributeType, AssemblyDefinition winrtRuntimeAssembly)
{
TypeDefinition def = type.Resolve();
var guidAttr = def.CustomAttributes.FirstOrDefault(attr => attr.AttributeType.Resolve() == guidAttributeType);
if (guidAttr is null)
{
TypeDefinition abiType = def.GetCswinrtAbiTypeDefinition(winrtRuntimeAssembly);
if (abiType is not null)
{
return abiType.ReadGuidFromAttribute(guidAttributeType, winrtRuntimeAssembly);
}
return null;
}
return new Guid((string)guidAttr.ConstructorArguments[0].Value);
}

internal static TypeDefinition GetCswinrtAbiTypeDefinition(this TypeReference type, AssemblyDefinition winrtRuntimeAssembly)
{
var resolvedType = type.Resolve();

return resolvedType.Module.GetType($"ABI.{resolvedType.FullName}") ??
winrtRuntimeAssembly.MainModule.GetType($"ABI.{resolvedType.FullName}");
}

internal static MethodDefinition CreateIIDDataGetter(TypeReference type, Guid iidValue, TypeDefinition dataBlockType, TypeDefinition parentType, TypeReference readOnlySpanOfByte, MethodReference readOnlySpanOfByteCtor)
{
var guidDataMethod = new MethodDefinition($"<IIDData>{type.FullName}", MethodAttributes.Assembly | MethodAttributes.Static, readOnlySpanOfByte);

WriteIIDDataGetterBody(guidDataMethod, type, iidValue, dataBlockType, parentType, readOnlySpanOfByteCtor);
return guidDataMethod;
}

internal static void WriteIIDDataGetterBody(MethodDefinition method, TypeReference type, Guid iidValue, TypeDefinition dataBlockType, TypeDefinition parentType, MethodReference readOnlySpanOfByteCtor)
{
var guidDataField = new FieldDefinition($"<IIDDataField>{type.FullName}", FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly | FieldAttributes.HasFieldRVA, dataBlockType)
{
InitialValue = iidValue.ToByteArray()
};
parentType.Fields.Add(guidDataField);

var ilProcessor = method.Body.GetILProcessor();
ilProcessor.Clear();
ilProcessor.Append(Instruction.Create(OpCodes.Ldsflda, guidDataField));
ilProcessor.Append(Instruction.Create(OpCodes.Ldc_I4, 16));
ilProcessor.Append(Instruction.Create(OpCodes.Newobj, readOnlySpanOfByteCtor));
ilProcessor.Append(Instruction.Create(OpCodes.Ret));
}

internal static TypeDefinition GetOrCreateDataBlockType(TypeDefinition parentType, int size)
{
if (size < 0 || size > ushort.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(size));
}

string typeName = $"__StaticDataBlock<>Size={size}";

var typeRef = new TypeReference(null, typeName, parentType.Module, parentType.Module)
{
DeclaringType = parentType
};

if (typeRef.Resolve() is TypeDefinition td)
{
return td;
}

td = new TypeDefinition(null, typeName, TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.NestedAssembly | TypeAttributes.SequentialLayout | TypeAttributes.AnsiClass, new TypeReference("System", "ValueType", parentType.Module, parentType.Module.TypeSystem.CoreLibrary))
{
PackingSize = 1,
ClassSize = size
};

parentType.NestedTypes.Add(td);

return td;
}

internal static TypeReference? FindTypeReference(ModuleDefinition module, string ns, string name, string basicAssemblyName, bool isValueType)
{
foreach (var asm in module.AssemblyReferences)
{
if (asm.Name == basicAssemblyName || asm.Name.StartsWith($"{basicAssemblyName},"))
{
TypeReference typeRef = new TypeReference(ns, name, module, asm, isValueType);
if (typeRef.Resolve() != null)
{
return module.ImportReference(typeRef);
}
break;
}
}
var resolved = module.AssemblyResolver.Resolve(new AssemblyNameReference(basicAssemblyName, default));
if (resolved is null)
{
return null;
}
return resolved.MainModule.Types.FirstOrDefault(t => t.Namespace == ns && t.Name == name);
}
}
}
Loading