Refactor frame types into frame package

Change-Id: I6ce1a2f7dd4f20631fd9424e570da8223a5927c0
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index 934db62..d2c931e 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -51,7 +51,7 @@
 import com.android.tools.r8.cf.code.CfSwitch;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.CfCode;
@@ -201,7 +201,7 @@
   }
 
   private String frameTypeType() {
-    return r8Type("FrameType", ImmutableList.of("cf", "code"));
+    return r8Type("FrameType", ImmutableList.of("cf", "code", "frame"));
   }
 
   private String monitorType() {
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index ee4cb11..0c4a184 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -54,7 +54,7 @@
 import com.android.tools.r8.cf.code.CfSwitch.Kind;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
index f60df0b..dc247a4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.cf.code;
 
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
 import com.android.tools.r8.cf.code.frame.SingleFrameType;
 import com.android.tools.r8.cf.code.frame.WideFrameType;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index f372c06..8d00469 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -6,13 +6,9 @@
 import static org.objectweb.asm.Opcodes.F_NEW;
 
 import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.frame.InitializedFrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
-import com.android.tools.r8.cf.code.frame.PrimitiveFrameType;
-import com.android.tools.r8.cf.code.frame.SingleFrameType;
-import com.android.tools.r8.cf.code.frame.WideFrameType;
-import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
@@ -50,205 +46,6 @@
   public static final Int2ObjectSortedMap<FrameType> EMPTY_LOCALS = Int2ObjectSortedMaps.emptyMap();
   public static final Deque<PreciseFrameType> EMPTY_STACK = ImmutableDeque.of();
 
-  private abstract static class BaseFrameType implements FrameType {
-
-    @Override
-    public boolean isBoolean() {
-      return false;
-    }
-
-    @Override
-    public boolean isByte() {
-      return false;
-    }
-
-    @Override
-    public boolean isChar() {
-      return false;
-    }
-
-    @Override
-    public boolean isDouble() {
-      return false;
-    }
-
-    @Override
-    public boolean isFloat() {
-      return false;
-    }
-
-    @Override
-    public boolean isInt() {
-      return false;
-    }
-
-    @Override
-    public boolean isLong() {
-      return false;
-    }
-
-    @Override
-    public boolean isShort() {
-      return false;
-    }
-
-    @Override
-    public boolean isNullType() {
-      return false;
-    }
-
-    @Override
-    public boolean isObject() {
-      return false;
-    }
-
-    @Override
-    public DexType getObjectType(DexType context) {
-      assert false : "Unexpected use of getObjectType() for non-object FrameType";
-      return null;
-    }
-
-    @Override
-    public boolean isPrecise() {
-      assert isOneWord() || isTwoWord();
-      return false;
-    }
-
-    @Override
-    public PreciseFrameType asPrecise() {
-      assert isOneWord() || isTwoWord();
-      return null;
-    }
-
-    @Override
-    public boolean isPrimitive() {
-      return false;
-    }
-
-    @Override
-    public PrimitiveFrameType asPrimitive() {
-      return null;
-    }
-
-    @Override
-    public final boolean isSingle() {
-      return !isWide();
-    }
-
-    @Override
-    public SingleFrameType asSingle() {
-      return null;
-    }
-
-    @Override
-    public SinglePrimitiveFrameType asSinglePrimitive() {
-      return null;
-    }
-
-    @Override
-    public InitializedReferenceFrameType asInitializedReferenceType() {
-      return null;
-    }
-
-    @Override
-    public boolean isWide() {
-      return false;
-    }
-
-    @Override
-    public WideFrameType asWide() {
-      return null;
-    }
-
-    @Override
-    public int getWidth() {
-      assert isSingle();
-      return 1;
-    }
-
-    @Override
-    public boolean isUninitializedNew() {
-      return false;
-    }
-
-    @Override
-    public UninitializedNew asUninitializedNew() {
-      return null;
-    }
-
-    @Override
-    public boolean isUninitialized() {
-      return false;
-    }
-
-    @Override
-    public UninitializedFrameType asUninitialized() {
-      return null;
-    }
-
-    @Override
-    public CfLabel getUninitializedLabel() {
-      return null;
-    }
-
-    @Override
-    public boolean isUninitializedThis() {
-      return false;
-    }
-
-    @Override
-    public UninitializedThis asUninitializedThis() {
-      return null;
-    }
-
-    @Override
-    public boolean isInitialized() {
-      return false;
-    }
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return null;
-    }
-
-    @Override
-    public DexType getUninitializedNewType() {
-      return null;
-    }
-
-    @Override
-    public boolean isOneWord() {
-      return false;
-    }
-
-    @Override
-    public boolean isTwoWord() {
-      return false;
-    }
-
-    private BaseFrameType() {}
-
-    @Override
-    public abstract boolean equals(Object obj);
-
-    @Override
-    public abstract int hashCode();
-
-  }
-
-  public abstract static class SingletonFrameType extends BaseFrameType {
-
-    @Override
-    public final boolean equals(Object obj) {
-      return this == obj;
-    }
-
-    @Override
-    public final int hashCode() {
-      return System.identityHashCode(this);
-    }
-  }
-
   @Override
   public boolean isFrame() {
     return true;
@@ -272,723 +69,6 @@
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
   }
 
