11using System ;
2+ using System . Collections . Generic ;
23using System . IO ;
34using System . Security . Cryptography ;
45using System . Text ;
@@ -7,6 +8,8 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
78
89static class MetadataHelper
910{
11+ static readonly Guid GeneratorModuleVersionId = typeof ( TypeMapAssemblyGenerator ) . Module . ModuleVersionId ;
12+
1013 /// <summary>
1114 /// Produces a deterministic MVID by hashing the module name together with content-dependent data.
1215 /// Assemblies with the same name but different content will have different MVIDs.
@@ -66,6 +69,99 @@ public static byte [] ComputeContentFingerprint (TypeMapAssemblyData data)
6669 return sha . ComputeHash ( stream . GetBuffer ( ) , 0 , checked ( ( int ) stream . Length ) ) ;
6770 }
6871
72+ /// <summary>
73+ /// Computes a fingerprint of every input that affects a generated per-assembly typemap.
74+ /// Unlike <see cref="ComputeContentFingerprint"/>, this is an incremental-build contract,
75+ /// so it includes the generator binary identity and all model fields consumed by the emitter.
76+ /// </summary>
77+ public static byte [ ] ComputeIncrementalFingerprint ( TypeMapAssemblyData data , Version systemRuntimeVersion , bool useSharedTypemapUniverse )
78+ {
79+ using var sha = SHA256 . Create ( ) ;
80+ using var stream = new MemoryStream ( ) ;
81+ using var writer = new BinaryWriter ( stream , Encoding . UTF8 ) ;
82+ writer . Write ( GeneratorModuleVersionId . ToByteArray ( ) ) ;
83+ writer . Write ( systemRuntimeVersion . ToString ( ) ) ;
84+ writer . Write ( useSharedTypemapUniverse ) ;
85+ writer . Write ( data . AssemblyName ) ;
86+ writer . Write ( data . ModuleName ) ;
87+ writer . Write ( data . Entries . Count ) ;
88+ foreach ( var entry in data . Entries ) {
89+ writer . Write ( entry . MapKey ) ;
90+ writer . Write ( entry . ProxyTypeReference ) ;
91+ writer . WriteOptionalString ( entry . TargetTypeReference ) ;
92+ }
93+ writer . Write ( data . ProxyTypes . Count ) ;
94+ foreach ( var proxy in data . ProxyTypes ) {
95+ writer . Write ( proxy . TypeName ) ;
96+ writer . Write ( proxy . JniName ) ;
97+ writer . Write ( proxy . Namespace ) ;
98+ writer . WriteTypeRef ( proxy . TargetType ) ;
99+ writer . WriteOptionalTypeRef ( proxy . InvokerType ) ;
100+ writer . Write ( proxy . InvokerActivationCtorStyle . HasValue ) ;
101+ if ( proxy . InvokerActivationCtorStyle . HasValue ) {
102+ writer . Write ( ( byte ) proxy . InvokerActivationCtorStyle . Value ) ;
103+ }
104+ writer . WriteOptionalActivationCtor ( proxy . ActivationCtor ) ;
105+ writer . Write ( proxy . IsGenericDefinition ) ;
106+ writer . Write ( proxy . CannotRegisterInStaticConstructor ) ;
107+ writer . Write ( proxy . IsAcw ) ;
108+ writer . Write ( proxy . UcoMethods . Count ) ;
109+ foreach ( var method in proxy . UcoMethods ) {
110+ writer . WriteUcoMethod ( method ) ;
111+ }
112+ writer . Write ( proxy . UcoConstructors . Count ) ;
113+ foreach ( var constructor in proxy . UcoConstructors ) {
114+ writer . WriteUcoConstructor ( constructor ) ;
115+ }
116+ writer . Write ( proxy . NativeRegistrations . Count ) ;
117+ foreach ( var registration in proxy . NativeRegistrations ) {
118+ writer . WriteNativeRegistration ( registration ) ;
119+ }
120+ }
121+ writer . Write ( data . Associations . Count ) ;
122+ foreach ( var assoc in data . Associations ) {
123+ writer . Write ( assoc . SourceTypeReference ) ;
124+ writer . Write ( assoc . AliasProxyTypeReference ) ;
125+ }
126+ writer . Write ( data . AliasHolders . Count ) ;
127+ foreach ( var holder in data . AliasHolders ) {
128+ writer . Write ( holder . TypeName ) ;
129+ writer . Write ( holder . Namespace ) ;
130+ writer . Write ( holder . AliasKeys . Count ) ;
131+ foreach ( var aliasKey in holder . AliasKeys ) {
132+ writer . Write ( aliasKey ) ;
133+ }
134+ }
135+ writer . Write ( data . IgnoresAccessChecksTo . Count ) ;
136+ foreach ( var assemblyName in data . IgnoresAccessChecksTo ) {
137+ writer . Write ( assemblyName ) ;
138+ }
139+ writer . Flush ( ) ;
140+ return sha . ComputeHash ( stream . GetBuffer ( ) , 0 , checked ( ( int ) stream . Length ) ) ;
141+ }
142+
143+ /// <summary>
144+ /// Computes a fingerprint of every input that affects the root typemap assembly.
145+ /// </summary>
146+ public static byte [ ] ComputeRootIncrementalFingerprint (
147+ IReadOnlyList < string > perAssemblyTypeMapNames ,
148+ Version systemRuntimeVersion ,
149+ bool useSharedTypemapUniverse )
150+ {
151+ using var sha = SHA256 . Create ( ) ;
152+ using var stream = new MemoryStream ( ) ;
153+ using var writer = new BinaryWriter ( stream , Encoding . UTF8 ) ;
154+ writer . Write ( GeneratorModuleVersionId . ToByteArray ( ) ) ;
155+ writer . Write ( systemRuntimeVersion . ToString ( ) ) ;
156+ writer . Write ( useSharedTypemapUniverse ) ;
157+ writer . Write ( perAssemblyTypeMapNames . Count ) ;
158+ foreach ( var assemblyName in perAssemblyTypeMapNames ) {
159+ writer . Write ( assemblyName ) ;
160+ }
161+ writer . Flush ( ) ;
162+ return sha . ComputeHash ( stream . GetBuffer ( ) , 0 , checked ( ( int ) stream . Length ) ) ;
163+ }
164+
69165 static void WriteTypeRef ( this BinaryWriter writer , TypeRefData type )
70166 {
71167 writer . Write ( type . ManagedTypeName ) ;
@@ -78,15 +174,55 @@ static void WriteTypeRef (this BinaryWriter writer, TypeRefData type)
78174 }
79175 }
80176
177+ static void WriteOptionalTypeRef ( this BinaryWriter writer , TypeRefData ? type )
178+ {
179+ writer . Write ( type is not null ) ;
180+ if ( type is not null ) {
181+ writer . WriteTypeRef ( type ) ;
182+ }
183+ }
184+
185+ static void WriteOptionalString ( this BinaryWriter writer , string ? value )
186+ {
187+ writer . Write ( value is not null ) ;
188+ if ( value is not null ) {
189+ writer . Write ( value ) ;
190+ }
191+ }
192+
193+ static void WriteOptionalActivationCtor ( this BinaryWriter writer , ActivationCtorData ? constructor )
194+ {
195+ writer . Write ( constructor is not null ) ;
196+ if ( constructor is not null ) {
197+ writer . WriteTypeRef ( constructor . DeclaringType ) ;
198+ writer . Write ( constructor . IsOnLeafType ) ;
199+ writer . Write ( ( byte ) constructor . Style ) ;
200+ }
201+ }
202+
81203 static void WriteUcoMethod ( this BinaryWriter writer , UcoMethodData method )
82204 {
83205 writer . Write ( method . WrapperName ) ;
84206 writer . Write ( method . CallbackMethodName ) ;
85207 writer . WriteTypeRef ( method . CallbackType ) ;
86208 writer . Write ( method . JniSignature ) ;
209+ writer . WriteOptionalStrings ( method . CallbackParameterTypeNames ) ;
210+ writer . WriteOptionalString ( method . CallbackReturnTypeName ) ;
87211 writer . WriteExportMethodDispatch ( method . ExportMethodDispatch ) ;
88212 }
89213
214+ static void WriteOptionalStrings ( this BinaryWriter writer , IReadOnlyList < string > ? values )
215+ {
216+ writer . Write ( values is not null ) ;
217+ if ( values is null ) {
218+ return ;
219+ }
220+ writer . Write ( values . Count ) ;
221+ foreach ( var value in values ) {
222+ writer . Write ( value ) ;
223+ }
224+ }
225+
90226 static void WriteExportMethodDispatch ( this BinaryWriter writer , ExportMethodDispatchData ? dispatch )
91227 {
92228 writer . Write ( dispatch is not null ) ;
0 commit comments