Retain runtime exception when amending origin information.

Wrapping in a CompilationError will result in the top-level handler stripping
the stack trace information. Rethrowing with a RuntimeException will preserve
the stack trace.

Bug: 145317871
Change-Id: I61d3ad7162af0b8e8dde40747df9b60a2304085e
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 5b3e1ed..5d12ded 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -95,6 +95,7 @@
 import com.android.tools.r8.shaking.MainDexClasses;
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
 import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
@@ -1066,18 +1067,10 @@
   private Timing rewriteCode(
       DexEncodedMethod method, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
     Origin origin = appView.appInfo().originFor(method.method.holder);
-    try {
-      return rewriteCodeInternal(method, feedback, methodProcessor, origin);
-    } catch (CompilationError e) {
-      // If rewriting throws a compilation error, attach the origin and method if missing.
-      throw e.withAdditionalOriginAndPositionInfo(origin, new MethodPosition(method.method));
-    } catch (NullPointerException e) {
-      throw new CompilationError(
-          "NullPointerException during IR Conversion",
-          e,
-          origin,
-          new MethodPosition(method.method));
-    }
+    return ExceptionUtils.withOriginAttachmentHandler(
+        origin,
+        new MethodPosition(method.method),
+        () -> rewriteCodeInternal(method, feedback, methodProcessor, origin));
   }
 
   private Timing rewriteCodeInternal(
diff --git a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
index d12c2a4..594abc2 100644
--- a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
@@ -11,12 +11,14 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.position.Position;
 import com.google.common.collect.ObjectArrays;
 import java.io.IOException;
 import java.nio.file.FileSystemException;
 import java.nio.file.Paths;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 public abstract class ExceptionUtils {
 
@@ -132,4 +134,23 @@
       throw new RuntimeException(executionException.getMessage(), cause);
     }
   }
+
+  public static <T> T withOriginAttachmentHandler(
+      Origin origin, Position position, Supplier<T> action) {
+    try {
+      return action.get();
+    } catch (CompilationError e) {
+      throw e.withAdditionalOriginAndPositionInfo(origin, position);
+    } catch (RuntimeException e) {
+      // On other exceptions attach the info in the message to ensure the stack trace is preserved.
+      if (origin == Origin.unknown() && position == Position.UNKNOWN) {
+        throw e;
+      }
+      throw new RuntimeException(
+          "Unexpected error"
+              + (position == Position.UNKNOWN ? "" : (" at " + position))
+              + (origin == Origin.unknown() ? "" : (" from input: " + origin)),
+          e);
+    }
+  }
 }