EA-85060: BreakableBlockInfo is split into LoopInfo & SubroutineInfo to make code more clear

(cherry picked from commit 48faf4a)
This commit is contained in:
Mikhail Glukhikh
2016-08-23 14:52:48 +03:00
committed by Mikhail Glukhikh
parent 64f0532934
commit c9f9ae7d2a
6 changed files with 59 additions and 28 deletions
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.KtElement;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
public class BreakableBlockInfo extends BlockInfo { public abstract class BreakableBlockInfo extends BlockInfo {
private final KtElement element; private final KtElement element;
private final Label entryPoint; private final Label entryPoint;
private final Label exitPoint; private final Label exitPoint;
@@ -39,8 +39,9 @@ interface ControlFlowBuilder {
fun exitBlockScope(block: KtElement) fun exitBlockScope(block: KtElement)
fun getExitPoint(labelElement: KtElement): Label? fun getSubroutineExitPoint(labelElement: KtElement): Label?
fun getConditionEntryPoint(labelElement: KtElement): Label fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label
fun getLoopExitPoint(loop: KtLoopExpression): Label?
// Declarations // Declarations
fun declareParameter(parameter: KtParameter) fun declareParameter(parameter: KtParameter)
@@ -123,12 +123,16 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.throwException(throwExpression, thrownValue) delegateBuilder.throwException(throwExpression, thrownValue)
} }
override fun getExitPoint(labelElement: KtElement): Label? { override fun getSubroutineExitPoint(labelElement: KtElement): Label? {
return delegateBuilder.getExitPoint(labelElement) return delegateBuilder.getSubroutineExitPoint(labelElement)
} }
override fun getConditionEntryPoint(labelElement: KtElement): Label { override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label {
return delegateBuilder.getConditionEntryPoint(labelElement) return delegateBuilder.getLoopConditionEntryPoint(loop)
}
override fun getLoopExitPoint(loop: KtLoopExpression): Label? {
return delegateBuilder.getLoopExitPoint(loop)
} }
override fun enterLoop(expression: KtLoopExpression): LoopInfo { override fun enterLoop(expression: KtLoopExpression): LoopInfo {
@@ -797,7 +797,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
val loop = getCorrespondingLoop(expression) val loop = getCorrespondingLoop(expression)
if (loop != null) { if (loop != null) {
if (jumpDoesNotCrossFunctionBoundary(expression, loop)) { if (jumpDoesNotCrossFunctionBoundary(expression, loop)) {
builder.getExitPoint(loop)?.let { builder.jump(it, expression) } builder.getLoopExitPoint(loop)?.let { builder.jump(it, expression) }
} }
} }
} }
@@ -806,7 +806,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
val loop = getCorrespondingLoop(expression) val loop = getCorrespondingLoop(expression)
if (loop != null) { if (loop != null) {
if (jumpDoesNotCrossFunctionBoundary(expression, loop)) { if (jumpDoesNotCrossFunctionBoundary(expression, loop)) {
builder.jump(builder.getConditionEntryPoint(loop), expression) builder.jump(builder.getLoopConditionEntryPoint(loop), expression)
} }
} }
} }
@@ -824,7 +824,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
} }
} }
private fun getCorrespondingLoop(expression: KtExpressionWithLabel): KtElement? { private fun getCorrespondingLoop(expression: KtExpressionWithLabel): KtLoopExpression? {
val labelName = expression.getLabelName() val labelName = expression.getLabelName()
val loop: KtLoopExpression? val loop: KtLoopExpression?
if (labelName != null) { if (labelName != null) {
@@ -860,14 +860,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
return loop return loop
} }
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtElement): Boolean { private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtLoopExpression): Boolean {
val bindingContext = trace.bindingContext val bindingContext = trace.bindingContext
val labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression) val labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
val labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget) val labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) { return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) {
// Check to report only once // Check to report only once
if (builder.getExitPoint(jumpTarget) != null || if (builder.getLoopExitPoint(jumpTarget) != null ||
// Local class secondary constructors are handled differently // Local class secondary constructors are handled differently
// They are the only local class element NOT included in owner pseudocode // They are the only local class element NOT included in owner pseudocode
// See generateInitializersForScriptClassOrObject && generateDeclarationForLocalClassOrObjectIfNeeded // See generateInitializersForScriptClassOrObject && generateDeclarationForLocalClassOrObjectIfNeeded
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cfg
import org.jetbrains.kotlin.psi.KtElement
class SubroutineInfo(subroutine: KtElement, entryPoint: Label, exitPoint: Label) : BreakableBlockInfo(subroutine, entryPoint, exitPoint)
@@ -40,7 +40,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
private val loopInfo = Stack<LoopInfo>() private val loopInfo = Stack<LoopInfo>()
private val blockScopes = Stack<BlockScope>() private val blockScopes = Stack<BlockScope>()
private val elementToBlockInfo = HashMap<KtElement, BreakableBlockInfo>() private val elementToLoopInfo = HashMap<KtLoopExpression, LoopInfo>()
private val elementToSubroutineInfo = HashMap<KtElement, SubroutineInfo>()
private var labelCount = 0 private var labelCount = 0
private val builders = Stack<ControlFlowInstructionsGeneratorWorker>() private val builders = Stack<ControlFlowInstructionsGeneratorWorker>()
@@ -130,12 +131,12 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
createUnboundLabel("body exit point"), createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point")) createUnboundLabel("condition entry point"))
bindLabel(info.entryPoint) bindLabel(info.entryPoint)
elementToBlockInfo.put(expression, info) elementToLoopInfo.put(expression, info)
return info return info
} }
override fun enterLoopBody(expression: KtLoopExpression) { override fun enterLoopBody(expression: KtLoopExpression) {
val info = elementToBlockInfo[expression] as LoopInfo val info = elementToLoopInfo[expression]!!
bindLabel(info.bodyEntryPoint) bindLabel(info.bodyEntryPoint)
loopInfo.push(info) loopInfo.push(info)
allBlocks.push(info) allBlocks.push(info)
@@ -143,7 +144,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun exitLoopBody(expression: KtLoopExpression) { override fun exitLoopBody(expression: KtLoopExpression) {
val info = loopInfo.pop() val info = loopInfo.pop()
elementToBlockInfo.remove(expression) elementToLoopInfo.remove(expression)
allBlocks.pop() allBlocks.pop()
bindLabel(info.bodyExitPoint) bindLabel(info.bodyExitPoint)
} }
@@ -152,11 +153,11 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
get() = if (loopInfo.empty()) null else loopInfo.peek().element get() = if (loopInfo.empty()) null else loopInfo.peek().element
override fun enterSubroutine(subroutine: KtElement) { override fun enterSubroutine(subroutine: KtElement) {
val blockInfo = BreakableBlockInfo( val blockInfo = SubroutineInfo(
subroutine, subroutine,
/* entry point */ createUnboundLabel(), /* entry point */ createUnboundLabel(),
/* exit point */ createUnboundLabel()) /* exit point */ createUnboundLabel())
elementToBlockInfo.put(subroutine, blockInfo) elementToSubroutineInfo.put(subroutine, blockInfo)
allBlocks.push(blockInfo) allBlocks.push(blockInfo)
bindLabel(blockInfo.entryPoint) bindLabel(blockInfo.entryPoint)
add(SubroutineEnterInstruction(subroutine, currentScope)) add(SubroutineEnterInstruction(subroutine, currentScope))
@@ -165,15 +166,19 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override val currentSubroutine: KtElement override val currentSubroutine: KtElement
get() = pseudocode.correspondingElement get() = pseudocode.correspondingElement
override fun getConditionEntryPoint(labelElement: KtElement): Label { override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label {
val blockInfo = elementToBlockInfo[labelElement] val blockInfo = elementToLoopInfo[loop] ?: error("expected LoopInfo for ${loop.text}")
assert(blockInfo is LoopInfo) { "expected LoopInfo for " + labelElement.text } return blockInfo.conditionEntryPoint
return (blockInfo as LoopInfo).conditionEntryPoint
} }
override fun getExitPoint(labelElement: KtElement): Label? { override fun getLoopExitPoint(loop: KtLoopExpression): Label? {
// It's quite possible to have null here, see testBreakInsideLocal
return elementToLoopInfo[loop]?.exitPoint
}
override fun getSubroutineExitPoint(labelElement: KtElement): Label? {
// It's quite possible to have null here, e.g. for non-local returns (see KT-10823) // It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
return elementToBlockInfo[labelElement]?.exitPoint return elementToSubroutineInfo[labelElement]?.exitPoint
} }
private val currentScope: BlockScope private val currentScope: BlockScope
@@ -214,13 +219,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
} }
override fun exitSubroutine(subroutine: KtElement): Pseudocode { override fun exitSubroutine(subroutine: KtElement): Pseudocode {
getExitPoint(subroutine)?.let { bindLabel(it) } getSubroutineExitPoint(subroutine)?.let { bindLabel(it) }
pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false)) pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false))
bindLabel(error) bindLabel(error)
pseudocode.addErrorInstruction(SubroutineExitInstruction(subroutine, currentScope, true)) pseudocode.addErrorInstruction(SubroutineExitInstruction(subroutine, currentScope, true))
bindLabel(sink) bindLabel(sink)
pseudocode.addSinkInstruction(SubroutineSinkInstruction(subroutine, currentScope, "<SINK>")) pseudocode.addSinkInstruction(SubroutineSinkInstruction(subroutine, currentScope, "<SINK>"))
elementToBlockInfo.remove(subroutine) elementToSubroutineInfo.remove(subroutine)
allBlocks.pop() allBlocks.pop()
return pseudocode return pseudocode
} }
@@ -242,13 +247,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
} }
override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) { override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) {
val exitPoint = getExitPoint(subroutine) ?: return val exitPoint = getSubroutineExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint) handleJumpInsideTryFinally(exitPoint)
add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue)) add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue))
} }
override fun returnNoValue(returnExpression: KtReturnExpression, subroutine: KtElement) { override fun returnNoValue(returnExpression: KtReturnExpression, subroutine: KtElement) {
val exitPoint = getExitPoint(subroutine) ?: return val exitPoint = getSubroutineExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint) handleJumpInsideTryFinally(exitPoint)
add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint)) add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint))
} }