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