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