X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java index d64dc60..bf4c55a 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TryStatement.java @@ -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 +}