private static EnumMap<JavaKind, LocationIdentity> initArrayLocations() {
   EnumMap<JavaKind, LocationIdentity> result = new EnumMap<>(JavaKind.class);
   for (JavaKind kind : JavaKind.values()) {
     result.put(kind, NamedLocationIdentity.mutable("Array: " + kind.getJavaName()));
   }
   return result;
 }
 @Fold
 static LocationIdentity getArrayLocation(JavaKind kind) {
   return NamedLocationIdentity.getArrayLocation(kind);
 }
/** A {@link LocationIdentity} with a name. */
public class NamedLocationIdentity extends LocationIdentity implements FormatWithToString {

  /** Map for asserting all {@link NamedLocationIdentity} instances have a unique name. */
  static class DB {
    private static final HashSet<String> map = new HashSet<>();

    static boolean checkUnique(String name) {
      if (!map.add(name)) {
        throw new AssertionError("identity " + name + " already exists");
      }
      return true;
    }
  }

  /** Denotes the location of a value that is guaranteed to be unchanging. */
  public static final LocationIdentity FINAL_LOCATION =
      NamedLocationIdentity.immutable("FINAL_LOCATION");

  /** Denotes the location of the length field of a Java array. */
  public static final LocationIdentity ARRAY_LENGTH_LOCATION =
      NamedLocationIdentity.immutable("[].length");

  public static LocationIdentity any() {
    return ANY_LOCATION;
  }

  private final String name;
  private final boolean immutable;

  protected NamedLocationIdentity(String name, boolean immutable) {
    this.name = name;
    this.immutable = immutable;
    assert DB.checkUnique(name);
  }

  /**
   * Creates a named unique location identity for read and write operations against mutable memory.
   *
   * @param name the name of the new location identity
   */
  public static NamedLocationIdentity mutable(String name) {
    return create(name, false);
  }

  /**
   * Creates a named unique location identity for read operations against immutable memory.
   * Immutable memory will never have a visible write in the graph, which is more restictive than
   * Java final.
   *
   * @param name the name of the new location identity
   */
  public static NamedLocationIdentity immutable(String name) {
    return create(name, true);
  }

  /**
   * Creates a named unique location identity for read and write operations.
   *
   * @param name the name of the new location identity
   * @param immutable true if the location is immutable
   */
  private static NamedLocationIdentity create(String name, boolean immutable) {
    return new NamedLocationIdentity(name, immutable);
  }

  @Override
  public boolean isImmutable() {
    return immutable;
  }

  @Override
  public String toString() {
    return name + (isImmutable() ? ":final" : "");
  }

  /**
   * Returns the named location identity for an array of the given element kind. Array accesses of
   * the same kind must have the same location identity unless an alias analysis guarantees that two
   * distinct arrays are accessed.
   */
  public static LocationIdentity getArrayLocation(JavaKind elementKind) {
    return ARRAY_LOCATIONS.get(elementKind);
  }

  private static final EnumMap<JavaKind, LocationIdentity> ARRAY_LOCATIONS = initArrayLocations();

  private static EnumMap<JavaKind, LocationIdentity> initArrayLocations() {
    EnumMap<JavaKind, LocationIdentity> result = new EnumMap<>(JavaKind.class);
    for (JavaKind kind : JavaKind.values()) {
      result.put(kind, NamedLocationIdentity.mutable("Array: " + kind.getJavaName()));
    }
    return result;
  }
}