Merge "Pass lense from LambdaRewriter to Outliner."
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index d264b87..9b90df2 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -97,6 +97,21 @@
 
   public abstract DexMethod getRenamedMethodSignature(DexMethod originalMethod);
 
+  public final DexEncodedMethod mapDexEncodedMethod(
+      AppInfo appInfo, DexEncodedMethod originalEncodedMethod) {
+    DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.method);
+    if (newMethod != originalEncodedMethod.method) {
+      // We can't directly use AppInfo#definitionFor(DexMethod) since definitions may not be
+      // updated either yet.
+      DexClass newHolder = appInfo.definitionFor(newMethod.holder);
+      assert newHolder != null;
+      DexEncodedMethod newEncodedMethod = newHolder.lookupMethod(newMethod);
+      assert newEncodedMethod != null;
+      return newEncodedMethod;
+    }
+    return originalEncodedMethod;
+  }
+
   public abstract DexType lookupType(DexType type);
 
   // This overload can be used when the graph lense is known to be context insensitive.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index af98f4b..15627e0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -109,7 +109,7 @@
   private final Devirtualizer devirtualizer;
   private final CovariantReturnTypeAnnotationTransformer covariantReturnTypeAnnotationTransformer;
 
-  private final boolean enableWholeProgramOptimizations;
+  public final boolean enableWholeProgramOptimizations;
 
   private final OptimizationFeedback ignoreOptimizationFeedback = new OptimizationFeedbackIgnore();
   private final OptimizationFeedback simpleOptimizationFeedback = new OptimizationFeedbackSimple();
@@ -147,7 +147,7 @@
       assert appInfo.hasLiveness();
       this.nonNullTracker = new NonNullTracker();
       this.inliner = new Inliner(this, options);
-      this.outliner = new Outliner(appInfo.withLiveness(), options);
+      this.outliner = new Outliner(appInfo.withLiveness(), options, this);
       this.memberValuePropagation =
           options.enableValuePropagation ?
               new MemberValuePropagation(appInfo.withLiveness()) : null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index db87d40..2fc5e56 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -510,6 +510,7 @@
                   encodedMethod.annotations,
                   encodedMethod.parameterAnnotationsList,
                   encodedMethod.getCode());
+          rewriter.methodMapping.put(encodedMethod.method, callTarget);
           // TODO(ager): Should we give the new first parameter an actual name? Maybe 'this'?
           DexCode dexCode = newMethod.getCode().asDexCode();
           dexCode.setDebugInfo(dexCode.debugInfoWithAdditionalFirstParameter(null));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 51b8b8a..cb6856c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -27,6 +27,8 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRConverter;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
 import java.util.ArrayList;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -62,6 +64,8 @@
   final DexString deserializeLambdaMethodName;
   final DexProto deserializeLambdaMethodProto;
 
+  final BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
+
   // Maps call sites seen so far to inferred lambda descriptor. It is intended
   // to help avoid re-matching call sites we already seen. Note that same call
   // site may match one or several lambda classes.
@@ -165,8 +169,13 @@
     // referenced symbols to make them accessible. This can result in
     // method access relaxation or creation of accessor method.
     for (LambdaClass lambdaClass : knownLambdaClasses.values()) {
+      // This call may cause methodMapping to be updated.
       lambdaClass.target.ensureAccessibility();
     }
+    if (converter.enableWholeProgramOptimizations && !methodMapping.isEmpty()) {
+      converter.setGraphLense(
+        new LambdaRewriterGraphLense(methodMapping, converter.getGraphLense(), factory));
+    }
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriterGraphLense.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriterGraphLense.java
new file mode 100644
index 0000000..26f890e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriterGraphLense.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2018, 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.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableMap;
+
+class LambdaRewriterGraphLense extends NestedGraphLense {
+
+  LambdaRewriterGraphLense(
+      BiMap<DexMethod, DexMethod> methodMapping, GraphLense previous, DexItemFactory factory) {
+    super(
+        ImmutableMap.of(),
+        methodMapping,
+        ImmutableMap.of(),
+        ImmutableBiMap.of(),
+        methodMapping.inverse(),
+        previous,
+        factory);
+  }
+
+  @Override
+  protected Type mapInvocationType(
+      DexMethod newMethod, DexMethod originalMethod, DexEncodedMethod context, Type type) {
+    if (methodMap.get(originalMethod) == newMethod) {
+      assert type == Type.VIRTUAL || type == Type.DIRECT;
+      return Type.STATIC;
+    }
+    return super.mapInvocationType(newMethod, originalMethod, context, type);
+  }
+
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 5397be4..5a7cba6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -44,6 +44,7 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.conversion.SourceCode;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -108,6 +109,7 @@
 
   final private AppInfoWithLiveness appInfo;
   final private DexItemFactory dexItemFactory;
+  final private IRConverter converter;
   private final InliningConstraints inliningConstraints;
 
   // Representation of an outline.
@@ -818,9 +820,10 @@
     }
   }
 
-  public Outliner(AppInfoWithLiveness appInfo, InternalOptions options) {
+  public Outliner(AppInfoWithLiveness appInfo, InternalOptions options, IRConverter converter) {
     this.appInfo = appInfo;
     this.dexItemFactory = appInfo.dexItemFactory;
+    this.converter = converter;
     this.inliningConstraints = new InliningConstraints(appInfo);
     this.options = options;
   }
@@ -852,7 +855,10 @@
     assert outlineSites.size() == 0;
     for (List<DexEncodedMethod> outlineMethods : candidateMethodLists) {
       if (outlineMethods.size() >= options.outline.threshold) {
-        methodsSelectedForOutlining.addAll(outlineMethods);
+        for (DexEncodedMethod outlineMethod : outlineMethods) {
+          methodsSelectedForOutlining.add(
+              converter.getGraphLense().mapDexEncodedMethod(appInfo, outlineMethod));
+        }
       }
     }
     candidateMethodLists.clear();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
index ea64746..860a913 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
@@ -26,7 +26,6 @@
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -66,7 +65,6 @@
 @RunWith(VmTestRunner.class)
 public class B111893131 extends TestBase {
 
-  @Ignore("b/111893131")
   @Test
   public void test() throws Exception {
     String javaResult = runOnJava(TestClass.class);