001 /*
002 * Copyright 2010-2013 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.jet.codegen;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.util.ArrayUtil;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.asm4.MethodVisitor;
025 import org.jetbrains.asm4.Type;
026 import org.jetbrains.asm4.commons.InstructionAdapter;
027 import org.jetbrains.asm4.commons.Method;
028 import org.jetbrains.jet.codegen.binding.CalculatedClosure;
029 import org.jetbrains.jet.codegen.context.CodegenContext;
030 import org.jetbrains.jet.codegen.context.LocalLookup;
031 import org.jetbrains.jet.codegen.context.MethodContext;
032 import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
033 import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
034 import org.jetbrains.jet.codegen.state.GenerationState;
035 import org.jetbrains.jet.codegen.state.JetTypeMapper;
036 import org.jetbrains.jet.lang.descriptors.*;
037 import org.jetbrains.jet.lang.resolve.BindingContext;
038 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
039 import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
040 import org.jetbrains.jet.lang.resolve.name.Name;
041 import org.jetbrains.jet.lang.types.JetType;
042 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
043
044 import java.util.Collection;
045 import java.util.List;
046
047 import static org.jetbrains.asm4.Opcodes.*;
048 import static org.jetbrains.jet.codegen.AsmUtil.*;
049 import static org.jetbrains.jet.codegen.CodegenUtil.isConst;
050 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
051 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
052
053 public class ClosureCodegen extends ParentCodegenAwareImpl {
054 private final PsiElement fun;
055 private final FunctionDescriptor funDescriptor;
056 private final ClassDescriptor samInterface;
057 private final Type superClass;
058 private final CodegenContext context;
059 private final FunctionGenerationStrategy strategy;
060 private final CalculatedClosure closure;
061 private final Type asmType;
062 private final int visibilityFlag;
063 private final KotlinSyntheticClass.Kind syntheticClassKind;
064
065 private Method constructor;
066
067 public ClosureCodegen(
068 @NotNull GenerationState state,
069 @NotNull PsiElement fun,
070 @NotNull FunctionDescriptor funDescriptor,
071 @Nullable ClassDescriptor samInterface,
072 @NotNull Type closureSuperClass,
073 @NotNull CodegenContext parentContext,
074 @NotNull KotlinSyntheticClass.Kind syntheticClassKind,
075 @NotNull LocalLookup localLookup,
076 @NotNull FunctionGenerationStrategy strategy,
077 @Nullable MemberCodegen parentCodegen
078 ) {
079 super(state, parentCodegen);
080
081 this.fun = fun;
082 this.funDescriptor = funDescriptor;
083 this.samInterface = samInterface;
084 this.superClass = closureSuperClass;
085 this.context = parentContext.intoClosure(funDescriptor, localLookup, typeMapper);
086 this.syntheticClassKind = syntheticClassKind;
087 this.strategy = strategy;
088
089 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor);
090 this.closure = bindingContext.get(CLOSURE, classDescriptor);
091 assert closure != null : "Closure must be calculated for class: " + classDescriptor;
092
093 this.asmType = asmTypeForAnonymousClass(bindingContext, funDescriptor);
094
095 //TODO: We should write header on lambda class and filter all completions by header
096 if (parentContext instanceof MethodContext) {
097 visibilityFlag = ((MethodContext) parentContext).isInlineFunction() ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
098 } else {
099 visibilityFlag = NO_FLAG_PACKAGE_PRIVATE;
100 }
101 }
102
103 public void gen() {
104 ClassBuilder cv = state.getFactory().newVisitor(asmType, fun.getContainingFile());
105
106 FunctionDescriptor interfaceFunction;
107 String[] superInterfaces;
108
109 if (samInterface == null) {
110 interfaceFunction = getInvokeFunction(funDescriptor);
111 superInterfaces = ArrayUtil.EMPTY_STRING_ARRAY;
112 }
113 else {
114 interfaceFunction = SingleAbstractMethodUtils.getAbstractMethodOfSamInterface(samInterface);
115 superInterfaces = new String[] { typeMapper.mapType(samInterface).getInternalName() };
116 }
117
118 cv.defineClass(fun,
119 V1_6,
120 ACC_FINAL | ACC_SUPER | visibilityFlag,
121 asmType.getInternalName(),
122 getGenericSignature(),
123 superClass.getInternalName(),
124 superInterfaces
125 );
126 cv.visitSource(fun.getContainingFile().getName(), null);
127
128 writeKotlinSyntheticClassAnnotation(cv, syntheticClassKind);
129
130 JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(funDescriptor).replaceName(interfaceFunction.getName().toString());
131 generateBridge(cv, typeMapper.mapSignature(interfaceFunction).getAsmMethod(), jvmMethodSignature.getAsmMethod());
132
133 FunctionCodegen fc = new FunctionCodegen(context, cv, state, getParentCodegen());
134 fc.generateMethod(fun, jvmMethodSignature, funDescriptor, strategy);
135
136 this.constructor = generateConstructor(cv);
137
138 if (isConst(closure)) {
139 generateConstInstance(cv);
140 }
141
142 genClosureFields(closure, cv, typeMapper);
143
144 fc.generateDefaultIfNeeded(context.intoFunction(funDescriptor),
145 typeMapper.mapSignature(funDescriptor),
146 funDescriptor,
147 context.getContextKind(),
148 DefaultParameterValueLoader.DEFAULT);
149
150 cv.done();
151 }
152
153 @NotNull
154 public StackValue putInstanceOnStack(@NotNull InstructionAdapter v, @NotNull ExpressionCodegen codegen) {
155 if (isConst(closure)) {
156 v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
157 }
158 else {
159 v.anew(asmType);
160 v.dup();
161
162 codegen.pushClosureOnStack(closure, false, codegen.defaulCallGenerator);
163 v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor());
164 }
165 return StackValue.onStack(asmType);
166 }
167
168
169 private void generateConstInstance(@NotNull ClassBuilder cv) {
170 MethodVisitor mv = cv.newMethod(fun, ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY);
171 InstructionAdapter iv = new InstructionAdapter(mv);
172
173 cv.newField(fun, ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
174
175 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
176 mv.visitCode();
177 iv.anew(asmType);
178 iv.dup();
179 iv.invokespecial(asmType.getInternalName(), "<init>", "()V");
180 iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
181 mv.visitInsn(RETURN);
182 FunctionCodegen.endVisit(mv, "<clinit>", fun);
183 }
184 }
185
186 private void generateBridge(@NotNull ClassBuilder cv, @NotNull Method bridge, @NotNull Method delegate) {
187 if (bridge.equals(delegate)) return;
188
189 MethodVisitor mv =
190 cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
191
192 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
193
194 mv.visitCode();
195
196 InstructionAdapter iv = new InstructionAdapter(mv);
197 iv.load(0, asmType);
198
199 ReceiverParameterDescriptor receiver = funDescriptor.getReceiverParameter();
200 int count = 1;
201 if (receiver != null) {
202 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv);
203 count++;
204 }
205
206 List<ValueParameterDescriptor> params = funDescriptor.getValueParameters();
207 for (ValueParameterDescriptor param : params) {
208 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv);
209 count++;
210 }
211
212 iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor());
213 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv);
214
215 iv.areturn(bridge.getReturnType());
216
217 FunctionCodegen.endVisit(mv, "bridge", fun);
218 }
219
220 @NotNull
221 private Method generateConstructor(@NotNull ClassBuilder cv) {
222 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);
223
224 return generateConstructor(cv, args, fun, superClass, state, visibilityFlag);
225 }
226
227 public static Method generateConstructor(
228 @NotNull ClassBuilder cv,
229 @NotNull List<FieldInfo> args,
230 @Nullable PsiElement fun,
231 @NotNull Type superClass,
232 @NotNull GenerationState state,
233 int flags
234 ) {
235 Type[] argTypes = fieldListToTypeArray(args);
236
237 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
238 MethodVisitor mv = cv.newMethod(fun, flags, "<init>", constructor.getDescriptor(), null,
239 ArrayUtil.EMPTY_STRING_ARRAY);
240 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
241 mv.visitCode();
242 InstructionAdapter iv = new InstructionAdapter(mv);
243
244 iv.load(0, superClass);
245 iv.invokespecial(superClass.getInternalName(), "<init>", "()V");
246
247 int k = 1;
248 for (FieldInfo fieldInfo : args) {
249 k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv);
250 }
251
252 iv.visitInsn(RETURN);
253
254 FunctionCodegen.endVisit(iv, "constructor", fun);
255 }
256 return constructor;
257 }
258
259 @NotNull
260 public static List<FieldInfo> calculateConstructorParameters(
261 @NotNull JetTypeMapper typeMapper,
262 @NotNull CalculatedClosure closure,
263 @NotNull Type ownerType
264 ) {
265 BindingContext bindingContext = typeMapper.getBindingContext();
266 List<FieldInfo> args = Lists.newArrayList();
267 ClassDescriptor captureThis = closure.getCaptureThis();
268 if (captureThis != null) {
269 Type type = typeMapper.mapType(captureThis);
270 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
271 }
272 JetType captureReceiverType = closure.getCaptureReceiverType();
273 if (captureReceiverType != null) {
274 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
275 }
276
277 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
278 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
279 Type sharedVarType = typeMapper.getSharedVarType(descriptor);
280
281 Type type = sharedVarType != null
282 ? sharedVarType
283 : typeMapper.mapType((VariableDescriptor) descriptor);
284 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
285 }
286 else if (isLocalNamedFun(descriptor)) {
287 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
288 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
289 }
290 else if (descriptor instanceof FunctionDescriptor) {
291 assert captureReceiverType != null;
292 }
293 }
294 return args;
295 }
296
297 private static Type[] fieldListToTypeArray(List<FieldInfo> args) {
298 Type[] argTypes = new Type[args.size()];
299 for (int i = 0; i != argTypes.length; ++i) {
300 argTypes[i] = args.get(i).getFieldType();
301 }
302 return argTypes;
303 }
304
305 @NotNull
306 private String getGenericSignature() {
307 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor);
308 Collection<JetType> supertypes = classDescriptor.getTypeConstructor().getSupertypes();
309 assert supertypes.size() == 1 : "Closure must have exactly one supertype: " + funDescriptor;
310 JetType supertype = supertypes.iterator().next();
311
312 BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS);
313 sw.writeSuperclass();
314 typeMapper.mapSupertype(supertype, sw);
315 sw.writeSuperclassEnd();
316
317 String signature = sw.makeJavaGenericSignature();
318 assert signature != null : "Closure superclass must have a generic signature: " + funDescriptor;
319 return signature;
320 }
321
322 public static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) {
323 int paramCount = funDescriptor.getValueParameters().size();
324 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
325 ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null
326 ? builtIns.getFunction(paramCount)
327 : builtIns.getExtensionFunction(paramCount);
328 return funClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next();
329 }
330 }