bool GenerateDebugFiles(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, ApplicationConfigTaskState appConfState) { var modules = new Dictionary <string, ModuleDebugData> (StringComparer.Ordinal); int maxModuleFileNameWidth = 0; int maxModuleNameWidth = 0; var javaDuplicates = new Dictionary <string, List <TypeMapDebugEntry> > (StringComparer.Ordinal); foreach (TypeDefinition td in javaTypes) { UpdateApplicationConfig(td, appConfState); string moduleName = td.Module.Assembly.Name.Name; ModuleDebugData module; if (!modules.TryGetValue(moduleName, out module)) { string outputFileName = $"{moduleName}{TypemapExtension}"; module = new ModuleDebugData { EntryCount = 0, JavaNameWidth = 0, ManagedNameWidth = 0, JavaToManagedMap = new List <TypeMapDebugEntry> (), ManagedToJavaMap = new List <TypeMapDebugEntry> (), OutputFilePath = Path.Combine(outputDirectory, outputFileName), ModuleName = moduleName, ModuleNameBytes = outputEncoding.GetBytes(moduleName), }; if (module.ModuleNameBytes.Length > maxModuleNameWidth) { maxModuleNameWidth = module.ModuleNameBytes.Length; } if (outputFileName.Length > maxModuleFileNameWidth) { maxModuleFileNameWidth = outputFileName.Length; } modules.Add(moduleName, module); } TypeMapDebugEntry entry = GetDebugEntry(td); HandleDebugDuplicates(javaDuplicates, entry, td, cache); if (entry.JavaName.Length > module.JavaNameWidth) { module.JavaNameWidth = (uint)entry.JavaName.Length + 1; } if (entry.ManagedName.Length > module.ManagedNameWidth) { module.ManagedNameWidth = (uint)entry.ManagedName.Length + 1; } module.JavaToManagedMap.Add(entry); module.ManagedToJavaMap.Add(entry); } SyncDebugDuplicates(javaDuplicates); foreach (ModuleDebugData module in modules.Values) { PrepareDebugMaps(module); } string typeMapIndexPath = Path.Combine(outputDirectory, "typemap.index"); using (var indexWriter = MemoryStreamPool.Shared.CreateBinaryWriter()) { OutputModules(modules, indexWriter, maxModuleFileNameWidth + 1); indexWriter.Flush(); Files.CopyIfStreamChanged(indexWriter.BaseStream, typeMapIndexPath); } GeneratedBinaryTypeMaps.Add(typeMapIndexPath); GenerateNativeAssembly( (NativeAssemblerTargetProvider asmTargetProvider, bool sharedBitsWritten, bool sharedIncludeUsesAbiPrefix) => { return(new TypeMappingDebugNativeAssemblyGenerator(asmTargetProvider, new ModuleDebugData(), outputDirectory, sharedBitsWritten)); } ); return(true); }
bool GenerateDebug(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, bool generateNativeAssembly, ApplicationConfigTaskState appConfState) { if (generateNativeAssembly) { return(GenerateDebugNativeAssembly(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, cache, outputDirectory, appConfState)); } return(GenerateDebugFiles(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, cache, outputDirectory, appConfState)); }
bool GenerateRelease(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, string outputDirectory, ApplicationConfigTaskState appConfState) { int assemblyId = 0; int maxJavaNameLength = 0; int maxModuleFileNameLength = 0; var knownAssemblies = new Dictionary <string, int> (StringComparer.Ordinal); var tempModules = new Dictionary <byte[], ModuleReleaseData> (); Dictionary <AssemblyDefinition, int> moduleCounter = null; var mvidCache = new Dictionary <Guid, byte[]> (); foreach (TypeDefinition td in javaTypes) { UpdateApplicationConfig(td, appConfState); string assemblyName = td.Module.Assembly.FullName; if (!knownAssemblies.ContainsKey(assemblyName)) { assemblyId++; knownAssemblies.Add(assemblyName, assemblyId); } // We must NOT use Guid here! The reason is that Guid sort order is different than its corresponding // byte array representation and on the runtime we need the latter in order to be able to binary search // through the module array. byte[] moduleUUID; if (!mvidCache.TryGetValue(td.Module.Mvid, out moduleUUID)) { moduleUUID = td.Module.Mvid.ToByteArray(); mvidCache.Add(td.Module.Mvid, moduleUUID); } ModuleReleaseData moduleData; if (!tempModules.TryGetValue(moduleUUID, out moduleData)) { if (moduleCounter == null) { moduleCounter = new Dictionary <AssemblyDefinition, int> (); } moduleData = new ModuleReleaseData { Mvid = td.Module.Mvid, MvidBytes = moduleUUID, Assembly = td.Module.Assembly, AssemblyName = td.Module.Assembly.Name.Name, TypesScratch = new Dictionary <string, TypeMapReleaseEntry> (StringComparer.Ordinal), DuplicateTypes = new Dictionary <uint, TypeMapReleaseEntry> (), }; tempModules.Add(moduleUUID, moduleData); } string javaName = Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager.ToJniName(td); var entry = new TypeMapReleaseEntry { JavaName = javaName, JavaNameLength = outputEncoding.GetByteCount(javaName), ManagedTypeName = td.FullName, Token = td.MetadataToken.ToUInt32(), AssemblyNameIndex = knownAssemblies [assemblyName] }; if (entry.JavaNameLength > maxJavaNameLength) { maxJavaNameLength = entry.JavaNameLength; } if (moduleData.TypesScratch.ContainsKey(entry.JavaName)) { // This is disabled because it costs a lot of time (around 150ms per standard XF Integration app // build) and has no value for the end user. The message is left here because it may be useful to us // in our devloop at some point. //logger ($"Warning: duplicate Java type name '{entry.JavaName}' in assembly '{moduleData.AssemblyName}' (new token: {entry.Token})."); moduleData.DuplicateTypes.Add(entry.Token, entry); } else { moduleData.TypesScratch.Add(entry.JavaName, entry); } } var modules = tempModules.Values.ToArray(); Array.Sort(modules, new ModuleUUIDArrayComparer()); var typeMapEntryComparer = new TypeMapEntryArrayComparer(); foreach (ModuleReleaseData module in modules) { if (module.TypesScratch.Count == 0) { module.Types = new TypeMapReleaseEntry[0]; continue; } module.Types = module.TypesScratch.Values.ToArray(); Array.Sort(module.Types, typeMapEntryComparer); } NativeTypeMappingData data; data = new NativeTypeMappingData(logger, modules, maxJavaNameLength + 1); GenerateNativeAssembly( (NativeAssemblerTargetProvider asmTargetProvider, bool sharedBitsWritten, bool sharedIncludeUsesAbiPrefix) => { return(new TypeMappingReleaseNativeAssemblyGenerator(asmTargetProvider, data, outputDirectory, sharedBitsWritten, sharedIncludeUsesAbiPrefix)); } ); return(true); }
public bool Generate(bool debugBuild, bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, TypeDefinitionCache cache, string outputDirectory, bool generateNativeAssembly, out ApplicationConfigTaskState appConfState) { if (String.IsNullOrEmpty(outputDirectory)) { throw new ArgumentException("must not be null or empty", nameof(outputDirectory)); } if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } appConfState = new ApplicationConfigTaskState { JniAddNativeMethodRegistrationAttributePresent = skipJniAddNativeMethodRegistrationAttributeScan }; string typemapsOutputDirectory = Path.Combine(outputDirectory, "typemaps"); if (debugBuild) { return(GenerateDebug(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, cache, typemapsOutputDirectory, generateNativeAssembly, appConfState)); } return(GenerateRelease(skipJniAddNativeMethodRegistrationAttributeScan, javaTypes, typemapsOutputDirectory, appConfState)); }
bool GenerateDebugNativeAssembly(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, string outputDirectory, ApplicationConfigTaskState appConfState) { var javaToManaged = new List <TypeMapDebugEntry> (); var managedToJava = new List <TypeMapDebugEntry> (); foreach (TypeDefinition td in javaTypes) { UpdateApplicationConfig(td, appConfState); TypeMapDebugEntry entry = GetDebugEntry(td); javaToManaged.Add(entry); managedToJava.Add(entry); } var data = new ModuleDebugData { EntryCount = (uint)javaToManaged.Count, JavaToManagedMap = javaToManaged, ManagedToJavaMap = managedToJava, }; PrepareDebugMaps(data); GenerateNativeAssembly( (NativeAssemblerTargetProvider asmTargetProvider, bool sharedBitsWritten, bool sharedIncludeUsesAbiPrefix) => { return(new TypeMappingDebugNativeAssemblyGenerator(asmTargetProvider, data, outputDirectory, sharedBitsWritten, sharedIncludeUsesAbiPrefix)); } ); return(true); }