Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed Jun 3, 2024
1 parent b82f705 commit b7ca41e
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 88 deletions.
15 changes: 8 additions & 7 deletions chibiar/chibiar.core/Archiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@
//
/////////////////////////////////////////////////////////////////////////////////////

using chibiar.Cli;
using chibicc.toolchain.Archiving;
using chibicc.toolchain.Generating;
using chibicc.toolchain.Internal;
using chibicc.toolchain.IO;
using chibicc.toolchain.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using chibiar.Cli;
using chibicc.toolchain.Archiving;
using chibicc.toolchain.Internal;
using chibicc.toolchain.IO;
using chibicc.toolchain.Logging;

namespace chibiar;

Expand Down Expand Up @@ -192,11 +193,11 @@ private static void AddSymbolTable(

using var outputStream = symbolTableEntry.Open();

ArchiverUtilities.WriteSymbolTable(outputStream, symbolLists);
SymbolUtilities.WriteSymbolTable(outputStream, symbolLists);
}
else
{
ArchiverUtilities.WriteSymbolTable(new MemoryStream(), symbolLists);
SymbolUtilities.WriteSymbolTable(new MemoryStream(), symbolLists);
}
}

Expand Down
4 changes: 4 additions & 0 deletions chibild/chibild.core/CilLinker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ private bool TryLoadInputReferences(
string[] assemblyReferenceBasePaths,
InputReference[] inputReferences,
bool isLocationOriginSource,
string cacheBasePath,
out InputFragment[] fragments)
{
// Load input files in parallelism.
Expand Down Expand Up @@ -157,6 +158,7 @@ when Path.GetExtension(relativePath) == ".a":
this.logger,
baseInputPath,
relativePath,
cacheBasePath,
// Create this assembly specific resolver,
// because shared resolver can not resolve on multi-threaded context.
// At the cost of having to load it again later in the primary assembly resolver.
Expand Down Expand Up @@ -194,6 +196,7 @@ when Path.GetExtension(relativePath) == ".a":
this.logger,
foundEntry.basePath,
foundEntry.fileName,
cacheBasePath,
// Create this assembly specific resolver,
// because shared resolver can not resolve on multi-threaded context.
// At the cost of having to load it again later in the primary assembly resolver.
Expand Down Expand Up @@ -327,6 +330,7 @@ injectToAssemblyPath is { } injectPath ?
assemblyReferenceBasePaths,
totalInputReferences,
produceDebuggingInformation,
options.CacheBasePath,
out var loadedFragments))
{
return false;
Expand Down
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
118 changes: 111 additions & 7 deletions chibild/chibild.core/Generating/AssemblyInputFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
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.Generating;
using chibicc.toolchain.Internal;
using chibicc.toolchain.IO;

namespace chibild.Generating;

Expand Down Expand Up @@ -166,7 +173,7 @@ public override bool ContainsFunctionAndSchedule(

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

private ModuleDefinition ResovleOnFallbackModule(
private ModuleDefinition ResolveOnFallbackModule(
ModuleDefinition fallbackModule,
MemberReference mr)
{
Expand Down Expand Up @@ -201,7 +208,7 @@ public override bool TryGetType(
}

// Resolve on fallback assembly resolver.
var exactModule = this.ResovleOnFallbackModule(fallbackModule, td);
var exactModule = this.ResolveOnFallbackModule(fallbackModule, td);
if (exactModule.GetType(td.FullName) is { } ftd)
{
this.types[type.TypeIdentity] = ftd;
Expand Down Expand Up @@ -233,7 +240,7 @@ public override bool TryGetField(
}

// Resolve on fallback assembly resolver.
var exactModule = this.ResovleOnFallbackModule(fallbackModule, fd);
var exactModule = this.ResolveOnFallbackModule(fallbackModule, fd);
if (exactModule.GetType(fd.DeclaringType.FullName) is { } ftd &&
ftd.Fields.FirstOrDefault(f => f.Name == fd.Name) is { } ffd)
{
Expand Down Expand Up @@ -267,7 +274,7 @@ public override bool TryGetMethod(
// Resolve on fallback assembly resolver.
MethodReference ResolveOnFallbackModule(MethodDefinition md)
{
var exactModule = this.ResovleOnFallbackModule(fallbackModule, md);
var exactModule = this.ResolveOnFallbackModule(fallbackModule, md);
if (exactModule.GetType(md.DeclaringType.FullName) is { } ftd &&
ftd.Methods.FirstOrDefault(m => CecilUtilities.Equals(m, md)) is { } fmd)
{
Expand Down Expand Up @@ -297,18 +304,94 @@ MethodReference ResolveOnFallbackModule(MethodDefinition md)

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

private static string GetAssemblyPathHashedPath(string assemblyPath)
{
using var alg = SHA1.Create();
var path = BitConverter.ToString(alg.ComputeHash(Encoding.UTF8.GetBytes(assemblyPath))).
Replace("-", string.Empty).
ToLowerInvariant();

return Path.Combine(
path.Substring(0, 2),
path.Substring(2, 2),
path.Substring(4));
}

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 assemblyPath,
string assemblyHash)
{
var header1 = tr.ReadLine()?.Split(' ') ?? CommonUtilities.Empty<string>();
if (header1.FirstOrDefault() is ".path" &&
header1.ElementAt(1) is { } path)
{
if (assemblyPath == path)
{
var header2 = tr.ReadLine()?.Split(' ') ?? CommonUtilities.Empty<string>();
if (header2.FirstOrDefault() is ".hash" &&
header2.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 assemblyHashedPath = GetAssemblyPathHashedPath(assemblyPath) + ".symtab";
var assemblyHash = GetAssemblyHash(assemblyPath);

// Found cached file.
var cachePath = Path.Combine(cacheBasePath, assemblyHashedPath);
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, assemblyPath, assemblyHash))
{
var symbolLists = SymbolUtilities.EnumerateSymbolTable(tr, cachePath);

// TODO:
return new(symbols);

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

View workflow job for this annotation

GitHub Actions / linux

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

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

View workflow job for this annotation

GitHub Actions / linux

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

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

View workflow job for this annotation

GitHub Actions / linux

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

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

View workflow job for this annotation

GitHub Actions / linux

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

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

View workflow job for this annotation

GitHub Actions / linux

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

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

View workflow job for this annotation

GitHub Actions / windows

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

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

View workflow job for this annotation

GitHub Actions / windows

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

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

View workflow job for this annotation

GitHub Actions / windows

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

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

View workflow job for this annotation

GitHub Actions / windows

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

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

View workflow job for this annotation

GitHub Actions / windows

The name 'symbols' does not exist in the current context
}
}
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 +486,27 @@ 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($".path {assemblyPath}");
tw.WriteLine($".hash {assemblyHash}");

SymbolUtilities.WriteSymbolTable(tw, symbolLists);

Check failure on line 497 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 497 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 497 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 497 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 497 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 497 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 497 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 497 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 497 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 497 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
5 changes: 5 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
7 changes: 7 additions & 0 deletions chibild/chibild.core/LinkerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,12 @@ public sealed class LinkerOptions
public string[] PrependExecutionSearchPaths =
CommonUtilities.Empty<string>();

public string CacheBasePath =
Path.Combine(
Environment.GetEnvironmentVariable("HOME") is { } homePath ? homePath : Environment.CurrentDirectory,
".cache",
"chibild-cil",
"symtab");

public bool IsDryRun = false;
}
82 changes: 10 additions & 72 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,27 +131,11 @@ tokens[0] is (TokenTypes.Identity, _))
}

public static IEnumerable<Symbol> EnumerateSymbolsFromObjectFile(
Stream objectFileStream) =>
InternalEnumerateSymbolsFromObjectFile(objectFileStream).
Distinct();

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

foreach (var symbolList in symbolLists)
{
tw.WriteLine($".object {symbolList.ObjectName}");

foreach (var symbol in symbolList.Symbols.Distinct())
{
tw.WriteLine($" {symbol.Directive} {symbol.Scope} {symbol.Name}{(symbol.MemberCount is { } mc ? $" {mc}" : "")}");
}
}

tw.Flush();
var tr = new StreamReader(objectFileStream, Encoding.UTF8, true);
return InternalEnumerateSymbols(tr).
Distinct();
}

public static IEnumerable<SymbolList> EnumerateSymbolTable(
Expand All @@ -169,54 +151,10 @@ public static IEnumerable<SymbolList> EnumerateSymbolTable(
using var stream = entry.Open();
var tr = new StreamReader(stream, Encoding.UTF8, true);

Token? currentObjectName = null;
var symbols = new List<Symbol>();

foreach (var tokens in CilTokenizer.TokenizeAll("", SymbolTableFileName, 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))
foreach (var symbolList in
SymbolUtilities.EnumerateSymbolTable(tr, SymbolTableFileName))
{
yield return new(
con2,
symbols.Distinct().ToArray());
yield return symbolList;
}
}
}
Expand Down
Loading

0 comments on commit b7ca41e

Please sign in to comment.