diff --git a/chibias/chibias.core/Assembler.cs b/chibias/chibias.core/Assembler.cs index cae043e..89c0848 100644 --- a/chibias/chibias.core/Assembler.cs +++ b/chibias/chibias.core/Assembler.cs @@ -64,7 +64,7 @@ public bool Assemble( { // Convert source code to object file. using var outputStream = isDryrun ? - null : ObjectStreamUtilities.OpenObjectStream(outputTemporaryFilePath, true); + null : CompressionStreamUtilities.OpenStream(outputTemporaryFilePath, true); if (outputStream != null) { diff --git a/chibild/chibild.core/CilLinker.cs b/chibild/chibild.core/CilLinker.cs index d7b88a5..afdd292 100644 --- a/chibild/chibild.core/CilLinker.cs +++ b/chibild/chibild.core/CilLinker.cs @@ -108,7 +108,7 @@ private bool TryLoadInputReferences( $"Unable to find the object file: {relativePath}"); break; } - using (var fs = ObjectStreamUtilities.OpenObjectStream( + using (var fs = CompressionStreamUtilities.OpenStream( Path.Combine(baseInputPath, relativePath), false)) { var tr = new StreamReader(fs, Encoding.UTF8, true); diff --git a/chibild/chibild.core/Generating/ArchivedObjectInputFragment.cs b/chibild/chibild.core/Generating/ArchivedObjectInputFragment.cs index 1622bf3..14269ee 100644 --- a/chibild/chibild.core/Generating/ArchivedObjectInputFragment.cs +++ b/chibild/chibild.core/Generating/ArchivedObjectInputFragment.cs @@ -217,7 +217,9 @@ public override LoadObjectResults LoadObjectIfRequired( LoadObjectResults.CaughtError : LoadObjectResults.Loaded; } - return LoadObjectResults.Ignored; + + return this.requiredState == (int)RequiredStates.Loaded ? + LoadObjectResults.Loaded : LoadObjectResults.Ignored; } public static ArchivedObjectInputFragment[] Load( diff --git a/chibild/chibild.core/Generating/AssemblyInputFragment.cs b/chibild/chibild.core/Generating/AssemblyInputFragment.cs index 705affc..d228cac 100644 --- a/chibild/chibild.core/Generating/AssemblyInputFragment.cs +++ b/chibild/chibild.core/Generating/AssemblyInputFragment.cs @@ -205,6 +205,7 @@ public override LoadObjectResults LoadObjectIfRequired( this.PrepareToLoadAssembly(); return LoadObjectResults.Loaded; } + return this.requiredState == (int)RequiredStates.Loaded ? LoadObjectResults.Loaded : LoadObjectResults.Ignored; } @@ -411,35 +412,15 @@ private static string GetAssemblyPathHashedPath(string assemblyPath) path.Substring(2)); } - private static string GetAssemblyHash(string assemblyPath) - { - using var fileStream = StreamUtilities.OpenStream( - assemblyPath, false); - - using var alg = MD5.Create(); - return BitConverter.ToString(alg.ComputeHash(fileStream)). - Replace("-", string.Empty). - ToLowerInvariant(); - } - private static bool IsValidCache( TextReader tr, - string assemblyPath, - string assemblyHash) + string assemblyPath) { var header1 = tr.ReadLine()?.Split(' ') ?? CommonUtilities.Empty(); if (header1.FirstOrDefault() is ".path" && header1.ElementAt(1) is { } path) { - if (assemblyPath == path) - { - var header2 = tr.ReadLine()?.Split(' ') ?? CommonUtilities.Empty(); - if (header2.FirstOrDefault() is ".hash" && - header2.ElementAt(1) is { } hash) - { - return assemblyHash == hash; - } - } + return assemblyPath == path; } return false; @@ -456,7 +437,7 @@ public static AssemblyInputFragment Load( { var assemblyPath = Path.Combine(baseInputPath, relativePath); var assemblyHashedPath = GetAssemblyPathHashedPath(assemblyPath) + ".symtab"; - var assemblyHash = GetAssemblyHash(assemblyPath); + //var assemblyHash = GetAssemblyHash(assemblyPath); // Found cached file. var cachePath = cacheBasePath != null ? @@ -464,44 +445,49 @@ public static AssemblyInputFragment Load( null; if (cachePath != null) { - if (File.Exists(cachePath)) + try { - // https://gist.github.com/kekyo/004e6970d9e442c96b672838a9e18a9d - try + if (File.Exists(cachePath)) { - using var cacheStream = ObjectStreamUtilities.OpenObjectStream( - cachePath, false); - var tr = new StreamReader(cacheStream, Encoding.UTF8, true); + var assemblyDate = File.GetLastWriteTime(assemblyPath); + var cacheDate = File.GetLastWriteTime(cachePath); - if (IsValidCache(tr, assemblyPath, assemblyHash)) + if (cacheDate >= assemblyDate) { - var symbolLists = SymbolUtilities.EnumerateSymbolTable( - tr, - cachePath); + using var cacheStream = CompressionStreamUtilities.OpenStream( + cachePath, false); + var tr = new StreamReader(cacheStream, Encoding.UTF8, true); - var aggSymbols = SymbolAggregator.AggregateSymbolsFromSymbolTable( - logger, - symbolLists). - ToArray(); - - if (aggSymbols.SingleOrDefault() is { } aggSymbol && - aggSymbol.ObjectName == "symcache") + if (IsValidCache(tr, assemblyPath)) { - logger.Information($"Loading cached symbols: {relativePath}"); - logger.Trace($"Cached symbols: {cachePath}"); - - return new( - baseInputPath, - relativePath, - assemblyPath, - assemblyResolverFactory, - aggSymbol); + var symbolLists = SymbolUtilities.EnumerateSymbolTable( + tr, + cachePath); + + var aggSymbols = SymbolAggregator.AggregateSymbolsFromSymbolTable( + logger, + symbolLists). + ToArray(); + + if (aggSymbols.SingleOrDefault() is { } aggSymbol && + aggSymbol.ObjectName == "symcache") + { + logger.Information($"Loading cached symbols: {relativePath}"); + logger.Trace($"Cached symbols: {cachePath}"); + + return new( + baseInputPath, + relativePath, + assemblyPath, + assemblyResolverFactory, + aggSymbol); + } } } } - catch - { - } + } + catch + { } } @@ -546,12 +532,11 @@ public static AssemblyInputFragment Load( try { - using (var cacheStream = ObjectStreamUtilities.OpenObjectStream( + using (var cacheStream = CompressionStreamUtilities.OpenStream( newCachePath, true)) { var tw = new StreamWriter(cacheStream, Encoding.UTF8); tw.WriteLine($".path {assemblyPath}"); - tw.WriteLine($".hash {assemblyHash}"); SymbolUtilities.WriteSymbolTable(tw, new[] { symbolList }); } diff --git a/chibild/chibild.core/Generating/CodeGenerator.cs b/chibild/chibild.core/Generating/CodeGenerator.cs index 89987c5..54e014f 100644 --- a/chibild/chibild.core/Generating/CodeGenerator.cs +++ b/chibild/chibild.core/Generating/CodeGenerator.cs @@ -176,9 +176,11 @@ private void ConsumeArchivedObject( isLocationOriginSource)) { case LoadObjectResults.Loaded: - found = true; if (currentFragment is ArchivedObjectInputFragment afif) { + // This consume may cause another `InputFragment` to become `Required` state. + // Therefore, it is a `do-while` loop to check again. + found = true; this.ConsumeFragment(afif, inputFragments); } break; @@ -199,9 +201,11 @@ private void ConsumeArchivedObject( isLocationOriginSource)) { case LoadObjectResults.Loaded: - found = true; if (currentFragment is ArchivedObjectInputFragment afif) { + // This consume may cause another `InputFragment` to become `Required` state. + // Therefore, it is a `do-while` loop to check again. + found = true; this.ConsumeFragment(afif, inputFragments); } break; @@ -214,6 +218,7 @@ private void ConsumeArchivedObject( }); #endif } + // Repeat if at least one `ArchivedObjectInputFragment` is processed and there are no errors. while (found && !this.caughtError); } diff --git a/chibild/chibild.core/Generating/CodeGenerator_Emit.cs b/chibild/chibild.core/Generating/CodeGenerator_Emit.cs index d19ee04..d5de348 100644 --- a/chibild/chibild.core/Generating/CodeGenerator_Emit.cs +++ b/chibild/chibild.core/Generating/CodeGenerator_Emit.cs @@ -675,7 +675,7 @@ private bool TryLoadAndConsumeCAbiStartUpObjectIfRequired( return false; } - using var fs = ObjectStreamUtilities.OpenObjectStream( + using var fs = CompressionStreamUtilities.OpenStream( objectPath, false); diff --git a/chibild/chibild.core/LinkerOptions.cs b/chibild/chibild.core/LinkerOptions.cs index bfd70cf..b058ede 100644 --- a/chibild/chibild.core/LinkerOptions.cs +++ b/chibild/chibild.core/LinkerOptions.cs @@ -229,13 +229,15 @@ public sealed class LinkerOptions public string[] PrependExecutionSearchPaths = CommonUtilities.Empty(); - public string? CacheBasePath = + GetDefaultCacheBasePath(); + + public bool IsDryRun = false; + + public static string GetDefaultCacheBasePath() => Path.Combine( - CommonUtilities.GetHomePath(), + CommonUtilities.GetHomePath() ?? Environment.CurrentDirectory, ".cache", "chibild-cil", "symtab"); - - public bool IsDryRun = false; } diff --git a/toolchain.common/Generating/SymbolUtilities.cs b/toolchain.common/Generating/SymbolUtilities.cs index 388253d..6ef7593 100644 --- a/toolchain.common/Generating/SymbolUtilities.cs +++ b/toolchain.common/Generating/SymbolUtilities.cs @@ -52,9 +52,13 @@ public static IEnumerable EnumerateSymbolTable( Token? currentObjectName = null; var symbols = new List(); - foreach (var tokens in CilTokenizer.TokenizeAll("", symbolTableName, tr). - Where(tokens => tokens.Length >= 2)) + foreach (var tokens in CilTokenizer.TokenizeAll("", symbolTableName, tr)) { + if (tokens.Length < 2) + { + continue; + } + switch (tokens[0]) { // .object [objectName] diff --git a/toolchain.common/IO/ObjectStreamUtilities.cs b/toolchain.common/IO/CompressionStreamUtilities.cs similarity index 92% rename from toolchain.common/IO/ObjectStreamUtilities.cs rename to toolchain.common/IO/CompressionStreamUtilities.cs index 4e3341c..00c25c9 100644 --- a/toolchain.common/IO/ObjectStreamUtilities.cs +++ b/toolchain.common/IO/CompressionStreamUtilities.cs @@ -15,9 +15,9 @@ namespace chibicc.toolchain.IO; -public static class ObjectStreamUtilities +public static class CompressionStreamUtilities { - public static Stream OpenObjectStream( + public static Stream OpenStream( string objectFilePath, bool writable) { var s = StreamUtilities.OpenStream(objectFilePath, writable); @@ -34,7 +34,7 @@ public static Stream OpenObjectStream( } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] - public static Stream OpenEmbeddedObjectStream( + public static Stream OpenEmbeddedStream( string objectResourcePath, Assembly? assembly = null) { diff --git a/toolchain.common/Internal/CommonUtilities.cs b/toolchain.common/Internal/CommonUtilities.cs index 8164c94..0dd4c51 100644 --- a/toolchain.common/Internal/CommonUtilities.cs +++ b/toolchain.common/Internal/CommonUtilities.cs @@ -55,7 +55,7 @@ internal static class CommonUtilities public static readonly bool IsInWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; - public static string GetHomePath() + public static string? GetHomePath() { if (IsInWindows) { @@ -64,30 +64,28 @@ public static string GetHomePath() if (!string.IsNullOrWhiteSpace(homeDrive) && !string.IsNullOrWhiteSpace(homePath)) { - var path = Path.GetFullPath( + var path1 = Path.GetFullPath( $"{homeDrive}{homePath}". TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); - if (Directory.Exists(path)) + if (Directory.Exists(path1)) { - return path; + return path1; } } } - else + + if (Environment.GetEnvironmentVariable("HOME") is { } path2 && + !string.IsNullOrWhiteSpace(path2)) { - if (Environment.GetEnvironmentVariable("HOME") is { } path && - !string.IsNullOrWhiteSpace(path)) + path2 = Path.GetFullPath( + path2.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); + if (Directory.Exists(path2)) { - path = Path.GetFullPath( - path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); - if (Directory.Exists(path)) - { - return path; - } + return path2; } } - return Path.GetFullPath("."); + return null; } public static string GetDirectoryPath(string path) =>