using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Reflection; using System.Threading; namespace Indy.IL2CPU.Assembler { public abstract class Assembler : IDisposable { // TODO: When threading is being worked on, fix this to work multithreaded! //public const string CurrentExceptionDataMember = "__CURRENT_EXCEPTION__"; public const string SignatureLabelName = "____SIGNATURE___"; public static Exception CurrentException; public static void PrintException() { // The RSOD - Red Screen of Death Console.BackgroundColor = ConsoleColor.DarkRed; Console.ForegroundColor = ConsoleColor.Yellow; Console.Clear(); Console.WriteLine("Cosmos Kernel. Copyright 2007-2008, The Cosmos Project."); Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); Console.WriteLine(""); Console.WriteLine("An unhandled kernel exception occurred."); Console.WriteLine(""); Console.WriteLine(CurrentException.ToString()); Console.WriteLine(""); Console.WriteLine("The Cosmos Project would appreciate your feedback about this issue."); } private static FieldInfo mCurrentExceptionRef; public static FieldInfo CurrentExceptionRef { get { if (mCurrentExceptionRef == null) { var xThisType = typeof(Assembler); mCurrentExceptionRef = xThisType.GetField("CurrentException"); if (mCurrentExceptionRef == null) { throw new Exception("Couldn't find CurrentException field!"); } } return mCurrentExceptionRef; } } private static MethodInfo mCurrentExceptionOccurredRef; public static MethodInfo CurrentExceptionOccurredRef { get { if (mCurrentExceptionOccurredRef == null) { var xThisType = typeof(Assembler); mCurrentExceptionOccurredRef = xThisType.GetMethod("ExceptionOccurred"); if (mCurrentExceptionOccurredRef == null) { throw new Exception("Couldn't find ExceptionOccurred method!"); } } return mCurrentExceptionOccurredRef; } } public byte[] Signature { get; set; } public static void ExceptionOccurred() { System.Diagnostics.Debugger.Break(); } public const string EntryPointName = "__ENGINE_ENTRYPOINT__"; protected internal List mInstructions = new List(); private List mDataMembers = new List(); public readonly Stack StackContents = new Stack(); private static ReaderWriterLocker mCurrentInstanceLocker = new ReaderWriterLocker(); private static SortedList> mCurrentInstance = new SortedList>(); public static Stack CurrentInstance { get { using(mCurrentInstanceLocker.AcquireReaderLock()) { if(mCurrentInstance.ContainsKey(Thread.CurrentThread.ManagedThreadId)) { return mCurrentInstance[Thread.CurrentThread.ManagedThreadId]; } } using(mCurrentInstanceLocker.AcquireWriterLock()) { if (mCurrentInstance.ContainsKey(Thread.CurrentThread.ManagedThreadId)) { return mCurrentInstance[Thread.CurrentThread.ManagedThreadId]; } var xResult = new Stack(); mCurrentInstance.Add(Thread.CurrentThread.ManagedThreadId, xResult); return xResult; } } } private uint mDataMemberCounter = 0; public string GetIdentifier(string aPrefix) { mDataMemberCounter++; return aPrefix + mDataMemberCounter.ToString("X8").ToUpper(); } public Assembler() { CurrentInstance.Push(this); //mInstructions.AddComplexIndexDefinition( } public List DataMembers { get { return mDataMembers; } } public List Instructions { get { return mInstructions; } } public void Dispose() { // MtW: I know, IDisposable usage for this isn't really nice, but for now this should be fine. // Anyhow, we need a way to clear the CurrentInstance property mInstructions.Clear(); mDataMembers.Clear(); CurrentInstance.Pop(); } public void Add(params Instruction[] aReaders) { foreach (Instruction xInstruction in aReaders) { mInstructions.Add(xInstruction); } } public virtual void Initialize() { } /// /// allows to emit footers to the code and datamember sections /// protected virtual void OnBeforeFlush() { } private void BeforeFlush() { using (Assembler.mCurrentInstanceLocker.AcquireReaderLock()) { foreach (var xItem in mCurrentInstance.Values) { if (xItem.Count > 0) { var xAsm = xItem.Peek(); if (xAsm != this) { mDataMembers.AddRange(xAsm.mDataMembers); mInstructions.AddRange(xAsm.mInstructions); } } } } OnBeforeFlush(); mAllAssemblerElements = new List(); mAllAssemblerElements.AddRange(mDataMembers.Cast()); mAllAssemblerElements.AddRange(mInstructions.Cast()); CleanupCode(); } /// /// Cleans up the Instructions list. it evaluates all conditionals. /// protected void CleanupCode() { int xCurrentIdx = 0; int xIfLevelsToSkip = 0; var xDefines = new List(); while (xCurrentIdx < mAllAssemblerElements.Count) { var xCurrentInstruction = mAllAssemblerElements[xCurrentIdx]; var xIfDefined = xCurrentInstruction as IIfDefined; var xEndIfDefined = xCurrentInstruction as IEndIfDefined; var xDefine = xCurrentInstruction as IDefine; var xIfNotDefined = xCurrentInstruction as IIfNotDefined; if(xIfDefined!=null){ if(xIfLevelsToSkip>0){ xIfLevelsToSkip++; } else { if (!xDefines.Contains(xIfDefined.Symbol.ToLowerInvariant())) { xIfLevelsToSkip++; } } mAllAssemblerElements.RemoveAt(xCurrentIdx); continue; } if (xIfNotDefined != null) { if (xIfLevelsToSkip > 0) { xIfLevelsToSkip++; } else { if (xDefines.Contains(xIfNotDefined.Symbol.ToLower())) { xIfLevelsToSkip++; } } mAllAssemblerElements.RemoveAt(xCurrentIdx); continue; } if (xEndIfDefined != null) { if (xIfLevelsToSkip > 0) { xIfLevelsToSkip--; } mAllAssemblerElements.RemoveAt(xCurrentIdx); continue; } if (xIfLevelsToSkip > 0) { mAllAssemblerElements.RemoveAt(xCurrentIdx); continue; } if (xDefine != null) { if (!xDefines.Contains(xDefine.Symbol.ToLowerInvariant())) { xDefines.Add(xDefine.Symbol.ToLowerInvariant()); } mAllAssemblerElements.RemoveAt(xCurrentIdx); continue; } xCurrentIdx++; } } private List mAllAssemblerElements; public virtual void FlushBinary(Stream aOutput, ulong aBaseAddress) { BeforeFlush(); bool xSituationChanged = false; var xIncompleteItems = new List(mAllAssemblerElements); var xCurrentAddresss = aBaseAddress; do { xSituationChanged = false; int xIdx = 0; while (xIdx < xIncompleteItems.Count) { var xCurrentItem = xIncompleteItems[xIdx]; xCurrentItem.StartAddress = xCurrentAddresss; ulong xSize = 0; if (xCurrentItem.DetermineSize(this, out xSize)) { xSituationChanged = true; //Console.WriteLine("Size of '{0}' = {1}", xCurrentItem, xSize); xCurrentAddresss += xSize; xIncompleteItems.RemoveAt(xIdx); continue; } else { break; } } } while (xSituationChanged); if (!xSituationChanged && xIncompleteItems.Count > 0) { throw new Exception("Not all Elements are able to determine size!"); } xIncompleteItems = new List(mAllAssemblerElements); do { int xIdx = 0; xSituationChanged = false; while (xIdx < xIncompleteItems.Count) { var xCurrentItem = xIncompleteItems[xIdx]; if (xCurrentItem.IsComplete(this)) { xSituationChanged = true; xIncompleteItems.RemoveAt(xIdx); continue; } else { break; } } } while (xSituationChanged); if (!xSituationChanged && xIncompleteItems.Count > 0) { throw new Exception("Not all Elements are complete!"); } foreach (var xItem in mAllAssemblerElements) { var xBuff = xItem.GetData(this); aOutput.Write(xBuff, 0, xBuff.Length); } } public virtual void FlushText(TextWriter aOutput) { BeforeFlush(); if (mDataMembers.Count > 0) { aOutput.WriteLine(); foreach (DataMember xMember in mDataMembers) { aOutput.WriteLine("\t" + xMember); } aOutput.WriteLine(); } if (mInstructions.Count > 0) { string xMainLabel=""; for(int i = 0; i < mInstructions.Count;i++){ //foreach (Instruction x in mInstructions) { var x = mInstructions[i]; string prefix = "\t\t\t"; Label xLabel = x as Label; if (xLabel != null) { string xFullName; if (xLabel.Name[0] != '.') { xMainLabel = xLabel.Name; xFullName = xMainLabel; } else { xFullName = xMainLabel + xLabel.Name; } aOutput.WriteLine(); if (x.ToString()[0] == '.') { prefix = "\t\t"; } else { prefix = "\t"; } aOutput.WriteLine(prefix + Label.FilterStringForIncorrectChars(xFullName) + ":"); continue; } aOutput.WriteLine(prefix + x); } } } public BaseAssemblerElement TryResolveReference(ElementReference aReference) { foreach (var xInstruction in mInstructions) { var xLabel = xInstruction as Label; if (xLabel != null) { if (xLabel.QualifiedName.Equals(aReference.Name, StringComparison.InvariantCultureIgnoreCase)) { return xLabel; } } } foreach (var xDataMember in mDataMembers) { if (xDataMember.Name.Equals(aReference.Name, StringComparison.InvariantCultureIgnoreCase)) { return xDataMember; } } return null; } } }