// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

package com.android.tools.r8.ir.desugar;

import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue.DexValueNull;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.base.Suppliers;
import com.google.common.primitives.Longs;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.zip.CRC32;

/**
 * Represents lambda class generated for a lambda descriptor in context of lambda instantiation
 * point.
 *
 * <p>Even though call sites, and thus lambda descriptors, are canonicalized across the application,
 * the context may require several lambda classes to be generated for the same lambda descriptor.
 *
 * <p>One reason is that we always generate a lambda class in the same package lambda instantiation
 * point is located in, so if same call site is used in two classes from different packages (which
 * can happen if same public method is being references via method reference expression) we generate
 * separate lambda classes in those packages.
 *
 * <p>Another reason is that if we generate an accessor, we generate it in the class referencing the
 * call site, and thus two such classes will require two separate lambda classes.
 */
final class LambdaClass {

  final LambdaRewriter rewriter;
  final DexType type;
  final LambdaDescriptor descriptor;
  final DexMethod constructor;
  final DexMethod classConstructor;
  final DexField lambdaField;
  final Target target;
  final AtomicBoolean addToMainDexList = new AtomicBoolean(false);
  private final Collection<DexProgramClass> synthesizedFrom = new ArrayList<>(1);
  private final Supplier<DexProgramClass> lazyDexClass =
      Suppliers.memoize(this::synthesizeLambdaClass); // NOTE: thread-safe.

  LambdaClass(
      LambdaRewriter rewriter,
      DexType accessedFrom,
      DexType lambdaClassType,
      LambdaDescriptor descriptor) {
    assert rewriter != null;
    assert lambdaClassType != null;
    assert descriptor != null;

    this.rewriter = rewriter;
    this.type = lambdaClassType;
    this.descriptor = descriptor;

    DexItemFactory factory = rewriter.getFactory();
    DexProto constructorProto = factory.createProto(
        factory.voidType, descriptor.captures.values);
    this.constructor = factory.createMethod(
        lambdaClassType, constructorProto, rewriter.constructorName);

    this.target = createTarget(accessedFrom);

    boolean stateless = isStateless();
    this.classConstructor = !stateless ? null
        : factory.createMethod(lambdaClassType, constructorProto, rewriter.classConstructorName);
    this.lambdaField =
        !stateless
            ? null
            : factory.createField(lambdaClassType, lambdaClassType, rewriter.instanceFieldName);
  }

  // Generate unique lambda class type for lambda descriptor and instantiation point context.
  static DexType createLambdaClassType(
      LambdaRewriter rewriter, DexType accessedFrom, LambdaDescriptor match) {
    return createLambdaClassType(rewriter.getFactory(), accessedFrom, match);
  }

  public static DexType createLambdaClassType(
      DexItemFactory factory, DexType accessedFrom, LambdaDescriptor match) {
    StringBuilder lambdaClassDescriptor = new StringBuilder("L");

    // We always create lambda class in the same package where it is referenced.
    String packageDescriptor = accessedFrom.getPackageDescriptor();
    if (!packageDescriptor.isEmpty()) {
      lambdaClassDescriptor.append(packageDescriptor).append('/');
    }

    // Lambda class name prefix
    lambdaClassDescriptor.append(LambdaRewriter.LAMBDA_CLASS_NAME_PREFIX);

    // If the lambda class should match 1:1 the class it is accessed from, we
    // just add the name of this type to make lambda class name unique.
    // It also helps link the class lambda originated from in some cases.
    if (match.delegatesToLambdaImplMethod() || match.needsAccessor(accessedFrom)) {
      lambdaClassDescriptor.append(accessedFrom.getName()).append('$');
    }

    // Add unique lambda descriptor id
    lambdaClassDescriptor.append(match.uniqueId).append(';');
    return factory.createType(lambdaClassDescriptor.toString());
  }

  final DexProgramClass getOrCreateLambdaClass() {
    return lazyDexClass.get();
  }

