All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.codegen.TailRecursionCodegen Maven / Gradle / Ivy

There is a newer version: 2.0.20-RC
Show newest version
/*
 * Copyright 2010-2016 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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 java.util.List;

import static org.jetbrains.kotlin.resolve.BindingContext.TAIL_RECURSION_CALL;

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;
    }

    public boolean isTailRecursion(@NotNull ResolvedCall resolvedCall) {
        TailRecursionKind status = state.getBindingContext().get(TAIL_RECURSION_CALL, resolvedCall.getCall());
        return status != null && status.isDoGenerateTailRecursion();
    }

    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);

        List 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 valueArguments
    ) {
        List 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
                        AsmUtil.pop(v, type);
                        continue;
                    }
                }
                //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);
            }

            store(parameterDescriptor, type);
        }
    }

    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);
        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());
        }

        if (index == -1) {
            throw new IllegalStateException("Failed to obtain parameter index: " + parameterDescriptor);
        }

        return index;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy