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.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)
|
||||||
+21
-16
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user