protected SubroutineSymbol( SourceFileSymbol declaringSourceFile, string name, SubroutineDeclaration declaration) : base(name) { DeclaringSourceFile = declaringSourceFile; Declaration = declaration; }
public NsxModuleBuilder(Compilation compilation, SourceFileSymbol sourceFile) { Compilation = compilation; SourceFile = sourceFile; Diagnostics = new DiagnosticBuilder(); _stringHeap = new TokenMap <string>(512); _subroutines = new TokenMap <SubroutineSymbol>(sourceFile.SubroutineCount); ConstructSubroutineMap(sourceFile); _externalSourceFiles = new TokenMap <SourceFileSymbol>(); }
private void ConstructSubroutineMap(SourceFileSymbol sourceFile) { foreach (ChapterSymbol chapter in sourceFile.Chapters) { _subroutines.GetOrAddToken(chapter); } foreach (SceneSymbol scene in sourceFile.Scenes) { _subroutines.GetOrAddToken(scene); } foreach (FunctionSymbol function in sourceFile.Functions) { _subroutines.GetOrAddToken(function); } }
public SourceModuleSymbol(Compilation compilation, ImmutableArray <SyntaxTree> syntaxTrees) { Debug.Assert(syntaxTrees.Length > 0); Compilation = compilation; RootSourceFile = MakeSourceFileSymbol(syntaxTrees[0]); if (syntaxTrees.Length > 1) { var builder = ImmutableArray.CreateBuilder <SourceFileSymbol>(syntaxTrees.Length - 1); for (int i = 1; i < syntaxTrees.Length; i++) { SourceFileSymbol sourceFile = MakeSourceFileSymbol(syntaxTrees[i]); builder.Add(sourceFile); } ReferencedSourceFiles = builder.ToImmutable(); } else { ReferencedSourceFiles = ImmutableArray <SourceFileSymbol> .Empty; } }
public static void WriteModule(NsxModuleBuilder builder) { SourceFileSymbol sourceFile = builder.SourceFile; Compilation compilation = builder.Compilation; ReadOnlySpan <SubroutineSymbol> subroutines = builder.Subroutines; // Compile subroutines using var codeBuffer = PooledBuffer <byte> .Allocate(64 * 1024); var codeWriter = new BufferWriter(codeBuffer); var subroutineOffsets = new List <int>(subroutines.Length); CompileSubroutines( builder, sourceFile.Chapters.As <SubroutineSymbol>(), ref codeWriter, subroutineOffsets ); CompileSubroutines( builder, sourceFile.Scenes.As <SubroutineSymbol>(), ref codeWriter, subroutineOffsets ); CompileSubroutines( builder, sourceFile.Functions.As <SubroutineSymbol>(), ref codeWriter, subroutineOffsets ); codeWriter.WriteBytes(NsxConstants.TableEndMarker); ReadOnlySpan <string> stringHeap = builder.StringHeap; const int subTableOffset = NsxConstants.NsxHeaderSize; int subTableSize = NsxConstants.TableHeaderSize + 6 + subroutines.Length * sizeof(int); int stringTableSize = NsxConstants.TableHeaderSize + 6 + stringHeap.Length * sizeof(int); // Build the runtime information table (RTI) int rtiTableOffset = NsxConstants.NsxHeaderSize + subTableSize; using var rtiBuffer = PooledBuffer <byte> .Allocate(8 * 1024); var rtiWriter = new BufferWriter(rtiBuffer); uint rtiOffsetBlockSize = sourceFile.SubroutineCount * sizeof(ushort); using var rtiEntryOffsets = PooledBuffer <byte> .Allocate(rtiOffsetBlockSize); var rtiOffsetWriter = new BufferWriter(rtiEntryOffsets); WriteRuntimeInformation( sourceFile.Chapters.As <SubroutineSymbol>(), ref rtiWriter, ref rtiOffsetWriter ); WriteRuntimeInformation( sourceFile.Scenes.As <SubroutineSymbol>(), ref rtiWriter, ref rtiOffsetWriter ); WriteRuntimeInformation( sourceFile.Functions.As <SubroutineSymbol>(), ref rtiWriter, ref rtiOffsetWriter ); rtiWriter.WriteBytes(NsxConstants.TableEndMarker); int rtiSize = NsxConstants.TableHeaderSize + rtiOffsetWriter.Position + rtiWriter.Position; Span <byte> rtiHeader = stackalloc byte[NsxConstants.TableHeaderSize]; var rtiHeaderWriter = new BufferWriter(rtiHeader); rtiHeaderWriter.WriteBytes(NsxConstants.RtiTableMarker); rtiHeaderWriter.WriteUInt16LE((ushort)(rtiSize - NsxConstants.TableHeaderSize)); int impTableOffset = rtiTableOffset + rtiSize; // Build the import table ReadOnlySpan <SourceFileSymbol> imports = builder.Imports; using var importTable = PooledBuffer <byte> .Allocate(2048); var impTableWriter = new BufferWriter(importTable); impTableWriter.WriteUInt16LE((ushort)imports.Length); for (int i = 0; i < imports.Length; i++) { impTableWriter.WriteLengthPrefixedUtf8String(imports[i].Name); } impTableWriter.WriteBytes(NsxConstants.TableEndMarker); Span <byte> impHeader = stackalloc byte[NsxConstants.TableHeaderSize]; var impHeaderWriter = new BufferWriter(impHeader); impHeaderWriter.WriteBytes(NsxConstants.ImportTableMarker); impHeaderWriter.WriteUInt16LE((ushort)impTableWriter.Position); int impTableSize = impHeaderWriter.Position + impTableWriter.Position; int stringTableOffset = impTableOffset + impTableSize; int codeStart = stringTableOffset + stringTableSize; // Build the subroutine offset table (SUB) using var subTable = PooledBuffer <byte> .Allocate((uint) subTableSize); var subWriter = new BufferWriter(subTable); subWriter.WriteUInt16LE((ushort)subroutines.Length); for (int i = 0; i < subroutines.Length; i++) { subWriter.WriteInt32LE(subroutineOffsets[i] + codeStart); } subWriter.WriteBytes(NsxConstants.TableEndMarker); Span <byte> subHeader = stackalloc byte[NsxConstants.TableHeaderSize]; var subHeaderWriter = new BufferWriter(subHeader); subHeaderWriter.WriteBytes(NsxConstants.SubTableMarker); subHeaderWriter.WriteUInt16LE((ushort)subWriter.Position); // Encode the strings and build the offset table (STR) int stringHeapStart = codeStart + codeWriter.Position; using var stringHeapBuffer = PooledBuffer <byte> .Allocate(64 * 1024); using var stringOffsetTable = PooledBuffer <byte> .Allocate((uint) stringTableSize); var strTableWriter = new BufferWriter(stringOffsetTable); strTableWriter.WriteUInt16LE((ushort)stringHeap.Length); var stringWriter = new BufferWriter(stringHeapBuffer); foreach (string s in stringHeap) { strTableWriter.WriteInt32LE(stringHeapStart + stringWriter.Position); stringWriter.WriteLengthPrefixedUtf8String(s); } strTableWriter.WriteBytes(NsxConstants.TableEndMarker); Span <byte> strTableHeader = stackalloc byte[NsxConstants.TableHeaderSize]; var strTableHeaderWriter = new BufferWriter(strTableHeader); strTableHeaderWriter.WriteBytes(NsxConstants.StringTableMarker); strTableHeaderWriter.WriteUInt16LE((ushort)stringTableSize); // Build the NSX header using var headerBuffer = PooledBuffer <byte> .Allocate(NsxConstants.NsxHeaderSize); var headerWriter = new BufferWriter(headerBuffer); long modificationTime = compilation.SourceReferenceResolver .GetModificationTimestamp(sourceFile.FilePath); headerWriter.WriteBytes(NsxConstants.NsxMagic); headerWriter.WriteInt64LE(modificationTime); headerWriter.WriteInt32LE(subTableOffset); headerWriter.WriteInt32LE(rtiTableOffset); headerWriter.WriteInt32LE(impTableOffset); headerWriter.WriteInt32LE(stringTableOffset); headerWriter.WriteInt32LE(codeStart); // --- Write everything to the stream --- string outDir = compilation.OutputDirectory; string?subDir = Path.GetDirectoryName(sourceFile.Name); if (!string.IsNullOrEmpty(subDir)) { subDir = Path.Combine(outDir, subDir); Directory.CreateDirectory(subDir); } string path = Path.Combine(outDir, Path.ChangeExtension(sourceFile.Name, "nsx")); using FileStream fileStream = File.Create(path); fileStream.Write(headerWriter.Written); fileStream.Write(subHeaderWriter.Written); fileStream.Write(subWriter.Written); fileStream.Write(rtiHeader); fileStream.Write(rtiOffsetWriter.Written); fileStream.Write(rtiWriter.Written); fileStream.Write(impHeaderWriter.Written); fileStream.Write(impTableWriter.Written); fileStream.Write(strTableHeaderWriter.Written); fileStream.Write(strTableWriter.Written); fileStream.Write(codeWriter.Written); fileStream.Write(stringWriter.Written); }
public ushort GetExternalModuleToken(SourceFileSymbol sourceFile) { return(_externalSourceFiles.GetOrAddToken(sourceFile)); }