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