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;
|
package org.jetbrains.kotlin.codegen;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.psi.KtExpression;
|
import org.jetbrains.kotlin.psi.KtExpression;
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
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.kotlin.types.FlexibleTypesKt;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
import java.util.List;
|
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 {
|
public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||||
private final ExpressionCodegen codegen;
|
private final ExpressionCodegen codegen;
|
||||||
@@ -64,19 +64,16 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) {
|
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) {
|
||||||
Type type = valueParameterTypes.get(i);
|
callGenerator.putValueIfNeeded(valueParameterTypes.get(i), createDefaulValue(valueParameterTypes.get(i)));
|
||||||
pushDefaultValueOnStack(type, codegen.v);
|
|
||||||
callGenerator.afterParameterPut(type, null, i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||||
ValueParameterDescriptor parameter = valueParameters.get(i);
|
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>',
|
// 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
|
// while its lower bound may be Nothing-typed after approximation
|
||||||
codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
StackValue lazyVararg = codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
||||||
callGenerator.afterParameterPut(type, null, i);
|
callGenerator.putValueIfNeeded(valueParameterTypes.get(i), lazyVararg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ abstract class CallGenerator {
|
|||||||
|
|
||||||
override fun afterParameterPut(
|
override fun afterParameterPut(
|
||||||
type: Type,
|
type: Type,
|
||||||
stackValue: StackValue?,
|
stackValue: StackValue,
|
||||||
parameterIndex: Int) {
|
parameterIndex: Int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ abstract class CallGenerator {
|
|||||||
|
|
||||||
abstract fun afterParameterPut(
|
abstract fun afterParameterPut(
|
||||||
type: Type,
|
type: Type,
|
||||||
stackValue: StackValue?,
|
stackValue: StackValue,
|
||||||
parameterIndex: Int)
|
parameterIndex: Int)
|
||||||
|
|
||||||
abstract fun genValueAndPut(
|
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.CoroutineCodegenUtilKt;
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
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.inline.*;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
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.binding.CodegenBinding.*;
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
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.isEnumEntry;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
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);
|
Type type = asmType(outType);
|
||||||
assert type.getSort() == Type.ARRAY;
|
assert type.getSort() == Type.ARRAY;
|
||||||
Type elementType = correctElementType(type);
|
Type elementType = correctElementType(type);
|
||||||
@@ -2553,17 +2556,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
if (hasSpread) {
|
if (hasSpread) {
|
||||||
boolean arrayOfReferences = KotlinBuiltIns.isArray(outType);
|
boolean arrayOfReferences = KotlinBuiltIns.isArray(outType);
|
||||||
if (size == 1) {
|
if (size == 1) {
|
||||||
// Arrays.copyOf(receiverValue, newLength)
|
Type arrayType = getArrayType(arrayOfReferences ? AsmTypes.OBJECT_TYPE : elementType);
|
||||||
ValueArgument argument = arguments.get(0);
|
return StackValue.operation(type, adapter -> {
|
||||||
Type arrayType = arrayOfReferences ? Type.getType("[Ljava/lang/Object;")
|
gen(arguments.get(0).getArgumentExpression(), type);
|
||||||
: Type.getType("[" + elementType.getDescriptor());
|
v.dup();
|
||||||
gen(argument.getArgumentExpression(), type);
|
v.arraylength();
|
||||||
v.dup();
|
v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
|
||||||
v.arraylength();
|
if (arrayOfReferences) {
|
||||||
v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
|
v.checkcast(type);
|
||||||
if (arrayOfReferences) {
|
}
|
||||||
v.checkcast(type);
|
return Unit.INSTANCE;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String owner;
|
String owner;
|
||||||
@@ -2580,42 +2583,49 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
addDescriptor = "(" + elementType.getDescriptor() + ")V";
|
addDescriptor = "(" + elementType.getDescriptor() + ")V";
|
||||||
toArrayDescriptor = "()" + type.getDescriptor();
|
toArrayDescriptor = "()" + type.getDescriptor();
|
||||||
}
|
}
|
||||||
v.anew(Type.getObjectType(owner));
|
|
||||||
v.dup();
|
return StackValue.operation(type, adapter -> {
|
||||||
v.iconst(size);
|
v.anew(Type.getObjectType(owner));
|
||||||
v.invokespecial(owner, "<init>", "(I)V", false);
|
|
||||||
for (int i = 0; i != size; ++i) {
|
|
||||||
v.dup();
|
v.dup();
|
||||||
ValueArgument argument = arguments.get(i);
|
v.iconst(size);
|
||||||
if (argument.getSpreadElement() != null) {
|
v.invokespecial(owner, "<init>", "(I)V", false);
|
||||||
gen(argument.getArgumentExpression(), OBJECT_TYPE);
|
for (int i = 0; i != size; ++i) {
|
||||||
v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false);
|
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 {
|
else {
|
||||||
gen(argument.getArgumentExpression(), elementType);
|
v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
|
||||||
v.invokevirtual(owner, "add", addDescriptor, false);
|
|
||||||
}
|
}
|
||||||
}
|
return Unit.INSTANCE;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
v.iconst(arguments.size());
|
return StackValue.operation(type, adapter -> {
|
||||||
newArrayInstruction(outType);
|
v.iconst(arguments.size());
|
||||||
for (int i = 0; i != size; ++i) {
|
newArrayInstruction(outType);
|
||||||
v.dup();
|
for (int i = 0; i != size; ++i) {
|
||||||
StackValue rightSide = gen(arguments.get(i).getArgumentExpression());
|
v.dup();
|
||||||
StackValue.arrayElement(elementType, StackValue.onStack(type), StackValue.constant(i, Type.INT_TYPE)).store(rightSide, v);
|
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
|
@NotNull
|
||||||
public static StackValue cmp(@NotNull IElementType opToken, @NotNull Type type, StackValue left, StackValue right) {
|
public static StackValue cmp(@NotNull IElementType opToken, @NotNull Type type, StackValue left, StackValue right) {
|
||||||
return BranchedValue.Companion.cmp(opToken, type, left, right);
|
return BranchedValue.Companion.cmp(opToken, type, left, right);
|
||||||
|
|||||||
@@ -671,13 +671,13 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putArgumentOrCapturedToLocalVal(
|
private void putArgumentOrCapturedToLocalVal(
|
||||||
@NotNull Type type,
|
@NotNull Type type,
|
||||||
@Nullable StackValue stackValue,
|
@NotNull StackValue stackValue,
|
||||||
int capturedParamIndex,
|
int capturedParamIndex,
|
||||||
int parameterIndex
|
int parameterIndex
|
||||||
) {
|
) {
|
||||||
@@ -701,12 +701,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*descriptor is null for captured vars*/
|
/*descriptor is null for captured vars*/
|
||||||
private static boolean shouldPutGeneralValue(@NotNull Type type, @Nullable StackValue stackValue) {
|
private static boolean shouldPutGeneralValue(@NotNull Type type, @NotNull StackValue stackValue) {
|
||||||
if (stackValue == null) {
|
|
||||||
//default or vararg
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//remap only inline functions (and maybe non primitives)
|
//remap only inline functions (and maybe non primitives)
|
||||||
//TODO - clean asserion and remapping logic
|
//TODO - clean asserion and remapping logic
|
||||||
if (isPrimitive(type) != isPrimitive(stackValue.type)) {
|
if (isPrimitive(type) != isPrimitive(stackValue.type)) {
|
||||||
|
|||||||
+1
-1
@@ -87,7 +87,7 @@ class InlineCodegenForDefaultBody(
|
|||||||
transformedMethod.accept(MethodBodyVisitor(codegen.v))
|
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")
|
throw UnsupportedOperationException("Shouldn't be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user