001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.codegen; 018 019 import com.google.common.collect.Lists; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.kotlin.cfg.TailRecursionKind; 022 import org.jetbrains.kotlin.codegen.context.MethodContext; 023 import org.jetbrains.kotlin.codegen.state.GenerationState; 024 import org.jetbrains.kotlin.descriptors.CallableDescriptor; 025 import org.jetbrains.kotlin.descriptors.FunctionDescriptor; 026 import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; 027 import org.jetbrains.kotlin.psi.KtExpression; 028 import org.jetbrains.kotlin.psi.KtSimpleNameExpression; 029 import org.jetbrains.kotlin.psi.ValueArgument; 030 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; 031 import org.jetbrains.kotlin.resolve.calls.model.*; 032 import org.jetbrains.org.objectweb.asm.Type; 033 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 034 035 import java.util.List; 036 037 import static org.jetbrains.kotlin.resolve.BindingContext.TAIL_RECURSION_CALL; 038 039 public class TailRecursionCodegen { 040 041 @NotNull 042 private final MethodContext context; 043 @NotNull 044 private final ExpressionCodegen codegen; 045 @NotNull 046 private final InstructionAdapter v; 047 @NotNull 048 private final GenerationState state; 049 050 public TailRecursionCodegen( 051 @NotNull MethodContext context, 052 @NotNull ExpressionCodegen codegen, 053 @NotNull InstructionAdapter v, 054 @NotNull GenerationState state 055 ) { 056 this.context = context; 057 this.codegen = codegen; 058 this.v = v; 059 this.state = state; 060 } 061 062 public boolean isTailRecursion(@NotNull ResolvedCall<?> resolvedCall) { 063 TailRecursionKind status = state.getBindingContext().get(TAIL_RECURSION_CALL, resolvedCall); 064 return status != null && status.isDoGenerateTailRecursion(); 065 } 066 067 public void generateTailRecursion(ResolvedCall<?> resolvedCall) { 068 CallableDescriptor fd = resolvedCall.getResultingDescriptor(); 069 assert fd instanceof FunctionDescriptor : "Resolved call doesn't refer to the function descriptor: " + fd; 070 CallableMethod callable = (CallableMethod) codegen.resolveToCallable((FunctionDescriptor) fd, false, resolvedCall); 071 072 List<ResolvedValueArgument> arguments = resolvedCall.getValueArgumentsByIndex(); 073 if (arguments == null) { 074 throw new IllegalStateException("Failed to arrange value arguments by index: " + fd); 075 } 076 assignParameterValues(fd, callable, arguments); 077 if (callable.getExtensionReceiverType() != null) { 078 if (resolvedCall.getExtensionReceiver() != fd.getExtensionReceiverParameter().getValue()) { 079 StackValue expression = context.getReceiverExpression(codegen.typeMapper); 080 expression.store(StackValue.onStack(callable.getExtensionReceiverType()), v, true); 081 } 082 else { 083 AsmUtil.pop(v, callable.getExtensionReceiverType()); 084 } 085 } 086 087 if (callable.getDispatchReceiverType() != null) { 088 AsmUtil.pop(v, callable.getDispatchReceiverType()); 089 } 090 091 v.goTo(context.getMethodStartLabel()); 092 } 093 094 private void assignParameterValues( 095 CallableDescriptor fd, 096 CallableMethod callableMethod, 097 List<ResolvedValueArgument> valueArguments 098 ) { 099 List<Type> types = callableMethod.getValueParameterTypes(); 100 for (ValueParameterDescriptor parameterDescriptor : Lists.reverse(fd.getValueParameters())) { 101 ResolvedValueArgument arg = valueArguments.get(parameterDescriptor.getIndex()); 102 Type type = types.get(parameterDescriptor.getIndex()); 103 104 if (arg instanceof ExpressionValueArgument) { 105 ExpressionValueArgument ev = (ExpressionValueArgument) arg; 106 ValueArgument argument = ev.getValueArgument(); 107 KtExpression argumentExpression = argument == null ? null : argument.getArgumentExpression(); 108 109 if (argumentExpression instanceof KtSimpleNameExpression) { 110 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(argumentExpression, state.getBindingContext()); 111 if (resolvedCall != null && resolvedCall.getResultingDescriptor().equals(parameterDescriptor.getOriginal())) { 112 // do nothing: we shouldn't store argument to itself again 113 AsmUtil.pop(v, type); 114 continue; 115 } 116 } 117 //assign the parameter below 118 } 119 else if (arg instanceof DefaultValueArgument) { 120 AsmUtil.pop(v, type); 121 DefaultParameterValueLoader.DEFAULT.genValue(parameterDescriptor, codegen).put(type, v); 122 } 123 else if (arg instanceof VarargValueArgument) { 124 // assign the parameter below 125 } 126 else { 127 throw new UnsupportedOperationException("Unknown argument type: " + arg + " in " + fd); 128 } 129 130 store(parameterDescriptor, type); 131 } 132 } 133 134 private void store(ValueParameterDescriptor parameterDescriptor, Type type) { 135 int index = getParameterVariableIndex(parameterDescriptor); 136 v.store(index, type); 137 } 138 139 private int getParameterVariableIndex(ValueParameterDescriptor parameterDescriptor) { 140 int index = codegen.lookupLocalIndex(parameterDescriptor); 141 if (index == -1) { 142 // in the case of a generic function recursively calling itself, the parameters on the call site are substituted 143 index = codegen.lookupLocalIndex(parameterDescriptor.getOriginal()); 144 } 145 146 if (index == -1) { 147 throw new IllegalStateException("Failed to obtain parameter index: " + parameterDescriptor); 148 } 149 150 return index; 151 } 152 }