EA-85060: BreakableBlockInfo is split into LoopInfo & SubroutineInfo to make code more clear
(cherry picked from commit 48faf4a)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
64f0532934
commit
c9f9ae7d2a
@@ -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)
|
||||
+21
-16
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user