Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed Jun 2, 2024
1 parent b82f705 commit 909961d
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//
/////////////////////////////////////////////////////////////////////////////////////

using System;
using chibicc.toolchain.Generating;
using chibicc.toolchain.Archiving;
using chibicc.toolchain.Parsing;
using chibicc.toolchain.Logging;
Expand Down
88 changes: 85 additions & 3 deletions chibild/chibild.core/Generating/AssemblyInputFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using chibicc.toolchain.Archiving;
using chibicc.toolchain.Internal;
using chibicc.toolchain.IO;

namespace chibild.Generating;

Expand Down Expand Up @@ -297,18 +303,74 @@ MethodReference ResolveOnFallbackModule(MethodDefinition md)

//////////////////////////////////////////////////////////////

private static string GetAssemblyHash(string assemblyPath)
{
using var fileStream = StreamUtilities.OpenStream(
assemblyPath, false);

using var alg = SHA1.Create();
return BitConverter.ToString(alg.ComputeHash(fileStream)).
Replace("-", string.Empty).
ToLowerInvariant();
}

private static bool IsValidCache(
TextReader tr,
string assemblyHash)
{
var header = tr.ReadLine()?.Split(':') ?? CommonUtilities.Empty<string>();
if (header.FirstOrDefault() is "hash" &&
header.ElementAt(1) is { } hash)
{
return assemblyHash == hash;
}

return false;
}

public static AssemblyInputFragment Load(
ILogger logger,
string baseInputPath,
string relativePath,
string cacheBasePath,
CachedAssemblyResolver assemblyResolver)
{
// TODO: native dll

logger.Information($"Loading assembly: {relativePath}");

var assemblyPath = Path.Combine(baseInputPath, relativePath);
var assemblyHash = GetAssemblyHash(assemblyPath);

var cacheFullPath = Path.GetFullPath(assemblyPath + ".symtab");

// Found cached file.
var cachePath = Utilities.GetCachedSymbolPath(
cacheBasePath, cacheFullPath);
if (File.Exists(cachePath))
{
// https://gist.github.com/kekyo/004e6970d9e442c96b672838a9e18a9d
try
{
using var cacheStream = StreamUtilities.OpenStream(
cachePath, false);
var tr = new StreamReader(cacheStream, Encoding.UTF8, true);

if (IsValidCache(tr, assemblyHash))
{
var symbols = ArchiverUtilities.EnumerateSymbolTable(tr, cachePath);

// TODO:
return new(symbols);

Check failure on line 362 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / linux

There is no argument given that corresponds to the required parameter 'relativePath' of 'AssemblyInputFragment.AssemblyInputFragment(string, string, AssemblyDefinition, Dictionary<string, TypeDefinition>, Dictionary<string, FieldDefinition>, Dictionary<string, MethodDefinition[]>)'

Check failure on line 362 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / linux

There is no argument given that corresponds to the required parameter 'relativePath' of 'AssemblyInputFragment.AssemblyInputFragment(string, string, AssemblyDefinition, Dictionary<string, TypeDefinition>, Dictionary<string, FieldDefinition>, Dictionary<string, MethodDefinition[]>)'

Check failure on line 362 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / windows

There is no argument given that corresponds to the required parameter 'relativePath' of 'AssemblyInputFragment.AssemblyInputFragment(string, string, AssemblyDefinition, Dictionary<string, TypeDefinition>, Dictionary<string, FieldDefinition>, Dictionary<string, MethodDefinition[]>)'

Check failure on line 362 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / windows

There is no argument given that corresponds to the required parameter 'relativePath' of 'AssemblyInputFragment.AssemblyInputFragment(string, string, AssemblyDefinition, Dictionary<string, TypeDefinition>, Dictionary<string, FieldDefinition>, Dictionary<string, MethodDefinition[]>)'
}
}
catch
{
}
}

// TODO: native dll

var assembly = assemblyResolver.ReadAssemblyFrom(
Path.Combine(baseInputPath, relativePath));
assemblyPath);

static IEnumerable<TypeDefinition> IterateTypesDescendants(TypeDefinition type)
{
Expand Down Expand Up @@ -403,6 +465,26 @@ static IEnumerable<TypeDefinition> IterateTypesDescendants(TypeDefinition type)
// Sorted descending longer parameters.
g => g.OrderByDescending(method => method.Parameters.Count).ToArray());

var newCachePath = cachePath + $"_{Guid.NewGuid():N}";
using (var cacheStream = StreamUtilities.OpenStream(
newCachePath, true))
{
var tw = new StreamWriter(cacheStream, Encoding.UTF8);
tw.WriteLine($"hash:{assemblyHash}");

ArchiverUtilities.WriteSymbolTable(tw, symbolLists);

Check failure on line 475 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / linux

The name 'symbolLists' does not exist in the current context

Check failure on line 475 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / linux

The name 'symbolLists' does not exist in the current context

Check failure on line 475 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / windows

The name 'symbolLists' does not exist in the current context

Check failure on line 475 in chibild/chibild.core/Generating/AssemblyInputFragment.cs

View workflow job for this annotation

GitHub Actions / windows

The name 'symbolLists' does not exist in the current context
}

