3131import java .io .DataInputStream ;
3232import java .io .DataOutputStream ;
3333import java .io .IOException ;
34- import java .lang .reflect .Constructor ;
3534import java .lang .reflect .InvocationTargetException ;
3635import java .util .ArrayList ;
3736import java .util .Arrays ;
4241
4342/**
4443 * Support for translating exceptions between the HotSpot heap and libjvmci heap.
45- *
46- * Successfully translated exceptions are wrapped in a TranslatedException instance.
47- * This allows callers to distiguish between a translated exception and an error
44+ * <p>
45+ * Apart from {@link OutOfMemoryError}s, successfully translated exceptions have
46+ * {@link #TRANSLATED_MARKER} as the first element in their stack trace. This
47+ * allows a caller to distinguish between a translated exception and an error
4848 * that arose during translation.
4949 */
5050@ SuppressWarnings ("serial" )
5151public final class TranslatedException extends Exception {
5252
53+ /**
54+ * Marker frame prepended to outermost stack of a translated exception.
55+ */
56+ public static final StackTraceElement TRANSLATED_MARKER = new StackTraceElement (TranslatedException .class .getName (), "translated" , null , -2 );
57+
5358 /**
5459 * The value returned by {@link #encodeThrowable(Throwable)} when encoding
5560 * fails due to an {@link OutOfMemoryError}.
@@ -114,7 +119,7 @@ public Throwable fillInStackTrace() {
114119 private static void debugPrintStackTrace (Throwable throwable , boolean debug ) {
115120 if (debug ) {
116121 System .err .print ("DEBUG: " );
117- throwable .printStackTrace ();
122+ throwable .printStackTrace (System . err );
118123 }
119124 }
120125
@@ -130,26 +135,71 @@ private static Throwable initCause(Throwable throwable, Throwable cause, boolean
130135 return throwable ;
131136 }
132137
138+ /**
139+ * Creates an exception if {@code className} is one of the supported
140+ * core exceptions for translation.
141+ *
142+ * @param className class name of exception to create
143+ * @param message the detailed message for the exception
144+ * @return {@code null} if {@code className} is unsupported
145+ */
146+ private static Throwable newThrowable (String className , String message ) {
147+ return switch (className ) {
148+ // Exceptions
149+ case "java.lang.ArithmeticException" -> new ArithmeticException (message );
150+ case "java.lang.ArrayIndexOutOfBoundsException" -> new ArrayIndexOutOfBoundsException (message );
151+ case "java.lang.ArrayStoreException" -> new ArrayStoreException (message );
152+ case "java.lang.ClassCastException" -> new ClassCastException (message );
153+ case "java.lang.ClassNotFoundException" -> new ClassNotFoundException (message );
154+ case "java.lang.CloneNotSupportedException" -> new CloneNotSupportedException (message );
155+ case "java.lang.IllegalAccessException" -> new IllegalAccessException (message );
156+ case "java.lang.IllegalArgumentException" -> new IllegalArgumentException (message );
157+ case "java.lang.IndexOutOfBoundsException" -> new IndexOutOfBoundsException (message );
158+ case "java.lang.InstantiationException" -> new InstantiationException (message );
159+ case "java.lang.NegativeArraySizeException" -> new NegativeArraySizeException (message );
160+ case "java.lang.NoSuchFieldException" -> new NoSuchFieldException (message );
161+ case "java.lang.NoSuchMethodException" -> new NoSuchMethodException (message );
162+ case "java.lang.NullPointerException" -> new NullPointerException (message );
163+ case "java.lang.RuntimeException" -> new RuntimeException (message );
164+ case "java.lang.StringIndexOutOfBoundsException" -> new StringIndexOutOfBoundsException (message );
165+ case "java.lang.UnsupportedOperationException" -> new UnsupportedOperationException (message );
166+
167+ // Errors
168+ case "java.lang.AbstractMethodError" -> new AbstractMethodError (message );
169+ case "java.lang.BootstrapMethodError" -> new BootstrapMethodError (message );
170+ case "java.lang.ClassCircularityError" -> new ClassCircularityError (message );
171+ case "java.lang.ClassFormatError" -> new ClassFormatError (message );
172+ case "java.lang.IllegalAccessError" -> new IllegalAccessError (message );
173+ case "java.lang.IncompatibleClassChangeError" -> new IncompatibleClassChangeError (message );
174+ case "java.lang.InstantiationError" -> new InstantiationError (message );
175+ case "java.lang.InternalError" -> new InternalError (message );
176+ case "java.lang.LinkageError" -> new LinkageError (message );
177+ case "java.lang.NoClassDefFoundError" -> new NoClassDefFoundError (message );
178+ case "java.lang.NoSuchFieldError" -> new NoSuchFieldError (message );
179+ case "java.lang.NoSuchMethodError" -> new NoSuchMethodError (message );
180+ case "java.lang.OutOfMemoryError" -> new OutOfMemoryError (message );
181+ case "java.lang.StackOverflowError" -> new StackOverflowError (message );
182+ case "java.lang.UnsatisfiedLinkError" -> new UnsatisfiedLinkError (message );
183+ default -> null ;
184+ };
185+ }
186+
133187 private static Throwable create (String className , String message , Throwable cause , boolean debug ) {
134- // Try create with reflection first.
135188 try {
136- Class <?> cls = Class .forName (className );
137- if (cause != null ) {
138- // Handle known exception types whose cause must
139- // be set in the constructor
140- if (cls == InvocationTargetException .class ) {
141- return new InvocationTargetException (cause , message );
142- }
143- if (cls == ExceptionInInitializerError .class ) {
144- return new ExceptionInInitializerError (cause );
145- }
189+ if (className .equals (InvocationTargetException .class .getName ())) {
190+ return new InvocationTargetException (cause , message );
146191 }
147- if (message == null ) {
148- Constructor <?> cons = cls .getConstructor ();
149- return initCause ((Throwable ) cons .newInstance (), cause , debug );
192+ if (className .equals (ExceptionInInitializerError .class .getName ())) {
193+ return new ExceptionInInitializerError (cause );
150194 }
151- Constructor <?> cons = cls .getDeclaredConstructor (String .class );
152- return initCause ((Throwable ) cons .newInstance (message ), cause , debug );
195+ if (className .equals (AssertionError .class .getName ())) {
196+ return initCause (new AssertionError (cause ), cause ,debug );
197+ }
198+ Throwable throwable = newThrowable (className , message );
199+ if (throwable != null ) {
200+ return initCause (throwable , cause ,debug );
201+ }
202+ return initCause (translationFailure ("%s [%s]" , message , className ), cause , debug );
153203 } catch (Throwable translationFailure ) {
154204 debugPrintStackTrace (translationFailure , debug );
155205 return initCause (translationFailure ("%s [%s]" , message , className ), cause , debug );
@@ -190,7 +240,7 @@ private static byte[] encodeThrowable(Throwable throwable,
190240 }
191241 }
192242
193- // Encode from inner most cause outwards
243+ // Encode from innermost cause outwards
194244 Collections .reverse (throwables );
195245
196246 for (Throwable current : throwables ) {
@@ -201,8 +251,7 @@ private static byte[] encodeThrowable(Throwable throwable,
201251 stackTrace = new StackTraceElement [0 ];
202252 }
203253 dos .writeInt (stackTrace .length );
204- for (int i = 0 ; i < stackTrace .length ; i ++) {
205- StackTraceElement frame = stackTrace [i ];
254+ for (StackTraceElement frame : stackTrace ) {
206255 if (frame != null ) {
207256 dos .writeUTF (emptyIfNull (frame .getClassLoaderName ()));
208257 dos .writeUTF (emptyIfNull (frame .getModuleName ()));
@@ -294,13 +343,20 @@ static Throwable decodeThrowable(byte[] encodedThrowable, boolean debug) {
294343 // Remove null entries at end of stackTrace
295344 stackTrace = Arrays .copyOf (stackTrace , stackTraceIndex );
296345 }
346+ if (dis .available () == 0 ) {
347+ // Prepend the marker frame to the outermost stack trace
348+ StackTraceElement [] newStackTrace = new StackTraceElement [stackTrace .length + 1 ];
349+ System .arraycopy (stackTrace , 0 , newStackTrace , 1 , stackTrace .length );
350+ newStackTrace [0 ] = TRANSLATED_MARKER ;
351+ stackTrace = newStackTrace ;
352+ }
297353 throwable .setStackTrace (stackTrace );
298354 cause = throwable ;
299355 }
300- return new TranslatedException ( throwable ) ;
356+ return throwable ;
301357 } catch (Throwable translationFailure ) {
302358 debugPrintStackTrace (translationFailure , debug );
303- return translationFailure ("error decoding exception: %s" , encodedThrowable );
359+ return translationFailure ("error decoding exception: %s" , Arrays . toString ( encodedThrowable ) );
304360 }
305361 }
306362}
0 commit comments