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 kotlin.KotlinPackage; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.kotlin.codegen.state.GenerationState; 023 import org.jetbrains.kotlin.descriptors.*; 024 import org.jetbrains.kotlin.psi.Call; 025 import org.jetbrains.kotlin.psi.JetCallExpression; 026 import org.jetbrains.kotlin.psi.JetExpression; 027 import org.jetbrains.kotlin.psi.ValueArgument; 028 import org.jetbrains.kotlin.resolve.calls.model.DelegatingResolvedCall; 029 import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument; 030 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; 031 import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; 032 import org.jetbrains.kotlin.resolve.calls.util.CallMaker; 033 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; 034 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; 035 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; 036 import org.jetbrains.org.objectweb.asm.Type; 037 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 038 039 import java.util.ArrayList; 040 import java.util.Iterator; 041 import java.util.List; 042 043 import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory; 044 import static org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; 045 046 public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased<FunctionDescriptor> { 047 private final ResolvedCall<?> resolvedCall; 048 private final FunctionDescriptor referencedFunction; 049 050 public FunctionReferenceGenerationStrategy( 051 @NotNull GenerationState state, 052 @NotNull FunctionDescriptor functionDescriptor, 053 @NotNull ResolvedCall<?> resolvedCall 054 ) { 055 super(state, functionDescriptor); 056 this.resolvedCall = resolvedCall; 057 this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); 058 } 059 060 @Override 061 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 062 /* 063 Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation 064 of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of 065 ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every 066 argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of 067 every argument boils down to calling LOAD with the corresponding index 068 */ 069 070 JetCallExpression fakeExpression = constructFakeFunctionCall(); 071 final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments(); 072 073 final ReceiverValue dispatchReceiver = computeAndSaveReceiver(signature, codegen, referencedFunction.getDispatchReceiverParameter()); 074 final ReceiverValue extensionReceiver = computeAndSaveReceiver(signature, codegen, referencedFunction.getExtensionReceiverParameter()); 075 computeAndSaveArguments(fakeArguments, codegen); 076 077 ResolvedCall<CallableDescriptor> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) { 078 @NotNull 079 @Override 080 public ReceiverValue getExtensionReceiver() { 081 return extensionReceiver; 082 } 083 084 @NotNull 085 @Override 086 public ReceiverValue getDispatchReceiver() { 087 return dispatchReceiver; 088 } 089 090 @NotNull 091 @Override 092 public List<ResolvedValueArgument> getValueArgumentsByIndex() { 093 List<ResolvedValueArgument> result = new ArrayList<ResolvedValueArgument>(fakeArguments.size()); 094 for (ValueArgument argument : fakeArguments) { 095 result.add(new ExpressionValueArgument(argument)); 096 } 097 return result; 098 } 099 }; 100 101 StackValue result; 102 Type returnType = codegen.getReturnType(); 103 if (referencedFunction instanceof ConstructorDescriptor) { 104 if (returnType.getSort() == Type.ARRAY) { 105 //noinspection ConstantConditions 106 result = codegen.generateNewArray(fakeExpression, referencedFunction.getReturnType()); 107 } 108 else { 109 result = codegen.generateConstructorCall(fakeResolvedCall, returnType); 110 } 111 } 112 else { 113 Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments); 114 result = codegen.invokeFunction(call, fakeResolvedCall, StackValue.none()); 115 } 116 117 InstructionAdapter v = codegen.v; 118 result.put(returnType, v); 119 v.areturn(returnType); 120 } 121 122 @NotNull 123 private JetCallExpression constructFakeFunctionCall() { 124 StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall("); 125 for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator(); iterator.hasNext(); ) { 126 ValueParameterDescriptor descriptor = iterator.next(); 127 fakeFunctionCall.append("p").append(descriptor.getIndex()); 128 if (iterator.hasNext()) { 129 fakeFunctionCall.append(", "); 130 } 131 } 132 fakeFunctionCall.append(")"); 133 return (JetCallExpression) JetPsiFactory(state.getProject()).createExpression(fakeFunctionCall.toString()); 134 } 135 136 private void computeAndSaveArguments(@NotNull List<? extends ValueArgument> fakeArguments, @NotNull ExpressionCodegen codegen) { 137 int receivers = (referencedFunction.getDispatchReceiverParameter() != null ? 1 : 0) + 138 (referencedFunction.getExtensionReceiverParameter() != null ? 1 : 0); 139 140 List<ValueParameterDescriptor> parameters = KotlinPackage.drop(callableDescriptor.getValueParameters(), receivers); 141 for (int i = 0; i < parameters.size(); i++) { 142 ValueParameterDescriptor parameter = parameters.get(i); 143 ValueArgument fakeArgument = fakeArguments.get(i); 144 145 Type type = state.getTypeMapper().mapType(parameter); 146 int localIndex = codegen.myFrameMap.getIndex(parameter); 147 codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type)); 148 } 149 } 150 151 @NotNull 152 private ReceiverValue computeAndSaveReceiver( 153 @NotNull JvmMethodSignature signature, 154 @NotNull ExpressionCodegen codegen, 155 @Nullable ReceiverParameterDescriptor receiver 156 ) { 157 if (receiver == null) return NO_RECEIVER; 158 159 JetExpression receiverExpression = JetPsiFactory(state.getProject()).createExpression("callableReferenceFakeReceiver"); 160 codegen.tempVariables.put(receiverExpression, receiverParameterStackValue(signature)); 161 return new ExpressionReceiver(receiverExpression, receiver.getType()); 162 } 163 164 @NotNull 165 private static StackValue.Local receiverParameterStackValue(@NotNull JvmMethodSignature signature) { 166 // 0 is this (the callable reference class), 1 is the invoke() method's first parameter 167 return StackValue.local(1, signature.getAsmMethod().getArgumentTypes()[0]); 168 } 169 }