IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ExceptionHelper.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2014 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Collections.Generic;
26using System.Diagnostics;
27using System.Reflection;
29using System.Runtime.Serialization;
30using System.Security;
31
32using IKVM.Attributes;
33
34using Interlocked = System.Threading.Interlocked;
35using MethodBase = System.Reflection.MethodBase;
36
37using ObjectInputStream = java.io.ObjectInputStream;
38using ObjectOutputStream = java.io.ObjectOutputStream;
39using ObjectStreamField = java.io.ObjectStreamField;
40using StackTraceElement = java.lang.StackTraceElement;
41using Throwable = java.lang.Throwable;
42
43namespace IKVM.Runtime
44{
45
47 {
48
49 static readonly Key EXCEPTION_DATA_KEY = new Key();
50 static readonly Exception NOT_REMAPPED = new Exception();
51 static readonly Exception[] EMPTY_THROWABLE_ARRAY = new Exception[0];
52 static readonly bool cleanStackTrace = JVM.SafeGetEnvironmentVariable("IKVM_DISABLE_STACKTRACE_CLEANING") == null;
53
54 readonly RuntimeContext context;
55 readonly Dictionary<string, string> failedTypes = new Dictionary<string, string>();
56
57#if FIRST_PASS == false
58 readonly ConditionalWeakTable<Exception, Exception> exceptions = new();
59#endif
60
66 {
67 this.context = context ?? throw new ArgumentNullException(nameof(context));
68
69#if FIRST_PASS == false
70 // make sure the exceptions map continues to work during AppDomain finalization
71 GC.SuppressFinalize(exceptions);
72#endif
73 }
74
75#if !FIRST_PASS
76
77 [Serializable]
78 internal sealed class ExceptionInfoHelper
79 {
80
81 readonly ExceptionHelper exceptionHelper;
82
83 [NonSerialized]
84 StackTrace tracePart1;
85 [NonSerialized]
86 StackTrace tracePart2;
87 StackTraceElement[] stackTrace;
88
94 internal ExceptionInfoHelper(ExceptionHelper exceptionHelper, StackTraceElement[] stackTrace)
95 {
96 this.exceptionHelper = exceptionHelper;
97 this.stackTrace = stackTrace;
98 }
99
106 internal ExceptionInfoHelper(ExceptionHelper exceptionHelper, StackTrace tracePart1, StackTrace tracePart2)
107 {
108 this.exceptionHelper = exceptionHelper;
109 this.tracePart1 = tracePart1;
110 this.tracePart2 = tracePart2;
111 }
112
119 [HideFromJava]
120 internal ExceptionInfoHelper(ExceptionHelper exceptionHelper, Exception x, bool captureAdditionalStackTrace)
121 {
122 this.exceptionHelper = exceptionHelper;
123 tracePart1 = new StackTrace(x, true);
124 if (captureAdditionalStackTrace)
125 tracePart2 = new StackTrace(true);
126 }
127
128 [OnSerializing]
129 void OnSerializing(StreamingContext context)
130 {
131 // make sure the stack trace is computed before serializing
132 get_StackTrace(null);
133 }
134
135 static bool IsPrivateScope(MethodBase mb)
136 {
137 return (mb.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope;
138 }
139
140 internal StackTraceElement[] get_StackTrace(Exception t)
141 {
142 lock (this)
143 {
144 if (stackTrace == null)
145 {
146 var list = new List<StackTraceElement>();
147
148 if (tracePart1 != null)
149 {
150 int skip1 = 0;
151 if (cleanStackTrace && t is java.lang.NullPointerException && tracePart1.FrameCount > 0)
152 {
153 // HACK if a NullPointerException originated inside an instancehelper method,
154 // we assume that the reference the method was called on was really the one that was null,
155 // so we filter it.
156 if (tracePart1.GetFrame(0).GetMethod().Name.StartsWith("instancehelper_") &&
157 !GetMethodName(tracePart1.GetFrame(0).GetMethod()).StartsWith("instancehelper_"))
158 {
159 skip1 = 1;
160 }
161 }
162
163 Append(exceptionHelper, list, tracePart1, skip1, false);
164 }
165
166 if (tracePart2 != null && tracePart2.FrameCount > 0)
167 {
168 int skip = 0;
169 if (cleanStackTrace)
170 {
171 // If fillInStackTrace was called (either directly or from the constructor),
172 // filter out fillInStackTrace and the following constructor frames.
173 if (tracePart1 == null)
174 {
175 var mb = tracePart2.GetFrame(skip).GetMethod();
176 if (mb.DeclaringType == typeof(Throwable) && mb.Name.EndsWith("fillInStackTrace", StringComparison.Ordinal))
177 {
178 skip++;
179
180 while (tracePart2.FrameCount > skip)
181 {
182 mb = tracePart2.GetFrame(skip).GetMethod();
183 if (mb.DeclaringType != typeof(Throwable) || !mb.Name.EndsWith("fillInStackTrace", StringComparison.Ordinal))
184 break;
185
186 skip++;
187 }
188
189 while (tracePart2.FrameCount > skip)
190 {
191 mb = tracePart2.GetFrame(skip).GetMethod();
192 if (mb.Name != ".ctor" || !mb.DeclaringType.IsInstanceOfType(t))
193 break;
194
195 skip++;
196 }
197 }
198 }
199 else
200 {
201 // Skip java.lang.Throwable.__<map> and other mapping methods, because we need to be able to remove the frame
202 // that called map (if it is the same as where the exception was caught).
203 while (tracePart2.FrameCount > skip && IsHideFromJava(tracePart2.GetFrame(skip).GetMethod()))
204 skip++;
205
206 if (tracePart1.FrameCount > 0 &&
207 tracePart2.FrameCount > skip &&
208 tracePart1.GetFrame(tracePart1.FrameCount - 1).GetMethod() == tracePart2.GetFrame(skip).GetMethod())
209 {
210 // skip the caller of the map method
211 skip++;
212 }
213 }
214 }
215
216 Append(exceptionHelper, list, tracePart2, skip, true);
217 }
218
219 if (cleanStackTrace && list.Count > 0)
220 {
221 var elem = list[list.Count - 1];
222 if (elem.getClassName() == "java.lang.reflect.Method")
223 list.RemoveAt(list.Count - 1);
224 }
225
226 tracePart1 = null;
227 tracePart2 = null;
228 this.stackTrace = list.ToArray();
229 }
230 }
231
232 return (StackTraceElement[])stackTrace.Clone();
233 }
234
235 internal static void Append(ExceptionHelper exceptionHelper, List<StackTraceElement> stackTrace, StackTrace st, int skip, bool isLast)
236 {
237 for (int i = skip; i < st.FrameCount; i++)
238 {
239 var frame = st.GetFrame(i);
240 var m = frame.GetMethod();
241 if (m == null)
242 continue;
243
244 var type = m.DeclaringType;
245 if (cleanStackTrace &&
246 (type == null
247 || typeof(MethodBase).IsAssignableFrom(type)
248 || type == typeof(RuntimeMethodHandle)
249 || (type == typeof(Throwable) && m.Name == "instancehelper_fillInStackTrace")
250 || (m.Name == "ToJava" && typeof(RetargetableJavaException).IsAssignableFrom(type))
251 || IsHideFromJava(m)
252 || IsPrivateScope(m))) // NOTE we assume that privatescope methods are always stubs that we should exclude
253 {
254 continue;
255 }
256
257 var lineNumber = frame.GetFileLineNumber();
258 if (lineNumber == 0)
259 lineNumber = exceptionHelper.GetLineNumber(frame);
260
261 var fileName = frame.GetFileName();
262 if (fileName != null)
263 {
264 try
265 {
266 fileName = new System.IO.FileInfo(fileName).Name;
267 }
268 catch
269 {
270 // Mono returns "<unknown>" for frame.GetFileName() and the FileInfo constructor
271 // doesn't like that
272 fileName = null;
273 }
274 }
275
276 fileName ??= exceptionHelper.GetFileName(frame);
277 stackTrace.Add(new StackTraceElement(exceptionHelper.GetClassNameFromType(type), GetMethodName(m), fileName, IsNative(m) ? -2 : lineNumber));
278 }
279
280 if (cleanStackTrace && isLast)
281 while (stackTrace.Count > 0 && stackTrace[stackTrace.Count - 1].getClassName().StartsWith("cli.System.Threading.", StringComparison.Ordinal))
282 stackTrace.RemoveAt(stackTrace.Count - 1);
283 }
284 }
285
286#endif
287
288 [Serializable]
289 sealed class Key : ISerializable
290 {
291
292 [Serializable]
293 sealed class Helper : IObjectReference
294 {
295
296 [SecurityCritical]
297 public object GetRealObject(StreamingContext context)
298 {
299 return EXCEPTION_DATA_KEY;
300 }
301
302 }
303
304 [SecurityCritical]
305 public void GetObjectData(SerializationInfo info, StreamingContext context)
306 {
307 info.SetType(typeof(Helper));
308 }
309
310 }
311
312 static bool IsNative(MethodBase m)
313 {
314 var methodFlagAttribs = m.GetCustomAttributes(typeof(ModifiersAttribute), false);
315 if (methodFlagAttribs.Length == 1)
316 {
317 var modifiersAttrib = (ModifiersAttribute)methodFlagAttribs[0];
318 return (modifiersAttrib.Modifiers & Modifiers.Native) != 0;
319 }
320
321 return false;
322 }
323
324 static string GetMethodName(MethodBase mb)
325 {
326 var attr = mb.GetCustomAttributes(typeof(NameSigAttribute), false);
327 if (attr.Length == 1)
328 {
329 return ((NameSigAttribute)attr[0]).Name;
330 }
331 else if (mb.Name == ".ctor")
332 {
333 return "<init>";
334 }
335 else if (mb.Name == ".cctor")
336 {
337 return "<clinit>";
338 }
339 else if (mb.Name.StartsWith(NamePrefix.DefaultMethod, StringComparison.Ordinal))
340 {
341 return mb.Name.Substring(NamePrefix.DefaultMethod.Length);
342 }
343 else if (mb.Name.StartsWith(NamePrefix.Bridge, StringComparison.Ordinal))
344 {
345 return mb.Name.Substring(NamePrefix.Bridge.Length);
346 }
347 else if (mb.IsSpecialName)
348 {
349 return UnicodeUtil.UnescapeInvalidSurrogates(mb.Name);
350 }
351 else
352 {
353 return mb.Name;
354 }
355 }
356
357 static bool IsHideFromJava(MethodBase mb)
358 {
359#if FIRST_PASS
360 throw new NotImplementedException();
361#else
362 return (IKVM.Java.Externs.sun.reflect.Reflection.GetHideFromJavaFlags(mb) & HideFromJavaFlags.StackTrace) != 0 || (mb.DeclaringType == typeof(ikvm.runtime.Util) && mb.Name == "mapException");
363#endif
364 }
365
366 string GetClassNameFromType(Type type)
367 {
368#if FIRST_PASS
369 throw new NotImplementedException();
370#else
371 if (type == null)
372 return "<Module>";
373
374 if (context.ClassLoaderFactory.IsRemappedType(type))
375 return RuntimeManagedJavaType.GetName(context, type);
376
377 var tw = context.ClassLoaderFactory.GetJavaTypeFromType(type);
378 if (tw != null)
379 {
380 if (tw.IsPrimitive)
381 return RuntimeManagedJavaType.GetName(context, type);
382 if (tw.IsUnsafeAnonymous)
383 return tw.ClassObject.getName();
384
385 return tw.Name;
386 }
387
388 return type.FullName;
389#endif
390 }
391
392 int GetLineNumber(StackFrame frame)
393 {
394 var ilOffset = frame.GetILOffset();
395 if (ilOffset != StackFrame.OFFSET_UNKNOWN)
396 {
397 var mb = frame.GetMethod();
398 if (mb != null && mb.DeclaringType != null)
399 {
400 if (context.ClassLoaderFactory.IsRemappedType(mb.DeclaringType))
401 return -1;
402
403 var tw = context.ClassLoaderFactory.GetJavaTypeFromType(mb.DeclaringType);
404 if (tw != null)
405 return tw.GetSourceLineNumber(mb, ilOffset);
406 }
407 }
408
409 return -1;
410 }
411
412 string GetFileName(StackFrame frame)
413 {
414 var mb = frame.GetMethod();
415 if (mb != null && mb.DeclaringType != null)
416 {
417 if (context.ClassLoaderFactory.IsRemappedType(mb.DeclaringType))
418 return null;
419
420 var tw = context.ClassLoaderFactory.GetJavaTypeFromType(mb.DeclaringType);
421 if (tw != null)
422 return tw.GetSourceFileName();
423 }
424
425 return null;
426 }
427
435 internal static object[] GetPersistentFields()
436 {
437#if FIRST_PASS
438 throw new NotImplementedException();
439#else
440 return new ObjectStreamField[]
441 {
442 new ObjectStreamField("detailMessage", typeof(global::java.lang.String)),
443 new ObjectStreamField("cause", typeof(global::java.lang.Throwable)),
444 new ObjectStreamField("stackTrace", typeof(global::java.lang.StackTraceElement[])),
445 new ObjectStreamField("suppressedExceptions", typeof(global::java.util.List))
446 };
447#endif
448 }
449
458 internal static void WriteObject(Exception e, object stream)
459 {
460#if FIRST_PASS
461 throw new NotImplementedException();
462#else
463 lock (e)
464 {
465 var fields = ((ObjectOutputStream)stream).putFields();
466 if (e is not Throwable t)
467 {
468 fields.put("detailMessage", e.Message);
469 fields.put("cause", e.InnerException);
470 // suppressed exceptions are not supported on CLR exceptions
471 fields.put("suppressedExceptions", null);
472 fields.put("stackTrace", GetOurStackTrace(e));
473 }
474 else
475 {
476 fields.put("detailMessage", t.detailMessage);
477 fields.put("cause", t.cause);
478 fields.put("suppressedExceptions", t.suppressedExceptions);
479 GetOurStackTrace(e);
480 fields.put("stackTrace", t.stackTrace ?? java.lang.ThrowableHelper.SentinelHolder.STACK_TRACE_SENTINEL);
481 }
482
483 ((ObjectOutputStream)stream).writeFields();
484 }
485#endif
486 }
487
488 internal static void ReadObject(Exception e, object stream)
489 {
490#if FIRST_PASS
491 throw new NotImplementedException();
492#else
493 lock (e)
494 {
495 // when you serialize a .NET exception it gets replaced by a com.sun.xml.internal.ws.developer.ServerSideException,
496 // so we know that Exception is always a Throwable
497 var _this = (Throwable)e;
498
499 // this the equivalent of s.defaultReadObject();
500 var fields = ((ObjectInputStream)stream).readFields();
501 var detailMessage = fields.get("detailMessage", null);
502 var cause = fields.get("cause", null);
503 var ctor = typeof(Throwable).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(Exception), typeof(bool), typeof(bool) }, null);
504 if (cause == _this)
505 {
506 ctor.Invoke(_this, [detailMessage, null, false, false]);
507 _this.cause = _this;
508 }
509 else
510 {
511 ctor.Invoke(_this, [detailMessage, cause, false, false]);
512 }
513
514 _this.stackTrace = (StackTraceElement[])fields.get("stackTrace", null);
515 _this.suppressedExceptions = (java.util.List)fields.get("suppressedExceptions", null);
516
517 // this is where the rest of the Throwable.readObject() code starts
518 if (_this.suppressedExceptions != null)
519 {
520 java.util.List suppressed = null;
521 if (_this.suppressedExceptions.isEmpty())
522 {
523 suppressed = Throwable.SUPPRESSED_SENTINEL;
524 }
525 else
526 {
527 suppressed = new java.util.ArrayList(1);
528 for (int i = 0; i < _this.suppressedExceptions.size(); i++)
529 {
530 var entry = (Exception)_this.suppressedExceptions.get(i);
531 if (entry == null)
532 throw new java.lang.NullPointerException("Cannot suppress a null exception.");
533 if (entry == _this)
534 throw new java.lang.IllegalArgumentException("Self-suppression not permitted");
535
536 suppressed.add(entry);
537 }
538 }
539
540 _this.suppressedExceptions = suppressed;
541 }
542
543 if (_this.stackTrace != null)
544 {
545 if (_this.stackTrace.Length == 0)
546 {
547 _this.stackTrace = [];
548 }
549 else if (_this.stackTrace.Length == 1 && java.lang.ThrowableHelper.SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(_this.stackTrace[0]))
550 {
551 _this.stackTrace = null;
552 }
553 else
554 {
555 foreach (var elem in _this.stackTrace)
556 if (elem == null)
557 throw new java.lang.NullPointerException("null StackTraceElement in serial stream. ");
558 }
559 }
560 else
561 {
562 _this.stackTrace = [];
563 }
564 }
565#endif
566 }
567
568 internal static string FilterMessage(string message)
569 {
570 return message ?? "";
571 }
572
573 internal static string GetMessageFromCause(Exception cause)
574 {
575#if FIRST_PASS
576 throw new NotImplementedException();
577#else
578 return cause != null ? ikvm.extensions.ExtensionMethods.toString(cause) : "";
579#endif
580 }
581
582 internal static string GetLocalizedMessage(Exception x)
583 {
584#if FIRST_PASS
585 throw new NotImplementedException();
586#else
587 return ikvm.extensions.ExtensionMethods.getMessage(x);
588#endif
589 }
590
591 internal static string ToString(Exception x)
592 {
593#if FIRST_PASS
594 throw new NotImplementedException();
595#else
596 var message = ikvm.extensions.ExtensionMethods.getLocalizedMessage(x);
597 if (message == null)
598 return ikvm.extensions.ExtensionMethods.getClass(x).getName();
599 else
600 return ikvm.extensions.ExtensionMethods.getClass(x).getName() + ": " + message;
601#endif
602 }
603
604 internal static Exception GetCause(Exception _this)
605 {
606#if FIRST_PASS
607 throw new NotImplementedException();
608#else
609 lock (_this)
610 {
611 var cause = ((Throwable)_this).cause;
612 return cause == _this ? null : cause;
613 }
614#endif
615 }
616
617 internal static void CheckInitCause(Exception self, Exception self_cause, Exception cause)
618 {
619#if FIRST_PASS
620 throw new NotImplementedException();
621#else
622 if (self_cause != self)
623 throw new java.lang.IllegalStateException("Can't overwrite cause with " + java.util.Objects.toString(cause, "a null"), self);
624
625 if (cause == self)
626 throw new java.lang.IllegalArgumentException("Self-causation not permitted", self);
627#endif
628 }
629
630 internal static void AddSuppressed(Exception self, Exception e)
631 {
632#if FIRST_PASS
633 throw new NotImplementedException();
634#else
635 lock (self)
636 {
637 if (self == e)
638 throw new java.lang.IllegalArgumentException("Self-suppression not permitted", e);
639 if (e == null)
640 throw new java.lang.NullPointerException("Cannot suppress a null exception.");
641
642 if (self is not Throwable _thisJava)
643 {
644 // we ignore suppressed exceptions for non-Java exceptions
645 }
646 else
647 {
648 if (_thisJava.suppressedExceptions == null)
649 return;
650
651 if (_thisJava.suppressedExceptions == Throwable.SUPPRESSED_SENTINEL)
652 _thisJava.suppressedExceptions = new java.util.ArrayList();
653
654 _thisJava.suppressedExceptions.add(e);
655 }
656 }
657#endif
658 }
659
660 internal static Exception[] GetSuppressed(Exception self)
661 {
662#if FIRST_PASS
663 throw new NotImplementedException();
664#else
665 lock (self)
666 {
667 if (self is not Throwable t)
668 {
669 // we ignore suppressed exceptions for non-Java exceptions
670 return EMPTY_THROWABLE_ARRAY;
671 }
672 else
673 {
674 if (t.suppressedExceptions == Throwable.SUPPRESSED_SENTINEL || t.suppressedExceptions == null)
675 return EMPTY_THROWABLE_ARRAY;
676 else
677 return (Exception[])t.suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
678 }
679 }
680#endif
681 }
682
683 internal static int GetStackTraceDepth(Exception self)
684 {
685 return GetOurStackTrace(self).Length;
686 }
687
688 internal static object GetStackTraceElement(Exception self, int index)
689 {
690 return GetOurStackTrace(self)[index];
691 }
692
700 internal static object[] GetOurStackTrace(Exception e)
701 {
702#if FIRST_PASS
703 throw new NotImplementedException();
704#else
705 if (e is not Throwable self)
706 {
707 lock (e)
708 {
709 ExceptionInfoHelper eih = null;
710 var data = e.Data;
711 if (data != null && !data.IsReadOnly)
712 lock (data.SyncRoot)
713 eih = (ExceptionInfoHelper)data[EXCEPTION_DATA_KEY];
714
715 if (eih == null)
716 return Throwable.UNASSIGNED_STACK;
717
718 return eih.get_StackTrace(e);
719 }
720 }
721 else
722 {
723 lock (self)
724 {
725 if (self.stackTrace == Throwable.UNASSIGNED_STACK || (self.stackTrace == null && (self.tracePart1 != null || self.tracePart2 != null)))
726 {
727 var eih = new ExceptionInfoHelper(JVM.Context.ExceptionHelper, self.tracePart1, self.tracePart2);
728 self.stackTrace = eih.get_StackTrace(e);
729 self.tracePart1 = null;
730 self.tracePart2 = null;
731 }
732 }
733
734 return self.stackTrace ?? Throwable.UNASSIGNED_STACK;
735 }
736#endif
737 }
738
746 internal static void SetStackTrace(Exception e, object[] stackTrace)
747 {
748#if FIRST_PASS
749 throw new NotImplementedException();
750#else
751 var stackTrace_ = (StackTraceElement[])stackTrace;
752 var copy = (StackTraceElement[])stackTrace_.Clone();
753 for (int i = 0; i < copy.Length; i++)
754 if (copy[i] == null)
755 throw new java.lang.NullPointerException();
756
757 JVM.Context.ExceptionHelper.SetStackTraceImpl(e, copy);
758#endif
759 }
760
761 void SetStackTraceImpl(Exception e, StackTraceElement[] stackTrace)
762 {
763#if FIRST_PASS
764 throw new NotImplementedException();
765#else
766 if (e is not Throwable t)
767 {
768 var eih = new ExceptionInfoHelper(this, stackTrace);
769 var data = e.Data;
770 if (data != null && !data.IsReadOnly)
771 lock (data.SyncRoot)
772 data[EXCEPTION_DATA_KEY] = eih;
773 }
774 else
775 {
776 lock (t)
777 {
778 if (t.stackTrace == null && t.tracePart1 == null && t.tracePart2 == null)
779 return;
780
781 t.stackTrace = stackTrace;
782 }
783 }
784#endif
785 }
786
794 [HideFromJava]
795 internal static void FillInStackTrace(Exception e)
796 {
797#if FIRST_PASS
798 throw new NotImplementedException();
799#else
800 lock (e)
801 {
802 var eih = new ExceptionInfoHelper(JVM.Context.ExceptionHelper, null, new StackTrace(true));
803 var data = e.Data;
804 if (data != null && !data.IsReadOnly)
805 lock (data.SyncRoot)
806 data[EXCEPTION_DATA_KEY] = eih;
807 }
808#endif
809 }
810
818 internal static void FixateException(Exception e)
819 {
820#if FIRST_PASS
821 throw new NotImplementedException();
822#else
823 JVM.Context.ExceptionHelper.FixateExceptionImpl(e);
824#endif
825 }
826 void FixateExceptionImpl(Exception e)
827 {
828#if FIRST_PASS
829 throw new NotImplementedException();
830#else
831 exceptions.Add(e, NOT_REMAPPED);
832#endif
833 }
834
835 internal static Exception UnmapException(Exception e)
836 {
837#if FIRST_PASS
838 throw new NotImplementedException();
839#else
840 return JVM.Context.ExceptionHelper.UnmapExceptionImpl(e);
841#endif
842 }
843
844 Exception UnmapExceptionImpl(Exception e)
845 {
846#if FIRST_PASS
847 throw new NotImplementedException();
848#else
849 if (e is Throwable t)
850 {
851 var org = Interlocked.Exchange(ref t.original, null);
852 if (org != null)
853 {
854 exceptions.Add(org, e);
855 e = org;
856 }
857 }
858
859 return e;
860#endif
861 }
862
863 [HideFromJava]
864 Exception MapTypeInitializeException(TypeInitializationException t, Type handler)
865 {
866#if FIRST_PASS
867 throw new NotImplementedException();
868#else
869 var wrapped = false;
870 var r = MapException<Exception>(t.InnerException, true, false);
871 if (r is not java.lang.Error)
872 {
873 // Forwarding "r" as cause only doesn't make it available in the debugger details
874 // of current versions of VS, so at least provide a text representation instead.
875 // Not wrapping at all might be the even better approach, but it was introduced for
876 // some reason I guess.
877 r = new java.lang.ExceptionInInitializerError(r.ToString());
878 wrapped = true;
879 }
880
881 var type = t.TypeName;
882 if (failedTypes.ContainsKey(type))
883 {
884 r = new java.lang.NoClassDefFoundError("Could not initialize class " + type);
885 wrapped = true;
886 }
887
888 if (handler != null && !handler.IsInstanceOfType(r))
889 return null;
890
891 failedTypes[type] = type;
892 if (wrapped)
893 {
894 // transplant the stack trace
895 ((Throwable)r).setStackTrace(new ExceptionInfoHelper(this, t, true).get_StackTrace(t));
896 }
897
898 return r;
899#endif
900 }
901
902 bool IsInstanceOfType<T>(Exception t, bool remap)
903 where T : Exception
904 {
905#if FIRST_PASS
906 throw new NotImplementedException();
907#else
908 return remap || typeof(T) != typeof(Exception) ? t is T : t is not Throwable;
909#endif
910 }
911
912 [HideFromJava]
913 internal T MapException<T>(Exception e, bool remap, bool unused)
914 where T : Exception
915 {
916#if FIRST_PASS
917 throw new NotImplementedException();
918#else
919 var org = e;
920 var nonJavaException = e is not Throwable;
921 if (nonJavaException && remap)
922 {
923 if (e is TypeInitializationException tie)
924 return (T)MapTypeInitializeException(tie, typeof(T));
925
926 exceptions.TryGetValue(e, out var obj);
927 var remapped = obj;
928 if (remapped == null)
929 {
930 remapped = Throwable.__mapImpl(e);
931 if (remapped == e)
932 exceptions.Add(e, NOT_REMAPPED);
933 else
934 exceptions.Add(e, remapped);
935
936 e = remapped;
937 }
938 else if (remapped != NOT_REMAPPED)
939 {
940 e = remapped;
941 }
942 }
943
944 if (IsInstanceOfType<T>(e, remap))
945 {
946 if (e is Throwable t)
947 {
948 if (!unused && t.tracePart1 == null && t.tracePart2 == null && t.stackTrace == Throwable.UNASSIGNED_STACK)
949 {
950 t.tracePart1 = new StackTrace(org, true);
951 t.tracePart2 = new StackTrace(true);
952 }
953 if (t != org)
954 {
955 t.original = org;
956 exceptions.Remove(org);
957 }
958 }
959 else
960 {
961 var data = e.Data;
962 if (data != null && !data.IsReadOnly)
963 {
964 lock (data.SyncRoot)
965 {
966 if (!data.Contains(EXCEPTION_DATA_KEY))
967 {
968 data.Add(EXCEPTION_DATA_KEY, new ExceptionInfoHelper(this, e, true));
969 }
970 }
971 }
972 }
973
974 if (nonJavaException && !remap)
975 exceptions.Add(e, NOT_REMAPPED);
976
977 return (T)e;
978 }
979
980 return null;
981#endif
982 }
983
984 }
985
986}
java.io.ObjectOutputStream ObjectOutputStream
java.lang.StackTraceElement StackTraceElement
java.lang.Throwable Throwable
java.io.ObjectStreamField ObjectStreamField
java.io.ObjectInputStream ObjectInputStream
System.Threading.Interlocked Interlocked
IKVM.Reflection.Type Type
IKVM.Reflection.MethodBase MethodBase
Provides the implementations of the native methods in global::sun.reflect.Reflection.
Definition Reflection.cs:40
ExceptionHelper(RuntimeContext context)
Initializes a new instance.
Main state of the running JVM.
Maintains services relevant to an instane of the IKVM runtime.