Replace path implementation.

Path and PathFragment have been replaced with String-based implementations. They are pretty similar, but each method is dissimilar enough that I did not feel sharing code was appropriate.

A summary of changes:

PATH
====

* Subsumes LocalPath (deleted, its tests repurposed)
* Use a simple string to back Path
* Path instances are no longer interned; Reference equality will no longer work
* Always normalized (same as before)
* Some operations will now be slower, like instance compares (which were previously just a reference check)
* Multiple identical paths will now consume more memory since they are not interned

PATH FRAGMENT
=============

* Use a simple string to back PathFragment
* No more segment arrays with interned strings
* Always normalized
* Remove isNormalized
* Replace some isNormalizied uses with containsUpLevelReferences() to check if path fragments try to escape their scope
* To check if user input is normalized, supply static methods on PathFragment to validate the string before constructing a PathFragment
* Because PathFragments are always normalized, we have to replace checks for literal "." from PathFragment#getPathString to PathFragment#getSafePathString. The latter returns "." for the empty string.
* The previous implementation supported efficient segment semantics (segment count, iterating over segments). This is now expensive since we do longer have a segment array.

ARTIFACT
========

* Remove Path instance. It is instead dynamically constructed on request. This is necessary to avoid this CL becoming a memory regression.

RELNOTES: None
PiperOrigin-RevId: 185062932
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
index aaaacd9..38da81c 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystem.java
@@ -23,7 +23,6 @@
 import com.google.common.io.CharStreams;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.vfs.Dirent.Type;
-import com.google.devtools.build.lib.vfs.Path.PathFactory;
 import com.google.devtools.common.options.EnumConverter;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -84,25 +83,6 @@
     return digestFunction;
   }
 
-  private enum UnixPathFactory implements PathFactory {
-    INSTANCE {
-      @Override
-      public Path createRootPath(FileSystem filesystem) {
-        return new Path(filesystem, PathFragment.ROOT_DIR, null);
-      }
-
-      @Override
-      public Path createChildPath(Path parent, String childName) {
-        return new Path(parent.getFileSystem(), childName, parent);
-      }
-
-      @Override
-      public Path getCachedChildPathInternal(Path path, String childName) {
-        return Path.getCachedChildPathInternal(path, childName, /*cacheable=*/ true);
-      }
-    };
-  }
-
   /**
    * An exception thrown when attempting to resolve an ordinary file as a symlink.
    */
@@ -112,53 +92,23 @@
     }
   }
 
-  /** Lazy-initialized on first access, always use {@link FileSystem#getRootDirectory} */
-  private volatile Path rootPath;
-
   private final Root absoluteRoot = new Root.AbsoluteRoot(this);
 
-  /** Returns filesystem-specific path factory. */
-  protected PathFactory getPathFactory() {
-    return UnixPathFactory.INSTANCE;
+  /**
+   * Returns an absolute path instance, given an absolute path name, without double slashes, .., or
+   * . segments. While this method will normalize the path representation by creating a
+   * structured/parsed representation, it will not cause any IO. (e.g., it will not resolve symbolic
+   * links if it's a Unix file system.
+   */
+  public Path getPath(String path) {
+    return Path.create(path, this);
   }
 
-  /**
-   * Returns an absolute path instance, given an absolute path name, without
-   * double slashes, .., or . segments. While this method will normalize the
-   * path representation by creating a structured/parsed representation, it will
-   * not cause any IO. (e.g., it will not resolve symbolic links if it's a Unix
-   * file system.
-   */
-  public Path getPath(String pathName) {
-    return getPath(PathFragment.create(pathName));
-  }
-
-  /**
-   * Returns an absolute path instance, given an absolute path name, without
-   * double slashes, .., or . segments. While this method will normalize the
-   * path representation by creating a structured/parsed representation, it will
-   * not cause any IO. (e.g., it will not resolve symbolic links if it's a Unix
-   * file system.
-   */
-  public Path getPath(PathFragment pathName) {
-    if (!pathName.isAbsolute()) {
-      throw new IllegalArgumentException(pathName.getPathString()  + " (not an absolute path)");
-    }
-    return getRootDirectory().getRelative(pathName);
-  }
-
-  /**
-   * Returns a path representing the root directory of the current file system.
-   */
-  public final Path getRootDirectory() {
-    if (rootPath == null) {
-      synchronized (this) {
-        if (rootPath == null) {
-          rootPath = getPathFactory().createRootPath(this);
-        }
-      }
-    }
-    return rootPath;
+  /** Returns an absolute path instance, given an absolute path fragment. */
+  public Path getPath(PathFragment pathFragment) {
+    Preconditions.checkArgument(pathFragment.isAbsolute());
+    return Path.createAlreadyNormalized(
+        pathFragment.getPathString(), pathFragment.getDriveStrLength(), this);
   }
 
   final Root getAbsoluteRoot() {
@@ -401,7 +351,7 @@
       throw new IOException(naive + " (Too many levels of symbolic links)");
     }
     if (linkTarget.isAbsolute()) {
-      dir = getRootDirectory();
+      dir = getPath(linkTarget.getDriveStr());
     }
     for (String name : linkTarget.segments()) {
       if (name.equals(".") || name.isEmpty()) {