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