Addded DefaultCallMask class and extended interface for argument generation

This commit is contained in:
Michael Bogdanov
2015-09-25 16:16:06 +03:00
parent 8104c10c5a
commit 1f2b9ce72b
8 changed files with 144 additions and 49 deletions
@@ -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.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
import org.jetbrains.kotlin.utils.mapToIndex
import java.util.ArrayList import org.jetbrains.org.objectweb.asm.Type
import java.util.Collections import java.util.*
abstract class ArgumentGenerator { abstract class ArgumentGenerator {
/** /**
@@ -30,54 +30,59 @@ abstract class ArgumentGenerator {
* * any default arguments, or an empty `List` if there were none * * any default arguments, or an empty `List` if there were none
* * * *
* @see kotlin.reflect.jvm.internal.KCallableImpl.callBy * @see kotlin.reflect.jvm.internal.KCallableImpl.callBy
* @param valueArgumentsByIndex
* *
* @param actualArgs
*/ */
open fun generate(valueArguments: List<ResolvedValueArgument>): List<Int> { open fun generate(valueArgumentsByIndex: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>): DefaultCallMask {
val masks = ArrayList<Int>(1) //HACK: see tempVariable in ExpressionCodegen
var mask = 0 val actualArguments = if (actualArgs.isNotEmpty()) actualArgs else valueArgumentsByIndex
val n = valueArguments.size()
for (i in 0..n - 1) { assert(valueArgumentsByIndex.size() == actualArguments.size()) {
if (i != 0 && i % Integer.SIZE == 0) { "Value arguments collection should have same size, but ${valueArgumentsByIndex.size()} != ${actualArguments.size()}"
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)
}
} }
if (mask == 0 && masks.isEmpty()) { val arg2Index = valueArgumentsByIndex.mapToIndex()
return emptyList()
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 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") 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") 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") throw UnsupportedOperationException("Unsupported vararg value argument #$i: $argument")
} }
@SuppressWarnings("MethodMayBeStatic") // is supposed to be overridden protected open fun generateOther(i: Int, argument: ResolvedValueArgument): Type {
protected fun generateOther(i: Int, argument: ResolvedValueArgument) {
throw UnsupportedOperationException("Unsupported value argument #$i: $argument") throw UnsupportedOperationException("Unsupported value argument #$i: $argument")
} }
} }
@@ -53,16 +53,17 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
@NotNull @NotNull
@Override @Override
public List<Integer> generate(@NotNull List<? extends ResolvedValueArgument> valueArguments) { public DefaultCallMask generate(@NotNull List<? extends ResolvedValueArgument> valueArgumentsByIndex, @NotNull List<? extends ResolvedValueArgument> valueArgs) {
boolean shouldMarkLineNumbers = codegen.isShouldMarkLineNumbers(); boolean shouldMarkLineNumbers = codegen.isShouldMarkLineNumbers();
codegen.setShouldMarkLineNumbers(false); codegen.setShouldMarkLineNumbers(false);
List<Integer> masks = super.generate(valueArguments); DefaultCallMask masks = super.generate(valueArgumentsByIndex, valueArgs);
codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers); codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers);
return masks; return masks;
} }
@NotNull
@Override @Override
protected void generateExpression(int i, @NotNull ExpressionValueArgument argument) { protected Type generateExpression(int i, @NotNull ExpressionValueArgument argument) {
ValueParameterDescriptor parameter = valueParameters.get(i); ValueParameterDescriptor parameter = valueParameters.get(i);
Type type = valueParameterTypes.get(i); Type type = valueParameterTypes.get(i);
ValueArgument valueArgument = argument.getValueArgument(); ValueArgument valueArgument = argument.getValueArgument();
@@ -70,21 +71,26 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
JetExpression argumentExpression = valueArgument.getArgumentExpression(); JetExpression argumentExpression = valueArgument.getArgumentExpression();
assert argumentExpression != null : valueArgument.asElement().getText(); assert argumentExpression != null : valueArgument.asElement().getText();
callGenerator.genValueAndPut(parameter, argumentExpression, type); callGenerator.genValueAndPut(parameter, argumentExpression, type);
return type;
} }
@NotNull
@Override @Override
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) { protected Type generateDefault(int i, @NotNull DefaultValueArgument argument) {
ValueParameterDescriptor parameter = valueParameters.get(i); ValueParameterDescriptor parameter = valueParameters.get(i);
Type type = valueParameterTypes.get(i); Type type = valueParameterTypes.get(i);
pushDefaultValueOnStack(type, codegen.v); pushDefaultValueOnStack(type, codegen.v);
callGenerator.afterParameterPut(type, null, parameter); callGenerator.afterParameterPut(type, null, parameter);
return type;
} }
@NotNull
@Override @Override
protected void generateVararg(int i, @NotNull VarargValueArgument argument) { protected Type generateVararg(int i, @NotNull VarargValueArgument argument) {
ValueParameterDescriptor parameter = valueParameters.get(i); ValueParameterDescriptor parameter = valueParameters.get(i);
Type type = valueParameterTypes.get(i); Type type = valueParameterTypes.get(i);
codegen.genVarargs(argument, parameter.getType()); codegen.genVarargs(argument, parameter.getType());
callGenerator.afterParameterPut(type, null, parameter); callGenerator.afterParameterPut(type, null, parameter);
return type;
} }
} }
@@ -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<Int> {
if (bits.isEmpty || size == 0) {
return emptyList()
}
val masks = ArrayList<Int>(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
}
}
@@ -1486,7 +1486,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
ArgumentGenerator argumentGenerator = ArgumentGenerator argumentGenerator =
new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes); new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
argumentGenerator.generate(valueArguments); argumentGenerator.generate(valueArguments, valueArguments);
} }
Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors(); Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
@@ -2454,7 +2454,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex(); List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor(); assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
List<Integer> masks = argumentGenerator.generate(valueArguments); List<Integer> masks =
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()))
.toInts();
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) { if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
tailRecursionCodegen.generateTailRecursion(resolvedCall); tailRecursionCodegen.generateTailRecursion(resolvedCall);
@@ -1644,24 +1644,27 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
@Override @Override
public void generateExpression(int i, @NotNull ExpressionValueArgument argument) { public Type generateExpression(int i, @NotNull ExpressionValueArgument argument) {
generateSuperCallArgument(i); return generateSuperCallArgument(i);
} }
@Override @Override
public void generateDefault(int i, @NotNull DefaultValueArgument argument) { public Type generateDefault(int i, @NotNull DefaultValueArgument argument) {
pushDefaultValueOnStack(parameters.get(i).getAsmType(), iv); Type type = parameters.get(i).getAsmType();
pushDefaultValueOnStack(type, iv);
return type;
} }
@Override @Override
public void generateVararg(int i, @NotNull VarargValueArgument argument) { public Type generateVararg(int i, @NotNull VarargValueArgument argument) {
generateSuperCallArgument(i); return generateSuperCallArgument(i);
} }
private void generateSuperCallArgument(int i) { private Type generateSuperCallArgument(int i) {
Type type = parameters.get(i).getAsmType(); Type type = parameters.get(i).getAsmType();
iv.load(offset, type); iv.load(offset, type);
offset += type.getSize(); offset += type.getSize();
return type;
} }
} }
@@ -769,7 +769,7 @@ public abstract class StackValue {
ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall; ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable); StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
newReceiver.put(newReceiver.type, v); newReceiver.put(newReceiver.type, v);
argumentGenerator.generate(valueArguments); argumentGenerator.generate(valueArguments, valueArguments);
} }
@Override @Override
@@ -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"
}
@@ -35,6 +35,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box"), Pattern.compile("^(.+)\\.kt$"), true); 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") @TestMetadata("compiler/testData/codegen/box/arrays")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)