/*******************************************************************************
- * 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.*;
-import net.sourceforge.phpdt.internal.compiler.flow.*;
-import net.sourceforge.phpdt.internal.compiler.lookup.*;
+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;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
+import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
+import net.sourceforge.phpdt.internal.compiler.flow.InsideSubRoutineFlowContext;
+import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
+import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
+import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
+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;
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;
}
}
/**
* 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);
}
for (int i = 0; i < length; i++) {
caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
for (int j = 0; j < i; j++) {
- if (scope.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);
}
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);
}
visitor.endVisit(this, blockScope);
}
-}
\ No newline at end of file
+}