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