diff --git a/classpath/gnu/java/nio/channels/FileChannelImpl.java b/classpath/gnu/java/nio/channels/FileChannelImpl.java index 3f4c0ec2..75fd3c56 100644 --- a/classpath/gnu/java/nio/channels/FileChannelImpl.java +++ b/classpath/gnu/java/nio/channels/FileChannelImpl.java @@ -440,18 +440,20 @@ public abstract class FileChannelImpl extends FileChannel { Stream local = stream; stream = null; - // HACK don't close stdin because that throws a NotSupportedException (bug in System.IO.__ConsoleStream) - if(local != in.stream) + try { - try - { - local.Close(); - if(false) throw new cli.System.IO.IOException(); - } - catch(cli.System.IO.IOException x) - { - throw new IOException(x.getMessage()); - } + local.Close(); + if(false) throw new cli.System.IO.IOException(); + if(false) throw new cli.System.NotSupportedException(); + } + catch(cli.System.NotSupportedException _) + { + // FXBUG ignore this, there's a bug in System.IO.__ConsoleStream, + // it throws this exception when you try to close it. + } + catch(cli.System.IO.IOException x) + { + throw new IOException(x.getMessage()); } } } diff --git a/runtime/CodeEmitter.cs b/runtime/CodeEmitter.cs index 5a28e80e..778ed963 100644 --- a/runtime/CodeEmitter.cs +++ b/runtime/CodeEmitter.cs @@ -330,7 +330,7 @@ namespace IKVM.Internal { if(!IKVM.Internal.JVM.NoStackTraceInfo && linenums != null) { - AttributeHelper.SetLineNumberTable(mb, linenums.ToArray()); + AttributeHelper.SetLineNumberTable(mb, linenums); } } diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index 1000ed99..7587982a 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -133,7 +133,8 @@ namespace IKVM.Internal private static ConstructorInfo implementsAttribute; private static ConstructorInfo throwsAttribute; private static ConstructorInfo sourceFileAttribute; - private static ConstructorInfo lineNumberTableAttribute; + private static ConstructorInfo lineNumberTableAttribute1; + private static ConstructorInfo lineNumberTableAttribute2; private static object ParseValue(TypeWrapper tw, string val) { @@ -772,19 +773,35 @@ namespace IKVM.Internal typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(sourceFileAttribute, new object[] { filename })); } - internal static void SetLineNumberTable(MethodBase mb, byte[] table) + internal static void SetLineNumberTable(MethodBase mb, IKVM.Attributes.LineNumberTableAttribute.LineNumberWriter writer) { - if(lineNumberTableAttribute == null) + object arg; + ConstructorInfo con; + if(writer.Count == 1) { - lineNumberTableAttribute = typeof(LineNumberTableAttribute).GetConstructor(new Type[] { typeof(byte[]) }); - } - if(mb is ConstructorBuilder) - { - ((ConstructorBuilder)mb).SetCustomAttribute(new CustomAttributeBuilder(lineNumberTableAttribute, new object[] { table })); + if(lineNumberTableAttribute2 == null) + { + lineNumberTableAttribute2 = typeof(LineNumberTableAttribute).GetConstructor(new Type[] { typeof(ushort) }); + } + con = lineNumberTableAttribute2; + arg = (ushort)writer.LineNo; } else { - ((MethodBuilder)mb).SetCustomAttribute(new CustomAttributeBuilder(lineNumberTableAttribute, new object[] { table })); + if(lineNumberTableAttribute1 == null) + { + lineNumberTableAttribute1 = typeof(LineNumberTableAttribute).GetConstructor(new Type[] { typeof(byte[]) }); + } + con = lineNumberTableAttribute1; + arg = writer.ToArray(); + } + if(mb is ConstructorBuilder) + { + ((ConstructorBuilder)mb).SetCustomAttribute(new CustomAttributeBuilder(con, new object[] { arg })); + } + else + { + ((MethodBuilder)mb).SetCustomAttribute(new CustomAttributeBuilder(con, new object[] { arg })); } } } diff --git a/runtime/attributes.cs b/runtime/attributes.cs index d0c90172..cf3d477a 100644 --- a/runtime/attributes.cs +++ b/runtime/attributes.cs @@ -49,6 +49,13 @@ namespace IKVM.Attributes { private byte[] table; + public LineNumberTableAttribute(ushort lineno) + { + LineNumberWriter w = new LineNumberWriter(1); + w.AddMapping(0, lineno); + table = w.ToArray(); + } + public LineNumberTableAttribute(byte[] table) { this.table = table; @@ -59,6 +66,7 @@ namespace IKVM.Attributes private System.IO.MemoryStream stream; private int prevILOffset; private int prevLineNum; + private int count; internal LineNumberWriter(int estimatedCount) { @@ -67,10 +75,75 @@ namespace IKVM.Attributes internal void AddMapping(int ilOffset, int linenumber) { - WritePackedInteger(ilOffset - prevILOffset); - WritePackedInteger(linenumber - prevLineNum); + if(count == 0) + { + if(ilOffset == 0 && linenumber != 0) + { + prevLineNum = linenumber; + count++; + WritePackedInteger(linenumber - (64 + 50)); + return; + } + else + { + prevLineNum = linenumber & ~3; + WritePackedInteger(((-prevLineNum / 4) - (64 + 50))); + } + } + bool pc_overflow; + bool lineno_overflow; + byte lead; + int deltaPC = ilOffset - prevILOffset; + if(deltaPC >= 0 && deltaPC < 31) + { + lead = (byte)deltaPC; + pc_overflow = false; + } + else + { + lead = (byte)31; + pc_overflow = true; + } + int deltaLineNo = linenumber - prevLineNum; + const int bias = 2; + if(deltaLineNo >= -bias && deltaLineNo < 7 - bias) + { + lead |= (byte)((deltaLineNo + bias) << 5); + lineno_overflow = false; + } + else + { + lead |= (byte)(7 << 5); + lineno_overflow = true; + } + stream.WriteByte(lead); + if(pc_overflow) + { + WritePackedInteger(deltaPC - (64 + 31)); + } + if(lineno_overflow) + { + WritePackedInteger(deltaLineNo); + } prevILOffset = ilOffset; prevLineNum = linenumber; + count++; + } + + internal int Count + { + get + { + return count; + } + } + + internal int LineNo + { + get + { + return prevLineNum; + } } internal byte[] ToArray() @@ -154,17 +227,38 @@ namespace IKVM.Attributes public int GetLineNumber(int ilOffset) { + int i = 0; int prevILOffset = 0; - int prevLineNum = 0; - int line = -1; - for(int i = 0; i < table.Length;) + int prevLineNum = ReadPackedInteger(ref i) + (64 + 50); + int line; + if(prevLineNum > 0) { - int currILOffset = ReadPackedInteger(ref i) + prevILOffset; + line = prevLineNum; + } + else + { + prevLineNum = 4 * -prevLineNum; + line = -1; + } + while(i < table.Length) + { + byte lead = table[i++]; + int deltaPC = lead & 31; + int deltaLineNo = (lead >> 5) - 2; + if(deltaPC == 31) + { + deltaPC = ReadPackedInteger(ref i) + (64 + 31); + } + if(deltaLineNo == 5) + { + deltaLineNo = ReadPackedInteger(ref i); + } + int currILOffset = prevILOffset + deltaPC; if(currILOffset > ilOffset) { return line; } - line = ReadPackedInteger(ref i) + prevLineNum; + line = prevLineNum + deltaLineNo; prevILOffset = currILOffset; prevLineNum = line; } diff --git a/runtime/compiler.cs b/runtime/compiler.cs index 1a76a0b4..f00d5e21 100644 --- a/runtime/compiler.cs +++ b/runtime/compiler.cs @@ -844,7 +844,7 @@ class Compiler } if(c.lineNumbers != null) { - AttributeHelper.SetLineNumberTable(mw.GetMethod(), c.lineNumbers.ToArray()); + AttributeHelper.SetLineNumberTable(mw.GetMethod(), c.lineNumbers); } // HACK because of the bogus Leave instruction that Reflection.Emit generates, this location // sometimes appears reachable (it isn't), so we emit a bogus branch to keep the verifier happy.