Generate default arguments and varargs lazily
The aim to perform optimizations in call generators
This commit is contained in:
@@ -17,18 +17,18 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument;
|
||||
import org.jetbrains.kotlin.types.FlexibleTypesKt;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.pushDefaultValueOnStack;
|
||||
import static org.jetbrains.kotlin.codegen.StackValue.createDefaulValue;
|
||||
|
||||
public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
private final ExpressionCodegen codegen;
|
||||
@@ -64,19 +64,16 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
|
||||
@Override
|
||||
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) {
|
||||
Type type = valueParameterTypes.get(i);
|
||||
pushDefaultValueOnStack(type, codegen.v);
|
||||
callGenerator.afterParameterPut(type, null, i);
|
||||
callGenerator.putValueIfNeeded(valueParameterTypes.get(i), createDefaulValue(valueParameterTypes.get(i)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||
Type type = valueParameterTypes.get(i);
|
||||
// Upper bound for type of vararg parameter should always have a form of 'Array<out T>',
|
||||
// while its lower bound may be Nothing-typed after approximation
|
||||
codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
||||
callGenerator.afterParameterPut(type, null, i);
|
||||
StackValue lazyVararg = codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
||||
callGenerator.putValueIfNeeded(valueParameterTypes.get(i), lazyVararg);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract class CallGenerator {
|
||||
|
||||
override fun afterParameterPut(
|
||||
type: Type,
|
||||
stackValue: StackValue?,
|
||||
stackValue: StackValue,
|
||||
parameterIndex: Int) {
|
||||
|
||||
}
|
||||
@@ -113,7 +113,7 @@ abstract class CallGenerator {
|
||||
|
||||
abstract fun afterParameterPut(
|
||||
type: Type,
|
||||
stackValue: StackValue?,
|
||||
stackValue: StackValue,
|
||||
parameterIndex: Int)
|
||||
|
||||
abstract fun genValueAndPut(
|
||||
|
||||
@@ -39,7 +39,8 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegen;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.kotlin.codegen.forLoop.*;
|
||||
import org.jetbrains.kotlin.codegen.forLoop.AbstractForLoopGenerator;
|
||||
import org.jetbrains.kotlin.codegen.forLoop.ForLoopGeneratorsKt;
|
||||
import org.jetbrains.kotlin.codegen.inline.*;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
||||
@@ -106,7 +107,8 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
@@ -2535,7 +2537,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
|
||||
public void genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) {
|
||||
@NotNull
|
||||
public StackValue genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) {
|
||||
Type type = asmType(outType);
|
||||
assert type.getSort() == Type.ARRAY;
|
||||
Type elementType = correctElementType(type);
|
||||
@@ -2553,17 +2556,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (hasSpread) {
|
||||
boolean arrayOfReferences = KotlinBuiltIns.isArray(outType);
|
||||
if (size == 1) {
|
||||
// Arrays.copyOf(receiverValue, newLength)
|
||||
ValueArgument argument = arguments.get(0);
|
||||
Type arrayType = arrayOfReferences ? Type.getType("[Ljava/lang/Object;")
|
||||
: Type.getType("[" + elementType.getDescriptor());
|
||||
gen(argument.getArgumentExpression(), type);
|
||||
v.dup();
|
||||
v.arraylength();
|
||||
v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
|
||||
if (arrayOfReferences) {
|
||||
v.checkcast(type);
|
||||
}
|
||||
Type arrayType = getArrayType(arrayOfReferences ? AsmTypes.OBJECT_TYPE : elementType);
|
||||
return StackValue.operation(type, adapter -> {
|
||||
gen(arguments.get(0).getArgumentExpression(), type);
|
||||
v.dup();
|
||||
v.arraylength();
|
||||
v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
|
||||
if (arrayOfReferences) {
|
||||
v.checkcast(type);
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
else {
|
||||
String owner;
|
||||
@@ -2580,42 +2583,49 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
addDescriptor = "(" + elementType.getDescriptor() + ")V";
|
||||
toArrayDescriptor = "()" + type.getDescriptor();
|
||||
}
|
||||
v.anew(Type.getObjectType(owner));
|
||||
v.dup();
|
||||
v.iconst(size);
|
||||
v.invokespecial(owner, "<init>", "(I)V", false);
|
||||
for (int i = 0; i != size; ++i) {
|
||||
|
||||
return StackValue.operation(type, adapter -> {
|
||||
v.anew(Type.getObjectType(owner));
|
||||
v.dup();
|
||||
ValueArgument argument = arguments.get(i);
|
||||
if (argument.getSpreadElement() != null) {
|
||||
gen(argument.getArgumentExpression(), OBJECT_TYPE);
|
||||
v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false);
|
||||
v.iconst(size);
|
||||
v.invokespecial(owner, "<init>", "(I)V", false);
|
||||
for (int i = 0; i != size; ++i) {
|
||||
v.dup();
|
||||
ValueArgument argument = arguments.get(i);
|
||||
if (argument.getSpreadElement() != null) {
|
||||
gen(argument.getArgumentExpression(), OBJECT_TYPE);
|
||||
v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false);
|
||||
}
|
||||
else {
|
||||
gen(argument.getArgumentExpression(), elementType);
|
||||
v.invokevirtual(owner, "add", addDescriptor, false);
|
||||
}
|
||||
}
|
||||
if (arrayOfReferences) {
|
||||
v.dup();
|
||||
v.invokevirtual(owner, "size", "()I", false);
|
||||
newArrayInstruction(outType);
|
||||
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
|
||||
v.checkcast(type);
|
||||
}
|
||||
else {
|
||||
gen(argument.getArgumentExpression(), elementType);
|
||||
v.invokevirtual(owner, "add", addDescriptor, false);
|
||||
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
|
||||
}
|
||||
}
|
||||
if (arrayOfReferences) {
|
||||
v.dup();
|
||||
v.invokevirtual(owner, "size", "()I", false);
|
||||
newArrayInstruction(outType);
|
||||
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
|
||||
v.checkcast(type);
|
||||
}
|
||||
else {
|
||||
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
v.iconst(arguments.size());
|
||||
newArrayInstruction(outType);
|
||||
for (int i = 0; i != size; ++i) {
|
||||
v.dup();
|
||||
StackValue rightSide = gen(arguments.get(i).getArgumentExpression());
|
||||
StackValue.arrayElement(elementType, StackValue.onStack(type), StackValue.constant(i, Type.INT_TYPE)).store(rightSide, v);
|
||||
}
|
||||
return StackValue.operation(type, adapter -> {
|
||||
v.iconst(arguments.size());
|
||||
newArrayInstruction(outType);
|
||||
for (int i = 0; i != size; ++i) {
|
||||
v.dup();
|
||||
StackValue rightSide = gen(arguments.get(i).getArgumentExpression());
|
||||
StackValue.arrayElement(elementType, StackValue.onStack(type), StackValue.constant(i, Type.INT_TYPE)).store(rightSide, v);
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +181,35 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
|
||||
public static StackValue createDefaulValue(@NotNull Type type) {
|
||||
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
return constant(null, type);
|
||||
}
|
||||
else {
|
||||
return createDefaultPrimitiveValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static StackValue createDefaultPrimitiveValue(@NotNull Type type) {
|
||||
assert Type.BOOLEAN <= type.getSort() && type.getSort() <= Type.DOUBLE :
|
||||
"'createDefaultPrimitiveValue' method should be called only for primitive types, but " + type;
|
||||
Object value = 0;
|
||||
if (type.getSort() == Type.BOOLEAN) {
|
||||
value = Boolean.FALSE;
|
||||
}
|
||||
else if (type.getSort() == Type.FLOAT) {
|
||||
value = new Float(0.0);
|
||||
}
|
||||
else if (type.getSort() == Type.DOUBLE) {
|
||||
value = new Double(0.0);
|
||||
}
|
||||
else if (type.getSort() == Type.LONG) {
|
||||
value = new Long(0);
|
||||
}
|
||||
|
||||
return constant(value, type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StackValue cmp(@NotNull IElementType opToken, @NotNull Type type, StackValue left, StackValue right) {
|
||||
return BranchedValue.Companion.cmp(opToken, type, left, right);
|
||||
|
||||
@@ -671,13 +671,13 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, int parameterIndex) {
|
||||
public void afterParameterPut(@NotNull Type type, @NotNull StackValue stackValue, int parameterIndex) {
|
||||
putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
|
||||
}
|
||||
|
||||
private void putArgumentOrCapturedToLocalVal(
|
||||
@NotNull Type type,
|
||||
@Nullable StackValue stackValue,
|
||||
@NotNull StackValue stackValue,
|
||||
int capturedParamIndex,
|
||||
int parameterIndex
|
||||
) {
|
||||
@@ -701,12 +701,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
|
||||
/*descriptor is null for captured vars*/
|
||||
private static boolean shouldPutGeneralValue(@NotNull Type type, @Nullable StackValue stackValue) {
|
||||
if (stackValue == null) {
|
||||
//default or vararg
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean shouldPutGeneralValue(@NotNull Type type, @NotNull StackValue stackValue) {
|
||||
//remap only inline functions (and maybe non primitives)
|
||||
//TODO - clean asserion and remapping logic
|
||||
if (isPrimitive(type) != isPrimitive(stackValue.type)) {
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ class InlineCodegenForDefaultBody(
|
||||
transformedMethod.accept(MethodBodyVisitor(codegen.v))
|
||||
}
|
||||
|
||||
override fun afterParameterPut(type: Type, stackValue: StackValue?, parameterIndex: Int) {
|
||||
override fun afterParameterPut(type: Type, stackValue: StackValue, parameterIndex: Int) {
|
||||
throw UnsupportedOperationException("Shouldn't be called")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user