  private DexProgramClass synthesizeLambdaClass() {
    DexMethod mainMethod =
        rewriter.getFactory().createMethod(type, descriptor.erasedProto, descriptor.name);

    DexProgramClass clazz =
        new DexProgramClass(
            type,
            null,
            new SynthesizedOrigin("lambda desugaring", getClass()),
            // Make the synthesized class public, as it might end up being accessed from a different
            // classloader (package private access is not allowed across classloaders, b/72538146).
            ClassAccessFlags.fromDexAccessFlags(
                Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC),
            rewriter.getFactory().objectType,
            buildInterfaces(),
            rewriter.getFactory().createString("lambda"),
            null,
            Collections.emptyList(),
            null,
            Collections.emptyList(),
            DexAnnotationSet.empty(),
            synthesizeStaticFields(),
            synthesizeInstanceFields(),
            synthesizeDirectMethods(),
            synthesizeVirtualMethods(mainMethod),
            rewriter.getFactory().getSkipNameValidationForTesting(),
            LambdaClass::computeChecksumForSynthesizedClass);
    rewriter.getAppInfo().addSynthesizedClass(clazz);

    // The method addSynthesizedFrom() may be called concurrently. To avoid a Concurrent-
    // ModificationException we must use synchronization.
    synchronized (synthesizedFrom) {
      synthesizedFrom.forEach(clazz::addSynthesizedFrom);
    }
    return clazz;
  }

  private static long computeChecksumForSynthesizedClass(DexProgramClass clazz) {
    // Checksum of synthesized classes are compute based off the depending input. This might
    // create false positives (ie: unchanged lambda class detected as changed even thought only
    // an unrelated part from a synthesizedFrom class is changed).

    // Ideally, we should use some hashcode of the dex program class that is deterministic across
    // compiles.
    Collection<DexProgramClass> synthesizedFrom = clazz.getSynthesizedFrom();
    ByteBuffer buffer = ByteBuffer.allocate(synthesizedFrom.size() * Longs.BYTES);
    for (DexProgramClass from : synthesizedFrom) {
      buffer.putLong(from.getChecksum());
    }
    CRC32 crc = new CRC32();
    byte[] array = buffer.array();
    crc.update(array, 0, array.length);
    return crc.getValue();
  }

  final DexField getCaptureField(int index) {
    return rewriter
        .getFactory()
        .createField(
            this.type,
            descriptor.captures.values[index],
            rewriter.getFactory().createString("f$" + index));
  }

  final boolean isStateless() {
    return descriptor.isStateless();
  }

  void addSynthesizedFrom(DexProgramClass clazz) {
    assert clazz != null;
    synchronized (synthesizedFrom) {
      if (synthesizedFrom.add(clazz)) {
        // The lambda class may already have been synthesized, and we therefore need to update the
        // synthesized lambda class as well.
        getOrCreateLambdaClass().addSynthesizedFrom(clazz);
      }
    }
  }

  // Synthesize virtual methods.
  private DexEncodedMethod[] synthesizeVirtualMethods(DexMethod mainMethod) {
    DexEncodedMethod[] methods = new DexEncodedMethod[1 + descriptor.bridges.size()];
    int index = 0;

    // Synthesize main method.
    methods[index++] =
        new DexEncodedMethod(
            mainMethod,
            MethodAccessFlags.fromSharedAccessFlags(
                Constants.ACC_PUBLIC | Constants.ACC_FINAL, false),
            DexAnnotationSet.empty(),
            ParameterAnnotationsList.empty(),
            new LambdaMainMethodSynthesizedCode(this, mainMethod),
            true);

    // Synthesize bridge methods.
    for (DexProto bridgeProto : descriptor.bridges) {
      DexMethod bridgeMethod =
          rewriter.getFactory().createMethod(type, bridgeProto, descriptor.name);
      methods[index++] =
          new DexEncodedMethod(
              bridgeMethod,
              MethodAccessFlags.fromSharedAccessFlags(
                  Constants.ACC_PUBLIC
                      | Constants.ACC_FINAL
                      | Constants.ACC_SYNTHETIC
                      | Constants.ACC_BRIDGE,
                  false),
              DexAnnotationSet.empty(),
              ParameterAnnotationsList.empty(),
              new LambdaBridgeMethodSynthesizedCode(this, mainMethod, bridgeMethod),
              true);
    }
    return methods;
  }

