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