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