  // Synthesize direct methods.
  private DexEncodedMethod[] synthesizeDirectMethods() {
    boolean stateless = isStateless();
    DexEncodedMethod[] methods = new DexEncodedMethod[stateless ? 2 : 1];

    // Constructor.
    methods[0] =
        new DexEncodedMethod(
            constructor,
            MethodAccessFlags.fromSharedAccessFlags(
                (stateless ? Constants.ACC_PRIVATE : Constants.ACC_PUBLIC)
                    | Constants.ACC_SYNTHETIC,
                true),
            DexAnnotationSet.empty(),
            ParameterAnnotationsList.empty(),
            new LambdaConstructorSynthesizedCode(this),
            true);

    // Class constructor for stateless lambda classes.
    if (stateless) {
      methods[1] =
          new DexEncodedMethod(
              classConstructor,
              MethodAccessFlags.fromSharedAccessFlags(
                  Constants.ACC_SYNTHETIC | Constants.ACC_STATIC, true),
              DexAnnotationSet.empty(),
              ParameterAnnotationsList.empty(),
              new LambdaClassConstructorSynthesizedCode(this),
              true);
    }
    return methods;
  }

  // Synthesize instance fields to represent captured values.
  private DexEncodedField[] synthesizeInstanceFields() {
    DexType[] fieldTypes = descriptor.captures.values;
    int fieldCount = fieldTypes.length;
    DexEncodedField[] fields = new DexEncodedField[fieldCount];
    for (int i = 0; i < fieldCount; i++) {
      FieldAccessFlags accessFlags =
          FieldAccessFlags.fromSharedAccessFlags(
              Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_PUBLIC);
      fields[i] = new DexEncodedField(
          getCaptureField(i), accessFlags, DexAnnotationSet.empty(), null);
    }
    return fields;
  }

  // Synthesize static fields to represent singleton instance.
  private DexEncodedField[] synthesizeStaticFields() {
    if (!isStateless()) {
      return DexEncodedField.EMPTY_ARRAY;
    }

    // Create instance field for stateless lambda.
    assert this.lambdaField != null;
    DexEncodedField[] fields = new DexEncodedField[1];
    fields[0] =
        new DexEncodedField(
            this.lambdaField,
            FieldAccessFlags.fromSharedAccessFlags(
                Constants.ACC_PUBLIC
                    | Constants.ACC_FINAL
                    | Constants.ACC_SYNTHETIC
                    | Constants.ACC_STATIC),
            DexAnnotationSet.empty(),
            DexValueNull.NULL);
    return fields;
  }

  // Build a list of implemented interfaces.
  private DexTypeList buildInterfaces() {
    List<DexType> interfaces = descriptor.interfaces;
    return interfaces.isEmpty()
        ? DexTypeList.empty()
        : new DexTypeList(interfaces.toArray(DexType.EMPTY_ARRAY));
  }

  // Creates a delegation target for this particular lambda class. Note that we
  // should always be able to create targets for the lambdas we support.
  private Target createTarget(DexType accessedFrom) {
    if (descriptor.delegatesToLambdaImplMethod()) {
      return createLambdaImplMethodTarget(accessedFrom);
    }

    // Method referenced directly, without lambda$ method.
    switch (descriptor.implHandle.type) {
      case INVOKE_SUPER:
        throw new Unimplemented("Method references to super methods are not yet supported");
      case INVOKE_INTERFACE:
        return createInterfaceMethodTarget(accessedFrom);
      case INVOKE_CONSTRUCTOR:
        return createConstructorTarget(accessedFrom);
      case INVOKE_STATIC:
        return createStaticMethodTarget(accessedFrom);
      case INVOKE_DIRECT:
      case INVOKE_INSTANCE:
        return createInstanceMethodTarget(accessedFrom);
      default:
        throw new Unreachable("Unexpected method handle type in " + descriptor.implHandle);
    }
  }

  private Target createLambdaImplMethodTarget(DexType accessedFrom) {
    DexMethodHandle implHandle = descriptor.implHandle;
    assert implHandle != null;
    DexMethod implMethod = implHandle.asMethod();

    // Lambda$ method. We must always find it.
    assert implMethod.holder == accessedFrom;
    assert descriptor.targetFoundInClass(accessedFrom);
    assert descriptor.getAccessibility() != null;

    if (implHandle.type.isInvokeStatic()) {
      return new StaticLambdaImplTarget();
    }

    assert implHandle.type.isInvokeInstance() || implHandle.type.isInvokeDirect();

    // If the lambda$ method is an instance-private method on an interface we convert it into a
    // public static method as it will be placed on the companion class.
    if (implHandle.type.isInvokeDirect()
        && rewriter.getAppView().definitionFor(implMethod.holder).isInterface()) {
      DexProto implProto = implMethod.proto;
      DexType[] implParams = implProto.parameters.values;
      DexType[] newParams = new DexType[implParams.length + 1];
      newParams[0] = implMethod.holder;
      System.arraycopy(implParams, 0, newParams, 1, implParams.length);

      DexProto newProto = rewriter.getFactory().createProto(implProto.returnType, newParams);
      return new InterfaceLambdaImplTarget(
          rewriter.getFactory().createMethod(implMethod.holder, newProto, implMethod.name));
    } else {
      // Otherwise we need to ensure the method can be reached publicly by virtual dispatch.
      // To avoid potential conflicts on the name of the lambda method once dispatch becomes virtual
      // we add the method-holder name as suffix to the lambda-method name.
      return new InstanceLambdaImplTarget(
          rewriter
              .getFactory()
              .createMethod(
                  implMethod.holder,
                  implMethod.proto,
                  rewriter
                      .getFactory()
                      .createString(
                          implMethod.name.toString() + "$" + implMethod.holder.getName())));
    }
  }

