This commit is contained in:
mterwoord_cp 2014-07-13 22:33:53 +00:00
parent 03366efdf7
commit e9a2fb40df
8 changed files with 221 additions and 178 deletions

View file

@ -0,0 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ObjectCreationAsStatement/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Locals/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="x" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="a" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="m" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="m" Suffix="" Style="AaBb" /&gt;</s:String></wpf:ResourceDictionary>

View file

@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
using System.Text;
using Cosmos.Assembler;
using Cosmos.Assembler.x86;
using Cosmos.Assembler.x86._486AndUp;
using Cosmos.Build.Common;
using Cosmos.Debug.Common;
using Cosmos.IL2CPU.Plugs;
@ -66,10 +67,6 @@ namespace Cosmos.IL2CPU
new Comment("Type: " + aMethod.MethodBase.DeclaringType.ToString());
new Comment("Name: " + aMethod.MethodBase.Name);
new Comment("Plugged: " + (aMethod.PlugMethod == null ? "No" : "Yes"));
if (aMethod.MethodBase.Name == "GetFatEntry")
{
Console.Write("");
}
// for now:
var shouldIncludeArgAndLocalsComment = true;
if (shouldIncludeArgAndLocalsComment)
@ -460,6 +457,8 @@ namespace Cosmos.IL2CPU
}
else
{
// now emit the actual assembler code for this method.
//Conditions under which we should emit an INT3 instead of a plceholder NOP:
/* - First instruction in a Method / Loop / If / Else etc.
* -- In essence, whenever there is a opening {
@ -467,109 +466,168 @@ namespace Cosmos.IL2CPU
* -- So only insert an INT3 when we are about to insert a NOP that came from IL code
*/
/* We group opcodes together by logical statement. Each statement will have its logical stack cleared.
* Also, this lets us do optimizations later on.
*/
bool emitINT3 = true;
foreach (var xOpCode in aOpCodes)
DebugInfo.SequencePoint xPreviousSequencePoint = null;
var xCurrentGroup = new List<ILOpCode>();
foreach (var xRawOpcode in aOpCodes)
{
ushort xOpCodeVal = (ushort)xOpCode.OpCode;
ILOp xILOp;
if (xOpCodeVal <= 0xFF)
var xSP = mSequences.FirstOrDefault(q => q.Offset == xRawOpcode.Position && q.LineStart != 0xFEEFEE);
var hasNewSP = false;
// detect if we're at a new statement.
if (xPreviousSequencePoint == null && xSP != null)
{
xILOp = mILOpsLo[xOpCodeVal];
}
else
if (xSP != null && xCurrentGroup.Count > 0)
{
xILOp = mILOpsHi[xOpCodeVal & 0xFF];
EmitInstructions(aMethod, xCurrentGroup, ref emitINT3);
xCurrentGroup.Clear();
xPreviousSequencePoint = xSP;
}
mLog.WriteLine("\t{0} {1}", Assembler.Stack.Count, xILOp.GetType().Name);
mLog.Flush();
//Only emit INT3 as per conditions above...
bool INT3Emitted = false;
BeforeOp(aMethod, xOpCode, emitINT3, out INT3Emitted);
//Emit INT3 on the first non-NOP instruction immediately after a NOP
// - This is because TracePoints for NOP are automatically ignored in code called below this
emitINT3 = (emitINT3 && !INT3Emitted) || xILOp is Cosmos.IL2CPU.X86.IL.Nop;
new Comment(xILOp.ToString());
var xNextPosition = xOpCode.Position + 1;
#region Exception handling support code
ExceptionHandlingClause xCurrentHandler = null;
var xBody = aMethod.MethodBase.GetMethodBody();
// todo: add support for nested handlers using a stack or so..
foreach (ExceptionHandlingClause xHandler in xBody.ExceptionHandlingClauses)
{
if (xHandler.TryOffset > 0)
{
if (xHandler.TryOffset <= xNextPosition && (xHandler.TryLength + xHandler.TryOffset) > xNextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.TryOffset > xCurrentHandler.TryOffset && (xHandler.TryLength + xHandler.TryOffset) < (xCurrentHandler.TryLength + xCurrentHandler.TryOffset))
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
if (xHandler.HandlerOffset > 0)
{
if (xHandler.HandlerOffset <= xNextPosition && (xHandler.HandlerOffset + xHandler.HandlerLength) > xNextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.HandlerOffset > xCurrentHandler.HandlerOffset && (xHandler.HandlerOffset + xHandler.HandlerLength) < (xCurrentHandler.HandlerOffset + xCurrentHandler.HandlerLength))
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
if ((xHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0)
{
if (xHandler.FilterOffset > 0)
{
if (xHandler.FilterOffset <= xNextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.FilterOffset > xCurrentHandler.FilterOffset)
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
}
}
#endregion
var xNeedsExceptionPush = (xCurrentHandler != null) && (((xCurrentHandler.HandlerOffset > 0 && xCurrentHandler.HandlerOffset == xOpCode.Position) || ((xCurrentHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0 && xCurrentHandler.FilterOffset > 0 && xCurrentHandler.FilterOffset == xOpCode.Position)) && (xCurrentHandler.Flags == ExceptionHandlingClauseOptions.Clause));
if (xNeedsExceptionPush)
{
Push(DataMember.GetStaticFieldName(ExceptionHelperRefs.CurrentExceptionRef), true);
Assembler.Stack.Push(4, typeof(Exception));
}
xILOp.DebugEnabled = DebugEnabled;
xILOp.Execute(aMethod, xOpCode);
AfterOp(aMethod, xOpCode);
//mLog.WriteLine( " end: " + Stack.Count.ToString() );
xCurrentGroup.Add(xRawOpcode);
}
if (xCurrentGroup.Count > 0)
{
EmitInstructions(aMethod, xCurrentGroup, ref emitINT3);
}
}
MethodEnd(aMethod);
}
private void BeforeEmitInstructions(MethodInfo aMethod, List<ILOpCode> aCurrentGroup)
{
// do optimizations
}
private void AfterEmitInstructions(MethodInfo aMethod, List<ILOpCode> aCurrentGroup)
{
// do optimizations
if (Assembler.Stack.Count > 0)
{
if (mDebugStackErrors)
{
Console.WriteLine("StackCorruption in Analytical stack:");
Console.WriteLine("- Method: {0}", aMethod.MethodBase.GetFullName());
Console.WriteLine("- Last ILOpCode offset: {0}", aCurrentGroup.Last().Position.ToString("X"));
}
}
}
private static bool mDebugStackErrors = true;
private void EmitInstructions(MethodInfo aMethod, List<ILOpCode> xCurrentGroup, ref bool emitINT3)
{
new Comment(String.Format("New Group Offset {0} - Offset {1}", xCurrentGroup.First().Position.ToString("X"), xCurrentGroup.Last().Position.ToString("X")));
BeforeEmitInstructions(aMethod, xCurrentGroup);
var xFirstInstruction = true;
foreach (var xOpCode in xCurrentGroup)
{
ushort xOpCodeVal = (ushort) xOpCode.OpCode;
ILOp xILOp;
if (xOpCodeVal <= 0xFF)
{
xILOp = mILOpsLo[xOpCodeVal];
}
else
{
xILOp = mILOpsHi[xOpCodeVal & 0xFF];
}
mLog.WriteLine("\t{0} {1}", Assembler.Stack.Count, xILOp.GetType().Name);
mLog.Flush();
//Only emit INT3 as per conditions above...
bool INT3Emitted = false;
BeforeOp(aMethod, xOpCode, emitINT3, out INT3Emitted, xFirstInstruction);
xFirstInstruction = false;
//Emit INT3 on the first non-NOP instruction immediately after a NOP
// - This is because TracePoints for NOP are automatically ignored in code called below this
emitINT3 = (emitINT3 && !INT3Emitted) || xILOp is Cosmos.IL2CPU.X86.IL.Nop;
new Comment(xILOp.ToString());
var xNextPosition = xOpCode.Position + 1;
#region Exception handling support code
ExceptionHandlingClause xCurrentHandler = null;
var xBody = aMethod.MethodBase.GetMethodBody();
// todo: add support for nested handlers using a stack or so..
foreach (ExceptionHandlingClause xHandler in xBody.ExceptionHandlingClauses)
{
if (xHandler.TryOffset > 0)
{
if (xHandler.TryOffset <= xNextPosition && (xHandler.TryLength + xHandler.TryOffset) > xNextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.TryOffset > xCurrentHandler.TryOffset && (xHandler.TryLength + xHandler.TryOffset) < (xCurrentHandler.TryLength + xCurrentHandler.TryOffset))
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
if (xHandler.HandlerOffset > 0)
{
if (xHandler.HandlerOffset <= xNextPosition && (xHandler.HandlerOffset + xHandler.HandlerLength) > xNextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.HandlerOffset > xCurrentHandler.HandlerOffset && (xHandler.HandlerOffset + xHandler.HandlerLength) < (xCurrentHandler.HandlerOffset + xCurrentHandler.HandlerLength))
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
if ((xHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0)
{
if (xHandler.FilterOffset > 0)
{
if (xHandler.FilterOffset <= xNextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.FilterOffset > xCurrentHandler.FilterOffset)
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
}
}
#endregion
var xNeedsExceptionPush = (xCurrentHandler != null) && (((xCurrentHandler.HandlerOffset > 0 && xCurrentHandler.HandlerOffset == xOpCode.Position) || ((xCurrentHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0 && xCurrentHandler.FilterOffset > 0 && xCurrentHandler.FilterOffset == xOpCode.Position)) && (xCurrentHandler.Flags == ExceptionHandlingClauseOptions.Clause));
if (xNeedsExceptionPush)
{
Push(DataMember.GetStaticFieldName(ExceptionHelperRefs.CurrentExceptionRef), true);
Assembler.Stack.Push(4, typeof (Exception));
}
xILOp.DebugEnabled = DebugEnabled;
xILOp.Execute(aMethod, xOpCode);
AfterOp(aMethod, xOpCode);
//mLog.WriteLine( " end: " + Stack.Count.ToString() );
}
AfterEmitInstructions(aMethod, xCurrentGroup);
}
protected void InitILOps()
{
InitILOps(typeof(ILOp));
@ -1177,7 +1235,7 @@ namespace Cosmos.IL2CPU
new Comment("Stack contains " + Assembler.Stack.Count + " items: (" + xContents + ")");
}
protected void BeforeOp(MethodInfo aMethod, ILOpCode aOpCode, bool emitInt3NotNop, out bool INT3Emitted)
protected void BeforeOp(MethodInfo aMethod, ILOpCode aOpCode, bool emitInt3NotNop, out bool INT3Emitted, bool hasSourcePoint)
{
string xLabel = TmpPosLabel(aMethod, aOpCode);
Assembler.CurrentIlLabel = xLabel;
@ -1211,7 +1269,7 @@ namespace Cosmos.IL2CPU
DebugInfo.AddSymbols(mSymbols, false);
bool INT3PlaceholderEmitted = false;
EmitTracer(aMethod, aOpCode, aMethod.MethodBase.DeclaringType.Namespace, emitInt3NotNop, out INT3Emitted, out INT3PlaceholderEmitted);
EmitTracer(aMethod, aOpCode, aMethod.MethodBase.DeclaringType.Namespace, emitInt3NotNop, out INT3Emitted, out INT3PlaceholderEmitted, hasSourcePoint);
if (INT3Emitted || INT3PlaceholderEmitted)
{
@ -1223,43 +1281,43 @@ namespace Cosmos.IL2CPU
DebugInfo.AddINT3Labels(mINT3Labels);
}
if (DebugEnabled && StackCorruptionDetection)
{
// if debugstub is active, emit a stack corruption detection. at this point, the difference between EBP and ESP
// should be equal to the local variables sizes and the IL stack.
// if not, we should break here.
//if (DebugEnabled && StackCorruptionDetection)
//{
// // if debugstub is active, emit a stack corruption detection. at this point, the difference between EBP and ESP
// // should be equal to the local variables sizes and the IL stack.
// // if not, we should break here.
// first, calculate the expected difference
var expectedDifference = aMethod.LocalVariablesSize;
foreach (var item in Assembler.Stack)
{
expectedDifference += X86.IL.Ldarg.Align(item.Size, 4);
}
// // first, calculate the expected difference
// var expectedDifference = aMethod.LocalVariablesSize;
// foreach (var item in Assembler.Stack)
// {
// expectedDifference += X86.IL.Ldarg.Align(item.Size, 4);
// }
// if debugstub is active, emit a stack corruption detection. at this point EBP and ESP should have the same value.
// if not, we should somehow break here.
new Mov { DestinationReg = Registers.EAX, SourceReg = RegistersEnum.ESP };
new Mov { DestinationReg = Registers.EBX, SourceReg = RegistersEnum.EBP };
new Add { DestinationReg = Registers.EAX, SourceValue = expectedDifference };
new Compare { SourceReg = RegistersEnum.EAX, DestinationReg = RegistersEnum.EBX };
new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = xLabel + ".StackCorruptionCheck_End" };
new ClrInterruptFlag();
// don't remove the call. It seems pointless, but we need it to retrieve the EIP value
new Call { DestinationLabel = xLabel + ".StackCorruptionCheck_GetAddress" };
new Assembler.Label(xLabel + ".StackCorruptionCheck_GetAddress");
new Pop { DestinationReg = RegistersEnum.EAX };
new Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX };
new Call { DestinationLabel = "DebugStub_SendStackCorruptionOccurred" };
new Halt();
new Assembler.Label(xLabel + ".StackCorruptionCheck_End");
// // if debugstub is active, emit a stack corruption detection. at this point EBP and ESP should have the same value.
// // if not, we should somehow break here.
// new Mov { DestinationReg = Registers.EAX, SourceReg = RegistersEnum.ESP };
// new Mov { DestinationReg = Registers.EBX, SourceReg = RegistersEnum.EBP };
// new Add { DestinationReg = Registers.EAX, SourceValue = expectedDifference };
// new Compare { SourceReg = RegistersEnum.EAX, DestinationReg = RegistersEnum.EBX };
// new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = xLabel + ".StackCorruptionCheck_End" };
// new ClrInterruptFlag();
// // don't remove the call. It seems pointless, but we need it to retrieve the EIP value
// new Call { DestinationLabel = xLabel + ".StackCorruptionCheck_GetAddress" };
// new Assembler.Label(xLabel + ".StackCorruptionCheck_GetAddress");
// new Pop { DestinationReg = RegistersEnum.EAX };
// new Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX };
// new Call { DestinationLabel = "DebugStub_SendStackCorruptionOccurred" };
// new Halt();
// new Assembler.Label(xLabel + ".StackCorruptionCheck_End");
}
//}
}
protected void EmitTracer(MethodInfo aMethod, ILOpCode aOp, string aNamespace, bool emitInt3NotNop, out bool INT3Emitted, out bool INT3PlaceholderEmitted)
protected void EmitTracer(MethodInfo aMethod, ILOpCode aOp, string aNamespace, bool emitInt3NotNop, out bool INT3Emitted, out bool INT3PlaceholderEmitted, bool isNewSourcePoint)
{
// NOTE - These if statements can be optimized down - but clarity is
// more important the optimizations. Furthermoer the optimazations available
// more important than the optimizations. Furthermore the optimizations available
// would not offer much benefit
// Determine if a new DebugStub should be emitted
@ -1282,16 +1340,10 @@ namespace Cosmos.IL2CPU
{
// If the current position equals one of the offsets, then we have
// reached a new atomic C# statement
var xSP = mSequences.SingleOrDefault(q => q.Offset == aOp.Position);
if (xSP == null)
if (!isNewSourcePoint)
{
return;
}
else if (xSP.LineStart == 0xFEEFEE)
{
// 0xFEEFEE means hiddenline -> we dont want to stop there
return;
}
}
// Check if the DebugStub has been disabled for this method

View file

@ -17,6 +17,7 @@ namespace Cosmos.IL2CPU.X86.IL
public override void Execute( MethodInfo aMethod, ILOpCode aOpCode )
{
var xStackItem = Assembler.Stack.Pop();
Assembler.Stack.Pop();
if( xStackItem.Size > 8 )
{
//EmitNotImplementedException( Assembler, GetServiceProvider(), "Cgt: StackSizes>8 not supported", CurInstructionLabel, mMethodInfo, mCurrentOffset, NextInstructionLabel );

View file

@ -16,6 +16,7 @@ namespace Cosmos.IL2CPU.X86.IL
public override void Execute( MethodInfo aMethod, ILOpCode aOpCode )
{
var xStackItem = Assembler.Stack.Pop();
Assembler.Stack.Pop();
if( xStackItem.Size > 8 )
{
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Clt_Un.cs->Error: StackSizes > 8 not supported");

View file

@ -3,18 +3,24 @@ using CPUx86 = Cosmos.Assembler.x86;
namespace Cosmos.IL2CPU.X86.IL
{
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Ret)]
public class Ret: ILOp
{
public Ret(Cosmos.Assembler.Assembler aAsmblr):base(aAsmblr)
{
}
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Ret)]
public class Ret : ILOp
{
public Ret(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr)
{
}
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) {
//TODO: Return
Jump_End(aMethod);
// Need to jump to end of method. Assembler can emit this label for now
//new CPU.Jump { DestinationLabel = MethodFooterOp.EndOfMethodLabelNameNormal };
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
{
//TODO: Return
Jump_End(aMethod);
// Need to jump to end of method. Assembler can emit this label for now
//new CPU.Jump { DestinationLabel = MethodFooterOp.EndOfMethodLabelNameNormal };
var methodInf = aMethod.MethodBase as System.Reflection.MethodInfo;
if (methodInf != null && methodInf.ReturnType != typeof (void))
{
Assembler.Stack.Pop();
}
}
}
}
}
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using SR = System.Reflection;
@ -10,6 +11,7 @@ namespace Cosmos.IL2CPU {
// Include reference to ILOp, the scanner should do that
// Include referense to System.Reflection.Emit, this is metadata
// only needed by reader and not ILOpCode
//[DebuggerDisplay("IL_{Position}{:{OpCode}")]
public abstract class ILOpCode {
public enum Code : ushort {
@ -258,5 +260,9 @@ namespace Cosmos.IL2CPU {
CurrentExceptionHandler = aCurrentExceptionHandler;
}
public override string ToString()
{
return String.Format("IL_{0}: {1}", Position.ToString("X4"), OpCode);
}
}
}

View file

@ -16,36 +16,6 @@ namespace Cosmos.IL2CPU
{
public delegate void LogExceptionDelegate(Exception e);
// This is necessary because HashSet and Dictionary
// have troubles when different types of objects are stored
// in them. I dont remember the exact problem, but something
// with how it compares objects. ie when HashSet<object> is used, this is necessary.
/*public class HashcodeComparer<T> : IEqualityComparer<T> {
public bool Equals(T x, T y) {
return internalEqualsSinceNET40(x, y);// x.GetHashCode() == y.GetHashCode();
}
public bool internalEqualsSinceNET40(T left, T right)
{
var methodDeclaringType = left.GetType().GetMethod("get_DeclaringType");
var leftDeclaringType = methodDeclaringType.Invoke(left, null);
var method = right.GetType().GetMethod("get_DeclaringType");
var rightDeclaringType = method.Invoke(right, null);
if (left.ToString() == right.ToString()
&& leftDeclaringType == rightDeclaringType)
{
return true;
}
return false;
}
public int GetHashCode(T obj) {
return obj.GetHashCode();
}
}*/
public class ScannerQueueItem
{
public _MemberInfo Item;

View file

@ -29,6 +29,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>