Generate default arguments and varargs lazily

The aim to perform optimizations in call generators
This commit is contained in:
Mikhael Bogdanov
2017-04-27 12:22:24 +02:00
parent 02cc5f6bc1
commit b440561f5c
6 changed files with 95 additions and 64 deletions
@@ -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)) {
@@ -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")
}