Merge
authortbell
Sat, 19 Dec 2009 10:26:47 -0800
changeset 4552 e7616c247414
parent 4546 378412bf1859 (current diff)
parent 4551 a986317586f6 (diff)
child 4553 235b2ff63e0a
Merge
langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java
--- a/langtools/make/build.properties	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/make/build.properties	Sat Dec 19 10:26:47 2009 -0800
@@ -149,11 +149,26 @@
 #
 
 # The following files require the import JDK to be available
-require.import.jdk.files =
+require.import.jdk.files = \
+    com/sun/tools/javac/nio/*.java
 
 # The following files in the import jdk source directory are required
 # in order to compile the files defined in ${require.import.jdk.files}
-import.jdk.stub.files =
+#
+# For NIO, the list of stub files is defined by the contents of the primary
+# API packages, together with such types that may be required in order to
+# compile the stubs. Some of these dependencies would go away if the stub
+# generator were to be improved -- e.g. by removing unnecessary imports.
+#
+import.jdk.stub.files = \
+    java/io/File.java \
+    java/nio/file/**.java \
+    java/nio/file/attribute/**.java \
+    java/nio/file/spi/**.java \
+    java/nio/channels/AsynchronousChannel.java \
+    java/nio/channels/AsynchronousFileChannel.java \
+    java/nio/channels/CompletionHandler.java \
+    java/nio/channels/SeekableByteChannel.java
 
 # The following value is used by the main jtreg target.
 # An empty value means all tests
--- a/langtools/make/build.xml	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/make/build.xml	Sat Dec 19 10:26:47 2009 -0800
@@ -98,7 +98,7 @@
         import.jdk should be unset, or set to jdk home (to use rt.jar)
         or to jdk repo (to use src/share/classes).
         Based on the value, if any, set up default values for javac's sourcepath,
-        classpath and bootclasspath. Note: the default values are overridden 
+        classpath and bootclasspath. Note: the default values are overridden
         in the build-bootstrap-classes macro. -->
 
     <available property="import.jdk.src.dir" value="${import.jdk}/src/share/classes"
@@ -552,8 +552,8 @@
                     <compilerarg line="${javac.version.opt}"/>
                     <compilerarg line="${javac.lint.opts}"/>
                 </javac>
-                <copy todir="@{classes.dir}">
-                    <fileset dir="${src.classes.dir}" includes="@{includes}">
+                <copy todir="@{classes.dir}" includeemptydirs="false">
+                    <fileset dir="${src.classes.dir}" includes="@{includes}" excludes="@{excludes}">
                         <exclude name="**/*.java"/>
                         <exclude name="**/*.properties"/>
                         <exclude name="**/*-template"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,718 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.tools.classfile;
