Revert R8 Nest based desugaring to use map

- We cannot use definitionFor in the Lens
  since the program has changed.
- We need to keep maps to correctly remap fields/
  methods.
- Fix bug where lookupMethod(DexMethod) was called in cases
  where the lens+method is context sensitive

Bug:132770201
Change-Id: I8207e8bea3fe3870ce9248276fa9cdada444c385
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index c79e13a..2530225 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.utils.ThreadUtils;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
@@ -62,7 +63,7 @@
           DexMethod methodCalled = invokeMethod.getInvokedMethod();
           DexEncodedMethod encodedMethodCalled = appView.definitionFor(methodCalled);
           if (encodedMethodCalled != null
-              && invokeRequiresRewriting(encodedMethodCalled, currentClass, appView)) {
+              && invokeRequiresRewriting(encodedMethodCalled, currentClass)) {
             DexMethod bridge = ensureInvokeBridge(encodedMethodCalled);
             if (encodedMethodCalled.isInstanceInitializer()) {
               instructions.previous();
@@ -82,8 +83,7 @@
         } else if (instruction.isFieldInstruction()) {
           DexEncodedField encodedField =
               appView.definitionFor(instruction.asFieldInstruction().getField());
-          if (encodedField != null
-              && fieldAccessRequiresRewriting(encodedField, currentClass, appView)) {
+          if (encodedField != null && fieldAccessRequiresRewriting(encodedField, currentClass)) {
             if (instruction.isInstanceGet() || instruction.isStaticGet()) {
               DexMethod bridge = ensureFieldAccessBridge(encodedField, true);
               instructions.replaceCurrentInstruction(
@@ -108,6 +108,32 @@
     ThreadUtils.awaitFutures(futures);
   }
 
+  private void addDeferredBridges() {
+    addDeferredBridges(bridges.values());
+    addDeferredBridges(getFieldBridges.values());
+    addDeferredBridges(putFieldBridges.values());
+  }
+
+  private void addDeferredBridges(Collection<DexEncodedMethod> bridges) {
+    for (DexEncodedMethod bridge : bridges) {
+      DexClass holder = definitionFor(bridge.method.holder);
+      assert holder != null && holder.isProgramClass();
+      holder.asProgramClass().addMethod(bridge);
+    }
+  }
+
+  private void optimizeDeferredBridgesConcurrently(
+      ExecutorService executorService, IRConverter converter) throws ExecutionException {
+    List<Future<?>> futures =
+        new ArrayList<>(bridges.size() + getFieldBridges.size() + putFieldBridges.size());
+    converter.optimizeSynthesizedMethodsConcurrently(bridges.values(), executorService, futures);
+    converter.optimizeSynthesizedMethodsConcurrently(
+        getFieldBridges.values(), executorService, futures);
+    converter.optimizeSynthesizedMethodsConcurrently(
+        putFieldBridges.values(), executorService, futures);
+    ThreadUtils.awaitFutures(futures);
+  }
+
   public void desugarNestBasedAccess(
       DexApplication.Builder<?> builder, ExecutorService executorService, IRConverter converter)
       throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 8086767..4b9224c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -19,19 +19,16 @@
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.code.Invoke;
 import com.android.tools.r8.origin.SynthesizedOrigin;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.ThreadUtils;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
@@ -56,9 +53,9 @@
   protected final AppView<?> appView;
   // Following maps are there to avoid creating the bridges multiple times
   // and remember the bridges to add once the nests are processed.
-  private final Map<DexEncodedMethod, DexEncodedMethod> bridges = new ConcurrentHashMap<>();
-  private final Map<DexEncodedField, DexEncodedMethod> getFieldBridges = new ConcurrentHashMap<>();
-  private final Map<DexEncodedField, DexEncodedMethod> putFieldBridges = new ConcurrentHashMap<>();
+  final Map<DexMethod, DexEncodedMethod> bridges = new ConcurrentHashMap<>();
+  final Map<DexField, DexEncodedMethod> getFieldBridges = new ConcurrentHashMap<>();
+  final Map<DexField, DexEncodedMethod> putFieldBridges = new ConcurrentHashMap<>();
   // Common single empty class for nest based private constructors
   private final DexProgramClass nestConstructor;
   private boolean nestConstructorUsed = false;
@@ -72,10 +69,24 @@
     return nestConstructor.type;
   }
 
+  protected DexClass definitionFor(DexType type) {
+    return appView.definitionFor(appView.graphLense().lookupType(type));
+  }
+
+  private DexEncodedMethod definitionFor(
+      DexMethod method, DexMethod context, Invoke.Type invokeType) {
+    return appView.definitionFor(
+        appView.graphLense().lookupMethod(method, context, invokeType).getMethod());
+  }
+
+  private DexEncodedField definitionFor(DexField field) {
+    return appView.definitionFor(appView.graphLense().lookupField(field));
+  }
+
   // Extract the list of types in the programClass' nest, of host hostClass
   private List<DexType> extractNest(DexClass clazz) {
     assert clazz != null;
-    DexClass hostClass = clazz.isNestHost() ? clazz : appView.definitionFor(clazz.getNestHost());
+    DexClass hostClass = clazz.isNestHost() ? clazz : definitionFor(clazz.getNestHost());
     if (hostClass == null) {
       reportMissingNestHost(clazz);
       return null;
@@ -93,6 +104,7 @@
     return executorService.submit(
         () -> {
           List<DexType> nest = extractNest(clazz);
+          // Nest is null when nest host is missing, we do nothing in this case.
           if (nest != null) {
             processNest(nest);
           }
@@ -103,7 +115,7 @@
   private void processNest(List<DexType> nest) {
     boolean reported = false;
     for (DexType type : nest) {
-      DexClass clazz = appView.definitionFor(type);
+      DexClass clazz = definitionFor(type);
       if (clazz == null) {
         if (!reported) {
           reportIncompleteNest(nest);
@@ -114,6 +126,7 @@
           NestBasedAccessDesugaringUseRegistry registry =
               new NestBasedAccessDesugaringUseRegistry(clazz);
           for (DexEncodedMethod method : clazz.methods()) {
+            registry.setContext(method.method);
             method.registerCodeReferences(registry);
           }
         }
@@ -123,39 +136,13 @@
 
   protected abstract boolean shouldProcessClassInNest(DexClass clazz, List<DexType> nest);
 
-  void addDeferredBridges() {
-    addDeferredBridges(bridges.values());
-    addDeferredBridges(getFieldBridges.values());
-    addDeferredBridges(putFieldBridges.values());
-  }
-
-  private void addDeferredBridges(Collection<DexEncodedMethod> bridges) {
-    for (DexEncodedMethod bridge : bridges) {
-      DexClass holder = appView.definitionFor(bridge.method.holder);
-      assert holder != null && holder.isProgramClass();
-      holder.asProgramClass().addMethod(bridge);
-    }
-  }
-
-  void optimizeDeferredBridgesConcurrently(ExecutorService executorService, IRConverter converter)
-      throws ExecutionException {
-    List<Future<?>> futures =
-        new ArrayList<>(bridges.size() + getFieldBridges.size() + putFieldBridges.size());
-    converter.optimizeSynthesizedMethodsConcurrently(bridges.values(), executorService, futures);
-    converter.optimizeSynthesizedMethodsConcurrently(
-        getFieldBridges.values(), executorService, futures);
-    converter.optimizeSynthesizedMethodsConcurrently(
-        putFieldBridges.values(), executorService, futures);
-    ThreadUtils.awaitFutures(futures);
-  }
-
   private void reportIncompleteNest(List<DexType> nest) {
     List<String> programClassesFromNest = new ArrayList<>();
     List<String> unavailableClasses = new ArrayList<>();
     List<String> classPathClasses = new ArrayList<>();
     List<String> libraryClasses = new ArrayList<>();
     for (DexType type : nest) {
-      DexClass clazz = appView.definitionFor(type);
+      DexClass clazz = definitionFor(type);
       if (clazz == null) {
         unavailableClasses.add(type.getName());
       } else if (clazz.isLibraryClass()) {
@@ -240,7 +227,7 @@
     return type.getName().equals(NEST_CONSTRUCTOR_NAME);
   }
 
-  private static DexString computeMethodBridgeName(DexEncodedMethod method, AppView<?> appView) {
+  private DexString computeMethodBridgeName(DexEncodedMethod method) {
     String methodName = method.method.name.toString();
     String fullName;
     if (method.isStatic()) {
@@ -251,8 +238,7 @@
     return appView.dexItemFactory().createString(fullName);
   }
 
-  private static DexString computeFieldBridgeName(
-      DexEncodedField field, boolean isGet, AppView<?> appView) {
+  private DexString computeFieldBridgeName(DexEncodedField field, boolean isGet) {
     String fieldName = field.field.name.toString();
     String fullName;
     if (isGet && !field.isStatic()) {
@@ -267,7 +253,7 @@
     return appView.dexItemFactory().createString(fullName);
   }
 
-  static DexMethod computeMethodBridge(DexEncodedMethod encodedMethod, AppView<?> appView) {
+  private DexMethod computeMethodBridge(DexEncodedMethod encodedMethod) {
     DexMethod method = encodedMethod.method;
     DexProto proto =
         encodedMethod.accessFlags.isStatic()
@@ -275,17 +261,16 @@
             : appView.dexItemFactory().prependTypeToProto(method.holder, method.proto);
     return appView
         .dexItemFactory()
-        .createMethod(method.holder, proto, computeMethodBridgeName(encodedMethod, appView));
+        .createMethod(method.holder, proto, computeMethodBridgeName(encodedMethod));
   }
 
-  static DexMethod computeInitializerBridge(
-      DexMethod method, AppView<?> appView, DexType nestConstructorType) {
+  private DexMethod computeInitializerBridge(DexMethod method) {
     DexProto newProto =
-        appView.dexItemFactory().appendTypeToProto(method.proto, nestConstructorType);
+        appView.dexItemFactory().appendTypeToProto(method.proto, nestConstructor.type);
     return appView.dexItemFactory().createMethod(method.holder, newProto, method.name);
   }
 
-  static DexMethod computeFieldBridge(DexEncodedField field, boolean isGet, AppView<?> appView) {
+  private DexMethod computeFieldBridge(DexEncodedField field, boolean isGet) {
     DexType holderType = field.field.holder;
     DexType fieldType = field.field.type;
     int bridgeParameterCount =
@@ -301,29 +286,27 @@
     DexProto proto = appView.dexItemFactory().createProto(returnType, parameters);
     return appView
         .dexItemFactory()
-        .createMethod(holderType, proto, computeFieldBridgeName(field, isGet, appView));
+        .createMethod(holderType, proto, computeFieldBridgeName(field, isGet));
   }
 
-  static boolean invokeRequiresRewriting(
-      DexEncodedMethod method, DexClass contextClass, AppView<?> appView) {
+  boolean invokeRequiresRewriting(DexEncodedMethod method, DexClass contextClass) {
     assert method != null;
     // Rewrite only when targeting other nest members private fields.
     if (!method.accessFlags.isPrivate() || method.method.holder == contextClass.type) {
       return false;
     }
-    DexClass methodHolder = appView.definitionFor(method.method.holder);
+    DexClass methodHolder = definitionFor(method.method.holder);
     assert methodHolder != null; // from encodedMethod
     return methodHolder.getNestHost() == contextClass.getNestHost();
   }
 
-  static boolean fieldAccessRequiresRewriting(
-      DexEncodedField field, DexClass contextClass, AppView<?> appView) {
+  boolean fieldAccessRequiresRewriting(DexEncodedField field, DexClass contextClass) {
     assert field != null;
     // Rewrite only when targeting other nest members private fields.
     if (!field.accessFlags.isPrivate() || field.field.holder == contextClass.type) {
       return false;
     }
-    DexClass fieldHolder = appView.definitionFor(field.field.holder);
+    DexClass fieldHolder = definitionFor(field.field.holder);
     assert fieldHolder != null; // from encodedField
     return fieldHolder.getNestHost() == contextClass.getNestHost();
   }
@@ -345,17 +328,17 @@
   }
 
   DexMethod ensureFieldAccessBridge(DexEncodedField field, boolean isGet) {
-    DexClass holder = appView.definitionFor(field.field.holder);
+    DexClass holder = definitionFor(field.field.holder);
     assert holder != null;
-    DexMethod bridgeMethod = computeFieldBridge(field, isGet, appView);
+    DexMethod bridgeMethod = computeFieldBridge(field, isGet);
     if (holderRequiresBridge(holder)) {
       return bridgeMethod;
     }
     // The map is used to avoid creating multiple times the bridge
     // and remembers the bridges to add.
-    Map<DexEncodedField, DexEncodedMethod> fieldMap = isGet ? getFieldBridges : putFieldBridges;
+    Map<DexField, DexEncodedMethod> fieldMap = isGet ? getFieldBridges : putFieldBridges;
     fieldMap.computeIfAbsent(
-        field,
+        field.field,
         k ->
             DexEncodedMethod.createFieldAccessorBridge(
                 new DexFieldWithAccess(field, isGet), holder, bridgeMethod));
@@ -364,14 +347,14 @@
 
   DexMethod ensureInvokeBridge(DexEncodedMethod method) {
     // We add bridges only when targeting other nest members.
-    DexClass holder = appView.definitionFor(method.method.holder);
+    DexClass holder = definitionFor(method.method.holder);
     assert holder != null;
     DexMethod bridgeMethod;
     if (method.isInstanceInitializer()) {
       nestConstructorUsed = true;
-      bridgeMethod = computeInitializerBridge(method.method, appView, nestConstructor.type);
+      bridgeMethod = computeInitializerBridge(method.method);
     } else {
-      bridgeMethod = computeMethodBridge(method, appView);
+      bridgeMethod = computeMethodBridge(method);
     }
     if (holderRequiresBridge(holder)) {
       return bridgeMethod;
@@ -379,26 +362,31 @@
     // The map is used to avoid creating multiple times the bridge
     // and remembers the bridges to add.
     bridges.computeIfAbsent(
-        method,
+        method.method,
         k ->
             method.isInstanceInitializer()
                 ? method.toInitializerForwardingBridge(holder, bridgeMethod)
-                : method.toStaticForwardingBridge(holder, computeMethodBridge(method, appView)));
+                : method.toStaticForwardingBridge(holder, computeMethodBridge(method)));
     return bridgeMethod;
   }
 
   protected class NestBasedAccessDesugaringUseRegistry extends UseRegistry {
 
     private final DexClass currentClass;
+    private DexMethod context;
 
     NestBasedAccessDesugaringUseRegistry(DexClass currentClass) {
       super(appView.options().itemFactory);
       this.currentClass = currentClass;
     }
 
-    private boolean registerInvoke(DexMethod method) {
-      DexEncodedMethod encodedMethod = appView.definitionFor(method);
-      if (encodedMethod != null && invokeRequiresRewriting(encodedMethod, currentClass, appView)) {
+    public void setContext(DexMethod context) {
+      this.context = context;
+    }
+
+    private boolean registerInvoke(DexMethod method, Invoke.Type invokeType) {
+      DexEncodedMethod encodedMethod = definitionFor(method, context, invokeType);
+      if (encodedMethod != null && invokeRequiresRewriting(encodedMethod, currentClass)) {
         ensureInvokeBridge(encodedMethod);
         return true;
       }
@@ -406,9 +394,8 @@
     }
 
     private boolean registerFieldAccess(DexField field, boolean isGet) {
-      DexEncodedField encodedField = appView.definitionFor(field);
-      if (encodedField != null
-          && fieldAccessRequiresRewriting(encodedField, currentClass, appView)) {
+      DexEncodedField encodedField = definitionFor(field);
+      if (encodedField != null && fieldAccessRequiresRewriting(encodedField, currentClass)) {
         ensureFieldAccessBridge(encodedField, isGet);
         return true;
       }
@@ -419,24 +406,24 @@
     public boolean registerInvokeVirtual(DexMethod method) {
       // Calls to class nest mate private methods are targeted by invokeVirtual in jdk11.
       // The spec recommends to do so, but do not enforce it, hence invokeDirect is also registered.
-      return registerInvoke(method);
+      return registerInvoke(method, Invoke.Type.VIRTUAL);
     }
 
     @Override
     public boolean registerInvokeDirect(DexMethod method) {
-      return registerInvoke(method);
+      return registerInvoke(method, Invoke.Type.DIRECT);
     }
 
     @Override
     public boolean registerInvokeStatic(DexMethod method) {
-      return registerInvoke(method);
+      return registerInvoke(method, Invoke.Type.STATIC);
     }
 
     @Override
     public boolean registerInvokeInterface(DexMethod method) {
       // Calls to interface nest mate private methods are targeted by invokeInterface in jdk11.
       // The spec recommends to do so, but do not enforce it, hence invokeDirect is also registered.
-      return registerInvoke(method);
+      return registerInvoke(method, Invoke.Type.INTERFACE);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
index c782edf..21d9b9f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLense.java
@@ -1,9 +1,6 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.graph.AppView;
-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.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -11,54 +8,74 @@
 import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.ir.code.Invoke;
 import com.google.common.collect.ImmutableMap;
+import java.util.IdentityHashMap;
+import java.util.Map;
 
 public class NestedPrivateMethodLense extends NestedGraphLense {
 
-  private final AppView<?> appView;
   // Map from nestHost to nest members including nest hosts
   private final DexType nestConstructorType;
+  private final Map<DexField, DexMethod> getFieldMap;
+  private final Map<DexField, DexMethod> putFieldMap;
 
-  public NestedPrivateMethodLense(
+  NestedPrivateMethodLense(
       AppView<?> appView,
       DexType nestConstructorType,
+      Map<DexMethod, DexMethod> methodMap,
+      Map<DexField, DexMethod> getFieldMap,
+      Map<DexField, DexMethod> putFieldMap,
       GraphLense previousLense) {
     super(
         ImmutableMap.of(),
-        ImmutableMap.of(),
+        methodMap,
         ImmutableMap.of(),
         null,
         null,
         previousLense,
         appView.dexItemFactory());
-    this.appView = appView;
+    // No concurrent maps here, we do not want synchronization overhead.
+    assert methodMap instanceof IdentityHashMap;
+    assert getFieldMap instanceof IdentityHashMap;
+    assert putFieldMap instanceof IdentityHashMap;
+    this.getFieldMap = getFieldMap;
+    this.putFieldMap = putFieldMap;
     this.nestConstructorType = nestConstructorType;
   }
 
-  private DexMethod lookupFieldForMethod(DexField field, DexMethod context, boolean isGet) {
-    DexEncodedField encodedField = appView.definitionFor(field);
-    DexClass contextClass = appView.definitionFor(context.holder);
-    assert contextClass != null;
-    if (encodedField != null
-        && NestBasedAccessDesugaring.fieldAccessRequiresRewriting(
-            encodedField, contextClass, appView)) {
-      return NestBasedAccessDesugaring.computeFieldBridge(encodedField, isGet, appView);
+  private DexMethod lookupFieldForMethod(
+      DexField field, DexMethod context, Map<DexField, DexMethod> map) {
+    assert context != null;
+    DexMethod bridge = map.get(field);
+    if (bridge != null && bridge.holder != context.holder) {
+      return bridge;
     }
     return null;
   }
 
   @Override
   public DexMethod lookupGetFieldForMethod(DexField field, DexMethod context) {
-    return lookupFieldForMethod(field, context, true);
+    assert previousLense.lookupGetFieldForMethod(field, context) == null;
+    return lookupFieldForMethod(field, context, getFieldMap);
   }
 
   @Override
   public DexMethod lookupPutFieldForMethod(DexField field, DexMethod context) {
-    return lookupFieldForMethod(field, context, false);
+    assert previousLense.lookupPutFieldForMethod(field, context) == null;
+    return lookupFieldForMethod(field, context, putFieldMap);
   }
 
   @Override
   public boolean isContextFreeForMethods() {
-    return false;
+    return methodMap.isEmpty();
+  }
+
+  @Override
+  public boolean isContextFreeForMethod(DexMethod method) {
+    if (!previousLense.isContextFreeForMethod(method)) {
+      return false;
+    }
+    DexMethod previous = previousLense.lookupMethod(method);
+    return !methodMap.containsKey(previous);
   }
 
   // This is true because mappings specific to this class can be filled.
@@ -67,20 +84,24 @@
     return true;
   }
 
-  @Override
-  public RewrittenPrototypeDescription lookupPrototypeChanges(DexMethod method) {
+  private boolean isConstructorBridge(DexMethod method) {
     DexType[] parameters = method.proto.parameters.values;
     if (parameters.length == 0) {
-      return previousLense.lookupPrototypeChanges(method);
+      return false;
     }
     DexType lastParameterType = parameters[parameters.length - 1];
-    if (lastParameterType == nestConstructorType) {
-      // This is an access bridge for a constructor that has been synthesized during
-      // nest-based access desugaring.
+    return lastParameterType == nestConstructorType;
+  }
+
+  @Override
+  public RewrittenPrototypeDescription lookupPrototypeChanges(DexMethod method) {
+    if (isConstructorBridge(method)) {
+      // TODO (b/132767654): Try to write a test which breaks that assertion.
       assert previousLense.lookupPrototypeChanges(method).isEmpty();
       return RewrittenPrototypeDescription.none().withExtraNullParameter();
+    } else {
+      return previousLense.lookupPrototypeChanges(method);
     }
-    return previousLense.lookupPrototypeChanges(method);
   }
 
   @Override
@@ -91,29 +112,18 @@
             ? originalMethodSignatures.getOrDefault(context, context)
             : context;
     GraphLenseLookupResult previous = previousLense.lookupMethod(method, previousContext, type);
-    if (context == null) {
+    DexMethod bridge = methodMap.get(previous.getMethod());
+    if (bridge == null) {
       return previous;
     }
-    DexEncodedMethod encodedMethod = appView.definitionFor(method);
-    DexClass contextClass = appView.definitionFor(context.holder);
-    assert contextClass != null;
-    if (encodedMethod == null
-        || !NestBasedAccessDesugaring.invokeRequiresRewriting(
-            encodedMethod, contextClass, appView)) {
+    assert context != null : "Guaranteed by isContextFreeForMethod";
+    if (bridge.holder == context.holder) {
       return previous;
     }
-    DexMethod bridge;
-    Invoke.Type invokeType;
-    if (encodedMethod.isInstanceInitializer()) {
-      bridge =
-          NestBasedAccessDesugaring.computeInitializerBridge(method, appView, nestConstructorType);
-      invokeType = Invoke.Type.DIRECT;
-    } else {
-      bridge = NestBasedAccessDesugaring.computeMethodBridge(encodedMethod, appView);
-      invokeType = Invoke.Type.STATIC;
+    if (isConstructorBridge(bridge)) {
+      return new GraphLenseLookupResult(bridge, Invoke.Type.DIRECT);
     }
-
-    return new GraphLenseLookupResult(bridge, invokeType);
+    return new GraphLenseLookupResult(bridge, Invoke.Type.STATIC);
   }
 
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
index 977c7d9..1526505 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
@@ -2,6 +2,9 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLense;
@@ -10,18 +13,22 @@
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
 // Summary:
-// - Computes all the live nests reachable from Program Classes (Sequential).
-// - Process all live nests finding nest based access (Nests processes concurrently).
-// - Add bridges to be processed by further passes (Sequential).
+// - Computes all the live nests reachable from Program Classes (Sequential), each time a
+//  nest is computed, its processing starts concurrently.
+// - Add bridges to be processed by further passes and create the maps
+// for the lens (Sequential)
 public class R8NestBasedAccessDesugaring extends NestBasedAccessDesugaring {
 
-  private boolean atLeast1Nest = false;
+  private final Map<DexMethod, DexMethod> lensBridges = new IdentityHashMap<>();
+  private final Map<DexField, DexMethod> lensGetFieldBridges = new IdentityHashMap<>();
+  private final Map<DexField, DexMethod> lensPutFieldBridges = new IdentityHashMap<>();
 
   public R8NestBasedAccessDesugaring(AppView<?> appView) {
     super(appView);
@@ -32,12 +39,43 @@
       return appView.graphLense();
     }
     computeAndProcessNestsConcurrently(executorService);
-    if (!atLeast1Nest) {
-      // Common path when no class file was generated by JDK11+.
+    addDeferredBridgesAndMapMethods();
+    if (nothingToMap()) {
       return appView.graphLense();
     }
-    addDeferredBridges();
-    return new NestedPrivateMethodLense(appView, getNestConstructorType(), appView.graphLense());
+    return new NestedPrivateMethodLense(
+        appView,
+        getNestConstructorType(),
+        lensBridges,
+        lensGetFieldBridges,
+        lensPutFieldBridges,
+        appView.graphLense());
+  }
+
+  private boolean nothingToMap() {
+    return lensBridges.isEmpty() && lensGetFieldBridges.isEmpty() && lensPutFieldBridges.isEmpty();
+  }
+
+  private void addDeferredBridgesAndMapMethods() {
+    // Here we add the bridges and we fill the lens map.
+    // The lens map are different than the original map since
+    // they refer DexMethod and not DexEncodedMethod (so they can be long lived without issues),
+    // and since they do not require synchronization (they are only read in the lens).
+    // We cannot easily do this concurrently since methods are added to classes.
+    addDeferredBridgesAndMapMethods(bridges, lensBridges);
+    addDeferredBridgesAndMapMethods(getFieldBridges, lensGetFieldBridges);
+    addDeferredBridgesAndMapMethods(putFieldBridges, lensPutFieldBridges);
+  }
+
+  private <E> void addDeferredBridgesAndMapMethods(
+      Map<E, DexEncodedMethod> bridges, Map<E, DexMethod> map) {
+    for (Map.Entry<E, DexEncodedMethod> entry : bridges.entrySet()) {
+      DexClass holder = definitionFor(entry.getValue().method.holder);
+      assert holder != null && holder.isProgramClass();
+      holder.asProgramClass().addMethod(entry.getValue());
+      map.put(entry.getKey(), entry.getValue().method);
+    }
+    bridges.clear();
   }
 
   private void computeAndProcessNestsConcurrently(ExecutorService executorService)
@@ -53,7 +91,6 @@
         DexType hostType = clazz.getNestHost();
         if (!nestHosts.contains(hostType)) {
           nestHosts.add(hostType);
-          atLeast1Nest = true;
           futures.add(asyncProcessNest(clazz, executorService));
         }
       }