  // Create targets for instance method referenced directly without
  // lambda$ methods. It may require creation of accessors in some cases.
  private Target createInstanceMethodTarget(DexType accessedFrom) {
    assert descriptor.implHandle.type.isInvokeInstance() ||
        descriptor.implHandle.type.isInvokeDirect();

    if (!descriptor.needsAccessor(accessedFrom)) {
      return new NoAccessorMethodTarget(Invoke.Type.VIRTUAL);
    }
    // We need to generate an accessor method in `accessedFrom` class/interface
    // for accessing the original instance impl-method. Note that impl-method's
    // holder does not have to be the same as `accessedFrom`.
    DexMethod implMethod = descriptor.implHandle.asMethod();
    DexProto implProto = implMethod.proto;
    DexType[] implParams = implProto.parameters.values;

    // The accessor method will be static, package private, and take the
    // receiver as the first argument. The receiver must be captured and
    // be the first captured value in case there are more than one.
    DexType[] accessorParams = new DexType[1 + implParams.length];
    accessorParams[0] = descriptor.getImplReceiverType();
    System.arraycopy(implParams, 0, accessorParams, 1, implParams.length);
    DexProto accessorProto =
        rewriter.getFactory().createProto(implProto.returnType, accessorParams);
    DexMethod accessorMethod =
        rewriter
            .getFactory()
            .createMethod(accessedFrom, accessorProto, generateUniqueLambdaMethodName());

    return new ClassMethodWithAccessorTarget(accessorMethod);
  }

  // Create targets for static method referenced directly without
  // lambda$ methods. It may require creation of accessors in some cases.
  private Target createStaticMethodTarget(DexType accessedFrom) {
    assert descriptor.implHandle.type.isInvokeStatic();

    if (!descriptor.needsAccessor(accessedFrom)) {
      return new NoAccessorMethodTarget(Invoke.Type.STATIC);
    }

    // We need to generate an accessor method in `accessedFrom` class/interface
    // for accessing the original static impl-method. The accessor method will be
    // static, package private with exactly same signature and the original method.
    DexMethod accessorMethod =
        rewriter
            .getFactory()
            .createMethod(
                accessedFrom,
                descriptor.implHandle.asMethod().proto,
                generateUniqueLambdaMethodName());
    return new ClassMethodWithAccessorTarget(accessorMethod);
  }

  // Create targets for constructor referenced directly without lambda$ methods.
  // It may require creation of accessors in some cases.
  private Target createConstructorTarget(DexType accessedFrom) {
    DexMethodHandle implHandle = descriptor.implHandle;
    assert implHandle != null;
    assert implHandle.type.isInvokeConstructor();

    if (!descriptor.needsAccessor(accessedFrom)) {
      return new NoAccessorMethodTarget(Invoke.Type.DIRECT);
    }

    // We need to generate an accessor method in `accessedFrom` class/interface for
    // instantiating the class and calling constructor on it. The accessor method will
    // be static, package private with exactly same parameters as the constructor,
    // and return the newly created instance.
    DexMethod implMethod = implHandle.asMethod();
    DexType returnType = implMethod.holder;
    DexProto accessorProto =
        rewriter.getFactory().createProto(returnType, implMethod.proto.parameters.values);
    DexMethod accessorMethod =
        rewriter
            .getFactory()
            .createMethod(accessedFrom, accessorProto, generateUniqueLambdaMethodName());
    return new ClassMethodWithAccessorTarget(accessorMethod);
  }

