Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2003-12-20 01:19:18 +0300
committerjfrijters <jfrijters>2003-12-20 01:19:18 +0300
commit244e221345fcd0779c1fbb6dace011618b546704 (patch)
tree9021d2659b6abeb7f1945c965607cea245e5cb37 /classpath/java/lang/ExceptionHelper.java
parent6b691380d26cb7d41ec4949cc66ad5caff8b0a66 (diff)
*** empty log message ***
Diffstat (limited to 'classpath/java/lang/ExceptionHelper.java')
-rw-r--r--classpath/java/lang/ExceptionHelper.java510
1 files changed, 510 insertions, 0 deletions
diff --git a/classpath/java/lang/ExceptionHelper.java b/classpath/java/lang/ExceptionHelper.java
new file mode 100644
index 00000000..6f021e3a
--- /dev/null
+++ b/classpath/java/lang/ExceptionHelper.java
@@ -0,0 +1,510 @@
+/*
+ Copyright (C) 2003 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+package java.lang;
+
+public final class ExceptionHelper
+{
+ // the contents of the NULL_STRING should be empty (because when the exception propagates to other .NET code
+ // it will return that text as the Message property), but it *must* be a copy, because we need to be
+ // able to distinguish it from a user specified blank string
+ private static final String NULL_STRING = new String();
+ private static final java.util.WeakHashMap exceptions = new java.util.WeakHashMap();
+ private static final boolean cleanStackTrace = System.getProperty("ikvm.cleanstacktrace", "1").equals("1");
+
+ private static class ExceptionInfoHelper
+ {
+ private static final Throwable CAUSE_NOT_SET = cli.System.Exception.__new();
+ private cli.System.Diagnostics.StackTrace tracePart1;
+ private cli.System.Diagnostics.StackTrace tracePart2;
+ private cli.System.Collections.ArrayList stackTrace;
+ private Throwable cause;
+
+ ExceptionInfoHelper(Throwable x)
+ {
+ tracePart1 = new cli.System.Diagnostics.StackTrace(x, true);
+ tracePart2 = new cli.System.Diagnostics.StackTrace(true);
+ cause = cli.System.Exception.get_InnerException(x);
+ if(cause == null)
+ {
+ cause = CAUSE_NOT_SET;
+ }
+ }
+
+ Throwable get_Cause()
+ {
+ return cause == CAUSE_NOT_SET ? null : cause;
+ }
+
+ void set_Cause(Throwable value)
+ {
+ if(cause == CAUSE_NOT_SET)
+ {
+ cause = value;
+ }
+ else
+ {
+ throw new IllegalStateException("Throwable cause already initialized");
+ }
+ }
+
+ void ResetStackTrace()
+ {
+ stackTrace = null;
+ tracePart1 = new cli.System.Diagnostics.StackTrace(true);
+ tracePart2 = null;
+ }
+
+ private static boolean IsPrivateScope(cli.System.Reflection.MethodBase mb)
+ {
+ // HACK shouldn't there be a better way to determine whether a method is privatescope?
+ return !mb.get_IsPrivate() && !mb.get_IsFamily() && !mb.get_IsFamilyAndAssembly() &&
+ !mb.get_IsFamilyOrAssembly() && !mb.get_IsPublic();
+ }
+
+ StackTraceElement[] get_StackTrace()
+ {
+ if(stackTrace == null)
+ {
+ stackTrace = new cli.System.Collections.ArrayList();
+ Append(stackTrace, tracePart1);
+ if(tracePart2 != null)
+ {
+ Append(stackTrace, tracePart2);
+ }
+ tracePart1 = null;
+ tracePart2 = null;
+ if(cleanStackTrace)
+ {
+ int chop = 0;
+ for(int i = stackTrace.get_Count() - 1; i >= 0; i--)
+ {
+ StackTraceElement ste = (StackTraceElement)stackTrace.get_Item(i);
+ if(ste.getClassName().equals("System.Reflection.MethodBase"))
+ {
+ // skip method invocation by reflection, if it is at the top of the stack
+ chop++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ stackTrace.RemoveRange(stackTrace.get_Count() - chop, chop);
+ }
+ }
+ StackTraceElement[] array = new StackTraceElement[stackTrace.get_Count()];
+ stackTrace.CopyTo((cli.System.Array)(Object)array);
+ return array;
+ }
+
+ void set_StackTrace(StackTraceElement[] value)
+ {
+ stackTrace = new cli.System.Collections.ArrayList((cli.System.Collections.ICollection)(Object)value);
+ tracePart1 = null;
+ tracePart2 = null;
+ }
+
+ public static void Append(cli.System.Collections.ArrayList stackTrace, cli.System.Diagnostics.StackTrace st)
+ {
+ if(st.get_FrameCount() > 0)
+ {
+ int baseSize = stackTrace.get_Count();
+ for(int i = 0; i < st.get_FrameCount(); i++)
+ {
+ cli.System.Diagnostics.StackFrame frame = st.GetFrame(i);
+ cli.System.Reflection.MethodBase m = frame.GetMethod();
+ // TODO I may need more safety checks like these
+ if(m == null || m.get_DeclaringType() == null || m.get_ReflectedType() == null)
+ {
+ continue;
+ }
+ if(cleanStackTrace &&
+ (m.get_DeclaringType().IsSubclassOf(typeof(cli.System.Reflection.MethodInfo.class))
+ || IsPrivateScope(m))) // NOTE we assume that privatescope methods are always stubs that we should exclude
+ {
+ continue;
+ }
+ String methodName = frame.GetMethod().get_Name();
+ if(methodName.equals(".ctor"))
+ {
+ methodName = "<init>";
+ }
+ else if(methodName.equals(".cctor"))
+ {
+ methodName = "<clinit>";
+ }
+ int lineNumber = frame.GetFileLineNumber();
+ if(lineNumber == 0)
+ {
+ lineNumber = -1;
+ }
+ String fileName = frame.GetFileName();
+ if(fileName != null)
+ {
+ try
+ {
+ fileName = new cli.System.IO.FileInfo(fileName).get_Name();
+ }
+ catch(Throwable x)
+ {
+ // Mono returns "<unknown>" for frame.GetFileName() and the FileInfo constructor
+ // doesn't like that
+ fileName = null;
+ }
+ }
+ String className = getClassNameFromType(frame.GetMethod().get_ReflectedType());
+ stackTrace.Add(new StackTraceElement(fileName, lineNumber, className, methodName, IsNative(m)));
+ }
+ }
+ }
+ }
+
+ private static native boolean IsNative(cli.System.Reflection.MethodBase mb);
+ private static native String getClassNameFromType(cli.System.Type type);
+
+ public static void printStackTrace(Throwable x)
+ {
+ printStackTrace(x, System.err);
+ }
+
+ public static void printStackTrace(Throwable x, java.io.PrintStream printStream)
+ {
+ printStream.print(buildStackTrace(x));
+ }
+
+ public static void printStackTrace(Throwable x, java.io.PrintWriter printWriter)
+ {
+ printWriter.print(buildStackTrace(x));
+ }
+
+ private static String buildStackTrace(Throwable x)
+ {
+ if(x == null)
+ {
+ throw new NullPointerException();
+ }
+ String newline = cli.System.Environment.get_NewLine();
+ StringBuffer sb = new StringBuffer();
+ sb.append(x).append(newline);
+ StackTraceElement[] stack = x.getStackTrace();
+ for(int i = 0; i < stack.length; i++)
+ {
+ sb.append("\tat ").append(stack[i]).append(newline);
+ }
+ Throwable cause = x.getCause();
+ while(cause != null)
+ {
+ sb.append("Caused by: ").append(cause).append(newline);
+
+ // Cause stacktrace
+ StackTraceElement[] parentStack = stack;
+ stack = cause.getStackTrace();
+ boolean equal = false; // Is rest of stack equal to parent frame?
+ for(int i = 0; i < stack.length && !equal; i++)
+ {
+ // Check if we already printed the rest of the stack
+ // since it was the tail of the parent stack
+ int remaining = stack.length - i;
+ int element = i;
+ int parentElement = parentStack.length - remaining;
+ equal = parentElement >= 0 && parentElement < parentStack.length;
+ while(equal && element < stack.length)
+ {
+ if(stack[element].equals(parentStack[parentElement]))
+ {
+ element++;
+ parentElement++;
+ }
+ else
+ {
+ equal = false;
+ }
+ }
+ // Print stacktrace element or indicate the rest is equal
+ if(!equal)
+ {
+ sb.append("\tat ").append(stack[i]).append(newline);
+ }
+ else
+ {
+ sb.append("\t... ").append(remaining).append(" more").append(newline);
+ break; // from stack printing for loop
+ }
+ }
+ cause = cause.getCause();
+ }
+ return sb.toString();
+ }
+
+ public static Throwable initCause(Throwable x, Throwable cause)
+ {
+ if(x == null)
+ {
+ throw new NullPointerException();
+ }
+ if(cause == x)
+ {
+ throw new IllegalArgumentException("Cause cannot be self");
+ }
+ ExceptionInfoHelper eih = (ExceptionInfoHelper)exceptions.get(x);
+ if(eih == null)
+ {
+ eih = new ExceptionInfoHelper(x);
+ exceptions.put(x, eih);
+ }
+ eih.set_Cause(cause);
+ return x;
+ }
+
+ public static Throwable getCause(Throwable x)
+ {
+ if(x == null)
+ {
+ throw new NullPointerException();
+ }
+ ExceptionInfoHelper eih = (ExceptionInfoHelper)exceptions.get(x);
+ if(eih == null)
+ {
+ return cli.System.Exception.get_InnerException(x);
+ }
+ return eih.get_Cause();
+ }
+
+ public static StackTraceElement[] getStackTrace(Throwable x)
+ {
+ if(x == null)
+ {
+ throw new NullPointerException();
+ }
+ ExceptionInfoHelper ei = (ExceptionInfoHelper)exceptions.get(x);
+ if(ei == null)
+ {
+ return new StackTraceElement[0];
+ }
+ return ei.get_StackTrace();
+ }
+
+ public static void setStackTrace(Throwable x, StackTraceElement[] stackTrace)
+ {
+ if(x == null)
+ {
+ throw new NullPointerException();
+ }
+ for(int i = 0; i < stackTrace.length; i++)
+ {
+ if(stackTrace[i] == null)
+ {
+ throw new NullPointerException();
+ }
+ }
+ ExceptionInfoHelper ei = (ExceptionInfoHelper)exceptions.get(x);
+ if(ei == null)
+ {
+ ei = new ExceptionInfoHelper(x);
+ exceptions.put(x, ei);
+ }
+ ei.set_StackTrace(stackTrace);
+ }
+
+ public static String get_NullString()
+ {
+ return NULL_STRING;
+ }
+
+ public static String FilterMessage(String message)
+ {
+ if(message == null)
+ {
+ message = NULL_STRING;
+ }
+ return message;
+ }
+
+ public static String GetMessageFromCause(Throwable cause)
+ {
+ if(cause == null)
+ {
+ return NULL_STRING;
+ }
+ return cause.toString();
+ }
+
+ public static String getMessage(Throwable x)
+ {
+ String message = cli.System.Exception.get_Message(x);
+ if(message == NULL_STRING)
+ {
+ message = null;
+ }
+ return message;
+ }
+
+ public static String getLocalizedMessage(Throwable x)
+ {
+ return x.getMessage();
+ }
+
+ public static Throwable fillInStackTrace(Throwable x)
+ {
+ if(x == null)
+ {
+ throw new NullPointerException();
+ }
+ ExceptionInfoHelper eih = (ExceptionInfoHelper)exceptions.get(x);
+ if(eih == null)
+ {
+ eih = new ExceptionInfoHelper(x);
+ exceptions.put(x, eih);
+ }
+ else
+ {
+ eih.ResetStackTrace();
+ }
+ return x;
+ }
+
+ public static String toString(Throwable x)
+ {
+ String message = x.getLocalizedMessage();
+ if(message == null)
+ {
+ return x.getClass().getName();
+ }
+ return x.getClass().getName() + ": " + message;
+ }
+
+ public static Throwable MapExceptionFast(Throwable t)
+ {
+ if(exceptions.containsKey(t))
+ {
+ return t;
+ }
+ return MapException(t, typeof(Throwable.class));
+ }
+
+ private static native Throwable MapExceptionImpl(Throwable t);
+
+ public static Throwable MapException(Throwable t, cli.System.Type handler)
+ {
+ //Console.WriteLine("MapException: {0}, {1}", t, handler);
+ //Console.WriteLine(new StackTrace(t));
+ Throwable org = t;
+
+ t = MapExceptionImpl(t);
+
+// cli.System.Type type = cli.System.Object.GetType(t);
+// // TODO don't remap if the exception already has associated ExceptionInfoHelper object (this means
+// // that the .NET exception was thrown from Java code, explicitly).
+// if(type == typeof(cli.System.NullReferenceException.class))
+// {
+// t = new NullPointerException();
+// }
+// // HACK many of the String and Object methods throw ArgumentNullException where Java throws an NPE
+// else if(type == typeof(cli.System.ArgumentNullException.class))
+// {
+// t = new NullPointerException();
+// }
+// else if(type == typeof(cli.System.IndexOutOfRangeException.class))
+// {
+// t = new ArrayIndexOutOfBoundsException();
+// }
+// // HACK for String methods, we remap ArgumentOutOfRangeException to StringIndexOutOfBoundsException
+// else if(type == typeof(cli.System.ArgumentOutOfRangeException.class))
+// {
+// t = new StringIndexOutOfBoundsException();
+// }
+// else if(type == typeof(cli.System.InvalidCastException.class))
+// {
+// t = new ClassCastException();
+// }
+// else if(type == typeof(cli.System.TypeInitializationException.class))
+// {
+// t = MapExceptionFast(cli.System.Exception.get_InnerException(t));
+// if(!(t instanceof Error))
+// {
+// t = new ExceptionInInitializerError(t);
+// }
+// }
+// else if(type == typeof(cli.System.Threading.SynchronizationLockException.class))
+// {
+// t = new IllegalMonitorStateException();
+// }
+// else if(type == typeof(cli.System.Threading.ThreadInterruptedException.class))
+// {
+// t = new InterruptedException();
+// }
+// else if(type == typeof(cli.System.OutOfMemoryException.class))
+// {
+// t = new OutOfMemoryError();
+// }
+// else if(type == typeof(cli.System.DivideByZeroException.class))
+// {
+// t = new ArithmeticException("/ by zero");
+// }
+// else if(type == typeof(cli.System.ArrayTypeMismatchException.class))
+// {
+// t = new ArrayStoreException();
+// }
+// else if(type == typeof(cli.System.StackOverflowException.class))
+// {
+// t = new StackOverflowError();
+// }
+// else if(type == typeof(cli.System.Security.VerificationException.class))
+// {
+// t = new VerifyError();
+// }
+// else if(type == typeof(cli.System.Threading.ThreadAbortException.class))
+// {
+// cli.System.Threading.ThreadAbortException abort = (cli.System.Threading.ThreadAbortException)t;
+// if(abort.get_ExceptionState() instanceof Throwable)
+// {
+// t = (Throwable)abort.get_ExceptionState();
+// }
+// else
+// {
+// t = new ThreadDeath();
+// }
+// cli.System.Threading.Thread.ResetAbort();
+// }
+// else if(type == typeof(cli.System.OverflowException.class))
+// {
+// // TODO make sure the originating method was from an IKVM.NET generated assembly, because if it was
+// // generated by non-Java code, this remapping is obviously bogus.
+// t = new NegativeArraySizeException();
+// }
+
+ if(!exceptions.containsKey(t))
+ {
+ exceptions.put(t, new ExceptionInfoHelper(org));
+ Throwable inner = cli.System.Exception.get_InnerException(org);
+ if(inner != null && !exceptions.containsKey(inner))
+ {
+ exceptions.put(inner, new ExceptionInfoHelper(inner));
+ }
+ }
+ return handler.IsInstanceOfType(t) ? t : null;
+ }
+
+ private static native cli.System.Type typeof(Class c);
+}