зеркало из https://github.com/mono/ikvm-fork.git
Moved line number / sequence point handling into CodeEmitter and made things more consistent.
This commit is contained in:
Родитель
c6e3c87af1
Коммит
ce884000ce
|
@ -78,13 +78,12 @@ namespace IKVM.Internal
|
|||
#endif
|
||||
private Stack<bool> exceptionStack = new Stack<bool>();
|
||||
private bool inFinally;
|
||||
#if STATIC_COMPILER
|
||||
private IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter linenums;
|
||||
#endif // STATIC_COMPILER
|
||||
private Expr[] stackArray = new Expr[8];
|
||||
private int topOfStack;
|
||||
private CodeEmitterLabel lazyBranch;
|
||||
private LocalBuilder[] tempLocals = new LocalBuilder[32];
|
||||
private ISymbolDocumentWriter symbols;
|
||||
#if LABELCHECK
|
||||
private Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame> labels = new Dictionary<CodeEmitterLabel, System.Diagnostics.StackFrame>();
|
||||
#endif
|
||||
|
@ -150,6 +149,11 @@ namespace IKVM.Internal
|
|||
return stackArray[topOfStack - 1];
|
||||
}
|
||||
|
||||
internal void DefineSymbolDocument(ModuleBuilder module, string url, Guid language, Guid languageVendor, Guid documentType)
|
||||
{
|
||||
symbols = module.DefineDocument(url, language, languageVendor, documentType);
|
||||
}
|
||||
|
||||
internal LocalBuilder UnsafeAllocTempLocal(Type type)
|
||||
{
|
||||
int free = -1;
|
||||
|
@ -210,7 +214,7 @@ namespace IKVM.Internal
|
|||
}
|
||||
}
|
||||
|
||||
internal int GetILOffset()
|
||||
private int GetILOffset()
|
||||
{
|
||||
LazyGen();
|
||||
#if STATIC_COMPILER
|
||||
|
@ -560,12 +564,6 @@ namespace IKVM.Internal
|
|||
loc.Offset = GetILOffset();
|
||||
}
|
||||
|
||||
internal void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
|
||||
{
|
||||
LazyGen();
|
||||
ilgen_real.MarkSequencePoint(document, startLine, startColumn, endLine, endColumn);
|
||||
}
|
||||
|
||||
internal void ThrowException(Type excType)
|
||||
{
|
||||
LazyGen();
|
||||
|
@ -575,16 +573,33 @@ namespace IKVM.Internal
|
|||
ilgen_real.ThrowException(excType);
|
||||
}
|
||||
|
||||
#if STATIC_COMPILER
|
||||
internal void SetLineNumber(ushort line)
|
||||
{
|
||||
if(linenums == null)
|
||||
if (symbols != null)
|
||||
{
|
||||
linenums = new IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter(32);
|
||||
LazyGen();
|
||||
ilgen_real.MarkSequencePoint(symbols, line, 0, line + 1, 0);
|
||||
// we emit a nop to make sure we always have an instruction associated with the sequence point
|
||||
Emit(OpCodes.Nop);
|
||||
}
|
||||
// we only add a line number mapping if the stack is empty because the CLR JIT only generates native to IL mappings
|
||||
// for locations where the stack is empty and we don't want to needlessly flush the stack
|
||||
if (topOfStack == 0)
|
||||
{
|
||||
if (linenums == null)
|
||||
{
|
||||
linenums = new IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter(32);
|
||||
}
|
||||
linenums.AddMapping(GetILOffset(), line);
|
||||
}
|
||||
linenums.AddMapping(GetILOffset(), line);
|
||||
}
|
||||
|
||||
internal byte[] GetLineNumberTable()
|
||||
{
|
||||
return linenums == null ? null : linenums.ToArray();
|
||||
}
|
||||
|
||||
#if STATIC_COMPILER
|
||||
internal void EmitLineNumberTable(MethodBase mb)
|
||||
{
|
||||
if(linenums != null)
|
||||
|
|
|
@ -3803,26 +3803,26 @@ namespace IKVM.Internal
|
|||
continue;
|
||||
}
|
||||
#endif // STATIC_COMPILER
|
||||
LineNumberTableAttribute.LineNumberWriter lineNumberTable = null;
|
||||
bool nonleaf = false;
|
||||
Compiler.Compile(this, wrapper, methods[i], classFile, m, ilGenerator, ref nonleaf, invokespecialstubcache, ref lineNumberTable);
|
||||
Compiler.Compile(this, wrapper, methods[i], classFile, m, ilGenerator, ref nonleaf, invokespecialstubcache);
|
||||
ilGenerator.CheckLabels();
|
||||
if (nonleaf)
|
||||
{
|
||||
mbld.SetImplementationFlags(mbld.GetMethodImplementationFlags() | MethodImplAttributes.NoInlining);
|
||||
}
|
||||
if (lineNumberTable != null)
|
||||
{
|
||||
#if STATIC_COMPILER
|
||||
AttributeHelper.SetLineNumberTable(methods[i].GetMethod(), lineNumberTable);
|
||||
ilGenerator.EmitLineNumberTable(methods[i].GetMethod());
|
||||
#else // STATIC_COMPILER
|
||||
byte[] linenumbers = ilGenerator.GetLineNumberTable();
|
||||
if (linenumbers != null)
|
||||
{
|
||||
if (wrapper.lineNumberTables == null)
|
||||
{
|
||||
wrapper.lineNumberTables = new byte[methods.Length][];
|
||||
}
|
||||
wrapper.lineNumberTables[i] = lineNumberTable.ToArray();
|
||||
#endif // STATIC_COMPILER
|
||||
wrapper.lineNumberTables[i] = linenumbers;
|
||||
}
|
||||
#endif // STATIC_COMPILER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5031,21 +5031,21 @@ namespace IKVM.Internal
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
LineNumberTableAttribute.LineNumberWriter lineNumberTable = null;
|
||||
bool nonLeaf = false;
|
||||
Compiler.Compile(context, wrapper, methods[methodIndex], classFile, m, ilGenerator, ref nonLeaf, invokespecialstubcache, ref lineNumberTable);
|
||||
if (lineNumberTable != null)
|
||||
{
|
||||
Compiler.Compile(context, wrapper, methods[methodIndex], classFile, m, ilGenerator, ref nonLeaf, invokespecialstubcache);
|
||||
#if STATIC_COMPILER
|
||||
AttributeHelper.SetLineNumberTable(methods[methodIndex].GetMethod(), lineNumberTable);
|
||||
ilGenerator.EmitLineNumberTable(methods[methodIndex].GetMethod());
|
||||
#else // STATIC_COMPILER
|
||||
byte[] linenumbers = ilGenerator.GetLineNumberTable();
|
||||
if (linenumbers != null)
|
||||
{
|
||||
if (wrapper.lineNumberTables == null)
|
||||
{
|
||||
wrapper.lineNumberTables = new byte[methods.Length][];
|
||||
}
|
||||
wrapper.lineNumberTables[methodIndex] = lineNumberTable.ToArray();
|
||||
#endif // STATIC_COMPILER
|
||||
wrapper.lineNumberTables[methodIndex] = linenumbers;
|
||||
}
|
||||
#endif // STATIC_COMPILER
|
||||
}
|
||||
|
||||
private static bool IsCompatibleArgList(TypeWrapper[] caller, TypeWrapper[] callee)
|
||||
|
|
|
@ -176,13 +176,12 @@ sealed class Compiler
|
|||
private readonly UntangledExceptionTable exceptions;
|
||||
private readonly List<string> harderrors;
|
||||
private readonly LocalVarInfo localVars;
|
||||
private readonly ISymbolDocumentWriter symboldocument;
|
||||
private readonly LineNumberTableAttribute.LineNumberWriter lineNumbers;
|
||||
private bool nonleaf;
|
||||
private Dictionary<MethodKey, MethodInfo> invokespecialstubcache;
|
||||
private readonly bool debug;
|
||||
private readonly bool keepAlive;
|
||||
private readonly bool strictfp;
|
||||
private readonly bool emitLineNumbers;
|
||||
private int[] scopeBegin;
|
||||
private int[] scopeClose;
|
||||
#if STATIC_COMPILER
|
||||
|
@ -225,7 +224,7 @@ sealed class Compiler
|
|||
getClassFromTypeHandle.Link();
|
||||
}
|
||||
|
||||
private Compiler(DynamicTypeWrapper.FinishContext context, DynamicTypeWrapper clazz, MethodWrapper mw, ClassFile classFile, ClassFile.Method m, CodeEmitter ilGenerator, ClassLoaderWrapper classLoader, ISymbolDocumentWriter symboldocument, Dictionary<MethodKey, MethodInfo> invokespecialstubcache)
|
||||
private Compiler(DynamicTypeWrapper.FinishContext context, DynamicTypeWrapper clazz, MethodWrapper mw, ClassFile classFile, ClassFile.Method m, CodeEmitter ilGenerator, ClassLoaderWrapper classLoader, Dictionary<MethodKey, MethodInfo> invokespecialstubcache)
|
||||
{
|
||||
this.context = context;
|
||||
this.clazz = clazz;
|
||||
|
@ -233,14 +232,9 @@ sealed class Compiler
|
|||
this.classFile = classFile;
|
||||
this.m = m;
|
||||
this.ilGenerator = ilGenerator;
|
||||
this.symboldocument = symboldocument;
|
||||
this.invokespecialstubcache = invokespecialstubcache;
|
||||
this.debug = classLoader.EmitDebugInfo;
|
||||
this.strictfp = m.IsStrictfp;
|
||||
if(m.LineNumberTableAttribute != null && classLoader.EmitStackTraceInfo)
|
||||
{
|
||||
this.lineNumbers = new LineNumberTableAttribute.LineNumberWriter(m.LineNumberTableAttribute.Length);
|
||||
}
|
||||
if(ReferenceEquals(mw.Name, StringConstants.INIT))
|
||||
{
|
||||
MethodWrapper finalize = clazz.GetMethodWrapper(StringConstants.FINALIZE, StringConstants.SIG_VOID, true);
|
||||
|
@ -267,6 +261,50 @@ sealed class Compiler
|
|||
Profiler.Leave("MethodAnalyzer");
|
||||
}
|
||||
|
||||
if (m.LineNumberTableAttribute != null)
|
||||
{
|
||||
if (classLoader.EmitDebugInfo)
|
||||
{
|
||||
emitLineNumbers = true;
|
||||
}
|
||||
else if (classLoader.EmitStackTraceInfo)
|
||||
{
|
||||
InstructionFlags[] flags = ComputePartialReachability(0, false);
|
||||
for (int i = 0; i < m.Instructions.Length; i++)
|
||||
{
|
||||
if ((flags[i] & InstructionFlags.Reachable) == 0)
|
||||
{
|
||||
// skip unreachable instructions
|
||||
}
|
||||
else if (m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__getfield
|
||||
&& VerifierTypeWrapper.IsThis(ma.GetRawStackTypeWrapper(i, 0)))
|
||||
{
|
||||
// loading a field from the current object cannot throw
|
||||
}
|
||||
else if (m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__putfield
|
||||
&& VerifierTypeWrapper.IsThis(ma.GetRawStackTypeWrapper(i, 1)))
|
||||
{
|
||||
// storing a field in the current object cannot throw
|
||||
}
|
||||
else if (m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__getstatic
|
||||
&& classFile.GetFieldref(m.Instructions[i].Arg1).GetClassType() == clazz)
|
||||
{
|
||||
// loading a field from the current class cannot throw
|
||||
}
|
||||
else if (m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__putstatic
|
||||
&& classFile.GetFieldref(m.Instructions[i].Arg1).GetClassType() == clazz)
|
||||
{
|
||||
// storing a field to the current class cannot throw
|
||||
}
|
||||
else if (ByteCodeMetaData.CanThrowException(m.Instructions[i].NormalizedOpCode))
|
||||
{
|
||||
emitLineNumbers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypeWrapper[] args = mw.GetParameters();
|
||||
LocalVar[] locals = localVars.GetAllLocalVars();
|
||||
foreach(LocalVar v in locals)
|
||||
|
@ -524,10 +562,9 @@ sealed class Compiler
|
|||
}
|
||||
}
|
||||
|
||||
internal static void Compile(DynamicTypeWrapper.FinishContext context, DynamicTypeWrapper clazz, MethodWrapper mw, ClassFile classFile, ClassFile.Method m, CodeEmitter ilGenerator, ref bool nonleaf, Dictionary<MethodKey, MethodInfo> invokespecialstubcache, ref LineNumberTableAttribute.LineNumberWriter lineNumberTable)
|
||||
internal static void Compile(DynamicTypeWrapper.FinishContext context, DynamicTypeWrapper clazz, MethodWrapper mw, ClassFile classFile, ClassFile.Method m, CodeEmitter ilGenerator, ref bool nonleaf, Dictionary<MethodKey, MethodInfo> invokespecialstubcache)
|
||||
{
|
||||
ClassLoaderWrapper classLoader = clazz.GetClassLoader();
|
||||
ISymbolDocumentWriter symboldocument = null;
|
||||
if(classLoader.EmitDebugInfo)
|
||||
{
|
||||
string sourcefile = classFile.SourceFileAttribute;
|
||||
|
@ -540,7 +577,7 @@ sealed class Compiler
|
|||
package = index == -1 ? "" : package.Substring(0, index).Replace('.', '/');
|
||||
sourcefile = new System.IO.FileInfo(classLoader.SourcePath + "/" + package + "/" + sourcefile).FullName;
|
||||
}
|
||||
symboldocument = classLoader.GetTypeWrapperFactory().ModuleBuilder.DefineDocument(sourcefile, SymLanguageType.Java, Guid.Empty, SymDocumentType.Text);
|
||||
ilGenerator.DefineSymbolDocument(classLoader.GetTypeWrapperFactory().ModuleBuilder, sourcefile, SymLanguageType.Java, Guid.Empty, SymDocumentType.Text);
|
||||
// the very first instruction in the method must have an associated line number, to be able
|
||||
// to step into the method in Visual Studio .NET
|
||||
ClassFile.Method.LineNumberTableEntry[] table = m.LineNumberTableAttribute;
|
||||
|
@ -558,7 +595,7 @@ sealed class Compiler
|
|||
}
|
||||
if(firstLine > 0)
|
||||
{
|
||||
ilGenerator.MarkSequencePoint(symboldocument, firstLine, 0, firstLine + 1, 0);
|
||||
ilGenerator.SetLineNumber((ushort)firstLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -582,7 +619,7 @@ sealed class Compiler
|
|||
Profiler.Enter("new Compiler");
|
||||
try
|
||||
{
|
||||
c = new Compiler(context, clazz, mw, classFile, m, ilGenerator, classLoader, symboldocument, invokespecialstubcache);
|
||||
c = new Compiler(context, clazz, mw, classFile, m, ilGenerator, classLoader, invokespecialstubcache);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -637,42 +674,6 @@ sealed class Compiler
|
|||
c.Compile(b, c.ComputePartialReachability(0, true));
|
||||
b.Leave();
|
||||
}
|
||||
if(c.lineNumbers != null)
|
||||
{
|
||||
InstructionFlags[] flags = c.ComputePartialReachability(0, false);
|
||||
for(int i = 0; i < m.Instructions.Length; i++)
|
||||
{
|
||||
if((flags[i] & InstructionFlags.Reachable) == 0)
|
||||
{
|
||||
// skip unreachable instructions
|
||||
}
|
||||
else if(m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__getfield
|
||||
&& VerifierTypeWrapper.IsThis(c.ma.GetRawStackTypeWrapper(i, 0)))
|
||||
{
|
||||
// loading a field from the current object cannot throw
|
||||
}
|
||||
else if(m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__putfield
|
||||
&& VerifierTypeWrapper.IsThis(c.ma.GetRawStackTypeWrapper(i, 1)))
|
||||
{
|
||||
// storing a field in the current object cannot throw
|
||||
}
|
||||
else if(m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__getstatic
|
||||
&& classFile.GetFieldref(m.Instructions[i].Arg1).GetClassType() == clazz)
|
||||
{
|
||||
// loading a field from the current class cannot throw
|
||||
}
|
||||
else if(m.Instructions[i].NormalizedOpCode == NormalizedByteCode.__putstatic
|
||||
&& classFile.GetFieldref(m.Instructions[i].Arg1).GetClassType() == clazz)
|
||||
{
|
||||
// storing a field to the current class cannot throw
|
||||
}
|
||||
else if(ByteCodeMetaData.CanThrowException(m.Instructions[i].NormalizedOpCode))
|
||||
{
|
||||
lineNumberTable = c.lineNumbers;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
nonleaf = c.nonleaf;
|
||||
}
|
||||
finally
|
||||
|
@ -1097,26 +1098,14 @@ sealed class Compiler
|
|||
block.MarkLabel(i);
|
||||
}
|
||||
|
||||
ClassFile.Method.LineNumberTableEntry[] table = m.LineNumberTableAttribute;
|
||||
if(table != null && (symboldocument != null || lineNumbers != null))
|
||||
if(emitLineNumbers)
|
||||
{
|
||||
for(int j = 0; j < table.Length; j++)
|
||||
ClassFile.Method.LineNumberTableEntry[] table = m.LineNumberTableAttribute;
|
||||
for (int j = 0; j < table.Length; j++)
|
||||
{
|
||||
if(table[j].start_pc == code[i].PC && table[j].line_number != 0)
|
||||
{
|
||||
if(symboldocument != null)
|
||||
{
|
||||
ilGenerator.MarkSequencePoint(symboldocument, table[j].line_number, 0, table[j].line_number + 1, 0);
|
||||
// we emit a nop to make sure we always have an instruction associated with the sequence point
|
||||
ilGenerator.Emit(OpCodes.Nop);
|
||||
}
|
||||
// we only add a line number mapping if the stack is empty for two reasons:
|
||||
// 1) the CLR JIT only generates native to IL mappings for locations where the stack is empty
|
||||
// 2) GetILOffset() flushes the lazy emit stack, so if we don't do this check we miss some optimization opportunities
|
||||
if(lineNumbers != null && ilGenerator.IsStackEmpty)
|
||||
{
|
||||
lineNumbers.AddMapping(ilGenerator.GetILOffset(), table[j].line_number);
|
||||
}
|
||||
ilGenerator.SetLineNumber(table[j].line_number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче