# HG changeset patch # User martin # Date 1518139557 28800 # Thu Feb 08 17:25:57 2018 -0800 # Node ID 12c61ec06d2a8cf5be551fcbb4728c200bd99b61 # Parent 1c28a76198da7ed383ccbc1862e42f81b813c80b 8198484: URLClassPath should use an ArrayDeque instead of a Stack Reviewed-by: alanb, mchung, plevart, psandoz diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -46,6 +46,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.cert.Certificate; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -57,7 +58,6 @@ import java.util.NoSuchElementException; import java.util.Properties; import java.util.Set; -import java.util.Stack; import java.util.StringTokenizer; import java.util.jar.JarFile; import java.util.zip.ZipEntry; @@ -101,10 +101,10 @@ } /* The original search path of URLs. */ - private final List path; + private final ArrayList path; - /* The stack of unopened URLs */ - private final Stack unopenedUrls = new Stack<>(); + /* The deque of unopened URLs */ + private final ArrayDeque unopenedUrls; /* The resulting search path of Loaders */ private final ArrayList loaders = new ArrayList<>(); @@ -138,12 +138,15 @@ public URLClassPath(URL[] urls, URLStreamHandlerFactory factory, AccessControlContext acc) { - List path = new ArrayList<>(urls.length); + ArrayList path = new ArrayList<>(urls.length); + ArrayDeque unopenedUrls = new ArrayDeque<>(urls.length); for (URL url : urls) { path.add(url); + unopenedUrls.add(url); } this.path = path; - push(urls); + this.unopenedUrls = unopenedUrls; + if (factory != null) { jarHandler = factory.createURLStreamHandler("jar"); } else { @@ -169,7 +172,7 @@ * @apiNote Used to create the application class path. */ URLClassPath(String cp, boolean skipEmptyElements) { - List path = new ArrayList<>(); + ArrayList path = new ArrayList<>(); if (cp != null) { // map each element of class path to a file URL int off = 0; @@ -189,13 +192,16 @@ URL url = toFileURL(element); if (url != null) path.add(url); } - - // push the URLs - for (int i = path.size() - 1; i >= 0; --i) { - unopenedUrls.push(path.get(i)); - } } + // can't use ArrayDeque#addAll or new ArrayDeque(Collection); + // it's too early in the bootstrap to trigger use of lambdas + int size = path.size(); + ArrayDeque unopenedUrls = new ArrayDeque<>(size); + for (int i = 0; i < size; i++) + unopenedUrls.add(path.get(i)); + + this.unopenedUrls = unopenedUrls; this.path = path; this.jarHandler = null; this.acc = null; @@ -225,14 +231,13 @@ * URLs, then invoking this method has no effect. */ public synchronized void addURL(URL url) { - if (closed) + if (closed || url == null) return; synchronized (unopenedUrls) { - if (url == null || path.contains(url)) - return; - - unopenedUrls.add(0, url); - path.add(url); + if (! path.contains(url)) { + unopenedUrls.addLast(url); + path.add(url); + } } } @@ -413,17 +418,14 @@ if (closed) { return null; } - // Expand URL search path until the request can be satisfied - // or the URL stack is empty. + // Expand URL search path until the request can be satisfied + // or unopenedUrls is exhausted. while (loaders.size() < index + 1) { - // Pop the next URL from the URL stack - URL url; + final URL url; synchronized (unopenedUrls) { - if (unopenedUrls.empty()) { + url = unopenedUrls.pollFirst(); + if (url == null) return null; - } else { - url = unopenedUrls.pop(); - } } // Skip this URL if it already has a Loader. (Loader // may be null in the case where URL has not been opened @@ -437,7 +439,7 @@ try { loader = getLoader(url); // If the loader defines a local class path then add the - // URLs to the list of URLs to be opened. + // URLs as the next URLs to be opened. URL[] urls = loader.getClassPath(); if (urls != null) { push(urls); @@ -502,12 +504,12 @@ } /* - * Pushes the specified URLs onto the list of unopened URLs. + * Pushes the specified URLs onto the head of unopened URLs. */ private void push(URL[] urls) { synchronized (unopenedUrls) { for (int i = urls.length - 1; i >= 0; --i) { - unopenedUrls.push(urls[i]); + unopenedUrls.addFirst(urls[i]); } } }