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