  // Create targets for interface methods.
  private Target createInterfaceMethodTarget(DexType accessedFrom) {
    assert descriptor.implHandle.type.isInvokeInterface();
    assert !descriptor.needsAccessor(accessedFrom);
    return new NoAccessorMethodTarget(Invoke.Type.INTERFACE);
  }

  private DexString generateUniqueLambdaMethodName() {
    return rewriter
        .getFactory()
        .createString(LambdaRewriter.EXPECTED_LAMBDA_METHOD_PREFIX + descriptor.uniqueId);
  }

  // Represents information about the method lambda class need to delegate the call to. It may
  // be the same method as specified in lambda descriptor or a newly synthesized accessor.
  // Also provides action for ensuring accessibility of the referenced symbols.
  abstract class Target {

    final DexMethod callTarget;
    final Invoke.Type invokeType;

    Target(DexMethod callTarget, Invoke.Type invokeType) {
      assert callTarget != null;
      assert invokeType != null;
      this.callTarget = callTarget;
      this.invokeType = invokeType;
    }

    // Ensure access of the referenced symbol(s).
    abstract void ensureAccessibility(IRConverter converter, OptimizationFeedback feedback);

    DexClass definitionFor(DexType type) {
      return rewriter.getAppInfo().app().definitionFor(type);
    }

    DexProgramClass programDefinitionFor(DexType type) {
      return rewriter.getAppInfo().app().programDefinitionFor(type);
    }

    boolean holderIsInterface() {
      InternalOptions options = rewriter.getAppView().options();
      if (!options.isGeneratingClassFiles()) {
        // When generating dex the value of this flag on invokes does not matter (unused).
        // We cannot know if definitionFor(implMethod.holder) is null or not in that case,
        // so we cannot set the flag and just return false.
        return false;
      }
      // The only case where we do Lambda desugaring with Cf to Cf is in L8.
      // If the compilation is not coreLibraryCompilation, then the assertion
      // implMethodHolder != null may fail, hence the assertion.
      assert options.isDesugaredLibraryCompilation() || options.enableCfInterfaceMethodDesugaring;
      DexMethod implMethod = descriptor.implHandle.asMethod();
      DexClass implMethodHolder = definitionFor(implMethod.holder);
      if (implMethodHolder == null) {
        assert options
            .desugaredLibraryConfiguration
            .getBackportCoreLibraryMember()
            .containsKey(implMethod.holder);
        return false;
      }
      return implMethodHolder.isInterface();
    }
  }

  // Used for targeting methods referenced directly without creating accessors.
  private final class NoAccessorMethodTarget extends Target {

    NoAccessorMethodTarget(Invoke.Type invokeType) {
      super(descriptor.implHandle.asMethod(), invokeType);
    }

    @Override
    void ensureAccessibility(IRConverter converter, OptimizationFeedback feedback) {}
  }

  // Used for static private lambda$ methods. Only needs access relaxation.
  private final class StaticLambdaImplTarget extends Target {

    StaticLambdaImplTarget() {
      super(descriptor.implHandle.asMethod(), Invoke.Type.STATIC);
    }

    @Override
    void ensureAccessibility(IRConverter converter, OptimizationFeedback feedback) {
      // We already found the static method to be called, just relax its accessibility.
      assert descriptor.getAccessibility() != null;
      descriptor.getAccessibility().unsetPrivate();
      DexClass implMethodHolder = definitionFor(descriptor.implHandle.asMethod().holder);
      if (implMethodHolder.isInterface()) {
        descriptor.getAccessibility().setPublic();
      }
    }
  }

  // Used for instance private lambda$ methods on interfaces which need to be converted to public
  // static methods. They can't remain instance methods as they will end up on the companion class.
  private class InterfaceLambdaImplTarget extends Target {

    InterfaceLambdaImplTarget(DexMethod staticMethod) {
      super(staticMethod, Type.STATIC);
    }

