Move vertical class merging classes to verticalclassmerging package

Change-Id: Id71b8a2a6870da4452df298d6d8670232dd9fcc6
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 1af471f..53f1446 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -34,7 +34,6 @@
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
 import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.graph.lens.AppliedGraphLens;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.inspector.internal.InspectorImpl;
@@ -105,8 +104,6 @@
 import com.android.tools.r8.shaking.RuntimeTypeCheckInfo;
 import com.android.tools.r8.shaking.TreePruner;
 import com.android.tools.r8.shaking.TreePrunerConfiguration;
-import com.android.tools.r8.shaking.VerticalClassMerger;
-import com.android.tools.r8.shaking.VerticalClassMergerGraphLens;
 import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
 import com.android.tools.r8.synthesis.SyntheticFinalization;
 import com.android.tools.r8.synthesis.SyntheticItems;
@@ -120,6 +117,9 @@
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.verticalclassmerging.VerticalClassMerger;
+import com.android.tools.r8.verticalclassmerging.VerticalClassMergerGraphLens;
+import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses;
 import com.google.common.collect.Iterables;
 import com.google.common.io.ByteStreams;
 import java.io.ByteArrayOutputStream;
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 5093100..4536685 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.graph.DexValue.DexValueString;
 import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis.InitializedClassesInInstanceMethods;
 import com.android.tools.r8.graph.classmerging.MergedClassesCollection;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.lens.InitClassLens;
 import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
@@ -65,6 +64,7 @@
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.threads.ThreadTask;
 import com.android.tools.r8.utils.threads.ThreadTaskUtils;
+import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
index ded7e1d..12ef6dc 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
@@ -16,8 +16,8 @@
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger.Mode;
 import com.android.tools.r8.horizontalclassmerging.MergeGroup;
 import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
-import com.android.tools.r8.shaking.VerticalClassMerger.IllegalAccessDetector;
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.verticalclassmerging.IllegalAccessDetector;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 07ea7c8..e46d250 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -50,7 +50,6 @@
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.graph.lens.FieldLookupResult;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.lens.MethodLookupResult;
@@ -115,6 +114,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.LazyBox;
 import com.android.tools.r8.verticalclassmerging.InterfaceTypeToClassTypeLensCodeRewriterHelper;
+import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses;
 import com.google.common.collect.Sets;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index 46dd4a0..f9c5e5f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -24,8 +24,8 @@
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.VerticalClassMerger.SingleTypeMapperGraphLens;
 import com.android.tools.r8.utils.TriFunction;
