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.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"
|
||||||
|
}
|
||||||
+15
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user