From 09286e7ba1f1a89730d7fb7a140a127fe70af126 Mon Sep 17 00:00:00 2001 From: Srikanth Sankaran <131454720+srikanth-sankaran@users.noreply.github.com> Date: Tue, 5 Nov 2024 06:44:30 +0530 Subject: [PATCH] * Modernize exception handling by pruning behavior applicable only to JDK6- (#3242) * Purge jsr/ret related code * Get rid of dated terminilogy: consistently use "FinallyBlock" instead of "subroutine" to refer to the finally block and StatementWithFinallyBlock instead of SubRoutineStatement to the construct containing the (implicit/explicit) finally block (try/synchronized) * Fixes https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3240 --- .../jdt/internal/compiler/ast/ASTNode.java | 10 +- .../compiler/ast/BranchStatement.java | 22 +- .../internal/compiler/ast/BreakStatement.java | 29 +- .../compiler/ast/ContinueStatement.java | 29 +- .../jdt/internal/compiler/ast/Expression.java | 2 +- .../compiler/ast/ReturnStatement.java | 55 ++-- ...nt.java => StatementWithFinallyBlock.java} | 24 +- .../compiler/ast/SynchronizedStatement.java | 12 +- .../internal/compiler/ast/TryStatement.java | 268 +++++++----------- .../internal/compiler/ast/YieldStatement.java | 51 ++-- .../internal/compiler/codegen/CodeStream.java | 44 --- .../flow/ExceptionHandlingFlowContext.java | 20 +- .../compiler/flow/FinallyFlowContext.java | 9 +- .../internal/compiler/flow/FlowContext.java | 66 ++--- ...StatementWithFinallyBlockFlowContext.java} | 14 +- .../lookup/AnnotatableTypeSystem.java | 2 +- .../model/org/eclipse/jdt/core/JavaCore.java | 4 +- 17 files changed, 268 insertions(+), 393 deletions(-) rename org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/{SubRoutineStatement.java => StatementWithFinallyBlock.java} (69%) rename org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/{InsideSubRoutineFlowContext.java => InsideStatementWithFinallyBlockFlowContext.java} (75%) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ASTNode.java index 85be2055391..ca30287ba48 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ASTNode.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ASTNode.java @@ -82,7 +82,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds { public final static int Bit12 = 0x800; // depth (name ref, msg) | operator (operator) | has abstract methods (type decl) public final static int Bit13 = 0x1000; // depth (name ref, msg) | operator (operator) | is secondary type (type decl) public final static int Bit14 = 0x2000; // strictly assigned (reference lhs) | discard enclosing instance (explicit constr call) | hasBeenGenerated (type decl) - public final static int Bit15 = 0x4000; // is unnecessary cast (expression) | is varargs (type ref) | isSubRoutineEscaping (try statement) | superAccess (javadoc allocation expression/javadoc message send/javadoc return statement) + public final static int Bit15 = 0x4000; // is unnecessary cast (expression) | is varargs (type ref) | IsFinallyBlockEscaping (try statement) | superAccess (javadoc allocation expression/javadoc message send/javadoc return statement) public final static int Bit16 = 0x8000; // in javadoc comment (name ref, type ref, msg) public final static int Bit17 = 0x10000; // compound assigned (reference lhs) | unchecked (msg, alloc, explicit constr call) public final static int Bit18 = 0x20000; // non null (expression) | onDemand (import reference) @@ -97,7 +97,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds { public final static int Bit27 = 0x4000000; // parenthesis count (expression) public final static int Bit28 = 0x8000000; // parenthesis count (expression) public final static int Bit29 = 0x10000000; // parenthesis count (expression) - public final static int Bit30 = 0x20000000; // elseif (if statement) | try block exit (try statement) | fall-through (case statement) | ignore no effect assign (expression ref) | needScope (for statement) | isAnySubRoutineEscaping (return statement) | blockExit (synchronized statement) + public final static int Bit30 = 0x20000000; // elseif (if statement) | try block exit (try statement) | fall-through (case statement) | ignore no effect assign (expression ref) | needScope (for statement) | IsAnyFinallyBlockEscaping (return statement) | blockExit (synchronized statement) public final static int Bit31 = 0x40000000; // local declaration reachable (local decl) | ignore raw type check (type ref) | discard entire assignment (assignment) | isSynchronized (return statement) | thenExit (if statement) public final static int Bit32 = 0x80000000; // reachable (statement) @@ -186,7 +186,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds { // try statements - public static final int IsSubRoutineEscaping = Bit15; + public static final int IsFinallyBlockEscaping = Bit15; public static final int IsTryBlockExiting = Bit30; // for type declaration @@ -280,7 +280,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds { public static final int DidResolve = Bit19; // for return statement - public static final int IsAnySubRoutineEscaping = Bit30; + public static final int IsAnyFinallyBlockEscaping = Bit30; public static final int IsSynchronized = Bit31; // for synchronized statement @@ -1075,7 +1075,7 @@ public static void resolveAnnotations(BlockScope scope, Annotation[] sourceAnnot return annotations; } - /** Resolve JSR308 annotations on a type reference, array creation expression or a wildcard. Type parameters go directly to the subroutine, + /** Resolve JSR308 annotations on a type reference, array creation expression or a wildcard. Type parameters go directly to the method/ctor, By construction the bindings associated with QTR, PQTR etc get resolved first and then annotations for different levels get resolved and applied at one go. Likewise for multidimensional arrays. diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java index ad3ab849b42..4ec9661c658 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java @@ -21,7 +21,7 @@ public abstract class BranchStatement extends Statement { public char[] label; public BranchLabel targetLabel; - public SubRoutineStatement[] subroutines; + public StatementWithFinallyBlock[] statementsWithFinallyBlock; public int initStateIndex = -1; /** @@ -33,7 +33,7 @@ public BranchStatement(char[] label, int sourceStart,int sourceEnd) { this.sourceEnd = sourceEnd; } -protected void setSubroutineSwitchExpression(SubRoutineStatement sub) { +protected void setSubroutineSwitchExpression(StatementWithFinallyBlock stmt) { // Do nothing } protected void restartExceptionLabels(CodeStream codeStream) { @@ -53,16 +53,16 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { // generation of code responsible for invoking the finally // blocks in sequence - if (this.subroutines != null){ - for (int i = 0, max = this.subroutines.length; i < max; i++){ - SubRoutineStatement sub = this.subroutines[i]; - SwitchExpression se = sub.getSwitchExpression(); - setSubroutineSwitchExpression(sub); - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); - sub.setSwitchExpression(se); + if (this.statementsWithFinallyBlock != null){ + for (int i = 0, max = this.statementsWithFinallyBlock.length; i < max; i++){ + StatementWithFinallyBlock stmt = this.statementsWithFinallyBlock[i]; + SwitchExpression se = stmt.getSwitchExpression(); + setSubroutineSwitchExpression(stmt); + boolean didEscape = stmt.generateFinallyBlock(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); + stmt.setSwitchExpression(se); if (didEscape) { codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, i, codeStream); if (this.initStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); @@ -75,7 +75,7 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { // checkAndLoadSyntheticVars(codeStream); codeStream.goto_(this.targetLabel); codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, -1, codeStream); if (this.initStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java index a157727a96e..265de6f1705 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java @@ -18,7 +18,7 @@ import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InsideSubRoutineFlowContext; +import org.eclipse.jdt.internal.compiler.flow.InsideStatementWithFinallyBlockFlowContext; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; public class BreakStatement extends BranchStatement { @@ -58,39 +58,38 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.targetLabel = targetContext.breakLabel(); FlowContext traversedContext = flowContext; - int subCount = 0; - this.subroutines = new SubRoutineStatement[5]; + int stmtCount = 0; + this.statementsWithFinallyBlock = new StatementWithFinallyBlock[5]; do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow + StatementWithFinallyBlock stmt; + if ((stmt = traversedContext.statementWithFinallyBlock()) != null) { + if (stmtCount == this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, (this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount*2]), 0, stmtCount); // grow } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { + this.statementsWithFinallyBlock[stmtCount++] = stmt; + if (stmt.isFinallyBlockEscaping()) { break; } } traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); traversedContext.recordBreakTo(targetContext); - if (traversedContext instanceof InsideSubRoutineFlowContext) { + if (traversedContext instanceof InsideStatementWithFinallyBlockFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + flowInfo.addInitializationsFrom(tryStatement.finallyBlockInits); // collect inits } } else if (traversedContext == targetContext) { - // only record break info once accumulated through subroutines, and only against target context + // only record break info once accumulated, and only against target context targetContext.recordBreakFrom(flowInfo); break; } } while ((traversedContext = traversedContext.getLocalParent()) != null); - // resize subroutines - if (subCount != this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); + if (stmtCount != this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, (this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount]), 0, stmtCount); } return FlowInfo.DEAD_END; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java index 0caa1678c89..4e439c0c39f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java @@ -18,7 +18,7 @@ import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InsideSubRoutineFlowContext; +import org.eclipse.jdt.internal.compiler.flow.InsideStatementWithFinallyBlockFlowContext; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; public class ContinueStatement extends BranchStatement { @@ -62,38 +62,37 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.targetLabel = targetContext.continueLabel(); FlowContext traversedContext = flowContext; - int subCount = 0; - this.subroutines = new SubRoutineStatement[5]; + int stmtCount = 0; + this.statementsWithFinallyBlock = new StatementWithFinallyBlock[5]; do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, this.subroutines = new SubRoutineStatement[subCount*2], 0, subCount); // grow + StatementWithFinallyBlock stmt; + if ((stmt = traversedContext.statementWithFinallyBlock()) != null) { + if (stmtCount == this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount*2], 0, stmtCount); // grow } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { + this.statementsWithFinallyBlock[stmtCount++] = stmt; + if (stmt.isFinallyBlockEscaping()) { break; } } traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - if (traversedContext instanceof InsideSubRoutineFlowContext) { + if (traversedContext instanceof InsideStatementWithFinallyBlockFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + flowInfo.addInitializationsFrom(tryStatement.finallyBlockInits); // collect inits } } else if (traversedContext == targetContext) { - // only record continue info once accumulated through subroutines, and only against target context + // only record continue info once accumulated and only against target context targetContext.recordContinueFrom(flowContext, flowInfo); break; } } while ((traversedContext = traversedContext.getLocalParent()) != null); - // resize subroutines - if (subCount != this.subroutines.length) { - System.arraycopy(this.subroutines, 0, this.subroutines = new SubRoutineStatement[subCount], 0, subCount); + if (stmtCount != this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount], 0, stmtCount); } return FlowInfo.DEAD_END; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Expression.java index 81a585d7278..7a96f7d2a71 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Expression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Expression.java @@ -1250,7 +1250,7 @@ public boolean forcedToBeRaw(ReferenceContext referenceContext) { /** * Returns an object which can be used to identify identical JSR sequence targets - * (see TryStatement subroutine codegen) + * (see TryStatement finally block codegen) * or null if not reusable */ public Object reusableJSRTarget() { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java index 722ede5980f..29d24383aa4 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java @@ -49,7 +49,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; -import org.eclipse.jdt.internal.compiler.flow.InsideSubRoutineFlowContext; +import org.eclipse.jdt.internal.compiler.flow.InsideStatementWithFinallyBlockFlowContext; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; @@ -64,7 +64,7 @@ public class ReturnStatement extends Statement { public Expression expression; - public SubRoutineStatement[] subroutines; + public StatementWithFinallyBlock[] statementsWithFinallyBlock; public LocalVariableBinding saveValueVariable; public int initStateIndex = -1; private final boolean implicitReturn; @@ -114,42 +114,42 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl methodScope.recordInitializationStates(flowInfo); // compute the return sequence (running the finally blocks) FlowContext traversedContext = flowContext; - int subCount = 0; + int stmtCount = 0; boolean saveValueNeeded = false; boolean hasValueToSave = needValueStore(); boolean noAutoCloseables = true; do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (this.subroutines == null){ - this.subroutines = new SubRoutineStatement[5]; + StatementWithFinallyBlock stmt; + if ((stmt = traversedContext.statementWithFinallyBlock()) != null) { + if (this.statementsWithFinallyBlock == null){ + this.statementsWithFinallyBlock = new StatementWithFinallyBlock[5]; } - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow + if (stmtCount == this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, (this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount*2]), 0, stmtCount); // grow } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { + this.statementsWithFinallyBlock[stmtCount++] = stmt; + if (stmt.isFinallyBlockEscaping()) { saveValueNeeded = false; - this.bits |= ASTNode.IsAnySubRoutineEscaping; + this.bits |= ASTNode.IsAnyFinallyBlockEscaping; break; } - if (sub instanceof TryStatement) { - if (((TryStatement) sub).resources.length > 0) { + if (stmt instanceof TryStatement) { + if (((TryStatement) stmt).resources.length > 0) { noAutoCloseables = false; } } } traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - if (traversedContext instanceof InsideSubRoutineFlowContext) { + if (traversedContext instanceof InsideStatementWithFinallyBlockFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof SynchronizedStatement) { this.bits |= ASTNode.IsSynchronized; } else if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + flowInfo.addInitializationsFrom(tryStatement.finallyBlockInits); // collect inits if (hasValueToSave) { - if (this.saveValueVariable == null){ // closest subroutine secret variable is used + if (this.saveValueVariable == null){ // closest try statememt's secret variable is used prepareSaveValueLocation(tryStatement); } saveValueNeeded = true; @@ -166,9 +166,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } } while ((traversedContext = traversedContext.getLocalParent()) != null); - // resize subroutines - if ((this.subroutines != null) && (subCount != this.subroutines.length)) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); + if ((this.statementsWithFinallyBlock != null) && (stmtCount != this.statementsWithFinallyBlock.length)) { + System.arraycopy(this.statementsWithFinallyBlock, 0, (this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount]), 0, stmtCount); } // secret local variable for return value (note that this can only occur in a real method) @@ -241,19 +240,19 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { // generate the expression if (needValueStore()) { alreadyGeneratedExpression = true; - this.expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine + this.expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning method generateStoreSaveValueIfNecessary(currentScope, codeStream); } // generation of code responsible for invoking the finally blocks in sequence - if (this.subroutines != null) { + if (this.statementsWithFinallyBlock != null) { Object reusableJSRTarget = this.expression == null ? (Object)TypeBinding.VOID : this.expression.reusableJSRTarget(); - for (int i = 0, max = this.subroutines.length; i < max; i++) { - SubRoutineStatement sub = this.subroutines[i]; - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, reusableJSRTarget, this.initStateIndex, this.saveValueVariable); + for (int i = 0, max = this.statementsWithFinallyBlock.length; i < max; i++) { + StatementWithFinallyBlock stmt = this.statementsWithFinallyBlock[i]; + boolean didEscape = stmt.generateFinallyBlock(currentScope, codeStream, reusableJSRTarget, this.initStateIndex, this.saveValueVariable); if (didEscape) { codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, i, codeStream); return; } } @@ -276,7 +275,7 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); } codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, -1, codeStream); } /** @@ -303,7 +302,7 @@ private boolean needValueStore() { public boolean needValue() { return this.saveValueVariable != null || (this.bits & ASTNode.IsSynchronized) != 0 - || ((this.bits & ASTNode.IsAnySubRoutineEscaping) == 0); + || ((this.bits & ASTNode.IsAnyFinallyBlockEscaping) == 0); } public void prepareSaveValueLocation(TryStatement targetTryStatement){ diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/StatementWithFinallyBlock.java similarity index 69% rename from org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/StatementWithFinallyBlock.java index 044cfa17df8..33a37f0eaa1 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/StatementWithFinallyBlock.java @@ -19,17 +19,17 @@ import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; /** - * Extra behavior for statements which are generating subroutines + * Extra behavior for statements which have a finally block - e.g., try blocks have finally; synchronized statements have hidden finally blocks that call monitorexit etc. */ -public abstract class SubRoutineStatement extends Statement { +public abstract class StatementWithFinallyBlock extends Statement { - public static void reenterAllExceptionHandlers(SubRoutineStatement[] subroutines, int max, CodeStream codeStream) { - if (subroutines == null) return; - if (max < 0) max = subroutines.length; + public static void reenterAllExceptionHandlers(StatementWithFinallyBlock[] statements, int max, CodeStream codeStream) { + if (statements == null) return; + if (max < 0) max = statements.length; for (int i = 0; i < max; i++) { - SubRoutineStatement sub = subroutines[i]; - sub.enterAnyExceptionHandler(codeStream); - sub.enterDeclaredExceptionHandlers(codeStream); + StatementWithFinallyBlock stmt = statements[i]; + stmt.enterAnyExceptionHandler(codeStream); + stmt.enterDeclaredExceptionHandlers(codeStream); } } @@ -61,12 +61,12 @@ public void exitDeclaredExceptionHandlers(CodeStream codeStream) { /** - * Generate an invocation of a subroutine (e.g. jsr finally) in current context. - * @return boolean, true if the generated code will abrupt completion + * Generate the finally block in current context. + * @return boolean, true if the generated code will complete abruptly. */ - public abstract boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal); + public abstract boolean generateFinallyBlock(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal); - public abstract boolean isSubRoutineEscaping(); + public abstract boolean isFinallyBlockEscaping(); public void placeAllAnyExceptionHandler() { this.anyExceptionLabel.place(); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java index 7ccb72dcf6c..6a395d93d07 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java @@ -20,14 +20,14 @@ import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InsideSubRoutineFlowContext; +import org.eclipse.jdt.internal.compiler.flow.InsideStatementWithFinallyBlockFlowContext; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -public class SynchronizedStatement extends SubRoutineStatement { +public class SynchronizedStatement extends StatementWithFinallyBlock { // comes with a hidden finally block that contains the monitorexit sequence public Expression expression; public Block block; @@ -72,7 +72,7 @@ public FlowInfo analyseCode( flowInfo = this.block.analyseCode( this.scope, - new InsideSubRoutineFlowContext(flowContext, this), + new InsideStatementWithFinallyBlockFlowContext(flowContext, this), expressionFlowInfo); this.mergedSynchronizedInitStateIndex = @@ -87,7 +87,7 @@ public FlowInfo analyseCode( } @Override -public boolean isSubRoutineEscaping() { +public boolean isFinallyBlockEscaping() { return false; } @@ -174,10 +174,10 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { } /** - * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) + * @see StatementWithFinallyBlock#generateFinallyBlock(BlockScope, CodeStream, Object, int, LocalVariableBinding) */ @Override -public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { +public boolean generateFinallyBlock(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { codeStream.load(this.synchroVariable); codeStream.monitorexit(); exitAnyExceptionHandler(); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TryStatement.java index 73df49508db..5b848021aaa 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TryStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TryStatement.java @@ -46,16 +46,15 @@ import org.eclipse.jdt.internal.compiler.flow.FinallyFlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InsideSubRoutineFlowContext; +import org.eclipse.jdt.internal.compiler.flow.InsideStatementWithFinallyBlockFlowContext; import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.JavaFeature; import org.eclipse.jdt.internal.compiler.lookup.*; -public class TryStatement extends SubRoutineStatement { +public class TryStatement extends StatementWithFinallyBlock { - static final char[] SECRET_RETURN_ADDRESS_NAME = " returnAddress".toCharArray(); //$NON-NLS-1$ static final char[] SECRET_ANY_HANDLER_NAME = " anyExceptionHandler".toCharArray(); //$NON-NLS-1$ static final char[] SECRET_PRIMARY_EXCEPTION_VARIABLE_NAME = " primaryException".toCharArray(); //$NON-NLS-1$ static final char[] SECRET_CAUGHT_THROWABLE_VARIABLE_NAME = " caughtThrowable".toCharArray(); //$NON-NLS-1$; @@ -70,27 +69,25 @@ public class TryStatement extends SubRoutineStatement { public Block finallyBlock; BlockScope scope; - public UnconditionalFlowInfo subRoutineInits; + public UnconditionalFlowInfo finallyBlockInits; ReferenceBinding[] caughtExceptionTypes; boolean[] catchExits; - BranchLabel subRoutineStartLabel; + BranchLabel finallyBlockStartLabel; public LocalVariableBinding anyExceptionVariable, - returnAddressVariable, secretReturnValue; ExceptionLabel[] declaredExceptionLabels; // only set while generating code - // for inlining/optimizing JSR instructions + // for sharing finally blocks - behavior disabled by https://bugs.eclipse.org/bugs/show_bug.cgi?id=404146; can be enabled only by an undocumented option. private Object[] reusableJSRTargets; private BranchLabel[] reusableJSRSequenceStartLabels; private int[] reusableJSRStateIndexes; private int reusableJSRTargetsCount = 0; - private static final int NO_FINALLY = 0; // no finally block - private static final int FINALLY_SUBROUTINE = 1; // finally is generated as a subroutine (using jsr/ret bytecodes) + private static final int NO_FINALLY = 0; // no finally block private static final int FINALLY_DOES_NOT_COMPLETE = 2; // non returning finally is optimized with only one instance of finally block - private static final int FINALLY_INLINE = 3; // finally block must be inlined since cannot use jsr/ret bytecodes >1.5 + private static final int FINALLY_INLINE = 3; // finally block must be inlined // for local variables table attributes int mergedInitStateIndex = -1; @@ -108,11 +105,11 @@ public class TryStatement extends SubRoutineStatement { 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 + // the minimum exit relative depth amongst all of them. Then consider the finally block, and append its + // initialization to the try/catch ones, if the finally block completes normally. If it 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 - create a context for it this.preTryInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); @@ -126,16 +123,13 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl if (this.caughtThrowableVariable != null) { this.caughtThrowableVariable.useFlag = LocalVariableBinding.USED; } - if (this.returnAddressVariable != null) { // TODO (philippe) if subroutine is escaping, unused - this.returnAddressVariable.useFlag = LocalVariableBinding.USED; - } int resourcesLength = this.resources.length; if (resourcesLength > 0) { this.postResourcesInitStateIndexes = new int[resourcesLength]; } - if (this.subRoutineStartLabel == null) { + if (this.finallyBlockStartLabel == null) { // no finally block -- this is a simplified copy of the else part if (flowContext instanceof FinallyFlowContext) { // if this TryStatement sits inside another TryStatement, establish the wiring so that @@ -245,11 +239,11 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl return tryInfo; } else { - InsideSubRoutineFlowContext insideSubContext; + InsideStatementWithFinallyBlockFlowContext insideSubContext; FinallyFlowContext finallyContext; - UnconditionalFlowInfo subInfo; + UnconditionalFlowInfo finallyInfo; // analyse finally block first - insideSubContext = new InsideSubRoutineFlowContext(flowContext, this); + insideSubContext = new InsideStatementWithFinallyBlockFlowContext(flowContext, this); if (flowContext instanceof FinallyFlowContext) { // if this TryStatement sits inside another TryStatement, establish the wiring so that // FlowContext.markFinallyNullStatus can report into initsOnFinally of the outer try context: @@ -269,7 +263,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo); insideSubContext.initsOnFinally = handlingContext.initsOnFinally; - subInfo = + finallyInfo = this.finallyBlock .analyseCode( currentScope, @@ -277,19 +271,19 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo.nullInfoLessUnconditionalCopy()) .unconditionalInits(); handlingContext.conditionalLevel = 0; // start collection initsOnFinally only after analysing the finally block - if (subInfo == FlowInfo.DEAD_END) { - this.bits |= ASTNode.IsSubRoutineEscaping; + if (finallyInfo == FlowInfo.DEAD_END) { + this.bits |= ASTNode.IsFinallyBlockEscaping; this.scope.problemReporter().finallyMustCompleteNormally(this.finallyBlock); } else { // for resource analysis we need the finallyInfo in these nested scopes: - FlowInfo finallyInfo = subInfo.copy(); - this.tryBlock.scope.finallyInfo = finallyInfo; + FlowInfo finallyInfoCopy = finallyInfo.copy(); + this.tryBlock.scope.finallyInfo = finallyInfoCopy; if (this.catchBlocks != null) { for (int i = 0; i < this.catchBlocks.length; i++) - this.catchBlocks[i].scope.finallyInfo = finallyInfo; + this.catchBlocks[i].scope.finallyInfo = finallyInfoCopy; } } - this.subRoutineInits = subInfo; + this.finallyBlockInits = finallyInfo; // only try blocks initialize that member - may consider creating a // separate class if needed @@ -384,12 +378,12 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.naturalExitMergeInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); - if (subInfo == FlowInfo.DEAD_END) { + if (finallyInfo == FlowInfo.DEAD_END) { this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(subInfo); - return subInfo; + currentScope.methodScope().recordInitializationStates(finallyInfo); + return finallyInfo; } else { - FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo); + FlowInfo mergedInfo = tryInfo.addInitializationsFrom(finallyInfo); this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); return mergedInfo; @@ -479,7 +473,7 @@ private boolean isUncheckedCatchBlock(int catchBlock) { @Override public ExceptionLabel enterAnyExceptionHandler(CodeStream codeStream) { - if (this.subRoutineStartLabel == null) + if (this.finallyBlockStartLabel == null) return null; return super.enterAnyExceptionHandler(codeStream); } @@ -500,7 +494,7 @@ public void enterDeclaredExceptionHandlers(CodeStream codeStream) { @Override public void exitAnyExceptionHandler() { - if (this.subRoutineStartLabel == null) + if (this.finallyBlockStartLabel == null) return; super.exitAnyExceptionHandler(); } @@ -513,31 +507,24 @@ public void exitDeclaredExceptionHandlers(CodeStream codeStream) { } private int finallyMode() { - if (this.subRoutineStartLabel == null) { + if (this.finallyBlockStartLabel == null) { return NO_FINALLY; - } else if (isSubRoutineEscaping()) { + } else if (isFinallyBlockEscaping()) { return FINALLY_DOES_NOT_COMPLETE; } else { return FINALLY_INLINE; } } -/** - * Try statement code generation with or without jsr bytecode use - * post 1.5 target level, cannot use jsr bytecode, must instead inline finally block - * returnAddress is only allocated if jsr is allowed - */ + @Override public void generateCode(BlockScope currentScope, CodeStream codeStream) { if ((this.bits & ASTNode.IsReachable) == 0) { return; } - boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; + // in case the labels needs to be reinitialized // when the code generation is restarted in wide mode this.anyExceptionLabel = null; - this.reusableJSRTargets = null; - this.reusableJSRSequenceStartLabels = null; - this.reusableJSRTargetsCount = 0; int pc = codeStream.position; int finallyMode = finallyMode(); @@ -564,8 +551,8 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { } else { exceptionLabels = null; } - if (this.subRoutineStartLabel != null) { - this.subRoutineStartLabel.initialize(codeStream); + if (this.finallyBlockStartLabel != null) { + this.finallyBlockStartLabel.initialize(codeStream); enterAnyExceptionHandler(codeStream); } // generate the try block @@ -685,7 +672,6 @@ Our initialization type state is the same as it was at the end of the just concl // place end positions of user-defined exception labels if (tryBlockHasSomeCode) { - // natural exit may require subroutine invocation (if finally != null) BranchLabel naturalExitLabel = new BranchLabel(codeStream); BranchLabel postCatchesFinallyLabel = null; boolean patternAccessorsMayThrow = codeStream.patternAccessorsMayThrow(this.tryBlock.scope); @@ -697,7 +683,6 @@ Our initialization type state is the same as it was at the end of the just concl if ((this.bits & ASTNode.IsTryBlockExiting) == 0) { int position = codeStream.position; switch(finallyMode) { - case FINALLY_SUBROUTINE : case FINALLY_INLINE : requiresNaturalExit = true; if (this.naturalExitMergeInitStateIndex != -1) { @@ -714,7 +699,7 @@ Our initialization type state is the same as it was at the end of the just concl codeStream.goto_(naturalExitLabel); break; case FINALLY_DOES_NOT_COMPLETE : - codeStream.goto_(this.subRoutineStartLabel); + codeStream.goto_(this.finallyBlockStartLabel); break; } @@ -769,9 +754,7 @@ Our initialization type state is the same as it was at the end of the just concl switch(finallyMode) { case FINALLY_INLINE : // inlined finally here can see all merged variables - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); - } + ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); if (this.catchExitInitStateIndexes[i] != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.catchExitInitStateIndexes[i]); codeStream.addDefinitelyAssignedVariables(currentScope, this.catchExitInitStateIndexes[i]); @@ -779,13 +762,9 @@ Our initialization type state is the same as it was at the end of the just concl // entire sequence for finally is associated to finally block this.finallyBlock.generateCode(this.scope, codeStream); codeStream.goto_(postCatchesFinallyLabel); - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).popStateIndex(); - } + ((StackMapFrameCodeStream) codeStream).popStateIndex(); + break; - case FINALLY_SUBROUTINE : - requiresNaturalExit = true; - //$FALL-THROUGH$ case NO_FINALLY : if (this.naturalExitMergeInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); @@ -794,21 +773,17 @@ Our initialization type state is the same as it was at the end of the just concl codeStream.goto_(naturalExitLabel); break; case FINALLY_DOES_NOT_COMPLETE : - codeStream.goto_(this.subRoutineStartLabel); + codeStream.goto_(this.finallyBlockStartLabel); break; } } } } - // extra handler for trailing natural exit (will be fixed up later on when natural exit is generated below) - ExceptionLabel naturalExitExceptionHandler = requiresNaturalExit && (finallyMode == FINALLY_SUBROUTINE) - ? new ExceptionLabel(codeStream, null) - : null; // 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 (this.subRoutineStartLabel != null && this.anyExceptionLabel.getCount() != 0) { + if (this.finallyBlockStartLabel != null && this.anyExceptionLabel.getCount() != 0) { codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); if (this.preTryInitStateIndex != -1) { // reset initialization state, as for a normal catch block @@ -816,75 +791,38 @@ Our initialization type state is the same as it was at the end of the just concl codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); } placeAllAnyExceptionHandler(); - if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); switch(finallyMode) { - case FINALLY_SUBROUTINE : - // any exception handler - codeStream.store(this.anyExceptionVariable, false); - codeStream.jsr(this.subRoutineStartLabel); - codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); - int position = codeStream.position; - codeStream.throwAnyException(this.anyExceptionVariable); - codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); - // subroutine - this.subRoutineStartLabel.place(); - codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); - position = codeStream.position; - codeStream.store(this.returnAddressVariable, false); - codeStream.recordPositionsFrom(position, this.finallyBlock.sourceStart); - this.finallyBlock.generateCode(this.scope, codeStream); - position = codeStream.position; - codeStream.ret(this.returnAddressVariable.resolvedPosition); - codeStream.recordPositionsFrom( - position, - this.finallyBlock.sourceEnd); - // the ret bytecode is part of the subroutine - break; case FINALLY_INLINE : // any exception handler codeStream.store(this.anyExceptionVariable, false); codeStream.addVariable(this.anyExceptionVariable); codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); - // subroutine this.finallyBlock.generateCode(currentScope, codeStream); - position = codeStream.position; + int position = codeStream.position; codeStream.throwAnyException(this.anyExceptionVariable); codeStream.removeVariable(this.anyExceptionVariable); if (this.preTryInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); } - this.subRoutineStartLabel.place(); + this.finallyBlockStartLabel.place(); codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); break; case FINALLY_DOES_NOT_COMPLETE : // any exception handler codeStream.pop(); - this.subRoutineStartLabel.place(); + this.finallyBlockStartLabel.place(); codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); - // subroutine this.finallyBlock.generateCode(this.scope, codeStream); break; } - // will naturally fall into subsequent code after subroutine invocation + // will naturally fall into subsequent code after finally block execution if (requiresNaturalExit) { switch(finallyMode) { - case FINALLY_SUBROUTINE : - naturalExitLabel.place(); - int position = codeStream.position; - naturalExitExceptionHandler.placeStart(); - codeStream.jsr(this.subRoutineStartLabel); - naturalExitExceptionHandler.placeEnd(); - codeStream.recordPositionsFrom( - position, - this.finallyBlock.sourceEnd); - break; case FINALLY_INLINE : // inlined finally here can see all merged variables - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); - } + ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); if (this.naturalExitMergeInitStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); @@ -893,16 +831,14 @@ Our initialization type state is the same as it was at the end of the just concl // entire sequence for finally is associated to finally block this.finallyBlock.generateCode(this.scope, codeStream); if (postCatchesFinallyLabel != null) { - position = codeStream.position; + int position = codeStream.position; // entire sequence for finally is associated to finally block codeStream.goto_(postCatchesFinallyLabel); codeStream.recordPositionsFrom( position, this.finallyBlock.sourceEnd); } - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).popStateIndex(); - } + ((StackMapFrameCodeStream) codeStream).popStateIndex(); break; case FINALLY_DOES_NOT_COMPLETE : break; @@ -915,12 +851,12 @@ Our initialization type state is the same as it was at the end of the just concl postCatchesFinallyLabel.place(); } } else { - // no subroutine, simply position end label (natural exit == end) + // no finally block, simply position end label (natural exit == end) naturalExitLabel.place(); } } else { // try block had no effect, only generate the body of the finally block if any - if (this.subRoutineStartLabel != null) { + if (this.finallyBlockStartLabel != null) { this.finallyBlock.generateCode(this.scope, codeStream); } } @@ -990,44 +926,9 @@ private boolean isDuplicateResourceReference(int index) { return false; } -/** - * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) - */ -@Override -public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { - - int resourceCount = this.resources.length; - if (resourceCount > 0 && this.resourceExceptionLabels != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=375248 - for (int i = resourceCount; i > 0; --i) { - // Disarm the handlers and take care of resource closure. - this.resourceExceptionLabels[i].placeEnd(); - BranchLabel exitLabel = new BranchLabel(codeStream); - int invokeCloseStartPc = codeStream.position; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343785 - generateCodeSnippet(this.resources[i - 1], codeStream, exitLabel, false); - codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd); - exitLabel.place(); - } - this.resourceExceptionLabels[0].placeEnd(); // outermost should end here as well, will start again on enter - } - - boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; - int finallyMode = finallyMode(); - switch(finallyMode) { - case FINALLY_DOES_NOT_COMPLETE : - if (this.switchExpression != null) { - exitAnyExceptionHandler(); - exitDeclaredExceptionHandlers(codeStream); - this.finallyBlock.generateCode(currentScope, codeStream); - return true; - } - codeStream.goto_(this.subRoutineStartLabel); - return true; - - case NO_FINALLY : - exitDeclaredExceptionHandlers(codeStream); - return false; - } - // optimize subroutine invocation sequences, using the targetLocation (if any) +// Disabled behavior enabled only by an undocumented option. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=404146 +private boolean reusedFinallyBlock(CodeStream codeStream, Object targetLocation, int stateIndex) { + // optimize finally block generation, using the targetLocation (if any) CompilerOptions options = this.scope.compilerOptions(); if (options.shareCommonFinallyBlocks && targetLocation != null) { boolean reuseTargetLocation = true; @@ -1046,7 +947,7 @@ public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream continue nextReusableTarget; } // current target has been used in the past, simply branch to its label - if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode == FINALLY_INLINE) { + if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode() == FINALLY_INLINE) { reuseTargetLocation = false; break nextReusableTarget; } else { @@ -1072,29 +973,62 @@ public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; } } - if (finallyMode == FINALLY_INLINE) { - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex); + return false; +} +/** + * @see StatementWithFinallyBlock#generateFinallyBlock(BlockScope, CodeStream, Object, int, LocalVariableBinding) + */ +@Override +public boolean generateFinallyBlock(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { + + int resourceCount = this.resources.length; + if (resourceCount > 0 && this.resourceExceptionLabels != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=375248 + for (int i = resourceCount; i > 0; --i) { + // Disarm the handlers and take care of resource closure. + this.resourceExceptionLabels[i].placeEnd(); + BranchLabel exitLabel = new BranchLabel(codeStream); + int invokeCloseStartPc = codeStream.position; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343785 + generateCodeSnippet(this.resources[i - 1], codeStream, exitLabel, false); + codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd); + exitLabel.place(); } - // cannot use jsr bytecode, then simply inline the subroutine - // inside try block, ensure to deactivate all catch block exception handlers while inlining finally block + this.resourceExceptionLabels[0].placeEnd(); // outermost should end here as well, will start again on enter + } + + int finallyMode = finallyMode(); + switch (finallyMode) { + case FINALLY_DOES_NOT_COMPLETE: + if (this.switchExpression != null) { + exitAnyExceptionHandler(); + exitDeclaredExceptionHandlers(codeStream); + this.finallyBlock.generateCode(currentScope, codeStream); + return true; + } + codeStream.goto_(this.finallyBlockStartLabel); + return true; + + case NO_FINALLY: + exitDeclaredExceptionHandlers(codeStream); + return false; + } + + /********* Begin: undocumented behavior off by default ******* */ + if (reusedFinallyBlock( codeStream, targetLocation, stateIndex)) + return true; + /********* End: undocumented behavior off by default ******* */ + + if (finallyMode == FINALLY_INLINE) { + ((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex); exitAnyExceptionHandler(); exitDeclaredExceptionHandlers(codeStream); this.finallyBlock.generateCode(currentScope, codeStream); - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).popStateIndex(); - } - } else { - // classic subroutine invocation, distinguish case of non-returning subroutine - codeStream.jsr(this.subRoutineStartLabel); - exitAnyExceptionHandler(); - exitDeclaredExceptionHandlers(codeStream); + ((StackMapFrameCodeStream) codeStream).popStateIndex(); } return false; } @Override -public boolean isSubRoutineEscaping() { - return (this.bits & ASTNode.IsSubRoutineEscaping) != 0; +public boolean isFinallyBlockEscaping() { + return (this.bits & ASTNode.IsFinallyBlockEscaping) != 0; } @Override @@ -1207,7 +1141,7 @@ public void resolve(BlockScope upperScope) { // provision for returning and forcing the finally block to run MethodScope methodScope = this.scope.methodScope(); - this.subRoutineStartLabel = new BranchLabel(); + this.finallyBlockStartLabel = new BranchLabel(); this.anyExceptionVariable = new LocalVariableBinding(TryStatement.SECRET_ANY_HANDLER_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java index ef6cde4239d..5f6fb710b90 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java @@ -18,7 +18,7 @@ import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InsideSubRoutineFlowContext; +import org.eclipse.jdt.internal.compiler.flow.InsideStatementWithFinallyBlockFlowContext; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; @@ -64,44 +64,43 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.targetLabel = targetContext.breakLabel(); FlowContext traversedContext = flowContext; - int subCount = 0; - this.subroutines = new SubRoutineStatement[5]; + int stmtCount = 0; + this.statementsWithFinallyBlock = new StatementWithFinallyBlock[5]; do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow + StatementWithFinallyBlock stmt; + if ((stmt = traversedContext.statementWithFinallyBlock()) != null) { + if (stmtCount == this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, (this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount*2]), 0, stmtCount); // grow } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { + this.statementsWithFinallyBlock[stmtCount++] = stmt; + if (stmt.isFinallyBlockEscaping()) { break; } } traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); traversedContext.recordBreakTo(targetContext); - if (traversedContext instanceof InsideSubRoutineFlowContext) { + if (traversedContext instanceof InsideStatementWithFinallyBlockFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { - flowInfo.addInitializationsFrom(((TryStatement) node).subRoutineInits); // collect inits + flowInfo.addInitializationsFrom(((TryStatement) node).finallyBlockInits); // collect inits } } else if (traversedContext == targetContext) { - // only record break info once accumulated through subroutines, and only against target context + // only record break info once accumulated and only against target context targetContext.recordBreakFrom(flowInfo); break; } } while ((traversedContext = traversedContext.getLocalParent()) != null); - // resize subroutines - if (subCount != this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); + if (stmtCount != this.statementsWithFinallyBlock.length) { + System.arraycopy(this.statementsWithFinallyBlock, 0, (this.statementsWithFinallyBlock = new StatementWithFinallyBlock[stmtCount]), 0, stmtCount); } return FlowInfo.DEAD_END; } @Override -protected void setSubroutineSwitchExpression(SubRoutineStatement sub) { +protected void setSubroutineSwitchExpression(StatementWithFinallyBlock sub) { sub.setSwitchExpression(this.switchExpression); } @@ -126,7 +125,7 @@ protected void addSecretYieldResultValue(BlockScope scope) { @Override protected void restartExceptionLabels(CodeStream codeStream) { - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, -1, codeStream); } @Override @@ -161,19 +160,19 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { int pc = codeStream.position; // generation of code responsible for invoking the finally // blocks in sequence - if (this.subroutines != null){ - for (int i = 0, max = this.subroutines.length; i < max; i++){ - SubRoutineStatement sub = this.subroutines[i]; - SwitchExpression se = sub.getSwitchExpression(); - setSubroutineSwitchExpression(sub); - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); - sub.setSwitchExpression(se); + if (this.statementsWithFinallyBlock != null){ + for (int i = 0, max = this.statementsWithFinallyBlock.length; i < max; i++){ + StatementWithFinallyBlock stmt = this.statementsWithFinallyBlock[i]; + SwitchExpression se = stmt.getSwitchExpression(); + setSubroutineSwitchExpression(stmt); + boolean didEscape = stmt.generateFinallyBlock(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); + stmt.setSwitchExpression(se); if (didEscape) { if (generateExpressionResultCodeExpanded) { codeStream.removeVariable(this.secretYieldResultValue); } codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, i, codeStream); if (this.initStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); @@ -190,7 +189,7 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { } codeStream.goto_(this.targetLabel); codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); + StatementWithFinallyBlock.reenterAllExceptionHandlers(this.statementsWithFinallyBlock, -1, codeStream); if (this.initStateIndex != -1) { codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java index 9e5c53fe73f..c2a820147ca 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java @@ -5744,30 +5744,6 @@ public void ixor() { this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ixor; } -final public void jsr(BranchLabel lbl) { - if (this.wideMode) { - jsr_w(lbl); - return; - } - this.countLabels = 0; - if (this.classFileOffset >= this.bCodeStream.length) { - resizeByteArray(); - } - this.position++; - this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_jsr; - lbl.branch(); -} - -final public void jsr_w(BranchLabel lbl) { - this.countLabels = 0; - if (this.classFileOffset >= this.bCodeStream.length) { - resizeByteArray(); - } - this.position++; - this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_jsr_w; - lbl.branchWide(); -} - public void l2d() { this.countLabels = 0; if (this.classFileOffset >= this.bCodeStream.length) { @@ -7233,26 +7209,6 @@ private final void resizeByteArray() { System.arraycopy(this.bCodeStream, 0, this.bCodeStream = new byte[requiredSize], 0, length); } -final public void ret(int index) { - this.countLabels = 0; - if (index > 255) { // Widen - if (this.classFileOffset + 3 >= this.bCodeStream.length) { - resizeByteArray(); - } - this.position += 2; - this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_wide; - this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ret; - writeUnsignedShort(index); - } else { // Don't Widen - if (this.classFileOffset + 1 >= this.bCodeStream.length) { - resizeByteArray(); - } - this.position += 2; - this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ret; - this.bCodeStream[this.classFileOffset++] = (byte) index; - } -} - public void return_() { this.countLabels = 0; if (this.classFileOffset >= this.bCodeStream.length) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java index f35a7d8f286..8eeccfb7ff2 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java @@ -24,7 +24,7 @@ import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement; +import org.eclipse.jdt.internal.compiler.ast.StatementWithFinallyBlock; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference; @@ -310,19 +310,19 @@ public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { } /** - * Exception handlers (with no finally block) are also included with subroutine - * only once (in case parented with true InsideSubRoutineFlowContext). - * Standard management of subroutines need to also operate on intermediate + * Exception handlers (with no finally block) are also included with statement with finally block + * only once (in case parented with true InsideStatementWithFinallyBlockFlowContext). + * Standard management of statements with finally blocks need to also operate on intermediate * exception handlers. - * @see org.eclipse.jdt.internal.compiler.flow.FlowContext#subroutine() + * @see org.eclipse.jdt.internal.compiler.flow.FlowContext#statementWithFinallyBlock() */ @Override -public SubRoutineStatement subroutine() { - if (this.associatedNode instanceof SubRoutineStatement) { - // exception handler context may be child of InsideSubRoutineFlowContext, which maps to same handler - if (this.parent.subroutine() == this.associatedNode) +public StatementWithFinallyBlock statementWithFinallyBlock() { + if (this.associatedNode instanceof StatementWithFinallyBlock) { + // exception handler context may be child of InsideStatementWithFinallyBlockFlowContext, which maps to same handler + if (this.parent.statementWithFinallyBlock() == this.associatedNode) return null; - return (SubRoutineStatement) this.associatedNode; + return (StatementWithFinallyBlock) this.associatedNode; } return null; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java index cbf65ca5ee1..fc59e146c5e 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java @@ -67,7 +67,7 @@ public FinallyFlowContext(FlowContext parent, ASTNode associatedNode, ExceptionH /** * Given some contextual initialization info (derived from a try block or a catch block), this - * code will check that the subroutine context does not also initialize a final variable potentially set + * code will check that the finally context does not also initialize a final variable potentially set * redundantly. */ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { @@ -101,9 +101,7 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { if (complained) { FlowContext currentContext = this.getLocalParent(); while (currentContext != null) { - //if (currentContext.isSubRoutine()) { currentContext.removeFinalAssignmentIfAny(this.finalAssignments[i]); - //} currentContext = currentContext.getLocalParent(); } } @@ -242,11 +240,6 @@ public String individualToString() { return buffer.toString(); } - @Override - public boolean isSubRoutine() { - return true; - } - @Override protected boolean recordFinalAssignment( VariableBinding binding, diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FlowContext.java index 4f6394109b8..414d51e8f44 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FlowContext.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/FlowContext.java @@ -249,9 +249,9 @@ public void checkExceptionHandlers(TypeBinding raisedException, ASTNode location } } while (traversedContext != null) { - SubRoutineStatement sub; - if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) { - // traversing a non-returning subroutine means that all unhandled + StatementWithFinallyBlock stmt; + if (((stmt = traversedContext.statementWithFinallyBlock()) != null) && stmt.isFinallyBlockEscaping()) { + // traversing a non-returning finally block means that all unhandled // exceptions will actually never get sent... return; } @@ -331,11 +331,11 @@ public void checkExceptionHandlers(TypeBinding raisedException, ASTNode location traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); if (!isExceptionOnAutoClose) { - if (traversedContext instanceof InsideSubRoutineFlowContext) { + if (traversedContext instanceof InsideStatementWithFinallyBlockFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + flowInfo.addInitializationsFrom(tryStatement.finallyBlockInits); // collect inits } } } @@ -373,9 +373,9 @@ public void checkExceptionHandlers(TypeBinding[] raisedExceptions, ASTNode locat ArrayList abruptlyExitedLoops = null; while (traversedContext != null) { - SubRoutineStatement sub; - if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) { - // traversing a non-returning subroutine means that all unhandled + StatementWithFinallyBlock stmt; + if (((stmt = traversedContext.statementWithFinallyBlock()) != null) && stmt.isFinallyBlockEscaping()) { + // traversing a non-returning finally block means that all unhandled // exceptions will actually never get sent... return; } @@ -482,11 +482,11 @@ public void checkExceptionHandlers(TypeBinding[] raisedExceptions, ASTNode locat traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - if (traversedContext instanceof InsideSubRoutineFlowContext) { + if (traversedContext instanceof InsideStatementWithFinallyBlockFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + flowInfo.addInitializationsFrom(tryStatement.finallyBlockInits); // collect inits } } traversedContext = traversedContext.getLocalParent(); @@ -537,20 +537,20 @@ public FlowInfo getInitsForFinalBlankInitializationCheck(TypeBinding declaringTy * lookup through break labels */ public FlowContext getTargetContextForBreakLabel(char[] labelName) { - FlowContext current = this, lastNonReturningSubRoutine = null; + FlowContext current = this, lastNonReturningContext = null; while (current != null) { if (current.associatedNode instanceof SwitchExpression) return NonLocalGotoThroughSwitchContext; if (current.isNonReturningContext()) { - lastNonReturningSubRoutine = current; + lastNonReturningContext = current; } char[] currentLabelName; if (((currentLabelName = current.labelName()) != null) && CharOperation.equals(currentLabelName, labelName)) { ((LabeledStatement)current.associatedNode).bits |= ASTNode.LabelUsed; - if (lastNonReturningSubRoutine == null) + if (lastNonReturningContext == null) return current; - return lastNonReturningSubRoutine; + return lastNonReturningContext; } current = current.getLocalParent(); } @@ -564,13 +564,13 @@ public FlowContext getTargetContextForBreakLabel(char[] labelName) { public FlowContext getTargetContextForContinueLabel(char[] labelName) { FlowContext current = this; FlowContext lastContinuable = null; - FlowContext lastNonReturningSubRoutine = null; + FlowContext lastNonReturningContext = null; while (current != null) { if (current.associatedNode instanceof SwitchExpression) return NonLocalGotoThroughSwitchContext; if (current.isNonReturningContext()) { - lastNonReturningSubRoutine = current; + lastNonReturningContext = current; } else { if (current.isContinuable()) { lastContinuable = current; @@ -585,8 +585,8 @@ public FlowContext getTargetContextForContinueLabel(char[] labelName) { if ((lastContinuable != null) && (current.associatedNode.concreteStatement() == lastContinuable.associatedNode)) { - if (lastNonReturningSubRoutine == null) return lastContinuable; - return lastNonReturningSubRoutine; + if (lastNonReturningContext == null) return lastContinuable; + return lastNonReturningContext; } // label is found, but not a continuable location return FlowContext.NotContinuableContext; @@ -601,16 +601,16 @@ public FlowContext getTargetContextForContinueLabel(char[] labelName) { * lookup a default break through breakable locations */ public FlowContext getTargetContextForDefaultBreak() { - FlowContext current = this, lastNonReturningSubRoutine = null; + FlowContext current = this, lastNonReturningContext = null; while (current != null) { if (current.associatedNode instanceof SwitchExpression) return NonLocalGotoThroughSwitchContext; if (current.isNonReturningContext()) { - lastNonReturningSubRoutine = current; + lastNonReturningContext = current; } if (current.isBreakable() && current.labelName() == null) { - if (lastNonReturningSubRoutine == null) return current; - return lastNonReturningSubRoutine; + if (lastNonReturningContext == null) return current; + return lastNonReturningContext; } current = current.getLocalParent(); } @@ -621,14 +621,14 @@ public FlowContext getTargetContextForDefaultBreak() { * lookup a yield target ... */ public FlowContext getTargetContextForYield(boolean requireExpression) { - FlowContext current = this, lastNonReturningSubRoutine = null; + FlowContext current = this, lastNonReturningContext = null; while (current != null) { if (current.isNonReturningContext()) { - lastNonReturningSubRoutine = current; + lastNonReturningContext = current; } if (current.isBreakable() && current.labelName() == null && (!requireExpression || ((SwitchFlowContext) current).isExpression)) { - if (lastNonReturningSubRoutine == null) return current; - return lastNonReturningSubRoutine; + if (lastNonReturningContext == null) return current; + return lastNonReturningContext; } current = current.getLocalParent(); } @@ -640,17 +640,17 @@ public FlowContext getTargetContextForYield(boolean requireExpression) { * lookup a default continue amongst continuable locations */ public FlowContext getTargetContextForDefaultContinue() { - FlowContext current = this, lastNonReturningSubRoutine = null; + FlowContext current = this, lastNonReturningContext = null; while (current != null) { if (current.associatedNode instanceof SwitchExpression) return NonLocalGotoThroughSwitchContext; if (current.isNonReturningContext()) { - lastNonReturningSubRoutine = current; + lastNonReturningContext = current; } if (current.isContinuable()) { - if (lastNonReturningSubRoutine == null) + if (lastNonReturningContext == null) return current; - return lastNonReturningSubRoutine; + return lastNonReturningContext; } current = current.getLocalParent(); } @@ -699,10 +699,6 @@ public boolean isNonReturningContext() { return false; } -public boolean isSubRoutine() { - return false; -} - public char[] labelName() { return null; } @@ -1028,7 +1024,7 @@ void removeFinalAssignmentIfAny(Reference reference) { // default implementation: do nothing } -public SubRoutineStatement subroutine() { +public StatementWithFinallyBlock statementWithFinallyBlock() { return null; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/InsideStatementWithFinallyBlockFlowContext.java similarity index 75% rename from org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java rename to org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/InsideStatementWithFinallyBlockFlowContext.java index bf746db6ce6..d94de0337e1 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/flow/InsideStatementWithFinallyBlockFlowContext.java @@ -14,17 +14,17 @@ package org.eclipse.jdt.internal.compiler.flow; import org.eclipse.jdt.internal.compiler.ast.ASTNode; -import org.eclipse.jdt.internal.compiler.ast.SubRoutineStatement; +import org.eclipse.jdt.internal.compiler.ast.StatementWithFinallyBlock; /** * Reflects the context of code analysis, keeping track of enclosing * try statements, exception handlers, etc... */ -public class InsideSubRoutineFlowContext extends TryFlowContext { +public class InsideStatementWithFinallyBlockFlowContext extends TryFlowContext { public UnconditionalFlowInfo initsOnReturn; -public InsideSubRoutineFlowContext( +public InsideStatementWithFinallyBlockFlowContext( FlowContext parent, ASTNode associatedNode) { super(parent, associatedNode); @@ -33,7 +33,7 @@ public InsideSubRoutineFlowContext( @Override public String individualToString() { - StringBuilder buffer = new StringBuilder("Inside SubRoutine flow context"); //$NON-NLS-1$ + StringBuilder buffer = new StringBuilder("Inside StatementWithPostScript flow context"); //$NON-NLS-1$ buffer.append("[initsOnReturn -").append(this.initsOnReturn.toString()).append(']'); //$NON-NLS-1$ return buffer.toString(); } @@ -45,7 +45,7 @@ public UnconditionalFlowInfo initsOnReturn(){ @Override public boolean isNonReturningContext() { - return ((SubRoutineStatement) this.associatedNode).isSubRoutineEscaping(); + return ((StatementWithFinallyBlock) this.associatedNode).isFinallyBlockEscaping(); } @Override @@ -60,7 +60,7 @@ public void recordReturnFrom(UnconditionalFlowInfo flowInfo) { } @Override -public SubRoutineStatement subroutine() { - return (SubRoutineStatement) this.associatedNode; +public StatementWithFinallyBlock statementWithFinallyBlock() { + return (StatementWithFinallyBlock) this.associatedNode; } } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java index 333378d416d..c2352305627 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java @@ -289,7 +289,7 @@ public TypeBinding getAnnotatedType(TypeBinding type, AnnotationBinding[][] anno return annotatedType; } - /* Private subroutine for public APIs. Create an annotated version of the type. To materialize the annotated version, we can't use new since + /* Private method for public APIs. Create an annotated version of the type. To materialize the annotated version, we can't use new since this is a general purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type that may itself be possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. Likewise so the bindings for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index 13ccd487d6b..1fe6b58c634 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -303,8 +303,8 @@ public final class JavaCore extends Plugin { public static final String COMPILER_CODEGEN_TARGET_PLATFORM = PLUGIN_ID + ".compiler.codegen.targetPlatform"; //$NON-NLS-1$ /** * Compiler option ID: Inline JSR Bytecode Instruction. - *

When enabled, the compiler will no longer generate JSR instructions, but rather inline corresponding - * subroutine code sequences (mostly corresponding to try finally blocks). The generated code will thus + *

When enabled, the compiler will no longer generate JSR instructions, but will rather inline the corresponding + * finally blocks). The generated code will thus * get bigger, but will load faster on virtual machines since the verification process is then much simpler.

*

This mode is anticipating support for the Java Specification Request 202.

*

Note that from 1.5 on, the JSR inlining is mandatory (also see related setting {@link #COMPILER_CODEGEN_TARGET_PLATFORM}).