Delete clean reference instructions on dereferencing captured variables
Codegen generates clean instructions for ref values (captured vars) on block exit so we should delete them on dereferencing captured values. #KT-17200 FIXED
This commit is contained in:
+31
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.captured
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||
@@ -63,6 +64,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
||||
val stackInsns: MutableCollection<AbstractInsnNode> = LinkedHashSet()
|
||||
val getFieldInsns: MutableCollection<FieldInsnNode> = LinkedHashSet()
|
||||
val putFieldInsns: MutableCollection<FieldInsnNode> = LinkedHashSet()
|
||||
var cleanVarInstruction: VarInsnNode? = null
|
||||
|
||||
fun canRewrite(): Boolean =
|
||||
!hazard &&
|
||||
@@ -198,6 +200,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
||||
for (refValue in refValues) {
|
||||
if (refValue.hazard) continue
|
||||
val localVar = refValue.localVar ?: continue
|
||||
val oldVarIndex = localVar.index
|
||||
|
||||
if (refValue.valueType.size != 1) {
|
||||
refValue.localVarIndex = methodNode.maxLocals
|
||||
@@ -214,9 +217,30 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
||||
refValue.hazard = true
|
||||
continue
|
||||
}
|
||||
|
||||
val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions)
|
||||
if (cleanInstructions.size > 1 ) {
|
||||
refValue.hazard = true
|
||||
continue
|
||||
}
|
||||
refValue.cleanVarInstruction = cleanInstructions.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private fun findCleanInstructions(refValue: CapturedVarDescriptor, oldVarIndex: Int, instructions: InsnList): List<VarInsnNode> {
|
||||
val cleanInstructions =
|
||||
InsnSequence(instructions).filterIsInstance<VarInsnNode>().filter {
|
||||
it.`var` == oldVarIndex
|
||||
}.filter {
|
||||
it.previous?.opcode == Opcodes.ACONST_NULL
|
||||
}.filter {
|
||||
val operationIndex = instructions.indexOf(it)
|
||||
val localVariableNode = refValue.localVar!!
|
||||
instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(localVariableNode.end)
|
||||
}.toList()
|
||||
return cleanInstructions
|
||||
}
|
||||
|
||||
private fun rewrite() {
|
||||
for (refValue in refValues) {
|
||||
if (!refValue.canRewrite()) continue
|
||||
@@ -248,6 +272,13 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
||||
capturedVar.putFieldInsns.forEach {
|
||||
set(it, VarInsnNode(capturedVar.valueType.getOpcode(Opcodes.ISTORE), capturedVar.localVarIndex))
|
||||
}
|
||||
|
||||
//after visiting block codegen tries to delete all allocated references:
|
||||
// see ExpressionCodegen.addLeaveTaskToRemoveLocalVariableFromFrameMap
|
||||
capturedVar.cleanVarInstruction?.let {
|
||||
remove(it.previous)
|
||||
remove(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
inline fun inlineCall(action: () -> Unit) {
|
||||
action()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
var width = 1
|
||||
inlineCall {
|
||||
width += width
|
||||
}
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
var width = 1L
|
||||
val newValue = 1;
|
||||
val newValue2 = "123";
|
||||
val newValue3 = 2.0;
|
||||
inlineCall {
|
||||
width += width
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test()
|
||||
test2()
|
||||
return "OK"
|
||||
}
|
||||
+6
@@ -3859,6 +3859,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt17200.kt")
|
||||
public void testKt17200() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/kt17200.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sharedSlotsWithCapturedVars.kt")
|
||||
public void testSharedSlotsWithCapturedVars() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/sharedSlotsWithCapturedVars.kt");
|
||||
|
||||
@@ -3859,6 +3859,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt17200.kt")
|
||||
public void testKt17200() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/kt17200.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sharedSlotsWithCapturedVars.kt")
|
||||
public void testSharedSlotsWithCapturedVars() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/sharedSlotsWithCapturedVars.kt");
|
||||
|
||||
@@ -3859,6 +3859,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt17200.kt")
|
||||
public void testKt17200() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/kt17200.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sharedSlotsWithCapturedVars.kt")
|
||||
public void testSharedSlotsWithCapturedVars() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/sharedSlotsWithCapturedVars.kt");
|
||||
|
||||
@@ -4532,6 +4532,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt17200.kt")
|
||||
public void testKt17200() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/kt17200.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sharedSlotsWithCapturedVars.kt")
|
||||
public void testSharedSlotsWithCapturedVars() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedVarsOptimization/sharedSlotsWithCapturedVars.kt");
|
||||
|
||||
Reference in New Issue
Block a user