@NotNull
  public static String[] getThrownExceptions(
      @NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
    AnnotationDescriptor annotation =
        function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
    if (annotation == null) {
      annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws"));
    }

    if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;

    Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
    if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;

    Object value = values.iterator().next();
    if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
    ArrayValue arrayValue = (ArrayValue) value;

    List<String> strings =
        ContainerUtil.mapNotNull(
            arrayValue.getValue(),
            new Function<ConstantValue<?>, String>() {
              @Override
              public String fun(ConstantValue<?> constant) {
                if (constant instanceof KClassValue) {
                  KClassValue classValue = (KClassValue) constant;
                  ClassDescriptor classDescriptor =
                      DescriptorUtils.getClassDescriptorForType(classValue.getValue());
                  return mapper.mapClass(classDescriptor).getInternalName();
                }
                return null;
              }
            });
    return ArrayUtil.toStringArray(strings);
  }
  @NotNull
  private static FrameMap createFrameMap(
      @NotNull GenerationState state,
      @NotNull FunctionDescriptor function,
      @NotNull JvmMethodSignature signature,
      boolean isStatic) {
    FrameMap frameMap = new FrameMap();
    if (!isStatic) {
      frameMap.enterTemp(OBJECT_TYPE);
    }

    for (JvmMethodParameterSignature parameter : signature.getValueParameters()) {
      if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) {
        ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter();
        if (receiverParameter != null) {
          frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter));
        }
      } else if (parameter.getKind() != JvmMethodParameterKind.VALUE) {
        frameMap.enterTemp(parameter.getAsmType());
      }
    }

    for (ValueParameterDescriptor parameter : function.getValueParameters()) {
      frameMap.enter(parameter, state.getTypeMapper().mapType(parameter));
    }

    return frameMap;
  }
 public void genDelegate(
     @NotNull FunctionDescriptor functionDescriptor,
     FunctionDescriptor overriddenDescriptor,
     StackValue field) {
   genDelegate(
       functionDescriptor,
       overriddenDescriptor.getOriginal(),
       (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(),
       field);
 }
 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
   String name = descriptor.getName().asString();
   List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
   if (parameters.isEmpty()) {
     return name.equals("hashCode") || name.equals("toString");
   } else if (parameters.size() == 1 && name.equals("equals")) {
     return isNullableAny(parameters.get(0).getType());
   }
   return false;
 }
  private void generateParameterAnnotations(
      @NotNull FunctionDescriptor functionDescriptor,
      @NotNull MethodVisitor mv,
      @NotNull JvmMethodSignature jvmSignature) {
    Iterator<ValueParameterDescriptor> iterator =
        functionDescriptor.getValueParameters().iterator();
    List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();

    for (int i = 0; i < kotlinParameterTypes.size(); i++) {
      JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i);
      JvmMethodParameterKind kind = parameterSignature.getKind();
      if (kind.isSkippedInGenericSignature()) {
        markEnumOrInnerConstructorParameterAsSynthetic(mv, i);
        continue;
      }

      if (kind == JvmMethodParameterKind.VALUE) {
        ValueParameterDescriptor parameter = iterator.next();
        if (parameter.getIndex() != i) {
          v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i);
        }
        AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper);

        if (functionDescriptor instanceof PropertySetterDescriptor) {
          PropertyDescriptor propertyDescriptor =
              ((PropertySetterDescriptor) functionDescriptor).getCorrespondingProperty();
          Annotated targetedAnnotations =
              new AnnotatedWithOnlyTargetedAnnotations(propertyDescriptor);
          annotationCodegen.genAnnotations(
              targetedAnnotations, parameterSignature.getAsmType(), SETTER_PARAMETER);
        }

        if (functionDescriptor instanceof ConstructorDescriptor) {
          annotationCodegen.genAnnotations(
              parameter, parameterSignature.getAsmType(), CONSTRUCTOR_PARAMETER);
        } else {
          annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType());
        }
      } else if (kind == JvmMethodParameterKind.RECEIVER) {
        ReceiverParameterDescriptor receiver =
            ((functionDescriptor instanceof PropertyAccessorDescriptor)
                    ? ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty()
                    : functionDescriptor)
                .getExtensionReceiverParameter();
        if (receiver != null) {
          AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper);
          Annotated targetedAnnotations =
              new AnnotatedWithOnlyTargetedAnnotations(receiver.getType());
          annotationCodegen.genAnnotations(
              targetedAnnotations, parameterSignature.getAsmType(), RECEIVER);
        }
      }
    }
  }
  private void generateBridge(
      @Nullable PsiElement origin,
      @NotNull FunctionDescriptor descriptor,
      @NotNull Method bridge,
      @NotNull Method delegateTo,
      boolean isSpecialBridge,
      boolean superCallNeeded) {
    int flags =
        ACC_PUBLIC
            | ACC_BRIDGE
            | (!isSpecialBridge ? ACC_SYNTHETIC : 0)
            | (isSpecialBridge ? ACC_FINAL : 0); // TODO.

    MethodVisitor mv =
        v.newMethod(
            DiagnosticsPackage.Bridge(descriptor, origin),
            flags,
            bridge.getName(),
            bridge.getDescriptor(),
            null,
            null);
    if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;

    mv.visitCode();

    Type[] argTypes = bridge.getArgumentTypes();
    Type[] originalArgTypes = delegateTo.getArgumentTypes();

    InstructionAdapter iv = new InstructionAdapter(mv);
    ImplementationBodyCodegen.markLineNumberForSyntheticFunction(owner.getThisDescriptor(), iv);

    iv.load(0, OBJECT_TYPE);
    for (int i = 0, reg = 1; i < argTypes.length; i++) {
      StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
      //noinspection AssignmentToForLoopParameter
      reg += argTypes[i].getSize();
    }

    if (superCallNeeded) {
      ClassDescriptor parentClass =
          getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
      assert parentClass != null;
      String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
      iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
    } else {
      iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
    }

    StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
    iv.areturn(bridge.getReturnType());

    endVisit(mv, "bridge method", origin);
  }
 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
   boolean needed = false;
   if (functionDescriptor != null) {
     for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
       if (parameterDescriptor.declaresDefaultValue()) {
         needed = true;
         break;
       }
     }
   }
   return needed;
 }
  private static void generateLocalVariableTable(
      @NotNull MethodVisitor mv,
      @NotNull JvmMethodSignature jvmMethodSignature,
      @NotNull FunctionDescriptor functionDescriptor,
      @Nullable Type thisType,
      @NotNull Label methodBegin,
      @NotNull Label methodEnd,
      @NotNull OwnerKind ownerKind) {
    Iterator<ValueParameterDescriptor> valueParameters =
        functionDescriptor.getValueParameters().iterator();
    List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
    int shift = 0;

    boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
    if (!isStatic) {
      // add this
      if (thisType != null) {
        mv.visitLocalVariable(
            "this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
      } else {
        // TODO: provide thisType for callable reference
      }
      shift++;
    }

    for (int i = 0; i < params.size(); i++) {
      JvmMethodParameterSignature param = params.get(i);
      JvmMethodParameterKind kind = param.getKind();
      String parameterName;

      if (kind == JvmMethodParameterKind.VALUE) {
        ValueParameterDescriptor parameter = valueParameters.next();
        parameterName = parameter.getName().asString();
      } else {
        String lowercaseKind = kind.name().toLowerCase();
        parameterName = needIndexForVar(kind) ? "$" + lowercaseKind + "$" + i : "$" + lowercaseKind;
      }

      Type type = param.getAsmType();
      mv.visitLocalVariable(
          parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
      shift += type.getSize();
    }
  }
 @Nullable
 private static Type getThisTypeForFunction(
     @NotNull FunctionDescriptor functionDescriptor,
     @NotNull MethodContext context,
     @NotNull JetTypeMapper typeMapper) {
   ReceiverParameterDescriptor dispatchReceiver =
       functionDescriptor.getDispatchReceiverParameter();
   if (functionDescriptor instanceof ConstructorDescriptor) {
     return typeMapper.mapType(functionDescriptor);
   } else if (dispatchReceiver != null) {
     return typeMapper.mapType(dispatchReceiver.getType());
   } else if (isFunctionLiteral(functionDescriptor)
       || isLocalFunction(functionDescriptor)
       || isFunctionExpression(functionDescriptor)) {
     return typeMapper.mapType(context.getThisDescriptor());
   } else {
     return null;
   }
 }
  public static void generateDefaultImplBody(
      @NotNull MethodContext methodContext,
      @NotNull FunctionDescriptor functionDescriptor,
      @NotNull MethodVisitor mv,
      @NotNull DefaultParameterValueLoader loadStrategy,
      @Nullable JetNamedFunction function,
      @NotNull MemberCodegen<?> parentCodegen) {
    GenerationState state = parentCodegen.state;
    JvmMethodSignature signature =
        state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind());

    boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor);
    FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic);

    ExpressionCodegen codegen =
        new ExpressionCodegen(
            mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);

    CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function);

    loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);

    List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters();
    int capturedArgumentsCount = 0;
    while (capturedArgumentsCount < mappedParameters.size()
        && mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) {
      capturedArgumentsCount++;
    }

    InstructionAdapter iv = new InstructionAdapter(mv);

    int maskIndex = 0;
    List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
    for (int index = 0; index < valueParameters.size(); index++) {
      if (index % Integer.SIZE == 0) {
        maskIndex = frameMap.enterTemp(Type.INT_TYPE);
      }
      ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
      Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();

      int parameterIndex = frameMap.getIndex(parameterDescriptor);
      if (parameterDescriptor.declaresDefaultValue()) {
        iv.load(maskIndex, Type.INT_TYPE);
        iv.iconst(1 << (index % Integer.SIZE));
        iv.and(Type.INT_TYPE);
        Label loadArg = new Label();
        iv.ifeq(loadArg);

        StackValue.local(parameterIndex, type)
            .store(loadStrategy.genValue(parameterDescriptor, codegen), iv);

        iv.mark(loadArg);
      }

      generator.putValueIfNeeded(parameterDescriptor, type, StackValue.local(parameterIndex, type));
    }

    CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false);

    generator.genCallWithoutAssertions(method, codegen);

    iv.areturn(signature.getReturnType());
  }
  public void generateBridges(@NotNull FunctionDescriptor descriptor) {
    if (descriptor instanceof ConstructorDescriptor) return;
    if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
    if (isInterface(descriptor.getContainingDeclaration())) return;

    // equals(Any?), hashCode(), toString() never need bridges
    if (isMethodOfAny(descriptor)) return;

    // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter
    // or alike and doesn't need bridges
    if (CallResolverUtilPackage.isOrOverridesSynthesized(descriptor)) return;

    boolean isSpecial = BuiltinsPropertiesUtilKt.overridesBuiltinSpecialDeclaration(descriptor);

    Set<Bridge<Method>> bridgesToGenerate;
    if (!isSpecial) {
      bridgesToGenerate =
          BridgesPackage.generateBridgesForFunctionDescriptor(
              descriptor,
              new Function1<FunctionDescriptor, Method>() {
                @Override
                public Method invoke(FunctionDescriptor descriptor) {
                  return typeMapper.mapSignature(descriptor).getAsmMethod();
                }
              });
      if (!bridgesToGenerate.isEmpty()) {
        PsiElement origin =
            descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
        for (Bridge<Method> bridge : bridgesToGenerate) {
          generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), false, false);
        }
      }
    } else {
      Set<BridgeForBuiltinSpecial<Method>> specials =
          BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
              descriptor,
              new Function1<FunctionDescriptor, Method>() {
                @Override
                public Method invoke(FunctionDescriptor descriptor) {
                  return typeMapper.mapSignature(descriptor).getAsmMethod();
                }
              });

      if (!specials.isEmpty()) {
        PsiElement origin =
            descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
        for (BridgeForBuiltinSpecial<Method> bridge : specials) {
          generateBridge(
              origin,
              descriptor,
              bridge.getFrom(),
              bridge.getTo(),
              bridge.isSpecial(),
              bridge.isDelegateToSuper());
        }
      }

      if (!descriptor.getKind().isReal()
          && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
        CallableDescriptor overridden =
            BuiltinsPropertiesUtilKt.getBuiltinSpecialOverridden(descriptor);
        assert overridden != null;

        Method method = typeMapper.mapSignature(descriptor).getAsmMethod();
        int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor);
        v.newMethod(
            OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null);
      }
    }
  }
  public void generateMethod(
      @NotNull JvmDeclarationOrigin origin,
      @NotNull FunctionDescriptor functionDescriptor,
      @NotNull MethodContext methodContext,
      @NotNull FunctionGenerationStrategy strategy) {
    OwnerKind contextKind = methodContext.getContextKind();
    if (isInterface(functionDescriptor.getContainingDeclaration())
        && functionDescriptor.getVisibility() == Visibilities.PRIVATE
        && contextKind != OwnerKind.DEFAULT_IMPLS) {
      return;
    }

    JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, contextKind);
    Method asmMethod = jvmSignature.getAsmMethod();

    int flags = getMethodAsmFlags(functionDescriptor, contextKind);
    boolean isNative = NativeDeclarationsPackage.hasNativeAnnotation(functionDescriptor);

    if (isNative && owner instanceof DelegatingFacadeContext) {
      // Native methods are only defined in facades and do not need package part implementations
      return;
    }
    MethodVisitor mv =
        v.newMethod(
            origin,
            flags,
            asmMethod.getName(),
            asmMethod.getDescriptor(),
            jvmSignature.getGenericsSignature(),
            getThrownExceptions(functionDescriptor, typeMapper));

    String implClassName = CodegenContextUtil.getImplementationClassShortName(owner);
    if (implClassName != null) {
      v.getSerializationBindings()
          .put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, implClassName);
    }
    if (CodegenContextUtil.isImplClassOwner(owner)) {
      v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
    }

    generateMethodAnnotations(functionDescriptor, asmMethod, mv);

    generateParameterAnnotations(
        functionDescriptor, mv, typeMapper.mapSignature(functionDescriptor));

    generateBridges(functionDescriptor);

    boolean staticInCompanionObject =
        AnnotationsPackage.isPlatformStaticInCompanionObject(functionDescriptor);
    if (staticInCompanionObject) {
      ImplementationBodyCodegen parentBodyCodegen =
          (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
      parentBodyCodegen.addAdditionalTask(
          new PlatformStaticGenerator(functionDescriptor, origin, state));
    }

    if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES
        || isAbstractMethod(functionDescriptor, contextKind)) {
      generateLocalVariableTable(
          mv,
          jvmSignature,
          functionDescriptor,
          getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
          new Label(),
          new Label(),
          contextKind);

      mv.visitEnd();
      return;
    }

    if (!isNative) {
      generateMethodBody(
          mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen);
    } else if (staticInCompanionObject) {
      // native platformStatic foo() in companion object should delegate to the static native
      // function moved to the outer class
      mv.visitCode();
      FunctionDescriptor staticFunctionDescriptor =
          PlatformStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
      JvmMethodSignature jvmMethodSignature =
          typeMapper.mapSignature(
              memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
      Type owningType =
          typeMapper.mapClass(
              (ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
      generateDelegateToMethodBody(
          false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName());
    }

    endVisit(mv, null, origin.getElement());

    methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
  }