+
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import com.sun.tools.classfile.Dependency.Finder;
+import com.sun.tools.classfile.Dependency.Filter;
+import com.sun.tools.classfile.Dependency.Location;
+import com.sun.tools.classfile.Type.ArrayType;
+import com.sun.tools.classfile.Type.ClassSigType;
+import com.sun.tools.classfile.Type.ClassType;
+import com.sun.tools.classfile.Type.MethodType;
+import com.sun.tools.classfile.Type.SimpleType;
+import com.sun.tools.classfile.Type.TypeParamType;
+import com.sun.tools.classfile.Type.WildcardType;
+
+import static com.sun.tools.classfile.ConstantPool.*;
+
+/**
+ * A framework for determining {@link Dependency dependencies} between class files.
+ *
+ * A {@link Dependency.Finder finder} is used to identify the dependencies of
+ * individual classes. Some finders may return subtypes of {@code Dependency} to
+ * further characterize the type of dependency, such as a dependency on a
+ * method within a class.
+ *
+ * A {@link Dependency.Filter filter} may be used to restrict the set of
+ * dependencies found by a finder.
+ *
+ * Dependencies that are found may be passed to a {@link Dependencies.Recorder
+ * recorder} so that the dependencies can be stored in a custom data structure.
+ */
+public class Dependencies {
+    /**
+     * Thrown when a class file cannot be found.
+     */
+    public static class ClassFileNotFoundException extends Exception {
+        private static final long serialVersionUID = 3632265927794475048L;
+
+        public ClassFileNotFoundException(String className) {
+            super(className);
+            this.className = className;
+        }
+
+        public ClassFileNotFoundException(String className, Throwable cause) {
+            this(className);
+            initCause(cause);
+        }
+
+        public final String className;
+    }
+
+    /**
+     * Thrown when an exception is found processing a class file.
+     */
+    public static class ClassFileError extends Error {
+        private static final long serialVersionUID = 4111110813961313203L;
+
+        public ClassFileError(Throwable cause) {
+            initCause(cause);
+        }
+    }
+
+    /**
+     * Service provider interface to locate and read class files.
+     */
+    public interface ClassFileReader {
+        /**
+         * Get the ClassFile object for a specified class.
+         * @param className the name of the class to be returned.
+         * @return the ClassFile for the given class
+         * @throws Dependencies#ClassFileNotFoundException if the classfile cannot be
+         *   found
+         */
+        public ClassFile getClassFile(String className)
+                throws ClassFileNotFoundException;
+    }
+
+    /**
+     * Service provide interface to handle results.
+     */
+    public interface Recorder {
+        /**
+         * Record a dependency that has been found.
+         * @param d
+         */
+        public void addDependency(Dependency d);
+    }
+
+    /**
+     * Get the  default finder used to locate the dependencies for a class.
+     * @return the default finder
+     */
+    public static Finder getDefaultFinder() {
+        return new APIDependencyFinder(AccessFlags.ACC_PRIVATE);
+    }
+
+    /**
+     * Get a finder used to locate the API dependencies for a class.
+     * These include the superclass, superinterfaces, and classes referenced in
+     * the declarations of fields and methods.  The fields and methods that
+     * are checked can be limited according to a specified access.
+     * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC},
+     * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE},
+     * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for
+     * package private access. Members with greater than or equal accessibility
+     * to that specified will be searched for dependencies.
+     * @param access the access of members to be checked
+     * @return an API finder
+     */
+    public static Finder getAPIFinder(int access) {
+        return new APIDependencyFinder(access);
+    }
+
+    /**
+     * Get the finder used to locate the dependencies for a class.
+     * @return the finder
+     */
+    public Finder getFinder() {
+        if (finder == null)
+            finder = getDefaultFinder();
+        return finder;
+    }
+
+    /**
+     * Set the finder used to locate the dependencies for a class.
+     * @param f the finder
+     */
+    public void setFinder(Finder f) {
+        f.getClass(); // null check
+        finder = f;
+    }
+
+    /**
+     * Get the default filter used to determine included when searching
+     * the transitive closure of all the dependencies.
+     * Unless overridden, the default filter accepts all dependencies.
+     * @return the default filter.
+     */
+    public static Filter getDefaultFilter() {
+        return DefaultFilter.instance();
+    }
+
+    /**
+     * Get a filter which uses a regular expression on the target's class name
+     * to determine if a dependency is of interest.
+     * @param pattern the pattern used to match the target's class name
+     * @return a filter for matching the target class name with a regular expression
+     */
+    public static Filter getRegexFilter(Pattern pattern) {
+        return new TargetRegexFilter(pattern);
+    }
+
+    /**
+     * Get a filter which checks the package of a target's class name
+     * to determine if a dependency is of interest. The filter checks if the
+     * package of the target's class matches any of a set of given package
+     * names. The match may optionally match subpackages of the given names as well.
+     * @param packageNames the package names used to match the target's class name
+     * @param matchSubpackages whether or not to match subpackages as well
+     * @return a filter for checking the target package name against a list of package names
+     */
+    public static Filter getPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
+        return new TargetPackageFilter(packageNames, matchSubpackages);
+    }
+
+    /**
+     * Get the filter used to determine the dependencies included when searching
+     * the transitive closure of all the dependencies.
+     * Unless overridden, the default filter accepts all dependencies.
+     * @return the filter
+     */
+    public Filter getFilter() {
+        if (filter == null)
+            filter = getDefaultFilter();
+        return filter;
+    }
+
+    /**
+     * Set the filter used to determine the dependencies included when searching
+     * the transitive closure of all the dependencies.
+     * @param f the filter
+     */
+    public void setFilter(Filter f) {
+        f.getClass(); // null check
+        filter = f;
+    }
+
+    /**
+     * Find the dependencies of a class, using the current
+     * {@link Dependencies#getFinder finder} and
+     * {@link Dependencies#getFilter filter}.
+     * The search may optionally include the transitive closure of all the
+     * filtered dependencies, by also searching in the classes named in those
+     * dependencies.
+     * @param classFinder a finder to locate class files
+     * @param rootClassNames the names of the root classes from which to begin
+     *      searching
+     * @param transitiveClosure whether or not to also search those classes
+     *      named in any filtered dependencies that are found.
+     * @return the set of dependencies that were found
+     * @throws ClassFileNotFoundException if a required class file cannot be found
+     * @throws ClassFileError if an error occurs while processing a class file,
+     *      such as an error in the internal class file structure.
+     */
+    public Set<Dependency> findAllDependencies(
+            ClassFileReader classFinder, Set<String> rootClassNames,
+            boolean transitiveClosure)
+            throws ClassFileNotFoundException {
+        final Set<Dependency> results = new HashSet<Dependency>();
+        Recorder r = new Recorder() {
+            public void addDependency(Dependency d) {
+                results.add(d);
+            }
+        };
+        findAllDependencies(classFinder, rootClassNames, transitiveClosure, r);
+        return results;
+    }
+
+
+
+    /**
+     * Find the dependencies of a class, using the current
+     * {@link Dependencies#getFinder finder} and
+     * {@link Dependencies#getFilter filter}.
+     * The search may optionally include the transitive closure of all the
+     * filtered dependencies, by also searching in the classes named in those
+     * dependencies.
+     * @param classFinder a finder to locate class files
+     * @param rootClassNames the names of the root classes from which to begin
+     *      searching
+     * @param transitiveClosure whether or not to also search those classes
+     *      named in any filtered dependencies that are found.
+     * @param recorder a recorder for handling the results
+     * @throws ClassFileNotFoundException if a required class file cannot be found
+     * @throws ClassFileError if an error occurs while processing a class file,
+     *      such as an error in the internal class file structure.
+     */
+    public void findAllDependencies(
+            ClassFileReader classFinder, Set<String> rootClassNames,
+            boolean transitiveClosure, Recorder recorder)
+            throws ClassFileNotFoundException {
+        Set<String> doneClasses = new HashSet<String>();
+
+        getFinder();  // ensure initialized
+        getFilter();  // ensure initialized
+
+        // Work queue of names of classfiles to be searched.
+        // Entries will be unique, and for classes that do not yet have
+        // dependencies in the results map.
+        Deque<String> deque = new LinkedList<String>(rootClassNames);
+
+        String className;
+        while ((className = deque.poll()) != null) {
+            assert (!doneClasses.contains(className));
+            doneClasses.add(className);
+
+            ClassFile cf = classFinder.getClassFile(className);
+
+            // The following code just applies the filter to the dependencies
+            // followed for the transitive closure.
+            for (Dependency d: finder.findDependencies(cf)) {
+                recorder.addDependency(d);
+                if (transitiveClosure && filter.accepts(d)) {
+                    String cn = d.getTarget().getClassName();
+                    if (!doneClasses.contains(cn))
+                        deque.add(cn);
+                }
+            }
+        }
+    }
+
+    private Filter filter;
+    private Finder finder;
+
+    /**
+     * A location identifying a class.
+     */
+    static class SimpleLocation implements Location {
+        public SimpleLocation(String className) {
+            this.className = className;
+        }
+
+        /**
+         * Get the name of the class being depended on. This name will be used to
+         * locate the class file for transitive dependency analysis.
+         * @return the name of the class being depended on
+         */
+        public String getClassName() {
+            return className;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other)
+                return true;
+            if (!(other instanceof SimpleLocation))
+                return false;
+            return (className.equals(((SimpleLocation) other).className));
+        }
+
+        @Override
+        public int hashCode() {
+            return className.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return className;
+        }
+
+        private String className;
+    }
+
+    /**
+     * A dependency of one class on another.
+     */
+    static class SimpleDependency implements Dependency {
+        public SimpleDependency(Location origin, Location target) {
+            this.origin = origin;
+            this.target = target;
+        }
+
+        public Location getOrigin() {
+            return origin;
+        }
+
+        public Location getTarget() {
+            return target;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other)
+                return true;
+            if (!(other instanceof SimpleDependency))
+                return false;
+            SimpleDependency o = (SimpleDependency) other;
+            return (origin.equals(o.origin) && target.equals(o.target));
+        }
+
+        @Override
+        public int hashCode() {
+            return origin.hashCode() * 31 + target.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return origin + ":" + target;
+        }
+
+        private Location origin;
+        private Location target;
+    }
+
+
+    /**
+     * This class accepts all dependencies.
+     */
+    static class DefaultFilter implements Filter {
+        private static DefaultFilter instance;
+
+        static DefaultFilter instance() {
+            if (instance == null)
+                instance = new DefaultFilter();
+            return instance;
+        }
+
+        public boolean accepts(Dependency dependency) {
+            return true;
+        }
+    }
+
+    /**
+     * This class accepts those dependencies whose target's class name matches a
+     * regular expression.
+     */
+    static class TargetRegexFilter implements Filter {
+        TargetRegexFilter(Pattern pattern) {
+            this.pattern = pattern;
+        }
+
+        public boolean accepts(Dependency dependency) {
+            return pattern.matcher(dependency.getTarget().getClassName()).matches();
+        }
+
+        private final Pattern pattern;
+    }
+
+    /**
+     * This class accepts those dependencies whose class name is in a given
+     * package.
+     */
+    static class TargetPackageFilter implements Filter {
+        TargetPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
+            for (String pn: packageNames) {
+                if (pn.length() == 0) // implies null check as well
+                    throw new IllegalArgumentException();
+            }
+            this.packageNames = packageNames;
+            this.matchSubpackages = matchSubpackages;
+        }
+
+        public boolean accepts(Dependency dependency) {
+            String cn = dependency.getTarget().getClassName();
+            int lastSep = cn.lastIndexOf("/");
+            String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep));
+            if (packageNames.contains(pn))
+                return true;
+
+            if (matchSubpackages) {
+                for (String n: packageNames) {
+                    if (pn.startsWith(n + "."))
+                        return true;
+                }
+            }
+
+            return false;
+        }
+
+        private final Set<String> packageNames;
+        private final boolean matchSubpackages;
+    }
+
+
+
+    /**
+     * This class identifies class names directly or indirectly in the constant pool.
+     */
+    static class ClassDependencyFinder extends BasicDependencyFinder {
+        public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
+            Visitor v = new Visitor(classfile);
+            for (CPInfo cpInfo: classfile.constant_pool.entries()) {
+                v.scan(cpInfo);
+            }
+            return v.deps;
+        }
+    }
+
+    /**
+     * This class identifies class names in the signatures of classes, fields,
+     * and methods in a class.
+     */
+    static class APIDependencyFinder extends BasicDependencyFinder {
+        APIDependencyFinder(int access) {
+            switch (access) {
+                case AccessFlags.ACC_PUBLIC:
+                case AccessFlags.ACC_PROTECTED:
+                case AccessFlags.ACC_PRIVATE:
+                case 0:
+                    showAccess = access;
+                    break;
+                default:
+                    throw new IllegalArgumentException("invalid access 0x"
+                            + Integer.toHexString(access));
+            }
+        }
+
+        public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
+            try {
+                Visitor v = new Visitor(classfile);
+                v.addClass(classfile.super_class);
+                v.addClasses(classfile.interfaces);
+                // inner classes?
+                for (Field f : classfile.fields) {
+                    if (checkAccess(f.access_flags))
+                        v.scan(f.descriptor, f.attributes);
+                }
+                for (Method m : classfile.methods) {
+                    if (checkAccess(m.access_flags)) {
+                        v.scan(m.descriptor, m.attributes);
+                        Exceptions_attribute e =
+                                (Exceptions_attribute) m.attributes.get(Attribute.Exceptions);
+                        if (e != null)
+                            v.addClasses(e.exception_index_table);
+                    }
+                }
+                return v.deps;
+            } catch (ConstantPoolException e) {
+                throw new ClassFileError(e);
+            }
+        }
+
+        boolean checkAccess(AccessFlags flags) {
+            // code copied from javap.Options.checkAccess
+            boolean isPublic = flags.is(AccessFlags.ACC_PUBLIC);
+            boolean isProtected = flags.is(AccessFlags.ACC_PROTECTED);
+            boolean isPrivate = flags.is(AccessFlags.ACC_PRIVATE);
+            boolean isPackage = !(isPublic || isProtected || isPrivate);
+
+            if ((showAccess == AccessFlags.ACC_PUBLIC) && (isProtected || isPrivate || isPackage))
+                return false;
+            else if ((showAccess == AccessFlags.ACC_PROTECTED) && (isPrivate || isPackage))
+                return false;
+            else if ((showAccess == 0) && (isPrivate))
+                return false;
+            else
+                return true;
+        }
+
+        private int showAccess;
+    }
+
+    static abstract class BasicDependencyFinder implements Finder {
+        private Map<String,Location> locations = new HashMap<String,Location>();
+
+        Location getLocation(String className) {
+            Location l = locations.get(className);
+            if (l == null)
+                locations.put(className, l = new SimpleLocation(className));
+            return l;
+        }
+
+        class Visitor implements ConstantPool.Visitor<Void,Void>, Type.Visitor<Void, Void> {
+            private ConstantPool constant_pool;
+            private Location origin;
+            Set<Dependency> deps;
+
+            Visitor(ClassFile classFile) {
+                try {
+                    constant_pool = classFile.constant_pool;
+                    origin = getLocation(classFile.getName());
+                    deps = new HashSet<Dependency>();
+                } catch (ConstantPoolException e) {
+                    throw new ClassFileError(e);
+                }
+            }
+
+            void scan(Descriptor d, Attributes attrs) {
+                try {
+                    scan(new Signature(d.index).getType(constant_pool));
+                    Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
+                    if (sa != null)
+                        scan(new Signature(sa.signature_index).getType(constant_pool));
+                } catch (ConstantPoolException e) {
+                    throw new ClassFileError(e);
+                }
+            }
+
+            void scan(CPInfo cpInfo) {
+                cpInfo.accept(this, null);
+            }
+
+            void scan(Type t) {
+                t.accept(this, null);
+            }
+
+            void addClass(int index) throws ConstantPoolException {
+                if (index != 0) {
+                    String name = constant_pool.getClassInfo(index).getBaseName();
+                    if (name != null)
+                        addDependency(name);
+                }
+            }
+
+            void addClasses(int[] indices) throws ConstantPoolException {
+                for (int i: indices)
+                    addClass(i);
+            }
+
+            private void addDependency(String name) {
+                deps.add(new SimpleDependency(origin, getLocation(name)));
+            }
+
+            // ConstantPool.Visitor methods
+
+            public Void visitClass(CONSTANT_Class_info info, Void p) {
+                try {
+                    if (info.getName().startsWith("["))
+                        new Signature(info.name_index).getType(constant_pool).accept(this, null);
+                    else
+                        addDependency(info.getBaseName());
+                    return null;
+                } catch (ConstantPoolException e) {
+                    throw new ClassFileError(e);
+                }
+            }
+
+            public Void visitDouble(CONSTANT_Double_info info, Void p) {
+                return null;
+            }
+
+            public Void visitFieldref(CONSTANT_Fieldref_info info, Void p) {
+                return visitRef(info, p);
+            }
+
+            public Void visitFloat(CONSTANT_Float_info info, Void p) {
+                return null;
+            }
+
+            public Void visitInteger(CONSTANT_Integer_info info, Void p) {
+                return null;
+            }
+
+            public Void visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
+                return visitRef(info, p);
+            }
+
+            public Void visitLong(CONSTANT_Long_info info, Void p) {
+                return null;
+            }
+
+            public Void visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
+                try {
+                    new Signature(info.type_index).getType(constant_pool).accept(this, null);
+                    return null;
+                } catch (ConstantPoolException e) {
+                    throw new ClassFileError(e);
+                }
+            }
+
+            public Void visitMethodref(CONSTANT_Methodref_info info, Void p) {
+                return visitRef(info, p);
+            }
+
+            public Void visitString(CONSTANT_String_info info, Void p) {
+                return null;
+            }
+
+            public Void visitUtf8(CONSTANT_Utf8_info info, Void p) {
+                return null;
+            }
+
+            private Void visitRef(CPRefInfo info, Void p) {
+                try {
+                    visitClass(info.getClassInfo(), p);
+                    return null;
+                } catch (ConstantPoolException e) {
+                    throw new ClassFileError(e);
+                }
+            }
+
+            // Type.Visitor methods
+
+            private void findDependencies(Type t) {
+                if (t != null)
+                    t.accept(this, null);
+            }
+
+            private void findDependencies(List<? extends Type> ts) {
+                if (ts != null) {
+                    for (Type t: ts)
+                        t.accept(this, null);
+                }
+            }
+
+            public Void visitSimpleType(SimpleType type, Void p) {
+                return null;
+            }
+
+            public Void visitArrayType(ArrayType type, Void p) {
+                findDependencies(type.elemType);
+                return null;
+            }
+
+            public Void visitMethodType(MethodType type, Void p) {
+                findDependencies(type.paramTypes);
+                findDependencies(type.returnType);
+                findDependencies(type.throwsTypes);
+                return null;
+            }
+
+            public Void visitClassSigType(ClassSigType type, Void p) {
+                findDependencies(type.superclassType);
+                findDependencies(type.superinterfaceTypes);
+                return null;
+            }
+
+            public Void visitClassType(ClassType type, Void p) {
+                findDependencies(type.outerType);
+                addDependency(type.name);
+                findDependencies(type.typeArgs);
+                return null;
+            }
+
+            public Void visitTypeParamType(TypeParamType type, Void p) {
+                findDependencies(type.classBound);
+                findDependencies(type.interfaceBounds);
+                return null;
+            }
+
+            public Void visitWildcardType(WildcardType type, Void p) {
+                findDependencies(type.boundType);
+                return null;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.classfile;
+
+
+/**
+ * A directed relationship between two {@link Dependency.Location Location}s.
+ * Subtypes of {@code Dependency} may provide additional detail about the dependency.
+ *
+ * @see Dependency.Finder
+ * @see Dependency.Filter
+ * @see Dependencies
+ */
+public interface Dependency {
+    /**
+     * A filter used to select dependencies of interest, and to discard others.
+     */
+    public interface Filter {
+        /**
+         * Return true if the dependency is of interest.
+         * @param dependency the dependency to be considered
+         * @return true if and only if the dependency is of interest.
+         */
+        boolean accepts(Dependency dependency);
+    }
+
+    /**
+     * An interface for finding the immediate dependencies of a given class file.
+     */
+    public interface Finder {
+        /**
+         * Find the immediate dependencies of a given class file.
+         * @param classfile the class file to be examined
+         * @return the dependencies located in the given class file.
+         */
+        public Iterable<? extends Dependency> findDependencies(ClassFile classfile);
+    }
+
+
+    /**
+     * A location somewhere within a class. Subtypes of {@code Location}
+     * may be used to provide additional detail about the location.
+     */
+    public interface Location {
+        /**
+         * Get the name of the class containing the location.
+         * This name will be used to locate the class file for transitive
+         * dependency analysis.
+         * @return the name of the class containing the location.
+         */
+        String getClassName();
+    }
+
+
+    /**
+     * Get the location that has the dependency.
+     * @return the location that has the dependency.
+     */
+    Location getOrigin();
+
+    /**
+     * Get the location that is being depended upon.
+     * @return the location that is being depended upon.
+     */
+    Location getTarget();
+}
+
--- a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java	Sat Dec 19 10:26:47 2009 -0800
@@ -39,6 +39,8 @@
 
 import static javax.tools.JavaFileObject.Kind.*;
 
+import com.sun.tools.javac.util.BaseFileManager;
+
 /**
  * <p><b>This is NOT part of any API supported by Sun Microsystems.
  * If you write code that depends on this, you do so at your own risk.
@@ -74,14 +76,7 @@
     protected abstract String inferBinaryName(Iterable<? extends File> path);
 
     protected static JavaFileObject.Kind getKind(String filename) {
-        if (filename.endsWith(CLASS.extension))
-            return CLASS;
-        else if (filename.endsWith(SOURCE.extension))
-            return SOURCE;
-        else if (filename.endsWith(HTML.extension))
-            return HTML;
-        else
-            return OTHER;
+        return BaseFileManager.getKind(filename);
     }
 
     protected static String removeExtension(String fileName) {
--- a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java	Thu Dec 17 14:10:44 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package com.sun.tools.javac.file;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.jar.JarFile;
-
-/**
- * A URLClassLoader that also implements Closeable.
- * Reflection is used to access internal data structures in the URLClassLoader,
- * since no public API exists for this purpose. Therefore this code is somewhat
- * fragile. Caveat emptor.
- * @throws Error if the internal data structures are not as expected.
- *
- *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
- *  you write code that depends on this, you do so at your own risk.
- *  This code and its internal interfaces are subject to change or
- *  deletion without notice.</b>
- */
-class CloseableURLClassLoader
-        extends URLClassLoader implements Closeable {
-    CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
-        super(urls, parent);
-        try {
-            getLoaders(); //proactive check that URLClassLoader is as expected
-        } catch (Throwable t) {
-            throw new Error("cannot create CloseableURLClassLoader", t);
-        }
-    }
-
-    /**
-     * Close any jar files that may have been opened by the class loader.
-     * Reflection is used to access the jar files in the URLClassLoader's
-     * internal data structures.
-     * @throws java.io.IOException if the jar files cannot be found for any
-     * reson, or if closing the jar file itself causes an IOException.
-     */
-    public void close() throws IOException {
-        try {
-            for (Object l: getLoaders()) {
-                if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
-                    Field jarField = l.getClass().getDeclaredField("jar");
-                    JarFile jar = (JarFile) getField(l, jarField);
-                    if (jar != null) {
-                        //System.err.println("CloseableURLClassLoader: closing " + jar);
-                        jar.close();
-                    }
-                }
-            }
-        } catch (Throwable t) {
-            IOException e = new IOException("cannot close class loader");
-            e.initCause(t);
-            throw e;
-        }
-    }
-
-    private ArrayList<?> getLoaders()
-            throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
-    {
-        Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
-        Object urlClassPath = getField(this, ucpField);
-        if (urlClassPath == null)
-            throw new AssertionError("urlClassPath not set in URLClassLoader");
-        Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
-        return (ArrayList<?>) getField(urlClassPath, loadersField);
-    }
-
-    private Object getField(Object o, Field f)
-            throws IllegalArgumentException, IllegalAccessException {
-        boolean prev = f.isAccessible();
-        try {
-            f.setAccessible(true);
-            return f.get(o);
-        } finally {
-            f.setAccessible(prev);
-        }
-    }
-
-}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Sat Dec 19 10:26:47 2009 -0800
@@ -26,29 +26,16 @@
 package com.sun.tools.javac.file;
 
 import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStreamWriter;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.Constructor;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
 import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -66,18 +53,13 @@
 import javax.tools.JavaFileObject;
 import javax.tools.StandardJavaFileManager;
 
-import com.sun.tools.javac.code.Source;
 import com.sun.tools.javac.file.RelativePath.RelativeFile;
 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
-import com.sun.tools.javac.main.JavacOption;
 import com.sun.tools.javac.main.OptionName;
-import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.BaseFileManager;
 import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Options;
 
 import static javax.tools.StandardLocation.*;
 import static com.sun.tools.javac.main.OptionName.*;
@@ -91,7 +73,7 @@
  * This code and its internal interfaces are subject to change or
  * deletion without notice.</b>
  */
-public class JavacFileManager implements StandardJavaFileManager {
+public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
 
     boolean useZipFileIndex;
 
@@ -102,17 +84,10 @@
             return buffer.toString().toCharArray();
     }
 
-    /**
-     * The log to be used for error reporting.
-     */
-    protected Log log;
-
     /** Encapsulates knowledge of paths
      */
     private Paths paths;
 
-    private Options options;
-
     private FSInfo fsInfo;
 
     private final File uninited = new File("U N I N I T E D");
@@ -134,12 +109,6 @@
 
     protected boolean mmappedIO;
     protected boolean ignoreSymbolFile;
-    protected String classLoaderClass;
-
-    /**
-     * User provided charset (through javax.tools).
-     */
-    protected Charset charset;
 
     /**
      * Register a Context.Factory to create a JavacFileManager.
@@ -157,18 +126,18 @@
      * it as the JavaFileManager for that context.
      */
     public JavacFileManager(Context context, boolean register, Charset charset) {
+        super(charset);
         if (register)
             context.put(JavaFileManager.class, this);
-        byteBufferCache = new ByteBufferCache();
-        this.charset = charset;
         setContext(context);
     }
 
     /**
      * Set the context for JavacFileManager.
      */
+    @Override
     public void setContext(Context context) {
-        log = Log.instance(context);
+        super.setContext(context);
         if (paths == null) {
             paths = Paths.instance(context);
         } else {
@@ -177,14 +146,12 @@
             paths.setContext(context);
         }
 
-        options = Options.instance(context);
         fsInfo = FSInfo.instance(context);
 
         useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
 
         mmappedIO = options.get("mmappedIO") != null;
         ignoreSymbolFile = options.get("ignore.symbol.file") != null;
-        classLoaderClass = options.get("procloader");
     }
 
     public JavaFileObject getFileForInput(String name) {
@@ -214,17 +181,6 @@
         return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
     }
 
-    protected JavaFileObject.Kind getKind(String extension) {
-        if (extension.equals(JavaFileObject.Kind.CLASS.extension))
-            return JavaFileObject.Kind.CLASS;
-        else if (extension.equals(JavaFileObject.Kind.SOURCE.extension))
-            return JavaFileObject.Kind.SOURCE;
-        else if (extension.equals(JavaFileObject.Kind.HTML.extension))
-            return JavaFileObject.Kind.HTML;
-        else
-            return JavaFileObject.Kind.OTHER;
-    }
-
     private static boolean isValidName(String name) {
         // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
         // but the set of keywords depends on the source level, and we don't want
@@ -359,9 +315,7 @@
     }
 
     private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
-        int lastDot = s.lastIndexOf(".");
-        String extn = (lastDot == -1 ? s : s.substring(lastDot));
-        JavaFileObject.Kind kind = getKind(extn);
+        JavaFileObject.Kind kind = getKind(s);
         return fileKinds.contains(kind);
     }
 
@@ -564,18 +518,6 @@
         }
     }
 
-    CharBuffer getCachedContent(JavaFileObject file) {
-        SoftReference<CharBuffer> r = contentCache.get(file);
-        return (r == null ? null : r.get());
-    }
-
-    void cache(JavaFileObject file, CharBuffer cb) {
-        contentCache.put(file, new SoftReference<CharBuffer>(cb));
-    }
-
-    private final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
-            = new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
-
     private String defaultEncodingName;
     private String getDefaultEncodingName() {
         if (defaultEncodingName == null) {
@@ -585,161 +527,6 @@
         return defaultEncodingName;
     }
 
-    protected String getEncodingName() {
-        String encName = options.get(OptionName.ENCODING);
-        if (encName == null)
-            return getDefaultEncodingName();
-        else
-            return encName;
-    }
-
-    protected Source getSource() {
-        String sourceName = options.get(OptionName.SOURCE);
-        Source source = null;
-        if (sourceName != null)
-            source = Source.lookup(sourceName);
-        return (source != null ? source : Source.DEFAULT);
-    }
-
-    /**
-     * Make a byte buffer from an input stream.
-     */
-    ByteBuffer makeByteBuffer(InputStream in)
-        throws IOException {
-        int limit = in.available();
-        if (mmappedIO && in instanceof FileInputStream) {
-            // Experimental memory mapped I/O
-            FileInputStream fin = (FileInputStream)in;
-            return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit);
-        }
-        if (limit < 1024) limit = 1024;
-        ByteBuffer result = byteBufferCache.get(limit);
-        int position = 0;
-        while (in.available() != 0) {
-            if (position >= limit)
-                // expand buffer
-                result = ByteBuffer.
-                    allocate(limit <<= 1).
-                    put((ByteBuffer)result.flip());
-            int count = in.read(result.array(),
-                position,
-                limit - position);
-            if (count < 0) break;
-            result.position(position += count);
-        }
-        return (ByteBuffer)result.flip();
-    }
-
-    void recycleByteBuffer(ByteBuffer bb) {
-        byteBufferCache.put(bb);
-    }
-
-    /**
-     * A single-element cache of direct byte buffers.
-     */
-    private static class ByteBufferCache {
-        private ByteBuffer cached;
-        ByteBuffer get(int capacity) {
-            if (capacity < 20480) capacity = 20480;
-            ByteBuffer result =
-                (cached != null && cached.capacity() >= capacity)
-                ? (ByteBuffer)cached.clear()
-                : ByteBuffer.allocate(capacity + capacity>>1);
-            cached = null;
-            return result;
-        }
-        void put(ByteBuffer x) {
-            cached = x;
-        }
-    }
-
-    private final ByteBufferCache byteBufferCache;
-
-    CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
-        Charset cs = (this.charset == null)
-            ? Charset.forName(encodingName)
-            : this.charset;
-        CharsetDecoder decoder = cs.newDecoder();
-
-        CodingErrorAction action;
-        if (ignoreEncodingErrors)
-            action = CodingErrorAction.REPLACE;
-        else
-            action = CodingErrorAction.REPORT;
-
-        return decoder
-            .onMalformedInput(action)
-            .onUnmappableCharacter(action);
-    }
-
-    /**
-     * Decode a ByteBuffer into a CharBuffer.
-     */
-    CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
-        String encodingName = getEncodingName();
-        CharsetDecoder decoder;
-        try {
-            decoder = getDecoder(encodingName, ignoreEncodingErrors);
-        } catch (IllegalCharsetNameException e) {
-            log.error("unsupported.encoding", encodingName);
-            return (CharBuffer)CharBuffer.allocate(1).flip();
-        } catch (UnsupportedCharsetException e) {
-            log.error("unsupported.encoding", encodingName);
-            return (CharBuffer)CharBuffer.allocate(1).flip();
-        }
-
-        // slightly overestimate the buffer size to avoid reallocation.
-        float factor =
-            decoder.averageCharsPerByte() * 0.8f +
-            decoder.maxCharsPerByte() * 0.2f;
-        CharBuffer dest = CharBuffer.
-            allocate(10 + (int)(inbuf.remaining()*factor));
-
-        while (true) {
-            CoderResult result = decoder.decode(inbuf, dest, true);
-            dest.flip();
-
-            if (result.isUnderflow()) { // done reading
-                // make sure there is at least one extra character
-                if (dest.limit() == dest.capacity()) {
-                    dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
-                    dest.flip();
-                }
-                return dest;
-            } else if (result.isOverflow()) { // buffer too small; expand
-                int newCapacity =
-                    10 + dest.capacity() +
-                    (int)(inbuf.remaining()*decoder.maxCharsPerByte());
-                dest = CharBuffer.allocate(newCapacity).put(dest);
-            } else if (result.isMalformed() || result.isUnmappable()) {
-                // bad character in input
-
-                // report coding error (warn only pre 1.5)
-                if (!getSource().allowEncodingErrors()) {
-                    log.error(new SimpleDiagnosticPosition(dest.limit()),
-                              "illegal.char.for.encoding",
-                              charset == null ? encodingName : charset.name());
-                } else {
-                    log.warning(new SimpleDiagnosticPosition(dest.limit()),
-                                "illegal.char.for.encoding",
-                                charset == null ? encodingName : charset.name());
-                }
-
-                // skip past the coding error
-                inbuf.position(inbuf.position() + result.length());
-
-                // undo the flip() to prepare the output buffer
-                // for more translation
-                dest.position(dest.limit());
-                dest.limit(dest.capacity());
-                dest.put((char)0xfffd); // backward compatible
-            } else {
-                throw new AssertionError(result);
-            }
-        }
-        // unreached
-    }
-
     public ClassLoader getClassLoader(Location location) {
         nullCheck(location);
         Iterable<? extends File> path = getLocation(location);
@@ -754,39 +541,7 @@
             }
         }
 
-        URL[] urls = lb.toArray(new URL[lb.size()]);
-        ClassLoader thisClassLoader = getClass().getClassLoader();
-
-        // Bug: 6558476
-        // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
-        // On older versions, try the following, to get a closeable classloader.
-
-        // 1: Allow client to specify the class to use via hidden option
-        if (classLoaderClass != null) {
-            try {
-                Class<? extends ClassLoader> loader =
-                        Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
-                Class<?>[] constrArgTypes = { URL[].class, ClassLoader.class };
-                Constructor<? extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
-                return constr.newInstance(new Object[] { urls, thisClassLoader });
-            } catch (Throwable t) {
-                // ignore errors loading user-provided class loader, fall through
-            }
-        }
-
-        // 2: If URLClassLoader implements Closeable, use that.
-        if (Closeable.class.isAssignableFrom(URLClassLoader.class))
-            return new URLClassLoader(urls, thisClassLoader);
-
-        // 3: Try using private reflection-based CloseableURLClassLoader
-        try {
-            return new CloseableURLClassLoader(urls, thisClassLoader);
-        } catch (Throwable t) {
-            // ignore errors loading workaround class loader, fall through
-        }
-
-        // 4: If all else fails, use plain old standard URLClassLoader
-        return new URLClassLoader(urls, thisClassLoader);
+        return getClassLoader(lb.toArray(new URL[lb.size()]));
     }
 
     public Iterable<JavaFileObject> list(Location location,
@@ -836,38 +591,6 @@
         return a.equals(b);
     }
 
-    public boolean handleOption(String current, Iterator<String> remaining) {
-        for (JavacOption o: javacFileManagerOptions) {
-            if (o.matches(current))  {
-                if (o.hasArg()) {
-                    if (remaining.hasNext()) {
-                        if (!o.process(options, current, remaining.next()))
-                            return true;
-                    }
-                } else {
-                    if (!o.process(options, current))
-                        return true;
-                }
-                // operand missing, or process returned false
-                throw new IllegalArgumentException(current);
-            }
-        }
-
-        return false;
-    }
-    // where
-        private static JavacOption[] javacFileManagerOptions =
-            RecognizedOptions.getJavacFileManagerOptions(
-            new RecognizedOptions.GrumpyHelper());
-
-    public int isSupportedOption(String option) {
-        for (JavacOption o : javacFileManagerOptions) {
-            if (o.matches(option))
-                return o.hasArg() ? 1 : 0;
-        }
-        return -1;
-    }
-
     public boolean hasLocation(Location location) {
         return getLocation(location) != null;
     }
@@ -1115,15 +838,4 @@
         }
         throw new IllegalArgumentException("Invalid relative path: " + file);
     }
-
-    private static <T> T nullCheck(T o) {
-        o.getClass(); // null check
-        return o;
-    }
-
-    private static <T> Iterable<T> nullCheck(Iterable<T> it) {
-        for (T t : it)
-            t.getClass(); // null check
-        return it;
-    }
 }
--- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java	Sat Dec 19 10:26:47 2009 -0800
@@ -66,7 +66,7 @@
      *  @param context the context
      *  @return the Paths instance for this context
      */
