001 /*
002 * Copyright 2010-2016 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.intellij.openapi.progress.ProcessCanceledException;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.util.ArrayUtil;
022 import com.intellij.util.Function;
023 import com.intellij.util.containers.ContainerUtil;
024 import kotlin.collections.CollectionsKt;
025 import kotlin.jvm.functions.Function1;
026 import kotlin.text.StringsKt;
027 import org.jetbrains.annotations.NotNull;
028 import org.jetbrains.annotations.Nullable;
029 import org.jetbrains.kotlin.backend.common.bridges.Bridge;
030 import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
031 import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
032 import org.jetbrains.kotlin.codegen.context.*;
033 import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor;
034 import org.jetbrains.kotlin.codegen.state.GenerationState;
035 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
036 import org.jetbrains.kotlin.descriptors.*;
037 import org.jetbrains.kotlin.descriptors.annotations.Annotated;
038 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
039 import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
040 import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
041 import org.jetbrains.kotlin.load.java.JvmAbi;
042 import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers;
043 import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
044 import org.jetbrains.kotlin.name.FqName;
045 import org.jetbrains.kotlin.psi.KtElement;
046 import org.jetbrains.kotlin.psi.KtFunction;
047 import org.jetbrains.kotlin.psi.KtNamedFunction;
048 import org.jetbrains.kotlin.resolve.BindingContext;
049 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
050 import org.jetbrains.kotlin.resolve.DescriptorUtils;
051 import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
052 import org.jetbrains.kotlin.resolve.constants.ArrayValue;
053 import org.jetbrains.kotlin.resolve.constants.ConstantValue;
054 import org.jetbrains.kotlin.resolve.constants.KClassValue;
055 import org.jetbrains.kotlin.resolve.inline.InlineUtil;
056 import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
057 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
058 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind;
059 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
060 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
061 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
062 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
063 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
064 import org.jetbrains.kotlin.types.KotlinType;
065 import org.jetbrains.kotlin.types.TypeUtils;
066 import org.jetbrains.org.objectweb.asm.*;
067 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
068 import org.jetbrains.org.objectweb.asm.commons.Method;
069 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
070
071 import java.io.PrintWriter;
072 import java.io.StringWriter;
073 import java.util.Collection;
074 import java.util.Iterator;
075 import java.util.List;
076 import java.util.Set;
077
078 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
079 import static org.jetbrains.kotlin.codegen.AsmUtil.*;
080 import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
081 import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
082 import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
083 import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
084 import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
085 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
086 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
087 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
088
089 public class FunctionCodegen {
090 public final GenerationState state;
091 private final KotlinTypeMapper typeMapper;
092 private final BindingContext bindingContext;
093 private final CodegenContext owner;
094 private final ClassBuilder v;
095 private final MemberCodegen<?> memberCodegen;
096
097 public FunctionCodegen(
098 @NotNull CodegenContext owner,
099 @NotNull ClassBuilder v,
100 @NotNull GenerationState state,
101 @NotNull MemberCodegen<?> memberCodegen
102 ) {
103 this.owner = owner;
104 this.v = v;
105 this.state = state;
106 this.typeMapper = state.getTypeMapper();
107 this.bindingContext = state.getBindingContext();
108 this.memberCodegen = memberCodegen;
109 }
110
111 public void gen(@NotNull KtNamedFunction function) {
112 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
113 if (functionDescriptor == null) {
114 throw ExceptionLogger.logDescriptorNotFound("No descriptor for function " + function.getName(), function);
115 }
116
117 if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
118 generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor,
119 new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
120 }
121
122 generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(),
123 DefaultParameterValueLoader.DEFAULT, function);
124
125 generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor);
126 }
127
128 public void generateOverloadsWithDefaultValues(
129 @Nullable KtNamedFunction function,
130 @NotNull FunctionDescriptor functionDescriptor,
131 @NotNull FunctionDescriptor delegateFunctionDescriptor
132 ) {
133 new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded(
134 function, functionDescriptor, delegateFunctionDescriptor, owner.getContextKind(), v
135 );
136 }
137
138 public void generateMethod(
139 @NotNull JvmDeclarationOrigin origin,
140 @NotNull FunctionDescriptor descriptor,
141 @NotNull FunctionGenerationStrategy strategy
142 ) {
143 generateMethod(origin, descriptor, owner.intoFunction(descriptor), strategy);
144 }
145
146 public void generateMethod(
147 @NotNull JvmDeclarationOrigin origin,
148 @NotNull FunctionDescriptor functionDescriptor,
149 @NotNull MethodContext methodContext,
150 @NotNull FunctionGenerationStrategy strategy
151 ) {
152 OwnerKind contextKind = methodContext.getContextKind();
153 if (isInterface(functionDescriptor.getContainingDeclaration()) &&
154 functionDescriptor.getVisibility() == Visibilities.PRIVATE &&
155 contextKind != OwnerKind.DEFAULT_IMPLS) {
156 return;
157 }
158
159 JvmMethodGenericSignature jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, contextKind);
160 Method asmMethod = jvmSignature.getAsmMethod();
161
162 int flags = getMethodAsmFlags(functionDescriptor, contextKind);
163
164 if (origin.getOriginKind() == JvmDeclarationOriginKind.SAM_DELEGATION) {
165 flags |= ACC_SYNTHETIC;
166 }
167
168 if (functionDescriptor.isExternal() && owner instanceof MultifileClassFacadeContext) {
169 // Native methods are only defined in facades and do not need package part implementations
170 return;
171 }
172 MethodVisitor mv = v.newMethod(origin,
173 flags,
174 asmMethod.getName(),
175 asmMethod.getDescriptor(),
176 jvmSignature.getGenericsSignature(),
177 getThrownExceptions(functionDescriptor, typeMapper));
178
179 if (CodegenContextUtil.isImplClassOwner(owner)) {
180 v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
181 }
182
183 generateMethodAnnotations(functionDescriptor, asmMethod, mv);
184
185 generateParameterAnnotations(functionDescriptor, mv, typeMapper.mapSignatureSkipGeneric(functionDescriptor));
186
187 generateBridges(functionDescriptor);
188
189 boolean staticInCompanionObject = CodegenUtilKt.isJvmStaticInCompanionObject(functionDescriptor);
190 if (staticInCompanionObject) {
191 ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
192 parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen));
193 }
194
195 if (!state.getClassBuilderMode().generateBodies || isAbstractMethod(functionDescriptor, contextKind)) {
196 generateLocalVariableTable(
197 mv,
198 jvmSignature,
199 functionDescriptor,
200 getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
201 new Label(),
202 new Label(),
203 contextKind
204 );
205
206 mv.visitEnd();
207 return;
208 }
209
210 if (!functionDescriptor.isExternal()) {
211 generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen);
212 }
213 else if (staticInCompanionObject) {
214 // native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
215 mv.visitCode();
216 FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
217 Method accessorMethod =
218 typeMapper.mapAsmMethod(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
219 Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
220 generateDelegateToMethodBody(false, mv, accessorMethod, owningType.getInternalName());
221 }
222
223 endVisit(mv, null, origin.getElement());
224 }
225
226 private void generateMethodAnnotations(
227 @NotNull FunctionDescriptor functionDescriptor,
228 Method asmMethod,
229 MethodVisitor mv
230 ) {
231 AnnotationCodegen annotationCodegen = AnnotationCodegen.forMethod(mv, typeMapper);
232
233 if (functionDescriptor instanceof PropertyAccessorDescriptor) {
234 AnnotationUseSiteTarget target = functionDescriptor instanceof PropertySetterDescriptor ? PROPERTY_SETTER : PROPERTY_GETTER;
235 annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType(), target);
236 }
237 else {
238 annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType());
239 }
240 }
241
242 private void generateParameterAnnotations(
243 @NotNull FunctionDescriptor functionDescriptor,
244 @NotNull MethodVisitor mv,
245 @NotNull JvmMethodSignature jvmSignature
246 ) {
247 Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator();
248 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
249
250 for (int i = 0; i < kotlinParameterTypes.size(); i++) {
251 JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i);
252 JvmMethodParameterKind kind = parameterSignature.getKind();
253 if (kind.isSkippedInGenericSignature()) {
254 markEnumOrInnerConstructorParameterAsSynthetic(mv, i);
255 continue;
256 }
257
258 if (kind == JvmMethodParameterKind.VALUE) {
259 ValueParameterDescriptor parameter = iterator.next();
260 AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper);
261
262 if (functionDescriptor instanceof PropertySetterDescriptor) {
263 PropertyDescriptor propertyDescriptor = ((PropertySetterDescriptor) functionDescriptor).getCorrespondingProperty();
264 Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(propertyDescriptor);
265 annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), SETTER_PARAMETER);
266 }
267
268 if (functionDescriptor instanceof ConstructorDescriptor) {
269 annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType(), CONSTRUCTOR_PARAMETER);
270 }
271 else {
272 annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType());
273 }
274 }
275 else if (kind == JvmMethodParameterKind.RECEIVER) {
276 ReceiverParameterDescriptor receiver = JvmCodegenUtil.getDirectMember(functionDescriptor).getExtensionReceiverParameter();
277
278 if (receiver != null) {
279 AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper);
280 Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(receiver.getType());
281 annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), RECEIVER);
282
283 annotationCodegen.genAnnotations(receiver, parameterSignature.getAsmType());
284 }
285 }
286 }
287 }
288
289 private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) {
290 // IDEA's ClsPsi builder fails to annotate synthetic parameters
291 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
292
293 // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac:
294 // see MethodWriter.visitParameterAnnotation()
295
296 AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true);
297 if (av != null) {
298 av.visitEnd();
299 }
300 }
301
302 @Nullable
303 private static Type getThisTypeForFunction(
304 @NotNull FunctionDescriptor functionDescriptor,
305 @NotNull MethodContext context,
306 @NotNull KotlinTypeMapper typeMapper
307 ) {
308 ReceiverParameterDescriptor dispatchReceiver = functionDescriptor.getDispatchReceiverParameter();
309 if (functionDescriptor instanceof ConstructorDescriptor) {
310 return typeMapper.mapType(functionDescriptor);
311 }
312 else if (dispatchReceiver != null) {
313 return typeMapper.mapType(dispatchReceiver.getType());
314 }
315 else if (isFunctionLiteral(functionDescriptor) ||
316 isLocalFunction(functionDescriptor) ||
317 isFunctionExpression(functionDescriptor)) {
318 return typeMapper.mapType(context.getThisDescriptor());
319 }
320 else {
321 return null;
322 }
323 }
324
325 public static void generateMethodBody(
326 @NotNull MethodVisitor mv,
327 @NotNull FunctionDescriptor functionDescriptor,
328 @NotNull MethodContext context,
329 @NotNull JvmMethodSignature signature,
330 @NotNull FunctionGenerationStrategy strategy,
331 @NotNull MemberCodegen<?> parentCodegen
332 ) {
333 mv.visitCode();
334
335 Label methodBegin = new Label();
336 mv.visitLabel(methodBegin);
337
338 KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
339 if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, getSignatureMapper(typeMapper))) {
340 generateTypeCheckBarrierIfNeeded(
341 new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterType = */null);
342 }
343
344 Label methodEnd;
345
346 int functionFakeIndex = -1;
347 int lambdaFakeIndex = -1;
348
349 if (context.getParentContext() instanceof MultifileClassFacadeContext) {
350 generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext());
351 methodEnd = new Label();
352 }
353 else {
354 FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(),
355 functionDescriptor));
356 if (context.isInlineMethodContext()) {
357 functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
358 }
359
360 if (context instanceof InlineLambdaContext) {
361 lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
362 }
363
364 Label methodEntry = new Label();
365 mv.visitLabel(methodEntry);
366 context.setMethodStartLabel(methodEntry);
367
368 if (!KotlinTypeMapper.isAccessor(functionDescriptor)) {
369 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap);
370 }
371
372 parentCodegen.beforeMethodBody(mv);
373
374 methodEnd = new Label();
375 context.setMethodEndLabel(methodEnd);
376 strategy.generateBody(mv, frameMap, signature, context, parentCodegen);
377 }
378
379 mv.visitLabel(methodEnd);
380
381 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
382 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
383
384 if (context.isInlineMethodContext() && functionFakeIndex != -1) {
385 mv.visitLocalVariable(
386 JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + functionDescriptor.getName().asString(),
387 Type.INT_TYPE.getDescriptor(), null,
388 methodBegin, methodEnd,
389 functionFakeIndex);
390 }
391
392 if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) {
393 String name = thisType.getClassName();
394 int indexOfLambdaOrdinal = name.lastIndexOf("$");
395 if (indexOfLambdaOrdinal > 0) {
396 int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1));
397
398 KtElement functionArgument = parentCodegen.element;
399 String functionName = "unknown";
400 if (functionArgument instanceof KtFunction) {
401 ValueParameterDescriptor inlineArgumentDescriptor =
402 InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext);
403 if (inlineArgumentDescriptor != null) {
404 functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString();
405 }
406 }
407 mv.visitLocalVariable(
408 JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal + "$" + functionName,
409 Type.INT_TYPE.getDescriptor(), null,
410 methodBegin, methodEnd,
411 lambdaFakeIndex);
412 }
413 }
414 }
415
416 private static void generateLocalVariableTable(
417 @NotNull MethodVisitor mv,
418 @NotNull JvmMethodSignature jvmMethodSignature,
419 @NotNull FunctionDescriptor functionDescriptor,
420 @Nullable Type thisType,
421 @NotNull Label methodBegin,
422 @NotNull Label methodEnd,
423 @NotNull OwnerKind ownerKind
424 ) {
425 generateLocalVariablesForParameters(mv, jvmMethodSignature, thisType, methodBegin, methodEnd,
426 functionDescriptor.getValueParameters(),
427 AsmUtil.isStaticMethod(ownerKind, functionDescriptor));
428 }
429
430 public static void generateLocalVariablesForParameters(
431 @NotNull MethodVisitor mv,
432 @NotNull JvmMethodSignature jvmMethodSignature,
433 @Nullable Type thisType,
434 @NotNull Label methodBegin,
435 @NotNull Label methodEnd,
436 Collection<ValueParameterDescriptor> valueParameters,
437 boolean isStatic
438 ) {
439 Iterator<ValueParameterDescriptor> valueParameterIterator = valueParameters.iterator();
440 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
441 int shift = 0;
442
443 if (!isStatic) {
444 //add this
445 if (thisType != null) {
446 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
447 }
448 else {
449 //TODO: provide thisType for callable reference
450 }
451 shift++;
452 }
453
454 for (int i = 0; i < params.size(); i++) {
455 JvmMethodParameterSignature param = params.get(i);
456 JvmMethodParameterKind kind = param.getKind();
457 String parameterName;
458
459 if (kind == JvmMethodParameterKind.VALUE) {
460 ValueParameterDescriptor parameter = valueParameterIterator.next();
461 parameterName = parameter.getName().asString();
462 }
463 else {
464 String lowercaseKind = kind.name().toLowerCase();
465 parameterName = needIndexForVar(kind)
466 ? "$" + lowercaseKind + "$" + i
467 : "$" + lowercaseKind;
468 }
469
470 Type type = param.getAsmType();
471 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
472 shift += type.getSize();
473 }
474 }
475
476 private static void generateFacadeDelegateMethodBody(
477 @NotNull MethodVisitor mv,
478 @NotNull Method asmMethod,
479 @NotNull MultifileClassFacadeContext context
480 ) {
481 generateDelegateToMethodBody(true, mv, asmMethod, context.getFilePartType().getInternalName());
482 }
483
484 private static void generateDelegateToMethodBody(
485 boolean isStatic,
486 @NotNull MethodVisitor mv,
487 @NotNull Method asmMethod,
488 @NotNull String classToDelegateTo
489 ) {
490 InstructionAdapter iv = new InstructionAdapter(mv);
491 Type[] argTypes = asmMethod.getArgumentTypes();
492
493 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it
494 // This is similar to what javac does with bridge methods
495 Label label = new Label();
496 iv.visitLabel(label);
497 iv.visitLineNumber(1, label);
498
499 int k = isStatic ? 0 : 1;
500 for (Type argType : argTypes) {
501 iv.load(k, argType);
502 k += argType.getSize();
503 }
504 iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false);
505 iv.areturn(asmMethod.getReturnType());
506 }
507
508 private static boolean needIndexForVar(JvmMethodParameterKind kind) {
509 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE ||
510 kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL ||
511 kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
512 }
513
514 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
515 try {
516 mv.visitMaxs(-1, -1);
517 mv.visitEnd();
518 }
519 catch (ProcessCanceledException e) {
520 throw e;
521 }
522 catch (Throwable t) {
523 String bytecode = renderByteCodeIfAvailable(mv);
524 throw new CompilationException(
525 "wrong code generated\n" +
526 (description != null ? " for " + description : "") +
527 t.getClass().getName() +
528 " " +
529 t.getMessage() +
530 (bytecode != null ? "\nbytecode:\n" + bytecode : ""),
531 t, method);
532 }
533 }
534
535 private static String renderByteCodeIfAvailable(MethodVisitor mv) {
536 String bytecode = null;
537
538 if (mv instanceof OptimizationMethodVisitor) {
539 mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible();
540 }
541
542 if (mv instanceof TraceMethodVisitor) {
543 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv;
544 StringWriter sw = new StringWriter();
545 PrintWriter pw = new PrintWriter(sw);
546 traceMethodVisitor.p.print(pw);
547 pw.close();
548 bytecode = sw.toString();
549 }
550 return bytecode;
551 }
552
553 public void generateBridges(@NotNull FunctionDescriptor descriptor) {
554 if (descriptor instanceof ConstructorDescriptor) return;
555 if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
556 if (isInterface(descriptor.getContainingDeclaration())) return;
557
558 // equals(Any?), hashCode(), toString() never need bridges
559 if (isMethodOfAny(descriptor)) return;
560
561 boolean isSpecial = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) != null;
562
563 Set<Bridge<Method>> bridgesToGenerate;
564 if (!isSpecial) {
565 bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor(
566 descriptor,
567 getSignatureMapper(typeMapper)
568 );
569 if (!bridgesToGenerate.isEmpty()) {
570 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
571 boolean isSpecialBridge =
572 BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null;
573
574 for (Bridge<Method> bridge : bridgesToGenerate) {
575 generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false);
576 }
577 }
578 }
579 else {
580 Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
581 descriptor,
582 getSignatureMapper(typeMapper)
583 );
584
585 if (!specials.isEmpty()) {
586 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
587 for (BridgeForBuiltinSpecial<Method> bridge : specials) {
588 generateBridge(
589 origin, descriptor, bridge.getFrom(), bridge.getTo(),
590 bridge.isSpecial(), bridge.isDelegateToSuper());
591 }
592 }
593
594 if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
595 CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor);
596 assert overridden != null;
597
598 if (!isThereOverriddenInKotlinClass(descriptor)) {
599 Method method = typeMapper.mapAsmMethod(descriptor);
600 int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor);
601 v.newMethod(JvmDeclarationOriginKt.OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null);
602 }
603 }
604 }
605 }
606
607 private static boolean isThereOverriddenInKotlinClass(@NotNull CallableMemberDescriptor descriptor) {
608 return CollectionsKt.any(getAllOverriddenDescriptors(descriptor), new Function1<CallableMemberDescriptor, Boolean>() {
609 @Override
610 public Boolean invoke(CallableMemberDescriptor descriptor) {
611 return !(descriptor.getContainingDeclaration() instanceof JavaClassDescriptor) &&
612 isClass(descriptor.getContainingDeclaration());
613 }
614 });
615 }
616
617 @NotNull
618 private static Function1<FunctionDescriptor, Method> getSignatureMapper(final @NotNull KotlinTypeMapper typeMapper) {
619 return new Function1<FunctionDescriptor, Method>() {
620 @Override
621 public Method invoke(FunctionDescriptor descriptor) {
622 return typeMapper.mapAsmMethod(descriptor);
623 }
624 };
625 }
626
627 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
628 String name = descriptor.getName().asString();
629 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
630 if (parameters.isEmpty()) {
631 return name.equals("hashCode") || name.equals("toString");
632 }
633 else if (parameters.size() == 1 && name.equals("equals")) {
634 return isNullableAny(parameters.get(0).getType());
635 }
636 return false;
637 }
638
639 @NotNull
640 public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final KotlinTypeMapper mapper) {
641 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
642 if (annotation == null) {
643 annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws"));
644 }
645
646 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
647
648 Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
649 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
650
651 Object value = values.iterator().next();
652 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
653 ArrayValue arrayValue = (ArrayValue) value;
654
655 List<String> strings = ContainerUtil.mapNotNull(
656 arrayValue.getValue(),
657 new Function<ConstantValue<?>, String>() {
658 @Override
659 public String fun(ConstantValue<?> constant) {
660 if (constant instanceof KClassValue) {
661 KClassValue classValue = (KClassValue) constant;
662 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
663 return mapper.mapClass(classDescriptor).getInternalName();
664 }
665 return null;
666 }
667 }
668 );
669 return ArrayUtil.toStringArray(strings);
670 }
671
672 void generateDefaultIfNeeded(
673 @NotNull MethodContext owner,
674 @NotNull FunctionDescriptor functionDescriptor,
675 @NotNull OwnerKind kind,
676 @NotNull DefaultParameterValueLoader loadStrategy,
677 @Nullable KtNamedFunction function
678 ) {
679 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
680
681 if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) {
682 return;
683 }
684
685 if (!isDefaultNeeded(functionDescriptor)) {
686 return;
687 }
688
689 // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors
690 // $default methods are never protected to be accessible from subclass nested classes
691 int visibilityFlag = Visibilities.isPrivate(functionDescriptor.getVisibility()) ||
692 AnnotationUtilKt.isInlineOnlyOrReified(functionDescriptor) ?
693 AsmUtil.NO_FLAG_PACKAGE_PRIVATE : Opcodes.ACC_PUBLIC;
694 int flags = visibilityFlag | getDeprecatedAccessFlag(functionDescriptor) | ACC_SYNTHETIC;
695 if (!(functionDescriptor instanceof ConstructorDescriptor)) {
696 flags |= ACC_STATIC | ACC_BRIDGE;
697 }
698
699 Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind);
700
701 MethodVisitor mv = v.newMethod(
702 JvmDeclarationOriginKt.Synthetic(function, functionDescriptor),
703 flags,
704 defaultMethod.getName(),
705 defaultMethod.getDescriptor(), null,
706 getThrownExceptions(functionDescriptor, typeMapper)
707 );
708
709 // Only method annotations are copied to the $default method. Parameter annotations are not copied until there are valid use cases;
710 // enum constructors have two additional synthetic parameters which somewhat complicate this task
711 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType());
712
713 if (state.getClassBuilderMode().generateBodies) {
714 if (this.owner instanceof MultifileClassFacadeContext) {
715 mv.visitCode();
716 generateFacadeDelegateMethodBody(mv, defaultMethod, (MultifileClassFacadeContext) this.owner);
717 endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
718 }
719 else {
720 mv.visitCode();
721 generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod);
722 endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
723 }
724 }
725 }
726
727 public static void generateDefaultImplBody(
728 @NotNull MethodContext methodContext,
729 @NotNull FunctionDescriptor functionDescriptor,
730 @NotNull MethodVisitor mv,
731 @NotNull DefaultParameterValueLoader loadStrategy,
732 @Nullable KtNamedFunction function,
733 @NotNull MemberCodegen<?> parentCodegen,
734 @NotNull Method defaultMethod
735 ) {
736 GenerationState state = parentCodegen.state;
737 JvmMethodSignature signature = state.getTypeMapper().mapSignatureWithGeneric(functionDescriptor, methodContext.getContextKind());
738
739 boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor);
740 FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic);
741
742 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);
743
744 CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function);
745
746 InstructionAdapter iv = new InstructionAdapter(mv);
747 genDefaultSuperCallCheckIfNeeded(iv, defaultMethod);
748
749 loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
750
751 List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters();
752 int capturedArgumentsCount = 0;
753 while (capturedArgumentsCount < mappedParameters.size() &&
754 mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) {
755 capturedArgumentsCount++;
756 }
757
758 int maskIndex = 0;
759 List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
760 for (int index = 0; index < valueParameters.size(); index++) {
761 if (index % Integer.SIZE == 0) {
762 maskIndex = frameMap.enterTemp(Type.INT_TYPE);
763 }
764 ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
765 Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();
766
767 int parameterIndex = frameMap.getIndex(parameterDescriptor);
768 if (parameterDescriptor.declaresDefaultValue()) {
769 iv.load(maskIndex, Type.INT_TYPE);
770 iv.iconst(1 << (index % Integer.SIZE));
771 iv.and(Type.INT_TYPE);
772 Label loadArg = new Label();
773 iv.ifeq(loadArg);
774
775 StackValue.local(parameterIndex, type).store(loadStrategy.genValue(parameterDescriptor, codegen), iv);
776
777 iv.mark(loadArg);
778 }
779
780 generator.putValueIfNeeded(type, StackValue.local(parameterIndex, type));
781 }
782
783 CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false);
784
785 generator.genCall(method, null, false, codegen);
786
787 iv.areturn(signature.getReturnType());
788 }
789
790 private static void genDefaultSuperCallCheckIfNeeded(@NotNull InstructionAdapter iv, @NotNull Method defaultMethod) {
791 String defaultMethodName = defaultMethod.getName();
792 if ("<init>".equals(defaultMethodName)) {
793 return;
794 }
795 Label end = new Label();
796 int handleIndex = (Type.getArgumentsAndReturnSizes(defaultMethod.getDescriptor()) >> 2) - 2; /*-1 for this, and -1 for handle*/
797 iv.load(handleIndex, OBJECT_TYPE);
798 iv.ifnull(end);
799 AsmUtil.genThrow(iv,
800 "java/lang/UnsupportedOperationException",
801 "Super calls with default arguments not supported in this target, function: " +
802 StringsKt.substringBeforeLast(defaultMethodName, JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodName));
803 iv.visitLabel(end);
804 }
805
806 @NotNull
807 private static FrameMap createFrameMap(
808 @NotNull GenerationState state,
809 @NotNull FunctionDescriptor function,
810 @NotNull JvmMethodSignature signature,
811 boolean isStatic
812 ) {
813 FrameMap frameMap = new FrameMap();
814 if (!isStatic) {
815 frameMap.enterTemp(OBJECT_TYPE);
816 }
817
818 for (JvmMethodParameterSignature parameter : signature.getValueParameters()) {
819 if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) {
820 ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter();
821 if (receiverParameter != null) {
822 frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter));
823 }
824 else {
825 frameMap.enterTemp(parameter.getAsmType());
826 }
827 }
828 else if (parameter.getKind() != JvmMethodParameterKind.VALUE) {
829 frameMap.enterTemp(parameter.getAsmType());
830 }
831 }
832
833 for (ValueParameterDescriptor parameter : function.getValueParameters()) {
834 frameMap.enter(parameter, state.getTypeMapper().mapType(parameter));
835 }
836
837 return frameMap;
838 }
839
840 private static void loadExplicitArgumentsOnStack(
841 @NotNull Type ownerType,
842 boolean isStatic,
843 @NotNull JvmMethodSignature signature,
844 @NotNull CallGenerator callGenerator
845 ) {
846 int var = 0;
847 if (!isStatic) {
848 callGenerator.putValueIfNeeded(ownerType, StackValue.local(var, ownerType));
849 var += ownerType.getSize();
850 }
851
852 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) {
853 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
854 Type type = parameterSignature.getAsmType();
855 callGenerator.putValueIfNeeded(type, StackValue.local(var, type));
856 var += type.getSize();
857 }
858 }
859 }
860
861 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
862 boolean needed = false;
863 if (functionDescriptor != null) {
864 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
865 if (parameterDescriptor.declaresDefaultValue()) {
866 needed = true;
867 break;
868 }
869 }
870 }
871 return needed;
872 }
873
874 private void generateBridge(
875 @Nullable PsiElement origin,
876 @NotNull FunctionDescriptor descriptor,
877 @NotNull Method bridge,
878 @NotNull Method delegateTo,
879 boolean isSpecialBridge,
880 boolean isStubDeclarationWithDelegationToSuper
881 ) {
882 boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper;
883 int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO.
884
885 MethodVisitor mv =
886 v.newMethod(JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null);
887 if (!state.getClassBuilderMode().generateBodies) return;
888
889 mv.visitCode();
890
891 Type[] argTypes = bridge.getArgumentTypes();
892 Type[] originalArgTypes = delegateTo.getArgumentTypes();
893
894 InstructionAdapter iv = new InstructionAdapter(mv);
895 MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
896
897 if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) {
898 generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]);
899 }
900
901 iv.load(0, OBJECT_TYPE);
902 for (int i = 0, reg = 1; i < argTypes.length; i++) {
903 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
904 //noinspection AssignmentToForLoopParameter
905 reg += argTypes[i].getSize();
906 }
907
908 if (isStubDeclarationWithDelegationToSuper) {
909 ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
910 assert parentClass != null;
911 String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
912 iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
913 }
914 else {
915 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
916 }
917
918 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
919 iv.areturn(bridge.getReturnType());
920
921 endVisit(mv, "bridge method", origin);
922 }
923
924 private static void generateTypeCheckBarrierIfNeeded(
925 @NotNull InstructionAdapter iv,
926 @NotNull FunctionDescriptor descriptor,
927 @NotNull Type returnType,
928 @Nullable final Type delegateParameterType
929 ) {
930 BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue =
931 BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
932 if (defaultValue == null) return;
933
934 assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor;
935
936 boolean isCheckForAny = delegateParameterType == null || OBJECT_TYPE.equals(delegateParameterType);
937
938 final KotlinType kotlinType = descriptor.getValueParameters().get(0).getType();
939
940 if (isCheckForAny && TypeUtils.isNullableType(kotlinType)) return;
941
942 iv.load(1, OBJECT_TYPE);
943
944 Label afterBarrier = new Label();
945
946 if (isCheckForAny) {
947 assert !TypeUtils.isNullableType(kotlinType) : "Only bridges for not-nullable types are necessary";
948 iv.ifnonnull(afterBarrier);
949 }
950 else {
951 CodegenUtilKt.generateIsCheck(iv, kotlinType, boxType(delegateParameterType));
952 iv.ifne(afterBarrier);
953 }
954
955 StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv);
956 iv.areturn(returnType);
957
958 iv.visitLabel(afterBarrier);
959 }
960
961 public void genSamDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
962 FunctionDescriptor delegatedTo = overriddenDescriptor.getOriginal();
963 JvmDeclarationOrigin declarationOrigin =
964 JvmDeclarationOriginKt.SamDelegation(functionDescriptor);
965 genDelegate(
966 functionDescriptor, delegatedTo,
967 declarationOrigin,
968 (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(),
969 field);
970 }
971
972 public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
973 genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(),
974 (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field);
975 }
976
977 public void genDelegate(
978 @NotNull FunctionDescriptor delegateFunction,
979 FunctionDescriptor delegatedTo,
980 ClassDescriptor toClass,
981 StackValue field
982 ) {
983 JvmDeclarationOrigin declarationOrigin =
984 JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction);
985 genDelegate(delegateFunction, delegatedTo, declarationOrigin, toClass, field);
986 }
987
988 private void genDelegate(
989 @NotNull final FunctionDescriptor delegateFunction,
990 final FunctionDescriptor delegatedTo,
991 @NotNull JvmDeclarationOrigin declarationOrigin,
992 final ClassDescriptor toClass,
993 final StackValue field
994 ) {
995 generateMethod(
996 declarationOrigin, delegateFunction,
997 new FunctionGenerationStrategy() {
998 @Override
999 public void generateBody(
1000 @NotNull MethodVisitor mv,
1001 @NotNull FrameMap frameMap,
1002 @NotNull JvmMethodSignature signature,
1003 @NotNull MethodContext context,
1004 @NotNull MemberCodegen<?> parentCodegen
1005 ) {
1006 Method delegateToMethod = typeMapper.mapToCallableMethod(delegatedTo, /* superCall = */ false).getAsmMethod();
1007 Method delegateMethod = typeMapper.mapAsmMethod(delegateFunction);
1008
1009 Type[] argTypes = delegateMethod.getArgumentTypes();
1010 Type[] originalArgTypes = delegateToMethod.getArgumentTypes();
1011
1012 InstructionAdapter iv = new InstructionAdapter(mv);
1013 iv.load(0, OBJECT_TYPE);
1014 field.put(field.type, iv);
1015 for (int i = 0, reg = 1; i < argTypes.length; i++) {
1016 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
1017 //noinspection AssignmentToForLoopParameter
1018 reg += argTypes[i].getSize();
1019 }
1020
1021 String internalName = typeMapper.mapType(toClass).getInternalName();
1022 if (toClass.getKind() == ClassKind.INTERFACE) {
1023 iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
1024 }
1025 else {
1026 iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
1027 }
1028
1029 StackValue stackValue = AsmUtil.genNotNullAssertions(
1030 state,
1031 StackValue.onStack(delegateToMethod.getReturnType()),
1032 RuntimeAssertionInfo.create(
1033 delegateFunction.getReturnType(),
1034 delegatedTo.getReturnType(),
1035 new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
1036 )
1037 );
1038
1039 stackValue.put(delegateMethod.getReturnType(), iv);
1040
1041 iv.areturn(delegateMethod.getReturnType());
1042 }
1043 }
1044 );
1045 }
1046 }