TCO: Re-use parameter values already loaded onto the stack for a recursive call
This commit is contained in:
@@ -1996,10 +1996,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
StackValue receiver,
|
StackValue receiver,
|
||||||
ResolvedCall<? extends CallableDescriptor> resolvedCall
|
ResolvedCall<? extends CallableDescriptor> resolvedCall
|
||||||
) {
|
) {
|
||||||
if (tailRecursionGeneratorUtil.isTailRecursion(resolvedCall)) {
|
|
||||||
return tailRecursionGeneratorUtil.generateTailRecursion(resolvedCall, call);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||||
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||||
ResolvedCallWithTrace<FunctionDescriptor> functionCall = variableAsFunctionResolvedCall.getFunctionCall();
|
ResolvedCallWithTrace<FunctionDescriptor> functionCall = variableAsFunctionResolvedCall.getFunctionCall();
|
||||||
@@ -2149,6 +2145,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
|
|
||||||
private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable) {
|
private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable) {
|
||||||
int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
|
int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
|
||||||
|
|
||||||
|
if (tailRecursionGeneratorUtil.isTailRecursion(resolvedCall)) {
|
||||||
|
tailRecursionGeneratorUtil.generateTailRecursion(resolvedCall);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
callable.invokeWithNotNullAssertion(v, state, resolvedCall);
|
callable.invokeWithNotNullAssertion(v, state, resolvedCall);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,16 +25,15 @@ import org.jetbrains.jet.codegen.state.GenerationState;
|
|||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.Call;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.TailRecursionKind;
|
import org.jetbrains.jet.lang.resolve.calls.TailRecursionKind;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.TAIL_RECURSION_CALL;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.TAIL_RECURSION_CALL;
|
||||||
|
|
||||||
public class TailRecursionGeneratorUtil {
|
public class TailRecursionGeneratorUtil {
|
||||||
@@ -65,33 +64,36 @@ public class TailRecursionGeneratorUtil {
|
|||||||
return status != null && status.isDoGenerateTailRecursion();
|
return status != null && status.isDoGenerateTailRecursion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StackValue generateTailRecursion(ResolvedCall<? extends CallableDescriptor> resolvedCall, Call call) {
|
public void generateTailRecursion(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
||||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||||
assert fd instanceof FunctionDescriptor : "the resolved call is not refer to the function descriptor so why do we use generateTailRecursion for something strange?";
|
assert fd instanceof FunctionDescriptor : "the resolved call is not refer to the function descriptor so why do we use generateTailRecursion for something strange?";
|
||||||
CallableMethod callable = (CallableMethod) codegen.resolveToCallable((FunctionDescriptor) fd, false);
|
CallableMethod callable = (CallableMethod) codegen.resolveToCallable((FunctionDescriptor) fd, false);
|
||||||
List<Type> types = callable.getValueParameterTypes();
|
|
||||||
List<ValueParameterDescriptor> parametersStored = prepareParameterValuesOnStack(fd, types, resolvedCall.getValueArgumentsByIndex());
|
|
||||||
|
|
||||||
// we can't store values to the variables in the loop above because it will affect expressions evaluation
|
assignParameterValues(fd, callable, resolvedCall.getValueArgumentsByIndex());
|
||||||
for (ValueParameterDescriptor parameterDescriptor : Lists.reverse(parametersStored)) {
|
if (callable.getReceiverClass() != null) {
|
||||||
Type asmType = types.get(parameterDescriptor.getIndex());
|
if (resolvedCall.getReceiverArgument() != fd.getReceiverParameter().getValue()) {
|
||||||
int index = getParameterVariableIndex(parameterDescriptor, call);
|
StackValue expression = context.getReceiverExpression(codegen.typeMapper);
|
||||||
|
expression.store(callable.getReceiverClass(), v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
AsmUtil.pop(v, callable.getReceiverClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
v.store(index, asmType);
|
if (callable.getThisType() != null) {
|
||||||
|
AsmUtil.pop(v, callable.getThisType());
|
||||||
}
|
}
|
||||||
|
|
||||||
v.goTo(context.getMethodStartLabel());
|
v.goTo(context.getMethodStartLabel());
|
||||||
|
|
||||||
return StackValue.none();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ValueParameterDescriptor> prepareParameterValuesOnStack(
|
private void assignParameterValues(
|
||||||
CallableDescriptor fd,
|
CallableDescriptor fd,
|
||||||
List<Type> types,
|
CallableMethod callableMethod,
|
||||||
List<ResolvedValueArgument> valueArguments
|
List<ResolvedValueArgument> valueArguments
|
||||||
) {
|
) {
|
||||||
List<ValueParameterDescriptor> descriptorsStored = new ArrayList<ValueParameterDescriptor>(valueArguments.size());
|
List<Type> types = callableMethod.getValueParameterTypes();
|
||||||
for (ValueParameterDescriptor parameterDescriptor : fd.getValueParameters()) {
|
for (ValueParameterDescriptor parameterDescriptor : Lists.reverse(fd.getValueParameters())) {
|
||||||
ResolvedValueArgument arg = valueArguments.get(parameterDescriptor.getIndex());
|
ResolvedValueArgument arg = valueArguments.get(parameterDescriptor.getIndex());
|
||||||
Type type = types.get(parameterDescriptor.getIndex());
|
Type type = types.get(parameterDescriptor.getIndex());
|
||||||
|
|
||||||
@@ -101,39 +103,44 @@ public class TailRecursionGeneratorUtil {
|
|||||||
JetExpression argumentExpression = argument == null ? null : argument.getArgumentExpression();
|
JetExpression argumentExpression = argument == null ? null : argument.getArgumentExpression();
|
||||||
|
|
||||||
if (argumentExpression instanceof JetSimpleNameExpression) {
|
if (argumentExpression instanceof JetSimpleNameExpression) {
|
||||||
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) argumentExpression;
|
ResolvedCall<? extends CallableDescriptor> resolvedCall = state.getBindingContext().get(RESOLVED_CALL, argumentExpression);
|
||||||
if (nameExpression.getReferencedNameAsName().equals(parameterDescriptor.getName())) {
|
if (resolvedCall != null && resolvedCall.getResultingDescriptor().equals(parameterDescriptor.getOriginal())) {
|
||||||
// do nothing: we shouldn't store argument to itself again
|
// do nothing: we shouldn't store argument to itself again
|
||||||
|
AsmUtil.pop(v, type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//assign the parameter below
|
||||||
codegen.gen(argumentExpression, type);
|
|
||||||
}
|
}
|
||||||
else if (arg instanceof DefaultValueArgument) {
|
else if (arg instanceof DefaultValueArgument) {
|
||||||
|
AsmUtil.pop(v, type);
|
||||||
DefaultParameterValueLoader.DEFAULT.putValueOnStack(parameterDescriptor, codegen);
|
DefaultParameterValueLoader.DEFAULT.putValueOnStack(parameterDescriptor, codegen);
|
||||||
}
|
}
|
||||||
else if (arg instanceof VarargValueArgument) {
|
else if (arg instanceof VarargValueArgument) {
|
||||||
VarargValueArgument valueArgument = (VarargValueArgument) arg;
|
// assign the parameter below
|
||||||
codegen.genVarargs(parameterDescriptor, valueArgument);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException("Unknown argument type: " + arg + " in " + fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptorsStored.add(parameterDescriptor);
|
store(parameterDescriptor, type);
|
||||||
}
|
}
|
||||||
return descriptorsStored;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getParameterVariableIndex(ValueParameterDescriptor parameterDescriptor, Call call) {
|
private void store(ValueParameterDescriptor parameterDescriptor, Type type) {
|
||||||
|
int index = getParameterVariableIndex(parameterDescriptor);
|
||||||
|
v.store(index, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getParameterVariableIndex(ValueParameterDescriptor parameterDescriptor) {
|
||||||
int index = codegen.lookupLocalIndex(parameterDescriptor);
|
int index = codegen.lookupLocalIndex(parameterDescriptor);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
|
// in the case of a generic function recursively calling itself, the parameters on the call site are substituted
|
||||||
index = codegen.lookupLocalIndex(parameterDescriptor.getOriginal());
|
index = codegen.lookupLocalIndex(parameterDescriptor.getOriginal());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
throw new CompilationException("Failed to obtain parameter index: " + parameterDescriptor.getName(), null, call.getCallElement());
|
throw new IllegalStateException("Failed to obtain parameter index: " + parameterDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
|
|||||||
Reference in New Issue
Block a user