-  public abstract static class SinglePrimitiveFrameType extends SingletonFrameType
-      implements PrimitiveFrameType, SingleFrameType {
-
-    public boolean hasIntVerificationType() {
-      return false;
-    }
-
-    @Override
-    public final boolean isInitialized() {
-      return true;
-    }
-
-    @Override
-    public final boolean isPrecise() {
-      return true;
-    }
-
-    @Override
-    public PreciseFrameType asPrecise() {
-      return this;
-    }
-
-    @Override
-    public final boolean isPrimitive() {
-      return true;
-    }
-
-    @Override
-    public PrimitiveFrameType asPrimitive() {
-      return this;
-    }
-
-    @Override
-    public final SingleFrameType asSingle() {
-      return this;
-    }
-
-    @Override
-    public final SinglePrimitiveFrameType asSinglePrimitive() {
-      return this;
-    }
-
-    @Override
-    public final SingleFrameType join(SingleFrameType frameType) {
-      if (this == frameType) {
-        return this;
-      }
-      if (hasIntVerificationType()
-          && frameType.isPrimitive()
-          && frameType.asSinglePrimitive().hasIntVerificationType()) {
-        return FrameType.intType();
-      }
-      return FrameType.oneWord();
-    }
-
-    @Override
-    public final String toString() {
-      return getTypeName();
-    }
-  }
-
-  public static class BooleanFrameType extends SinglePrimitiveFrameType {
-
-    static final BooleanFrameType SINGLETON = new BooleanFrameType();
-
-    private BooleanFrameType() {}
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.booleanType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "boolean";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      throw new Unreachable("Unexpected value type: " + this);
-    }
-
-    @Override
-    public boolean hasIntVerificationType() {
-      return true;
-    }
-
-    @Override
-    public boolean isBoolean() {
-      return true;
-    }
-  }
-
-  public static class ByteFrameType extends SinglePrimitiveFrameType {
-
-    static final ByteFrameType SINGLETON = new ByteFrameType();
-
-    private ByteFrameType() {}
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.byteType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "byte";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      throw new Unreachable("Unexpected value type: " + this);
-    }
-
-    @Override
-    public boolean hasIntVerificationType() {
-      return true;
-    }
-
-    @Override
-    public boolean isByte() {
-      return true;
-    }
-  }
-
-  public static class CharFrameType extends SinglePrimitiveFrameType {
-
-    static final CharFrameType SINGLETON = new CharFrameType();
-
-    private CharFrameType() {}
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.charType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "char";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      throw new Unreachable("Unexpected value type: " + this);
-    }
-
-    @Override
-    public boolean hasIntVerificationType() {
-      return true;
-    }
-
-    @Override
-    public boolean isChar() {
-      return true;
-    }
-  }
-
-  public static class FloatFrameType extends SinglePrimitiveFrameType {
-
-    static final FloatFrameType SINGLETON = new FloatFrameType();
-
-    private FloatFrameType() {}
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.floatType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "float";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.FLOAT;
-    }
-
-    @Override
-    public boolean isFloat() {
-      return true;
-    }
-  }
-
-  public static class IntFrameType extends SinglePrimitiveFrameType {
-
-    static final IntFrameType SINGLETON = new IntFrameType();
-
-    private IntFrameType() {}
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.intType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "int";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.INTEGER;
-    }
-
-    @Override
-    public boolean hasIntVerificationType() {
-      return true;
-    }
-
-    @Override
-    public boolean isInt() {
-      return true;
-    }
-  }
-
-  public static class ShortFrameType extends SinglePrimitiveFrameType {
-
-    static final ShortFrameType SINGLETON = new ShortFrameType();
-
-    private ShortFrameType() {}
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.shortType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "short";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      throw new Unreachable("Unexpected value type: " + this);
-    }
-
-    @Override
-    public boolean hasIntVerificationType() {
-      return true;
-    }
-
-    @Override
-    public boolean isShort() {
-      return true;
-    }
-  }
-
-  public static class InitializedReferenceFrameType extends BaseFrameType
-      implements InitializedFrameType, SingleFrameType {
-
-    private final DexType type;
-
-    InitializedReferenceFrameType(DexType type) {
-      assert type != null;
-      assert type.isReferenceType();
-      this.type = type;
-    }
-
-    @Override
-    public boolean isPrecise() {
-      return true;
-    }
-
-    @Override
-    public PreciseFrameType asPrecise() {
-      return this;
-    }
-
-    @Override
-    public InitializedReferenceFrameType asInitializedReferenceType() {
-      return this;
-    }
-
-    @Override
-    public SingleFrameType join(SingleFrameType frameType) {
-      if (equals(frameType)) {
-        return this;
-      }
-      if (frameType.isOneWord() || frameType.isPrimitive() || frameType.isUninitialized()) {
-        return FrameType.oneWord();
-      }
-      DexType otherType = frameType.asInitializedReferenceType().getInitializedType();
-      assert type != otherType;
-      assert type.isReferenceType();
-      if (isNullType()) {
-        return otherType.isReferenceType() ? frameType : FrameType.oneWord();
-      }
-      if (frameType.isNullType()) {
-        return this;
-      }
-      assert type.isArrayType() || type.isClassType();
-      assert otherType.isArrayType() || otherType.isClassType();
-      // TODO(b/214496607): Implement join of different reference types using class hierarchy.
-      throw new Unimplemented();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-      if (obj == null || getClass() != obj.getClass()) {
-        return false;
-      }
-      InitializedReferenceFrameType initializedType = (InitializedReferenceFrameType) obj;
-      return type == initializedType.type;
-    }
-
-    @Override
-    public int hashCode() {
-      return type.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return "Initialized(" + type.toString() + ")";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      DexType rewrittenType = graphLens.lookupType(type);
-      if (rewrittenType == DexItemFactory.nullValueType) {
-        return Opcodes.NULL;
-      }
-      switch (rewrittenType.toShorty()) {
-        case 'L':
-          return namingLens.lookupInternalName(rewrittenType);
-        case 'I':
-          return Opcodes.INTEGER;
-        case 'F':
-          return Opcodes.FLOAT;
-        case 'J':
-          return Opcodes.LONG;
-        case 'D':
-          return Opcodes.DOUBLE;
-        default:
-          throw new Unreachable("Unexpected value type: " + rewrittenType);
-      }
-    }
-
-    @Override
-    public SingleFrameType asSingle() {
-      return this;
-    }
-
-    @Override
-    public boolean isWide() {
-      return false;
-    }
-
-    @Override
-    public boolean isInitialized() {
-      return true;
-    }
-
-    public DexType getInitializedType() {
-      return type;
-    }
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return getInitializedType();
-    }
-
-    @Override
-    public boolean isNullType() {
-      return type.isNullValueType();
-    }
-
-    @Override
-    public boolean isObject() {
-      return type.isReferenceType();
-    }
-
-    @Override
-    public DexType getObjectType(DexType context) {
-      assert isObject() : "Unexpected use of getObjectType() for non-object FrameType";
-      return type;
-    }
-  }
-
-  public abstract static class WidePrimitiveFrameType extends SingletonFrameType
-      implements PrimitiveFrameType, WideFrameType {
-
-    @Override
-    public boolean isInitialized() {
-      return true;
-    }
-
-    @Override
-    public boolean isPrecise() {
-      return true;
-    }
-
-    @Override
-    public PreciseFrameType asPrecise() {
-      return this;
-    }
-
-    @Override
-    public boolean isPrimitive() {
-      return true;
-    }
-
-    @Override
-    public PrimitiveFrameType asPrimitive() {
-      return this;
-    }
-
-    @Override
-    public boolean isWide() {
-      return true;
-    }
-
-    @Override
-    public WideFrameType asWide() {
-      return this;
-    }
-
-    @Override
-    public int getWidth() {
-      return 2;
-    }
-
-    @Override
-    public WideFrameType join(WideFrameType frameType) {
-      return this == frameType ? this : FrameType.twoWord();
-    }
-
-    @Override
-    public final String toString() {
-      return getTypeName();
-    }
-  }
-
-  public static class DoubleFrameType extends WidePrimitiveFrameType {
-
-    static final DoubleFrameType SINGLETON = new DoubleFrameType();
-
-    private DoubleFrameType() {}
-
-    @Override
-    public boolean isDouble() {
-      return true;
-    }
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.doubleType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "double";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.DOUBLE;
-    }
-  }
-
-  public static class LongFrameType extends WidePrimitiveFrameType {
-
-    static final LongFrameType SINGLETON = new LongFrameType();
-
-    private LongFrameType() {}
-
-    @Override
-    public boolean isLong() {
-      return true;
-    }
-
-    @Override
-    public DexType getInitializedType(DexItemFactory dexItemFactory) {
-      return dexItemFactory.longType;
-    }
-
-    @Override
-    public String getTypeName() {
-      return "long";
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.LONG;
-    }
-  }
-
-  public abstract static class UninitializedFrameType extends BaseFrameType
-      implements PreciseFrameType, SingleFrameType {
-
-    @Override
-    public boolean isObject() {
-      return true;
-    }
-
-    @Override
-    public boolean isPrecise() {
-      return true;
-    }
-
-    @Override
-    public PreciseFrameType asPrecise() {
-      return this;
-    }
-
-    @Override
-    public SingleFrameType asSingle() {
-      return this;
-    }
-
-    @Override
-    public boolean isUninitialized() {
-      return true;
-    }
-
-    @Override
-    public UninitializedFrameType asUninitialized() {
-      return this;
-    }
-  }
-
-  public static class UninitializedNew extends UninitializedFrameType {
-
-    private final CfLabel label;
-    private final DexType type;
-
-    UninitializedNew(CfLabel label, DexType type) {
-      this.label = label;
-      this.type = type;
-    }
-
-    @Override
-    public DexType getObjectType(DexType context) {
-      return type;
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return label.getLabel();
-    }
-
-    @Override
-    public CfLabel getUninitializedLabel() {
-      return label;
-    }
-
-    @Override
-    public DexType getUninitializedNewType() {
-      return type;
-    }
-
-    @Override
-    public boolean isUninitializedNew() {
-      return true;
-    }
-
-    @Override
-    public UninitializedNew asUninitializedNew() {
-      return this;
-    }
-
-    @Override
-    public SingleFrameType join(SingleFrameType frameType) {
-      return equals(frameType) ? this : FrameType.oneWord();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-      UninitializedNew uninitializedNew = (UninitializedNew) o;
-      return label == uninitializedNew.label && type == uninitializedNew.type;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(label, type);
-    }
-
-    @Override
-    public String toString() {
-      return "uninitialized new";
-    }
-  }
-
-  public static class UninitializedThis extends UninitializedFrameType {
-
-    static final UninitializedThis SINGLETON = new UninitializedThis();
-
-    private UninitializedThis() {}
-
-    @Override
-    public DexType getObjectType(DexType context) {
-      return context;
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.UNINITIALIZED_THIS;
-    }
-
-    @Override
-    public boolean isUninitializedThis() {
-      return true;
-    }
-
-    @Override
-    public UninitializedThis asUninitializedThis() {
-      return this;
-    }
-
-    @Override
-    public SingleFrameType join(SingleFrameType frameType) {
-      if (this == frameType) {
-        return this;
-      }
-      return FrameType.oneWord();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      return this == obj;
-    }
-
-    @Override
-    public int hashCode() {
-      return System.identityHashCode(this);
-    }
-
-    @Override
-    public String toString() {
-      return "uninitialized this";
-    }
-  }
-
-  public static class OneWord extends SingletonFrameType implements SingleFrameType {
-
-    static final OneWord SINGLETON = new OneWord();
-
-    private OneWord() {}
-
-    @Override
-    public boolean isOneWord() {
-      return true;
-    }
-
-    @Override
-    public SingleFrameType asSingle() {
-      return this;
-    }
-
-    @Override
-    public SingleFrameType join(SingleFrameType frameType) {
-      return this;
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      return Opcodes.TOP;
-    }
-
-    @Override
-    public String toString() {
-      return "oneword";
-    }
-  }
-
-  static class TwoWord extends SingletonFrameType implements WideFrameType {
-
-    static final TwoWord SINGLETON = new TwoWord();
-
-    private TwoWord() {}
-
-    @Override
-    public boolean isTwoWord() {
-      return true;
-    }
-
-    @Override
-    public boolean isWide() {
-      return true;
-    }
-
-    @Override
-    public WideFrameType asWide() {
-      return this;
-    }
-
-    @Override
-    public int getWidth() {
-      return 2;
-    }
-
-    @Override
-    public WideFrameType join(WideFrameType frameType) {
-      // The join of wide with one of {double, long, wide} is wide.
-      return this;
-    }
-
-    @Override
-    public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
-      throw new Unreachable("Should only be used for verification");
-    }
-
-    @Override
-    public String toString() {
-      return "twoword";
-    }
-  }
-
   private final Int2ObjectSortedMap<FrameType> locals;
   private final Deque<PreciseFrameType> stack;
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
index f1154e8..7c73bbb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.code.CfAssignability.AssignabilityResult;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 84358f7..6831f06 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index e9941cf..ec6d665 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.cf.code;
 
 import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCompareHelper;
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/BaseFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/BaseFrameType.java
new file mode 100644
index 0000000..ce9f818
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/BaseFrameType.java
@@ -0,0 +1,194 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+
+public abstract class BaseFrameType implements FrameType {
+
+  @Override
+  public boolean isBoolean() {
+    return false;
+  }
+
+  @Override
+  public boolean isByte() {
+    return false;
+  }
+
+  @Override
+  public boolean isChar() {
+    return false;
+  }
+
+  @Override
+  public boolean isDouble() {
+    return false;
+  }
+
+  @Override
+  public boolean isFloat() {
+    return false;
+  }
+
+  @Override
+  public boolean isInt() {
+    return false;
+  }
+
+  @Override
+  public boolean isLong() {
+    return false;
+  }
+
+  @Override
+  public boolean isShort() {
+    return false;
+  }
+
+  @Override
+  public boolean isNullType() {
+    return false;
+  }
+
+  @Override
+  public boolean isObject() {
+    return false;
+  }
+
+  @Override
+  public DexType getObjectType(DexType context) {
+    assert false : "Unexpected use of getObjectType() for non-object FrameType";
+    return null;
+  }
+
+  @Override
+  public boolean isPrecise() {
+    assert isOneWord() || isTwoWord();
+    return false;
+  }
+
+  @Override
+  public PreciseFrameType asPrecise() {
+    assert isOneWord() || isTwoWord();
+    return null;
+  }
+
+  @Override
+  public boolean isPrimitive() {
+    return false;
+  }
+
+  @Override
+  public PrimitiveFrameType asPrimitive() {
+    return null;
+  }
+
+  @Override
+  public final boolean isSingle() {
+    return !isWide();
+  }
+
+  @Override
+  public SingleFrameType asSingle() {
+    return null;
+  }
+
+  @Override
+  public SinglePrimitiveFrameType asSinglePrimitive() {
+    return null;
+  }
+
+  @Override
+  public InitializedReferenceFrameType asInitializedReferenceType() {
+    return null;
+  }
+
+  @Override
+  public boolean isWide() {
+    return false;
+  }
+
+  @Override
+  public WideFrameType asWide() {
+    return null;
+  }
+
+  @Override
+  public int getWidth() {
+    assert isSingle();
+    return 1;
+  }
+
+  @Override
+  public boolean isUninitializedNew() {
+    return false;
+  }
+
+  @Override
+  public UninitializedNew asUninitializedNew() {
+    return null;
+  }
+
+  @Override
+  public boolean isUninitialized() {
+    return false;
+  }
+
+  @Override
+  public UninitializedFrameType asUninitialized() {
+    return null;
+  }
+
+  @Override
+  public CfLabel getUninitializedLabel() {
+    return null;
+  }
+
+  @Override
+  public boolean isUninitializedThis() {
+    return false;
+  }
+
+  @Override
+  public UninitializedThis asUninitializedThis() {
+    return null;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    return false;
+  }
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return null;
+  }
+
+  @Override
+  public DexType getUninitializedNewType() {
+    return null;
+  }
+
+  @Override
+  public boolean isOneWord() {
+    return false;
+  }
+
+  @Override
+  public boolean isTwoWord() {
+    return false;
+  }
+
+  BaseFrameType() {}
+
+  @Override
+  public abstract boolean equals(Object obj);
+
+  @Override
+  public abstract int hashCode();
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
new file mode 100644
index 0000000..faca255
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class BooleanFrameType extends SinglePrimitiveFrameType {
+
+  static final BooleanFrameType SINGLETON = new BooleanFrameType();
+
+  private BooleanFrameType() {}
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.booleanType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "boolean";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    throw new Unreachable("Unexpected value type: " + this);
+  }
+
+  @Override
+  public boolean hasIntVerificationType() {
+    return true;
+  }
+
+  @Override
+  public boolean isBoolean() {
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
new file mode 100644
index 0000000..c55f98f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class ByteFrameType extends SinglePrimitiveFrameType {
+
+  static final ByteFrameType SINGLETON = new ByteFrameType();
+
+  private ByteFrameType() {}
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.byteType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "byte";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    throw new Unreachable("Unexpected value type: " + this);
+  }
+
+  @Override
+  public boolean hasIntVerificationType() {
+    return true;
+  }
+
+  @Override
+  public boolean isByte() {
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
new file mode 100644
index 0000000..99fadc1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class CharFrameType extends SinglePrimitiveFrameType {
+
+  static final CharFrameType SINGLETON = new CharFrameType();
+
+  private CharFrameType() {}
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.charType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "char";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    throw new Unreachable("Unexpected value type: " + this);
+  }
+
+  @Override
+  public boolean hasIntVerificationType() {
+    return true;
+  }
+
+  @Override
+  public boolean isChar() {
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
new file mode 100644
index 0000000..93c0687
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class DoubleFrameType extends WidePrimitiveFrameType {
+
+  static final DoubleFrameType SINGLETON = new DoubleFrameType();
+
+  private DoubleFrameType() {}
+
+  @Override
+  public boolean isDouble() {
+    return true;
+  }
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.doubleType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "double";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return Opcodes.DOUBLE;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
new file mode 100644
index 0000000..6789e2e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class FloatFrameType extends SinglePrimitiveFrameType {
+
+  static final FloatFrameType SINGLETON = new FloatFrameType();
+
+  private FloatFrameType() {}
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.floatType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "float";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return Opcodes.FLOAT;
+  }
+
+  @Override
+  public boolean isFloat() {
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/FrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
similarity index 77%
rename from src/main/java/com/android/tools/r8/cf/code/FrameType.java
rename to src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
index 93d60f0..6522c7e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/FrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
@@ -2,28 +2,9 @@
 // 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.cf.code;
+package com.android.tools.r8.cf.code.frame;
 
-import com.android.tools.r8.cf.code.CfFrame.BooleanFrameType;
-import com.android.tools.r8.cf.code.CfFrame.ByteFrameType;
-import com.android.tools.r8.cf.code.CfFrame.CharFrameType;
-import com.android.tools.r8.cf.code.CfFrame.DoubleFrameType;
-import com.android.tools.r8.cf.code.CfFrame.FloatFrameType;
-import com.android.tools.r8.cf.code.CfFrame.InitializedReferenceFrameType;
-import com.android.tools.r8.cf.code.CfFrame.IntFrameType;
-import com.android.tools.r8.cf.code.CfFrame.LongFrameType;
-import com.android.tools.r8.cf.code.CfFrame.OneWord;
-import com.android.tools.r8.cf.code.CfFrame.ShortFrameType;
-import com.android.tools.r8.cf.code.CfFrame.SinglePrimitiveFrameType;
-import com.android.tools.r8.cf.code.CfFrame.TwoWord;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedFrameType;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedNew;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedThis;
-import com.android.tools.r8.cf.code.frame.InitializedFrameType;
-import com.android.tools.r8.cf.code.frame.PreciseFrameType;
-import com.android.tools.r8.cf.code.frame.PrimitiveFrameType;
-import com.android.tools.r8.cf.code.frame.SingleFrameType;
-import com.android.tools.r8.cf.code.frame.WideFrameType;
+import com.android.tools.r8.cf.code.CfLabel;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedReferenceFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedReferenceFrameType.java
new file mode 100644
index 0000000..c2a2152
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedReferenceFrameType.java
@@ -0,0 +1,147 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class InitializedReferenceFrameType extends BaseFrameType
+    implements InitializedFrameType, SingleFrameType {
+
+  private final DexType type;
+
+  public InitializedReferenceFrameType(DexType type) {
+    assert type != null;
+    assert type.isReferenceType();
+    this.type = type;
+  }
+
+  @Override
+  public boolean isPrecise() {
+    return true;
+  }
+
+  @Override
+  public PreciseFrameType asPrecise() {
+    return this;
+  }
+
+  @Override
+  public InitializedReferenceFrameType asInitializedReferenceType() {
+    return this;
+  }
+
+  @Override
+  public SingleFrameType join(SingleFrameType frameType) {
+    if (equals(frameType)) {
+      return this;
+    }
+    if (frameType.isOneWord() || frameType.isPrimitive() || frameType.isUninitialized()) {
+      return FrameType.oneWord();
+    }
+    DexType otherType = frameType.asInitializedReferenceType().getInitializedType();
+    assert type != otherType;
+    assert type.isReferenceType();
+    if (isNullType()) {
+      return otherType.isReferenceType() ? frameType : FrameType.oneWord();
+    }
+    if (frameType.isNullType()) {
+      return this;
+    }
+    assert type.isArrayType() || type.isClassType();
+    assert otherType.isArrayType() || otherType.isClassType();
+    // TODO(b/214496607): Implement join of different reference types using class hierarchy.
+    throw new Unimplemented();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null || getClass() != obj.getClass()) {
+      return false;
+    }
+    InitializedReferenceFrameType initializedType = (InitializedReferenceFrameType) obj;
+    return type == initializedType.type;
+  }
+
+  @Override
+  public int hashCode() {
+    return type.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return "Initialized(" + type.toString() + ")";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    DexType rewrittenType = graphLens.lookupType(type);
+    if (rewrittenType == DexItemFactory.nullValueType) {
+      return Opcodes.NULL;
+    }
+    switch (rewrittenType.toShorty()) {
+      case 'L':
+        return namingLens.lookupInternalName(rewrittenType);
+      case 'I':
+        return Opcodes.INTEGER;
+      case 'F':
+        return Opcodes.FLOAT;
+      case 'J':
+        return Opcodes.LONG;
+      case 'D':
+        return Opcodes.DOUBLE;
+      default:
+        throw new Unreachable("Unexpected value type: " + rewrittenType);
+    }
+  }
+
+  @Override
+  public SingleFrameType asSingle() {
+    return this;
+  }
+
+  @Override
+  public boolean isWide() {
+    return false;
+  }
+
+  @Override
+  public boolean isInitialized() {
+    return true;
+  }
+
+  public DexType getInitializedType() {
+    return type;
+  }
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return getInitializedType();
+  }
+
+  @Override
+  public boolean isNullType() {
+    return type.isNullValueType();
+  }
+
+  @Override
+  public boolean isObject() {
+    return type.isReferenceType();
+  }
+
+  @Override
+  public DexType getObjectType(DexType context) {
+    assert isObject() : "Unexpected use of getObjectType() for non-object FrameType";
+    return type;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
new file mode 100644
index 0000000..23fd119
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class IntFrameType extends SinglePrimitiveFrameType {
+
+  static final IntFrameType SINGLETON = new IntFrameType();
+
+  private IntFrameType() {}
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.intType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "int";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return Opcodes.INTEGER;
+  }
+
+  @Override
+  public boolean hasIntVerificationType() {
+    return true;
+  }
+
+  @Override
+  public boolean isInt() {
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
new file mode 100644
index 0000000..1fb59c7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class LongFrameType extends WidePrimitiveFrameType {
+
+  static final LongFrameType SINGLETON = new LongFrameType();
+
+  private LongFrameType() {}
+
+  @Override
+  public boolean isLong() {
+    return true;
+  }
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.longType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "long";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return Opcodes.LONG;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java b/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
new file mode 100644
index 0000000..9ac5082
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class OneWord extends SingletonFrameType implements SingleFrameType {
+
+  static final OneWord SINGLETON = new OneWord();
+
+  private OneWord() {}
+
+  @Override
+  public boolean isOneWord() {
+    return true;
+  }
+
+  @Override
+  public SingleFrameType asSingle() {
+    return this;
+  }
+
+  @Override
+  public SingleFrameType join(SingleFrameType frameType) {
+    return this;
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return Opcodes.TOP;
+  }
+
+  @Override
+  public String toString() {
+    return "oneword";
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java
index cd7673c..aa105e0 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java
@@ -4,10 +4,6 @@
 
 package com.android.tools.r8.cf.code.frame;
 
-import static com.android.tools.r8.cf.code.FrameType.initialized;
-import static com.android.tools.r8.cf.code.FrameType.uninitializedNew;
-
-import com.android.tools.r8.cf.code.FrameType;
 import com.android.tools.r8.graph.DexType;
 import java.util.function.Function;
 
@@ -20,14 +16,14 @@
         DexType type = asInitializedReferenceType().getInitializedType();
         DexType newType = fn.apply(type);
         if (type != newType) {
-          return initialized(newType);
+          return FrameType.initialized(newType);
         }
       }
       if (isUninitializedNew()) {
         DexType type = getUninitializedNewType();
         DexType newType = fn.apply(type);
         if (type != newType) {
-          return uninitializedNew(getUninitializedLabel(), newType);
+          return FrameType.uninitializedNew(getUninitializedLabel(), newType);
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
new file mode 100644
index 0000000..0b64a52
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class ShortFrameType extends SinglePrimitiveFrameType {
+
+  static final ShortFrameType SINGLETON = new ShortFrameType();
+
+  private ShortFrameType() {}
+
+  @Override
+  public DexType getInitializedType(DexItemFactory dexItemFactory) {
+    return dexItemFactory.shortType;
+  }
+
+  @Override
+  public String getTypeName() {
+    return "short";
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    throw new Unreachable("Unexpected value type: " + this);
+  }
+
+  @Override
+  public boolean hasIntVerificationType() {
+    return true;
+  }
+
+  @Override
+  public boolean isShort() {
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
index 92cd068..657d493 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.cf.code.frame;
 
-import com.android.tools.r8.cf.code.FrameType;
 
 public interface SingleFrameType extends FrameType {
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SinglePrimitiveFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SinglePrimitiveFrameType.java
new file mode 100644
index 0000000..69ba4b6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SinglePrimitiveFrameType.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+public abstract class SinglePrimitiveFrameType extends SingletonFrameType
+    implements PrimitiveFrameType, SingleFrameType {
+
+  public boolean hasIntVerificationType() {
+    return false;
+  }
+
+  @Override
+  public final boolean isInitialized() {
+    return true;
+  }
+
+  @Override
+  public final boolean isPrecise() {
+    return true;
+  }
+
+  @Override
+  public PreciseFrameType asPrecise() {
+    return this;
+  }
+
+  @Override
+  public final boolean isPrimitive() {
+    return true;
+  }
+
+  @Override
+  public PrimitiveFrameType asPrimitive() {
+    return this;
+  }
+
+  @Override
+  public final SingleFrameType asSingle() {
+    return this;
+  }
+
+  @Override
+  public final SinglePrimitiveFrameType asSinglePrimitive() {
+    return this;
+  }
+
+  @Override
+  public final SingleFrameType join(SingleFrameType frameType) {
+    if (this == frameType) {
+      return this;
+    }
+    if (hasIntVerificationType()
+        && frameType.isPrimitive()
+        && frameType.asSinglePrimitive().hasIntVerificationType()) {
+      return FrameType.intType();
+    }
+    return FrameType.oneWord();
+  }
+
+  @Override
+  public final String toString() {
+    return getTypeName();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SingletonFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SingletonFrameType.java
new file mode 100644
index 0000000..a8759af
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SingletonFrameType.java
@@ -0,0 +1,18 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+public abstract class SingletonFrameType extends BaseFrameType {
+
+  @Override
+  public final boolean equals(Object obj) {
+    return this == obj;
+  }
+
+  @Override
+  public final int hashCode() {
+    return System.identityHashCode(this);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java b/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
new file mode 100644
index 0000000..23a4ca1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class TwoWord extends SingletonFrameType implements WideFrameType {
+
+  static final TwoWord SINGLETON = new TwoWord();
+
+  private TwoWord() {}
+
+  @Override
+  public boolean isTwoWord() {
+    return true;
+  }
+
+  @Override
+  public boolean isWide() {
+    return true;
+  }
+
+  @Override
+  public WideFrameType asWide() {
+    return this;
+  }
+
+  @Override
+  public int getWidth() {
+    return 2;
+  }
+
+  @Override
+  public WideFrameType join(WideFrameType frameType) {
+    // The join of wide with one of {double, long, wide} is wide.
+    return this;
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    throw new Unreachable("Should only be used for verification");
+  }
+
+  @Override
+  public String toString() {
+    return "twoword";
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedFrameType.java
new file mode 100644
index 0000000..a31453d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedFrameType.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+public abstract class UninitializedFrameType extends BaseFrameType
+    implements PreciseFrameType, SingleFrameType {
+
+  @Override
+  public boolean isObject() {
+    return true;
+  }
+
+  @Override
+  public boolean isPrecise() {
+    return true;
+  }
+
+  @Override
+  public PreciseFrameType asPrecise() {
+    return this;
+  }
+
+  @Override
+  public SingleFrameType asSingle() {
+    return this;
+  }
+
+  @Override
+  public boolean isUninitialized() {
+    return true;
+  }
+
+  @Override
+  public UninitializedFrameType asUninitialized() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
new file mode 100644
index 0000000..03eff42
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import java.util.Objects;
+
+public class UninitializedNew extends UninitializedFrameType {
+
+  private final CfLabel label;
+  private final DexType type;
+
+  public UninitializedNew(CfLabel label, DexType type) {
+    this.label = label;
+    this.type = type;
+  }
+
+  @Override
+  public DexType getObjectType(DexType context) {
+    return type;
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return label.getLabel();
+  }
+
+  @Override
+  public CfLabel getUninitializedLabel() {
+    return label;
+  }
+
+  @Override
+  public DexType getUninitializedNewType() {
+    return type;
+  }
+
+  @Override
+  public boolean isUninitializedNew() {
+    return true;
+  }
+
+  @Override
+  public UninitializedNew asUninitializedNew() {
+    return this;
+  }
+
+  @Override
+  public SingleFrameType join(SingleFrameType frameType) {
+    return equals(frameType) ? this : FrameType.oneWord();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    UninitializedNew uninitializedNew = (UninitializedNew) o;
+    return label == uninitializedNew.label && type == uninitializedNew.type;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(label, type);
+  }
+
+  @Override
+  public String toString() {
+    return "uninitialized new";
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
new file mode 100644
index 0000000..69d1ecb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class UninitializedThis extends UninitializedFrameType {
+
+  static final UninitializedThis SINGLETON = new UninitializedThis();
+
+  private UninitializedThis() {}
+
+  @Override
+  public DexType getObjectType(DexType context) {
+    return context;
+  }
+
+  @Override
+  public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+    return Opcodes.UNINITIALIZED_THIS;
+  }
+
+  @Override
+  public boolean isUninitializedThis() {
+    return true;
+  }
+
+  @Override
+  public UninitializedThis asUninitializedThis() {
+    return this;
+  }
+
+  @Override
+  public SingleFrameType join(SingleFrameType frameType) {
+    if (this == frameType) {
+      return this;
+    }
+    return FrameType.oneWord();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    return this == obj;
+  }
+
+  @Override
+  public int hashCode() {
+    return System.identityHashCode(this);
+  }
+
+  @Override
+  public String toString() {
+    return "uninitialized this";
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java
index 4dad0f5..d780cf4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.cf.code.frame;
 
-import com.android.tools.r8.cf.code.FrameType;
 
 public interface WideFrameType extends FrameType {
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/WidePrimitiveFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/WidePrimitiveFrameType.java
new file mode 100644
index 0000000..11f7b75
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/WidePrimitiveFrameType.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2022, 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.cf.code.frame;
+
+public abstract class WidePrimitiveFrameType extends SingletonFrameType
+    implements PrimitiveFrameType, WideFrameType {
+
+  @Override
+  public boolean isInitialized() {
+    return true;
+  }
+
+  @Override
+  public boolean isPrecise() {
+    return true;
+  }
+
+  @Override
+  public PreciseFrameType asPrecise() {
+    return this;
+  }
+
+  @Override
+  public boolean isPrimitive() {
+    return true;
+  }
+
+  @Override
+  public PrimitiveFrameType asPrimitive() {
+    return this;
+  }
+
+  @Override
+  public boolean isWide() {
+    return true;
+  }
+
+  @Override
+  public WideFrameType asWide() {
+    return this;
+  }
+
+  @Override
+  public int getWidth() {
+    return 2;
+  }
+
+  @Override
+  public WideFrameType join(WideFrameType frameType) {
+    return this == frameType ? this : FrameType.twoWord();
+  }
+
+  @Override
+  public final String toString() {
+    return getTypeName();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 7ef054e..42d0bcd 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -17,7 +17,7 @@
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.cf.code.CfReturnVoid;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.dex.code.DexBase5Format;
 import com.android.tools.r8.errors.InvalidDebugInfoException;
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index f2cc9f2..d18e823 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.cf.code.CfConstString;
 import com.android.tools.r8.cf.code.CfFieldInstruction;
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedNew;
 import com.android.tools.r8.cf.code.CfGoto;
 import com.android.tools.r8.cf.code.CfIf;
 import com.android.tools.r8.cf.code.CfIfCmp;
@@ -46,8 +45,9 @@
 import com.android.tools.r8.cf.code.CfSwitch;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedNew;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index 79fc829..8c29b17 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.cf.code.CfReturnVoid;
 import com.android.tools.r8.cf.code.CfSwitch;
 import com.android.tools.r8.cf.code.CfSwitch.Kind;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 043024f..e6228f7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -13,14 +13,14 @@
 import com.android.tools.r8.cf.TypeVerificationHelper.ThisInstanceInfo;
 import com.android.tools.r8.cf.TypeVerificationHelper.TypeInfo;
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedFrameType;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfLabel;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index f800b05..86fa768 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.cf.code.CfSwitch;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
 import com.android.tools.r8.errors.InvalidDebugInfoException;
 import com.android.tools.r8.errors.Unreachable;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java
index b02284c..0aa439a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java
@@ -23,7 +23,7 @@
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index 9cfdc04..324ecfa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -38,7 +38,7 @@
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index fa6d469..00892fa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -30,7 +30,7 @@
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java
index 5143b7e..e46b8d6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java
@@ -26,7 +26,7 @@
 import com.android.tools.r8.cf.code.CfReturn;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStore;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
index 9718b1b..527fb13 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
@@ -27,7 +27,7 @@
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStore;
 import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java b/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
index 1ae27d7..162a1cc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
@@ -17,7 +17,7 @@
 import com.android.tools.r8.cf.code.CfReturnVoid;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
index dd1f19d..2852ce9 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.cf.code.CfLoad;
 import com.android.tools.r8.cf.code.CfReturn;
 import com.android.tools.r8.cf.code.CfReturnVoid;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index 74f4dea..34e3f71 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -21,7 +21,7 @@
 import com.android.tools.r8.cf.code.CfStaticFieldRead;
 import com.android.tools.r8.cf.code.CfStaticFieldWrite;
 import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
index 223f6c7..f328c2c 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.cf.code.CfRecordFieldValues;
 import com.android.tools.r8.cf.code.CfReturn;
 import com.android.tools.r8.cf.code.CfStore;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexField;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
index 4671d3d..10e267b 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
@@ -28,7 +28,7 @@
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStaticFieldRead;
 import com.android.tools.r8.cf.code.CfStore;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexEncodedField;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
index b05f3c2..5c9e671 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
@@ -5,9 +5,9 @@
 package com.android.tools.r8.optimize.interfaces.analysis;
 
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedFrameType;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
index 78f1cf7..2131f02 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
@@ -9,9 +9,9 @@
 
 import com.android.tools.r8.cf.code.CfAssignability;
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedFrameType;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
index 1f8ec7f..e920d8e 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
@@ -10,10 +10,10 @@
 import com.android.tools.r8.cf.code.CfAssignability;
 import com.android.tools.r8.cf.code.CfAssignability.AssignabilityResult;
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedFrameType;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
 import com.android.tools.r8.cf.code.frame.SingleFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
 import com.android.tools.r8.cf.code.frame.WideFrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
index b606332..5f8569b 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
@@ -5,9 +5,9 @@
 package com.android.tools.r8.optimize.interfaces.analysis;
 
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.UninitializedFrameType;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
diff --git a/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java b/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java
index e74edc8..095c7c4 100644
--- a/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java
+++ b/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
 import com.android.tools.r8.graph.DexItemFactory;
 import org.junit.Test;
 import org.junit.runner.RunWith;