Skip to content

Commit

Permalink
* Modernize exception handling by pruning behavior applicable only to…
Browse files Browse the repository at this point in the history
… 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 #3240
  • Loading branch information
srikanth-sankaran authored Nov 5, 2024
1 parent 7ce3a3c commit 09286e7
Show file tree
Hide file tree
Showing 17 changed files with 268 additions and 393 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>null</code> if not reusable
*/
public Object reusableJSRTarget() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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);
}

/**
Expand All @@ -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){
Expand Down
Loading

0 comments on commit 09286e7

Please sign in to comment.