Support more than 32 default arguments
#KT-4675 Fixed
This commit is contained in:
committed by
Alexander Udalov
parent
3ada0ce0a9
commit
1533c0e9f3
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user