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