Fixes missing unwrapping logic in emulated stack mode.

This was causing JavaScript errors to propagate as wrapped
object incorrectly.

Change-Id: I79143f7683c31bb2e5d117bba9c0ecf6eaea2aa4
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java b/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
index bb7f1ff..0faa7ad 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
@@ -458,7 +458,7 @@
 
     private JsCatch makeSyntheticCatchBlock(JsTry x) {
       /*
-       * catch (e) { e = wrap(e); throw e; }
+       * catch (e) { e = wrap(e); throw unwrap(e); }
        */
       SourceInfo info = x.getSourceInfo();
 
@@ -473,8 +473,12 @@
       JsBinaryOperation asg = new JsBinaryOperation(info, JsBinaryOperator.ASG,
           paramName.makeRef(info), wrapCall);
 
-      // throw e
-      JsThrow throwStatement = new JsThrow(info, paramName.makeRef(info));
+      // unwrap(e)
+      JsInvocation unwrapCall =
+          new JsInvocation(info, unwrapFunctionName.makeRef(info), paramName.makeRef(info));
+
+      // throw unwrap(e)
+      JsThrow throwStatement = new JsThrow(info, unwrapCall);
 
       JsBlock body = new JsBlock(info);
       body.getStatements().add(asg.makeStmt());
@@ -968,6 +972,7 @@
   }
 
   private JsName wrapFunctionName;
+  private JsName unwrapFunctionName;
   private JsName lineNumbers;
   private JProgram jprogram;
   private final JsProgram jsProgram;
@@ -1008,10 +1013,13 @@
   private void execImpl() {
     wrapFunctionName =
         JsUtils.getJsNameForMethod(jjsmap, jprogram, RuntimeConstants.EXCEPTIONS_WRAP);
+    unwrapFunctionName =
+        JsUtils.getJsNameForMethod(jjsmap, jprogram, RuntimeConstants.EXCEPTIONS_UNWRAP);
     if (wrapFunctionName == null) {
       // No exceptions caught? Weird, but possible.
       return;
     }
+    assert unwrapFunctionName != null;
     initNames();
     makeVars();
     (new ReplaceUnobfuscatableNames()).accept(jsProgram);
diff --git a/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java b/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java
index e679535..9faa5e6 100644
--- a/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java
+++ b/user/test/com/google/gwt/core/client/JavaScriptExceptionTest.java
@@ -107,6 +107,20 @@
     };
   }
 
+  private static boolean keepFinallyAlive = false;
+
+  private static Runnable wrapWithFinally(final Runnable runnable) {
+    return new Runnable() {
+      @Override public void run() {
+        try {
+          runnable.run();
+        } finally {
+          keepFinallyAlive = true;
+        }
+      }
+    };
+  }
+
   private static void assertJavaScriptException(Object expected, Throwable exception) {
     assertTrue(exception instanceof JavaScriptException);
     assertEquals(expected, ((JavaScriptException) exception).getThrown());
@@ -142,6 +156,17 @@
     assertJavaScriptException(jso, catchJava(createThrowRunnable(e)));
   }
 
+  public void testCatchNativePropagatedFromFinally() {
+    RuntimeException e = new RuntimeException();
+    assertSame(e, catchNative(wrapWithFinally(createThrowRunnable(e))));
+
+    JavaScriptObject jso = makeJSO();
+    e = new JavaScriptException(jso);
+    assertSame(jso, catchNative(wrapWithFinally(createThrowRunnable(e))));
+
+    assertTrue(keepFinallyAlive);
+  }
+
   // java throw -> jsni catch -> jsni throw -> java catch
   public void testJavaNativeJavaSandwichCatch() {
     RuntimeException e = new RuntimeException();