diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt index 57a4b989e55..e93fe73c8d4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt @@ -20,9 +20,9 @@ import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument - -import java.util.ArrayList -import java.util.Collections +import org.jetbrains.kotlin.utils.mapToIndex +import org.jetbrains.org.objectweb.asm.Type +import java.util.* abstract class ArgumentGenerator { /** @@ -30,54 +30,59 @@ abstract class ArgumentGenerator { * * any default arguments, or an empty `List` if there were none * * * @see kotlin.reflect.jvm.internal.KCallableImpl.callBy + * @param valueArgumentsByIndex + * * + * @param actualArgs */ - open fun generate(valueArguments: List): List { - val masks = ArrayList(1) - var mask = 0 - val n = valueArguments.size() - for (i in 0..n - 1) { - if (i != 0 && i % Integer.SIZE == 0) { - masks.add(mask) - mask = 0 - } - val argument = valueArguments.get(i) - if (argument is ExpressionValueArgument) { - generateExpression(i, argument) - } - else if (argument is DefaultValueArgument) { - mask = mask or (1 shl (i % Integer.SIZE)) - generateDefault(i, argument) - } - else if (argument is VarargValueArgument) { - generateVararg(i, argument) - } - else { - generateOther(i, argument) - } + open fun generate(valueArgumentsByIndex: List, actualArgs: List): DefaultCallMask { + //HACK: see tempVariable in ExpressionCodegen + val actualArguments = if (actualArgs.isNotEmpty()) actualArgs else valueArgumentsByIndex + + assert(valueArgumentsByIndex.size() == actualArguments.size()) { + "Value arguments collection should have same size, but ${valueArgumentsByIndex.size()} != ${actualArguments.size()}" } - if (mask == 0 && masks.isEmpty()) { - return emptyList() + val arg2Index = valueArgumentsByIndex.mapToIndex() + + val masks = DefaultCallMask(valueArgumentsByIndex.size()) + for ((index, argument) in valueArgumentsByIndex.withIndex()) { + //var i = arg2Index[argument]!! + var i = index + + var type = when (argument) { + is ExpressionValueArgument -> { + generateExpression(i, argument) + } + is DefaultValueArgument -> { + masks.mark(i) + generateDefault(i, argument) + } + is VarargValueArgument -> { + generateVararg(i, argument) + } + else -> { + generateOther(i, argument) + } + } + } - masks.add(mask) return masks } - protected open fun generateExpression(i: Int, argument: ExpressionValueArgument) { + protected open fun generateExpression(i: Int, argument: ExpressionValueArgument): Type { throw UnsupportedOperationException("Unsupported expression value argument #$i: $argument") } - protected open fun generateDefault(i: Int, argument: DefaultValueArgument) { + protected open fun generateDefault(i: Int, argument: DefaultValueArgument): Type { throw UnsupportedOperationException("Unsupported default value argument #$i: $argument") } - protected open fun generateVararg(i: Int, argument: VarargValueArgument) { + protected open fun generateVararg(i: Int, argument: VarargValueArgument): Type { throw UnsupportedOperationException("Unsupported vararg value argument #$i: $argument") } - @SuppressWarnings("MethodMayBeStatic") // is supposed to be overridden - protected fun generateOther(i: Int, argument: ResolvedValueArgument) { + protected open fun generateOther(i: Int, argument: ResolvedValueArgument): Type { throw UnsupportedOperationException("Unsupported value argument #$i: $argument") } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java index 56dcc1a27b3..2e6597bb8c0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java @@ -53,16 +53,17 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { @NotNull @Override - public List generate(@NotNull List valueArguments) { + public DefaultCallMask generate(@NotNull List valueArgumentsByIndex, @NotNull List valueArgs) { boolean shouldMarkLineNumbers = codegen.isShouldMarkLineNumbers(); codegen.setShouldMarkLineNumbers(false); - List masks = super.generate(valueArguments); + DefaultCallMask masks = super.generate(valueArgumentsByIndex, valueArgs); codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers); return masks; } + @NotNull @Override - protected void generateExpression(int i, @NotNull ExpressionValueArgument argument) { + protected Type generateExpression(int i, @NotNull ExpressionValueArgument argument) { ValueParameterDescriptor parameter = valueParameters.get(i); Type type = valueParameterTypes.get(i); ValueArgument valueArgument = argument.getValueArgument(); @@ -70,21 +71,26 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { JetExpression argumentExpression = valueArgument.getArgumentExpression(); assert argumentExpression != null : valueArgument.asElement().getText(); callGenerator.genValueAndPut(parameter, argumentExpression, type); + return type; } + @NotNull @Override - protected void generateDefault(int i, @NotNull DefaultValueArgument argument) { + protected Type generateDefault(int i, @NotNull DefaultValueArgument argument) { ValueParameterDescriptor parameter = valueParameters.get(i); Type type = valueParameterTypes.get(i); pushDefaultValueOnStack(type, codegen.v); callGenerator.afterParameterPut(type, null, parameter); + return type; } + @NotNull @Override - protected void generateVararg(int i, @NotNull VarargValueArgument argument) { + protected Type generateVararg(int i, @NotNull VarargValueArgument argument) { ValueParameterDescriptor parameter = valueParameters.get(i); Type type = valueParameterTypes.get(i); codegen.genVarargs(argument, parameter.getType()); callGenerator.afterParameterPut(type, null, parameter); + return type; } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallMask.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallMask.kt new file mode 100644 index 00000000000..a36f632e0b9 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallMask.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2015 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.codegen + +import java.util.* + +class DefaultCallMask(val size: Int) { + + val bits: BitSet = BitSet(size) + + fun mark(index: Int) { + assert (index < size) { + "Mask index should be less then size, but $index >= $size" + } + bits.set(index) + } + + fun toInts(): List { + if (bits.isEmpty || size == 0) { + return emptyList() + } + + val masks = ArrayList(1) + + var mask = 0 + for (i in 0..size - 1) { + if (i != 0 && i % Integer.SIZE == 0) { + masks.add(mask) + mask = 0; + } + mask = mask or if (bits.get(i)) 1 shl (i % Integer.SIZE) else 0 + } + masks.add(mask) + + return masks + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index a16011ba56b..b690b8f9c1d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1486,7 +1486,7 @@ public class ExpressionCodegen extends JetVisitor implem ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes); - argumentGenerator.generate(valueArguments); + argumentGenerator.generate(valueArguments, valueArguments); } Collection constructors = classDescriptor.getConstructors(); @@ -2454,7 +2454,9 @@ public class ExpressionCodegen extends JetVisitor implem List valueArguments = resolvedCall.getValueArgumentsByIndex(); assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor(); - List masks = argumentGenerator.generate(valueArguments); + List masks = + argumentGenerator.generate(valueArguments, new ArrayList(resolvedCall.getValueArguments().values())) + .toInts(); if (tailRecursionCodegen.isTailRecursion(resolvedCall)) { tailRecursionCodegen.generateTailRecursion(resolvedCall); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 63f80b62e38..6ba72975c9f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1644,24 +1644,27 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } @Override - public void generateExpression(int i, @NotNull ExpressionValueArgument argument) { - generateSuperCallArgument(i); + public Type generateExpression(int i, @NotNull ExpressionValueArgument argument) { + return generateSuperCallArgument(i); } @Override - public void generateDefault(int i, @NotNull DefaultValueArgument argument) { - pushDefaultValueOnStack(parameters.get(i).getAsmType(), iv); + public Type generateDefault(int i, @NotNull DefaultValueArgument argument) { + Type type = parameters.get(i).getAsmType(); + pushDefaultValueOnStack(type, iv); + return type; } @Override - public void generateVararg(int i, @NotNull VarargValueArgument argument) { - generateSuperCallArgument(i); + public Type generateVararg(int i, @NotNull VarargValueArgument argument) { + return generateSuperCallArgument(i); } - private void generateSuperCallArgument(int i) { + private Type generateSuperCallArgument(int i) { Type type = parameters.get(i).getAsmType(); iv.load(offset, type); offset += type.getSize(); + return type; } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 6860e949462..d2b69cb23b4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -769,7 +769,7 @@ public abstract class StackValue { ResolvedCall call = isGetter ? resolvedGetCall : resolvedSetCall; StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable); newReceiver.put(newReceiver.type, v); - argumentGenerator.generate(valueArguments); + argumentGenerator.generate(valueArguments, valueArguments); } @Override diff --git a/compiler/testData/codegen/box/argumentOrder/arguments.kt b/compiler/testData/codegen/box/argumentOrder/arguments.kt new file mode 100644 index 00000000000..f3d4d9b9b33 --- /dev/null +++ b/compiler/testData/codegen/box/argumentOrder/arguments.kt @@ -0,0 +1,13 @@ + +fun test(a: String, b: String): String { + return a + b; +} + +fun box(): String { + var res = ""; + val call = test(b = {res += "K"; "K"}(), a = {res+="O"; "O"}()) + + if (res != "KO" || call != "OK") return "fail: $res != KO or $call != OK" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index b0cb25b1510..b2ec8e8ae70 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -35,6 +35,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("compiler/testData/codegen/box/argumentOrder") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ArgumentOrder extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInArgumentOrder() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/argumentOrder"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("arguments.kt") + public void testArguments() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/argumentOrder/arguments.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/arrays") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)