Convert TailRecursionCodegen.java to Kotlin

This commit is contained in:
Mikhael Bogdanov
2019-06-13 12:49:47 +02:00
parent 2eda7cb4b0
commit 077092d619
@@ -14,145 +14,122 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.codegen; package org.jetbrains.kotlin.codegen
import com.google.common.collect.Lists; import com.google.common.collect.Lists
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cfg.TailRecursionKind
import org.jetbrains.kotlin.cfg.TailRecursionKind; import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.context.MethodContext; import org.jetbrains.kotlin.codegen.coroutines.*
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor; 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.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression; import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.psi.ValueArgument; import org.jetbrains.kotlin.resolve.calls.callUtil.*
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.*; import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import java.util.List; import org.jetbrains.kotlin.resolve.BindingContext.TAIL_RECURSION_CALL
import static org.jetbrains.kotlin.resolve.BindingContext.TAIL_RECURSION_CALL; class TailRecursionCodegen(
private val context: MethodContext,
private val codegen: ExpressionCodegen,
private val v: InstructionAdapter,
private val state: GenerationState
) {
public class TailRecursionCodegen { fun isTailRecursion(resolvedCall: ResolvedCall<*>): Boolean {
val status = state.bindingContext.get(TAIL_RECURSION_CALL, resolvedCall.call)
return status != null && status.isDoGenerateTailRecursion
}
@NotNull fun generateTailRecursion(resolvedCall: ResolvedCall<*>) {
private final MethodContext context; val fd = resolvedCall.resultingDescriptor.unwrapInitialDescriptorForSuspendFunction().let {
@NotNull it as? FunctionDescriptor
private final ExpressionCodegen codegen; ?: error("Resolved call doesn't refer to the function descriptor: $it")
@NotNull }
private final InstructionAdapter v; val callable = codegen.resolveToCallable(fd, false, resolvedCall) as CallableMethod
@NotNull
private final GenerationState state;
public TailRecursionCodegen( val arguments = resolvedCall.valueArgumentsByIndex ?: throw IllegalStateException("Failed to arrange value arguments by index: $fd")
@NotNull MethodContext context,
@NotNull ExpressionCodegen codegen, if (fd.isSuspend) {
@NotNull InstructionAdapter v, AsmUtil.pop(v, callable.getValueParameters()[callable.getValueParameters().size - 1].asmType)
@NotNull GenerationState state }
assignParameterValues(fd, callable, arguments)
if (callable.extensionReceiverType != null) {
if (resolvedCall.extensionReceiver != fd.extensionReceiverParameter!!.value) {
val expression = context.getReceiverExpression(codegen.typeMapper)
expression.store(StackValue.onStack(callable.extensionReceiverType), v, true)
} else {
AsmUtil.pop(v, callable.extensionReceiverType)
}
}
if (callable.dispatchReceiverType != null) {
AsmUtil.pop(v, callable.dispatchReceiverType)
}
v.goTo(context.methodStartLabel)
}
private fun assignParameterValues(
fd: CallableDescriptor,
callableMethod: CallableMethod,
valueArguments: List<ResolvedValueArgument>
) { ) {
this.context = context; val types = callableMethod.valueParameterTypes
this.codegen = codegen; loop@ for (parameterDescriptor in fd.valueParameters.asReversed()) {
this.v = v; val arg = valueArguments[parameterDescriptor.index]
this.state = state; val type = types[parameterDescriptor.index]
}
public boolean isTailRecursion(@NotNull ResolvedCall<?> resolvedCall) { when (arg) {
TailRecursionKind status = state.getBindingContext().get(TAIL_RECURSION_CALL, resolvedCall.getCall()); is ExpressionValueArgument -> {
return status != null && status.isDoGenerateTailRecursion(); val argumentExpression = arg.valueArgument?.getArgumentExpression()
}
public void generateTailRecursion(ResolvedCall<?> resolvedCall) { if (argumentExpression is KtSimpleNameExpression) {
CallableDescriptor fd = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(resolvedCall.getResultingDescriptor()); val resolvedCall = argumentExpression.getResolvedCall(state.bindingContext)
assert fd instanceof FunctionDescriptor : "Resolved call doesn't refer to the function descriptor: " + fd; if (resolvedCall?.resultingDescriptor == parameterDescriptor.original) {
CallableMethod callable = (CallableMethod) codegen.resolveToCallable((FunctionDescriptor) fd, false, resolvedCall);
List<ResolvedValueArgument> arguments = resolvedCall.getValueArgumentsByIndex();
if (arguments == null) {
throw new IllegalStateException("Failed to arrange value arguments by index: " + fd);
}
if (((FunctionDescriptor) fd).isSuspend()) {
AsmUtil.pop(v, callable.getValueParameters().get(callable.getValueParameters().size() - 1).getAsmType());
}
assignParameterValues(fd, callable, arguments);
if (callable.getExtensionReceiverType() != null) {
if (resolvedCall.getExtensionReceiver() != fd.getExtensionReceiverParameter().getValue()) {
StackValue expression = context.getReceiverExpression(codegen.typeMapper);
expression.store(StackValue.onStack(callable.getExtensionReceiverType()), v, true);
}
else {
AsmUtil.pop(v, callable.getExtensionReceiverType());
}
}
if (callable.getDispatchReceiverType() != null) {
AsmUtil.pop(v, callable.getDispatchReceiverType());
}
v.goTo(context.getMethodStartLabel());
}
private void assignParameterValues(
CallableDescriptor fd,
CallableMethod callableMethod,
List<ResolvedValueArgument> valueArguments
) {
List<Type> types = callableMethod.getValueParameterTypes();
for (ValueParameterDescriptor parameterDescriptor : Lists.reverse(fd.getValueParameters())) {
ResolvedValueArgument arg = valueArguments.get(parameterDescriptor.getIndex());
Type type = types.get(parameterDescriptor.getIndex());
if (arg instanceof ExpressionValueArgument) {
ExpressionValueArgument ev = (ExpressionValueArgument) arg;
ValueArgument argument = ev.getValueArgument();
KtExpression argumentExpression = argument == null ? null : argument.getArgumentExpression();
if (argumentExpression instanceof KtSimpleNameExpression) {
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(argumentExpression, state.getBindingContext());
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); AsmUtil.pop(v, type)
continue; continue@loop
} }
} }
//assign the parameter below //assign the parameter below
} }
else if (arg instanceof DefaultValueArgument) { is DefaultValueArgument -> {
AsmUtil.pop(v, type); AsmUtil.pop(v, type)
DefaultParameterValueLoader.DEFAULT.genValue(parameterDescriptor, codegen).put(type, v); DefaultParameterValueLoader.DEFAULT.genValue(parameterDescriptor, codegen).put(type, v)
} }
else if (arg instanceof VarargValueArgument) { is VarargValueArgument -> {
// assign the parameter below // assign the parameter below
} }
else { else -> throw UnsupportedOperationException("Unknown argument type: $arg in $fd")
throw new UnsupportedOperationException("Unknown argument type: " + arg + " in " + fd);
} }
store(parameterDescriptor, type); store(parameterDescriptor, type)
} }
} }
private void store(ValueParameterDescriptor parameterDescriptor, Type type) { private fun store(parameterDescriptor: ValueParameterDescriptor, type: Type) {
int index = getParameterVariableIndex(parameterDescriptor); val index = getParameterVariableIndex(parameterDescriptor)
v.store(index, type); v.store(index, type)
} }
private int getParameterVariableIndex(ValueParameterDescriptor parameterDescriptor) { private fun getParameterVariableIndex(parameterDescriptor: ValueParameterDescriptor): Int {
int index = codegen.lookupLocalIndex(parameterDescriptor); var 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 // 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.original)
} }
if (index == -1) { if (index == -1) {
throw new IllegalStateException("Failed to obtain parameter index: " + parameterDescriptor); throw IllegalStateException("Failed to obtain parameter index: $parameterDescriptor")
} }
return index; return index
} }
} }