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
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
@@ -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 {
@@ -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<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() {
@@ -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(
@@ -89,14 +89,17 @@ private fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
fun SourceValue.singleOrNullInsn() = insns.singleOrNull()
fun expandMaskConditions(node: MethodNode, maskStartIndex: Int, masks: List<Int>, methodHandlerIndex: Int) {
class Condition(mask: Int, constant: Int, val maskInstruction: VarInsnNode, val jumpInstruction: JumpInsnNode) {
fun expandMaskConditionsAndUpdateVariableNodes(node: MethodNode, maskStartIndex: Int, masks: List<Int>, 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<Int>
}
val conditions = maskProcessingHeader.filterIsInstance<VarInsnNode>().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<Int>
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<AbstractInsnNode>()
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<Int>
}
}
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
}
private fun isMethodHandleIndex(methodHandlerIndex: Int, it: VarInsnNode) = methodHandlerIndex == it.`var`
@@ -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 {
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
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}