try
{
File.Delete(cachePath);
File.Move(newCachePath, cachePath);
}
catch
{
File.Delete(newCachePath);
}

return new(
baseInputPath,
relativePath,
Expand Down
31 changes: 31 additions & 0 deletions chibild/chibild.core/Internal/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ internal enum chmodFlags

internal static class Utilities
{
private static readonly HashSet<string> invalidPathStrings = new()
{
":", "//", @"\\",
};

public const int EINTR = 4;

[DllImport("libc", SetLastError = true)]
Expand Down Expand Up @@ -180,4 +185,30 @@ public static void SafeCopy(string from, string to)
File.Delete(to2);
}
}

public static string GetCachedSymbolPath(
string cacheBasePath, string cacheFullPath)
{
var sb = new StringBuilder(cacheFullPath);

var ds = Path.DirectorySeparatorChar.ToString();
var last = sb.ToString();
while (true)
{
foreach (var invalidPathString in invalidPathStrings)
{
sb.Replace(invalidPathString, ds);
}

var current = sb.ToString();
if (current == last)
{
break;
}

last = current;
}

return Path.Combine(cacheBasePath, sb.ToString());
}
}
86 changes: 74 additions & 12 deletions toolchain.common/Archiving/ArchiverUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//
/////////////////////////////////////////////////////////////////////////////////////

using System;
using chibicc.toolchain.Generating;
using chibicc.toolchain.Internal;
using chibicc.toolchain.Parsing;
using chibicc.toolchain.Tokenizing;
Expand All @@ -32,11 +32,9 @@ private enum ObjectSymbolStates
Structure,
}

private static IEnumerable<Symbol> InternalEnumerateSymbolsFromObjectFile(
Stream objectFileStream)
private static IEnumerable<Symbol> InternalEnumerateSymbols(
TextReader tr)
{
var tr = new StreamReader(objectFileStream, Encoding.UTF8, true);

var state = ObjectSymbolStates.Idle;
string? currentDirective = null;
string? currentScope = null;
Expand Down Expand Up @@ -133,16 +131,17 @@ tokens[0] is (TokenTypes.Identity, _))
}

public static IEnumerable<Symbol> EnumerateSymbolsFromObjectFile(
Stream objectFileStream) =>
InternalEnumerateSymbolsFromObjectFile(objectFileStream).
Distinct();
Stream objectFileStream)
{
var tr = new StreamReader(objectFileStream, Encoding.UTF8, true);
return InternalEnumerateSymbols(tr).
Distinct();
}

public static void WriteSymbolTable(
Stream symbolTableStream,
TextWriter tw,
SymbolList[] symbolLists)
{
var tw = new StreamWriter(symbolTableStream, Encoding.UTF8);

foreach (var symbolList in symbolLists)
{
tw.WriteLine($".object {symbolList.ObjectName}");
Expand All @@ -155,7 +154,70 @@ public static void WriteSymbolTable(

tw.Flush();
}


public static void WriteSymbolTable(
Stream symbolTableStream,
SymbolList[] symbolLists)
{
var tw = new StreamWriter(symbolTableStream, Encoding.UTF8);
WriteSymbolTable(tw, symbolLists);
}

public static IEnumerable<SymbolList> EnumerateSymbolTable(
TextReader tr,
string symbolTableName)
{
Token? currentObjectName = null;
var symbols = new List<Symbol>();

foreach (var tokens in CilTokenizer.TokenizeAll("", symbolTableName, tr).
Where(tokens => tokens.Length >= 2))
{
switch (tokens[0])
{
case (TokenTypes.Directive, "object")
when tokens[1] is (TokenTypes.Identity, _):
if (currentObjectName is (_, var objectName))
{
yield return new(
objectName,
symbols.Distinct().ToArray());
}
currentObjectName = tokens[1];
symbols.Clear();
break;
// function public funcfoo
// global public varbar
// enumeration public enumbaz 3
// structure public structhoge 5
case (TokenTypes.Identity, var directive)
when tokens.Length >= 3 &&
tokens[1] is (TokenTypes.Identity, var scope) &&
CommonUtilities.TryParseEnum<Scopes>(scope, out _) &&
tokens[2] is (TokenTypes.Identity, var name):
if (tokens.Length >= 4 &&
tokens[3] is (TokenTypes.Identity, var mc) &&
int.TryParse(mc, NumberStyles.Integer, CultureInfo.InvariantCulture, out var memberCount) &&
memberCount >= 0)
{
symbols.Add(new(directive, scope, name, memberCount));
}
else
{
symbols.Add(new(directive, scope, name, null));
}
break;
}
}

if (currentObjectName is var (_, con2))
{
yield return new(
con2,
symbols.Distinct().ToArray());
}
}

public static IEnumerable<SymbolList> EnumerateSymbolTable(
string archiveFilePath)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using System;
using System.Linq;

namespace chibicc.toolchain.Archiving;
namespace chibicc.toolchain.Generating;

public readonly struct Symbol : IEquatable<Symbol>
{
Expand Down

0 comments on commit 909961d

Please sign in to comment.