diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java index 1670f125c3e..fd98bddc99b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java @@ -64,7 +64,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { @Override protected void generateDefault(int i, @NotNull DefaultValueArgument argument) { - callGenerator.putValueIfNeeded(valueParameterTypes.get(i), createDefaulValue(valueParameterTypes.get(i))); + callGenerator.putValueIfNeeded(valueParameterTypes.get(i), createDefaulValue(valueParameterTypes.get(i)), ValueKind.DEFAULT_PARAMETER); } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt index c3d1bef6e08..49cd0e8569a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt @@ -23,8 +23,10 @@ import org.jetbrains.org.objectweb.asm.Type enum class ValueKind { GENERAL, + DEFAULT_PARAMETER, DEFAULT_MASK, - METHOD_HANDLE_IN_DEFAULT + METHOD_HANDLE_IN_DEFAULT, + CAPTURED } abstract class CallGenerator { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 1623cc75b73..1c64b85d7fe 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -414,7 +414,7 @@ public class InlineCodegen extends CallGenerator { defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber())); MethodNode node = nodeAndSmap.getNode(); if (callDefault) { - MethodInlinerUtilKt.expandMaskConditions(node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex); + MethodInlinerUtilKt.expandMaskConditionsAndUpdateVariableNodes(node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex); } ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node); generateClosuresBodies(); @@ -674,11 +674,17 @@ public class InlineCodegen extends CallGenerator { @NotNull Type type, @NotNull StackValue stackValue, int capturedParamIndex, - int parameterIndex + int parameterIndex, + @NotNull ValueKind kind ) { + boolean isDefaultParameter = kind == ValueKind.DEFAULT_PARAMETER; + if (!isDefaultParameter && shouldPutGeneralValue(type, stackValue)) { + stackValue.put(type, codegen.v); + } + if (!asFunctionInline && Type.VOID_TYPE != type) { //TODO remap only inlinable closure => otherwise we could get a lot of problem - boolean couldBeRemapped = !shouldPutGeneralValue(type, stackValue); + boolean couldBeRemapped = !shouldPutGeneralValue(type, stackValue) && kind != ValueKind.DEFAULT_PARAMETER; StackValue remappedValue = couldBeRemapped ? stackValue : null; ParameterInfo info; @@ -691,7 +697,7 @@ public class InlineCodegen extends CallGenerator { info = invocationParamBuilder.addNextValueParameter(type, false, remappedValue, parameterIndex); } - recordParameterValueInLocalVal(false, info); + recordParameterValueInLocalVal(false, isDefaultParameter, info); } } @@ -725,7 +731,7 @@ public class InlineCodegen extends CallGenerator { return true; } - private Runnable recordParameterValueInLocalVal(boolean delayedWritingToLocals, @NotNull ParameterInfo... infos) { + private Runnable recordParameterValueInLocalVal(boolean delayedWritingToLocals, boolean skipStore, @NotNull ParameterInfo... infos) { int[] index = new int[infos.length]; for (int i = 0; i < infos.length; i++) { ParameterInfo info = infos[i]; @@ -743,7 +749,9 @@ public class InlineCodegen extends CallGenerator { if (!info.isSkippedOrRemapped()) { Type type = info.type; StackValue.Local local = StackValue.local(index[i], type); - local.store(StackValue.onStack(type), codegen.v); + if (!skipStore) { + local.store(StackValue.onStack(type), codegen.v); + } if (info instanceof CapturedParamInfo) { info.setRemapValue(local); ((CapturedParamInfo) info).setSynthetic(true); @@ -773,7 +781,7 @@ public class InlineCodegen extends CallGenerator { invocationParamBuilder.markValueParametersStart(); List hiddenParameters = invocationParamBuilder.buildParameters().getParameters(); - delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()])); + delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()])); } private void leaveTemps() { @@ -924,11 +932,7 @@ public class InlineCodegen extends CallGenerator { assert maskValues.isEmpty() : "Additional default call arguments should be last ones, but " + value; - if (shouldPutGeneralValue(parameterType, value)) { - value.put(parameterType, codegen.v); - } - - putArgumentOrCapturedToLocalVal(parameterType, value, -1, index); + putArgumentOrCapturedToLocalVal(parameterType, value, -1, index, kind); } private boolean processDefaultMaskOrMethodHandler(@NotNull StackValue value, @NotNull ValueKind kind) { @@ -953,10 +957,7 @@ public class InlineCodegen extends CallGenerator { @Override public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) { - if (shouldPutGeneralValue(stackValue.type, stackValue)) { - stackValue.put(stackValue.type, codegen.v); - } - putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex); + putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED); } private void generateAndInsertFinallyBlocks( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt index 3760f557dc5..93632d0abd9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInlinerUtil.kt @@ -89,14 +89,17 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions( fun SourceValue.singleOrNullInsn() = insns.singleOrNull() -fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List, methodHandlerIndex: Int) { - class Condition(mask: Int, constant: Int, val maskInstruction: VarInsnNode, val jumpInstruction: JumpInsnNode) { +fun expandMaskConditionsAndUpdateVariableNodes(node: MethodNode, maskStartIndex: Int, masks: List, methodHandlerIndex: Int) { + class Condition(mask: Int, constant: Int, val maskInstruction: VarInsnNode, val jumpInstruction: JumpInsnNode, val varIndex: Int) { val expandNotDelete = mask and constant != 0 } + fun isMaskIndex(varIndex: Int): Boolean { + return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size + } val maskProcessingHeader = node.instructions.asSequence().takeWhile { if (it is VarInsnNode) { - if (isMaskIndex(it, maskStartIndex, masks)) { + if (isMaskIndex(it.`var`)) { /*if slot for default mask is updated than we occurred in actual function body*/ return@takeWhile it.opcode == Opcodes.ILOAD } @@ -108,14 +111,16 @@ fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List } val conditions = maskProcessingHeader.filterIsInstance().mapNotNull { - if (isMaskIndex(it, maskStartIndex, masks) && + if (isMaskIndex(it.`var`) && it.next?.next?.opcode == Opcodes.IAND && it.next.next.next?.opcode == Opcodes.IFEQ) { + val jumpInstruction = it.next?.next?.next as JumpInsnNode Condition( masks[it.`var` - maskStartIndex], InlineCodegenUtil.getConstant(it.next), it, - it.next?.next?.next as JumpInsnNode + jumpInstruction, + (jumpInstruction.label.previous as VarInsnNode).`var` ) } else if (isMethodHandleIndex(methodHandlerIndex, it) && @@ -123,17 +128,23 @@ fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List it.next.next?.opcode == Opcodes.NEW) { //Always delete method handle for now //This logic should be updated when method handles would be supported - Condition(0, 0, it,it.next as JumpInsnNode) + Condition(0, 0, it,it.next as JumpInsnNode, -1) } else null } + val indexToVarNode = node.localVariables?.filter { it.index < maskStartIndex }?.associateBy { it.index } ?: emptyMap() val toDelete = arrayListOf() conditions.forEach { val jumpInstruction = it.jumpInstruction InsnSequence(it.maskInstruction, (if (it.expandNotDelete) jumpInstruction.next else jumpInstruction.label)).forEach { toDelete.add(it) } + if (it.expandNotDelete) { + indexToVarNode[it.varIndex]?.let { varNode -> + varNode.start = it.jumpInstruction.label + } + } } toDelete.forEach { @@ -141,10 +152,4 @@ fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List } } -private fun isMethodHandleIndex(methodHandlerIndex: Int, it: VarInsnNode) = methodHandlerIndex == it.`var` - -private fun isMaskIndex(variable: VarInsnNode, maskStartIndex: Int, masks: List): Boolean { - val varIndex = variable.`var` - return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size -} - +private fun isMethodHandleIndex(methodHandlerIndex: Int, it: VarInsnNode) = methodHandlerIndex == it.`var` \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/defaultValues/maskElumination/32Parameters.kt b/compiler/testData/codegen/boxInline/defaultValues/maskElimination/32Parameters.kt similarity index 100% rename from compiler/testData/codegen/boxInline/defaultValues/maskElumination/32Parameters.kt rename to compiler/testData/codegen/boxInline/defaultValues/maskElimination/32Parameters.kt diff --git a/compiler/testData/codegen/boxInline/defaultValues/maskElumination/33Parameters.kt b/compiler/testData/codegen/boxInline/defaultValues/maskElimination/33Parameters.kt similarity index 100% rename from compiler/testData/codegen/boxInline/defaultValues/maskElumination/33Parameters.kt rename to compiler/testData/codegen/boxInline/defaultValues/maskElimination/33Parameters.kt diff --git a/compiler/testData/codegen/boxInline/defaultValues/maskElumination/simple.kt b/compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt similarity index 100% rename from compiler/testData/codegen/boxInline/defaultValues/maskElumination/simple.kt rename to compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt diff --git a/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt b/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt new file mode 100644 index 00000000000..78b440a64af --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt @@ -0,0 +1,20 @@ +inline fun test(p: String = "OK"): String { + return p +} + +fun box() : String { + return test() +} + +//mask check in test$default +// 1 IFEQ + +//total ifs +// 1 IF + +//no default argument on call site +// 0 NULL + +//proper variable start label: after assignment +// 1 LOCALVARIABLE p\$iv Ljava/lang/String; L2 L3 0 +// 1 LDC "OK"\s*ASTORE 0\s*L2 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/defaultArguments/maskElumination.kt b/compiler/testData/codegen/bytecodeText/defaultArguments/maskElumination.kt deleted file mode 100644 index 05b267ba075..00000000000 --- a/compiler/testData/codegen/bytecodeText/defaultArguments/maskElumination.kt +++ /dev/null @@ -1,11 +0,0 @@ -inline fun test(p: String = "OK"): String { - return p -} - -fun box() : String { - return test() -} - -//mask check in test$default -// 1 IFEQ -// 1 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElumination.kt b/compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElimination.kt similarity index 78% rename from compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElumination.kt rename to compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElimination.kt index 9082e7ca737..30afd11b3b2 100644 --- a/compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElumination.kt +++ b/compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElimination.kt @@ -1,3 +1,4 @@ +//open modality to method handle check generation open class A { inline fun test(p: String = "OK"): String { return p @@ -12,4 +13,5 @@ fun box(): String { // 1 IFNULL //mask check in test$default // 1 IFEQ +//total ifs // 2 IF \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 449cbc35b62..232ed6b5295 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -929,29 +929,29 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTest(fileName); } - @TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination") + @TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class MaskElumination extends AbstractBlackBoxInlineCodegenTest { + public static class MaskElimination extends AbstractBlackBoxInlineCodegenTest { @TestMetadata("32Parameters.kt") public void test32Parameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/32Parameters.kt"); + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/32Parameters.kt"); doTest(fileName); } @TestMetadata("33Parameters.kt") public void test33Parameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/33Parameters.kt"); + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/33Parameters.kt"); doTest(fileName); } - public void testAllFilesPresentInMaskElumination() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElumination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + public void testAllFilesPresentInMaskElimination() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } @TestMetadata("simple.kt") public void testSimple() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/simple.kt"); + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt"); doTest(fileName); } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 3d095913d4c..1c86a18c609 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1091,15 +1091,15 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } - @TestMetadata("maskElumination.kt") - public void testMaskElumination() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/maskElumination.kt"); + @TestMetadata("maskAndArgumentElimination.kt") + public void testMaskAndArgumentElimination() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt"); doTest(fileName); } - @TestMetadata("methodHandlerElumination.kt") - public void testMethodHandlerElumination() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElumination.kt"); + @TestMetadata("methodHandlerElimination.kt") + public void testMethodHandlerElimination() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElimination.kt"); doTest(fileName); } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 4446867567c..956548d90f5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -929,29 +929,29 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doTest(fileName); } - @TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination") + @TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class MaskElumination extends AbstractCompileKotlinAgainstInlineKotlinTest { + public static class MaskElimination extends AbstractCompileKotlinAgainstInlineKotlinTest { @TestMetadata("32Parameters.kt") public void test32Parameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/32Parameters.kt"); + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/32Parameters.kt"); doTest(fileName); } @TestMetadata("33Parameters.kt") public void test33Parameters() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/33Parameters.kt"); + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/33Parameters.kt"); doTest(fileName); } - public void testAllFilesPresentInMaskElumination() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElumination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + public void testAllFilesPresentInMaskElimination() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } @TestMetadata("simple.kt") public void testSimple() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination/simple.kt"); + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt"); doTest(fileName); } }