### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java,v retrieving revision 1.16 diff -u -r1.16 StackMapFrameCodeStream.java --- compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java 5 Jan 2007 04:26:55 -0000 1.16 +++ compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java 20 Jan 2007 03:28:02 -0000 @@ -38,6 +38,9 @@ public ArrayList variablesModificationsPositions; + public int[] stateIndexes; + public int stateIndexesCounter; + public StackMapFrameCodeStream(ClassFile givenClassFile) { super(givenClassFile); } @@ -56,11 +59,34 @@ } public void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) { // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect - for (int i = 0; i < visibleLocalsCount; i++) { + loop: for (int i = 0; i < visibleLocalsCount; i++) { LocalVariableBinding localBinding = visibleLocals[i]; if (localBinding != null) { // Check if the local is definitely assigned - if (isDefinitelyAssigned(scope, initStateIndex, localBinding)) { + boolean isDefinitelyAssigned = isDefinitelyAssigned(scope, initStateIndex, localBinding); + if (!isDefinitelyAssigned) { + if (this.stateIndexes != null) { + for (int j = 0, max = this.stateIndexesCounter; j < max; j++) { + if (isDefinitelyAssigned(scope, this.stateIndexes[j], localBinding)) { + currentFrame.putLocal(localBinding.resolvedPosition, new VerificationTypeInfo(localBinding.type)); + if ((localBinding.initializationCount == 0) || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1) + 1] != -1)) { + /* There are two cases: + * 1) there is no initialization interval opened ==> add an opened interval + * 2) there is already some initialization intervals but the last one is closed ==> add an opened interval + * An opened interval means that the value at localBinding.initializationPCs[localBinding.initializationCount - 1][1] + * is equals to -1. + * initializationPCs is a collection of pairs of int: + * first value is the startPC and second value is the endPC. -1 one for the last value means that the interval + * is not closed yet. + */ + localBinding.recordInitializationStartPC(position); + } + continue loop; + } + } + } + } else { + currentFrame.putLocal(localBinding.resolvedPosition, new VerificationTypeInfo(localBinding.type)); if ((localBinding.initializationCount == 0) || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1) + 1] != -1)) { /* There are two cases: * 1) there is no initialization interval opened ==> add an opened interval @@ -71,7 +97,7 @@ * first value is the startPC and second value is the endPC. -1 one for the last value means that the interval * is not closed yet. */ - currentFrame.putLocal(localBinding.resolvedPosition, new VerificationTypeInfo(localBinding.type)); + localBinding.recordInitializationStartPC(position); } } } @@ -81,7 +107,6 @@ this.variablesModificationsPositions.add(newValue); } storeStackMapFrame(); - super.addDefinitelyAssignedVariables(scope, initStateIndex); } public void addVariable(LocalVariableBinding localBinding) { currentFrame.putLocal(localBinding.resolvedPosition, new VerificationTypeInfo(localBinding.type)); @@ -1746,6 +1771,9 @@ this.currentFrame.numberOfStackItems -= 2; } } +public void popStateIndex() { + this.stateIndexesCounter--; +} public void pushOnStack(TypeBinding binding) { super.pushOnStack(binding); this.currentFrame.addStackItem(binding); @@ -1754,6 +1782,18 @@ super.putfield(fieldBinding); this.currentFrame.numberOfStackItems -= 2; } + +public void pushStateIndex(int naturalExitMergeInitStateIndex) { + if (this.stateIndexes == null) { + this.stateIndexes = new int[3]; + } + int length = this.stateIndexes.length; + if (length == this.stateIndexesCounter) { + // resize + System.arraycopy(this.stateIndexes, 0, (this.stateIndexes = new int[length * 2]), 0, length); + } + this.stateIndexes[this.stateIndexesCounter++] = naturalExitMergeInitStateIndex; +} public void putstatic(FieldBinding fieldBinding) { super.putstatic(fieldBinding); this.currentFrame.numberOfStackItems--; @@ -1768,11 +1808,21 @@ } public void removeNotDefinitelyAssignedVariables(Scope scope, int initStateIndex) { int index = this.visibleLocalsCount; - for (int i = 0; i < index; i++) { + loop : for (int i = 0; i < index; i++) { LocalVariableBinding localBinding = visibleLocals[i]; - if (localBinding != null && !isDefinitelyAssigned(scope, initStateIndex, localBinding) - && localBinding.initializationCount > 0) { - this.currentFrame.removeLocals(localBinding.resolvedPosition); + if (localBinding != null && localBinding.initializationCount > 0) { + boolean isDefinitelyAssigned = isDefinitelyAssigned(scope, initStateIndex, localBinding); + if (!isDefinitelyAssigned) { + if (this.stateIndexes != null) { + for (int j = 0, max = this.stateIndexesCounter; j < max; j++) { + if (isDefinitelyAssigned(scope, this.stateIndexes[j], localBinding)) { + continue loop; + } + } + } + this.currentFrame.removeLocals(localBinding.resolvedPosition); + localBinding.recordInitializationEndPC(position); + } } } Integer newValue = new Integer(this.position); @@ -1780,7 +1830,6 @@ this.variablesModificationsPositions.add(newValue); } storeStackMapFrame(); - super.removeNotDefinitelyAssignedVariables(scope, initStateIndex); } public void storeStackMapFrame() { int frameSize = this.frames.size(); Index: compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java,v retrieving revision 1.147 diff -u -r1.147 CodeStream.java --- compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java 22 Dec 2006 16:08:15 -0000 1.147 +++ compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java 20 Jan 2007 03:28:02 -0000 @@ -4525,11 +4525,11 @@ } public boolean isDefinitelyAssigned(Scope scope, int initStateIndex, LocalVariableBinding local) { // Mirror of UnconditionalFlowInfo.isDefinitelyAssigned(..) - if (initStateIndex == -1) - return false; if ((local.tagBits & TagBits.IsArgument) != 0) { return true; } + if (initStateIndex == -1) + return false; int localPosition = local.id + maxFieldCount; MethodScope methodScope = scope.methodScope(); // id is zero-based Index: compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java,v retrieving revision 1.54 diff -u -r1.54 ReturnStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 4 Sep 2006 17:05:32 -0000 1.54 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 20 Jan 2007 03:27:59 -0000 @@ -39,9 +39,9 @@ if (this.expression != null) { flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); - this.initStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); } + this.initStateIndex = + currentScope.methodScope().recordInitializationStates(flowInfo); // compute the return sequence (running the finally blocks) FlowContext traversedContext = flowContext; int subCount = 0; @@ -132,12 +132,8 @@ 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); + boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, reusableJSRTarget, this.initStateIndex, this.saveValueVariable); if (didEscape) { - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } codeStream.recordPositionsFrom(pc, this.sourceStart); SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); return; @@ -174,7 +170,9 @@ } public void generateStoreSaveValueIfNecessary(CodeStream codeStream){ - if (this.saveValueVariable != null) codeStream.store(this.saveValueVariable, false); + if (this.saveValueVariable != null) { + codeStream.store(this.saveValueVariable, false); + } } public boolean needValue() { Index: compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java,v retrieving revision 1.20 diff -u -r1.20 BranchStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java 23 Aug 2006 16:32:56 -0000 1.20 +++ compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java 20 Jan 2007 03:27:59 -0000 @@ -45,7 +45,7 @@ if (this.subroutines != null){ for (int i = 0, max = this.subroutines.length; i < max; i++){ SubRoutineStatement sub = this.subroutines[i]; - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel); + boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); if (didEscape) { codeStream.recordPositionsFrom(pc, this.sourceStart); SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); Index: compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java,v retrieving revision 1.12 diff -u -r1.12 SubRoutineStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java 23 Aug 2006 16:32:56 -0000 1.12 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java 20 Jan 2007 03:27:59 -0000 @@ -13,6 +13,7 @@ import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; /** * Extra behavior for statements which are generating subroutines @@ -55,7 +56,7 @@ } - public abstract boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation); + public abstract boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal); public abstract boolean isSubRoutineEscaping(); Index: compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java,v retrieving revision 1.45 diff -u -r1.45 SynchronizedStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java 23 Aug 2006 16:32:56 -0000 1.45 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java 20 Jan 2007 03:27:59 -0000 @@ -152,9 +152,9 @@ } /** - * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object) + * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) */ -public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation) { +public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { codeStream.load(this.synchroVariable); codeStream.monitorexit(); exitAnyExceptionHandler(); Index: compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java,v retrieving revision 1.104 diff -u -r1.104 TryStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 8 Jan 2007 15:52:42 -0000 1.104 +++ compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java 20 Jan 2007 03:27:59 -0000 @@ -47,6 +47,7 @@ // for inlining/optimizing JSR instructions private Object[] reusableJSRTargets; private BranchLabel[] reusableJSRSequenceStartLabels; + private int[] reusableJSRStateIndexes; private int reusableJSRTargetsCount = 0; private final static int NO_FINALLY = 0; // no finally block @@ -57,7 +58,7 @@ // for local variables table attributes int mergedInitStateIndex = -1; int preTryInitStateIndex = -1; - int postTryInitStateIndex = -1; + int naturalExitMergeInitStateIndex = -1; public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { @@ -95,12 +96,10 @@ FlowInfo tryInfo; if (this.tryBlock.isEmptyBlock()) { tryInfo = flowInfo; - this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); } else { tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) this.bits |= ASTNode.IsTryBlockExiting; - this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); } // check unreachable catch blocks @@ -207,12 +206,10 @@ FlowInfo tryInfo; if (this.tryBlock.isEmptyBlock()) { tryInfo = flowInfo; - this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); } else { tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) this.bits |= ASTNode.IsTryBlockExiting; - this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); } // check unreachable catch blocks @@ -293,6 +290,8 @@ flowContext.initsOnFinally.add(handlingContext.initsOnFinally); } + this.naturalExitMergeInitStateIndex = + currentScope.methodScope().recordInitializationStates(tryInfo); if (subInfo == FlowInfo.DEAD_END) { this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(subInfo); @@ -404,16 +403,16 @@ case FINALLY_SUBROUTINE : case FINALLY_INLINE : requiresNaturalExit = true; - if (this.postTryInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); + if (this.naturalExitMergeInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); } codeStream.goto_(naturalExitLabel); break; case NO_FINALLY : - if (this.postTryInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); + if (this.naturalExitMergeInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); } codeStream.goto_(naturalExitLabel); break; @@ -464,9 +463,9 @@ requiresNaturalExit = true; // fall through case NO_FINALLY : - if (this.postTryInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); + if (this.naturalExitMergeInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); } codeStream.goto_(naturalExitLabel); break; @@ -491,6 +490,7 @@ if (this.preTryInitStateIndex != -1) { // reset initialization state, as for a normal catch block codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); } this.placeAllAnyExceptionHandler(); if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); @@ -557,9 +557,13 @@ break; case FINALLY_INLINE : // inlined finally here can see all merged variables - if (this.postTryInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); + boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; + if (isStackMapFrameCodeStream) { + ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); + } + if (this.naturalExitMergeInitStateIndex != -1) { + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); } naturalExitLabel.place(); // entire sequence for finally is associated to finally block @@ -572,6 +576,9 @@ position, this.finallyBlock.sourceEnd); } + if (isStackMapFrameCodeStream) { + ((StackMapFrameCodeStream) codeStream).popStateIndex(); + } break; case FINALLY_DOES_NOT_COMPLETE : break; @@ -617,10 +624,11 @@ } /** - * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object) + * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) */ -public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation) { +public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { + boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; int finallyMode = finallyMode(); switch(finallyMode) { case FINALLY_DOES_NOT_COMPLETE : @@ -633,6 +641,7 @@ } // optimize subroutine invocation sequences, using the targetLocation (if any) if (targetLocation != null) { + boolean reuseTargetLocation = true; if (this.reusableJSRTargetsCount > 0) { nextReusableTarget: for (int i = 0, count = this.reusableJSRTargetsCount; i < count; i++) { Object reusableJSRTarget = this.reusableJSRTargets[i]; @@ -648,32 +657,58 @@ continue nextReusableTarget; } // current target has been used in the past, simply branch to its label - codeStream.goto_(this.reusableJSRSequenceStartLabels[i]); - return true; + if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode == FINALLY_INLINE && isStackMapFrameCodeStream) { + reuseTargetLocation = false; + break nextReusableTarget; + } else { + codeStream.goto_(this.reusableJSRSequenceStartLabels[i]); + return true; + } } } else { this.reusableJSRTargets = new Object[3]; this.reusableJSRSequenceStartLabels = new BranchLabel[3]; + this.reusableJSRStateIndexes = new int[3]; + } + if (reuseTargetLocation) { + if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) { + System.arraycopy(this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); + System.arraycopy(this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); + System.arraycopy(this.reusableJSRStateIndexes, 0, this.reusableJSRStateIndexes = new int[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); + } + this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation; + BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream); + reusableJSRSequenceStartLabel.place(); + this.reusableJSRStateIndexes[this.reusableJSRTargetsCount] = stateIndex; + this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; } - if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) { - System.arraycopy(this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); - System.arraycopy(this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); - } - this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation; - BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream); - reusableJSRSequenceStartLabel.place(); - this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; - } + } if (finallyMode == FINALLY_INLINE) { - if (this.preTryInitStateIndex != -1) { - // reset initialization state, as for a normal catch block - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); + if (isStackMapFrameCodeStream) { + ((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex); + if (this.naturalExitMergeInitStateIndex != -1 || stateIndex != -1) { + // reset initialization state, as for a normal catch block + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + } + } else { + if (this.naturalExitMergeInitStateIndex != -1) { + // reset initialization state, as for a normal catch block + codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); + } + } + if (secretLocal != null) { + codeStream.addVariable(secretLocal); } // cannot use jsr bytecode, then simply inline the subroutine // inside try block, ensure to deactivate all catch block exception handlers while inlining finally block 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); @@ -682,7 +717,6 @@ } return false; } - public boolean isSubRoutineEscaping() { return (this.bits & ASTNode.IsSubRoutineEscaping) != 0; }