    @Override
    void ensureAccessibility(IRConverter converter, OptimizationFeedback feedback) {
      // For all instantiation points for which the compiler creates lambda$
      // methods, it creates these methods in the same class/interface.
      DexMethod implMethod = descriptor.implHandle.asMethod();
      DexClass implMethodHolder = definitionFor(implMethod.holder);

      List<DexEncodedMethod> directMethods = implMethodHolder.directMethods();
      for (int i = 0; i < directMethods.size(); i++) {
        DexEncodedMethod encodedMethod = directMethods.get(i);
        if (implMethod.match(encodedMethod)) {
          // We need to create a new static method with the same code to be able to safely
          // relax its accessibility without making it virtual.
          MethodAccessFlags newAccessFlags = encodedMethod.accessFlags.copy();
          newAccessFlags.setStatic();
          newAccessFlags.unsetPrivate();
          // Always make the method public to provide access when r8 minification is allowed to move
          // the lambda class accessing this method to another package (-allowaccessmodification).
          newAccessFlags.setPublic();
          DexEncodedMethod newMethod =
              new DexEncodedMethod(
                  callTarget,
                  newAccessFlags,
                  encodedMethod.annotations,
                  encodedMethod.parameterAnnotationsList,
                  encodedMethod.getCode(),
                  true);
          newMethod.copyMetadata(encodedMethod, feedback);
          rewriter.methodMapping.put(encodedMethod.method, callTarget);

          DexEncodedMethod.setDebugInfoWithFakeThisParameter(
              newMethod.getCode(), callTarget.getArity(), rewriter.getAppView());
          implMethodHolder.setDirectMethod(i, newMethod);
          return;
        }
      }
      assert false
          : "Unexpected failure to find direct lambda target for: " + implMethod.qualifiedName();
    }
  }

  // Used for instance private lambda$ methods which need to be converted to public methods.
  private class InstanceLambdaImplTarget extends Target {

    InstanceLambdaImplTarget(DexMethod staticMethod) {
      super(staticMethod, Type.VIRTUAL);
    }

    @Override
    void ensureAccessibility(IRConverter converter, OptimizationFeedback feedback) {
      // For all instantiation points for which the compiler creates lambda$
      // methods, it creates these methods in the same class/interface.
      DexMethod implMethod = descriptor.implHandle.asMethod();
      DexClass implMethodHolder = definitionFor(implMethod.holder);

      List<DexEncodedMethod> oldDirectMethods = implMethodHolder.directMethods();
      for (int i = 0; i < oldDirectMethods.size(); i++) {
        DexEncodedMethod encodedMethod = oldDirectMethods.get(i);
        if (implMethod.match(encodedMethod)) {
          // We need to create a new method with the same code to be able to safely relax its
          // accessibility and make it virtual.
          MethodAccessFlags newAccessFlags = encodedMethod.accessFlags.copy();
          newAccessFlags.unsetPrivate();
          newAccessFlags.setPublic();
          DexEncodedMethod newMethod =
              new DexEncodedMethod(
                  callTarget,
                  newAccessFlags,
                  encodedMethod.annotations,
                  encodedMethod.parameterAnnotationsList,
                  encodedMethod.getCode(),
                  true);
          newMethod.copyMetadata(encodedMethod, feedback);
          rewriter.methodMapping.put(encodedMethod.method, callTarget);
          // Move the method from the direct methods to the virtual methods set.
          implMethodHolder.removeDirectMethod(i);
          implMethodHolder.appendVirtualMethod(newMethod);
          return;
        }
      }
    }
  }

  // Used for instance/static methods or constructors accessed via
  // synthesized accessor method. Needs accessor method to be created.
  private class ClassMethodWithAccessorTarget extends Target {

    ClassMethodWithAccessorTarget(DexMethod accessorMethod) {
      super(accessorMethod, Invoke.Type.STATIC);
    }

    @Override
    void ensureAccessibility(IRConverter converter, OptimizationFeedback feedback) {
      // Create a static accessor with proper accessibility.
      DexProgramClass accessorClass = programDefinitionFor(callTarget.holder);
      assert accessorClass != null;

      // Always make the method public to provide access when r8 minification is allowed to move
      // the lambda class accessing this method to another package (-allowaccessmodification).
      MethodAccessFlags accessorFlags =
          MethodAccessFlags.fromSharedAccessFlags(
              Constants.ACC_SYNTHETIC | Constants.ACC_STATIC | Constants.ACC_PUBLIC,
              false);
      DexEncodedMethod accessorEncodedMethod =
          new DexEncodedMethod(
              callTarget,
              accessorFlags,
              DexAnnotationSet.empty(),
              ParameterAnnotationsList.empty(),
              new SynthesizedCode(
                  callerPosition ->
                      new AccessorMethodSourceCode(LambdaClass.this, callerPosition)),
              true);

      // We may arrive here concurrently so we need must update the methods of the class atomically.
      synchronized (accessorClass) {
        accessorClass.appendDirectMethod(accessorEncodedMethod);
      }

      converter.optimizeSynthesizedMethod(accessorEncodedMethod);
    }
  }
}
