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 com.google.common.collect.Lists;
020 import com.intellij.util.ArrayUtil;
021 import kotlin.Unit;
022 import kotlin.jvm.functions.Function1;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
026 import org.jetbrains.kotlin.codegen.context.ClosureContext;
027 import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
028 import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
029 import org.jetbrains.kotlin.codegen.state.GenerationState;
030 import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
031 import org.jetbrains.kotlin.descriptors.*;
032 import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
033 import org.jetbrains.kotlin.load.java.JvmAbi;
034 import org.jetbrains.kotlin.psi.JetElement;
035 import org.jetbrains.kotlin.resolve.BindingContext;
036 import org.jetbrains.kotlin.resolve.DescriptorUtils;
037 import org.jetbrains.kotlin.types.JetType;
038 import org.jetbrains.kotlin.types.expressions.OperatorConventions;
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.kotlin.codegen.AsmUtil.*;
049 import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
050 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
051 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
052 import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
053 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
054 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
055 import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
056 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
057
058 public class ClosureCodegen extends MemberCodegen<JetElement> {
059 private final FunctionDescriptor funDescriptor;
060 private final ClassDescriptor classDescriptor;
061 private final SamType samType;
062 private final JetType superClassType;
063 private final List<JetType> superInterfaceTypes;
064 private final FunctionGenerationStrategy strategy;
065 private final CalculatedClosure closure;
066 private final Type asmType;
067 private final int visibilityFlag;
068 private final KotlinSyntheticClass.Kind syntheticClassKind;
069
070 private Method constructor;
071 private Type superClassAsmType;
072
073 public ClosureCodegen(
074 @NotNull GenerationState state,
075 @NotNull JetElement element,
076 @Nullable SamType samType,
077 @NotNull ClosureContext context,
078 @NotNull KotlinSyntheticClass.Kind syntheticClassKind,
079 @NotNull FunctionGenerationStrategy strategy,
080 @NotNull MemberCodegen<?> parentCodegen,
081 @NotNull ClassBuilder classBuilder
082 ) {
083 super(state, parentCodegen, context, element, classBuilder);
084
085 this.funDescriptor = context.getFunctionDescriptor();
086 this.classDescriptor = context.getContextDescriptor();
087 this.samType = samType;
088 this.syntheticClassKind = syntheticClassKind;
089 this.strategy = strategy;
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 = getBuiltIns(funDescriptor).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 = typeMapper.mapClass(classDescriptor);
118
119 visibilityFlag = AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor);
120 }
121
122 @Override
123 protected void generateDeclaration() {
124 BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS);
125 if (samType != null) {
126 typeMapper.writeFormalTypeParameters(samType.getType().getConstructor().getParameters(), sw);
127 }
128 sw.writeSuperclass();
129 superClassAsmType = typeMapper.mapSupertype(superClassType, sw);
130 sw.writeSuperclassEnd();
131 String[] superInterfaceAsmTypes = new String[superInterfaceTypes.size()];
132 for (int i = 0; i < superInterfaceTypes.size(); i++) {
133 JetType superInterfaceType = superInterfaceTypes.get(i);
134 sw.writeInterface();
135 superInterfaceAsmTypes[i] = typeMapper.mapSupertype(superInterfaceType, sw).getInternalName();
136 sw.writeInterfaceEnd();
137 }
138
139 v.defineClass(element,
140 V1_6,
141 ACC_FINAL | ACC_SUPER | visibilityFlag,
142 asmType.getInternalName(),
143 sw.makeJavaGenericSignature(),
144 superClassAsmType.getInternalName(),
145 superInterfaceAsmTypes
146 );
147
148 InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
149
150 v.visitSource(element.getContainingFile().getName(), null);
151 }
152
153 @Nullable
154 @Override
155 protected ClassDescriptor classForInnerClassRecord() {
156 return JvmCodegenUtil.isArgumentWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor;
157 }
158
159 @Override
160 protected void generateBody() {
161 FunctionDescriptor erasedInterfaceFunction;
162 if (samType == null) {
163 erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
164 }
165 else {
166 erasedInterfaceFunction = samType.getAbstractMethod().getOriginal();
167 }
168
169 generateBridge(
170 typeMapper.mapSignature(erasedInterfaceFunction).getAsmMethod(),
171 typeMapper.mapSignature(funDescriptor).getAsmMethod()
172 );
173
174 functionCodegen.generateMethod(OtherOrigin(element, funDescriptor), funDescriptor, strategy);
175
176 //TODO: rewrite cause ugly hack
177 if (samType != null) {
178 SimpleFunctionDescriptorImpl descriptorForBridges = SimpleFunctionDescriptorImpl
179 .create(funDescriptor.getContainingDeclaration(), funDescriptor.getAnnotations(),
180 erasedInterfaceFunction.getName(),
181 CallableMemberDescriptor.Kind.DECLARATION, funDescriptor.getSource());
182
183 descriptorForBridges
184 .initialize(null, erasedInterfaceFunction.getDispatchReceiverParameter(), erasedInterfaceFunction.getTypeParameters(),
185 erasedInterfaceFunction.getValueParameters(), erasedInterfaceFunction.getReturnType(), Modality.OPEN,
186 erasedInterfaceFunction.getVisibility());
187
188 descriptorForBridges.addOverriddenDescriptor(erasedInterfaceFunction);
189 functionCodegen.generateBridges(descriptorForBridges);
190 }
191
192 this.constructor = generateConstructor(superClassAsmType);
193
194 if (isConst(closure)) {
195 generateConstInstance();
196 }
197
198 genClosureFields(closure, v, typeMapper);
199
200 functionCodegen.generateDefaultIfNeeded(
201 context.intoFunction(funDescriptor), funDescriptor, context.getContextKind(), DefaultParameterValueLoader.DEFAULT, null
202 );
203 }
204
205 @Override
206 protected void generateKotlinAnnotation() {
207 writeKotlinSyntheticClassAnnotation(v, syntheticClassKind);
208 }
209
210 @Override
211 protected void done() {
212 writeOuterClassAndEnclosingMethod();
213 super.done();
214 }
215
216 @NotNull
217 public StackValue putInstanceOnStack(
218 @NotNull final ExpressionCodegen codegen,
219 @Nullable final FunctionDescriptor functionReferenceTarget
220 ) {
221 return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
222 @Override
223 public Unit invoke(InstructionAdapter v) {
224 if (isConst(closure)) {
225 v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
226 }
227 else {
228 v.anew(asmType);
229 v.dup();
230
231 codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator);
232 v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false);
233 }
234
235 if (functionReferenceTarget != null) {
236 equipFunctionReferenceWithReflection(v, functionReferenceTarget);
237 }
238
239 return Unit.INSTANCE$;
240 }
241 });
242 }
243
244 private static void equipFunctionReferenceWithReflection(@NotNull InstructionAdapter v, @NotNull FunctionDescriptor target) {
245 DeclarationDescriptor container = target.getContainingDeclaration();
246
247 Type type;
248 if (container instanceof PackageFragmentDescriptor) {
249 type = target.getExtensionReceiverParameter() != null
250 ? K_TOP_LEVEL_EXTENSION_FUNCTION
251 : K_TOP_LEVEL_FUNCTION;
252 }
253 else if (container instanceof ClassDescriptor) {
254 type = K_MEMBER_FUNCTION;
255 }
256 else {
257 type = K_LOCAL_FUNCTION;
258 }
259
260 Method method = method("function", K_FUNCTION, FUNCTION_REFERENCE);
261 v.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false);
262 StackValue.coerce(K_FUNCTION, type, v);
263 }
264
265
266 private void generateConstInstance() {
267 MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY);
268 InstructionAdapter iv = new InstructionAdapter(mv);
269
270 v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
271
272 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
273 mv.visitCode();
274 iv.anew(asmType);
275 iv.dup();
276 iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
277 iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
278 mv.visitInsn(RETURN);
279 FunctionCodegen.endVisit(mv, "<clinit>", element);
280 }
281 }
282
283 private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
284 if (bridge.equals(delegate)) return;
285
286 MethodVisitor mv =
287 v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
288
289 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
290
291 mv.visitCode();
292
293 InstructionAdapter iv = new InstructionAdapter(mv);
294 ImplementationBodyCodegen.markLineNumberForSyntheticFunction(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);
295
296 iv.load(0, asmType);
297
298 ReceiverParameterDescriptor receiver = funDescriptor.getExtensionReceiverParameter();
299 int count = 1;
300 if (receiver != null) {
301 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv);
302 count++;
303 }
304
305 List<ValueParameterDescriptor> params = funDescriptor.getValueParameters();
306 for (ValueParameterDescriptor param : params) {
307 StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv);
308 count++;
309 }
310
311 iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false);
312 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv);
313
314 iv.areturn(bridge.getReturnType());
315
316 FunctionCodegen.endVisit(mv, "bridge", element);
317 }
318
319 @NotNull
320 private Method generateConstructor(@NotNull Type superClassAsmType) {
321 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);
322
323 Type[] argTypes = fieldListToTypeArray(args);
324
325 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
326 MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null,
327 ArrayUtil.EMPTY_STRING_ARRAY);
328 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
329 mv.visitCode();
330 InstructionAdapter iv = new InstructionAdapter(mv);
331
332 int k = 1;
333 for (FieldInfo fieldInfo : args) {
334 k = genAssignInstanceFieldFromParam(fieldInfo, k, iv);
335 }
336
337 iv.load(0, superClassAsmType);
338
339 if (superClassAsmType.equals(LAMBDA)) {
340 int arity = funDescriptor.getValueParameters().size();
341 if (funDescriptor.getExtensionReceiverParameter() != null) arity++;
342 if (funDescriptor.getDispatchReceiverParameter() != null) arity++;
343 iv.iconst(arity);
344 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false);
345 }
346 else {
347 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
348 }
349
350 iv.visitInsn(RETURN);
351
352 FunctionCodegen.endVisit(iv, "constructor", element);
353 }
354 return constructor;
355 }
356
357 @NotNull
358 public static List<FieldInfo> calculateConstructorParameters(
359 @NotNull JetTypeMapper typeMapper,
360 @NotNull CalculatedClosure closure,
361 @NotNull Type ownerType
362 ) {
363 BindingContext bindingContext = typeMapper.getBindingContext();
364 List<FieldInfo> args = Lists.newArrayList();
365 ClassDescriptor captureThis = closure.getCaptureThis();
366 if (captureThis != null) {
367 Type type = typeMapper.mapType(captureThis);
368 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
369 }
370 JetType captureReceiverType = closure.getCaptureReceiverType();
371 if (captureReceiverType != null) {
372 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
373 }
374
375 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
376 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
377 Type sharedVarType = typeMapper.getSharedVarType(descriptor);
378
379 Type type = sharedVarType != null
380 ? sharedVarType
381 : typeMapper.mapType((VariableDescriptor) descriptor);
382 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
383 }
384 else if (DescriptorUtils.isLocalFunction(descriptor)) {
385 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
386 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
387 }
388 else if (descriptor instanceof FunctionDescriptor) {
389 assert captureReceiverType != null;
390 }
391 }
392 return args;
393 }
394
395 private static Type[] fieldListToTypeArray(List<FieldInfo> args) {
396 Type[] argTypes = new Type[args.size()];
397 for (int i = 0; i != argTypes.length; ++i) {
398 argTypes[i] = args.get(i).getFieldType();
399 }
400 return argTypes;
401 }
402
403 @NotNull
404 public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor elementDescriptor) {
405 int arity = elementDescriptor.getValueParameters().size();
406 ClassDescriptor elementClass = elementDescriptor.getExtensionReceiverParameter() == null
407 ? getBuiltIns(elementDescriptor).getFunction(arity)
408 : getBuiltIns(elementDescriptor).getExtensionFunction(arity);
409 return elementClass.getDefaultType().getMemberScope().getFunctions(OperatorConventions.INVOKE).iterator().next();
410 }
411 }