Addded DefaultCallMask class and extended interface for argument generation
This commit is contained in:
@@ -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"
|
||||
}
|
||||
+15
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user