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.Set;
public class BreakableBlockInfo extends BlockInfo {
public abstract class BreakableBlockInfo extends BlockInfo {
private final KtElement element;
private final Label entryPoint;
private final Label exitPoint;
@@ -39,8 +39,9 @@ interface ControlFlowBuilder {
fun exitBlockScope(block: KtElement)
fun getExitPoint(labelElement: KtElement): Label?
fun getConditionEntryPoint(labelElement: KtElement): Label
fun getSubroutineExitPoint(labelElement: KtElement): Label?
fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label
fun getLoopExitPoint(loop: KtLoopExpression): Label?
// Declarations
fun declareParameter(parameter: KtParameter)
@@ -123,12 +123,16 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.throwException(throwExpression, thrownValue)
}
override fun getExitPoint(labelElement: KtElement): Label? {
return delegateBuilder.getExitPoint(labelElement)
override fun getSubroutineExitPoint(labelElement: KtElement): Label? {
return delegateBuilder.getSubroutineExitPoint(labelElement)
}
override fun getConditionEntryPoint(labelElement: KtElement): Label {
return delegateBuilder.getConditionEntryPoint(labelElement)
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label {
return delegateBuilder.getLoopConditionEntryPoint(loop)
}
override fun getLoopExitPoint(loop: KtLoopExpression): Label? {
return delegateBuilder.getLoopExitPoint(loop)
}
override fun enterLoop(expression: KtLoopExpression): LoopInfo {
@@ -797,7 +797,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
val loop = getCorrespondingLoop(expression)
if (loop != null) {
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)
if (loop != null) {
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 loop: KtLoopExpression?
if (labelName != null) {
@@ -860,14 +860,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
return loop
}
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtElement): Boolean {
private fun jumpDoesNotCrossFunctionBoundary(jumpExpression: KtExpressionWithLabel, jumpTarget: KtLoopExpression): Boolean {
val bindingContext = trace.bindingContext
val labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression)
val labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget)
return if (labelExprEnclosingFunc !== labelTargetEnclosingFunc) {
// Check to report only once
if (builder.getExitPoint(jumpTarget) != null ||
if (builder.getLoopExitPoint(jumpTarget) != null ||
// Local class secondary constructors are handled differently
// They are the only local class element NOT included in owner pseudocode
// 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 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 val builders = Stack<ControlFlowInstructionsGeneratorWorker>()
@@ -130,12 +131,12 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point"))
bindLabel(info.entryPoint)
elementToBlockInfo.put(expression, info)
elementToLoopInfo.put(expression, info)
return info
}
override fun enterLoopBody(expression: KtLoopExpression) {
val info = elementToBlockInfo[expression] as LoopInfo
val info = elementToLoopInfo[expression]!!
bindLabel(info.bodyEntryPoint)
loopInfo.push(info)
allBlocks.push(info)
@@ -143,7 +144,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun exitLoopBody(expression: KtLoopExpression) {
val info = loopInfo.pop()
elementToBlockInfo.remove(expression)
elementToLoopInfo.remove(expression)
allBlocks.pop()
bindLabel(info.bodyExitPoint)
}
@@ -152,11 +153,11 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
get() = if (loopInfo.empty()) null else loopInfo.peek().element
override fun enterSubroutine(subroutine: KtElement) {
val blockInfo = BreakableBlockInfo(
val blockInfo = SubroutineInfo(
subroutine,
/* entry point */ createUnboundLabel(),
/* exit point */ createUnboundLabel())
elementToBlockInfo.put(subroutine, blockInfo)
elementToSubroutineInfo.put(subroutine, blockInfo)
allBlocks.push(blockInfo)
bindLabel(blockInfo.entryPoint)
add(SubroutineEnterInstruction(subroutine, currentScope))
@@ -165,15 +166,19 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override val currentSubroutine: KtElement
get() = pseudocode.correspondingElement
override fun getConditionEntryPoint(labelElement: KtElement): Label {
val blockInfo = elementToBlockInfo[labelElement]
assert(blockInfo is LoopInfo) { "expected LoopInfo for " + labelElement.text }
return (blockInfo as LoopInfo).conditionEntryPoint
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label {
val blockInfo = elementToLoopInfo[loop] ?: error("expected LoopInfo for ${loop.text}")
return blockInfo.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)
return elementToBlockInfo[labelElement]?.exitPoint
return elementToSubroutineInfo[labelElement]?.exitPoint
}
private val currentScope: BlockScope
@@ -214,13 +219,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
override fun exitSubroutine(subroutine: KtElement): Pseudocode {
getExitPoint(subroutine)?.let { bindLabel(it) }
getSubroutineExitPoint(subroutine)?.let { bindLabel(it) }
pseudocode.addExitInstruction(SubroutineExitInstruction(subroutine, currentScope, false))
bindLabel(error)
pseudocode.addErrorInstruction(SubroutineExitInstruction(subroutine, currentScope, true))
bindLabel(sink)
pseudocode.addSinkInstruction(SubroutineSinkInstruction(subroutine, currentScope, "<SINK>"))
elementToBlockInfo.remove(subroutine)
elementToSubroutineInfo.remove(subroutine)
allBlocks.pop()
return pseudocode
}
@@ -242,13 +247,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) {
val exitPoint = getExitPoint(subroutine) ?: return
val exitPoint = getSubroutineExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint)
add(ReturnValueInstruction(returnExpression, currentScope, exitPoint, returnValue))
}
override fun returnNoValue(returnExpression: KtReturnExpression, subroutine: KtElement) {
val exitPoint = getExitPoint(subroutine) ?: return
val exitPoint = getSubroutineExitPoint(subroutine) ?: return
handleJumpInsideTryFinally(exitPoint)
add(ReturnNoValueInstruction(returnExpression, currentScope, exitPoint))
}