Cosmos/source2/Compiler/Cosmos.Compiler.Assembler/ElementReference.cs
kudzu_cp c5b64267e4
2011-07-16 20:31:56 +00:00

205 lines
6.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Cosmos.Compiler.Assembler
{
public class ElementReference
{
private static Dictionary<string, ElementReference> mLookup = new Dictionary<string, ElementReference>( StringComparer.InvariantCultureIgnoreCase );
public static ElementReference New( string aName, int aOffset )
{
ElementReference xResult;
if( aName.StartsWith( "." ) )
{
aName = Label.LastFullLabel + aName;
}
string xId = String.Intern( aName + "@@" + aOffset );
if( mLookup.TryGetValue( xId, out xResult ) )
{
return xResult;
}
if( aOffset == 0 )
{
xResult = new ElementReference( aName );
}
else
{
xResult = new ElementReference( aName, aOffset );
}
mLookup.Add( xId, xResult );
return xResult;
}
public static ElementReference New( string aName )
{
return New( aName, 0 );
}
private ElementReference( string aName, int aOffset )
: this( aName )
{
Offset = aOffset;
}
private ElementReference( string aName )
{
if( String.IsNullOrEmpty( aName ) )
{
throw new ArgumentNullException( "aName" );
}
if( aName == "00h" )
{
Console.Write( "" );
}
if( aName.StartsWith( "." ) )
{
Name = Label.LastFullLabel + aName;
}
else
{
Name = aName;
}
}
private ulong? mActualAddress;
private static ReaderWriterLockSlim mCacheLocker = new ReaderWriterLockSlim( LockRecursionPolicy.NoRecursion );
private static Dictionary<string, BaseAssemblerElement> mCache;// = new SortedList<string, BaseAssemblerElement>(StringComparer.InvariantCultureIgnoreCase);
private static int? mThreadId = null;
private static BaseAssemblerElement DoResolve( Assembler aAssembler, string aName )
{
if( !mThreadId.HasValue )
{
mThreadId = Thread.CurrentThread.ManagedThreadId;
}
else
{
if( mThreadId.Value != Thread.CurrentThread.ManagedThreadId )
{
throw new Exception( "Called from multiple threads" );
}
}
mCacheLocker.EnterReadLock();
try
{
if( mCache != null )
{
BaseAssemblerElement xTempResult;
if( mCache.TryGetValue( aName, out xTempResult ) )
{
return xTempResult;
}
}
}
finally
{
mCacheLocker.ExitReadLock();
}
mCacheLocker.EnterWriteLock();
try
{
if( mCache == null )
{
mCache = new Dictionary<string, BaseAssemblerElement>( StringComparer.InvariantCultureIgnoreCase );
int xMax = aAssembler.AllAssemblerElementCount;
for( int i = 0; i < xMax; i++ )
{
var xInstruction = aAssembler.GetAssemblerElement( i );
var xLabel = xInstruction as Label;
if( xLabel != null )
{
mCache.Add( xLabel.QualifiedName, xLabel );
}
var xDataMember = xInstruction as DataMember;
if( xDataMember != null )
{
if( mCache.ContainsKey( xDataMember.Name ) )
{
Console.Write( "" );
}
mCache.Add( xDataMember.Name, xDataMember );
}
}
}
BaseAssemblerElement xTempResult;
if( mCache.TryGetValue( aName, out xTempResult ) )
{
return xTempResult;
}
throw new Exception( "Cannot resolve ElementReference to '" + aName + "'!" );
//foreach(var xInstruction in aAssembler.Instructions ) {
// var xLabel = xInstruction as Label;
// if(xLabel!=null) {
// if(aName.Equals(xLabel.Name, StringComparison.InvariantCultureIgnoreCase)) {
// xTempResult = xLabel;
// break;
// }
// }
//}
//if (xTempResult == null) {
// foreach (var xDataMember in aAssembler.DataMembers) {
// if (aName.Equals(xDataMember.Name, StringComparison.InvariantCultureIgnoreCase)) {
// xTempResult = xDataMember;
// break;
// }
// }
//}
}
finally
{
mCacheLocker.ExitWriteLock();
}
}
public bool Resolve( Assembler aAssembler, out ulong aAddress )
{
//
if( mActualAddress != null )
{
aAddress = mActualAddress.Value;
return true;
}
var xElement = DoResolve( aAssembler, Name );
if( xElement != null )
{
if( xElement.ActualAddress.HasValue )
{
mActualAddress = ( ulong )( ( long )xElement.ActualAddress.Value + Offset );
aAddress = mActualAddress.Value;
return true;
}
}
aAddress = 0;
return false;
}
public int Offset
{
get;
set;
}
public string Name
{
get;
set;
}
public override string ToString()
{
if( Offset != 0 )
{
return Name + " + " + Offset;
}
else
{
return Name;
}
}
}
}