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