Support more than 32 default arguments

#KT-4675 Fixed
This commit is contained in:
Denis Mekhanikov
2014-08-18 14:42:53 +04:00
committed by Alexander Udalov
parent 3ada0ce0a9
commit 1533c0e9f3
12 changed files with 1149 additions and 24 deletions
@@ -22,23 +22,33 @@ import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public abstract class ArgumentGenerator {
/**
* @return a bit mask of default arguments which should be passed as the last argument to $default method, if there were any default
* arguments, or 0 if there were none
* @return a {@code List} of bit masks of default arguments that should be passed as last arguments to $default method, if there were
* any default arguments, or an empty {@code List} if there were none
*/
public int generate(@NotNull List<ResolvedValueArgument> valueArguments) {
@NotNull
public List<Integer> generate(@NotNull List<ResolvedValueArgument> valueArguments) {
List<Integer> masks = new ArrayList<Integer>(1);
boolean maskIsNeeded = false;
int mask = 0;
int n = valueArguments.size();
for (int i = 0; i < n; i++) {
if (i != 0 && i % Integer.SIZE == 0) {
masks.add(mask);
mask = 0;
}
ResolvedValueArgument argument = valueArguments.get(i);
if (argument instanceof ExpressionValueArgument) {
generateExpression(i, (ExpressionValueArgument) argument);
}
else if (argument instanceof DefaultValueArgument) {
mask |= 1 << i;
maskIsNeeded = true;
mask |= 1 << (i % Integer.SIZE);
generateDefault(i, (DefaultValueArgument) argument);
}
else if (argument instanceof VarargValueArgument) {
@@ -49,7 +59,12 @@ public abstract class ArgumentGenerator {
}
}
return mask;
if (!maskIsNeeded) {
return Collections.emptyList();
}
masks.add(mask);
return masks;
}
protected void generateExpression(int i, @NotNull ExpressionValueArgument argument) {
@@ -19,6 +19,7 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
@@ -134,8 +135,7 @@ public class CallableMethod implements Callable {
}
Method method = getAsmMethod();
String desc = method.getDescriptor().replace(")", "I)");
String desc = JetTypeMapper.getDefaultDescriptor(method, receiverParameterType != null);
if ("<init>".equals(method.getName())) {
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", desc, false);
}
@@ -81,7 +81,8 @@ import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure;
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.*;
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin;
@@ -2175,19 +2176,18 @@ 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();
int mask = argumentGenerator.generate(valueArguments);
List<Integer> masks = argumentGenerator.generate(valueArguments);
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
tailRecursionCodegen.generateTailRecursion(resolvedCall);
return;
}
boolean callDefault = mask != 0;
if (callDefault) {
for (int mask : masks) {
callGenerator.putValueIfNeeded(null, Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE));
}
callGenerator.genCall(callableMethod, resolvedCall, callDefault, this);
callGenerator.genCall(callableMethod, resolvedCall, !masks.isEmpty(), this);
}
@NotNull
@@ -59,10 +59,7 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
@@ -524,13 +521,22 @@ public class FunctionCodegen extends ParentCodegenAware {
v.load(0, methodOwner); // Load this on stack
int mask = 0;
List<Integer> masks = new ArrayList<Integer>(1);
for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
pushDefaultValueOnStack(paramType, v);
mask |= (1 << parameterDescriptor.getIndex());
int i = parameterDescriptor.getIndex();
if (i != 0 && i % Integer.SIZE == 0) {
masks.add(mask);
mask = 0;
}
mask |= (1 << (i % Integer.SIZE));
}
v.iconst(mask);
String desc = method.getAsmMethod().getDescriptor().replace(")", "I)");
masks.add(mask);
for (int m : masks) {
v.iconst(m);
}
String desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false);
v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false);
v.areturn(Type.VOID_TYPE);
endVisit(mv, "default constructor for " + methodOwner.getInternalName(), null);
@@ -610,8 +616,6 @@ public class FunctionCodegen extends ParentCodegenAware {
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);
int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function);
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -625,15 +629,19 @@ public class FunctionCodegen extends ParentCodegenAware {
capturedArgumentsCount++;
}
int maskIndex = 0;
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
for (int index = 0; index < valueParameters.size(); index++) {
if (index % Integer.SIZE == 0) {
maskIndex = frameMap.enterTemp(Type.INT_TYPE);
}
ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();
int parameterIndex = frameMap.getIndex(parameterDescriptor);
if (parameterDescriptor.declaresDefaultValue()) {
iv.load(maskIndex, Type.INT_TYPE);
iv.iconst(1 << index);
iv.iconst(1 << (index % Integer.SIZE));
iv.and(Type.INT_TYPE);
Label loadArg = new Label();
iv.ifeq(loadArg);
@@ -16,6 +16,7 @@
package org.jetbrains.jet.codegen.state;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -613,11 +614,23 @@ public class JetTypeMapper {
return sw.makeJvmMethodSignature(mapFunctionName(f));
}
@NotNull
public static String getDefaultDescriptor(@NotNull Method method, boolean isExtension) {
String descriptor = method.getDescriptor();
int argumentsCount = (Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1;
if (isExtension) {
argumentsCount--;
}
int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE;
String maskArguments = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
return descriptor.replace(")", maskArguments + ")");
}
@NotNull
public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext<?> context) {
Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod();
Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
String descriptor = getDefaultDescriptor(jvmSignature, functionDescriptor.getReceiverParameter() != null);
boolean isConstructor = "<init>".equals(jvmSignature.getName());
if (!isStatic(kind) && !isConstructor) {
descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());