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.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<ResolvedValueArgument>): List<Int> {
val masks = ArrayList<Int>(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<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>): 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")
}
}
@@ -53,16 +53,17 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
@NotNull
@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();
codegen.setShouldMarkLineNumbers(false);
List<Integer> 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;
}
}
@@ -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 =
new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
argumentGenerator.generate(valueArguments);
argumentGenerator.generate(valueArguments, valueArguments);
}
Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
@@ -2454,7 +2454,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
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)) {
tailRecursionCodegen.generateTailRecursion(resolvedCall);
@@ -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;
}
}
@@ -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
@@ -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);
}
@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)