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