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