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