Lines 47-52
Link Here
|
47 |
// for inlining/optimizing JSR instructions |
47 |
// for inlining/optimizing JSR instructions |
48 |
private Object[] reusableJSRTargets; |
48 |
private Object[] reusableJSRTargets; |
49 |
private BranchLabel[] reusableJSRSequenceStartLabels; |
49 |
private BranchLabel[] reusableJSRSequenceStartLabels; |
|
|
50 |
private int[] reusableJSRStateIndexes; |
50 |
private int reusableJSRTargetsCount = 0; |
51 |
private int reusableJSRTargetsCount = 0; |
51 |
|
52 |
|
52 |
private final static int NO_FINALLY = 0; // no finally block |
53 |
private final static int NO_FINALLY = 0; // no finally block |
Lines 57-63
Link Here
|
57 |
// for local variables table attributes |
58 |
// for local variables table attributes |
58 |
int mergedInitStateIndex = -1; |
59 |
int mergedInitStateIndex = -1; |
59 |
int preTryInitStateIndex = -1; |
60 |
int preTryInitStateIndex = -1; |
60 |
int postTryInitStateIndex = -1; |
61 |
int naturalExitMergeInitStateIndex = -1; |
61 |
|
62 |
|
62 |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { |
63 |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { |
63 |
|
64 |
|
Lines 95-106
Link Here
|
95 |
FlowInfo tryInfo; |
96 |
FlowInfo tryInfo; |
96 |
if (this.tryBlock.isEmptyBlock()) { |
97 |
if (this.tryBlock.isEmptyBlock()) { |
97 |
tryInfo = flowInfo; |
98 |
tryInfo = flowInfo; |
98 |
this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); |
|
|
99 |
} else { |
99 |
} else { |
100 |
tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); |
100 |
tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); |
101 |
if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) |
101 |
if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) |
102 |
this.bits |= ASTNode.IsTryBlockExiting; |
102 |
this.bits |= ASTNode.IsTryBlockExiting; |
103 |
this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); |
|
|
104 |
} |
103 |
} |
105 |
|
104 |
|
106 |
// check unreachable catch blocks |
105 |
// check unreachable catch blocks |
Lines 207-218
Link Here
|
207 |
FlowInfo tryInfo; |
206 |
FlowInfo tryInfo; |
208 |
if (this.tryBlock.isEmptyBlock()) { |
207 |
if (this.tryBlock.isEmptyBlock()) { |
209 |
tryInfo = flowInfo; |
208 |
tryInfo = flowInfo; |
210 |
this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); |
|
|
211 |
} else { |
209 |
} else { |
212 |
tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); |
210 |
tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy()); |
213 |
if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) |
211 |
if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0) |
214 |
this.bits |= ASTNode.IsTryBlockExiting; |
212 |
this.bits |= ASTNode.IsTryBlockExiting; |
215 |
this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); |
|
|
216 |
} |
213 |
} |
217 |
|
214 |
|
218 |
// check unreachable catch blocks |
215 |
// check unreachable catch blocks |
Lines 293-298
Link Here
|
293 |
flowContext.initsOnFinally.add(handlingContext.initsOnFinally); |
290 |
flowContext.initsOnFinally.add(handlingContext.initsOnFinally); |
294 |
} |
291 |
} |
295 |
|
292 |
|
|
|
293 |
this.naturalExitMergeInitStateIndex = |
294 |
currentScope.methodScope().recordInitializationStates(tryInfo); |
296 |
if (subInfo == FlowInfo.DEAD_END) { |
295 |
if (subInfo == FlowInfo.DEAD_END) { |
297 |
this.mergedInitStateIndex = |
296 |
this.mergedInitStateIndex = |
298 |
currentScope.methodScope().recordInitializationStates(subInfo); |
297 |
currentScope.methodScope().recordInitializationStates(subInfo); |
Lines 404-419
Link Here
|
404 |
case FINALLY_SUBROUTINE : |
403 |
case FINALLY_SUBROUTINE : |
405 |
case FINALLY_INLINE : |
404 |
case FINALLY_INLINE : |
406 |
requiresNaturalExit = true; |
405 |
requiresNaturalExit = true; |
407 |
if (this.postTryInitStateIndex != -1) { |
406 |
if (this.naturalExitMergeInitStateIndex != -1) { |
408 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
407 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
409 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
408 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
410 |
} |
409 |
} |
411 |
codeStream.goto_(naturalExitLabel); |
410 |
codeStream.goto_(naturalExitLabel); |
412 |
break; |
411 |
break; |
413 |
case NO_FINALLY : |
412 |
case NO_FINALLY : |
414 |
if (this.postTryInitStateIndex != -1) { |
413 |
if (this.naturalExitMergeInitStateIndex != -1) { |
415 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
414 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
416 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
415 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
417 |
} |
416 |
} |
418 |
codeStream.goto_(naturalExitLabel); |
417 |
codeStream.goto_(naturalExitLabel); |
419 |
break; |
418 |
break; |
Lines 464-472
Link Here
|
464 |
requiresNaturalExit = true; |
463 |
requiresNaturalExit = true; |
465 |
// fall through |
464 |
// fall through |
466 |
case NO_FINALLY : |
465 |
case NO_FINALLY : |
467 |
if (this.postTryInitStateIndex != -1) { |
466 |
if (this.naturalExitMergeInitStateIndex != -1) { |
468 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
467 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
469 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
468 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
470 |
} |
469 |
} |
471 |
codeStream.goto_(naturalExitLabel); |
470 |
codeStream.goto_(naturalExitLabel); |
472 |
break; |
471 |
break; |
Lines 491-496
Link Here
|
491 |
if (this.preTryInitStateIndex != -1) { |
490 |
if (this.preTryInitStateIndex != -1) { |
492 |
// reset initialization state, as for a normal catch block |
491 |
// reset initialization state, as for a normal catch block |
493 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); |
492 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); |
|
|
493 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); |
494 |
} |
494 |
} |
495 |
this.placeAllAnyExceptionHandler(); |
495 |
this.placeAllAnyExceptionHandler(); |
496 |
if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); |
496 |
if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); |
Lines 557-565
Link Here
|
557 |
break; |
557 |
break; |
558 |
case FINALLY_INLINE : |
558 |
case FINALLY_INLINE : |
559 |
// inlined finally here can see all merged variables |
559 |
// inlined finally here can see all merged variables |
560 |
if (this.postTryInitStateIndex != -1) { |
560 |
boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; |
561 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
561 |
if (isStackMapFrameCodeStream) { |
562 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); |
562 |
((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); |
|
|
563 |
} |
564 |
if (this.naturalExitMergeInitStateIndex != -1) { |
565 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
566 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
563 |
} |
567 |
} |
564 |
naturalExitLabel.place(); |
568 |
naturalExitLabel.place(); |
565 |
// entire sequence for finally is associated to finally block |
569 |
// entire sequence for finally is associated to finally block |
Lines 572-577
Link Here
|
572 |
position, |
576 |
position, |
573 |
this.finallyBlock.sourceEnd); |
577 |
this.finallyBlock.sourceEnd); |
574 |
} |
578 |
} |
|
|
579 |
if (isStackMapFrameCodeStream) { |
580 |
((StackMapFrameCodeStream) codeStream).popStateIndex(); |
581 |
} |
575 |
break; |
582 |
break; |
576 |
case FINALLY_DOES_NOT_COMPLETE : |
583 |
case FINALLY_DOES_NOT_COMPLETE : |
577 |
break; |
584 |
break; |
Lines 617-626
Link Here
|
617 |
} |
624 |
} |
618 |
|
625 |
|
619 |
/** |
626 |
/** |
620 |
* @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object) |
627 |
* @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) |
621 |
*/ |
628 |
*/ |
622 |
public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation) { |
629 |
public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { |
623 |
|
630 |
|
|
|
631 |
boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; |
624 |
int finallyMode = finallyMode(); |
632 |
int finallyMode = finallyMode(); |
625 |
switch(finallyMode) { |
633 |
switch(finallyMode) { |
626 |
case FINALLY_DOES_NOT_COMPLETE : |
634 |
case FINALLY_DOES_NOT_COMPLETE : |
Lines 633-638
Link Here
|
633 |
} |
641 |
} |
634 |
// optimize subroutine invocation sequences, using the targetLocation (if any) |
642 |
// optimize subroutine invocation sequences, using the targetLocation (if any) |
635 |
if (targetLocation != null) { |
643 |
if (targetLocation != null) { |
|
|
644 |
boolean reuseTargetLocation = true; |
636 |
if (this.reusableJSRTargetsCount > 0) { |
645 |
if (this.reusableJSRTargetsCount > 0) { |
637 |
nextReusableTarget: for (int i = 0, count = this.reusableJSRTargetsCount; i < count; i++) { |
646 |
nextReusableTarget: for (int i = 0, count = this.reusableJSRTargetsCount; i < count; i++) { |
638 |
Object reusableJSRTarget = this.reusableJSRTargets[i]; |
647 |
Object reusableJSRTarget = this.reusableJSRTargets[i]; |
Lines 648-679
Link Here
|
648 |
continue nextReusableTarget; |
657 |
continue nextReusableTarget; |
649 |
} |
658 |
} |
650 |
// current target has been used in the past, simply branch to its label |
659 |
// current target has been used in the past, simply branch to its label |
651 |
codeStream.goto_(this.reusableJSRSequenceStartLabels[i]); |
660 |
if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode == FINALLY_INLINE && isStackMapFrameCodeStream) { |
652 |
return true; |
661 |
reuseTargetLocation = false; |
|
|
662 |
break nextReusableTarget; |
663 |
} else { |
664 |
codeStream.goto_(this.reusableJSRSequenceStartLabels[i]); |
665 |
return true; |
666 |
} |
653 |
} |
667 |
} |
654 |
} else { |
668 |
} else { |
655 |
this.reusableJSRTargets = new Object[3]; |
669 |
this.reusableJSRTargets = new Object[3]; |
656 |
this.reusableJSRSequenceStartLabels = new BranchLabel[3]; |
670 |
this.reusableJSRSequenceStartLabels = new BranchLabel[3]; |
|
|
671 |
this.reusableJSRStateIndexes = new int[3]; |
672 |
} |
673 |
if (reuseTargetLocation) { |
674 |
if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) { |
675 |
System.arraycopy(this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); |
676 |
System.arraycopy(this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); |
677 |
System.arraycopy(this.reusableJSRStateIndexes, 0, this.reusableJSRStateIndexes = new int[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); |
678 |
} |
679 |
this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation; |
680 |
BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream); |
681 |
reusableJSRSequenceStartLabel.place(); |
682 |
this.reusableJSRStateIndexes[this.reusableJSRTargetsCount] = stateIndex; |
683 |
this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; |
657 |
} |
684 |
} |
658 |
if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) { |
685 |
} |
659 |
System.arraycopy(this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); |
|
|
660 |
System.arraycopy(this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); |
661 |
} |
662 |
this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation; |
663 |
BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream); |
664 |
reusableJSRSequenceStartLabel.place(); |
665 |
this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; |
666 |
} |
667 |
if (finallyMode == FINALLY_INLINE) { |
686 |
if (finallyMode == FINALLY_INLINE) { |
668 |
if (this.preTryInitStateIndex != -1) { |
687 |
if (isStackMapFrameCodeStream) { |
669 |
// reset initialization state, as for a normal catch block |
688 |
((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex); |
670 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); |
689 |
if (this.naturalExitMergeInitStateIndex != -1 || stateIndex != -1) { |
|
|
690 |
// reset initialization state, as for a normal catch block |
691 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
692 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
693 |
} |
694 |
} else { |
695 |
if (this.naturalExitMergeInitStateIndex != -1) { |
696 |
// reset initialization state, as for a normal catch block |
697 |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
698 |
codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); |
699 |
} |
700 |
} |
701 |
if (secretLocal != null) { |
702 |
codeStream.addVariable(secretLocal); |
671 |
} |
703 |
} |
672 |
// cannot use jsr bytecode, then simply inline the subroutine |
704 |
// cannot use jsr bytecode, then simply inline the subroutine |
673 |
// inside try block, ensure to deactivate all catch block exception handlers while inlining finally block |
705 |
// inside try block, ensure to deactivate all catch block exception handlers while inlining finally block |
674 |
exitAnyExceptionHandler(); |
706 |
exitAnyExceptionHandler(); |
675 |
exitDeclaredExceptionHandlers(codeStream); |
707 |
exitDeclaredExceptionHandlers(codeStream); |
676 |
this.finallyBlock.generateCode(currentScope, codeStream); |
708 |
this.finallyBlock.generateCode(currentScope, codeStream); |
|
|
709 |
if (isStackMapFrameCodeStream) { |
710 |
((StackMapFrameCodeStream) codeStream).popStateIndex(); |
711 |
} |
677 |
} else { |
712 |
} else { |
678 |
// classic subroutine invocation, distinguish case of non-returning subroutine |
713 |
// classic subroutine invocation, distinguish case of non-returning subroutine |
679 |
codeStream.jsr(this.subRoutineStartLabel); |
714 |
codeStream.jsr(this.subRoutineStartLabel); |
Lines 682-688
Link Here
|
682 |
} |
717 |
} |
683 |
return false; |
718 |
return false; |
684 |
} |
719 |
} |
685 |
|
|
|
686 |
public boolean isSubRoutineEscaping() { |
720 |
public boolean isSubRoutineEscaping() { |
687 |
return (this.bits & ASTNode.IsSubRoutineEscaping) != 0; |
721 |
return (this.bits & ASTNode.IsSubRoutineEscaping) != 0; |
688 |
} |
722 |
} |