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