+import com.android.tools.r8.verticalclassmerging.VerticalClassMerger.SingleTypeMapperGraphLens;
 
 // Computes the inlining constraint for a given instruction.
 public class InliningConstraints {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index bd85948..1cd2253 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -17,7 +17,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
@@ -48,6 +47,7 @@
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses;
 import com.google.common.collect.Sets;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 4bda905..2bf05d0 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -62,7 +62,6 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.analysis.ResourceAccessAnalysis;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
 import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
 import com.android.tools.r8.horizontalclassmerging.Policy;
@@ -111,6 +110,7 @@
 import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.android.tools.r8.utils.structural.Ordered;
+import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.base.Predicates;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/IllegalAccessDetector.java b/src/main/java/com/android/tools/r8/verticalclassmerging/IllegalAccessDetector.java
new file mode 100644
index 0000000..c71a51d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/IllegalAccessDetector.java
@@ -0,0 +1,207 @@
+package com.android.tools.r8.verticalclassmerging;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndField;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistryWithResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.utils.OptionalBool;
+
+// Searches for a reference to a non-private, non-public class, field or method declared in the
+// same package as [source].
+public class IllegalAccessDetector extends UseRegistryWithResult<Boolean, ProgramMethod> {
+
+  private final AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy;
+
+  public IllegalAccessDetector(
+      AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy,
+      ProgramMethod context) {
+    super(appViewWithClassHierarchy, context, false);
+    this.appViewWithClassHierarchy = appViewWithClassHierarchy;
+  }
+
+  protected boolean checkFoundPackagePrivateAccess() {
+    assert getResult();
+    return true;
+  }
+
+  protected boolean setFoundPackagePrivateAccess() {
+    setResult(true);
+    return true;
+  }
+
+  protected static boolean continueSearchForPackagePrivateAccess() {
+    return false;
+  }
+
+  private boolean checkFieldReference(DexField field) {
+    return checkRewrittenFieldReference(appViewWithClassHierarchy.graphLens().lookupField(field));
+  }
+
+  private boolean checkRewrittenFieldReference(DexField field) {
+    assert field.getHolderType().isClassType();
+    DexType fieldHolder = field.getHolderType();
+    if (fieldHolder.isSamePackage(getContext().getHolderType())) {
+      if (checkRewrittenTypeReference(fieldHolder)) {
+        return checkFoundPackagePrivateAccess();
+      }
+      DexClassAndField resolvedField =
+          appViewWithClassHierarchy.appInfo().resolveField(field).getResolutionPair();
+      if (resolvedField == null) {
+        return setFoundPackagePrivateAccess();
+      }
+      if (resolvedField.getHolder() != getContext().getHolder()
+          && !resolvedField.getAccessFlags().isPublic()) {
+        return setFoundPackagePrivateAccess();
+      }
+      if (checkRewrittenFieldType(resolvedField)) {
+        return checkFoundPackagePrivateAccess();
+      }
+    }
+    return continueSearchForPackagePrivateAccess();
+  }
+
+  protected boolean checkRewrittenFieldType(DexClassAndField field) {
+    return continueSearchForPackagePrivateAccess();
+  }
+
+  private boolean checkRewrittenMethodReference(
+      DexMethod rewrittenMethod, OptionalBool isInterface) {
+    DexType baseType =
+        rewrittenMethod.getHolderType().toBaseType(appViewWithClassHierarchy.dexItemFactory());
+    if (baseType.isClassType() && baseType.isSamePackage(getContext().getHolderType())) {
+      if (checkTypeReference(rewrittenMethod.getHolderType())) {
+        return checkFoundPackagePrivateAccess();
+      }
+      MethodResolutionResult resolutionResult =
+          isInterface.isUnknown()
+              ? appViewWithClassHierarchy
+                  .appInfo()
+                  .unsafeResolveMethodDueToDexFormat(rewrittenMethod)
+              : appViewWithClassHierarchy
+                  .appInfo()
+                  .resolveMethod(rewrittenMethod, isInterface.isTrue());
+      if (!resolutionResult.isSingleResolution()) {
+        return setFoundPackagePrivateAccess();
+      }
+      DexClassAndMethod resolvedMethod = resolutionResult.asSingleResolution().getResolutionPair();
+      if (resolvedMethod.getHolder() != getContext().getHolder()
+          && !resolvedMethod.getAccessFlags().isPublic()) {
+        return setFoundPackagePrivateAccess();
+      }
+    }
+    return continueSearchForPackagePrivateAccess();
+  }
+
+  private boolean checkTypeReference(DexType type) {
+    return internalCheckTypeReference(type, appViewWithClassHierarchy.graphLens());
+  }
+
+  private boolean checkRewrittenTypeReference(DexType type) {
+    return internalCheckTypeReference(type, GraphLens.getIdentityLens());
+  }
+
+  private boolean internalCheckTypeReference(DexType type, GraphLens graphLens) {
+    DexType baseType =
+        graphLens.lookupType(type.toBaseType(appViewWithClassHierarchy.dexItemFactory()));
+    if (baseType.isClassType() && baseType.isSamePackage(getContext().getHolderType())) {
+      DexClass clazz = appViewWithClassHierarchy.definitionFor(baseType);
+      if (clazz == null || !clazz.isPublic()) {
+        return setFoundPackagePrivateAccess();
+      }
+    }
+    return continueSearchForPackagePrivateAccess();
+  }
+
+  @Override
+  public void registerInitClass(DexType clazz) {
+    if (appViewWithClassHierarchy.initClassLens().isFinal()) {
+      // The InitClass lens is always rewritten up until the most recent graph lens, so first map
+      // the class type to the most recent graph lens.
+      DexType rewrittenType = appViewWithClassHierarchy.graphLens().lookupType(clazz);
+      DexField initClassField =
+          appViewWithClassHierarchy.initClassLens().getInitClassField(rewrittenType);
+      checkRewrittenFieldReference(initClassField);
+    } else {
+      checkTypeReference(clazz);
+    }
+  }
+
+  @Override
+  public void registerInvokeVirtual(DexMethod method) {
+    MethodLookupResult lookup =
+        appViewWithClassHierarchy.graphLens().lookupInvokeVirtual(method, getContext());
+    checkRewrittenMethodReference(lookup.getReference(), OptionalBool.FALSE);
+  }
+
+  @Override
+  public void registerInvokeDirect(DexMethod method) {
+    MethodLookupResult lookup =
+        appViewWithClassHierarchy.graphLens().lookupInvokeDirect(method, getContext());
+    checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
+  }
+
+  @Override
+  public void registerInvokeStatic(DexMethod method) {
+    MethodLookupResult lookup =
+        appViewWithClassHierarchy.graphLens().lookupInvokeStatic(method, getContext());
+    checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
+  }
+
+  @Override
+  public void registerInvokeInterface(DexMethod method) {
+    MethodLookupResult lookup =
+        appViewWithClassHierarchy.graphLens().lookupInvokeInterface(method, getContext());
+    checkRewrittenMethodReference(lookup.getReference(), OptionalBool.TRUE);
+  }
+
+  @Override
+  public void registerInvokeSuper(DexMethod method) {
+    MethodLookupResult lookup =
+        appViewWithClassHierarchy.graphLens().lookupInvokeSuper(method, getContext());
+    checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
+  }
+
+  @Override
+  public void registerInstanceFieldWrite(DexField field) {
+    checkFieldReference(field);
+  }
+
+  @Override
+  public void registerInstanceFieldRead(DexField field) {
+    checkFieldReference(field);
+  }
+
+  @Override
+  public void registerNewInstance(DexType type) {
+    checkTypeReference(type);
+  }
+
+  @Override
+  public void registerStaticFieldRead(DexField field) {
+    checkFieldReference(field);
+  }
+
+  @Override
+  public void registerStaticFieldWrite(DexField field) {
+    checkFieldReference(field);
+  }
+
+  @Override
+  public void registerTypeReference(DexType type) {
+    checkTypeReference(type);
+  }
+
+  @Override
+  public void registerInstanceOf(DexType type) {
+    checkTypeReference(type);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/InvokeSpecialToDefaultLibraryMethodUseRegistry.java b/src/main/java/com/android/tools/r8/verticalclassmerging/InvokeSpecialToDefaultLibraryMethodUseRegistry.java
new file mode 100644
index 0000000..2451630
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/InvokeSpecialToDefaultLibraryMethodUseRegistry.java
@@ -0,0 +1,67 @@
+package com.android.tools.r8.verticalclassmerging;
+
+import com.android.tools.r8.graph.AppView;
+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;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistryWithResult;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class InvokeSpecialToDefaultLibraryMethodUseRegistry
+    extends UseRegistryWithResult<Boolean, ProgramMethod> {
+
+  InvokeSpecialToDefaultLibraryMethodUseRegistry(
+      AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
+    super(appView, context, false);
+    assert context.getHolder().isInterface();
+  }
+
+  @Override
+  @SuppressWarnings("ReferenceEquality")
+  public void registerInvokeSpecial(DexMethod method) {
+    ProgramMethod context = getContext();
+    if (method.getHolderType() != context.getHolderType()) {
+      return;
+    }
+
+    DexEncodedMethod definition = context.getHolder().lookupMethod(method);
+    if (definition != null && definition.belongsToVirtualPool()) {
+      setResult(true);
+    }
+  }
+
+  @Override
+  public void registerInitClass(DexType type) {}
+
+  @Override
+  public void registerInvokeDirect(DexMethod method) {}
+
+  @Override
+  public void registerInvokeInterface(DexMethod method) {}
+
+  @Override
+  public void registerInvokeStatic(DexMethod method) {}
+
+  @Override
+  public void registerInvokeSuper(DexMethod method) {}
+
+  @Override
+  public void registerInvokeVirtual(DexMethod method) {}
+
+  @Override
+  public void registerInstanceFieldRead(DexField field) {}
+
+  @Override
+  public void registerInstanceFieldWrite(DexField field) {}
+
+  @Override
+  public void registerStaticFieldRead(DexField field) {}
+
+  @Override
+  public void registerStaticFieldWrite(DexField field) {}
+
+  @Override
+  public void registerTypeReference(DexType type) {}
+}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/SynthesizedBridgeCode.java b/src/main/java/com/android/tools/r8/verticalclassmerging/SynthesizedBridgeCode.java
new file mode 100644
index 0000000..4471ff5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/SynthesizedBridgeCode.java
@@ -0,0 +1,84 @@
+package com.android.tools.r8.verticalclassmerging;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
+import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class SynthesizedBridgeCode extends AbstractSynthesizedCode {
+
+  private DexMethod method;
+  private DexMethod invocationTarget;
+  private InvokeType type;
+  private final boolean isInterface;
+
+  public SynthesizedBridgeCode(
+      DexMethod method, DexMethod invocationTarget, InvokeType type, boolean isInterface) {
+    this.method = method;
+    this.invocationTarget = invocationTarget;
+    this.type = type;
+    this.isInterface = isInterface;
+  }
+
+  public DexMethod getMethod() {
+    return method;
+  }
+
+  public DexMethod getTarget() {
+    return invocationTarget;
+  }
+
+  // By the time the synthesized code object is created, vertical class merging still has not
+  // finished. Therefore it is possible that the method signatures `method` and `invocationTarget`
+  // will change as a result of additional class merging operations. To deal with this, the
+  // vertical class merger explicitly invokes this method to update `method` and `invocation-
+  // Target` when vertical class merging has finished.
+  //
+  // Note that, without this step, these method signatures might refer to intermediate signatures
+  // that are only present in the middle of vertical class merging, which means that the graph
+  // lens will not work properly (since the graph lens generated by vertical class merging only
+  // expects to be applied to method signatures from *before* vertical class merging or *after*
+  // vertical class merging).
+  public void updateMethodSignatures(Function<DexMethod, DexMethod> transformer) {
+    method = transformer.apply(method);
+    invocationTarget = transformer.apply(invocationTarget);
+  }
+
+  @Override
+  public SourceCodeProvider getSourceCodeProvider() {
+    ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
+        ForwardMethodSourceCode.builder(method);
+    forwardSourceCodeBuilder
+        .setReceiver(method.holder)
+        .setTargetReceiver(type.isStatic() ? null : method.holder)
+        .setTarget(invocationTarget)
+        .setInvokeType(type)
+        .setIsInterface(isInterface);
+    return forwardSourceCodeBuilder::build;
+  }
+
+  @Override
+  public Consumer<UseRegistry> getRegistryCallback(DexClassAndMethod method) {
+    return registry -> {
+      assert registry.getTraversalContinuation().shouldContinue();
+      switch (type) {
+        case DIRECT:
+          registry.registerInvokeDirect(invocationTarget);
+          break;
+        case STATIC:
+          registry.registerInvokeStatic(invocationTarget);
+          break;
+        case VIRTUAL:
+          registry.registerInvokeVirtual(invocationTarget);
+          break;
+        default:
+          throw new Unreachable("Unexpected invocation type: " + type);
+      }
+    };
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
rename to src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
index 2211f75..36982c6 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
@@ -1,7 +1,7 @@
 // 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.shaking;
+package com.android.tools.r8.verticalclassmerging;
 
 import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
 import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
@@ -17,15 +17,12 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.features.FeatureSplitBoundaryOptimizationUtils;
 import com.android.tools.r8.graph.AccessControl;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndField;
-import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -57,9 +54,6 @@
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.graph.UseRegistryWithResult;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.graph.fixup.TreeFixerBase;
 import com.android.tools.r8.graph.lens.FieldLookupResult;
 import com.android.tools.r8.graph.lens.GraphLens;
@@ -70,9 +64,11 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
-import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
 import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
+import com.android.tools.r8.shaking.AnnotationFixer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.KeepInfoCollection;
+import com.android.tools.r8.shaking.MainDexInfo;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.CollectionUtils;
 import com.android.tools.r8.utils.FieldSignatureEquivalence;
@@ -108,8 +104,6 @@
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
-import java.util.function.Consumer;
-import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -638,8 +632,8 @@
     if (!profileCollectionAdditions.isNop()) {
       for (SynthesizedBridgeCode synthesizedBridge : synthesizedBridges) {
         profileCollectionAdditions.applyIfContextIsInProfile(
-            lens.getPreviousMethodSignature(synthesizedBridge.method),
-            additionsBuilder -> additionsBuilder.addRule(synthesizedBridge.method));
+            lens.getPreviousMethodSignature(synthesizedBridge.getMethod()),
+            additionsBuilder -> additionsBuilder.addRule(synthesizedBridge.getMethod()));
       }
     }
     profileCollectionAdditions.commit(appView);
@@ -652,9 +646,9 @@
         mutator -> {
           for (SynthesizedBridgeCode synthesizedBridge : synthesizedBridges) {
             ProgramMethod bridge =
-                asProgramMethodOrNull(appView.definitionFor(synthesizedBridge.method));
+                asProgramMethodOrNull(appView.definitionFor(synthesizedBridge.getMethod()));
             ProgramMethod target =
-                asProgramMethodOrNull(appView.definitionFor(synthesizedBridge.invocationTarget));
+                asProgramMethodOrNull(appView.definitionFor(synthesizedBridge.getTarget()));
             if (bridge != null && target != null) {
               mutator.joinMethod(bridge, info -> info.merge(appView.getKeepInfo(target).joiner()));
               continue;
@@ -711,7 +705,7 @@
           // the two methods map back to the same original method, and that the original method
           // can be mapped to the implementation method.
           DexMethod implementationMethod =
-              ((SynthesizedBridgeCode) encodedMethod.getCode()).invocationTarget;
+              ((SynthesizedBridgeCode) encodedMethod.getCode()).getTarget();
           DexMethod originalImplementationMethod =
               graphLens.getOriginalMethodSignature(implementationMethod);
           assert originalMethod == originalImplementationMethod;
@@ -1999,325 +1993,4 @@
       return true;
     }
   }
-
-  // Searches for a reference to a non-private, non-public class, field or method declared in the
-  // same package as [source].
-  public static class IllegalAccessDetector extends UseRegistryWithResult<Boolean, ProgramMethod> {
-
-    private final AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy;
-
-    public IllegalAccessDetector(
-        AppView<? extends AppInfoWithClassHierarchy> appViewWithClassHierarchy,
-        ProgramMethod context) {
-      super(appViewWithClassHierarchy, context, false);
-      this.appViewWithClassHierarchy = appViewWithClassHierarchy;
-    }
-
-    protected boolean checkFoundPackagePrivateAccess() {
-      assert getResult();
-      return true;
-    }
-
-    protected boolean setFoundPackagePrivateAccess() {
-      setResult(true);
-      return true;
-    }
-
-    protected static boolean continueSearchForPackagePrivateAccess() {
-      return false;
-    }
-
-    private boolean checkFieldReference(DexField field) {
-      return checkRewrittenFieldReference(appViewWithClassHierarchy.graphLens().lookupField(field));
-    }
-
-    private boolean checkRewrittenFieldReference(DexField field) {
-      assert field.getHolderType().isClassType();
-      DexType fieldHolder = field.getHolderType();
-      if (fieldHolder.isSamePackage(getContext().getHolderType())) {
-        if (checkRewrittenTypeReference(fieldHolder)) {
-          return checkFoundPackagePrivateAccess();
-        }
-        DexClassAndField resolvedField =
-            appViewWithClassHierarchy.appInfo().resolveField(field).getResolutionPair();
-        if (resolvedField == null) {
-          return setFoundPackagePrivateAccess();
-        }
-        if (resolvedField.getHolder() != getContext().getHolder()
-            && !resolvedField.getAccessFlags().isPublic()) {
-          return setFoundPackagePrivateAccess();
-        }
-        if (checkRewrittenFieldType(resolvedField)) {
-          return checkFoundPackagePrivateAccess();
-        }
-      }
-      return continueSearchForPackagePrivateAccess();
-    }
-
-    protected boolean checkRewrittenFieldType(DexClassAndField field) {
-      return continueSearchForPackagePrivateAccess();
-    }
-
-    private boolean checkRewrittenMethodReference(
-        DexMethod rewrittenMethod, OptionalBool isInterface) {
-      DexType baseType =
-          rewrittenMethod.getHolderType().toBaseType(appViewWithClassHierarchy.dexItemFactory());
-      if (baseType.isClassType() && baseType.isSamePackage(getContext().getHolderType())) {
-        if (checkTypeReference(rewrittenMethod.getHolderType())) {
-          return checkFoundPackagePrivateAccess();
-        }
-        MethodResolutionResult resolutionResult =
-            isInterface.isUnknown()
-                ? appViewWithClassHierarchy
-                    .appInfo()
-                    .unsafeResolveMethodDueToDexFormat(rewrittenMethod)
-                : appViewWithClassHierarchy
-                    .appInfo()
-                    .resolveMethod(rewrittenMethod, isInterface.isTrue());
-        if (!resolutionResult.isSingleResolution()) {
-          return setFoundPackagePrivateAccess();
-        }
-        DexClassAndMethod resolvedMethod =
-            resolutionResult.asSingleResolution().getResolutionPair();
-        if (resolvedMethod.getHolder() != getContext().getHolder()
-            && !resolvedMethod.getAccessFlags().isPublic()) {
-          return setFoundPackagePrivateAccess();
-        }
-      }
-      return continueSearchForPackagePrivateAccess();
-    }
-
-    private boolean checkTypeReference(DexType type) {
-      return internalCheckTypeReference(type, appViewWithClassHierarchy.graphLens());
-    }
-
-    private boolean checkRewrittenTypeReference(DexType type) {
-      return internalCheckTypeReference(type, GraphLens.getIdentityLens());
-    }
-
-    private boolean internalCheckTypeReference(DexType type, GraphLens graphLens) {
-      DexType baseType =
-          graphLens.lookupType(type.toBaseType(appViewWithClassHierarchy.dexItemFactory()));
-      if (baseType.isClassType() && baseType.isSamePackage(getContext().getHolderType())) {
-        DexClass clazz = appViewWithClassHierarchy.definitionFor(baseType);
-        if (clazz == null || !clazz.isPublic()) {
-          return setFoundPackagePrivateAccess();
-        }
-      }
-      return continueSearchForPackagePrivateAccess();
-    }
-
-    @Override
-    public void registerInitClass(DexType clazz) {
-      if (appViewWithClassHierarchy.initClassLens().isFinal()) {
-        // The InitClass lens is always rewritten up until the most recent graph lens, so first map
-        // the class type to the most recent graph lens.
-        DexType rewrittenType = appViewWithClassHierarchy.graphLens().lookupType(clazz);
-        DexField initClassField =
-            appViewWithClassHierarchy.initClassLens().getInitClassField(rewrittenType);
-        checkRewrittenFieldReference(initClassField);
-      } else {
-        checkTypeReference(clazz);
-      }
-    }
-
-    @Override
-    public void registerInvokeVirtual(DexMethod method) {
-      MethodLookupResult lookup =
-          appViewWithClassHierarchy.graphLens().lookupInvokeVirtual(method, getContext());
-      checkRewrittenMethodReference(lookup.getReference(), OptionalBool.FALSE);
-    }
-
-    @Override
-    public void registerInvokeDirect(DexMethod method) {
-      MethodLookupResult lookup =
-          appViewWithClassHierarchy.graphLens().lookupInvokeDirect(method, getContext());
-      checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
-    }
-
-    @Override
-    public void registerInvokeStatic(DexMethod method) {
-      MethodLookupResult lookup =
-          appViewWithClassHierarchy.graphLens().lookupInvokeStatic(method, getContext());
-      checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
-    }
-
-    @Override
-    public void registerInvokeInterface(DexMethod method) {
-      MethodLookupResult lookup =
-          appViewWithClassHierarchy.graphLens().lookupInvokeInterface(method, getContext());
-      checkRewrittenMethodReference(lookup.getReference(), OptionalBool.TRUE);
-    }
-
-    @Override
-    public void registerInvokeSuper(DexMethod method) {
-      MethodLookupResult lookup =
-          appViewWithClassHierarchy.graphLens().lookupInvokeSuper(method, getContext());
-      checkRewrittenMethodReference(lookup.getReference(), OptionalBool.UNKNOWN);
-    }
-
-    @Override
-    public void registerInstanceFieldWrite(DexField field) {
-      checkFieldReference(field);
-    }
-
-    @Override
-    public void registerInstanceFieldRead(DexField field) {
-      checkFieldReference(field);
-    }
-
-    @Override
-    public void registerNewInstance(DexType type) {
-      checkTypeReference(type);
-    }
-
-    @Override
-    public void registerStaticFieldRead(DexField field) {
-      checkFieldReference(field);
-    }
-
-    @Override
-    public void registerStaticFieldWrite(DexField field) {
-      checkFieldReference(field);
-    }
-
-    @Override
-    public void registerTypeReference(DexType type) {
-      checkTypeReference(type);
-    }
-
-    @Override
-    public void registerInstanceOf(DexType type) {
-      checkTypeReference(type);
-    }
-  }
-
-  public static class InvokeSpecialToDefaultLibraryMethodUseRegistry
-      extends UseRegistryWithResult<Boolean, ProgramMethod> {
-
-    InvokeSpecialToDefaultLibraryMethodUseRegistry(
-        AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
-      super(appView, context, false);
-      assert context.getHolder().isInterface();
-    }
-
-    @Override
-    @SuppressWarnings("ReferenceEquality")
-    public void registerInvokeSpecial(DexMethod method) {
-      ProgramMethod context = getContext();
-      if (method.getHolderType() != context.getHolderType()) {
-        return;
-      }
-
-      DexEncodedMethod definition = context.getHolder().lookupMethod(method);
-      if (definition != null && definition.belongsToVirtualPool()) {
-        setResult(true);
-      }
-    }
-
-    @Override
-    public void registerInitClass(DexType type) {}
-
-    @Override
-    public void registerInvokeDirect(DexMethod method) {}
-
-    @Override
-    public void registerInvokeInterface(DexMethod method) {}
-
-    @Override
-    public void registerInvokeStatic(DexMethod method) {}
-
-    @Override
-    public void registerInvokeSuper(DexMethod method) {}
-
-    @Override
-    public void registerInvokeVirtual(DexMethod method) {}
-
-    @Override
-    public void registerInstanceFieldRead(DexField field) {}
-
-    @Override
-    public void registerInstanceFieldWrite(DexField field) {}
-
-    @Override
-    public void registerStaticFieldRead(DexField field) {}
-
-    @Override
-    public void registerStaticFieldWrite(DexField field) {}
-
-    @Override
-    public void registerTypeReference(DexType type) {}
-  }
-
-  public static class SynthesizedBridgeCode extends AbstractSynthesizedCode {
-
-    private DexMethod method;
-    private DexMethod invocationTarget;
-    private InvokeType type;
-    private final boolean isInterface;
-
-    public SynthesizedBridgeCode(
-        DexMethod method,
-        DexMethod invocationTarget,
-        InvokeType type,
-        boolean isInterface) {
-      this.method = method;
-      this.invocationTarget = invocationTarget;
-      this.type = type;
-      this.isInterface = isInterface;
-    }
-
-    // By the time the synthesized code object is created, vertical class merging still has not
-    // finished. Therefore it is possible that the method signatures `method` and `invocationTarget`
-    // will change as a result of additional class merging operations. To deal with this, the
-    // vertical class merger explicitly invokes this method to update `method` and `invocation-
-    // Target` when vertical class merging has finished.
-    //
-    // Note that, without this step, these method signatures might refer to intermediate signatures
-    // that are only present in the middle of vertical class merging, which means that the graph
-    // lens will not work properly (since the graph lens generated by vertical class merging only
-    // expects to be applied to method signatures from *before* vertical class merging or *after*
-    // vertical class merging).
-    public void updateMethodSignatures(Function<DexMethod, DexMethod> transformer) {
-      method = transformer.apply(method);
-      invocationTarget = transformer.apply(invocationTarget);
-    }
-
-    @Override
-    public SourceCodeProvider getSourceCodeProvider() {
-      ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
-          ForwardMethodSourceCode.builder(method);
-      forwardSourceCodeBuilder
-          .setReceiver(method.holder)
-          .setTargetReceiver(type.isStatic() ? null : method.holder)
-          .setTarget(invocationTarget)
-          .setInvokeType(type)
-          .setIsInterface(isInterface);
-      return forwardSourceCodeBuilder::build;
-    }
-
-    @Override
-    public Consumer<UseRegistry> getRegistryCallback(DexClassAndMethod method) {
-      return registry -> {
-        assert registry.getTraversalContinuation().shouldContinue();
-        switch (type) {
-          case DIRECT:
-            registry.registerInvokeDirect(invocationTarget);
-            break;
-          case STATIC:
-            registry.registerInvokeStatic(invocationTarget);
-            break;
-          case VIRTUAL:
-            registry.registerInvokeVirtual(invocationTarget);
-            break;
-          default:
-            throw new Unreachable("Unexpected invocation type: " + type);
-        }
-      };
-    }
-  }
-
-  public Collection<DexType> getRemovedClasses() {
-    return Collections.unmodifiableCollection(mergedClasses.keySet());
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
similarity index 99%
rename from src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
rename to src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
index d4525f0..1a08e65 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
@@ -2,7 +2,7 @@
 // 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.shaking;
+package com.android.tools.r8.verticalclassmerging;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
@@ -11,7 +11,6 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.graph.lens.NestedGraphLens;
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticallyMergedClasses.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java
rename to src/main/java/com/android/tools/r8/verticalclassmerging/VerticallyMergedClasses.java
index 78c6259..d6f3e64 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticallyMergedClasses.java
@@ -2,10 +2,11 @@
 // 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.graph.classmerging;
+package com.android.tools.r8.verticalclassmerging;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.classmerging.MergedClasses;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
 import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java
index d1f04cb..5b8f002 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java
@@ -8,9 +8,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.verticalclassmerging.VerticallyMergedClasses;
 
 public class VerticallyMergedClassesInspector {