1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / TryStatement.java
index d64dc60..bf4c55a 100644 (file)
@@ -1,18 +1,16 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v0.5 
+ * are made available under the terms of the Common Public License v1.0
  * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.ast;
 
-import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
-import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
-import net.sourceforge.phpdt.internal.compiler.codegen.ExceptionLabel;
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
 import net.sourceforge.phpdt.internal.compiler.flow.ExceptionHandlingFlowContext;
 import net.sourceforge.phpdt.internal.compiler.flow.FinallyFlowContext;
@@ -28,54 +26,69 @@ import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
 
 public class TryStatement extends Statement {
-       
+
        public Block tryBlock;
+
        public Block[] catchBlocks;
+
        public Argument[] catchArguments;
+
        public Block finallyBlock;
+
        BlockScope scope;
 
        public boolean subRoutineCannotReturn = true;
+
+       public UnconditionalFlowInfo subRoutineInits;
+
        // should rename into subRoutineComplete to be set to false by default
 
        ReferenceBinding[] caughtExceptionTypes;
+
        boolean tryBlockExit;
+
        boolean[] catchExits;
+
        public int[] preserveExceptionHandler;
 
        Label subRoutineStartLabel;
-       public LocalVariableBinding anyExceptionVariable,
-               returnAddressVariable,
-               secretReturnValue;
+
+       public LocalVariableBinding anyExceptionVariable, returnAddressVariable,
+                       secretReturnValue;
 
        public final static char[] SecretReturnName = " returnAddress".toCharArray(); //$NON-NLS-1$
+
        public final static char[] SecretAnyHandlerName = " anyExceptionHandler".toCharArray(); //$NON-NLS-1$
+
        public static final char[] SecretLocalDeclarationName = " returnValue".toCharArray(); //$NON-NLS-1$
 
        // for local variables table attributes
        int preTryInitStateIndex = -1;
+
        int mergedInitStateIndex = -1;
 
-       public FlowInfo analyseCode(
-               BlockScope currentScope,
-               FlowContext flowContext,
-               FlowInfo flowInfo) {
+       public FlowInfo analyseCode(BlockScope currentScope,
+                       FlowContext flowContext, FlowInfo flowInfo) {
 
-               // Consider the try block and catch block so as to compute the intersection of initializations and      
-               // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its
-               // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not
+               // Consider the try block and catch block so as to compute the
+               // intersection of initializations and
+               // the minimum exit relative depth amongst all of them. Then consider
+               // the subroutine, and append its
+               // initialization to the try/catch ones, if the subroutine completes
+               // normally. If the subroutine does not
                // complete, then only keep this result for the rest of the analysis
 
-               // process the finally block (subroutine) - create a context for the subroutine
+               // process the finally block (subroutine) - create a context for the
+               // subroutine
 
-               preTryInitStateIndex =
-                       currentScope.methodScope().recordInitializationStates(flowInfo);
+               preTryInitStateIndex = currentScope.methodScope()
+                               .recordInitializationStates(flowInfo);
 
                if (anyExceptionVariable != null) {
-                       anyExceptionVariable.used = true;
+                       anyExceptionVariable.useFlag = LocalVariableBinding.USED;
                }
                if (returnAddressVariable != null) {
-                       returnAddressVariable.used = true;
+                       returnAddressVariable.useFlag = LocalVariableBinding.USED;
                }
                InsideSubRoutineFlowContext insideSubContext;
                FinallyFlowContext finallyContext;
@@ -87,95 +100,103 @@ public class TryStatement extends Statement {
                        subInfo = null;
                } else {
                        // analyse finally block first
-                       insideSubContext = new InsideSubRoutineFlowContext(flowContext, this);
-                       subInfo =
-                               finallyBlock
-                                       .analyseCode(
-                                               currentScope,
-                                               finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
-                                               flowInfo.copy())
+                       insideSubContext = new InsideSubRoutineFlowContext(flowContext,
+                                       this);
+                       subInfo = finallyBlock.analyseCode(
+                                       currentScope,
+                                       finallyContext = new FinallyFlowContext(flowContext,
+                                                       finallyBlock), flowInfo.copy())
                                        .unconditionalInits();
-                       if (!((subInfo == FlowInfo.DeadEnd) || subInfo.isFakeReachable())) {
+                       if (subInfo.isReachable()) {
                                subRoutineCannotReturn = false;
                        }
+                       this.subRoutineInits = subInfo;
                }
                // process the try block in a context handling the local exceptions.
-               ExceptionHandlingFlowContext handlingContext =
-                       new ExceptionHandlingFlowContext(
+               ExceptionHandlingFlowContext handlingContext = new ExceptionHandlingFlowContext(
                                insideSubContext == null ? flowContext : insideSubContext,
-                               tryBlock,
-                               caughtExceptionTypes,
-                               scope,
-                               flowInfo.unconditionalInits());
+                               tryBlock, caughtExceptionTypes, scope, flowInfo
+                                               .unconditionalInits());
 
                FlowInfo tryInfo;
                if (tryBlock.statements == null) {
                        tryInfo = flowInfo;
                        tryBlockExit = false;
                } else {
-                       tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
-                       tryBlockExit = (tryInfo == FlowInfo.DeadEnd) || tryInfo.isFakeReachable();
+                       tryInfo = tryBlock.analyseCode(currentScope, handlingContext,
+                                       flowInfo.copy());
+                       tryBlockExit = !tryInfo.isReachable();
                }
 
                // check unreachable catch blocks
-               handlingContext.complainIfUnusedExceptionHandlers(catchBlocks, scope, this);
+               // handlingContext.complainIfUnusedExceptionHandlers(catchBlocks, scope,
+               // this);
 
-               // process the catch blocks - computing the minimal exit depth amongst try/catch
+               // process the catch blocks - computing the minimal exit depth amongst
+               // try/catch
                if (catchArguments != null) {
                        int catchCount;
                        catchExits = new boolean[catchCount = catchBlocks.length];
                        for (int i = 0; i < catchCount; i++) {
-                               // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis)
-                               ///*
-                               FlowInfo catchInfo =
-                                       flowInfo
-                                               .copy()
-                                               .unconditionalInits()
+                               // keep track of the inits that could potentially have led to
+                               // this exception handler (for final assignments diagnosis)
+                               FlowInfo catchInfo = flowInfo.copy().unconditionalInits()
+                                               .addPotentialInitializationsFrom(
+                                                               handlingContext.initsOnException(
+                                                                               caughtExceptionTypes[i])
+                                                                               .unconditionalInits())
+                                               .addPotentialInitializationsFrom(
+                                                               tryInfo.unconditionalInits())
                                                .addPotentialInitializationsFrom(
-                                                       handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits())
-                                               .addPotentialInitializationsFrom(tryInfo.unconditionalInits())
-                                               .addPotentialInitializationsFrom(handlingContext.initsOnReturn);
+                                                               handlingContext.initsOnReturn);
 
                                // catch var is always set
                                catchInfo.markAsDefinitelyAssigned(catchArguments[i].binding);
                                /*
-                               "If we are about to consider an unchecked exception handler, potential inits may have occured inside
-                               the try block that need to be detected , e.g. 
-                               try { x = 1; throwSomething();} catch(Exception e){ x = 2} "
-                               "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index])
-                               ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]."
-                               */
+                                * "If we are about to consider an unchecked exception handler,
+                                * potential inits may have occured inside the try block that
+                                * need to be detected , e.g. try { x = 1; throwSomething();}
+                                * catch(Exception e){ x = 2} " "(uncheckedExceptionTypes notNil
+                                * and: [uncheckedExceptionTypes at: index]) ifTrue: [catchInits
+                                * addPotentialInitializationsFrom: tryInits]."
+                                */
+                               // TODO: should only tag as unreachable if the catchblock cannot
+                               // be reached
+                               // ??? if
+                               // (!handlingContext.initsOnException(caughtExceptionTypes[i]).isReachable()){
                                if (tryBlock.statements == null) {
-                                       catchInfo.markAsFakeReachable(true);
+                                       catchInfo.setReachMode(FlowInfo.UNREACHABLE);
                                }
-                               catchInfo =
-                                       catchBlocks[i].analyseCode(
-                                               currentScope,
-                                               insideSubContext == null ? flowContext : insideSubContext,
-                                               catchInfo);
-                               catchExits[i] =
-                                       ((catchInfo == FlowInfo.DeadEnd) || catchInfo.isFakeReachable());
+                               catchInfo = catchBlocks[i].analyseCode(currentScope,
+                                               insideSubContext == null ? flowContext
+                                                               : insideSubContext, catchInfo);
+                               catchExits[i] = !catchInfo.isReachable();
                                tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
                        }
                }
                if (subRoutineStartLabel == null) {
-                       mergedInitStateIndex =
-                               currentScope.methodScope().recordInitializationStates(tryInfo);
+                       mergedInitStateIndex = currentScope.methodScope()
+                                       .recordInitializationStates(tryInfo);
                        return tryInfo;
                }
 
-               // we also need to check potential multiple assignments of final variables inside the finally block
-               // need to include potential inits from returns inside the try/catch parts - 1GK2AOF
-               tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn);
-               finallyContext.complainOnRedundantFinalAssignments(tryInfo, currentScope);
-               if (subInfo == FlowInfo.DeadEnd) {
-                       mergedInitStateIndex =
-                               currentScope.methodScope().recordInitializationStates(subInfo);
+               // we also need to check potential multiple assignments of final
+               // variables inside the finally block
+               // need to include potential inits from returns inside the try/catch
+               // parts - 1GK2AOF
+               finallyContext
+                               .complainOnRedundantFinalAssignments(
+                                               tryInfo.isReachable() ? (tryInfo
+                                                               .addPotentialInitializationsFrom(insideSubContext.initsOnReturn))
+                                                               : insideSubContext.initsOnReturn, currentScope);
+               if (subInfo == FlowInfo.DEAD_END) {
+                       mergedInitStateIndex = currentScope.methodScope()
+                                       .recordInitializationStates(subInfo);
                        return subInfo;
                } else {
                        FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo);
-                       mergedInitStateIndex =
-                               currentScope.methodScope().recordInitializationStates(mergedInfo);
+                       mergedInitStateIndex = currentScope.methodScope()
+                                       .recordInitializationStates(mergedInfo);
                        return mergedInfo;
                }
        }
@@ -187,281 +208,323 @@ public class TryStatement extends Statement {
 
        /**
         * Try statement code generation
-        *
+        * 
         */
-       public void generateCode(BlockScope currentScope, CodeStream codeStream) {
-
-               if ((bits & IsReachableMASK) == 0) {
-                       return;
-               }
-               if (tryBlock.isEmptyBlock()) {
-                       if (subRoutineStartLabel != null) {
-                               // since not passing the finallyScope, the block generation will exitUserScope(finallyScope)
-                               finallyBlock.generateCode(scope, codeStream);
-                       }
-                       // May loose some local variable initializations : affecting the local variable attributes
-                       if (mergedInitStateIndex != -1) {
-                               codeStream.removeNotDefinitelyAssignedVariables(
-                                       currentScope,
-                                       mergedInitStateIndex);
-                       }
-                       // no local bytecode produced so no need for position remembering
-                       return;
-               }
-               int pc = codeStream.position;
-               Label endLabel = new Label(codeStream);
-               boolean requiresNaturalJsr = false;
-
-               // preparing exception labels
-               int maxCatches;
-               ExceptionLabel[] exceptionLabels =
-                       new ExceptionLabel[maxCatches =
-                               catchArguments == null ? 0 : catchArguments.length];
-               for (int i = 0; i < maxCatches; i++) {
-                       boolean preserveCurrentHandler =
-                               (preserveExceptionHandler[i
-                                       / ExceptionHandlingFlowContext.BitCacheSize]
-                                               & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
-                                       != 0;
-                       if (preserveCurrentHandler) {
-                               exceptionLabels[i] =
-                                       new ExceptionLabel(
-                                               codeStream,
-                                               (ReferenceBinding) catchArguments[i].binding.type);
-                       }
-               }
-               ExceptionLabel anyExceptionLabel = null;
-               if (subRoutineStartLabel != null) {
-                       subRoutineStartLabel.codeStream = codeStream;
-                       anyExceptionLabel = new ExceptionLabel(codeStream, null);
-               }
-               // generate the try block
-               tryBlock.generateCode(scope, codeStream);
-               boolean tryBlockHasSomeCode = codeStream.position != pc;
-               // flag telling if some bytecodes were issued inside the try block
-
-               // natural exit: only if necessary
-               boolean nonReturningSubRoutine =
-                       (subRoutineStartLabel != null) && subRoutineCannotReturn;
-               if ((!tryBlockExit) && tryBlockHasSomeCode) {
-                       int position = codeStream.position;
-                       if (nonReturningSubRoutine) {
-                               codeStream.goto_(subRoutineStartLabel);
-                       } else {
-                               requiresNaturalJsr = true;
-                               codeStream.goto_(endLabel);
-                       }
-                       codeStream.updateLastRecordedEndPC(position);
-                       //goto is tagged as part of the try block
+       // public void generateCode(BlockScope currentScope, CodeStream codeStream)
+       // {
+       //
+       // if ((bits & IsReachableMASK) == 0) {
+       // return;
+       // }
+       // if (tryBlock.isEmptyBlock()) {
+       // if (subRoutineStartLabel != null) {
+       // // since not passing the finallyScope, the block generation will
+       // exitUserScope(finallyScope)
+       // finallyBlock.generateCode(scope, codeStream);
+       // }
+       // // May loose some local variable initializations : affecting the local
+       // variable attributes
+       // if (mergedInitStateIndex != -1) {
+       // codeStream.removeNotDefinitelyAssignedVariables(
+       // currentScope,
+       // mergedInitStateIndex);
+       // }
+       // // no local bytecode produced so no need for position remembering
+       // return;
+       // }
+       // int pc = codeStream.position;
+       // Label endLabel = new Label(codeStream);
+       // boolean requiresNaturalJsr = false;
+       //
+       // // preparing exception labels
+       // int maxCatches;
+       // ExceptionLabel[] exceptionLabels =
+       // new ExceptionLabel[maxCatches =
+       // catchArguments == null ? 0 : catchArguments.length];
+       // for (int i = 0; i < maxCatches; i++) {
+       // boolean preserveCurrentHandler =
+       // (preserveExceptionHandler[i
+       // / ExceptionHandlingFlowContext.BitCacheSize]
+       // & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+       // != 0;
+       // if (preserveCurrentHandler) {
+       // exceptionLabels[i] =
+       // new ExceptionLabel(
+       // codeStream,
+       // (ReferenceBinding) catchArguments[i].binding.type);
+       // }
+       // }
+       // ExceptionLabel anyExceptionLabel = null;
+       // if (subRoutineStartLabel != null) {
+       // subRoutineStartLabel.codeStream = codeStream;
+       // anyExceptionLabel = new ExceptionLabel(codeStream, null);
+       // }
+       // // generate the try block
+       // tryBlock.generateCode(scope, codeStream);
+       // boolean tryBlockHasSomeCode = codeStream.position != pc;
+       // // flag telling if some bytecodes were issued inside the try block
+       //
+       // // natural exit: only if necessary
+       // boolean nonReturningSubRoutine =
+       // (subRoutineStartLabel != null) && subRoutineCannotReturn;
+       // if ((!tryBlockExit) && tryBlockHasSomeCode) {
+       // int position = codeStream.position;
+       // if (nonReturningSubRoutine) {
+       // codeStream.goto_(subRoutineStartLabel);
+       // } else {
+       // requiresNaturalJsr = true;
+       // codeStream.goto_(endLabel);
+       // }
+       // codeStream.updateLastRecordedEndPC(position);
+       // //goto is tagged as part of the try block
+       // }
+       // // place end positions of user-defined exception labels
+       // if (tryBlockHasSomeCode) {
+       // for (int i = 0; i < maxCatches; i++) {
+       // boolean preserveCurrentHandler =
+       // (preserveExceptionHandler[i / ExceptionHandlingFlowContext.BitCacheSize]
+       // & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+       // != 0;
+       // if (preserveCurrentHandler) {
+       // exceptionLabels[i].placeEnd();
+       // }
+       // }
+       // /* generate sequence of handler, all starting by storing the TOS
+       // (exception
+       // thrown) into their own catch variables, the one specified in the source
+       // that must denote the handled exception.
+       // */
+       // if (catchArguments == null) {
+       // if (anyExceptionLabel != null) {
+       // anyExceptionLabel.placeEnd();
+       // }
+       // } else {
+       // for (int i = 0; i < maxCatches; i++) {
+       // boolean preserveCurrentHandler =
+       // (preserveExceptionHandler[i / ExceptionHandlingFlowContext.BitCacheSize]
+       // & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+       // != 0;
+       // if (preserveCurrentHandler) {
+       // // May loose some local variable initializations : affecting the local
+       // variable attributes
+       // if (preTryInitStateIndex != -1) {
+       // codeStream.removeNotDefinitelyAssignedVariables(
+       // currentScope,
+       // preTryInitStateIndex);
+       // }
+       // exceptionLabels[i].place();
+       // codeStream.incrStackSize(1);
+       // // optimizing the case where the exception variable is not actually used
+       // LocalVariableBinding catchVar;
+       // int varPC = codeStream.position;
+       // if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) {
+       // codeStream.store(catchVar, false);
+       // catchVar.recordInitializationStartPC(codeStream.position);
+       // codeStream.addVisibleLocalVariable(catchVar);
+       // } else {
+       // codeStream.pop();
+       // }
+       // codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart);
+       // // Keep track of the pcs at diverging point for computing the local
+       // attribute
+       // // since not passing the catchScope, the block generation will
+       // exitUserScope(catchScope)
+       // catchBlocks[i].generateCode(scope, codeStream);
+       // }
+       // if (i == maxCatches - 1) {
+       // if (anyExceptionLabel != null) {
+       // anyExceptionLabel.placeEnd();
+       // }
+       // if (subRoutineStartLabel != null) {
+       // if (!catchExits[i] && preserveCurrentHandler) {
+       // requiresNaturalJsr = true;
+       // codeStream.goto_(endLabel);
+       // }
+       // }
+       // } else {
+       // if (!catchExits[i] && preserveCurrentHandler) {
+       // if (nonReturningSubRoutine) {
+       // codeStream.goto_(subRoutineStartLabel);
+       // } else {
+       // requiresNaturalJsr = true;
+       // codeStream.goto_(endLabel);
+       // }
+       // }
+       // }
+       // }
+       // }
+       // // addition of a special handler so as to ensure that any uncaught
+       // exception (or exception thrown
+       // // inside catch blocks) will run the finally block
+       // int finallySequenceStartPC = codeStream.position;
+       // if (subRoutineStartLabel != null) {
+       // // the additional handler is doing: jsr finallyBlock and rethrow
+       // TOS-exception
+       // anyExceptionLabel.place();
+       //
+       // if (preTryInitStateIndex != -1) {
+       // // reset initialization state, as for a normal catch block
+       // codeStream.removeNotDefinitelyAssignedVariables(
+       // currentScope,
+       // preTryInitStateIndex);
+       // }
+       //
+       // codeStream.incrStackSize(1);
+       // if (nonReturningSubRoutine) {
+       // codeStream.pop();
+       // // "if subroutine cannot return, no need to jsr/jump to subroutine since
+       // it will be entered in sequence
+       // } else {
+       // codeStream.store(anyExceptionVariable, false);
+       // codeStream.jsr(subRoutineStartLabel);
+       // codeStream.load(anyExceptionVariable);
+       // codeStream.athrow();
+       // }
+       // }
+       // // end of catch sequence, place label that will correspond to the finally
+       // block beginning, or end of statement
+       // endLabel.place();
+       // if (subRoutineStartLabel != null) {
+       // if (nonReturningSubRoutine) {
+       // requiresNaturalJsr = false;
+       // }
+       // Label veryEndLabel = new Label(codeStream);
+       // if (requiresNaturalJsr) {
+       // codeStream.jsr(subRoutineStartLabel);
+       // codeStream.goto_(veryEndLabel);
+       // }
+       // subRoutineStartLabel.place();
+       // if (!nonReturningSubRoutine) {
+       // codeStream.incrStackSize(1);
+       // codeStream.store(returnAddressVariable, false);
+       // }
+       // codeStream.recordPositionsFrom(
+       // finallySequenceStartPC,
+       // finallyBlock.sourceStart);
+       // // entire sequence for finally is associated to finally block
+       // finallyBlock.generateCode(scope, codeStream);
+       // if (!nonReturningSubRoutine) {
+       // int position = codeStream.position;
+       // codeStream.ret(returnAddressVariable.resolvedPosition);
+       // codeStream.updateLastRecordedEndPC(position);
+       // // the ret bytecode is part of the subroutine
+       // }
+       // if (requiresNaturalJsr) {
+       // veryEndLabel.place();
+       // }
+       // }
+       // } else {
+       // // try block had no effect, only generate the body of the finally block
+       // if any
+       // if (subRoutineStartLabel != null) {
+       // finallyBlock.generateCode(scope, codeStream);
+       // }
+       // }
+       // // May loose some local variable initializations : affecting the local
+       // variable attributes
+       // if (mergedInitStateIndex != -1) {
+       // codeStream.removeNotDefinitelyAssignedVariables(
+       // currentScope,
+       // mergedInitStateIndex);
+       // codeStream.addDefinitelyAssignedVariables(currentScope,
+       // mergedInitStateIndex);
+       // }
+       // codeStream.recordPositionsFrom(pc, this.sourceStart);
+       // }
+       public void resetStateForCodeGeneration() {
+               if (this.subRoutineStartLabel != null) {
+                       this.subRoutineStartLabel.resetStateForCodeGeneration();
                }
-               // place end positions of user-defined exception labels
-               if (tryBlockHasSomeCode) {
-                       for (int i = 0; i < maxCatches; i++) {
-                               boolean preserveCurrentHandler =
-                                       (preserveExceptionHandler[i
-                                               / ExceptionHandlingFlowContext.BitCacheSize]
-                                                       & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
-                                               != 0;
-                               if (preserveCurrentHandler) {
-                                       exceptionLabels[i].placeEnd();
-                               }
-                       }
-                       /* generate sequence of handler, all starting by storing the TOS (exception
-                       thrown) into their own catch variables, the one specified in the source
-                       that must denote the handled exception.
-                       */
-                       if (catchArguments == null) {
-                               if (anyExceptionLabel != null) {
-                                       anyExceptionLabel.placeEnd();
-                               }
-                       } else {
-                               for (int i = 0; i < maxCatches; i++) {
-                                       boolean preserveCurrentHandler =
-                                               (preserveExceptionHandler[i
-                                                       / ExceptionHandlingFlowContext.BitCacheSize]
-                                                               & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
-                                                       != 0;
-                                       if (preserveCurrentHandler) {
-                                               // May loose some local variable initializations : affecting the local variable attributes
-                                               if (preTryInitStateIndex != -1) {
-                                                       codeStream.removeNotDefinitelyAssignedVariables(
-                                                               currentScope,
-                                                               preTryInitStateIndex);
-                                               }
-                                               exceptionLabels[i].place();
-                                               codeStream.incrStackSize(1);
-                                               // optimizing the case where the exception variable is not actually used
-                                               LocalVariableBinding catchVar;
-                                               int varPC = codeStream.position;
-                                               if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) {
-                                                       codeStream.store(catchVar, false);
-                                                       catchVar.recordInitializationStartPC(codeStream.position);
-                                                       codeStream.addVisibleLocalVariable(catchVar);
-                                               } else {
-                                                       codeStream.pop();
-                                               }
-                                               codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart);
-                                               // Keep track of the pcs at diverging point for computing the local attribute
-                                               // since not passing the catchScope, the block generation will exitUserScope(catchScope)
-                                               catchBlocks[i].generateCode(scope, codeStream);
-                                       }
-                                       if (i == maxCatches - 1) {
-                                               if (anyExceptionLabel != null) {
-                                                       anyExceptionLabel.placeEnd();
-                                               }
-                                               if (subRoutineStartLabel != null) {
-                                                       if (!catchExits[i] && preserveCurrentHandler) {
-                                                               requiresNaturalJsr = true;
-                                                               codeStream.goto_(endLabel);
-                                                       }
-                                               }
-                                       } else {
-                                               if (!catchExits[i] && preserveCurrentHandler) {
-                                                       if (nonReturningSubRoutine) {
-                                                               codeStream.goto_(subRoutineStartLabel);
-                                                       } else {
-                                                               requiresNaturalJsr = true;
-                                                               codeStream.goto_(endLabel);
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       // addition of a special handler so as to ensure that any uncaught exception (or exception thrown
-                       // inside catch blocks) will run the finally block
-                       int finallySequenceStartPC = codeStream.position;
-                       if (subRoutineStartLabel != null) {
-                               // the additional handler is doing: jsr finallyBlock and rethrow TOS-exception
-                               anyExceptionLabel.place();
-
-                               if (preTryInitStateIndex != -1) {
-                                       // reset initialization state, as for a normal catch block
-                                       codeStream.removeNotDefinitelyAssignedVariables(
-                                               currentScope,
-                                               preTryInitStateIndex);
-                               }
+       }
 
-                               codeStream.incrStackSize(1);
-                               if (nonReturningSubRoutine) {
-                                       codeStream.pop();
-                                       // "if subroutine cannot return, no need to jsr/jump to subroutine since it will be entered in sequence
-                               } else {
-                                       codeStream.store(anyExceptionVariable, false);
-                                       codeStream.jsr(subRoutineStartLabel);
-                                       codeStream.load(anyExceptionVariable);
-                                       codeStream.athrow();
-                               }
-                       }
-                       // end of catch sequence, place label that will correspond to the finally block beginning, or end of statement
-                       endLabel.place();
-                       if (subRoutineStartLabel != null) {
-                               if (nonReturningSubRoutine) {
-                                       requiresNaturalJsr = false;
-                               }
-                               Label veryEndLabel = new Label(codeStream);
-                               if (requiresNaturalJsr) {
-                                       codeStream.jsr(subRoutineStartLabel);
-                                       codeStream.goto_(veryEndLabel);
-                               }
-                               subRoutineStartLabel.place();
-                               if (!nonReturningSubRoutine) {
-                                       codeStream.incrStackSize(1);
-                                       codeStream.store(returnAddressVariable, false);
-                               }
-                               codeStream.recordPositionsFrom(
-                                       finallySequenceStartPC,
-                                       finallyBlock.sourceStart);
-                               // entire sequence for finally is associated to finally block
-                               finallyBlock.generateCode(scope, codeStream);
-                               if (!nonReturningSubRoutine) {
-                                       int position = codeStream.position;
-                                       codeStream.ret(returnAddressVariable.resolvedPosition);
-                                       codeStream.updateLastRecordedEndPC(position);
-                                       // the ret bytecode is part of the subroutine
-                               }
-                               if (requiresNaturalJsr) {
-                                       veryEndLabel.place();
-                               }
-                       }
-               } else {
-                       // try block had no effect, only generate the body of the finally block if any
-                       if (subRoutineStartLabel != null) {
-                               finallyBlock.generateCode(scope, codeStream);
+       public StringBuffer printStatement(int indent, StringBuffer output) {
+               printIndent(indent, output).append("try \n"); //$NON-NLS-1$
+               tryBlock.printStatement(indent + 1, output); //$NON-NLS-1$
+
+               // catches
+               if (catchBlocks != null)
+                       for (int i = 0; i < catchBlocks.length; i++) {
+                               output.append('\n');
+                               printIndent(indent, output).append("catch ("); //$NON-NLS-1$
+                               catchArguments[i].print(0, output).append(") "); //$NON-NLS-1$
+                               catchBlocks[i].printStatement(indent + 1, output);
                        }
+               // finally
+               if (finallyBlock != null) {
+                       output.append('\n');
+                       printIndent(indent, output).append("finally\n"); //$NON-NLS-1$
+                       finallyBlock.printStatement(indent + 1, output);
                }
-               // May loose some local variable initializations : affecting the local variable attributes
-               if (mergedInitStateIndex != -1) {
-                       codeStream.removeNotDefinitelyAssignedVariables(
-                               currentScope,
-                               mergedInitStateIndex);
-                       codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
-               }
-               codeStream.recordPositionsFrom(pc, this.sourceStart);
+
+               return output;
        }
 
        public void resolve(BlockScope upperScope) {
 
-               // special scope for secret locals optimization.        
+               // special scope for secret locals optimization.
                this.scope = new BlockScope(upperScope);
 
                BlockScope tryScope = new BlockScope(scope);
                BlockScope finallyScope = null;
-               
-               if (finallyBlock != null
-                       && finallyBlock.statements != null) {
 
-                       finallyScope = new BlockScope(scope, false); // don't add it yet to parent scope
+               if (finallyBlock != null && finallyBlock.statements != null) {
+
+                       finallyScope = new BlockScope(scope, false); // don't add it yet
+                                                                                                                       // to parent scope
 
                        // provision for returning and forcing the finally block to run
                        MethodScope methodScope = scope.methodScope();
 
-                       // the type does not matter as long as its not a normal base type
-                       this.returnAddressVariable =
-                               new LocalVariableBinding(SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false);
+                       // the type does not matter as long as it is not a base type
+                       this.returnAddressVariable = new LocalVariableBinding(
+                                       SecretReturnName, upperScope.getJavaLangObject(),
+                                       AccDefault, false);
                        finallyScope.addLocalVariable(returnAddressVariable);
                        this.returnAddressVariable.constant = NotAConstant; // not inlinable
                        this.subRoutineStartLabel = new Label();
 
-                       this.anyExceptionVariable =
-                               new LocalVariableBinding(SecretAnyHandlerName, scope.getJavaLangThrowable(), AccDefault, false);
+                       this.anyExceptionVariable = new LocalVariableBinding(
+                                       SecretAnyHandlerName, scope.getJavaLangThrowable(),
+                                       AccDefault, false);
                        finallyScope.addLocalVariable(this.anyExceptionVariable);
                        this.anyExceptionVariable.constant = NotAConstant; // not inlinable
 
                        if (!methodScope.isInsideInitializer()) {
-                               MethodBinding methodBinding =
-                                       ((AbstractMethodDeclaration) methodScope.referenceContext).binding;
+                               MethodBinding methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding;
                                if (methodBinding != null) {
                                        TypeBinding methodReturnType = methodBinding.returnType;
                                        if (methodReturnType.id != T_void) {
-                                               this.secretReturnValue =
-                                                       new LocalVariableBinding(
-                                                               SecretLocalDeclarationName,
-                                                               methodReturnType,
-                                                               AccDefault,
-                                                               false);
+                                               this.secretReturnValue = new LocalVariableBinding(
+                                                               SecretLocalDeclarationName, methodReturnType,
+                                                               AccDefault, false);
                                                finallyScope.addLocalVariable(this.secretReturnValue);
-                                               this.secretReturnValue.constant = NotAConstant; // not inlinable
+                                               this.secretReturnValue.constant = NotAConstant; // not
+                                                                                                                                               // inlinable
                                        }
                                }
                        }
                        finallyBlock.resolveUsing(finallyScope);
-                       // force the finally scope to have variable positions shifted after its try scope and catch ones
-                       finallyScope.shiftScopes = new BlockScope[catchArguments == null ? 1 : catchArguments.length+1];
+                       // force the finally scope to have variable positions shifted after
+                       // its try scope and catch ones
+                       finallyScope.shiftScopes = new BlockScope[catchArguments == null ? 1
+                                       : catchArguments.length + 1];
                        finallyScope.shiftScopes[0] = tryScope;
                }
                this.tryBlock.resolveUsing(tryScope);
 
-               // arguments type are checked against JavaLangThrowable in resolveForCatch(..)
+               // arguments type are checked against JavaLangThrowable in
+               // resolveForCatch(..)
                if (this.catchBlocks != null) {
                        int length = this.catchArguments.length;
                        TypeBinding[] argumentTypes = new TypeBinding[length];
                        for (int i = 0; i < length; i++) {
                                BlockScope catchScope = new BlockScope(scope);
-                               if (finallyScope != null){
-                                       finallyScope.shiftScopes[i+1] = catchScope;
+                               if (finallyScope != null) {
+                                       finallyScope.shiftScopes[i + 1] = catchScope;
                                }
                                // side effect on catchScope in resolveForCatch(..)
-                               if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null)
+                               if ((argumentTypes[i] = catchArguments[i]
+                                               .resolveForCatch(catchScope)) == null)
                                        return;
                                catchBlocks[i].resolveUsing(catchScope);
                        }
@@ -472,19 +535,24 @@ public class TryStatement extends Statement {
                        for (int i = 0; i < length; i++) {
                                caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
                                for (int j = 0; j < i; j++) {
-                                       if (BlockScope.areTypesCompatible(caughtExceptionTypes[i], argumentTypes[j])) {
-                                               scope.problemReporter().wrongSequenceOfExceptionTypesError(this, i, j);
-                                               return;
+                                       if (caughtExceptionTypes[i]
+                                                       .isCompatibleWith(argumentTypes[j])) {
+                                               scope.problemReporter()
+                                                               .wrongSequenceOfExceptionTypesError(this, i, j);
+                                               // cannot return - since may still proceed if
+                                               // unreachable code is ignored (21203)
                                        }
                                }
                        }
                } else {
                        caughtExceptionTypes = new ReferenceBinding[0];
                }
-               
-               if (finallyScope != null){
-                       // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes.
-                       // the shifting is necessary to achieve no overlay in between the finally scope and its
+
+               if (finallyScope != null) {
+                       // add finallyScope as last subscope, so it can be shifted behind
+                       // try/catch subscopes.
+                       // the shifting is necessary to achieve no overlay in between the
+                       // finally scope and its
                        // sibling in term of local variable positions.
                        this.scope.addSubscope(finallyScope);
                }
@@ -492,34 +560,32 @@ public class TryStatement extends Statement {
 
        public String toString(int tab) {
                String s = tabString(tab);
-               //try
+               // try
                s = s + "try "; //$NON-NLS-1$
                if (tryBlock == Block.None)
                        s = s + "{}"; //$NON-NLS-1$
                else
                        s = s + "\n" + tryBlock.toString(tab + 1); //$NON-NLS-1$
 
-               //catches
+               // catches
                if (catchBlocks != null)
                        for (int i = 0; i < catchBlocks.length; i++)
-                                       s = s + "\n" + tabString(tab) + "catch (" //$NON-NLS-2$ //$NON-NLS-1$
-                                               +catchArguments[i].toString(0) + ") " //$NON-NLS-1$
-                                               +catchBlocks[i].toString(tab + 1);
-               //finally
+                               s = s + "\n" + tabString(tab) + "catch (" //$NON-NLS-2$ //$NON-NLS-1$
+                                               + catchArguments[i].toString(0) + ") " //$NON-NLS-1$
+                                               + catchBlocks[i].toString(tab + 1);
+               // finally
                if (finallyBlock != null) {
                        if (finallyBlock == Block.None)
                                s = s + "\n" + tabString(tab) + "finally {}"; //$NON-NLS-2$ //$NON-NLS-1$
                        else
-                                       s = s + "\n" + tabString(tab) + "finally\n" + //$NON-NLS-2$ //$NON-NLS-1$
-                       finallyBlock.toString(tab + 1);
+                               s = s + "\n" + tabString(tab) + "finally\n" + //$NON-NLS-2$ //$NON-NLS-1$
+                                               finallyBlock.toString(tab + 1);
                }
 
                return s;
        }
 
-       public void traverse(
-               IAbstractSyntaxTreeVisitor visitor,
-               BlockScope blockScope) {
+       public void traverse(ASTVisitor visitor, BlockScope blockScope) {
 
                if (visitor.visit(this, blockScope)) {
                        tryBlock.traverse(visitor, scope);
@@ -534,4 +600,4 @@ public class TryStatement extends Statement {
                }
                visitor.endVisit(this, blockScope);
        }
-}
\ No newline at end of file
+}