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);
        }