Don't generate default arguments for inline call

This commit is contained in:
Mikhael Bogdanov
2017-04-27 15:38:11 +02:00
parent 7690a8bc3e
commit a7c9e14805
13 changed files with 81 additions and 62 deletions
@@ -64,7 +64,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
@Override @Override
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) { 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 @Override
@@ -23,8 +23,10 @@ import org.jetbrains.org.objectweb.asm.Type
enum class ValueKind { enum class ValueKind {
GENERAL, GENERAL,
DEFAULT_PARAMETER,
DEFAULT_MASK, DEFAULT_MASK,
METHOD_HANDLE_IN_DEFAULT METHOD_HANDLE_IN_DEFAULT,
CAPTURED
} }
abstract class CallGenerator { abstract class CallGenerator {
@@ -414,7 +414,7 @@ public class InlineCodegen extends CallGenerator {
defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber())); defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber()));
MethodNode node = nodeAndSmap.getNode(); MethodNode node = nodeAndSmap.getNode();
if (callDefault) { if (callDefault) {
MethodInlinerUtilKt.expandMaskConditions(node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex); MethodInlinerUtilKt.expandMaskConditionsAndUpdateVariableNodes(node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex);
} }
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node); ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
generateClosuresBodies(); generateClosuresBodies();
@@ -674,11 +674,17 @@ public class InlineCodegen extends CallGenerator {
@NotNull Type type, @NotNull Type type,
@NotNull StackValue stackValue, @NotNull StackValue stackValue,
int capturedParamIndex, 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) { if (!asFunctionInline && Type.VOID_TYPE != type) {
//TODO remap only inlinable closure => otherwise we could get a lot of problem //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; StackValue remappedValue = couldBeRemapped ? stackValue : null;
ParameterInfo info; ParameterInfo info;
@@ -691,7 +697,7 @@ public class InlineCodegen extends CallGenerator {
info = invocationParamBuilder.addNextValueParameter(type, false, remappedValue, parameterIndex); 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; 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]; int[] index = new int[infos.length];
for (int i = 0; i < infos.length; i++) { for (int i = 0; i < infos.length; i++) {
ParameterInfo info = infos[i]; ParameterInfo info = infos[i];
@@ -743,7 +749,9 @@ public class InlineCodegen extends CallGenerator {
if (!info.isSkippedOrRemapped()) { if (!info.isSkippedOrRemapped()) {
Type type = info.type; Type type = info.type;
StackValue.Local local = StackValue.local(index[i], 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) { if (info instanceof CapturedParamInfo) {
info.setRemapValue(local); info.setRemapValue(local);
((CapturedParamInfo) info).setSynthetic(true); ((CapturedParamInfo) info).setSynthetic(true);
@@ -773,7 +781,7 @@ public class InlineCodegen extends CallGenerator {
invocationParamBuilder.markValueParametersStart(); invocationParamBuilder.markValueParametersStart();
List<ParameterInfo> hiddenParameters = invocationParamBuilder.buildParameters().getParameters(); List<ParameterInfo> 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() { 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; assert maskValues.isEmpty() : "Additional default call arguments should be last ones, but " + value;
if (shouldPutGeneralValue(parameterType, value)) { putArgumentOrCapturedToLocalVal(parameterType, value, -1, index, kind);
value.put(parameterType, codegen.v);
}
putArgumentOrCapturedToLocalVal(parameterType, value, -1, index);
} }
private boolean processDefaultMaskOrMethodHandler(@NotNull StackValue value, @NotNull ValueKind kind) { private boolean processDefaultMaskOrMethodHandler(@NotNull StackValue value, @NotNull ValueKind kind) {
@@ -953,10 +957,7 @@ public class InlineCodegen extends CallGenerator {
@Override @Override
public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) { public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
if (shouldPutGeneralValue(stackValue.type, stackValue)) { putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED);
stackValue.put(stackValue.type, codegen.v);
}
putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
} }
private void generateAndInsertFinallyBlocks( private void generateAndInsertFinallyBlocks(
@@ -89,14 +89,17 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
fun SourceValue.singleOrNullInsn() = insns.singleOrNull() fun SourceValue.singleOrNullInsn() = insns.singleOrNull()
fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List<Int>, methodHandlerIndex: Int) { fun expandMaskConditionsAndUpdateVariableNodes(node: MethodNode, maskStartIndex: Int, masks: List<Int>, methodHandlerIndex: Int) {
class Condition(mask: Int, constant: Int, val maskInstruction: VarInsnNode, val jumpInstruction: JumpInsnNode) { class Condition(mask: Int, constant: Int, val maskInstruction: VarInsnNode, val jumpInstruction: JumpInsnNode, val varIndex: Int) {
val expandNotDelete = mask and constant != 0 val expandNotDelete = mask and constant != 0
} }
fun isMaskIndex(varIndex: Int): Boolean {
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
}
val maskProcessingHeader = node.instructions.asSequence().takeWhile { val maskProcessingHeader = node.instructions.asSequence().takeWhile {
if (it is VarInsnNode) { 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*/ /*if slot for default mask is updated than we occurred in actual function body*/
return@takeWhile it.opcode == Opcodes.ILOAD return@takeWhile it.opcode == Opcodes.ILOAD
} }
@@ -108,14 +111,16 @@ fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List<Int>
} }
val conditions = maskProcessingHeader.filterIsInstance<VarInsnNode>().mapNotNull { val conditions = maskProcessingHeader.filterIsInstance<VarInsnNode>().mapNotNull {
if (isMaskIndex(it, maskStartIndex, masks) && if (isMaskIndex(it.`var`) &&
it.next?.next?.opcode == Opcodes.IAND && it.next?.next?.opcode == Opcodes.IAND &&
it.next.next.next?.opcode == Opcodes.IFEQ) { it.next.next.next?.opcode == Opcodes.IFEQ) {
val jumpInstruction = it.next?.next?.next as JumpInsnNode
Condition( Condition(
masks[it.`var` - maskStartIndex], masks[it.`var` - maskStartIndex],
InlineCodegenUtil.getConstant(it.next), InlineCodegenUtil.getConstant(it.next),
it, it,
it.next?.next?.next as JumpInsnNode jumpInstruction,
(jumpInstruction.label.previous as VarInsnNode).`var`
) )
} }
else if (isMethodHandleIndex(methodHandlerIndex, it) && else if (isMethodHandleIndex(methodHandlerIndex, it) &&
@@ -123,17 +128,23 @@ fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List<Int>
it.next.next?.opcode == Opcodes.NEW) { it.next.next?.opcode == Opcodes.NEW) {
//Always delete method handle for now //Always delete method handle for now
//This logic should be updated when method handles would be supported //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 else null
} }
val indexToVarNode = node.localVariables?.filter { it.index < maskStartIndex }?.associateBy { it.index } ?: emptyMap()
val toDelete = arrayListOf<AbstractInsnNode>() val toDelete = arrayListOf<AbstractInsnNode>()
conditions.forEach { conditions.forEach {
val jumpInstruction = it.jumpInstruction val jumpInstruction = it.jumpInstruction
InsnSequence(it.maskInstruction, (if (it.expandNotDelete) jumpInstruction.next else jumpInstruction.label)).forEach { InsnSequence(it.maskInstruction, (if (it.expandNotDelete) jumpInstruction.next else jumpInstruction.label)).forEach {
toDelete.add(it) toDelete.add(it)
} }
if (it.expandNotDelete) {
indexToVarNode[it.varIndex]?.let { varNode ->
varNode.start = it.jumpInstruction.label
}
}
} }
toDelete.forEach { toDelete.forEach {
@@ -141,10 +152,4 @@ fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List<Int>
} }
} }
private fun isMethodHandleIndex(methodHandlerIndex: Int, it: VarInsnNode) = methodHandlerIndex == it.`var` private fun isMethodHandleIndex(methodHandlerIndex: Int, it: VarInsnNode) = methodHandlerIndex == it.`var`
private fun isMaskIndex(variable: VarInsnNode, maskStartIndex: Int, masks: List<Int>): Boolean {
val varIndex = variable.`var`
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
}
@@ -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
@@ -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
@@ -1,3 +1,4 @@
//open modality to method handle check generation
open class A { open class A {
inline fun test(p: String = "OK"): String { inline fun test(p: String = "OK"): String {
return p return p
@@ -12,4 +13,5 @@ fun box(): String {
// 1 IFNULL // 1 IFNULL
//mask check in test$default //mask check in test$default
// 1 IFEQ // 1 IFEQ
//total ifs
// 2 IF // 2 IF
@@ -929,29 +929,29 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination") @TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
public static class MaskElumination extends AbstractBlackBoxInlineCodegenTest { public static class MaskElimination extends AbstractBlackBoxInlineCodegenTest {
@TestMetadata("32Parameters.kt") @TestMetadata("32Parameters.kt")
public void test32Parameters() throws Exception { 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); doTest(fileName);
} }
@TestMetadata("33Parameters.kt") @TestMetadata("33Parameters.kt")
public void test33Parameters() throws Exception { 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); doTest(fileName);
} }
public void testAllFilesPresentInMaskElumination() throws Exception { public void testAllFilesPresentInMaskElimination() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElumination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("simple.kt") @TestMetadata("simple.kt")
public void testSimple() throws Exception { 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); doTest(fileName);
} }
} }
@@ -1091,15 +1091,15 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("maskElumination.kt") @TestMetadata("maskAndArgumentElimination.kt")
public void testMaskElumination() throws Exception { public void testMaskAndArgumentElimination() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/maskElumination.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("methodHandlerElumination.kt") @TestMetadata("methodHandlerElimination.kt")
public void testMethodHandlerElumination() throws Exception { public void testMethodHandlerElimination() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElumination.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/defaultArguments/methodHandlerElimination.kt");
doTest(fileName); doTest(fileName);
} }
} }
@@ -929,29 +929,29 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElumination") @TestMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
public static class MaskElumination extends AbstractCompileKotlinAgainstInlineKotlinTest { public static class MaskElimination extends AbstractCompileKotlinAgainstInlineKotlinTest {
@TestMetadata("32Parameters.kt") @TestMetadata("32Parameters.kt")
public void test32Parameters() throws Exception { 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); doTest(fileName);
} }
@TestMetadata("33Parameters.kt") @TestMetadata("33Parameters.kt")
public void test33Parameters() throws Exception { 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); doTest(fileName);
} }
public void testAllFilesPresentInMaskElumination() throws Exception { public void testAllFilesPresentInMaskElimination() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElumination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/defaultValues/maskElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("simple.kt") @TestMetadata("simple.kt")
public void testSimple() throws Exception { 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); doTest(fileName);
} }
} }