diff -u new/src/java.base/share/classes/java/io/FilePermission.java new/src/java.base/share/classes/java/io/FilePermission.java
--- new/src/java.base/share/classes/java/io/FilePermission.java	2017-04-07 22:45:54.258437300 +0800
+++ new/src/java.base/share/classes/java/io/FilePermission.java	2017-04-08 08:33:31.913651300 +0800
@@ -684,28 +684,46 @@
      */
     private static int containsPath(Path p1, Path p2) {
 
+        // Two paths must have the same root. For example,
+        // there is no contains relation between any two of
+        // "/x", "x", "C:/x", "C:x", and "//host/share/x".
         if (!Objects.equals(p1.getRoot(), p2.getRoot())) {
             return -1;
         }
 
+        // Empty path (i.e. "." or "") is a strange beast,
+        // because its getNameCount()==1 but getName(0) is null.
+        // It's better to deal with it separately.
         if (p1.equals(EMPTY_PATH)) {
             if (p2.equals(EMPTY_PATH)) {
                 return 0;
             } else if (p2.getName(0).equals(DOTDOT_PATH)) {
+                // "." contains p2 iif p2 has no "..". Since a
+                // a normalized path can only have 0 or more
+                // ".." at the beginning. We only need to look
+                // at the head.
                 return -1;
             } else {
+                // and the distance is p2's name count. i.e.
+                // 3 between "." and "a/b/c".
                 return p2.getNameCount();
             }
         } else if (p2.equals(EMPTY_PATH)) {
             int c1 = p1.getNameCount();
-            for (int j = 0; j < c1; j++) {
-                if (!p1.getName(j).equals(DOTDOT_PATH)) {
-                    return -1;
-                }
+            if (!p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
+                // "." is inside p1 iif p1 is 1 or more "..".
+                // For the same reason above, we only need to
+                // look at the tail.
+                return -1;
             }
+            // and the distance is the count of ".."
             return c1;
         }
 
+        // Good. No more empty paths.
+
+        // Common heads are removed
+
         int c1 = p1.getNameCount();
         int c2 = p2.getNameCount();
 
@@ -717,16 +735,23 @@
             i++;
         }
 
-        for (int j = i; j < c1; j++) {
-            if (!p1.getName(j).equals(DOTDOT_PATH)) {
-                return -1;
-            }
+        // for p1 containing p2, p1 must be 0-or-more "..",
+        // and p2 cannot have "..". For the same reason, we only
+        // check tail of p1 and head of p2.
+        if (i < c1 && !p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
+            return -1;
         }
 
         if (i < c2 && p2.getName(i).equals(DOTDOT_PATH)) {
             return -1;
         }
 
+        // and the distance is the name counts added (after removing
+        // the common heads).
+
+        // For example: p1 = "../../..", p2 = "../a".
+        // After removing the common heads, they become "../.." and "a",
+        // and the distance is (3-1)+(2-1) = 3.
         return c1 - i + c2 - i;
     }