This is a patch to remove catch blocks for globally uninstantiable
exception types.  It does not do any control flow analysis to determine
what exceptions could be thrown from a particular try block (that would be
a good idea for the future).  My first try at implementing this was to
simply use the typeOracle.isInstantiatedType() test; this did not work.  
The reason is that the catch arg had already been tightened to the
nullType by global pruning.  What's really weird is that during
CaseNormalizer, we were actually generating code for "x instanceof
nullType" which is totally bogus.  I added in assertions into
CastNormalizer to ensure that instanceof and casts to the nullType don't
reach there.  Had those assertions been in before, it would have forced
the catch block optimization.

Review by: mmendez



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@391 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index 70d4589..7368151 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -155,11 +155,13 @@
 
     // @Override
     public void endVisit(JCastOperation x, Context ctx) {
+      assert (x.getCastType() != program.getTypeNull());
       recordCast(x.getCastType(), x.getExpr());
     }
 
     // @Override
     public void endVisit(JInstanceOf x, Context ctx) {
+      assert (x.getTestType() != program.getTypeNull());
       recordCast(x.getTestType(), x.getExpr());
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index 7b5311a..6c6176d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -26,15 +26,20 @@
 import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JForStatement;
 import com.google.gwt.dev.jjs.ast.JIfStatement;
+import com.google.gwt.dev.jjs.ast.JLocalRef;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JPrefixOperation;
 import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JStatement;
 import com.google.gwt.dev.jjs.ast.JTryStatement;
 import com.google.gwt.dev.jjs.ast.JUnaryOperator;
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.dev.jjs.ast.JWhileStatement;
 
+import java.util.Iterator;
+import java.util.List;
+
 /**
  * Attempts to remove dead code.
  */
@@ -173,20 +178,37 @@
     }
 
     /**
-     * Prune try statements with no body. Hoist up try statements with no
-     * catches and an empty finally.
+     * 1) Remove catch blocks whose exception type is not instantiable. 2) Prune
+     * try statements with no body. 3) Hoist up try statements with no catches
+     * and an empty finally.
      */
     public void endVisit(JTryStatement x, Context ctx) {
+      // 1) Remove catch blocks whose exception type is not instantiable.
+      List catchArgs = x.getCatchArgs();
+      List catchBlocks = x.getCatchBlocks();
+      for (Iterator itA = catchArgs.iterator(), itB = catchBlocks.iterator(); itA.hasNext();) {
+        JLocalRef localRef = (JLocalRef) itA.next();
+        itB.next();
+        JReferenceType type = (JReferenceType) localRef.getType();
+        if (!program.typeOracle.isInstantiatedType(type)
+            || type == program.getTypeNull()) {
+          itA.remove();
+          itB.remove();
+        }
+      }
+
+      // Compute properties regarding the state of this try statement
       boolean noTry = x.getTryBlock().statements.isEmpty();
       // TODO: normalize finally block handling
       boolean noFinally = (x.getFinallyBlock() == null)
           || x.getFinallyBlock().statements.isEmpty();
-      boolean noCatch = x.getCatchArgs().size() == 0;
+      boolean noCatch = catchArgs.size() == 0;
 
       if (noTry) {
-        // If the try block is empty, just remove it
+        // 2) Prune try statements with no body.
         removeMe(x, ctx);
       } else if (noCatch && noFinally) {
+        // 3) Hoist up try statements with no catches and an empty finally.
         // If there's no catch or finally, there's no point in this even being
         // a try statement, replace myself with the try block
         ctx.replaceMe(x.getTryBlock());