-    static Paths instance(Context context) {
+    public static Paths instance(Context context) {
         Paths instance = context.get(pathsKey);
         if (instance == null)
             instance = new Paths(context);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardLocation;
+
+import static java.nio.file.FileVisitOption.*;
+import static javax.tools.StandardLocation.*;
+
+import com.sun.tools.javac.file.Paths;
+import com.sun.tools.javac.util.BaseFileManager;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+
+import static com.sun.tools.javac.main.OptionName.*;
+
+
+// NOTE the imports carefully for this compilation unit.
+//
+// Path:  java.nio.file.Path -- the new NIO type for which this file manager exists
+//
+// Paths: com.sun.tools.javac.file.Paths -- legacy javac type for handling path options
+//      The other Paths (java.nio.file.Paths) is not used
+
+// NOTE this and related classes depend on new API in JDK 7.
+// This requires special handling while bootstrapping the JDK build,
+// when these classes might not yet have been compiled. To workaround
+// this, the build arranges to make stubs of these classes available
+// when compiling this and related classes. The set of stub files
+// is specified in make/build.properties.
+
+/**
+ *  Implementation of PathFileManager: a JavaFileManager based on the use
+ *  of java.nio.file.Path.
+ *
+ *  <p>Just as a Path is somewhat analagous to a File, so too is this
+ *  JavacPathFileManager analogous to JavacFileManager, as it relates to the
+ *  support of FileObjects based on File objects (i.e. just RegularFileObject,
+ *  not ZipFileObject and its variants.)
+ *
+ *  <p>The default values for the standard locations supported by this file
+ *  manager are the same as the default values provided by JavacFileManager --
+ *  i.e. as determined by the javac.file.Paths class. To override these values,
+ *  call {@link #setLocation}.
+ *
+ *  <p>To reduce confusion with Path objects, the locations such as "class path",
+ *  "source path", etc, are generically referred to here as "search paths".
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class JavacPathFileManager extends BaseFileManager implements PathFileManager {
+    protected FileSystem defaultFileSystem;
+
+    /**
+     * Create a JavacPathFileManager using a given context, optionally registering
+     * it as the JavaFileManager for that context.
+     */
+    public JavacPathFileManager(Context context, boolean register, Charset charset) {
+        super(charset);
+        if (register)
+            context.put(JavaFileManager.class, this);
+        pathsForLocation = new HashMap<Location, PathsForLocation>();
+        fileSystems = new HashMap<Path,FileSystem>();
+        setContext(context);
+    }
+
+    /**
+     * Set the context for JavacPathFileManager.
+     */
+    @Override
+    protected void setContext(Context context) {
+        super.setContext(context);
+        searchPaths = Paths.instance(context);
+    }
+
+    @Override
+    public FileSystem getDefaultFileSystem() {
+        if (defaultFileSystem == null)
+            defaultFileSystem = FileSystems.getDefault();
+        return defaultFileSystem;
+    }
+
+    @Override
+    public void setDefaultFileSystem(FileSystem fs) {
+        defaultFileSystem = fs;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        contentCache.clear();
+    }
+
+    @Override
+    public void close() throws IOException {
+        for (FileSystem fs: fileSystems.values())
+            fs.close();
+    }
+
+    @Override
+    public ClassLoader getClassLoader(Location location) {
+        nullCheck(location);
+        Iterable<? extends Path> path = getLocation(location);
+        if (path == null)
+            return null;
+        ListBuffer<URL> lb = new ListBuffer<URL>();
+        for (Path p: path) {
+            try {
+                lb.append(p.toUri().toURL());
+            } catch (MalformedURLException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        return getClassLoader(lb.toArray(new URL[lb.size()]));
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="Location handling">
+
+    public boolean hasLocation(Location location) {
+        return (getLocation(location) != null);
+    }
+
+    public Iterable<? extends Path> getLocation(Location location) {
+        nullCheck(location);
+        lazyInitSearchPaths();
+        PathsForLocation path = pathsForLocation.get(location);
+        if (path == null && !pathsForLocation.containsKey(location)) {
+            setDefaultForLocation(location);
+            path = pathsForLocation.get(location);
+        }
+        return path;
+    }
+
+    private Path getOutputLocation(Location location) {
+        Iterable<? extends Path> paths = getLocation(location);
+        return (paths == null ? null : paths.iterator().next());
+    }
+
+    public void setLocation(Location location, Iterable<? extends Path> searchPath)
+            throws IOException
+    {
+        nullCheck(location);
+        lazyInitSearchPaths();
+        if (searchPath == null) {
+            setDefaultForLocation(location);
+        } else {
+            if (location.isOutputLocation())
+                checkOutputPath(searchPath);
+            PathsForLocation pl = new PathsForLocation();
+            for (Path p: searchPath)
+                pl.add(p);  // TODO -Xlint:path warn if path not found
+            pathsForLocation.put(location, pl);
+        }
+    }
+
+    private void checkOutputPath(Iterable<? extends Path> searchPath) throws IOException {
+        Iterator<? extends Path> pathIter = searchPath.iterator();
+        if (!pathIter.hasNext())
+            throw new IllegalArgumentException("empty path for directory");
+        Path path = pathIter.next();
+        if (pathIter.hasNext())
+            throw new IllegalArgumentException("path too long for directory");
+        if (!path.exists())
+            throw new FileNotFoundException(path + ": does not exist");
+        else if (!isDirectory(path))
+            throw new IOException(path + ": not a directory");
+    }
+
+    private void setDefaultForLocation(Location locn) {
+        Collection<File> files = null;
+        if (locn instanceof StandardLocation) {
+            switch ((StandardLocation) locn) {
+                case CLASS_PATH:
+                    files = searchPaths.userClassPath();
+                    break;
+                case PLATFORM_CLASS_PATH:
+                    files = searchPaths.bootClassPath();
+                    break;
+                case SOURCE_PATH:
+                    files = searchPaths.sourcePath();
+                    break;
+                case CLASS_OUTPUT: {
+                    String arg = options.get(D);
+                    files = (arg == null ? null : Collections.singleton(new File(arg)));
+                    break;
+                }
+                case SOURCE_OUTPUT: {
+                    String arg = options.get(S);
+                    files = (arg == null ? null : Collections.singleton(new File(arg)));
+                    break;
+                }
+            }
+        }
+
+        PathsForLocation pl = new PathsForLocation();
+        if (files != null) {
+            for (File f: files)
+                pl.add(f.toPath());
+        }
+        pathsForLocation.put(locn, pl);
+    }
+
+    private void lazyInitSearchPaths() {
+        if (!inited) {
+            setDefaultForLocation(PLATFORM_CLASS_PATH);
+            setDefaultForLocation(CLASS_PATH);
+            setDefaultForLocation(SOURCE_PATH);
+            inited = true;
+        }
+    }
+    // where
+        private boolean inited = false;
+
+    private Map<Location, PathsForLocation> pathsForLocation;
+    private Paths searchPaths;
+
+    private static class PathsForLocation extends LinkedHashSet<Path> {
+        private static final long serialVersionUID = 6788510222394486733L;
+    }
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="FileObject handling">
+
+    @Override
+    public Path getPath(FileObject fo) {
+        nullCheck(fo);
+        if (!(fo instanceof PathFileObject))
+            throw new IllegalArgumentException();
+        return ((PathFileObject) fo).getPath();
+    }
+
+    @Override
+    public boolean isSameFile(FileObject a, FileObject b) {
+        nullCheck(a);
+        nullCheck(b);
+        if (!(a instanceof PathFileObject))
+            throw new IllegalArgumentException("Not supported: " + a);
+        if (!(b instanceof PathFileObject))
+            throw new IllegalArgumentException("Not supported: " + b);
+        return ((PathFileObject) a).isSameFile((PathFileObject) b);
+    }
+
+    @Override
+    public Iterable<JavaFileObject> list(Location location,
+            String packageName, Set<Kind> kinds, boolean recurse)
+            throws IOException {
+        // validatePackageName(packageName);
+        nullCheck(packageName);
+        nullCheck(kinds);
+
+        Iterable<? extends Path> paths = getLocation(location);
+        if (paths == null)
+            return List.nil();
+        ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
+
+        for (Path path : paths)
+            list(path, packageName, kinds, recurse, results);
+
+        return results.toList();
+    }
+
+    private void list(Path path, String packageName, final Set<Kind> kinds,
+            boolean recurse, final ListBuffer<JavaFileObject> results)
+            throws IOException {
+        if (!path.exists())
+            return;
+
+        final Path pathDir;
+        if (isDirectory(path))
+            pathDir = path;
+        else {
+            FileSystem fs = getFileSystem(path);
+            if (fs == null)
+                return;
+            pathDir = fs.getRootDirectories().iterator().next();
+        }
+        String sep = path.getFileSystem().getSeparator();
+        Path packageDir = packageName.isEmpty() ? pathDir
+                : pathDir.resolve(packageName.replace(".", sep));
+        if (!packageDir.exists())
+            return;
+
+/* Alternate impl of list, superceded by use of Files.walkFileTree */
+//        Deque<Path> queue = new LinkedList<Path>();
+//        queue.add(packageDir);
+//
+//        Path dir;
+//        while ((dir = queue.poll()) != null) {
+//            DirectoryStream<Path> ds = dir.newDirectoryStream();
+//            try {
+//                for (Path p: ds) {
+//                    String name = p.getName().toString();
+//                    if (isDirectory(p)) {
+//                        if (recurse && SourceVersion.isIdentifier(name)) {
+//                            queue.add(p);
+//                        }
+//                    } else {
+//                        if (kinds.contains(getKind(name))) {
+//                            JavaFileObject fe =
+//                                PathFileObject.createDirectoryPathFileObject(this, p, pathDir);
+//                            results.append(fe);
+//                        }
+//                    }
+//                }
+//            } finally {
+//                ds.close();
+//            }
+//        }
+        int maxDepth = (recurse ? Integer.MAX_VALUE : 1);
+        Set<FileVisitOption> opts = EnumSet.of(DETECT_CYCLES, FOLLOW_LINKS);
+        Files.walkFileTree(packageDir, opts, maxDepth,
+                new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir) {
+                if (SourceVersion.isIdentifier(dir.getName().toString())) // JSR 292?
+                    return FileVisitResult.CONTINUE;
+                else
+                    return FileVisitResult.SKIP_SUBTREE;
+            }
+
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+                if (attrs.isRegularFile() && kinds.contains(getKind(file.getName().toString()))) {
+                    JavaFileObject fe =
+                        PathFileObject.createDirectoryPathFileObject(
+                            JavacPathFileManager.this, file, pathDir);
+                    results.append(fe);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    @Override
+    public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
+        Iterable<? extends Path> paths) {
+        ArrayList<PathFileObject> result;
+        if (paths instanceof Collection<?>)
+            result = new ArrayList<PathFileObject>(((Collection<?>)paths).size());
+        else
+            result = new ArrayList<PathFileObject>();
+        for (Path p: paths)
+            result.add(PathFileObject.createSimplePathFileObject(this, nullCheck(p)));
+        return result;
+    }
+
+    @Override
+    public Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths) {
+        return getJavaFileObjectsFromPaths(Arrays.asList(nullCheck(paths)));
+    }
+
+    @Override
+    public JavaFileObject getJavaFileForInput(Location location,
+            String className, Kind kind) throws IOException {
+        return getFileForInput(location, getRelativePath(className, kind));
+    }
+
+    @Override
+    public FileObject getFileForInput(Location location,
+            String packageName, String relativeName) throws IOException {
+        return getFileForInput(location, getRelativePath(packageName, relativeName));
+    }
+
+    private JavaFileObject getFileForInput(Location location, String relativePath)
+            throws IOException {
+        for (Path p: getLocation(location)) {
+            if (isDirectory(p)) {
+                Path f = resolve(p, relativePath);
+                if (f.exists())
+                    return PathFileObject.createDirectoryPathFileObject(this, f, p);
+            } else {
+                FileSystem fs = getFileSystem(p);
+                if (fs != null) {
+                    Path file = getPath(fs, relativePath);
+                    if (file.exists())
+                        return PathFileObject.createJarPathFileObject(this, file);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public JavaFileObject getJavaFileForOutput(Location location,
+            String className, Kind kind, FileObject sibling) throws IOException {
+        return getFileForOutput(location, getRelativePath(className, kind), sibling);
+    }
+
+    @Override
+    public FileObject getFileForOutput(Location location, String packageName,
+            String relativeName, FileObject sibling)
+            throws IOException {
+        return getFileForOutput(location, getRelativePath(packageName, relativeName), sibling);
+    }
+
+    private JavaFileObject getFileForOutput(Location location,
+            String relativePath, FileObject sibling) {
+        Path dir = getOutputLocation(location);
+        if (dir == null) {
+            if (location == CLASS_OUTPUT) {
+                Path siblingDir = null;
+                if (sibling != null && sibling instanceof PathFileObject) {
+                    siblingDir = ((PathFileObject) sibling).getPath().getParent();
+                }
+                return PathFileObject.createSiblingPathFileObject(this,
+                        siblingDir.resolve(getBaseName(relativePath)),
+                        relativePath);
+            } else if (location == SOURCE_OUTPUT) {
+                dir = getOutputLocation(CLASS_OUTPUT);
+            }
+        }
+
+        Path file;
+        if (dir != null) {
+            file = resolve(dir, relativePath);
+            return PathFileObject.createDirectoryPathFileObject(this, file, dir);
+        } else {
+            file = getPath(getDefaultFileSystem(), relativePath);
+            return PathFileObject.createSimplePathFileObject(this, file);
+        }
+
+    }
+
+    @Override
+    public String inferBinaryName(Location location, JavaFileObject fo) {
+        nullCheck(fo);
+        // Need to match the path semantics of list(location, ...)
+        Iterable<? extends Path> paths = getLocation(location);
+        if (paths == null) {
+            return null;
+        }
+
+        if (!(fo instanceof PathFileObject))
+            throw new IllegalArgumentException(fo.getClass().getName());
+
+        return ((PathFileObject) fo).inferBinaryName(paths);
+    }
+
+    private FileSystem getFileSystem(Path p) throws IOException {
+        FileSystem fs = fileSystems.get(p);
+        if (fs == null) {
+            fs = FileSystems.newFileSystem(p, Collections.<String,Void>emptyMap(), null);
+            fileSystems.put(p, fs);
+        }
+        return fs;
+    }
+
+    private Map<Path,FileSystem> fileSystems;
+
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Utility methods">
+
+    private static String getRelativePath(String className, Kind kind) {
+        return className.replace(".", "/") + kind.extension;
+    }
+
+    private static String getRelativePath(String packageName, String relativeName) {
+        return packageName.replace(".", "/") + relativeName;
+    }
+
+    private static String getBaseName(String relativePath) {
+        int lastSep = relativePath.lastIndexOf("/");
+        return relativePath.substring(lastSep + 1); // safe if "/" not found
+    }
+
+    private static boolean isDirectory(Path path) throws IOException {
+        BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+        return attrs.isDirectory();
+    }
+
+    private static Path getPath(FileSystem fs, String relativePath) {
+        return fs.getPath(relativePath.replace("/", fs.getSeparator()));
+    }
+
+    private static Path resolve(Path base, String relativePath) {
+        FileSystem fs = base.getFileSystem();
+        Path rp = fs.getPath(relativePath.replace("/", fs.getSeparator()));
+        return base.resolve(rp);
+    }
+
+    // </editor-fold>
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileManager.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import javax.tools.FileObject;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+
+/**
+ *  File manager based on {@linkplain File java.nio.file.Path}.
+ *
+ *  Eventually, this should be moved to javax.tools.
+ *  Also, JavaCompiler might reasonably provide a method getPathFileManager,
+ *  similar to {@link javax.tools.JavaCompiler#getStandardFileManager
+ *  getStandardFileManager}. However, would need to be handled carefully
+ *  as another forward reference from langtools to jdk.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public interface PathFileManager extends JavaFileManager {
+    /**
+     * Get the default file system used to create paths. If no value has been
+     * set, the default file system is {@link FileSystems#getDefault}.
+     */
+    FileSystem getDefaultFileSystem();
+
+    /**
+     * Set the default file system used to create paths.
+     * @param fs the default file system used to create any new paths.
+     */
+    void setDefaultFileSystem(FileSystem fs);
+
+    /**
+     * Get file objects representing the given files.
+     *
+     * @param paths a list of paths
+     * @return a list of file objects
+     * @throws IllegalArgumentException if the list of paths includes
+     * a directory
+     */
+    Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
+        Iterable<? extends Path> paths);
+
+    /**
+     * Get file objects representing the given paths.
+     * Convenience method equivalent to:
+     *
+     * <pre>
+     *     getJavaFileObjectsFromPaths({@linkplain java.util.Arrays#asList Arrays.asList}(paths))
+     * </pre>
+     *
+     * @param paths an array of paths
+     * @return a list of file objects
+     * @throws IllegalArgumentException if the array of files includes
+     * a directory
+     * @throws NullPointerException if the given array contains null
+     * elements
+     */
+    Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths);
+
+    /**
+     * Return the Path for a file object that has been obtained from this
+     * file manager.
+     *
+     * @param fo A file object that has been obtained from this file manager.
+     * @return The underlying Path object.
+     * @throws IllegalArgumentException is the file object was not obtained from
+     * from this file manager.
+     */
+    Path getPath(FileObject fo);
+
+    /**
+     * Get the search path associated with the given location.
+     *
+     * @param location a location
+     * @return a list of paths or {@code null} if this location has no
+     * associated search path
+     * @see #setLocation
+     */
+    Iterable<? extends Path> getLocation(Location location);
+
+    /**
+     * Associate the given search path with the given location.  Any
+     * previous value will be discarded.
+     *
+     * @param location a location
+     * @param searchPath a list of files, if {@code null} use the default
+     * search path for this location
+     * @see #getLocation
+     * @throws IllegalArgumentException if location is an output
+     * location and searchpath does not contain exactly one element
+     * @throws IOException if location is an output location and searchpath
+     * does not represent an existing directory
+     */
+    void setLocation(Location location, Iterable<? extends Path> searchPath) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.util.BaseFileManager;
+
+
+/**
+ *  Implementation of JavaFileObject using java.nio.file API.
+ *
+ *  <p>PathFileObjects are, for the most part, straightforward wrappers around
+ *  Path objects. The primary complexity is the support for "inferBinaryName".
+ *  This is left as an abstract method, implemented by each of a number of
+ *  different factory methods, which compute the binary name based on
+ *  information available at the time the file object is created.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+abstract class PathFileObject implements JavaFileObject {
+    private JavacPathFileManager fileManager;
+    private Path path;
+
+    /**
+     * Create a PathFileObject within a directory, such that the binary name
+     * can be inferred from the relationship to the parent directory.
+     */
+    static PathFileObject createDirectoryPathFileObject(JavacPathFileManager fileManager,
+            final Path path, final Path dir) {
+        return new PathFileObject(fileManager, path) {
+            @Override
+            String inferBinaryName(Iterable<? extends Path> paths) {
+                return toBinaryName(dir.relativize(path));
+            }
+        };
+    }
+
+    /**
+     * Create a PathFileObject in a file system such as a jar file, such that
+     * the binary name can be inferred from its position within the filesystem.
+     */
+    static PathFileObject createJarPathFileObject(JavacPathFileManager fileManager,
+            final Path path) {
+        return new PathFileObject(fileManager, path) {
+            @Override
+            String inferBinaryName(Iterable<? extends Path> paths) {
+                return toBinaryName(path);
+            }
+        };
+    }
+
+    /**
+     * Create a PathFileObject whose binary name can be inferred from the
+     * relative path to a sibling.
+     */
+    static PathFileObject createSiblingPathFileObject(JavacPathFileManager fileManager,
+            final Path path, final String relativePath) {
+        return new PathFileObject(fileManager, path) {
+            @Override
+            String inferBinaryName(Iterable<? extends Path> paths) {
+                return toBinaryName(relativePath, "/");
+            }
+        };
+    }
+
+    /**
+     * Create a PathFileObject whose binary name might be inferred from its
+     * position on a search path.
+     */
+    static PathFileObject createSimplePathFileObject(JavacPathFileManager fileManager,
+            final Path path) {
+        return new PathFileObject(fileManager, path) {
+            @Override
+            String inferBinaryName(Iterable<? extends Path> paths) {
+                Path absPath = path.toAbsolutePath();
+                for (Path p: paths) {
+                    Path ap = p.toAbsolutePath();
+                    if (absPath.startsWith(ap)) {
+                        try {
+                            Path rp = ap.relativize(absPath);
+                            if (rp != null) // maybe null if absPath same as ap
+                                return toBinaryName(rp);
+                        } catch (IllegalArgumentException e) {
+                            // ignore this p if cannot relativize path to p
+                        }
+                    }
+                }
+                return null;
+            }
+        };
+    }
+
+    protected PathFileObject(JavacPathFileManager fileManager, Path path) {
+        fileManager.getClass(); // null check
+        path.getClass();        // null check
+        this.fileManager = fileManager;
+        this.path = path;
+    }
+
+    abstract String inferBinaryName(Iterable<? extends Path> paths);
+
+    /**
+     * Return the Path for this object.
+     * @return the Path for this object.
+     */
+    Path getPath() {
+        return path;
+    }
+
+    @Override
+    public Kind getKind() {
+        return BaseFileManager.getKind(path.getName().toString());
+    }
+
+    @Override
+    public boolean isNameCompatible(String simpleName, Kind kind) {
+        simpleName.getClass();
+        // null check
+        if (kind == Kind.OTHER && getKind() != kind) {
+            return false;
+        }
+        String sn = simpleName + kind.extension;
+        String pn = path.getName().toString();
+        if (pn.equals(sn)) {
+            return true;
+        }
+        if (pn.equalsIgnoreCase(sn)) {
+            try {
+                // allow for Windows
+                return path.toRealPath(false).getName().toString().equals(sn);
+            } catch (IOException e) {
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public NestingKind getNestingKind() {
+        return null;
+    }
+
+    @Override
+    public Modifier getAccessLevel() {
+        return null;
+    }
+
+    @Override
+    public URI toUri() {
+        return path.toUri();
+    }
+
+    @Override
+    public String getName() {
+        return path.toString();
+    }
+
+    @Override
+    public InputStream openInputStream() throws IOException {
+        return path.newInputStream();
+    }
+
+    @Override
+    public OutputStream openOutputStream() throws IOException {
+        ensureParentDirectoriesExist();
+        return path.newOutputStream();
+    }
+
+    @Override
+    public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+        CharsetDecoder decoder = fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
+        return new InputStreamReader(openInputStream(), decoder);
+    }
+
+    @Override
+    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+        CharBuffer cb = fileManager.getCachedContent(this);
+        if (cb == null) {
+            InputStream in = openInputStream();
+            try {
+                ByteBuffer bb = fileManager.makeByteBuffer(in);
+                JavaFileObject prev = fileManager.log.useSource(this);
+                try {
+                    cb = fileManager.decode(bb, ignoreEncodingErrors);
+                } finally {
+                    fileManager.log.useSource(prev);
+                }
+                fileManager.recycleByteBuffer(bb);
+                if (!ignoreEncodingErrors) {
+                    fileManager.cache(this, cb);
+                }
+            } finally {
+                in.close();
+            }
+        }
+        return cb;
+    }
+
+    @Override
+    public Writer openWriter() throws IOException {
+        ensureParentDirectoriesExist();
+        return new OutputStreamWriter(path.newOutputStream(), fileManager.getEncodingName());
+    }
+
+    @Override
+    public long getLastModified() {
+        try {
+            BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+            return attrs.lastModifiedTime().toMillis();
+        } catch (IOException e) {
+            return -1;
+        }
+    }
+
+    @Override
+    public boolean delete() {
+        try {
+            path.delete();
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    public boolean isSameFile(PathFileObject other) {
+        try {
+            return path.isSameFile(other.path);
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return (other instanceof PathFileObject && path.equals(((PathFileObject) other).path));
+    }
+
+    @Override
+    public int hashCode() {
+        return path.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + path + "]";
+    }
+
+    private void ensureParentDirectoriesExist() throws IOException {
+        Path parent = path.getParent();
+        if (parent != null)
+            Files.createDirectories(parent);
+    }
+
+    private long size() {
+        try {
+            BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+            return attrs.size();
+        } catch (IOException e) {
+            return -1;
+        }
+    }
+
+    protected static String toBinaryName(Path relativePath) {
+        return toBinaryName(relativePath.toString(),
+                relativePath.getFileSystem().getSeparator());
+    }
+
+    protected static String toBinaryName(String relativePath, String sep) {
+        return removeExtension(relativePath).replaceAll(sep, ".");
+    }
+
+    protected static String removeExtension(String fileName) {
+        int lastDot = fileName.lastIndexOf(".");
+        return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.util;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.main.JavacOption;
+import com.sun.tools.javac.main.OptionName;
+import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+
+/**
+ * Utility methods for building a filemanager.
+ * There are no references here to file-system specific objects such as
+ * java.io.File or java.nio.file.Path.
+ */
+public class BaseFileManager {
+    protected BaseFileManager(Charset charset) {
+        this.charset = charset;
+        byteBufferCache = new ByteBufferCache();
+    }
+
+    /**
+     * Set the context for JavacPathFileManager.
+     */
+    protected void setContext(Context context) {
+        log = Log.instance(context);
+        options = Options.instance(context);
+        classLoaderClass = options.get("procloader");
+    }
+
+    /**
+     * The log to be used for error reporting.
+     */
+    public Log log;
+
+    /**
+     * User provided charset (through javax.tools).
+     */
+    protected Charset charset;
+
+    protected Options options;
+
+    protected String classLoaderClass;
+
+    protected Source getSource() {
+        String sourceName = options.get(OptionName.SOURCE);
+        Source source = null;
+        if (sourceName != null)
+            source = Source.lookup(sourceName);
+        return (source != null ? source : Source.DEFAULT);
+    }
+
+    protected ClassLoader getClassLoader(URL[] urls) {
+        ClassLoader thisClassLoader = getClass().getClassLoader();
+
+        // Bug: 6558476
+        // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
+        // On older versions, try the following, to get a closeable classloader.
+
+        // 1: Allow client to specify the class to use via hidden option
+        if (classLoaderClass != null) {
+            try {
+                Class<? extends ClassLoader> loader =
+                        Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
+                Class<?>[] constrArgTypes = { URL[].class, ClassLoader.class };
+                Constructor<? extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
+                return constr.newInstance(new Object[] { urls, thisClassLoader });
+            } catch (Throwable t) {
+                // ignore errors loading user-provided class loader, fall through
+            }
+        }
+
+        // 2: If URLClassLoader implements Closeable, use that.
+        if (Closeable.class.isAssignableFrom(URLClassLoader.class))
+            return new URLClassLoader(urls, thisClassLoader);
+
+        // 3: Try using private reflection-based CloseableURLClassLoader
+        try {
+            return new CloseableURLClassLoader(urls, thisClassLoader);
+        } catch (Throwable t) {
+            // ignore errors loading workaround class loader, fall through
+        }
+
+        // 4: If all else fails, use plain old standard URLClassLoader
+        return new URLClassLoader(urls, thisClassLoader);
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="Option handling">
+    public boolean handleOption(String current, Iterator<String> remaining) {
+        for (JavacOption o: javacFileManagerOptions) {
+            if (o.matches(current))  {
+                if (o.hasArg()) {
+                    if (remaining.hasNext()) {
+                        if (!o.process(options, current, remaining.next()))
+                            return true;
+                    }
+                } else {
+                    if (!o.process(options, current))
+                        return true;
+                }
+                // operand missing, or process returned false
+                throw new IllegalArgumentException(current);
+            }
+        }
+
+        return false;
+    }
+    // where
+        private static JavacOption[] javacFileManagerOptions =
+            RecognizedOptions.getJavacFileManagerOptions(
+            new RecognizedOptions.GrumpyHelper());
+
+    public int isSupportedOption(String option) {
+        for (JavacOption o : javacFileManagerOptions) {
+            if (o.matches(option))
+                return o.hasArg() ? 1 : 0;
+        }
+        return -1;
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Encoding">
+    private String defaultEncodingName;
+    private String getDefaultEncodingName() {
+        if (defaultEncodingName == null) {
+            defaultEncodingName =
+                new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
+        }
+        return defaultEncodingName;
+    }
+
+    public String getEncodingName() {
+        String encName = options.get(OptionName.ENCODING);
+        if (encName == null)
+            return getDefaultEncodingName();
+        else
+            return encName;
+    }
+
+    public CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
+        String encodingName = getEncodingName();
+        CharsetDecoder decoder;
+        try {
+            decoder = getDecoder(encodingName, ignoreEncodingErrors);
+        } catch (IllegalCharsetNameException e) {
+            log.error("unsupported.encoding", encodingName);
+            return (CharBuffer)CharBuffer.allocate(1).flip();
+        } catch (UnsupportedCharsetException e) {
+            log.error("unsupported.encoding", encodingName);
+            return (CharBuffer)CharBuffer.allocate(1).flip();
+        }
+
+        // slightly overestimate the buffer size to avoid reallocation.
+        float factor =
+            decoder.averageCharsPerByte() * 0.8f +
+            decoder.maxCharsPerByte() * 0.2f;
+        CharBuffer dest = CharBuffer.
+            allocate(10 + (int)(inbuf.remaining()*factor));
+
+        while (true) {
+            CoderResult result = decoder.decode(inbuf, dest, true);
+            dest.flip();
+
+            if (result.isUnderflow()) { // done reading
+                // make sure there is at least one extra character
+                if (dest.limit() == dest.capacity()) {
+                    dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
+                    dest.flip();
+                }
+                return dest;
+            } else if (result.isOverflow()) { // buffer too small; expand
+                int newCapacity =
+                    10 + dest.capacity() +
+                    (int)(inbuf.remaining()*decoder.maxCharsPerByte());
+                dest = CharBuffer.allocate(newCapacity).put(dest);
+            } else if (result.isMalformed() || result.isUnmappable()) {
+                // bad character in input
+
+                // report coding error (warn only pre 1.5)
+                if (!getSource().allowEncodingErrors()) {
+                    log.error(new SimpleDiagnosticPosition(dest.limit()),
+                              "illegal.char.for.encoding",
+                              charset == null ? encodingName : charset.name());
+                } else {
+                    log.warning(new SimpleDiagnosticPosition(dest.limit()),
+                                "illegal.char.for.encoding",
+                                charset == null ? encodingName : charset.name());
+                }
+
+                // skip past the coding error
+                inbuf.position(inbuf.position() + result.length());
+
+                // undo the flip() to prepare the output buffer
+                // for more translation
+                dest.position(dest.limit());
+                dest.limit(dest.capacity());
+                dest.put((char)0xfffd); // backward compatible
+            } else {
+                throw new AssertionError(result);
+            }
+        }
+        // unreached
+    }
+
+    public CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
+        Charset cs = (this.charset == null)
+            ? Charset.forName(encodingName)
+            : this.charset;
+        CharsetDecoder decoder = cs.newDecoder();
+
+        CodingErrorAction action;
+        if (ignoreEncodingErrors)
+            action = CodingErrorAction.REPLACE;
+        else
+            action = CodingErrorAction.REPORT;
+
+        return decoder
+            .onMalformedInput(action)
+            .onUnmappableCharacter(action);
+    }
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="ByteBuffers">
+    /**
+     * Make a byte buffer from an input stream.
+     */
+    public ByteBuffer makeByteBuffer(InputStream in)
+        throws IOException {
+        int limit = in.available();
+        if (limit < 1024) limit = 1024;
+        ByteBuffer result = byteBufferCache.get(limit);
+        int position = 0;
+        while (in.available() != 0) {
+            if (position >= limit)
+                // expand buffer
+                result = ByteBuffer.
+                    allocate(limit <<= 1).
+                    put((ByteBuffer)result.flip());
+            int count = in.read(result.array(),
+                position,
+                limit - position);
+            if (count < 0) break;
+            result.position(position += count);
+        }
+        return (ByteBuffer)result.flip();
+    }
+
+    public void recycleByteBuffer(ByteBuffer bb) {
+        byteBufferCache.put(bb);
+    }
+
+    /**
+     * A single-element cache of direct byte buffers.
+     */
+    private static class ByteBufferCache {
+        private ByteBuffer cached;
+        ByteBuffer get(int capacity) {
+            if (capacity < 20480) capacity = 20480;
+            ByteBuffer result =
+                (cached != null && cached.capacity() >= capacity)
+                ? (ByteBuffer)cached.clear()
+                : ByteBuffer.allocate(capacity + capacity>>1);
+            cached = null;
+            return result;
+        }
+        void put(ByteBuffer x) {
+            cached = x;
+        }
+    }
+
+    private final ByteBufferCache byteBufferCache;
+    // </editor-fold>
+
+    // <editor-fold defaultstate="collapsed" desc="Content cache">
+    public CharBuffer getCachedContent(JavaFileObject file) {
+        SoftReference<CharBuffer> r = contentCache.get(file);
+        return (r == null ? null : r.get());
+    }
+
+    public void cache(JavaFileObject file, CharBuffer cb) {
+        contentCache.put(file, new SoftReference<CharBuffer>(cb));
+    }
+
+    protected final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
+            = new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
+    // </editor-fold>
+
+    public static Kind getKind(String name) {
+        if (name.endsWith(Kind.CLASS.extension))
+            return Kind.CLASS;
+        else if (name.endsWith(Kind.SOURCE.extension))
+            return Kind.SOURCE;
+        else if (name.endsWith(Kind.HTML.extension))
+            return Kind.HTML;
+        else
+            return Kind.OTHER;
+    }
+
+    protected static <T> T nullCheck(T o) {
+        o.getClass(); // null check
+        return o;
+    }
+
+    protected static <T> Collection<T> nullCheck(Collection<T> it) {
+        for (T t : it)
+            t.getClass(); // null check
+        return it;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/CloseableURLClassLoader.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.jar.JarFile;
+
+/**
+ * A URLClassLoader that also implements Closeable.
+ * Reflection is used to access internal data structures in the URLClassLoader,
+ * since no public API exists for this purpose. Therefore this code is somewhat
+ * fragile. Caveat emptor.
+ * @throws Error if the internal data structures are not as expected.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class CloseableURLClassLoader
+        extends URLClassLoader implements Closeable {
+    public CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
+        super(urls, parent);
+        try {
+            getLoaders(); //proactive check that URLClassLoader is as expected
+        } catch (Throwable t) {
+            throw new Error("cannot create CloseableURLClassLoader", t);
+        }
+    }
+
+    /**
+     * Close any jar files that may have been opened by the class loader.
+     * Reflection is used to access the jar files in the URLClassLoader's
+     * internal data structures.
+     * @throws java.io.IOException if the jar files cannot be found for any
+     * reson, or if closing the jar file itself causes an IOException.
+     */
+    @Override
+    public void close() throws IOException {
+        try {
+            for (Object l: getLoaders()) {
+                if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
+                    Field jarField = l.getClass().getDeclaredField("jar");
+                    JarFile jar = (JarFile) getField(l, jarField);
+                    if (jar != null) {
+                        //System.err.println("CloseableURLClassLoader: closing " + jar);
+                        jar.close();
+                    }
+                }
+            }
+        } catch (Throwable t) {
+            IOException e = new IOException("cannot close class loader");
+            e.initCause(t);
+            throw e;
+        }
+    }
+
+    private ArrayList<?> getLoaders()
+            throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
+    {
+        Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
+        Object urlClassPath = getField(this, ucpField);
+        if (urlClassPath == null)
+            throw new AssertionError("urlClassPath not set in URLClassLoader");
+        Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
+        return (ArrayList<?>) getField(urlClassPath, loadersField);
+    }
+
+    private Object getField(Object o, Field f)
+            throws IllegalArgumentException, IllegalAccessException {
+        boolean prev = f.isAccessible();
+        try {
+            f.setAccessible(true);
+            return f.get(o);
+        } finally {
+            f.setAccessible(prev);
+        }
+    }
+
+}
--- a/langtools/src/share/classes/javax/lang/model/element/package-info.java	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/javax/lang/model/element/package-info.java	Sat Dec 19 10:26:47 2009 -0800
@@ -26,6 +26,16 @@
 /**
  * Interfaces used to model elements of the Java programming language.
  *
+ * The term "element" in this package is used to refer to program
+ * elements, the declared entities that make up a program.  Elements
+ * include classes, interfaces, methods, constructors, and fields.
+ * The interfaces in this package do not model the structure of a
+ * program inside a method body; for example there is no
+ * representation of a {@code for} loop or {@code try}-{@code finally}
+ * block.  However, the interfaces can model some structures only
+ * appearing inside method bodies, such as local variables and
+ * anonymous classes.
+ *
  * <p>When used in the context of annotation processing, an accurate
  * model of the element being represented must be returned.  As this
  * is a language model, the source code provides the fiducial
--- a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java	Sat Dec 19 10:26:47 2009 -0800
@@ -28,7 +28,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.*;
-import java.util.concurrent.*;
 
 /**
  * File manager based on {@linkplain File java.io.File}.  A common way
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/nio/compileTest/CompileTest.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @compile HelloPathWorld.java
+ * @run main CompileTest
+ */
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.jar.*;
+import javax.tools.*;
+
+import com.sun.tools.javac.nio.*;
+import com.sun.tools.javac.util.Context;
+import java.nio.file.spi.FileSystemProvider;
+
+
+public class CompileTest {
+    public static void main(String[] args) throws Exception {
+        new CompileTest().run();
+    }
+
+    public void run() throws Exception {
+        File rtDir = new File("rt.dir");
+        File javaHome = new File(System.getProperty("java.home"));
+        if (javaHome.getName().equals("jre"))
+            javaHome = javaHome.getParentFile();
+        File rtJar = new File(new File(new File(javaHome, "jre"), "lib"), "rt.jar");
+        expand(rtJar, rtDir);
+
+        String[] rtDir_opts = {
+            "-bootclasspath", rtDir.toString(),
+            "-classpath", "",
+            "-sourcepath", "",
+            "-extdirs", ""
+        };
+        test(rtDir_opts, "HelloPathWorld");
+
+        if (isJarFileSystemAvailable()) {
+            String[] rtJar_opts = {
+                "-bootclasspath", rtJar.toString(),
+                "-classpath", "",
+                "-sourcepath", "",
+                "-extdirs", ""
+            };
+            test(rtJar_opts, "HelloPathWorld");
+
+            String[] default_opts = { };
+            test(default_opts, "HelloPathWorld");
+
+            // finally, a non-trivial program
+            test(default_opts, "CompileTest");
+        } else
+            System.err.println("jar file system not available: test skipped");
+    }
+
+    void test(String[] opts, String className) throws Exception {
+        count++;
+        System.err.println("Test " + count + " " + Arrays.asList(opts) + " " + className);
+        Path testSrcDir = Paths.get(System.getProperty("test.src"));
+        Path testClassesDir = Paths.get(System.getProperty("test.classes"));
+        Path classes = Paths.get("classes." + count);
+        classes.createDirectory();
+
+        Context ctx = new Context();
+        PathFileManager fm = new JavacPathFileManager(ctx, true, null);
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        List<String> options = new ArrayList<String>();
+        options.addAll(Arrays.asList(opts));
+        options.addAll(Arrays.asList(
+                "-verbose", "-XDverboseCompilePolicy",
+                "-d", classes.toString()
+        ));
+        Iterable<? extends JavaFileObject> compilationUnits =
+                fm.getJavaFileObjects(testSrcDir.resolve(className + ".java"));
+        StringWriter sw = new StringWriter();
+        PrintWriter out = new PrintWriter(sw);
+        JavaCompiler.CompilationTask t =
+                compiler.getTask(out, fm, null, options, null, compilationUnits);
+        boolean ok = t.call();
+        System.err.println(sw.toString());
+        if (!ok) {
+            throw new Exception("compilation failed");
+        }
+
+        File expect = new File("classes." + count + "/" + className + ".class");
+        if (!expect.exists())
+            throw new Exception("expected file not found: " + expect);
+        long expectedSize = new File(testClassesDir.toString(), className + ".class").length();
+        long actualSize = expect.length();
+        if (expectedSize != actualSize)
+            throw new Exception("wrong size found: " + actualSize + "; expected: " + expectedSize);
+    }
+
+    boolean isJarFileSystemAvailable() {
+        boolean result = false;
+        for (FileSystemProvider fsp: FileSystemProvider.installedProviders()) {
+            String scheme = fsp.getScheme();
+            System.err.println("Provider: " + scheme + " " + fsp);
+            if (scheme.equalsIgnoreCase("jar") || scheme.equalsIgnoreCase("zip"))
+                result = true;
+        }
+        return result;
+    }
+
+    void expand(File jar, File dir) throws IOException {
+        JarFile jarFile = new JarFile(jar);
+        try {
+            Enumeration<JarEntry> entries = jarFile.entries();
+            while (entries.hasMoreElements()) {
+                JarEntry je = entries.nextElement();
+                if (!je.isDirectory()) {
+                    copy(jarFile.getInputStream(je), new File(dir, je.getName()));
+                }
+            }
+        } finally {
+            jarFile.close();
+        }
+    }
+
+    void copy(InputStream in, File dest) throws IOException {
+        dest.getParentFile().mkdirs();
+        OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
+        try {
+            byte[] data = new byte[8192];
+            int n;
+            while ((n = in.read(data, 0, data.length)) > 0)
+                out.write(data, 0, n);
+        } finally {
+            out.close();
+            in.close();
+        }
+    }
+
+    void error(String message) {
+        System.err.println("Error: " + message);
+        errors++;
+    }
+
+    int errors;
+    int count;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/nio/compileTest/HelloPathWorld.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+class HelloPathWorld {
+    public static void main(String... args) {
+        System.out.println("Hello World!");
+    }
+}
--- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java	Thu Dec 17 14:10:44 2009 -0800
+++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java	Sat Dec 19 10:26:47 2009 -0800
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938
+ * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854
  * @summary Tests that getElementsAnnotatedWith works properly.
  * @author  Joseph D. Darcy
  * @compile TestElementsAnnotatedWith.java
@@ -33,8 +33,8 @@
  * @compile -processor TestElementsAnnotatedWith -proc:only Part1.java Part2.java
  * @compile -processor TestElementsAnnotatedWith -proc:only C2.java
  * @compile -processor TestElementsAnnotatedWith -proc:only Foo.java
- * @compile -XD-d=. Foo.java
- * @compile -processor TestElementsAnnotatedWith -proc:only TestElementsAnnotatedWith.java
+ * @compile Foo.java
+ * @compile/process -processor TestElementsAnnotatedWith -proc:only Foo
  */
 
 import java.lang.annotation.Annotation;
@@ -89,7 +89,7 @@
                 // Verify that the annotation information is as
                 // expected.
 
-                Set<String> expectedNames = new HashSet<String>(Arrays.asList(annotatedElementInfo.names()));
+                Set<String> expectedNames = new HashSet<>(Arrays.asList(annotatedElementInfo.names()));
 
                 resultsMeta =
                     roundEnvironment.
@@ -126,9 +126,6 @@
                 System.err.println("AnnotatedElementInfo: " + annotatedElementInfo);
                 throw new RuntimeException();
             }
-
-            if("TestElementsAnnotatedWith".equals(firstType.getSimpleName().toString()))
-               writeClassFile(); // Start another round to test class file input
         } else {
             // If processing is over without an error, the specified
             // elements should be empty so an empty set should be returned.
@@ -163,48 +160,14 @@
         } catch(IllegalArgumentException iae) {}
 
         try {
-            Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(processingEnv.
-                                                                                        getElementUtils().
-                                                                                        getTypeElement("java.lang.Object") );
+            Set<? extends Element> elements =
+                roundEnvironment.getElementsAnnotatedWith(processingEnv.
+                                                          getElementUtils().
+                                                          getTypeElement("java.lang.Object") );
             throw new RuntimeException("Illegal argument exception not thrown");
         } catch(IllegalArgumentException iae) {}
     }
 
-    /*
-     * Hack alert!  The class file read below is generated by the
-     * "@compile -XD-d=. Foo.java" directive above.  This sneakily
-     * overrides the output location to the current directory where a
-     * subsequent @compile can read the file.  This could be improved
-     * if either a new directive like @process accepted class file
-     * arguments (the javac command accepts such arguments but
-     * @compile does not) or the test.src and test.classes properties
-     * were set to be read with @compile jobs.
-     */
-    private void writeClassFile() {
-        try {
-            Filer filer = processingEnv.getFiler();
-            JavaFileObject jfo = filer.createClassFile("Foo");
-            OutputStream os = jfo.openOutputStream();
-            // Copy the bytes over
-            System.out.println((new File(".")).getAbsolutePath());
-            InputStream io = new BufferedInputStream(new FileInputStream(new File(".", "Foo.class")));
-            try {
-                int datum = io.read();
-                while(datum != -1) {
-                    os.write(datum);
-                    datum = io.read();
-                }
-            } finally {
-                io.close();
-            }
-            os.close();
-        } catch (IOException ioe) {
-            throw new RuntimeException(ioe);
-        }
-
-
-    }
-
     @Override
     public SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latest();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/GetDeps.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Pattern;
+import javax.tools.*;
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.Dependencies.*;
+import com.sun.tools.classfile.Dependency.Location;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+
+/**
+ * Demo utility for using the classfile dependency analysis API framework.
+ *
+ * Usage:
+ *    getdeps [options] classes
+ * where options include:
+ *    -classpath path   where to find classes to analyze
+ *    -p package-name   restrict analysis to classes in this package
+ *                      (may be given multiple times)
+ *    -r regex          restrict analysis to packages matching pattern
+ *                      (-p and -r are exclusive)
+ *    -rev              invert the dependencies in the output
+ *    -t                transitive closure of dependencies
+ */
+public class GetDeps {
+    public static void main(String... args) throws Exception {
+        new GetDeps().run(args);
+    }
+
+    void run(String... args) throws IOException, ClassFileNotFoundException {
+        PrintWriter pw = new PrintWriter(System.out);
+        try {
+            run(pw, args);
+        } finally {
+            pw.flush();
+        }
+    }
+
+    void run(PrintWriter out, String... args) throws IOException, ClassFileNotFoundException {
+        decodeArgs(args);
+
+        final StandardJavaFileManager fm = new JavacFileManager(new Context(), false, null);
+        if (classpath != null)
+            fm.setLocation(StandardLocation.CLASS_PATH, classpath);
+
+        ClassFileReader reader = new ClassFileReader(fm);
+
+        Dependencies d = new Dependencies();
+
+        if (regex != null)
+            d.setFilter(Dependencies.getRegexFilter(Pattern.compile(regex)));
+
+        if (packageNames.size() > 0)
+            d.setFilter(Dependencies.getPackageFilter(packageNames, false));
+
+        SortedRecorder r = new SortedRecorder(reverse);
+
+        d.findAllDependencies(reader, rootClassNames, transitiveClosure, r);
+
+        SortedMap<Location,SortedSet<Dependency>> deps = r.getMap();
+        for (Map.Entry<Location, SortedSet<Dependency>> e: deps.entrySet()) {
+            out.println(e.getKey());
+            for (Dependency dep: e.getValue()) {
+                out.println("    " + dep.getTarget());
+            }
+        }
+    }
+
+    void decodeArgs(String... args) {
+        rootClassNames = new TreeSet<String>();
+        packageNames = new TreeSet<String>();
+
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.equals("-classpath") && (i + 1 < args.length))
+                classpath = getPathFiles(args[++i]);
+            else if (arg.equals("-p") && (i + 1 < args.length))
+                packageNames.add(args[++i]);
+            else if (arg.equals("-r") && (i + 1 < args.length))
+                regex = args[++i];
+            else if (arg.equals("-rev"))
+                reverse = true;
+            else if (arg.equals("-t"))
+                transitiveClosure = true;
+            else if (arg.startsWith("-"))
+                throw new Error(arg);
+            else {
+                for ( ; i < args.length; i++)
+                    rootClassNames.add(args[i]);
+            }
+        }
+    }
+
+    List<File> getPathFiles(String path) {
+        List<File> files = new ArrayList<File>();
+        for (String p: path.split(File.pathSeparator)) {
+            if (p.length() > 0)
+                files.add(new File(p));
+        }
+        return files;
+    }
+
+    boolean transitiveClosure;
+    List<File> classpath;
+    Set<String> rootClassNames;
+    Set<String> packageNames;
+    String regex;
+    boolean reverse;
+
+
+    static class ClassFileReader implements Dependencies.ClassFileReader {
+        private JavaFileManager fm;
+
+        ClassFileReader(JavaFileManager fm) {
+            this.fm = fm;
+        }
+
+        @Override
+        public ClassFile getClassFile(String className) throws ClassFileNotFoundException {
+            try {
+                JavaFileObject fo = fm.getJavaFileForInput(
+                        StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
+                if (fo == null)
+                    fo = fm.getJavaFileForInput(
+                        StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
+                if (fo == null)
+                    throw new ClassFileNotFoundException(className);
+                InputStream in = fo.openInputStream();
+                try {
+                    return ClassFile.read(in);
+                } finally {
+                    in.close();
+                }
+            } catch (ConstantPoolException e) {
+                throw new ClassFileNotFoundException(className, e);
+            } catch (IOException e) {
+                throw new ClassFileNotFoundException(className, e);
+            }
+        }
+    };
+
+    static class SortedRecorder implements Recorder {
+        public SortedRecorder(boolean reverse) {
+            this.reverse = reverse;
+        }
+
+        public void addDependency(Dependency d) {
+            Location o = (reverse ? d.getTarget() : d.getOrigin());
+            SortedSet<Dependency> odeps = map.get(o);
+            if (odeps == null) {
+                Comparator<Dependency> c = (reverse ? originComparator : targetComparator);
+                map.put(o, odeps = new TreeSet<Dependency>(c));
+            }
+            odeps.add(d);
+        }
+
+        public SortedMap<Location, SortedSet<Dependency>> getMap() {
+            return map;
+        }
+
+        private Comparator<Dependency> originComparator = new Comparator<Dependency>() {
+            public int compare(Dependency o1, Dependency o2) {
+                return o1.getOrigin().toString().compareTo(o2.getOrigin().toString());
+            }
+        };
+
+        private Comparator<Dependency> targetComparator = new Comparator<Dependency>() {
+            public int compare(Dependency o1, Dependency o2) {
+                return o1.getTarget().toString().compareTo(o2.getTarget().toString());
+            }
+        };
+
+        private Comparator<Location> locationComparator = new Comparator<Location>() {
+            public int compare(Location o1, Location o2) {
+                return o1.toString().compareTo(o2.toString());
+            }
+        };
+
+        private final SortedMap<Location, SortedSet<Dependency>> map =
+                new TreeMap<Location, SortedSet<Dependency>>(locationComparator);
+
+        boolean reverse;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/T6907575.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6907575
+ * @build GetDeps p.C1
+ * @run main T6907575
+ */
+
+import java.io.*;
+
+public class T6907575 {
+    public static void main(String... args) throws Exception {
+        new T6907575().run();
+    }
+
+    void run() throws Exception {
+        String testSrc = System.getProperty("test.src");
+        String testClasses = System.getProperty("test.classes");
+
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        GetDeps gd = new GetDeps();
+        gd.run(pw, "-classpath", testClasses, "-t", "-p", "p", "p/C1");
+        pw.close();
+        System.out.println(sw);
+
+        String ref = readFile(new File(testSrc, "T6907575.out"));
+        diff(sw.toString().replaceAll("[\r\n]+", "\n"), ref);
+    }
+
+    void diff(String actual, String ref) throws Exception {
+        System.out.println("EXPECT:>>>" + ref + "<<<");
+        System.out.println("ACTUAL:>>>" + actual + "<<<");
+        if (!actual.equals(ref))
+            throw new Exception("output not as expected");
+    }
+
+    String readFile(File f) throws IOException {
+        Reader r = new FileReader(f);
+        char[] buf = new char[(int) f.length()];
+        int offset = 0;
+        int n;
+        while (offset < buf.length && (n = r.read(buf, offset, buf.length - offset)) != -1)
+            offset += n;
+        return new String(buf, 0, offset);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/T6907575.out	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,8 @@
+p/C1
+    java/lang/Object
+    p/C2
+p/C2
+    java/lang/Object
+    p/C3
+p/C3
+    java/lang/Object
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/deps/p/C1.java	Sat Dec 19 10:26:47 2009 -0800
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package p;
+
+public class C1 {
+    C2 c2;
+}
+
+class C2 {
+    C3 c3;
+}
+
+class C3 {
+}