changeset 445:51b53bc20417 jigsaw-b01

Merge
author mr
date Fri, 06 Nov 2009 13:20:18 -0800
parents 8fb9b4be3cb1 (current diff) bd48e67333aa (diff)
children 6b9edecbb15a
files .hgtags .jcheck/conf src/share/classes/com/sun/tools/classfile/ModuleExportTable_attribute.java src/share/classes/com/sun/tools/classfile/ModuleMemberTable_attribute.java src/share/classes/com/sun/tools/javac/code/Source.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Lower.java src/share/classes/com/sun/tools/javac/resources/compiler.properties
diffstat 98 files changed, 7303 insertions(+), 565 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Nov 02 21:36:59 2009 -0800
+++ b/.hgtags	Fri Nov 06 13:20:18 2009 -0800
@@ -30,6 +30,7 @@
 dbdeb4a7581b2a8699644b91cae6793cb01953f7 jdk7-b53
 197a7f881937d406a01214aa9ded49c073f7d380 jdk7-b54
 7394a8694cedea574c7dbd38de87f4cbe0e27b8a jdk7-b55
+9359f5d705289c8680748d11bc80978edc957ba1 j1-2009-demo
 825f23a4f262eb06cfc94406140f3bfecb17ffe8 jdk7-b56
 4030cc469205bbd517ca629fb170afb81760bbc5 jdk7-b57
 5bcac54d408b436d2364925ee7947b5609e07962 jdk7-b58
--- a/.jcheck/conf	Mon Nov 02 21:36:59 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-project=jdk7
--- a/make/build.xml	Mon Nov 02 21:36:59 2009 -0800
+++ b/make/build.xml	Fri Nov 06 13:20:18 2009 -0800
@@ -204,7 +204,7 @@
         <javadoc-tool name="javac" includes="${javac.includes}" options="${javadoc.jls3.option}"/>
     </target>
 
-    <target name="jtreg-javac" depends="build-javac,-def-jtreg">
+    <target name="jtreg-javac" depends="build-javac,build-javap,-def-jtreg">
         <jtreg-tool name="javac" tests="${javac.tests}"/>
     </target>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/ModuleClassTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,34 @@
+/*
+ * 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.source.tree;
+
+import java.util.List;
+import javax.lang.model.element.Name;
+
+public interface ModuleClassTree extends Tree {
+    List<? extends Name> getFlags();
+    Tree getClassName();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/ModuleIdTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,36 @@
+/*
+ * 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.source.tree;
+
+import javax.lang.model.element.Name;
+
+/**
+ *
+ */
+public interface ModuleIdTree extends Tree {
+    Tree getModuleName();
+    Name getModuleVersion();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/ModulePermitsTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,32 @@
+/*
+ * 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.source.tree;
+
+import java.util.List;
+
+public interface ModulePermitsTree extends Tree {
+    List<? extends ExpressionTree> getModuleNames();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/ModuleRequiresTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,34 @@
+/*
+ * 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.source.tree;
+
+import java.util.List;
+import javax.lang.model.element.Name;
+
+public interface ModuleRequiresTree extends Tree {
+    List<? extends Name> getFlags();
+    List<? extends ModuleIdTree> getModuleIds();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/ModuleTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,39 @@
+/*
+ * 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.source.tree;
+
+import java.util.List;
+
+
+/**
+ *
+ */
+public interface ModuleTree extends Tree {
+    List<? extends AnnotationTree> getAnnotations();
+    ModuleIdTree getId();
+    List<? extends ModuleIdTree> getProvides();
+    List<? extends Tree> getMetadataList();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/source/tree/PackageTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,13 @@
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+
+/**
+ *
+ */
+public interface PackageTree extends Tree {
+    List<? extends AnnotationTree> getAnnotations();
+    Tree getPackageId();
+}
--- a/src/share/classes/com/sun/source/tree/Tree.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/source/tree/Tree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -552,6 +552,18 @@
          */
         ERRONEOUS(ErroneousTree.class),
 
+        MODULE(ModuleTree.class),
+
+        MODULE_CLASS(ModuleClassTree.class),
+
+        MODULE_ID(ModuleIdTree.class),
+
+        MODULE_PERMITS(ModulePermitsTree.class),
+
+        MODULE_REQUIRES(ModuleRequiresTree.class),
+
+        PACKAGE(PackageTree.class),
+
         /**
          * An implementation-reserved node. This is the not the node
          * you are looking for.
--- a/src/share/classes/com/sun/source/tree/TreeVisitor.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Nov 06 13:20:18 2009 -0800
@@ -84,8 +84,14 @@
     R visitLiteral(LiteralTree node, P p);
     R visitMethod(MethodTree node, P p);
     R visitModifiers(ModifiersTree node, P p);
+    R visitModule(ModuleTree node, P p);
+    R visitModuleClass(ModuleClassTree node, P p);
+    R visitModuleId(ModuleIdTree node, P p);
+    R visitModulePermits(ModulePermitsTree node, P p);
+    R visitModuleRequires(ModuleRequiresTree node, P p);
     R visitNewArray(NewArrayTree node, P p);
     R visitNewClass(NewClassTree node, P p);
+    R visitPackage(PackageTree node, P p);
     R visitParenthesized(ParenthesizedTree node, P p);
     R visitReturn(ReturnTree node, P p);
     R visitMemberSelect(MemberSelectTree node, P p);
--- a/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Fri Nov 06 13:20:18 2009 -0800
@@ -33,7 +33,7 @@
  * @author Peter von der Ah&eacute;
  * @since 1.6
  */
-public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
+public class SimpleTreeVisitor<R,P> implements TreeVisitor<R,P> {
     protected final R DEFAULT_VALUE;
 
     protected SimpleTreeVisitor() {
@@ -252,6 +252,30 @@
         return defaultAction(node, p);
     }
 
+    public R visitModule(ModuleTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    public R visitModuleClass(ModuleClassTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    public R visitModuleId(ModuleIdTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    public R visitModulePermits(ModulePermitsTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    public R visitModuleRequires(ModuleRequiresTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    public R visitPackage(PackageTree node, P p) {
+        return defaultAction(node, p);
+    }
+
     public R visitOther(Tree node, P p) {
         return defaultAction(node, p);
     }
--- a/src/share/classes/com/sun/source/util/TreeScanner.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/source/util/TreeScanner.java	Fri Nov 06 13:20:18 2009 -0800
@@ -380,6 +380,34 @@
        return r;
    }
 
+    public R visitModule(ModuleTree node, P p) {
+        R r = scan(node.getAnnotations(), p);
+        r = scanAndReduce(node.getId(), p, r);
+        return r;
+    }
+
+    public R visitModuleClass(ModuleClassTree node, P p) {
+        return scan(node.getClassName(), p);
+    }
+
+    public R visitModuleId(ModuleIdTree node, P p) {
+        return scan(node.getModuleName(), p);
+    }
+
+    public R visitModulePermits(ModulePermitsTree node, P p) {
+        return scan(node.getModuleNames(), p);
+    }
+
+    public R visitModuleRequires(ModuleRequiresTree node, P p) {
+        return scan(node.getModuleIds(), p);
+    }
+
+    public R visitPackage(PackageTree node, P p) {
+        R r = scan(node.getAnnotations(), p);
+        r = scanAndReduce(node.getPackageId(), p, r);
+        return r;
+    }
+
     public R visitOther(Tree node, P p) {
         return null;
     }
--- a/src/share/classes/com/sun/tools/classfile/Attribute.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/classfile/Attribute.java	Fri Nov 06 13:20:18 2009 -0800
@@ -64,10 +64,12 @@
     public static final String StackMapTable            = "StackMapTable";
     public static final String Synthetic                = "Synthetic";
 
-    // JSR 277/294
+    // JSR 294
     public static final String Module                   = "Module";
-    public static final String ModuleExportTable        = "ModuleExportTable";
-    public static final String ModuleMemberTable        = "ModuleMemberTable";
+    public static final String ModuleClass              = "ModuleClass";
+    public static final String ModulePermits            = "ModulePermits";
+    public static final String ModuleProvides           = "ModuleProvides";
+    public static final String ModuleRequires           = "ModuleRequires";
 
     public static class Factory {
         public Factory() {
@@ -78,10 +80,6 @@
             this.compat = compat;
         }
 
-        public void setJSR277(boolean jsr277) {
-            this.jsr277 = jsr277;
-        }
-
         public Attribute createAttribute(ClassReader cr, int name_index, byte[] data)
                 throws IOException {
             if (standardAttributes == null)
@@ -121,11 +119,11 @@
             standardAttributes.put(LocalVariableTable, LocalVariableTable_attribute.class);
             standardAttributes.put(LocalVariableTypeTable, LocalVariableTypeTable_attribute.class);
 
-            if (jsr277) {
-                standardAttributes.put(Module,            Module_attribute.class);
-                standardAttributes.put(ModuleExportTable, ModuleExportTable_attribute.class);
-                standardAttributes.put(ModuleMemberTable, ModuleMemberTable_attribute.class);
-            }
+            standardAttributes.put(Module,            Module_attribute.class);
+            standardAttributes.put(ModuleClass,       ModuleClass_attribute.class);
+            standardAttributes.put(ModulePermits,     ModulePermits_attribute.class);
+            standardAttributes.put(ModuleProvides,    ModuleProvides_attribute.class);
+            standardAttributes.put(ModuleRequires,    ModuleRequires_attribute.class);
 
             if (!compat) { // old javap does not recognize recent attributes
                 standardAttributes.put(CompilationID, CompilationID_attribute.class);
@@ -148,7 +146,6 @@
 
         private Map<String,Class<? extends Attribute>> standardAttributes;
         private boolean compat; // don't support recent attrs in compatibility mode
-        private boolean jsr277; // support new jsr277 attrs
     }
 
     public static Attribute read(ClassReader cr) throws IOException {
@@ -203,7 +200,9 @@
         R visitSynthetic(Synthetic_attribute attr, P p);
 
         R visitModule(Module_attribute attr, P p);
-        R visitModuleExportTable(ModuleExportTable_attribute attr, P p);
-        R visitModuleMemberTable(ModuleMemberTable_attribute attr, P p);
+        R visitModuleClass(ModuleClass_attribute attr, P p);
+        R visitModulePermits(ModulePermits_attribute attr, P p);
+        R visitModuleProvides(ModuleProvides_attribute attr, P p);
+        R visitModuleRequires(ModuleRequires_attribute attr, P p);
     }
 }
--- a/src/share/classes/com/sun/tools/classfile/ClassTranslator.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/classfile/ClassTranslator.java	Fri Nov 06 13:20:18 2009 -0800
@@ -33,6 +33,7 @@
 import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_ModuleId_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
@@ -313,6 +314,32 @@
         return info;
     }
 
+    public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map<Object, Object> translations) {
+        CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info);
+        if (info2 == null) {
+            ConstantPool cp2 = translate(info.cp, translations);
+            if (cp2 == info.cp)
+                info2 = info;
+            else
+                info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index);
+            translations.put(info, info2);
+        }
+        return info;
+    }
+
+    public CPInfo visitModuleId(CONSTANT_ModuleId_info info, Map<Object, Object> translations) {
+        CONSTANT_ModuleId_info info2 = (CONSTANT_ModuleId_info) translations.get(info);
+        if (info2 == null) {
+            ConstantPool cp2 = translate(info.cp, translations);
+            if (cp2 == info.cp)
+                info2 = info;
+            else
+                info2 = new CONSTANT_ModuleId_info(cp2, info.name_index, info.version_index);
+            translations.put(info, info2);
+        }
+        return info;
+    }
+
     public CPInfo visitNameAndType(CONSTANT_NameAndType_info info, Map<Object, Object> translations) {
         CONSTANT_NameAndType_info info2 = (CONSTANT_NameAndType_info) translations.get(info);
         if (info2 == null) {
@@ -326,19 +353,6 @@
         return info;
     }
 
-    public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map<Object, Object> translations) {
-        CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info);
-        if (info2 == null) {
-            ConstantPool cp2 = translate(info.cp, translations);
-            if (cp2 == info.cp)
-                info2 = info;
-            else
-                info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index);
-            translations.put(info, info2);
-        }
-        return info;
-    }
-
     public CPInfo visitString(CONSTANT_String_info info, Map<Object, Object> translations) {
         CONSTANT_String_info info2 = (CONSTANT_String_info) translations.get(info);
         if (info2 == null) {
--- a/src/share/classes/com/sun/tools/classfile/ClassWriter.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/classfile/ClassWriter.java	Fri Nov 06 13:20:18 2009 -0800
@@ -272,16 +272,22 @@
             return 2;
         }
 
+        public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {
+            return writeRef(info, out);
+        }
+
+        public Integer visitModuleId(CONSTANT_ModuleId_info info, ClassOutputStream out) {
+            out.writeShort(info.name_index);
+            out.writeShort(info.version_index);
+            return 1;
+        }
+
         public Integer visitNameAndType(CONSTANT_NameAndType_info info, ClassOutputStream out) {
             out.writeShort(info.name_index);
             out.writeShort(info.type_index);
             return 1;
         }
 
-        public Integer visitMethodref(CONSTANT_Methodref_info info, ClassOutputStream out) {
-            return writeRef(info, out);
-        }
-
         public Integer visitString(CONSTANT_String_info info, ClassOutputStream out) {
             out.writeShort(info.string_index);
             return 1;
@@ -450,24 +456,45 @@
         }
 
         public Void visitModule(Module_attribute attr, ClassOutputStream out) {
-            out.writeShort(attr.module_name);
+            out.writeShort(attr.module_id_index);
             return null;
         }
 
-        public Void visitModuleExportTable(ModuleExportTable_attribute attr, ClassOutputStream out) {
-            out.writeShort(attr.export_type_table.length);
-            for (int i: attr.export_type_table)
+        public Void visitModuleClass(ModuleClass_attribute attr, ClassOutputStream out) {
+            out.writeShort(attr.class_index);
+            out.writeShort(attr.attributes.length);
+            for (int index: attr.attributes) {
+                out.writeShort(index);
+            }
+            return null;
+        }
+
+        public Void visitModulePermits(ModulePermits_attribute attr, ClassOutputStream out) {
+            out.writeShort(attr.permits_table.length);
+            for (int i: attr.permits_table)
                 out.writeShort(i);
             return null;
         }
 
-        public Void visitModuleMemberTable(ModuleMemberTable_attribute attr, ClassOutputStream out) {
-            out.writeShort(attr.package_member_table.length);
-            for (int i: attr.package_member_table)
+        public Void visitModuleProvides(ModuleProvides_attribute attr, ClassOutputStream out) {
+            out.writeShort(attr.provides_table.length);
+            for (int i: attr.provides_table)
                 out.writeShort(i);
             return null;
         }
 
+        public Void visitModuleRequires(ModuleRequires_attribute attr, ClassOutputStream out) {
+            out.writeShort(attr.requires_table.length);
+            for (ModuleRequires_attribute.Entry e: attr.requires_table) {
+                out.writeShort(e.requires_index);
+                out.writeShort(e.attributes.length);
+                for (int i = 0; i < e.attributes_length; i++) {
+                    out.writeShort(e.attributes[i]);
+                }
+            }
+            return null;
+        }
+
         public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) {
             annotationWriter.write(attr.annotations, out);
             return null;
--- a/src/share/classes/com/sun/tools/classfile/ConstantPool.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/classfile/ConstantPool.java	Fri Nov 06 13:20:18 2009 -0800
@@ -114,6 +114,7 @@
     public static final int CONSTANT_Methodref = 10;
     public static final int CONSTANT_InterfaceMethodref = 11;
     public static final int CONSTANT_NameAndType = 12;
+    public static final int CONSTANT_ModuleId = 13;
 
     ConstantPool(ClassReader cr) throws IOException, InvalidEntry {
         int count = cr.readUnsignedShort();
@@ -155,6 +156,10 @@
                 pool[i] = new CONSTANT_Methodref_info(this, cr);
                 break;
 
+            case CONSTANT_ModuleId:
+                pool[i] = new CONSTANT_ModuleId_info(this, cr);
+                break;
+
             case CONSTANT_NameAndType:
                 pool[i] = new CONSTANT_NameAndType_info(this, cr);
                 break;
@@ -218,6 +223,10 @@
         return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
     }
 
+    public CONSTANT_ModuleId_info getModuleIdInfo(int index) throws InvalidIndex, UnexpectedEntry {
+        return ((CONSTANT_ModuleId_info) get(index, CONSTANT_ModuleId));
+    }
+
     public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
         return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
     }
@@ -280,8 +289,9 @@
         R visitInteger(CONSTANT_Integer_info info, P p);
         R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p);
         R visitLong(CONSTANT_Long_info info, P p);
+        R visitMethodref(CONSTANT_Methodref_info info, P p);
+        R visitModuleId(CONSTANT_ModuleId_info info, P p);
         R visitNameAndType(CONSTANT_NameAndType_info info, P p);
-        R visitMethodref(CONSTANT_Methodref_info info, P p);
         R visitString(CONSTANT_String_info info, P p);
         R visitUtf8(CONSTANT_Utf8_info info, P p);
     }
@@ -601,6 +611,48 @@
         }
     }
 
+    public static class CONSTANT_ModuleId_info extends CPInfo {
+        CONSTANT_ModuleId_info(ConstantPool cp, ClassReader cr) throws IOException {
+            super(cp);
+            name_index = cr.readUnsignedShort();
+            version_index = cr.readUnsignedShort();
+        }
+
+        public CONSTANT_ModuleId_info(ConstantPool cp, int name_index, int version_index) {
+            super(cp);
+            this.name_index = name_index;
+            this.version_index = version_index;
+        }
+
+        public int getTag() {
+            return CONSTANT_ModuleId;
+        }
+
+        public String getName() throws ConstantPoolException {
+            return cp.getUTF8Value(name_index);
+        }
+
+        public int byteLength() {
+            return 5;
+        }
+
+        public String getVersion() throws ConstantPoolException {
+            return (version_index == 0 ? null : cp.getUTF8Value(version_index));
+        }
+
+        @Override
+        public String toString() {
+            return "CONSTANT_ModuleId_info[name_index: " + name_index + ", version_index: " + version_index + "]";
+        }
+
+        public <R, D> R accept(Visitor<R, D> visitor, D data) {
+            return visitor.visitModuleId(this, data);
+        }
+
+        public final int name_index;
+        public final int version_index;
+    }
+
     public static class CONSTANT_NameAndType_info extends CPInfo {
         CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException {
             super(cp);
@@ -630,15 +682,15 @@
             return cp.getUTF8Value(type_index);
         }
 
-        public <R, D> R accept(Visitor<R, D> visitor, D data) {
-            return visitor.visitNameAndType(this, data);
-        }
-
         @Override
         public String toString() {
             return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]";
         }
 
+        public <R, D> R accept(Visitor<R, D> visitor, D data) {
+            return visitor.visitNameAndType(this, data);
+        }
+
         public final int name_index;
         public final int type_index;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/classfile/ModuleClass_attribute.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2008 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.io.IOException;
+
+import com.sun.tools.classfile.ConstantPool.*;
+
+/**
+ * See JSR294.
+ *
+ *  <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 ModuleClass_attribute extends Attribute {
+    ModuleClass_attribute(ClassReader cr, int name_index, int length) throws IOException {
+        super(name_index, length);
+        class_index = cr.readUnsignedShort();
+        attributes_length = cr.readUnsignedShort();
+        attributes = new int[attributes_length];
+        for (int i = 0; i < attributes.length; i++)
+            attributes[i] = cr.readUnsignedShort();
+    }
+
+    public ModuleClass_attribute(ConstantPool constant_pool, int class_index, int[] attributes)
+            throws ConstantPoolException {
+        this(constant_pool.getUTF8Index(Attribute.ModuleRequires), class_index, attributes);
+    }
+
+    public ModuleClass_attribute(int name_index, int class_index, int[] attributes) {
+        super(name_index, 2 + attributes.length * 2);
+        this.class_index = class_index;
+        this.attributes_length = attributes.length;
+        this.attributes = attributes;
+    }
+    
+    public CONSTANT_Class_info getClassInfo(ConstantPool constant_pool) throws ConstantPoolException {
+        if (class_index == 0)
+            return null;
+        return constant_pool.getClassInfo(class_index);
+    }
+    
+    public String getClassName(ConstantPool constant_pool) throws ConstantPoolException {
+        if (class_index == 0)
+            return null;
+        return constant_pool.getClassInfo(class_index).getName();
+    }
+    
+    public String[] getClassAttributes(ConstantPool constant_pool) throws ConstantPoolException {
+        String[] attrs = new String[attributes.length];
+        for (int i = 0; i < attrs.length; i++)
+            attrs[i] = constant_pool.getUTF8Value(attributes[i]);
+        return attrs;
+    }
+
+    public <R, D> R accept(Visitor<R, D> visitor, D data) {
+        return visitor.visitModuleClass(this, data);
+    }
+
+    public final int class_index;
+    public final int attributes_length;
+    public final int[] attributes;
+}
--- a/src/share/classes/com/sun/tools/classfile/ModuleExportTable_attribute.java	Mon Nov 02 21:36:59 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright 2007-2008 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.io.IOException;
-
-/**
- * See JSR 277.
- *
- *  <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 ModuleExportTable_attribute extends Attribute {
-    ModuleExportTable_attribute(ClassReader cr, int name_index, int length) throws IOException {
-        super(name_index, length);
-        int export_type_length = cr.readUnsignedShort();
-        export_type_table = new int[export_type_length];
-        for (int i = 0; i < export_type_table.length; i++)
-            export_type_table[i] = cr.readUnsignedShort();
-    }
-
-    public ModuleExportTable_attribute(ConstantPool cp, int[] export_type_table)
-            throws ConstantPoolException {
-        this(cp.getUTF8Index(Attribute.ModuleExportTable), export_type_table);
-    }
-
-    public ModuleExportTable_attribute(int name_index, int[] export_type_table) {
-        super(name_index, 2 + 2 * export_type_table.length);
-        this.export_type_table = export_type_table;
-    }
-
-    public int getExportTypeCount() {
-        return export_type_table.length;
-    }
-
-    public String getExportTypeName(int index, ConstantPool constant_pool) throws ConstantPoolException {
-        return constant_pool.getUTF8Value(export_type_table[index]);
-    }
-
-    public <R, P> R accept(Visitor<R, P> visitor, P p) {
-        return visitor.visitModuleExportTable(this, p);
-    }
-
-    public final int[] export_type_table;
-}
--- a/src/share/classes/com/sun/tools/classfile/ModuleMemberTable_attribute.java	Mon Nov 02 21:36:59 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2007-2008 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.io.IOException;
-
-/**
- * See JSR 277.
- *
- *  <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 ModuleMemberTable_attribute extends Attribute {
-    ModuleMemberTable_attribute(ClassReader cr, int name_index, int length) throws IOException {
-        super(name_index, length);
-        int package_member_length = cr.readUnsignedShort();
-        package_member_table = new int[package_member_length];
-        for (int i = 0; i < package_member_table.length; i++)
-            package_member_table[i] = cr.readUnsignedShort();
-    }
-
-    public ModuleMemberTable_attribute(ConstantPool cp, int[] package_member_table)
-            throws ConstantPoolException {
-        this(cp.getUTF8Index(Attribute.ModuleMemberTable), package_member_table);
-    }
-
-    public ModuleMemberTable_attribute(int name_index, int[] package_member_table) {
-        super(name_index, 2 + 2 * package_member_table.length);
-        this.package_member_table = package_member_table;
-    }
-
-    public int getPackageMemberCount() {
-        return package_member_table.length;
-    }
-
-    public String getPackageMemberName(int index, ConstantPool constant_pool) throws ConstantPoolException {
-        return constant_pool.getUTF8Value(package_member_table[index]);
-    }
-
-    public <R, P> R accept(Visitor<R, P> visitor, P p) {
-        return visitor.visitModuleMemberTable(this, p);
-    }
-
-    public final int[] package_member_table;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/classfile/ModulePermits_attribute.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008 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.io.IOException;
+
+/**
+ * See JSR294.
+ *
+ *  <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 ModulePermits_attribute extends Attribute {
+    ModulePermits_attribute(ClassReader cr, int name_index, int length) throws IOException {
+        super(name_index, length);
+        permits_length = cr.readUnsignedShort();
+        permits_table = new int[permits_length];
+        for (int i = 0; i < permits_length; i++)
+            permits_table[i] = cr.readUnsignedShort();
+    }
+
+    public ModulePermits_attribute(ConstantPool constant_pool, int[] provides_table)
+            throws ConstantPoolException {
+        this(constant_pool.getUTF8Index(Attribute.ModulePermits), provides_table);
+    }
+
+    public ModulePermits_attribute(int name_index, int[] permits_table) {
+        super(name_index, 2 + 2 * permits_table.length);
+        this.permits_length = permits_table.length;
+        this.permits_table = permits_table;
+    }
+
+    public String getPermits(int index, ConstantPool constant_pool) throws ConstantPoolException {
+        int permits_index = permits_table[index];
+        return constant_pool.getUTF8Value(permits_index);
+    }
+
+    public <R, D> R accept(Visitor<R, D> visitor, D data) {
+        return visitor.visitModulePermits(this, data);
+    }
+
+    public final int permits_length;
+    public final int[] permits_table;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/classfile/ModuleProvides_attribute.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008 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.io.IOException;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_ModuleId_info;
+
+/**
+ * See JSR294.
+ *
+ *  <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 ModuleProvides_attribute extends Attribute {
+    ModuleProvides_attribute(ClassReader cr, int name_index, int length) throws IOException {
+        super(name_index, length);
+        provides_length = cr.readUnsignedShort();
+        provides_table = new int[provides_length];
+        for (int i = 0; i < provides_length; i++)
+            provides_table[i] = cr.readUnsignedShort();
+    }
+
+    public ModuleProvides_attribute(ConstantPool constant_pool, int[] provides_table)
+            throws ConstantPoolException {
+        this(constant_pool.getUTF8Index(Attribute.ModuleProvides), provides_table);
+    }
+
+    public ModuleProvides_attribute(int name_index, int[] provides_table) {
+        super(name_index, 2 + 2 * provides_table.length);
+        this.provides_length = provides_table.length;
+        this.provides_table = provides_table;
+    }
+
+    public CONSTANT_ModuleId_info getProvides(int index, ConstantPool constant_pool) throws ConstantPoolException {
+        int provides_index = provides_table[index];
+        return constant_pool.getModuleIdInfo(provides_index);
+    }
+
+    public <R, D> R accept(Visitor<R, D> visitor, D data) {
+        return visitor.visitModuleProvides(this, data);
+    }
+
+    public final int provides_length;
+    public final int[] provides_table;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/classfile/ModuleRequires_attribute.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 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.io.IOException;
+
+/**
+ * See JSR294.
+ *
+ *  <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 ModuleRequires_attribute extends Attribute {
+    ModuleRequires_attribute(ClassReader cr, int name_index, int length) throws IOException {
+        super(name_index, length);
+        requires_length = cr.readUnsignedShort();
+        requires_table = new Entry[requires_length];
+        for (int i = 0; i < requires_length; i++)
+            requires_table[i] = new Entry(cr);
+    }
+
+    public ModuleRequires_attribute(ConstantPool constant_pool, Entry[] requires_table)
+            throws ConstantPoolException {
+        this(constant_pool.getUTF8Index(Attribute.ModuleRequires), requires_table);
+    }
+
+    public ModuleRequires_attribute(int name_index, Entry[] requires_table) {
+        super(name_index, 2 + length(requires_table));
+        this.requires_length = requires_table.length;
+        this.requires_table = requires_table;
+    }
+
+    public <R, D> R accept(Visitor<R, D> visitor, D data) {
+        return visitor.visitModuleRequires(this, data);
+    }
+
+    public final int requires_length;
+    public final Entry[] requires_table;
+
+    private static int length(Entry[] requires_table) {
+        int n = 0;
+        for (int i = 0; i < requires_table.length; i++)
+            n += requires_table[i].length();
+        return n;
+    }
+
+    public static class Entry {
+        Entry(ClassReader cr) throws IOException {
+            requires_index = cr.readUnsignedShort();
+            attributes_length = cr.readUnsignedShort();
+            attributes = new int[attributes_length];
+            for (int i = 0; i < attributes_length; i++)
+                attributes[i] = cr.readUnsignedShort();
+        }
+
+        public int length() {
+            return 4 + attributes_length * 2;
+        }
+
+        public final int requires_index;
+        public final int attributes_length;
+        public final int[] attributes;
+    }
+}
--- a/src/share/classes/com/sun/tools/classfile/Module_attribute.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/classfile/Module_attribute.java	Fri Nov 06 13:20:18 2009 -0800
@@ -28,7 +28,7 @@
 import java.io.IOException;
 
 /**
- * See JSR 277.
+ * See JSR 294.
  *
  *  <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.
@@ -38,27 +38,26 @@
 public class Module_attribute extends Attribute {
     Module_attribute(ClassReader cr, int name_index, int length) throws IOException {
         super(name_index, length);
-        module_name = cr.readUnsignedShort();
+        module_id_index = cr.readUnsignedShort();
     }
 
-    public Module_attribute(ConstantPool constant_pool, int module_name)
-            throws ConstantPoolException {
-        this(constant_pool.getUTF8Index(Attribute.Module), module_name);
-    }
-
-    public Module_attribute(int name_index, int module_name) {
+    public Module_attribute(int name_index, int module_id_index) {
         super(name_index, 2);
-        this.module_name = module_name;
+        this.module_id_index = module_id_index;
     }
 
     public String getModuleName(ConstantPool constant_pool) throws ConstantPoolException {
-        return constant_pool.getUTF8Value(module_name);
+        return constant_pool.getModuleIdInfo(module_id_index).getName();
+    }
+
+    public String getModuleVersion(ConstantPool constant_pool) throws ConstantPoolException {
+        return constant_pool.getModuleIdInfo(module_id_index).getVersion();
     }
 
     public <R, D> R accept(Visitor<R, D> visitor, D data) {
         return visitor.visitModule(this, data);
     }
 
-    public final int module_name;
+    public final int module_id_index;
 
 }
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java	Fri Nov 06 13:20:18 2009 -0800
@@ -112,7 +112,10 @@
      *  classfile v49.0. */
     public static final int ENUM         = 1<<14;
 
-    public static final int StandardFlags = 0x0fff;
+    /** Module access, added in classfile v51.0. */
+    public static final int MODULE       = 1<<15;
+
+    public static final int StandardFlags = 0x8fff;
 
     // Because the following access flags are overloaded with other
     // bit positions, we translate them when reading and writing class
@@ -232,15 +235,15 @@
     /** Modifier masks.
      */
     public static final int
-        AccessFlags           = PUBLIC | PROTECTED | PRIVATE,
+        AccessFlags           = PUBLIC | PROTECTED | PRIVATE | MODULE,
         LocalClassFlags       = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
         MemberClassFlags      = LocalClassFlags | INTERFACE | AccessFlags,
-        ClassFlags            = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
-        InterfaceVarFlags     = FINAL | STATIC | PUBLIC,
+        ClassFlags            = LocalClassFlags | INTERFACE | PUBLIC | MODULE | ANNOTATION,
+        InterfaceVarFlags     = FINAL | STATIC | PUBLIC | MODULE,
         VarFlags              = AccessFlags | FINAL | STATIC |
                                 VOLATILE | TRANSIENT | ENUM,
         ConstructorFlags      = AccessFlags,
-        InterfaceMethodFlags  = ABSTRACT | PUBLIC,
+        InterfaceMethodFlags  = ABSTRACT | PUBLIC | MODULE,
         MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
                                 SYNCHRONIZED | FINAL | STRICTFP;
     public static final long
@@ -253,6 +256,7 @@
             if (0 != (flags & PUBLIC))    modifiers.add(Modifier.PUBLIC);
             if (0 != (flags & PROTECTED)) modifiers.add(Modifier.PROTECTED);
             if (0 != (flags & PRIVATE))   modifiers.add(Modifier.PRIVATE);
+            if (0 != (flags & MODULE))    modifiers.add(Modifier.MODULE);
             if (0 != (flags & ABSTRACT))  modifiers.add(Modifier.ABSTRACT);
             if (0 != (flags & STATIC))    modifiers.add(Modifier.STATIC);
             if (0 != (flags & FINAL))     modifiers.add(Modifier.FINAL);
@@ -284,6 +288,10 @@
         return symbol.getConstValue() != null;
     }
 
+    public static boolean isModuleAccess(Symbol symbol) {
+        return (symbol.flags() & MODULE) != 0;
+    }
+
     public enum Flag {
 
         PUBLIC("public"),
@@ -303,6 +311,7 @@
         DEPRECATED("deprecated"),
         HASINIT("hasinit"),
         ENUM("enum"),
+        MODULE("module"),
         IPROXY("iproxy"),
         NOOUTERTHIS("noouterthis"),
         EXISTS("exists"),
@@ -323,6 +332,7 @@
             this.name = name;
         }
 
+        @Override
         public String toString() {
             return name;
         }
--- a/src/share/classes/com/sun/tools/javac/code/Kinds.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Kinds.java	Fri Nov 06 13:20:18 2009 -0800
@@ -71,9 +71,13 @@
      */
     public final static int MTH = 1 << 4;
 
+    /** The kind of modules.
+     */
+    public final static int MDL = 1 << 5;
+
     /** The error kind, which includes all other kinds.
      */
-    public final static int ERR = (1 << 5) - 1;
+    public final static int ERR = (1 << 6) - 1;
 
     /** The set of all kinds.
      */
@@ -103,7 +107,8 @@
         VAL("kindname.value"),
         METHOD("kindname.method"),
         CLASS("kindname.class"),
-        PACKAGE("kindname.package");
+        PACKAGE("kindname.package"),
+        MODULE("kindname.module");
 
         private String name;
 
--- a/src/share/classes/com/sun/tools/javac/code/Printer.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Printer.java	Fri Nov 06 13:20:18 2009 -0800
@@ -227,6 +227,11 @@
         return visitType(t, locale);
     }
 
+    @Override
+    public String visitModuleType(ModuleType t, Locale locale) {
+        return visitType(t, locale);
+    }
+
     public String visitType(Type t, Locale locale) {
         String s = (t.tsym == null || t.tsym.name == null)
                 ? localize(locale, "compiler.misc.type.none")
--- a/src/share/classes/com/sun/tools/javac/code/Scope.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Scope.java	Fri Nov 06 13:20:18 2009 -0800
@@ -96,7 +96,7 @@
         this.shared = 0;
     }
 
-    /** Construct a new scope, within scope next, with given owner,
+    /** Construct a new scope, with given owner,
      *  using a fresh table of length INITIAL_SIZE.
      */
     public Scope(Symbol owner) {
--- a/src/share/classes/com/sun/tools/javac/code/Source.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java	Fri Nov 06 13:20:18 2009 -0800
@@ -153,6 +153,12 @@
     public boolean allowAnonOuterThis() {
         return compareTo(JDK1_5) >= 0;
     }
+    public boolean allowModules() {
+        return compareTo(JDK1_7) >= 0;
+    }
+    public boolean allowImportsBeforePackage() {
+        return compareTo(JDK1_7) >= 0;
+    }
     public boolean addBridges() {
         return compareTo(JDK1_5) >= 0;
     }
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Nov 06 13:20:18 2009 -0800
@@ -25,9 +25,11 @@
 
 package com.sun.tools.javac.code;
 
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import javax.lang.model.element.*;
+import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.util.*;
@@ -37,12 +39,14 @@
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.jvm.*;
+import com.sun.tools.javac.jvm.ClassFile.ModuleId;
 import com.sun.tools.javac.model.*;
 import com.sun.tools.javac.tree.JCTree;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTags.*;
+import static com.sun.tools.javac.code.Flags.MODULE; // disambiguate
 
 /** Root class for Java symbols. It contains subclasses
  *  for specific sorts of symbols, such as variables, methods and operators,
@@ -305,6 +309,13 @@
         return (PackageSymbol) sym;
     }
 
+    /** The module which indirectly owns this symbol.
+     */
+    public ModuleSymbol modle() {
+        ClassSymbol c = outermostClass();
+        return c == null ? null : c.modle;
+    }
+
     /** Is this symbol a subclass of `base'? Only defined for ClassSymbols.
      */
     public boolean isSubClass(Symbol base, Types types) {
@@ -383,6 +394,20 @@
                     return false;
             }
             return (clazz.flags() & INTERFACE) == 0;
+        case MODULE:
+            ModuleSymbol thisModule = this.modle();
+            for (Symbol sup = clazz;
+                 sup != null && sup != this.owner;
+                 sup = types.supertype(sup.type).tsym) {
+                if (sup.type.isErroneous())
+                    return true; // error recovery
+                if ((sup.flags() & COMPOUND) != 0)
+                    continue;
+                if (sup.modle() != thisModule)
+                    return false;
+            }
+            return true;
+
         }
     }
 
@@ -612,6 +637,78 @@
         }
     }
 
+    public static class ModuleRequires implements ModuleElement.ModuleRequires {
+        public ModuleId moduleId;
+        public List<Name> flags;
+
+        public ModuleRequires(ModuleId moduleIdQuery, List<Name> flags) {
+            this.moduleId = moduleIdQuery;
+            this.flags = flags;
+        }
+
+        public ModuleElement.ModuleId getModuleId() {
+            return moduleId;
+        }
+
+        public java.util.List<? extends CharSequence> getFlags() {
+            return flags;
+        }
+
+    }
+
+    /** A class for module symbols.
+     */
+    public static class ModuleSymbol extends TypeSymbol implements ModuleElement // JIGSAW need TypeSymbol?
+            /*implements ModuleElement*/ {
+        public Name fullname;
+        public Name version;
+
+        public ClassSymbol module_info;
+
+        public ClassSymbol className;
+        public List<Name> classFlags;
+        public ListBuffer<Name> permits;
+        public ListBuffer<ClassFile.ModuleId> provides;
+        public Map<ClassFile.ModuleId,Symbol.ModuleRequires> requires;
+        public JavaFileManager.Location location;
+
+        public ModuleSymbol() {
+            super(0, null, null, null);
+            this.kind = MDL;
+            this.type = new ModuleType(this);
+        }
+
+        public ModuleSymbol(Name name, Symbol owner) {
+            super(0, name, null, owner);
+            this.kind = MDL;
+            this.type = new ModuleType(this);
+            this.fullname = formFullName(name, owner);
+        }
+
+        public java.util.List<Symbol.ModuleRequires> getRequires() {
+            List<Symbol.ModuleRequires> l = List.nil();
+            for (Symbol.ModuleRequires mr: requires.values()) {
+                l = l.prepend(mr);
+            }
+            return l.reverse();
+        }
+
+        @Override
+        public String toString() {
+            String n = fullname== null ? "<unknown>" : String.valueOf(fullname); // null-safe
+            return (version == null) ? n : n + "@" + version;
+        }
+
+        @Override
+        public Name getQualifiedName() {
+            return fullname;
+        }
+
+        public boolean isUnnamed() {
+            return name.isEmpty() && owner != null;
+        }
+    }
+
     /** A class for package symbols
      */
     public static class PackageSymbol extends TypeSymbol
@@ -688,6 +785,10 @@
     /** A class for class symbols
      */
     public static class ClassSymbol extends TypeSymbol implements TypeElement {
+        /**
+         * The module for the class.
+         */
+        public ModuleSymbol modle;
 
         /** a scope for all class members; variables, methods and inner classes
          *  type parameters are not part of this scope
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Nov 06 13:20:18 2009 -0800
@@ -77,6 +77,14 @@
     private final ClassReader reader;
     private final Target target;
 
+    /** A symbol for the root module.
+     */
+    public final ModuleSymbol rootModule;
+
+    /** A symbol for the unnamed module.
+     */
+    public final ModuleSymbol unnamedModule;
+
     /** A symbol for the root package.
      */
     public final PackageSymbol rootPackage;
@@ -355,9 +363,17 @@
         unknownType = new Type(TypeTags.UNKNOWN, null);
 
         // create the basic builtin symbols
+        final JavacMessages messages = JavacMessages.instance(context);
+        rootModule = new ModuleSymbol(names.empty, null);
+        unnamedModule = new ModuleSymbol(names.empty, rootModule) {
+                @Override
+                public String toString() {
+                    return messages.getLocalizedString("compiler.misc.unnamed.module");
+                }
+            };
         rootPackage = new PackageSymbol(names.empty, null);
-        final JavacMessages messages = JavacMessages.instance(context);
         unnamedPackage = new PackageSymbol(names.empty, rootPackage) {
+                @Override
                 public String toString() {
                     return messages.getLocalizedString("compiler.misc.unnamed.package");
                 }
--- a/src/share/classes/com/sun/tools/javac/code/Type.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java	Fri Nov 06 13:20:18 2009 -0800
@@ -917,6 +917,34 @@
         }
     }
 
+    public static class ModuleType extends Type implements NoType {
+
+        ModuleType(TypeSymbol tsym) {
+            super(TypeTags.MODULE, tsym);
+        }
+
+        @Override
+        public <R,S> R accept(Type.Visitor<R,S> v, S s) {
+            return v.visitModuleType(this, s);
+        }
+
+        @Override
+        public String toString() {
+            return tsym.getQualifiedName().toString();
+        }
+
+        @Override
+        public TypeKind getKind() {
+            return TypeKind.MODULE;
+        }
+
+        @Override
+        public <R, P> R accept(TypeVisitor<R, P> v, P p) {
+            return v.visitNoType(this, p);
+        }
+    }
+
+
     public static class TypeVar extends Type implements TypeVariable {
 
         /** The bound of this type variable; set from outside.
@@ -1301,6 +1329,7 @@
         R visitArrayType(ArrayType t, S s);
         R visitMethodType(MethodType t, S s);
         R visitPackageType(PackageType t, S s);
+        R visitModuleType(ModuleType t, S s);
         R visitTypeVar(TypeVar t, S s);
         R visitCapturedType(CapturedType t, S s);
         R visitForAll(ForAll t, S s);
--- a/src/share/classes/com/sun/tools/javac/code/TypeTags.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/TypeTags.java	Fri Nov 06 13:20:18 2009 -0800
@@ -90,9 +90,14 @@
      */
     public static final int PACKAGE = METHOD+1;
 
+    /** The tag of all module "types".
+     */
+    public static final int MODULE = PACKAGE+1;
+
+
     /** The tag of all (source-level) type variables.
      */
-    public static final int TYPEVAR = PACKAGE+1;
+    public static final int TYPEVAR = MODULE+1;
 
     /** The tag of all type arguments.
      */
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Nov 06 13:20:18 2009 -0800
@@ -3407,6 +3407,7 @@
         public R visitArrayType(ArrayType t, S s)       { return visitType(t, s); }
         public R visitMethodType(MethodType t, S s)     { return visitType(t, s); }
         public R visitPackageType(PackageType t, S s)   { return visitType(t, s); }
+        public R visitModuleType(ModuleType t, S s)     { return visitType(t, s); }
         public R visitTypeVar(TypeVar t, S s)           { return visitType(t, s); }
         public R visitCapturedType(CapturedType t, S s) { return visitType(t, s); }
         public R visitForAll(ForAll t, S s)             { return visitType(t, s); }
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Nov 06 13:20:18 2009 -0800
@@ -646,6 +646,9 @@
             // JLS ???
             chk.checkOverride(tree, m);
 
+            // Module modifier may not be used in unnamed module
+            chk.checkModuleModifier(tree.pos(), m);
+
             // Create a new environment with local scope
             // for attributing the method.
             Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env);
@@ -768,6 +771,8 @@
 
         try {
             chk.checkDeprecatedAnnotation(tree.pos(), v);
+            // Module modifier may not be used in unnamed module
+            chk.checkModuleModifier(tree.pos(), v);
 
             if (tree.init != null) {
                 if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) {
@@ -2707,6 +2712,26 @@
         result = tree.type = attribType(tree.getUnderlyingType(), env);
     }
 
+    public void visitModuleDef(JCModuleDecl tree) {
+        attribStats(tree.getMetadataList(), env);
+    }
+
+    public void visitModuleRequires(JCModuleRequires tree) {
+    }
+
+    public void visitModulePermits(JCModulePermits tree) {
+    }
+
+    public void visitModuleClass(JCModuleClass tree) {
+        ModuleSymbol msym = env.toplevel.modle;
+        Type t = attribType(tree.qualId, env);
+        if (t.tag == CLASS) {
+            // check duplicates
+            msym.className = (ClassSymbol) tree.qualId.type.tsym;
+            msym.classFlags = tree.flags;
+        }
+    }
+
     public void visitErroneous(JCErroneous tree) {
         if (tree.errs != null)
             for (JCTree err : tree.errs)
@@ -2720,6 +2745,33 @@
         throw new AssertionError();
     }
 
+    public void analyze(Env<AttrContext> env) {
+        switch (env.tree.getTag()) {
+            case JCTree.MODULE:
+                attribModule(env.tree.pos(), ((JCModuleDecl)env.tree).sym);
+                break;
+            default:
+                attribClass(env.tree.pos(), env.enclClass.sym);
+        }
+    }
+
+    public void attribModule(DiagnosticPosition pos, ModuleSymbol m) {
+        try {
+            annotate.flush();
+            attribModule(m);
+        } catch (CompletionFailure ex) {
+            chk.completionError(pos, ex);
+        }
+
+    }
+
+    void attribModule(ModuleSymbol m) {
+        // Get environment current at the point of module definition.
+        Env<AttrContext> env = enter.typeEnvs.get(m);
+        //System.err.println("Attr.attribModule: " + env + " " + env.tree);
+        attribStat(env.tree, env);
+    }
+
     /** Main method: attribute class definition associated with given class symbol.
      *  reporting completion failures at the given position.
      *  @param pos The source position at which completion errors are to be
@@ -2822,6 +2874,9 @@
         chk.validate(tree.extending, env);
         chk.validate(tree.implementing, env);
 
+        // Module modifier may not be used in unnamed module
+        chk.checkModuleModifier(tree.pos(), c);
+
         // If this is a non-abstract class, check that it has no abstract
         // methods or unimplemented methods of an implemented interface.
         if ((c.flags() & (ABSTRACT | INTERFACE)) == 0) {
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Nov 06 13:20:18 2009 -0800
@@ -44,6 +44,7 @@
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTags.*;
+import static com.sun.tools.javac.code.Flags.MODULE; // resolve ambiguity
 
 /** Type checking helper class for the attribution phase.
  *
@@ -665,7 +666,7 @@
     }
 
     /** Check that given modifiers are legal for given symbol and
-     *  return modifiers together with any implicit modififiers for that symbol.
+     *  return modifiers together with any implicit modifiers for that symbol.
      *  Warning: we can't use flags() here since this method
      *  is called during class enter, when flags() would cause a premature
      *  completion.
@@ -680,8 +681,12 @@
         case VAR:
             if (sym.owner.kind != TYP)
                 mask = LocalVarFlags;
-            else if ((sym.owner.flags_field & INTERFACE) != 0)
-                mask = implicit = InterfaceVarFlags;
+            else if ((sym.owner.flags_field & INTERFACE) != 0) {
+                mask = InterfaceVarFlags;
+                implicit = STATIC | FINAL;
+                if ((flags & MODULE) == 0)
+                    implicit |= PUBLIC;
+            }
             else
                 mask = VarFlags;
             break;
@@ -695,8 +700,12 @@
                     mask = PRIVATE;
                 } else
                     mask = ConstructorFlags;
-            }  else if ((sym.owner.flags_field & INTERFACE) != 0)
-                mask = implicit = InterfaceMethodFlags;
+            }  else if ((sym.owner.flags_field & INTERFACE) != 0) {
+                mask = InterfaceMethodFlags;
+                implicit = ABSTRACT;
+                if ((flags & MODULE) == 0)
+                    implicit |= PUBLIC;
+            }
             else {
                 mask = MethodFlags;
             }
@@ -724,13 +733,19 @@
                     mask |= STATIC;
                 else if ((flags & ENUM) != 0)
                     log.error(pos, "enums.must.be.static");
+                if ((sym.owner.flags_field & INTERFACE) != 0) {
+                    if ((flags & MODULE) == 0)
+                        implicit |= PUBLIC;
+                }
                 // Nested interfaces and enums are always STATIC (Spec ???)
-                if ((flags & (INTERFACE | ENUM)) != 0 ) implicit = STATIC;
+                if ((flags & (INTERFACE | ENUM)) != 0 )
+                    implicit = STATIC;
             } else {
                 mask = ClassFlags;
             }
             // Interfaces are always ABSTRACT
-            if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
+            if ((flags & INTERFACE) != 0)
+                implicit |= ABSTRACT;
 
             if ((flags & ENUM) != 0) {
                 // enums can't be declared abstract or final
@@ -750,8 +765,7 @@
                 mask |= INTERFACE;
             }
             else {
-                log.error(pos,
-                          "mod.not.allowed.here", asFlagSet(illegal));
+                log.error(pos, "mod.not.allowed.here", asFlagSet(illegal));
             }
         }
         else if ((sym.kind == TYP ||
@@ -767,11 +781,15 @@
                  &&
                  checkDisjoint(pos, flags,
                                PUBLIC,
-                               PRIVATE | PROTECTED)
+                               PRIVATE | PROTECTED | MODULE)
                  &&
                  checkDisjoint(pos, flags,
                                PRIVATE,
-                               PUBLIC | PROTECTED)
+                               PUBLIC | PROTECTED | MODULE)
+                 &&
+                 checkDisjoint(pos, flags,
+                               PROTECTED,
+                               PUBLIC | PRIVATE | MODULE)
                  &&
                  checkDisjoint(pos, flags,
                                FINAL,
@@ -786,6 +804,16 @@
         return flags & (mask | ~StandardFlags) | implicit;
     }
 
+    /**
+     * Determine if module modifier is legal here.
+     */
+    void checkModuleModifier(DiagnosticPosition pos, Symbol sym) {
+        // JIGSAW FIXME
+//        if (Flags.isModuleAccess(sym) && sym.packge().modle == syms.unnamedModule) {
+//            log.error(pos, "module.not.allowed.here");
+//        }
+    }
+
 
     /** Determine if this enum should be implicitly final.
      *
@@ -1620,8 +1648,8 @@
                         MethodSymbol implmeth = absmeth.implementation(impl, types, true);
                         if (implmeth == null || implmeth == absmeth)
                             undef = absmeth;
+                        }
                     }
-                }
                 if (undef == null) {
                     Type st = types.supertype(c.type);
                     if (st.tag == CLASS)
--- a/src/share/classes/com/sun/tools/javac/comp/Enter.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Enter.java	Fri Nov 06 13:20:18 2009 -0800
@@ -101,6 +101,7 @@
     Types types;
     Lint lint;
     JavaFileManager fileManager;
+    Modules modules;
 
     private final Todo todo;
 
@@ -123,6 +124,7 @@
         types = Types.instance(context);
         annotate = Annotate.instance(context);
         lint = Lint.instance(context);
+        modules = Modules.instance(context);
 
         predefClassDef = make.ClassDef(
             make.Modifiers(PUBLIC),
@@ -224,6 +226,21 @@
             ? ((JCClassDecl) env.tree).sym.members_field
             : env.info.scope;
     }
+    /** Create a fresh environment for modules.
+     *
+     *  @param tree     The module definition.
+     *  @param env      The environment current outside of the module definition.
+     */
+    public Env<AttrContext> moduleEnv(JCModuleDecl tree, Env<AttrContext> env) {
+        Env<AttrContext> localEnv =
+            env.dup(tree, env.info.dup(new Scope(tree.sym)));
+        localEnv.enclClass = predefClassDef;
+        localEnv.outer = env;
+        localEnv.info.isSelfCall = false;
+        localEnv.info.lint = null; // leave this to be filled in by Attr,
+                                   // when annotations have been processed
+        return localEnv;
+    }
 
 /* ************************************************************************
  * Visitor methods for phase 1: class enter
@@ -268,55 +285,65 @@
         return ts.toList();
     }
 
+    @Override
     public void visitTopLevel(JCCompilationUnit tree) {
         JavaFileObject prev = log.useSource(tree.sourcefile);
         boolean addEnv = false;
-        boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info",
-                                                             JavaFileObject.Kind.SOURCE);
-        if (tree.pid != null) {
-            tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid));
-            if (tree.packageAnnotations.nonEmpty()) {
-                if (isPkgInfo) {
-                    addEnv = true;
-                } else {
-                    log.error(tree.packageAnnotations.head.pos(),
-                              "pkg.annotations.sb.in.package-info.java");
-                }
+
+        boolean isPackageInfo = TreeInfo.isPackageInfo(tree);
+        boolean isModuleInfo = TreeInfo.isModuleInfo(tree);
+        JCPackageDecl pd = TreeInfo.getPackage(tree);
+
+        if (pd != null) {
+            tree.packge = pd.sym = reader.enterPackage(TreeInfo.fullName(pd.packageId));
+            if (pd.annots.nonEmpty() && !isPackageInfo) {
+                log.error(pd.annots.head.pos(),
+                          "pkg.annotations.sb.in.package-info.java");
             }
         } else {
             tree.packge = syms.unnamedPackage;
         }
         tree.packge.complete(); // Find all classes in package.
-        Env<AttrContext> env = topLevelEnv(tree);
+
+        Env<AttrContext> treeEnv = topLevelEnv(tree);
 
         // Save environment of package-info.java file.
-        if (isPkgInfo) {
+        if (isPackageInfo) {
+            addEnv = (pd != null) && pd.annots.nonEmpty();
+
             Env<AttrContext> env0 = typeEnvs.get(tree.packge);
             if (env0 == null) {
-                typeEnvs.put(tree.packge, env);
+                typeEnvs.put(tree.packge, treeEnv);
             } else {
                 JCCompilationUnit tree0 = env0.toplevel;
                 if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) {
-                    log.warning(tree.pid != null ? tree.pid.pos()
-                                                 : null,
+                    log.warning(pd != null ? pd.pos() : null,
                                 "pkg-info.already.seen",
                                 tree.packge);
-                    if (addEnv || (tree0.packageAnnotations.isEmpty() &&
+                    if (addEnv || (tree0.getPackageAnnotations().isEmpty() &&
                                    tree.docComments != null &&
                                    tree.docComments.get(tree) != null)) {
-                        typeEnvs.put(tree.packge, env);
+                        typeEnvs.put(tree.packge, treeEnv);
                     }
                 }
             }
+        } else if (isModuleInfo) {
+            JCModuleDecl md = TreeInfo.getModule(tree);
+            if (md != null) {
+                typeEnvs.put(md.sym, treeEnv);
+            }
         }
-        classEnter(tree.defs, env);
-        if (addEnv) {
-            todo.append(env);
-        }
+
+        classEnter(tree.defs, treeEnv);
+
+        if (addEnv)
+            todo.append(treeEnv);
+
         log.useSource(prev);
         result = null;
     }
 
+    @Override
     public void visitClassDef(JCClassDecl tree) {
         Symbol owner = env.info.scope.owner;
         Scope enclScope = enterScope(env);
@@ -342,7 +369,9 @@
                 // We are seeing a member class.
                 c = reader.enterClass(tree.name, (TypeSymbol)owner);
                 if ((owner.flags_field & INTERFACE) != 0) {
-                    tree.mods.flags |= PUBLIC | STATIC;
+                    if ((tree.mods.flags & MODULE) == 0)
+                        tree.mods.flags |= PUBLIC;
+                    tree.mods.flags |= STATIC;
                 }
             } else {
                 // We are seeing a local class.
@@ -374,6 +403,7 @@
         c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);
         c.sourcefile = env.toplevel.sourcefile;
         c.members_field = new Scope(c);
+        c.modle = env.toplevel.modle;
 
         ClassType ct = (ClassType)c.type;
         if (owner.kind != PCK && (c.flags_field & STATIC) == 0) {
@@ -422,6 +452,7 @@
      *  Enter a symbol for type parameter in local scope, after checking that it
      *  is unique.
      */
+    @Override
     public void visitTypeParameter(JCTypeParameter tree) {
         TypeVar a = (tree.type != null)
             ? (TypeVar)tree.type
@@ -433,8 +464,16 @@
         result = a;
     }
 
+    @Override
+    public void visitModuleDef(JCModuleDecl tree) {
+        Env<AttrContext> moduleEnv = moduleEnv(tree, env);
+        typeEnvs.put(tree.sym, moduleEnv);
+        todo.append(moduleEnv);
+    }
+
     /** Default class enter visitor method: do nothing.
      */
+    @Override
     public void visitTree(JCTree tree) {
         result = null;
     }
@@ -454,9 +493,13 @@
     public void complete(List<JCCompilationUnit> trees, ClassSymbol c) {
         annotate.enterStart();
         ListBuffer<ClassSymbol> prevUncompleted = uncompleted;
-        if (memberEnter.completionEnabled) uncompleted = new ListBuffer<ClassSymbol>();
+        if (memberEnter.completionEnabled)
+            uncompleted = new ListBuffer<ClassSymbol>();
 
         try {
+            // process module declarations
+            modules.enter(trees);
+
             // enter all classes, and construct uncompleted list
             classEnter(trees, null);
 
@@ -476,11 +519,14 @@
                 for (JCCompilationUnit tree : trees) {
                     if (tree.starImportScope.elems == null) {
                         JavaFileObject prev = log.useSource(tree.sourcefile);
-                        Env<AttrContext> env = typeEnvs.get(tree);
-                        if (env == null)
-                            env = topLevelEnv(tree);
-                        memberEnter.memberEnter(tree, env);
-                        log.useSource(prev);
+                        try {
+                            Env<AttrContext> tenv = typeEnvs.get(tree);
+                            if (tenv == null)
+                                tenv = topLevelEnv(tree);
+                            memberEnter.memberEnter(tree, tenv);
+                        } finally {
+                            log.useSource(prev);
+                        }
                     }
                 }
             }
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Nov 06 13:20:18 2009 -0800
@@ -1269,6 +1269,10 @@
         // Do nothing for TopLevel since each class is visited individually
     }
 
+    public void visitModuleDef(JCModuleDecl tree) {
+        // Do nothing for modules
+    }
+
 /**************************************************************************
  * utility methods for ignoring type-annotated casts lint checking
  *************************************************************************/
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Nov 06 13:20:18 2009 -0800
@@ -1983,34 +1983,40 @@
     }
 
     public void visitTopLevel(JCCompilationUnit tree) {
-        if (tree.packageAnnotations.nonEmpty()) {
-            Name name = names.package_info;
+        if (TreeInfo.isPackageInfo(tree)) {
+            JCPackageDecl pd = TreeInfo.getPackage(tree);
             long flags = Flags.ABSTRACT | Flags.INTERFACE;
             if (target.isPackageInfoSynthetic())
-                // package-info is marked SYNTHETIC in JDK 1.6 and later releases
-                flags = flags | Flags.SYNTHETIC;
-            JCClassDecl packageAnnotationsClass
-                = make.ClassDef(make.Modifiers(flags,
-                                               tree.packageAnnotations),
-                                name, List.<JCTypeParameter>nil(),
-                                null, List.<JCExpression>nil(), List.<JCTree>nil());
-            ClassSymbol c = reader.enterClass(name, tree.packge);
-            c.flatname = names.fromString(tree.packge + "." + name);
-            c.sourcefile = tree.sourcefile;
+                flags |= SYNTHETIC;
+            ClassSymbol c = reader.enterClass(names.package_info, tree.packge);
+            c.sourcefile = attrEnv.toplevel.sourcefile;
             c.completer = null;
             c.members_field = new Scope(c);
             c.flags_field = flags;
-            c.attributes_field = tree.packge.attributes_field;
+            c.attributes_field = pd.sym.attributes_field;
+            c.modle = attrEnv.toplevel.modle;
+            pd.sym.attributes_field = List.nil();
             ClassType ctype = (ClassType) c.type;
             ctype.supertype_field = syms.objectType;
             ctype.interfaces_field = List.nil();
-            packageAnnotationsClass.sym = c;
-
-
-            translated.append(packageAnnotationsClass);
+            createInfoClass(pd.annots, c);
         }
     }
 
+    public void visitModuleDef(JCModuleDecl tree) {
+        createInfoClass(tree.annots, tree.sym.module_info);
+    }
+
+    private void createInfoClass(List<JCAnnotation> annots, ClassSymbol c) {
+        long flags = Flags.ABSTRACT | Flags.INTERFACE;
+        JCClassDecl infoClass =
+                make.ClassDef(make.Modifiers(flags, annots),
+                    c.name, List.<JCTypeParameter>nil(),
+                    null, List.<JCExpression>nil(), List.<JCTree>nil());
+        infoClass.sym = c;
+        translated.append(infoClass);
+    }
+
     public void visitClassDef(JCClassDecl tree) {
         ClassSymbol currentClassPrev = currentClass;
         MethodSymbol currentMethodSymPrev = currentMethodSym;
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Nov 06 13:20:18 2009 -0800
@@ -33,6 +33,7 @@
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
 
 import com.sun.tools.javac.code.Type.*;
@@ -42,7 +43,7 @@
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTags.*;
-import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import static com.sun.tools.javac.code.Flags.MODULE; // resolve ambiguity
 
 /** This is the second phase of Enter, in which classes are completed
  *  by entering their members into the class scope using
@@ -160,6 +161,7 @@
                                  Env<AttrContext> env) {
         final JavaFileObject sourcefile = env.toplevel.sourcefile;
         final Scope toScope = env.toplevel.starImportScope;
+        final ModuleSymbol modle = env.toplevel.modle;
         final PackageSymbol packge = env.toplevel.packge;
         final TypeSymbol origin = tsym;
 
@@ -180,7 +182,7 @@
                     Symbol sym = e.sym;
                     if (sym.kind == TYP &&
                         (sym.flags() & STATIC) != 0 &&
-                        staticImportAccessible(sym, packge) &&
+                        staticImportAccessible(sym, modle, packge) &&
                         sym.isMemberOf(origin, types) &&
                         !toScope.includes(sym))
                         toScope.enter(sym, fromScope, origin.members());
@@ -208,7 +210,7 @@
                 for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
                     Symbol sym = e.sym;
                     if (sym.isStatic() && sym.kind != TYP &&
-                        staticImportAccessible(sym, packge) &&
+                        staticImportAccessible(sym, modle, packge) &&
                         !toScope.includes(sym) &&
                         sym.isMemberOf(origin, types)) {
                         toScope.enter(sym, fromScope, origin.members());
@@ -222,7 +224,7 @@
     }
 
     // is the sym accessible everywhere in packge?
-    boolean staticImportAccessible(Symbol sym, PackageSymbol packge) {
+    boolean staticImportAccessible(Symbol sym, ModuleSymbol modle, PackageSymbol packge) {
         int flags = (int)(sym.flags() & AccessFlags);
         switch (flags) {
         default:
@@ -233,6 +235,8 @@
         case 0:
         case PROTECTED:
             return sym.packge() == packge;
+        case MODULE:
+            return  sym.modle() == modle;
         }
     }
 
@@ -253,6 +257,7 @@
         }
 
         final Scope toScope = env.toplevel.namedImportScope;
+        final ModuleSymbol modle = env.toplevel.modle;
         final PackageSymbol packge = env.toplevel.packge;
         final TypeSymbol origin = tsym;
 
@@ -274,7 +279,7 @@
                     Symbol sym = e.sym;
                     if (sym.isStatic() &&
                         sym.kind == TYP &&
-                        staticImportAccessible(sym, packge) &&
+                        staticImportAccessible(sym, modle, packge) &&
                         sym.isMemberOf(origin, types) &&
                         chk.checkUniqueStaticImport(pos, sym, toScope))
                         toScope.enter(sym, sym.owner.members(), origin.members());
@@ -304,7 +309,7 @@
                      e = e.next()) {
                     Symbol sym = e.sym;
                     if (sym.isStatic() &&
-                        staticImportAccessible(sym, packge) &&
+                        staticImportAccessible(sym, modle, packge) &&
                         sym.isMemberOf(origin, types)) {
                         found = true;
                         if (sym.kind == MTH ||
@@ -502,23 +507,36 @@
             return;
         }
 
+        JCModuleDecl md = TreeInfo.getModule(tree);
+        JCPackageDecl pd = TreeInfo.getPackage(tree);
+
         // check that no class exists with same fully qualified name as
         // toplevel package
-        if (checkClash && tree.pid != null) {
+        if (checkClash && pd != null) {
             Symbol p = tree.packge;
             while (p.owner != syms.rootPackage) {
                 p.owner.complete(); // enter all class members of p
                 if (syms.classes.get(p.getQualifiedName()) != null) {
                     log.error(tree.pos,
-                              "pkg.clashes.with.class.of.same.name",
-                              p);
+                            "pkg.clashes.with.class.of.same.name",
+                            p);
                 }
                 p = p.owner;
             }
         }
 
+        // set up module and its dependencies
+        /*temp*/if (tree.modle != null)/*temp*/ // JIGSAW TEMP: tree.modle SHOULD ALWAYS BE SET
+            tree.modle.complete();
+
+        // process module annotations
+        if (md != null) {
+            annotateLater(md.annots, env, md.sym);
+        }
+
         // process package annotations
-        annotateLater(tree.packageAnnotations, env, tree.packge);
+        if (pd != null)
+            annotateLater(pd.annots, env, pd.sym);
 
         // Import-on-demand java.lang.
         importAll(tree.pos, reader.enterPackage(names.java_lang), env);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Modules.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,878 @@
+/*
+ * 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.comp;
+
+import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.CompletionFailure;
+import com.sun.tools.javac.code.Symbol.ModuleRequires;
+import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.jvm.ClassFile;
+import com.sun.tools.javac.jvm.ClassFile.ModuleId;
+import com.sun.tools.javac.jvm.ClassReader;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCModuleClass;
+import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
+import com.sun.tools.javac.tree.JCTree.JCModuleId;
+import com.sun.tools.javac.tree.JCTree.JCModulePermits;
+import com.sun.tools.javac.tree.JCTree.JCModuleRequires;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic;
+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.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.util.ModuleResolver;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.ModuleFileManager;
+import javax.tools.ModuleFileManager.InvalidFileObjectException;
+import javax.tools.ModuleFileManager.ModuleMode;
+
+import static javax.tools.StandardLocation.*;
+
+/**
+ * <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 Modules extends JCTree.Visitor {
+    ClassReader reader;
+    Log log;
+    JavaFileManager fileManager;
+    ModuleFileManager moduleFileManager;
+    Names names;
+    Symtab syms;
+
+    ModuleMode mode;
+
+    /** The set of locations for entered trees */
+    Set<Location> rootLocns = new LinkedHashSet<Location>();
+
+    // The following should be moved to Symtab, with possible reference in ClassReader
+    Map<Location,ModuleSymbol> allModules = new LinkedHashMap<Location,ModuleSymbol>();
+
+    /** The current top level tree */
+    JCCompilationUnit currTopLevel;
+
+    /** The symbol currently being analyzed. */
+    ModuleSymbol currSym;
+
+    static class ModuleContext {
+        ModuleContext(JCModuleDecl decl) {
+            this.decl = decl;
+        }
+        final JCModuleDecl decl;
+        boolean seenPlatformRequires;
+    }
+
+    Env<ModuleContext> env;
+    Map<ModuleSymbol, Env<ModuleContext>> moduleEnvs = new HashMap<ModuleSymbol, Env<ModuleContext>>();
+
+    /** True if file manager is not a ModuleFileManager and we have
+     * seen module declaration in input trees. */
+    boolean moduleFileManagerUnavailable;
+
+    public static Modules instance(Context context) {
+        Modules instance = context.get(Modules.class);
+        if (instance == null)
+            instance = new Modules(context);
+        return instance;
+    }
+
+    protected Modules(Context context) {
+        context.put(Modules.class, this);
+        log = Log.instance(context);
+        reader = ClassReader.instance(context);
+        fileManager = context.get(JavaFileManager.class);
+        names = Names.instance(context);
+        syms = Symtab.instance(context);
+
+        if (fileManager instanceof ModuleFileManager) {
+            moduleFileManager = (ModuleFileManager) fileManager;
+            mode = moduleFileManager.getModuleMode();
+        } else
+            mode = ModuleMode.SINGLE;
+    }
+
+    <T extends JCTree> void acceptAll(List<T> trees) {
+        for (List<T> l = trees; l.nonEmpty(); l = l.tail)
+            l.head.accept(this);
+    }
+
+
+
+    @Override
+    public void visitModuleDef(JCModuleDecl tree) {
+        DEBUG("Modules.visitModuleDef " + tree.id);
+
+        if (mode == ModuleMode.SINGLE) {
+            if (moduleFileManager == null) {
+                log.error(tree, "mdl.module.file.manager.required");
+                moduleFileManagerUnavailable = true;
+            } else {
+                currTopLevel.locn = moduleFileManager.join(List.of(CLASS_PATH, SOURCE_PATH));
+                if (state == State.INITIAL)
+                    rootLocns.add(currTopLevel.locn);
+            }
+        }
+
+        ModuleSymbol sym = enterModule(currTopLevel.locn);
+        if (sym.name != null) {
+            log.error(tree.pos(), "mdl.already.defined", sym.module_info.sourcefile);
+            sym = new ModuleSymbol(TreeInfo.fullName(tree.id.qualId), syms.rootModule);
+        } else {
+            sym.name = sym.fullname = TreeInfo.fullName(tree.id.qualId);
+            sym.module_info.fullname = ClassSymbol.formFullName(sym.module_info.name, sym);
+            sym.module_info.flatname = ClassSymbol.formFlatName(sym.module_info.name, sym);
+            sym.module_info.sourcefile = currTopLevel.sourcefile;
+            sym.module_info.members_field = new Scope(sym.module_info);
+            sym.completer = null;
+        }
+
+        DEBUG("Modules.visitModuleDef name "         + sym.name);
+        DEBUG("Modules.visitModuleDef fullname "     + sym.fullname);
+        DEBUG("Modules.visitModuleDef flatName() "   + sym.flatName());
+        DEBUG("Modules.visitModuleDef m-i name "     + sym.module_info.name);
+        DEBUG("Modules.visitModuleDef m-i fullname " + sym.module_info.fullname);
+        DEBUG("Modules.visitModuleDef m-i flatname " + sym.module_info.flatname);
+
+        sym.location = currTopLevel.locn;
+        tree.sym = sym;
+
+        sym.version = tree.getId().version;
+        sym.permits = new ListBuffer<Name>();
+        sym.provides = new ListBuffer<ModuleId>();
+        sym.requires = new LinkedHashMap<ModuleId,ModuleRequires>();
+        for (List<JCModuleId> l = tree.provides; l.nonEmpty(); l = l.tail) {
+            JCModuleId moduleId = l.head;
+            sym.provides.append(new ModuleId(TreeInfo.fullName(moduleId.qualId), moduleId.version));
+        }
+
+        currSym = sym;
+        Env<ModuleContext> menv = env.dup(tree, new ModuleContext(tree));
+        moduleEnvs.put(sym, menv);
+        Env<ModuleContext> prev = env;
+        env = menv;
+        try {
+            acceptAll(tree.metadata);
+
+            if (!env.info.seenPlatformRequires) {
+                ModuleId mid = getDefaultPlatformModule();
+                sym.requires.put(mid, new ModuleRequires(mid, List.of(names.synthetic)));
+            }
+        } finally {
+            currSym = null;
+            env = prev;
+        }
+    }
+
+    @Override
+    public void visitTopLevel(JCCompilationUnit tree) {
+        DEBUG("Modules.visitTopLevel " + tree.sourcefile);
+        env = new Env<ModuleContext>(tree, null);
+        env.toplevel = tree;
+        currTopLevel = tree;
+        JavaFileObject prev = log.useSource(tree.sourcefile);
+        try {
+            if (mode == ModuleMode.MULTIPLE) {
+                assert moduleFileManager != null;
+                Location l = moduleFileManager.join(List.of(MODULE_PATH, SOURCE_PATH));
+                JCExpression pn = tree.getPackageName();
+                String pkgName = (pn == null) ? "" : TreeInfo.fullName(pn).toString();
+                try {
+                    tree.locn = moduleFileManager.getModuleLocation(l, tree.sourcefile, pkgName);
+                    DEBUG("Modules.visitTopLevel MULTIPLE " + tree.locn);
+                    if (state == State.INITIAL)
+                        rootLocns.add(tree.locn);
+                } catch (InvalidFileObjectException e) {
+                    log.error(pn, "mdl.file.in.wrong.directory", tree.sourcefile, pkgName);
+                }
+            }
+
+            if (TreeInfo.isModuleInfo(tree))
+                acceptAll(tree.defs);
+        } finally {
+            currTopLevel = null;
+            log.useSource(prev);
+            DEBUG("Modules.visitTopLevel EXIT rootLocns=" + rootLocns);
+        }
+    }
+
+    @Override
+    public void visitModuleClass(JCModuleClass tree) {
+//        ModuleSymbol sym = currSym;
+//        Name className = TreeInfo.fullName(tree.qualId);
+//        // JIGSAW TODO check conflicts (at most one class)
+//        sym.className = reader.enterClass(className);
+//        sym.classFlags = tree.flags;
+    }
+
+    @Override
+    public void visitModulePermits(JCModulePermits tree) {
+        ModuleSymbol sym = currSym;
+        for (List<JCExpression> l = tree.moduleNames; l.nonEmpty(); l = l.tail) {
+            JCTree qualId = l.head;
+            Name moduleName = TreeInfo.fullName(qualId);
+            // JIGSAW TODO check duplicates
+            sym.permits.add(moduleName);
+        }
+    }
+
+    @Override
+    public void visitModuleRequires(JCModuleRequires tree) {
+        ModuleSymbol sym = currSym;
+        for (List<JCModuleId> l = tree.moduleIds; l.nonEmpty(); l = l.tail) {
+            JCModuleId moduleId = l.head;
+            ModuleId mid = new ModuleId(TreeInfo.fullName(moduleId.qualId), moduleId.version);
+            // JIGSAW TODO check duplicates
+            sym.requires.put(mid, new ModuleRequires(mid, tree.flags));
+            ModuleResolver mr = getModuleResolver();
+            if (mr.isPlatformName(mid.name))
+                env.info.seenPlatformRequires = true;
+        }
+    }
+
+    @Override
+    public void visitTree(JCTree tree) { }
+
+    ModuleSymbol enterModule(Location locn) {
+        ModuleSymbol sym = allModules.get(locn);
+        if (sym == null) {
+            sym = new ModuleSymbol(null, syms.rootModule);
+            sym.location = locn;
+            sym.module_info = new ClassSymbol(0, names.module_info, sym);
+            sym.module_info.modle = sym;
+            sym.completer = new Symbol.Completer() {
+                public void complete(Symbol sym) throws CompletionFailure {
+                    readModule((ModuleSymbol) sym);
+                }
+            };
+            allModules.put(locn, sym);
+        }
+        return sym;
+    }
+
+    void readModule(ModuleSymbol sym) {
+        Location locn = sym.location;
+        JavaFileObject srcFile = getModuleInfo(locn, JavaFileObject.Kind.SOURCE);
+        JavaFileObject classFile = getModuleInfo(locn, JavaFileObject.Kind.CLASS);
+        DEBUG("Modules.readModule: src:" + srcFile + " class:" + classFile);
+        JavaFileObject file;
+        if (srcFile == null) {
+            if (classFile == null) {
+                sym.name = names.empty; // unnamed module
+                return;
+            }
+            file = classFile;
+        } else if (classFile == null)
+            file = srcFile;
+        else
+            file = reader.preferredFileObject(srcFile, classFile);
+        DEBUG("Modules.readModule: select:" + file);
+
+        sym.module_info.classfile = file;
+        DEBUG("Modules.readModule: complete:" + sym + " " + sym.module_info.classfile);
+        reader.complete(sym);
+        assert sym.name != null;
+        DEBUG("Modules.readModule: finished:" + sym + " name:" + sym.name + " fullname:" + sym.fullname + " flatName():" + sym.flatName());
+    }
+
+    JavaFileObject getModuleInfo(Location locn, JavaFileObject.Kind kind) {
+        try {
+            return fileManager.getJavaFileForInput(locn, "module-info", kind);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    ModuleId getDefaultPlatformModule() {
+        if (defaultPlatformModule == null) {
+            ModuleResolver mr = getModuleResolver();
+            String def = mr.getDefaultPlatformModule();
+            int at = def.indexOf("@");
+            if (at == -1)
+                defaultPlatformModule = new ModuleId(names.fromString(def), null);
+            else {
+                Name name = names.fromString(def.substring(0, at).trim());
+                Name version = names.fromString(def.substring(at + 1).trim());
+                defaultPlatformModule = new ModuleId(name, version);
+            }
+        }
+        return defaultPlatformModule;
+    }
+    // where
+    private ModuleId defaultPlatformModule;
+
+    private boolean resolve(List<JCCompilationUnit> trees) {
+        if (moduleFileManagerUnavailable)
+            return false;
+
+        DEBUG("Modules.resolve mode=" + mode + ", rootLocns=" + rootLocns + " (" + rootLocns.size() + "]" );
+        if (mode == ModuleMode.SINGLE && rootLocns.isEmpty()) {
+            if (moduleFileManager != null) {
+                rootLocns.add(moduleFileManager.join(List.of(CLASS_PATH, SOURCE_PATH)));
+            } else {
+                // TODO: check for module-info.{java,class} and give error if found
+                // TODO?? use a custom DEFAULT locn, instead of null??
+                return true;
+            }
+        }
+
+        DEBUG("Modules.resolve: building roots, rootLocns=" + rootLocns);
+        List<ModuleSymbol> roots = List.nil();
+        for (Location locn: rootLocns) {
+            DEBUG("Modules.resolve: building roots: locn: " + locn);
+            ModuleSymbol msym = enterModule(locn);
+            DEBUG("Modules.resolve: building roots: msym: " + msym);
+            msym.complete();
+            DEBUG("Modules.resolve: building roots: completed: " + msym);
+            if (msym.name != names.empty)
+                roots = roots.prepend(msym);
+        }
+        roots = roots.reverse();
+        DEBUG("Modules.resolve: roots: " + roots);
+
+        updateTrees(trees);
+
+        if (roots.isEmpty())
+            return true;
+
+        DEBUG("Modules.resolve: modules so far: " + allModules);
+
+        DEBUG("Modules.resolve: reading module-info as needed");
+        Location l = (moduleFileManager.getModuleMode() == ModuleMode.SINGLE)
+                ? MODULE_PATH : moduleFileManager.join(List.of(MODULE_PATH, SOURCE_PATH));
+        for (Location locn: moduleFileManager.getModuleLocations(l)) {
+            DEBUG("Modules.resolve: ensuring module-info for " + locn);
+            enterModule(locn).complete();
+        }
+
+        DEBUG("Modules.resolve: resolve modules");
+        ModuleResolver mr = getModuleResolver();
+        DEBUG("Modules.resolve: module resolver: " + mr);
+        try {
+            ListBuffer<ModuleSymbol> namedModules = new ListBuffer<ModuleSymbol>();
+            for (ModuleSymbol msym: allModules.values()) {
+                if (msym.name != names.empty)
+                    namedModules.add(msym);
+            }
+            Iterable<? extends ModuleElement> modules =
+                    mr.resolve(roots, namedModules);
+
+            ListBuffer<Location> locns = new ListBuffer<Location>();
+            for (ModuleElement me: modules) {
+                ModuleSymbol msym = (ModuleSymbol) me;
+                DEBUG("Modules.resolve: msym: " + msym);
+                DEBUG("Modules.resolve: msym.location: " + msym.location);
+                locns.add(msym.location);
+            }
+            Location merged = moduleFileManager.join(locns);
+            DEBUG("Modules.resolve: merged result: " + merged);
+            reader.setPathLocation(merged);
+        } catch (ModuleResolver.ResolutionException e) {
+            DEBUG("Modules.resolve: resolution error " + e);
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+
+    }
+
+    protected ModuleResolver getModuleResolver() {
+        if (moduleResolver != null)
+            return moduleResolver;
+
+        ServiceLoader<ModuleResolver> loader = ServiceLoader.load(ModuleResolver.class);
+        // for now, use the first available, if any
+        for (Iterator<ModuleResolver> iter = loader.iterator(); iter.hasNext(); ) {
+            moduleResolver = iter.next();
+            return moduleResolver;
+        }
+
+        // use Class.forName on jigsaw module resolve
+
+        // use ZeroMod
+        moduleResolver = new ZeroMod(new ErrorHandler() {
+            public void report(ModuleSymbol msym, ModuleId mid, String key, Object... args) {
+                error(msym, mid, key, args);
+            }
+        });
+        return moduleResolver;
+    }
+    // where
+    private ModuleResolver moduleResolver;
+
+    private void error(ModuleSymbol msym, ModuleId id, String key, Object... args) {
+        // TODO, determine error location from msym, mid
+        ClassSymbol minfo = msym.module_info;
+
+        Env<ModuleContext> menv = moduleEnvs.get(msym);
+        DEBUG("Modules.error " + msym + " -- " + moduleEnvs.get(msym));
+        JavaFileObject fo;
+        JCDiagnostic.DiagnosticPosition pos;
+        if (menv == null) {
+            fo = (minfo.sourcefile != null ? minfo.sourcefile : minfo.classfile);
+            if (fo == null)
+                fo = msym.module_info.classfile;
+            pos = null;
+        } else {
+            fo = menv.toplevel.sourcefile;
+            pos = treeFinder.find(menv.info.decl, id);
+        }
+
+        JavaFileObject prev = log.useSource(fo);
+        try {
+            log.error(pos, key, args);
+        } finally {
+            log.useSource(prev);
+        }
+    }
+
+    class TreeFinder extends JCTree.Visitor {
+        ModuleId mid;
+        JCTree result;
+
+        JCTree find(JCTree tree, ModuleId mid) {
+            DEBUG("Modules.TreeFinder.find mid=" + mid);
+            this.mid = mid;
+            result = null;
+            tree.accept(this);
+            DEBUG("Modules.TreeFinder.find result=" + result);
+            return result;
+        }
+
+        @Override
+        public void visitModuleDef(JCModuleDecl tree) {
+            search(tree.id);
+            search(tree.provides);
+            search(tree.metadata);
+        }
+
+        @Override
+        public void visitModuleRequires(JCModuleRequires tree) {
+            search(tree.moduleIds);
+        }
+
+        @Override
+        public void visitModuleId(JCModuleId tree) {
+            DEBUG("Modules.treeFinder.visitModuleId " + tree + " " + mid);
+            if (equal(TreeInfo.fullName(tree.qualId), mid.name) && equal(tree.version, mid.version))
+                result = tree;
+            DEBUG("Modules.treeFinder.visitModuleId result " + result);
+        }
+
+        void search(JCTree tree) {
+            if (result != null)
+                return;
+
+            tree.accept(this);
+        }
+
+        void search(List<? extends JCTree> trees) {
+            if (result != null)
+                return;
+
+            for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
+                l.head.accept(this);
+                if (result != null)
+                    return;
+            }
+        }
+
+        <T> boolean equal(T t1, T t2) {
+            DEBUG("Modules.treeFinder.equal " + t1 + " " + t2 + (t1 == null ? t2 == null : t1.equals(t2)));
+            return t1 == null ? t2 == null : t1.equals(t2);
+        }
+    }
+    TreeFinder treeFinder = new TreeFinder();
+
+    private void updateTrees(List<JCCompilationUnit> trees) {
+        if (mode == ModuleMode.SINGLE) {
+            assert rootLocns.size() == 1;
+            Location locn = rootLocns.iterator().next();
+            locn.getClass(); // debug
+            ModuleSymbol msym = allModules.get(locn);
+            DEBUG("Modules.updateTrees: update SINGLE trees: " + locn + " " + msym);
+            if (msym == null) {
+                msym = syms.unnamedModule;
+                DEBUG("Modules.updateTrees: using unnamed module " + syms.unnamedModule.completer);
+            }
+            for (List<JCCompilationUnit> l = trees; l.nonEmpty(); l = l.tail) {
+                JCCompilationUnit tree = l.head;
+                assert tree.locn == null || tree.locn == locn;
+                tree.locn = locn;
+                assert tree.modle == null || tree.modle == msym;
+                tree.modle = msym;
+            }
+        } else {
+            for (List<JCCompilationUnit> l = trees; l.nonEmpty(); l = l.tail) {
+                JCCompilationUnit t = l.head;
+                ModuleSymbol msym = allModules.get(t.locn);
+                if (msym == null) {
+                    msym = syms.unnamedModule;
+                    DEBUG("Modules.updateTrees: using unnamed module " + syms.unnamedModule.completer);
+                }
+                t.modle = msym;
+                DEBUG("Modules.updateTrees: update MULTIPLE trees: " + t.locn + " " + t.modle);
+            }
+        }
+    }
+
+    private enum State { INITIAL, RESOLVING, RESOLVED};
+    private State state = State.INITIAL;
+
+    private int enterCount = 0; // debug only
+
+    public boolean enter(List<JCCompilationUnit> trees) {
+        int count = enterCount++;
+        DEBUG("Modules.enter " + count + " " + state);
+
+        DEBUG("Modules.enter " + count + ": acceptAll");
+        acceptAll(trees);
+
+        try { // debug
+
+        switch (state) {
+            case INITIAL:
+                state = State.RESOLVING;
+                try {
+                    return resolve(trees);
+                } finally {
+                    state = State.RESOLVED;
+                }
+
+            case RESOLVING:
+                updateTrees(trees);
+                return true;
+
+            case RESOLVED:
+                return true;
+
+            default:
+                throw new AssertionError();
+        }
+
+        // debug
+        } finally {
+             DEBUG("Modules.enter " + count + ": exit " + state);
+        }
+    }
+
+    // Quick and dirty temporary debug printing;
+    // this should all be removed prior to final integration
+    boolean DEBUG = false;
+    void DEBUG(String s) {
+        if (DEBUG)
+            System.err.println(s);
+    }
+
+    private static <T> String toString(Iterable<T> items) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        String sep = "";
+        for (T t: items) {
+            sb.append(sep);
+            sb.append(t);
+            sep = ",";
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    // should be static within ZeroMod
+    enum VersionErrorKind {
+        NO_VERSION_AVAILABLE("mdl.no.version.available"),
+        NO_UNIQUE_VERSION_AVAILABLE("mdl.no.unique.version.available"),
+        REQUIRED_VERSION_NOT_AVAILABLE("mdl.required.version.not.available");
+        VersionErrorKind(String key) { this.key = key; }
+        final String key;
+    };
+
+    interface ErrorHandler {
+        void report(ModuleSymbol msym, ModuleId mid, String key, Object... args);
+    }
+
+    class ZeroMod implements ModuleResolver {
+        private ErrorHandler errorHandler;
+
+        ZeroMod(ErrorHandler e) {
+            errorHandler = e;
+        }
+
+        public Iterable<? extends ModuleElement> resolve(
+                Iterable<? extends ModuleElement> roots,
+                Iterable<? extends ModuleElement> modules)
+        {
+            DEBUG("ZeroMod: roots: " + Modules.toString(roots));
+            DEBUG("ZeroMod: modules: " + Modules.toString(modules));
+            roots.getClass();
+            modules.getClass();
+
+            moduleTable = buildModuleTable(modules);
+            List<Node> rootNodes = getNodes(roots);
+            tarjan(rootNodes);
+
+            DEBUG("ZeroMod.NODE MAP {");
+            for (Node n: nodeMap.values())
+                DEBUG("  Node " + n + " " + n.scc);
+            DEBUG("}");
+
+            ListBuffer<ModuleSymbol> results = new ListBuffer<ModuleSymbol>();
+            for (Node node: rootNodes) {
+                if (!results.contains(node.sym))
+                    getVisibleModules(node.scc, results);
+            }
+
+            DEBUG("ZeroMod: results: " + Modules.toString(results));
+            return results;
+        }
+
+        public Iterable<? extends ModuleElement> getVisibleModules(ModuleElement elem) {
+            ModuleSymbol sym = (ModuleSymbol) elem;
+            DEBUG("ZeroMod getVisibleModules " + getNode(sym));
+            SCC scc = getNode(sym).scc;
+            ListBuffer<ModuleSymbol> results = new ListBuffer<ModuleSymbol>();
+            getVisibleModules(scc, results);
+            return results.toList();
+        }
+
+        private void getVisibleModules(SCC scc, ListBuffer<ModuleSymbol> results) {
+            for (Node n: scc.nodes)
+                results.add(n.sym);
+            for (SCC child: scc.getChildren())
+                getVisibleModules(child, results);
+        }
+
+        private Map<Name, Map<Name, ModuleSymbol>> buildModuleTable(
+                Iterable<? extends ModuleElement> modules) {
+            Map<Name, Map<Name, ModuleSymbol>> table = new HashMap<Name, Map<Name, ModuleSymbol>>();
+            // build module index
+            for (ModuleElement elem: modules) {
+                ModuleSymbol sym = (ModuleSymbol) elem;
+                add(table, sym, new ClassFile.ModuleId(sym.name, sym.version));
+                for (List<ClassFile.ModuleId> l = sym.provides.toList(); l.nonEmpty(); l = l.tail)
+                    add(table, sym, l.head);
+            }
+            return table;
+        }
+
+        private void add(Map<Name, Map<Name, ModuleSymbol>> table,
+                ModuleSymbol sym, ModuleId mid) {
+            Map<Name, ModuleSymbol> versions = table.get(mid.name);
+            if (versions == null)
+                table.put(mid.name, versions = new HashMap<Name, ModuleSymbol>());
+            ModuleSymbol m = versions.get(mid.version);
+            if (m != null)
+                // TODO ?? enhance error to disambiguate between define and provides
+                errorHandler.report(sym, mid, "mdl.duplicate.definition", m);
+            else
+                versions.put(mid.version, sym);
+        }
+
+        private ModuleSymbol getModule(ModuleId mid) throws ModuleException {
+            Map<Name, ModuleSymbol> versions = moduleTable.get(mid.name);
+            if (versions == null)
+                throw new ModuleException("mdl.no.version.available", mid);
+            if (mid.version == null) {
+                if (versions.size() > 1)
+                    throw new ModuleException("mdl.no.unique.version.available", mid);
+                return versions.values().iterator().next();
+            } else {
+                ModuleSymbol sym = versions.get(mid.version);
+                if (sym == null)
+                    throw new ModuleException("mdl.required.version.not.available", mid);
+                return sym;
+            }
+        }
+        // where
+        private Map<Name, Map<Name, ModuleSymbol>> moduleTable;
+
+        public boolean isPlatformName(CharSequence name) {
+            String n = name.toString();
+            return n.equals("jdk") || n.startsWith("jdk.");  // for now
+        }
+
+        public String getDefaultPlatformModule() {
+            return "jdk@7-ea"; // for now
+        }
+
+        private class ModuleException extends Exception {
+            private static final long serialVersionUID = 0;
+            ModuleException(String key, ModuleId moduleId) {
+                this.key = key;
+                this.moduleId = moduleId;
+            }
+            final String key;
+            final ModuleId moduleId;
+        }
+
+        List<Node> getNodes(Iterable<? extends ModuleElement> elems) {
+            ListBuffer<Node> lb = new ListBuffer<Node>();
+            for (ModuleElement elem: elems) {
+                ModuleSymbol sym = (ModuleSymbol) elem;
+                lb.add(getNode(sym));
+            }
+            return lb.toList();
+        }
+
+        Node getNode(ModuleSymbol sym) {
+            Node node = nodeMap.get(sym);
+            if (node == null)
+                nodeMap.put(sym, (node = new Node(sym)));
+            return node;
+        }
+        // where
+        private Map<ModuleSymbol, Node> nodeMap= new HashMap<ModuleSymbol, Node>();
+
+        private class Node implements Comparable<Node> {
+            final ModuleSymbol sym;
+            SCC scc;
+            int index = -1;
+            int lowlink;
+            boolean active;
+
+            Node(ModuleSymbol sym) {
+                this.sym = sym;
+            }
+
+            Iterable<Node> getDependencies() {
+                DEBUG("ZeroMod.Node.getDependencies: " + sym + " " + sym.requires);
+                ListBuffer<Node> nodes = new ListBuffer<Node>();
+                for (ModuleRequires mr: sym.requires.values()) {
+                    if (isPlatformName(mr.moduleId.name)) {
+                        DEBUG("ZeroMod.Node.getDependencies: ignore platform module " + mr.moduleId.name);
+                        continue;
+                    }
+                    try {
+                        nodes.add(getNode(getModule(mr.moduleId)));
+                    } catch (ModuleException e) {
+                        errorHandler.report(sym, e.moduleId, e.key, e.moduleId);
+                    }
+                }
+                return nodes.toList();
+            }
+
+            @Override
+            public String toString() {
+                return sym.name + "@" + sym.version + "(index:" + index +",low:" + lowlink + ",active:" + active + ")" ;
+            }
+
+            public int compareTo(Node o) {
+                return (index < o.index) ? -1 : (index == o.index) ? 0 : 1;
+            }
+        }
+
+        private class SCC {
+            void add(Node node) {
+                nodes.add(node);
+                node.scc = this;
+            }
+
+            Set<SCC> getChildren() {
+                if (children == null) {
+                    children = new LinkedHashSet<SCC>();
+                    for (Node node: nodes) {
+                        for (Node n: node.getDependencies()) {
+                            n.scc.getClass(); // nullcheck
+                            if (n.scc != this)
+                                children.add(n.scc);
+                        }
+                    }
+                }
+                return children;
+            }
+
+            @Override
+            public String toString() {
+                return nodes.toString();
+            }
+
+            private SortedSet<Node> nodes = new TreeSet<Node>();
+            private Set<SCC> children;
+        }
+
+        // Tarjan's algorithm to determine strongly connected components of a
+        // directed graph in linear time.
+
+        void tarjan(Iterable<? extends Node> nodes) {
+            for (Node node: nodes) {
+                if (node.index == -1)
+                    tarjan(node);
+            }
+        }
+
+        void tarjan(Node v) {
+            v.index = index;
+            v.lowlink = index;
+            index++;
+            stack.add(0, v);
+            v.active = true;
+            for (Node n: v.getDependencies()) {
+                if (n.index == -1) {
+                    tarjan(n);
+                    v.lowlink = Math.min(v.lowlink, n.lowlink);
+                } else if (stack.contains(n)) {
+                    v.lowlink = Math.min(v.lowlink, n.index);
+                }
+            }
+            if (v.lowlink == v.index) {
+                Node n;
+                SCC scc = new SCC();
+                do {
+                    n = stack.remove(0);
+                    n.active = false;
+                    scc.add(n);
+                } while (n != v);
+            }
+        }
+
+        private int index = 0;
+        private ArrayList<Node> stack = new ArrayList<Node>();
+    }
+}
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Nov 06 13:20:18 2009 -0800
@@ -25,6 +25,10 @@
 
 package com.sun.tools.javac.comp;
 
+import java.util.Map;
+import java.util.HashMap;
+import javax.lang.model.element.ElementVisitor;
+
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.code.*;
@@ -40,10 +44,8 @@
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTags.*;
-import javax.lang.model.element.ElementVisitor;
 
-import java.util.Map;
-import java.util.HashMap;
+import static com.sun.tools.javac.code.Flags.MODULE; // disambiguate
 
 /** Helper class for name resolution, used mostly by the attribution phase.
  *
@@ -144,7 +146,7 @@
      *  @param c      The class whose accessibility is checked.
      */
     public boolean isAccessible(Env<AttrContext> env, TypeSymbol c) {
-        switch ((short)(c.flags() & AccessFlags)) {
+        switch ((int)(c.flags() & AccessFlags)) {
         case PRIVATE:
             return
                 env.enclClass.sym.outermostClass() ==
@@ -160,6 +162,10 @@
                 // classes which would be inaccessible otherwise.
                 env.enclMethod != null &&
                 (env.enclMethod.mods.flags & ANONCONSTR) != 0;
+        case MODULE:
+            return
+                env.toplevel.modle == c.modle();
+
         default: // error recovery
         case PUBLIC:
             return true;
@@ -199,9 +205,9 @@
      *  @param sym    The symbol.
      */
     public boolean isAccessible(Env<AttrContext> env, Type site, Symbol sym) {
-        if (sym.name == names.init && sym.owner != site.tsym) return false;
-        ClassSymbol sub;
-        switch ((short)(sym.flags() & AccessFlags)) {
+        if (sym.name == names.init && sym.owner != site.tsym)
+            return false;
+        switch ((int)(sym.flags() & AccessFlags)) {
         case PRIVATE:
             return
                 (env.enclClass.sym == sym.owner // fast special case
@@ -221,6 +227,15 @@
                 sym.isInheritedIn(site.tsym, types)
                 &&
                 notOverriddenIn(site, sym);
+        case MODULE:
+            return
+                (env.toplevel.modle == sym.modle())
+                &&
+                isAccessible(env, site)
+                &&
+                sym.isInheritedIn(site.tsym, types)
+                &&
+                notOverriddenIn(site, sym);
         case PROTECTED:
             return
                 (env.toplevel.packge == sym.owner.owner // fast special case
--- a/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java	Fri Nov 06 13:20:18 2009 -0800
@@ -73,6 +73,8 @@
 
     protected abstract String inferBinaryName(Iterable<? extends File> path);
 
+    protected abstract String inferModuleTag(String binaryName);
+
     protected static JavaFileObject.Kind getKind(String filename) {
         if (filename.endsWith(CLASS.extension))
             return CLASS;
--- a/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Fri Nov 06 13:20:18 2009 -0800
@@ -55,7 +55,10 @@
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.zip.ZipFile;
@@ -63,10 +66,18 @@
 import javax.lang.model.SourceVersion;
 import javax.tools.FileObject;
 import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
 import javax.tools.JavaFileObject;
+import javax.tools.ModuleFileManager;
 import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+
+import static javax.tools.StandardLocation.*;
 
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.file.Paths.Path;
+import com.sun.tools.javac.file.Paths.PathEntry;
+import com.sun.tools.javac.file.Paths.PathLocation;
 import com.sun.tools.javac.file.RelativePath.RelativeFile;
 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
 import com.sun.tools.javac.main.JavacOption;
@@ -79,7 +90,6 @@
 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 +101,7 @@
  * This code and its internal interfaces are subject to change or
  * deletion without notice.</b>
  */
-public class JavacFileManager implements StandardJavaFileManager {
+public class JavacFileManager implements StandardJavaFileManager, ModuleFileManager {
 
     boolean useZipFileIndex;
 
@@ -398,6 +408,188 @@
         return j < 0;
     }
 
+    private ModuleMode moduleMode;
+
+    public ModuleMode getModuleMode() {
+        if (moduleMode == null) {
+            if (options.get(MODULEPATH) != null && options.get(CLASSPATH) == null)
+                moduleMode = ModuleMode.MULTIPLE;
+            else
+                moduleMode = ModuleMode.SINGLE;
+        }
+        return moduleMode;
+    }
+
+    public Location getModuleLocation(Location locn, JavaFileObject fo, String pkgName)
+            throws InvalidLocationException, InvalidFileObjectException {
+        if (getModuleMode() == ModuleMode.SINGLE)
+            return locn;
+        else {
+            fo.getClass(); // null check
+            if (!(fo instanceof BaseFileObject))
+                throw new IllegalArgumentException();
+
+            if (!hasLocation(locn))
+                throw new InvalidLocationException();
+            String tag = ((BaseFileObject) fo).inferModuleTag(pkgName);
+            if (tag == null)
+                throw new InvalidFileObjectException();
+            return getModuleLocation(locn, tag);
+        }
+    }
+
+    private Map<Location,Iterable<Location>> moduleLocations =
+            new LinkedHashMap<Location,Iterable<Location>>();
+
+    public Iterable<Location> getModuleLocations(Location locn) {
+        //System.err.println("JavacFileManager.getModuleLocations " + getModuleMode() + " " + locn);
+
+        Iterable<Location> result = moduleLocations.get(locn);
+        if (result == null) {
+            Iterable<PathEntry> pathEntries = getEntriesForLocation(locn);
+            if (pathEntries == null)
+                result = List.<Location>nil();
+            else {
+                Set<Location> locns = new LinkedHashSet<Location>();
+                for (PathEntry pe: pathEntries) {
+                    if (pe.file.isDirectory()) {
+                        for (File f: pe.file.listFiles()) {
+                            String tag = null;
+                            if (f.isDirectory())
+                                tag = f.getName();
+//                            else if (isArchive(f)) {
+//                                String name = f.getName();
+//                                tag = name.substring(0, name.lastIndexOf("."));
+//                            }
+                            if (tag != null)
+                                locns.add(getModuleLocation(locn, tag));
+                        }
+                    } else {
+                        // ignore archive files for now, these would be "module archive
+                        // files", containing multiple modules in a new but obvious way
+                    }
+
+                }
+                result = locns;
+            }
+        }
+
+//        System.err.println("JavacFileManager.getModuleLocations.result " + result);
+        return result;
+    }
+
+
+    private Map<String, Location> locationCache = new HashMap<String,Location>();
+
+    public Location join(Iterable<? extends Location> locations)
+            throws IllegalArgumentException {
+        StringBuilder sb = new StringBuilder("{");
+        String sep = "";
+        for (Location l: locations) {
+            if (l instanceof StandardLocation || l instanceof PathLocation) {
+                sb.append(sep);
+                sb.append(l.getName());
+                sep = ",";
+            } else
+                throw new IllegalArgumentException(l.toString());
+        }
+        sb.append("{");
+        String name = sb.toString();
+
+        Location result = locationCache.get(name);
+        if (result == null) {
+            Path p = paths.new Path();
+            for (Location l: locations) {
+                if (l instanceof StandardLocation) {
+                    if (hasLocation(l)) {
+                        Set<JavaFileObject.Kind> kinds = allKinds;
+                        switch ((StandardLocation) l) {
+                            case CLASS_PATH:
+                                kinds = (hasLocation(SOURCE_PATH) ? noSourceKind : allKinds);
+                                break;
+                            case SOURCE_OUTPUT:
+                            case SOURCE_PATH:
+                                kinds = noClassKind;
+                                break;
+                            case ANNOTATION_PROCESSOR_PATH:
+                            case PLATFORM_CLASS_PATH:
+                            case CLASS_OUTPUT:
+                                kinds = noSourceKind;
+                                break;
+                        }
+                        p.addAll(getEntriesForLocation(l), kinds);
+                    }
+                } else if (l instanceof PathLocation) {
+                    p.addAll(((PathLocation) l).path);
+                }
+            }
+            result = new PathLocation(p, name);
+            locationCache.put(name, result);
+        }
+
+//        System.err.println("JavacFileManager.join: " + toString(locations) + " = " + result);
+        return result;
+    }
+
+    // Get a location for all the containers named "tag" on given location
+    // Containers may be either directories or archive files.
+    private Location getModuleLocation(Location location, String tag) {
+        // TODO: should reject bad use when location is already a module location
+        // TODO: should honor location.isOutput()
+        String name = location.getName() + "[" + tag + "]";
+        Location result = locationCache.get(name);
+        if (result == null) {
+            Iterable<? extends PathEntry> pathEntries;
+            if (location instanceof StandardLocation)
+                pathEntries = getEntriesForLocation(location);
+            else if (location instanceof PathLocation)
+                pathEntries = ((PathLocation) location).path;
+            else
+                throw new IllegalArgumentException(location.getName());
+            Path p = paths.new Path();
+            if (pathEntries != null) {
+                for (PathEntry e: pathEntries) {
+                    File dir = new File(e.file, tag);
+                    if (dir.exists() && dir.isDirectory() || location.isOutputLocation())
+                        p.add(paths.new PathEntry(dir, e.kinds));
+                    else {
+                        File jar = new File(e.file, tag + ".jar");
+                        if (jar.exists() && jar.isFile())
+                            p.add(paths.new PathEntry(dir, e.kinds));
+                    }
+                }
+            }
+            result = new PathLocation(p, name);
+            locationCache.put(name, result);
+        }
+        return result;
+    }
+
+    private <T> String toString(Iterable<T> items) {
+        ArrayList<T> list = new ArrayList<T>();
+        for (T t: items)
+            list.add(t);
+        return list.toString();
+    }
+
+    private boolean isArchive(File f) {
+        String name = f.getName();
+        String extn = name.substring(name.lastIndexOf(".")).toLowerCase(); // safe if not found
+        return archiveExtns.contains(extn);
+    }
+
+    private static final Set<String> archiveExtns = new HashSet<String>(Arrays.asList(".jar"));
+
+    private static Set<JavaFileObject.Kind> allKinds, noSourceKind, noClassKind;
+    static {
+        allKinds = EnumSet.allOf(JavaFileObject.Kind.class);
+        noSourceKind = EnumSet.allOf(JavaFileObject.Kind.class);
+        noSourceKind.remove(JavaFileObject.Kind.SOURCE);
+        noClassKind = EnumSet.allOf(JavaFileObject.Kind.class);
+        noClassKind.remove(JavaFileObject.Kind.CLASS);
+    }
+
+
     /**
      * An archive provides a flat directory structure of a ZipFile by
      * mapping directory names to lists of files (basenames).
@@ -799,14 +991,18 @@
         nullCheck(packageName);
         nullCheck(kinds);
 
-        Iterable<? extends File> path = getLocation(location);
-        if (path == null)
+        Iterable<? extends PathEntry> entries = getEntriesForLocation(location);
+        if (entries == null)
             return List.nil();
         RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
         ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
 
-        for (File directory : path)
-            listDirectory(directory, subdirectory, kinds, recurse, results);
+        for (PathEntry e: entries) {
+            Set<JavaFileObject.Kind> s = EnumSet.copyOf(kinds);
+            s.retainAll(e.kinds);
+            if (!s.isEmpty())
+                listDirectory(e.file, subdirectory, s, recurse, results);
+        }
 
         return results.toList();
     }
@@ -883,7 +1079,7 @@
         nullCheck(kind);
         if (!sourceOrClass.contains(kind))
             throw new IllegalArgumentException("Invalid kind " + kind);
-        return getFileForInput(location, RelativeFile.forClass(className, kind));
+        return getFileForInput(location, RelativeFile.forClass(className, kind), kind);
     }
 
     public FileObject getFileForInput(Location location,
@@ -899,15 +1095,28 @@
         RelativeFile name = packageName.length() == 0
             ? new RelativeFile(relativeName)
             : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
-        return getFileForInput(location, name);
+        return getFileForInput(location, name, getKindForName(name.path));
     }
 
-    private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException {
-        Iterable<? extends File> path = getLocation(location);
-        if (path == null)
+    private JavaFileObject.Kind getKindForName(String name) {
+        for (JavaFileObject.Kind k: JavaFileObject.Kind.values()) {
+            if (k != JavaFileObject.Kind.OTHER && name.endsWith(k.extension)) {
+                return k;
+            }
+        }
+        return JavaFileObject.Kind.OTHER;
+    }
+
+    private JavaFileObject getFileForInput(Location location, RelativeFile name,
+                JavaFileObject.Kind kind) throws IOException {
+        Iterable<? extends PathEntry> entries = getEntriesForLocation(location);
+        if (entries == null)
             return null;
 
-        for (File dir: path) {
+        for (PathEntry e: entries) {
+            if (kind != null && !e.kinds.contains(kind))
+                continue;
+            File dir = e.file;
             if (dir.isDirectory()) {
                 File f = name.getFile(dir);
                 if (f.exists())
@@ -917,7 +1126,6 @@
                 if (a.contains(name)) {
                     return a.getFileObject(name.dirname(), name.basename());
                 }
-
             }
         }
 
@@ -975,12 +1183,15 @@
         } else if (location == SOURCE_OUTPUT) {
             dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
         } else {
-            Iterable<? extends File> path = paths.getPathForLocation(location);
             dir = null;
-            for (File f: path) {
-                dir = f;
-                break;
+            Iterable<? extends PathEntry> path = getEntriesForLocation(location);
+            if (path != null) {
+                for (PathEntry e: path) {
+                    dir = e.file;
+                    break;
+                }
             }
+            //System.err.println("JavacFileManager.getFileForOutput location:" + location + " path:" + toString(path) + " dir:" + dir);
         }
 
         File file = fileName.getFile(dir); // null-safe
@@ -1047,15 +1258,71 @@
         return new File(arg);
     }
 
-    public Iterable<? extends File> getLocation(Location location) {
+    public Iterable<File> getLocation(Location location) {
         nullCheck(location);
         paths.lazy();
+
         if (location == CLASS_OUTPUT) {
-            return (getClassOutDir() == null ? null : List.of(getClassOutDir()));
-        } else if (location == SOURCE_OUTPUT) {
-            return (getSourceOutDir() == null ? null : List.of(getSourceOutDir()));
-        } else
-            return paths.getPathForLocation(location);
+            File dir = getClassOutDir();
+            return (dir == null ? null : List.of(dir));
+        }
+
+        if (location == SOURCE_OUTPUT) {
+            File dir = getSourceOutDir();
+            return (dir == null ? null : List.of(dir));
+        }
+
+
+        final Iterable<? extends PathEntry> entries;
+        if (location instanceof PathLocation)
+            entries = ((PathLocation) location).path;
+        else
+            entries = paths.getPathForLocation(location);
+
+        if (entries == null)
+            return null;
+
+        // wrap the natural PathEntry iterator with one that just returns the file values
+        return new Iterable<File>() {
+            public Iterator<File> iterator() {
+                return new Iterator<File>() {
+                    public boolean hasNext() {
+                        return iter.hasNext();
+                    }
+
+                    public File next() {
+                        return iter.next().file;
+                    }
+
+                    public void remove() {
+                        iter.remove();
+                    }
+
+                    final Iterator<? extends PathEntry> iter = entries.iterator();
+                };
+            }
+        };
+    }
+
+    Iterable<PathEntry> getEntriesForLocation(Location location) {
+        nullCheck(location);
+
+        if (location instanceof PathLocation)
+            return ((PathLocation) location).path;
+
+        paths.lazy();
+
+        if (location == CLASS_OUTPUT) {
+            File dir = getClassOutDir();
+            return (dir == null ? null : List.of(paths.new PathEntry(dir)));
+        }
+
+        if (location == SOURCE_OUTPUT) {
+            File dir = getSourceOutDir();
+            return (dir == null ? null : List.of(paths.new PathEntry(dir)));
+        }
+
+        return paths.getPathForLocation(location);
     }
 
     private File getClassOutDir() {
--- a/src/share/classes/com/sun/tools/javac/file/Paths.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/file/Paths.java	Fri Nov 06 13:20:18 2009 -0800
@@ -27,15 +27,16 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.zip.ZipFile;
 import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.code.Lint;
 import com.sun.tools.javac.util.Context;
@@ -131,6 +132,8 @@
                 p = computeAnnotationProcessorPath();
             else if (location == SOURCE_PATH)
                 p = computeSourcePath();
+            else if (location == MODULE_PATH)
+                p = computeModulePath();
             else
                 // no defaults for other paths
                 p = null;
@@ -154,22 +157,6 @@
         }
     }
 
-    public Collection<File> bootClassPath() {
-        lazy();
-        return Collections.unmodifiableCollection(getPathForLocation(PLATFORM_CLASS_PATH));
-    }
-    public Collection<File> userClassPath() {
-        lazy();
-        return Collections.unmodifiableCollection(getPathForLocation(CLASS_PATH));
-    }
-    public Collection<File> sourcePath() {
-        lazy();
-        Path p = getPathForLocation(SOURCE_PATH);
-        return p == null || p.size() == 0
-            ? null
-            : Collections.unmodifiableCollection(p);
-    }
-
     boolean isBootClassPathRtJar(File file) {
         return file.equals(bootClassPathRtJar);
     }
@@ -208,11 +195,84 @@
         return entries;
     }
 
-    private class Path extends LinkedHashSet<File> {
+    static class PathLocation implements Location {
+        PathLocation(Path p) {
+            path = p;
+            name = "pathLocation#" + (count++) + p;
+        }
+
+        PathLocation(Path p, String name) {
+            path = p;
+            this.name = name;
+        }
+
+        final Path path;
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isOutputLocation() {
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return getName();
+        }
+
+        final String name;
+        static int count;
+    }
+
+    class PathEntry {
+        PathEntry(File file) {
+            this(file, allKinds);
+        }
+
+        PathEntry(File file, Set<JavaFileObject.Kind> kinds) {
+            file.getClass(); // null check
+            kinds.getClass(); // null check
+            this.file = file;
+            this.canonFile = fsInfo.getCanonicalFile(file);
+            this.kinds = kinds;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other)
+                return true;
+            if (!(other instanceof PathEntry))
+                return false;
+            PathEntry o = (PathEntry) other;
+            return canonFile.equals(o.canonFile) && kinds.equals(o.kinds);
+        }
+
+        @Override
+        public int hashCode() {
+            return canonFile.hashCode() + kinds.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            if (kinds.equals(allKinds))
+                return file.getPath();
+            else
+                return "" + file + kinds;
+        }
+
+        final File file;
+        final File canonFile;
+        final Set<JavaFileObject.Kind> kinds;
+    }
+
+    private static final Set<JavaFileObject.Kind> allKinds =
+                    EnumSet.allOf(JavaFileObject.Kind.class);
+
+    class Path extends LinkedHashSet<PathEntry> {
         private static final long serialVersionUID = 0;
 
         private boolean expandJarClassPaths = false;
-        private Set<File> canonicalValues = new HashSet<File>();
 
         public Path expandJarClassPaths(boolean x) {
             expandJarClassPaths = x;
@@ -227,8 +287,18 @@
             return this;
         }
 
-        public Path() { super(); }
+        /** Notional set of acceptable file kinds for this type of path entry. */
+        private Set<JavaFileObject.Kind> acceptedKinds = EnumSet.allOf(JavaFileObject.Kind.class);
 
+        public Path acceptKinds(Set<JavaFileObject.Kind> kinds) {
+            acceptedKinds = kinds;
+            return this;
+        }
+
+        /** Add all the jar files found in one or more directories.
+         *  @param dirs one or more directories separated by path separator char
+         *  @param whether to generate a warning if a given directory does not exist
+         */
         public Path addDirectories(String dirs, boolean warn) {
             if (dirs != null)
                 for (File dir : getPathEntries(dirs))
@@ -236,10 +306,18 @@
             return this;
         }
 
+        /** Add all the jar files found in one or more directories.
+         *  Warnings about non-existent directories are given iff Paths.warn is set.
+         *  @param dirs one or more directories separated by path separator char
+         */
         public Path addDirectories(String dirs) {
             return addDirectories(dirs, warn);
         }
 
+        /** Add all the jar files found in a directory.
+         *  @param dirs one or more directories separated by path separator char
+         *  @param whether to generate a warning if a given directory does not exist
+         */
         private void addDirectory(File dir, boolean warn) {
             if (!dir.isDirectory()) {
                 if (warn)
@@ -257,6 +335,10 @@
             }
         }
 
+        /** Add directories and archive files.
+         *  @param files one or more directories and archive files separated by path separator char
+         *  @param whether to generate a warning if a given entry does not exist
+         */
         public Path addFiles(String files, boolean warn) {
             if (files != null)
                 for (File file : getPathEntries(files, emptyPathDefault))
@@ -264,13 +346,21 @@
             return this;
         }
 
+        /** Add directories and archive files.
+         *  Warnings about non-existent directories are given iff Paths.warn is set.
+         *  @param files one or more directories and archive files separated by path separator char
+         */
         public Path addFiles(String files) {
             return addFiles(files, warn);
         }
 
+        /** Add a directory or archive file.
+         *  @param directory or archive file to be added
+         *  @param whether to generate a warning if the file does not exist
+         */
         public void addFile(File file, boolean warn) {
-            File canonFile = fsInfo.getCanonicalFile(file);
-            if (contains(file) || canonicalValues.contains(canonFile)) {
+            PathEntry entry = new PathEntry(file);
+            if (contains(entry)) {
                 /* Discard duplicates and avoid infinite recursion */
                 return;
             }
@@ -300,8 +390,7 @@
 
             /* Now what we have left is either a directory or a file name
                confirming to archive naming convention */
-            super.add(file);
-            canonicalValues.add(canonFile);
+            super.add(entry);
 
             if (expandJarClassPaths && fsInfo.exists(file) && fsInfo.isFile(file))
                 addJarClassPath(file, warn);
@@ -320,6 +409,19 @@
                 log.error("error.reading.file", jarFile, e.getLocalizedMessage());
             }
         }
+
+        void addAll(Iterable<PathEntry> entries, Set<JavaFileObject.Kind> kinds) {
+            for (PathEntry e: entries) {
+                if (kinds.containsAll(e.kinds))
+                    add(e);
+                else {
+                    Set<JavaFileObject.Kind> k = EnumSet.copyOf(kinds);
+                    k.retainAll(e.kinds);
+                    if (!k.isEmpty())
+                        add(new PathEntry(e.file, k));
+                }
+            }
+        }
     }
 
     private Path computeBootClassPath() {
@@ -388,6 +490,14 @@
         return new Path().addFiles(sourcePathArg);
     }
 
+    private Path computeModulePath() {
+        String modulePathArg = options.get(MODULEPATH);
+        if (modulePathArg == null)
+            return null;
+
+        return new Path().addFiles(modulePathArg);
+    }
+
     private Path computeAnnotationProcessorPath() {
         String processorPathArg = options.get(PROCESSORPATH);
         if (processorPathArg == null)
@@ -399,7 +509,7 @@
     /** The actual effective locations searched for sources */
     private Path sourceSearchPath;
 
-    public Collection<File> sourceSearchPath() {
+    Collection<PathEntry> sourceSearchPath() {
         if (sourceSearchPath == null) {
             lazy();
             Path sourcePath = getPathForLocation(SOURCE_PATH);
@@ -412,7 +522,7 @@
     /** The actual effective locations searched for classes */
     private Path classSearchPath;
 
-    public Collection<File> classSearchPath() {
+    Collection<PathEntry> classSearchPath() {
         if (classSearchPath == null) {
             lazy();
             Path bootClassPath = getPathForLocation(PLATFORM_CLASS_PATH);
@@ -427,7 +537,7 @@
     /** The actual effective locations for non-source, non-class files */
     private Path otherSearchPath;
 
-    Collection<File> otherSearchPath() {
+    Collection<PathEntry> otherSearchPath() {
         if (otherSearchPath == null) {
             lazy();
             Path userClassPath = getPathForLocation(CLASS_PATH);
--- a/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java	Fri Nov 06 13:20:18 2009 -0800
@@ -39,6 +39,7 @@
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.CharsetDecoder;
+import java.util.Arrays;
 import javax.tools.JavaFileObject;
 
 /**
@@ -167,6 +168,25 @@
         return null;
     }
 
+    protected String inferModuleTag(String pkgName) {
+        File fn = file.getAbsoluteFile();
+        //System.err.println("RegularFileObject.inferModuleTag.args " + fn + " '" + pkgName + "'");
+        fn = fn.getParentFile();
+        if (pkgName.length() > 0) {
+            String[] pn = pkgName.replace('/', '.').split("\\.");
+            //System.err.println("RegularFileObject.inferModuleTag.pn " + Arrays.asList(pn) + " " + pn.length);
+            for (int i = pn.length - 1; i >= 0; i--) {
+                String n = fn.getName();
+                if (n.equalsIgnoreCase(pn[i]))
+                    fn = fn.getParentFile();
+                else
+                    return null;
+            }
+        }
+        //System.err.println("RegularFileObject.inferModuleTag.result " + (fn == null ? null : fn.getName()));
+        return (fn == null ? null : fn.getName());
+    }
+
     @Override
     public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) {
         cn.getClass();
--- a/src/share/classes/com/sun/tools/javac/file/ZipArchive.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/file/ZipArchive.java	Fri Nov 06 13:20:18 2009 -0800
@@ -250,6 +250,12 @@
             String entryName = entry.getName();
             return removeExtension(entryName).replace('/', '.');
         }
+        
+        @Override
+        protected String inferModuleTag(String binaryName) {
+            File zf = new File(zarch.zfile.getName());
+            return removeExtension(zf.getName());
+        }
 
         @Override
         public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
--- a/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java	Fri Nov 06 13:20:18 2009 -0800
@@ -248,6 +248,9 @@
             else
                 return entry.getName();
         }
+        protected String inferModuleTag(String binaryName) {
+            return removeExtension(zfIndex.getZipFile().getName());
+        }
     }
 
 }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassFile.java	Fri Nov 06 13:20:18 2009 -0800
@@ -25,6 +25,11 @@
 
 package com.sun.tools.javac.jvm;
 
+import java.util.Locale;
+import javax.lang.model.element.ModuleElement;
+
+import com.sun.tools.javac.api.Formattable;
+import com.sun.tools.javac.api.Messages;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.util.Name;
 
@@ -80,6 +85,7 @@
     public final static int CONSTANT_Methodref = 10;
     public final static int CONSTANT_InterfaceMethodref = 11;
     public final static int CONSTANT_NameandType = 12;
+    public final static int CONSTANT_ModuleId = 13;
 
     public final static int MAX_PARAMETERS = 0xff;
     public final static int MAX_DIMENSIONS = 0xff;
@@ -170,4 +176,53 @@
             return name.hashCode() * type.hashCode();
         }
     }
+
+    // move to top level in code or jvm?
+    public static class ModuleId implements ModuleElement.ModuleId, Formattable {
+        public final Name name;
+        public final Name version;
+
+        public ModuleId(Name name, Name version) {
+            this.name = name;
+            this.version = version;
+        }
+
+        public CharSequence getName() {
+            return name;
+        }
+
+        public CharSequence getVersion() {
+            return version;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            return
+                other instanceof ModuleId &&
+                name == ((ModuleId) other).name &&
+                version.equals(((ModuleId) other).version);
+        }
+
+        @Override
+        public int hashCode() {
+            if (version == null)
+                return name.hashCode();
+            else
+                return name.hashCode() * version.hashCode();
+        }
+
+        @Override // for debugging
+        public String toString() {
+            return "ModuleId[" + name + (version == null ? "" : "@" + version) + "]";
+        }
+
+        @Override // for use in diagnostics
+        public String toString(Locale locale, Messages messages) {
+            return (version == null ? name.toString() : name + "@" + version);
+        }
+
+        public String getKind() {
+            return "ModuleId";
+        }
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Nov 06 13:20:18 2009 -0800
@@ -32,6 +32,7 @@
 import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 import javax.lang.model.SourceVersion;
@@ -100,6 +101,10 @@
      */
     boolean allowAnnotations;
 
+    /** Switch: allow modules
+     */
+    boolean allowModules;
+
     /** Switch: preserve parameter names from the variable table.
      */
     public boolean saveParameterNames;
@@ -261,6 +266,7 @@
         allowGenerics    = source.allowGenerics();
         allowVarargs     = source.allowVarargs();
         allowAnnotations = source.allowAnnotations();
+        allowModules     = source.allowModules();
         saveParameterNames = options.get("save-parameter-names") != null;
         cacheCompletionFailure = options.get("dev") == null;
         preferSource = "source".equals(options.get("-Xprefer"));
@@ -419,6 +425,7 @@
             case CONSTANT_NameandType:
             case CONSTANT_Integer:
             case CONSTANT_Float:
+            case CONSTANT_ModuleId:
                 bp = bp + 4;
                 break;
             case CONSTANT_Long:
@@ -487,6 +494,11 @@
         case CONSTANT_Double:
             poolObj[i] = new Double(getDouble(index + 1));
             break;
+        case CONSTANT_ModuleId:
+            poolObj[i] = new ModuleId(
+                readInternalName(getChar(index + 1)),
+                readName(getChar(index + 3)));
+            break;
         default:
             throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
         }
@@ -535,6 +547,29 @@
         return (Name) (readPool(i));
     }
 
+    /** Read module id.
+     */
+    ModuleId readModuleId(int i) {
+        return (ModuleId) (readPool(i));
+    }
+
+    Name readInternalName(int i) {
+        int index = poolIdx[i];
+        return names.fromUtf(internalize(buf, index + 3, getChar(index + 1)));
+    }
+
+    /** Read module name.
+     * The module name is in a CONSTANT_Class_info, but we don't want to
+     * enter a class for it, so can't use readClassSymbol.
+     */
+    Name readModuleInfoName(int i) {
+        int index = poolIdx[i];
+        assert index != 0;
+        byte tag = buf[index];
+        assert tag == CONSTANT_Class;
+        return readInternalName(getChar(index+1));
+    }
+
 /************************************************************************
  * Reading Types
  ***********************************************************************/
@@ -1085,6 +1120,75 @@
                 }
             },
 
+            //  v51 module attributes
+
+            new AttributeReader(names.Module, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
+                @Override
+                boolean accepts(AttributeKind kind) {
+                    return super.accepts(kind) && allowModules;
+                }
+                void read(Symbol sym, int attrLen) {
+                    if (sym.kind == TYP && sym.owner.kind == MDL) {
+                        ModuleSymbol msym = (ModuleSymbol) sym.owner;
+                        ModuleId mid = readModuleId(nextChar());
+                        msym.name = msym.fullname = mid.name;
+                        msym.version = mid.version;
+                    }
+                }
+            },
+
+            new AttributeReader(names.ModulePermits, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
+                @Override
+                boolean accepts(AttributeKind kind) {
+                    return super.accepts(kind) && allowModules;
+                }
+                void read(Symbol sym, int attrLen) {
+                    if (sym.kind == TYP && sym.owner.kind == MDL) {
+                        ModuleSymbol msym = (ModuleSymbol) sym.owner;
+                        int num = nextChar();
+                        for (int i = 0; i < num; i++)
+                            msym.permits.append(readName(nextChar()));
+                    }
+                }
+            },
+
+            new AttributeReader(names.ModuleProvides, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
+                @Override
+                boolean accepts(AttributeKind kind) {
+                    return super.accepts(kind) && allowModules;
+                }
+                void read(Symbol sym, int attrLen) {
+                    if (sym.kind == TYP && sym.owner.kind == MDL) {
+                        ModuleSymbol msym = (ModuleSymbol) sym.owner;
+                        int num = nextChar();
+                        for (int i = 0; i < num; i++)
+                            msym.provides.append(readModuleId(nextChar()));
+                    }
+                }
+            },
+
+            new AttributeReader(names.ModuleRequires, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
+                @Override
+                boolean accepts(AttributeKind kind) {
+                    return super.accepts(kind) && allowModules;
+                }
+                void read(Symbol sym, int attrLen) {
+                    if (sym.kind == TYP && sym.owner.kind == MDL) {
+                        ModuleSymbol msym = (ModuleSymbol) sym.owner;
+                        int numRequires = nextChar();
+                        for (int r = 0; r < numRequires; r++) {
+                            ModuleId id = readModuleId(nextChar());
+                            ListBuffer<Name> flags = new ListBuffer<Name>();
+                            int numFlags = nextChar();
+                            for (int f = 0; f < numFlags; f++) {
+                                flags.append(readName(nextChar()));
+                            }
+                            msym.requires.put(id, new ModuleRequires(id, flags.toList()));
+                        }
+                    }
+                }
+            },
+
             // v51 attributes
             new AttributeReader(names.RuntimeVisibleTypeAnnotations, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
                 void read(Symbol sym, int attrLen) {
@@ -1992,11 +2096,20 @@
         long flags = adjustClassFlags(nextChar());
         if (c.owner.kind == PCK) c.flags_field = flags;
 
-        // read own class name and check that it matches
-        ClassSymbol self = readClassSymbol(nextChar());
-        if (c != self)
-            throw badClassFile("class.file.wrong.class",
-                               self.flatname);
+        if (c.owner.kind == MDL) {
+            //System.err.println("ClassReader.readClass getModuleInfoName");
+            c.fullname = c.flatname = readModuleInfoName(nextChar());
+            c.name = Convert.shortName(c.fullname);
+            assert c.name == names.module_info;
+        } else {
+            // read own class name and check that it matches
+            ClassSymbol self = readClassSymbol(nextChar());
+            if (c != self) {
+                //System.err.println("ClassReader.readClass c=" + c + " self=" + self);
+                throw badClassFile("class.file.wrong.class",
+                                   self.flatname);
+            }
+        }
 
         // class attributes must be read before class
         // skip ahead to read class attributes
@@ -2233,6 +2346,16 @@
             } catch (IOException ex) {
                 throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);
             }
+        } else if (sym.kind == MDL) {
+            //System.err.println("ClassReader.complete module " + sym + " " + sym.name);
+            ModuleSymbol msym = (ModuleSymbol) sym;
+            msym.permits = new ListBuffer<Name>();
+            msym.provides = new ListBuffer<ModuleId>();
+            msym.requires = new LinkedHashMap<ModuleId,ModuleRequires>();
+            msym.module_info.members_field = new Scope(sym); // or Scope.empty?
+            fillIn(msym.module_info);
+            assert msym.name != null;
+            //System.err.println("ClassReader.completed module " + sym + " " + sym.name);
         }
         if (!filling && !suppressFlush)
             annotate.flush(); // finish attaching annotations
@@ -2444,7 +2567,9 @@
      *         (2) we have one of the other kind, and the given class file
      *             is older.
      */
-    protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
+    protected void includeClassFile(PackageSymbol p, JavaFileObject file, Name simpleName) {
+        boolean isPackageInfo = simpleName == names.package_info;
+
         if ((p.flags_field & EXISTS) == 0)
             for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
                 q.flags_field |= EXISTS;
@@ -2454,18 +2579,14 @@
             seen = CLASS_SEEN;
         else
             seen = SOURCE_SEEN;
-        String binaryName = fileManager.inferBinaryName(currentLoc, file);
-        int lastDot = binaryName.lastIndexOf(".");
-        Name classname = names.fromString(binaryName.substring(lastDot + 1));
-        boolean isPkgInfo = classname == names.package_info;
-        ClassSymbol c = isPkgInfo
-            ? p.package_info
-            : (ClassSymbol) p.members_field.lookup(classname).sym;
+        ClassSymbol c =
+            isPackageInfo ? p.package_info
+            : (ClassSymbol) p.members_field.lookup(simpleName).sym;
         if (c == null) {
-            c = enterClass(classname, p);
+            c = enterClass(simpleName, p);
             if (c.classfile == null) // only update the file if's it's newly created
                 c.classfile = file;
-            if (isPkgInfo) {
+            if (isPackageInfo) {
                 p.package_info = c;
             } else {
                 if (c.owner == p)  // it might be an inner class
@@ -2486,7 +2607,7 @@
      *  file or a class file when both are present.  May be overridden
      *  by subclasses.
      */
-    protected JavaFileObject preferredFileObject(JavaFileObject a,
+    public JavaFileObject preferredFileObject(JavaFileObject a,
                                            JavaFileObject b) {
 
         if (preferSource)
@@ -2513,10 +2634,14 @@
     protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) {
     }
 
-    protected Location currentLoc; // FIXME
+    public void setPathLocation(Location pathLocation) {
+        this.pathLocation = pathLocation;
+    }
 
+    private Location pathLocation;
     private boolean verbosePath = true;
 
+
     /** Load directory of package into members scope.
      */
     private void fillIn(PackageSymbol p) throws IOException {
@@ -2531,6 +2656,16 @@
                                 EnumSet.of(JavaFileObject.Kind.CLASS),
                                 false));
 
+        if (pathLocation != null) {
+            //System.err.println("ClassReader.fillIn using pathLocation " + pathLocation);
+            fillIn(p, pathLocation,
+                    fileManager.list(pathLocation,
+                                    packageName,
+                                    EnumSet.allOf(JavaFileObject.Kind.class),
+                                    false));
+            return;
+        }
+
         Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds);
         classKinds.remove(JavaFileObject.Kind.SOURCE);
         boolean wantClassFiles = !classKinds.isEmpty();
@@ -2597,18 +2732,17 @@
                             Location location,
                             Iterable<JavaFileObject> files)
         {
-            currentLoc = location;
             for (JavaFileObject fo : files) {
                 switch (fo.getKind()) {
                 case CLASS:
                 case SOURCE: {
-                    // TODO pass binaryName to includeClassFile
-                    String binaryName = fileManager.inferBinaryName(currentLoc, fo);
+                    String binaryName = fileManager.inferBinaryName(location, fo);
                     String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
                     if (SourceVersion.isIdentifier(simpleName) ||
                         fo.getKind() == JavaFileObject.Kind.CLASS ||
-                        simpleName.equals("package-info"))
-                        includeClassFile(p, fo);
+                        simpleName.contentEquals(names.package_info)) {
+                        includeClassFile(p, fo, names.fromString(simpleName));
+                    }
                     break;
                 }
                 default:
@@ -2638,7 +2772,6 @@
         void complete(ClassSymbol sym)
             throws CompletionFailure;
     }
-
     /**
      * A subclass of JavaFileObject for the sourcefile attribute found in a classfile.
      * The attribute is only the last component of the original filename, so is unlikely
@@ -2721,6 +2854,11 @@
         protected String inferBinaryName(Iterable<? extends File> path) {
             return flatname.toString();
         }
+        
+        @Override
+        protected String inferModuleTag(String binaryName) {
+            return null;
+        }
 
         @Override
         public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Nov 06 13:20:18 2009 -0800
@@ -29,8 +29,8 @@
 import java.util.Set;
 import java.util.HashSet;
 
+import javax.tools.FileObject;
 import javax.tools.JavaFileManager;
-import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.code.*;
@@ -39,6 +39,9 @@
 import com.sun.tools.javac.file.BaseFileObject;
 import com.sun.tools.javac.util.*;
 
+import java.util.Map;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.ModuleFileManager;
 import static com.sun.tools.javac.code.BoundKind.*;
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
@@ -529,8 +532,18 @@
                 if (type.tag == CLASS) enterInner((ClassSymbol)type.tsym);
                 poolbuf.appendByte(CONSTANT_Class);
                 poolbuf.appendChar(pool.put(xClassName(type)));
+            } else if (value instanceof ModuleSymbol) {
+                ModuleSymbol sym = (ModuleSymbol) value;
+                poolbuf.appendByte(CONSTANT_ModuleId);
+                poolbuf.appendChar(pool.put(names.fromUtf(externalize(sym.flatName()))));
+                poolbuf.appendChar(sym.version == null ? 0 : pool.put(sym.version));
+            } else if (value instanceof ModuleId) {
+                ModuleId mid = (ModuleId)value;
+                poolbuf.appendByte(CONSTANT_ModuleId);
+                poolbuf.appendChar(pool.put(mid.name));
+                poolbuf.appendChar(mid.version == null ? 0 : pool.put(mid.version));
             } else {
-                assert false : "writePool " + value;
+                throw new AssertionError("writePool " + value);
             }
             i++;
         }
@@ -1006,6 +1019,76 @@
     }
 
 /**********************************************************************
+ * Writing module attributes
+ **********************************************************************/
+
+    /** Write the Module attribute if needed.
+     *  Returns the number of attributes written (0 or 1).
+     */
+    int writeModuleAttribute(ClassSymbol c) {
+        if (c.modle == null)
+            return 0;
+
+        int alenIdx = writeAttr(names.Module);
+        databuf.appendChar(pool.put(c.modle));
+        endAttr(alenIdx);
+        return 1;
+    }
+
+    int writeModuleMetadata(ModuleSymbol sym) {
+        int n = 0;
+
+        if (sym.provides.size() > 0) {
+            int alenIdx = writeAttr(names.ModuleProvides);
+            databuf.appendChar(sym.provides.size());
+            for (List<ModuleId> l = sym.provides.elems; l.nonEmpty(); l = l.tail) {
+                databuf.appendChar(pool.put(l.head));
+            }
+            endAttr(alenIdx);
+            n++;
+        }
+
+        if (sym.requires.size() > 0) {
+            int alenIdx = writeAttr(names.ModuleRequires);
+            databuf.appendChar(sym.requires.size());
+            for (Map.Entry<ModuleId,ModuleRequires> e: sym.requires.entrySet()) {
+                ModuleId m = e.getKey();
+                ModuleRequires mr = e.getValue();
+                databuf.appendChar(pool.put(m));
+                databuf.appendChar(mr.flags.size());
+                for (List<Name> l = mr.flags; l.nonEmpty(); l = l.tail) {
+                    databuf.appendChar(pool.put(l.head));
+                }
+            }
+            endAttr(alenIdx);
+            n++;
+        }
+
+        if (sym.permits.size() > 0) {
+            int alenIdx = writeAttr(names.ModulePermits);
+            databuf.appendChar(sym.permits.size());
+            for (Name name: sym.permits) {
+                databuf.appendChar(pool.put(name));
+            }
+            endAttr(alenIdx);
+            n++;
+        }
+
+        if (sym.className != null) {
+            int alenIdx = writeAttr(names.ModuleClass);
+            databuf.appendChar(pool.put(sym.className));
+            databuf.appendChar(sym.classFlags.size());
+            for (Name name: sym.classFlags) {
+                databuf.appendChar(pool.put(name));
+            }
+            endAttr(alenIdx);
+            n++;
+        }
+
+        return n;
+    }
+
+/**********************************************************************
  * Writing Objects
  **********************************************************************/
 
@@ -1022,6 +1105,7 @@
         if (c.type.tag != CLASS) return; // arrays
         if (pool != null && // pool might be null if called from xClassName
             c.owner.kind != PCK &&
+            c.owner.kind != MDL &&
             (innerClasses == null || !innerClasses.contains(c))) {
 //          log.errWriter.println("enter inner " + c);//DEBUG
             if (c.owner.kind == TYP) enterInner((ClassSymbol)c.owner);
@@ -1588,9 +1672,25 @@
     public JavaFileObject writeClass(ClassSymbol c)
         throws IOException, PoolOverflow, StringOverflow
     {
+        String name = (c.owner.kind == MDL ? c.name : c.flatname).toString();
+
+        Location outLocn;
+        if (fileManager instanceof ModuleFileManager && fileManager.hasLocation(CLASS_OUTPUT)) {
+            ModuleFileManager mfm = (ModuleFileManager) fileManager;
+            String pkgName = c.owner.kind == MDL ? "" : c.packge().fullname.toString();
+            try {
+                outLocn = mfm.getModuleLocation(CLASS_OUTPUT, c.sourcefile, pkgName);
+            } catch (IllegalArgumentException e) {
+                throw new AssertionError();
+            }
+        } else
+            // Note: when CLASS_OUTPUT is not set, getJavaFileForOutput will
+            // default to writing the output in the same directory as the sourcefile
+            outLocn = CLASS_OUTPUT;
+
         JavaFileObject outFile
-            = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
-                                               c.flatname.toString(),
+            = fileManager.getJavaFileForOutput(outLocn,
+                                               name,
                                                JavaFileObject.Kind.CLASS,
                                                c.sourcefile);
         OutputStream out = outFile.openOutputStream();
@@ -1709,6 +1809,10 @@
         acount += writeJavaAnnotations(c.getAnnotationMirrors());
         acount += writeTypeAnnotations(c.typeAnnotations);
         acount += writeEnclosingMethodAttribute(c);
+        if (c.owner.kind == MDL) {
+            acount += writeModuleAttribute(c);
+            acount += writeModuleMetadata(c.modle);
+        }
 
         poolbuf.appendInt(JAVA_MAGIC);
         poolbuf.appendChar(target.minorVersion);
--- a/src/share/classes/com/sun/tools/javac/jvm/Target.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/jvm/Target.java	Fri Nov 06 13:20:18 2009 -0800
@@ -306,4 +306,8 @@
     public boolean hasEnclosingMethodAttribute() {
         return compareTo(JDK1_5) >= 0 || this == JSR14;
     }
+
+    public boolean useModules() {
+        return compareTo(JDK1_7) >= 0;
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Nov 06 13:20:18 2009 -0800
@@ -575,8 +575,7 @@
      */
     protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
         long msec = now();
-        JCCompilationUnit tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(),
-                                      null, List.<JCTree>nil());
+        JCCompilationUnit tree = make.TopLevel(List.<JCTree>nil());
         if (content != null) {
             if (verbose) {
                 printVerbose("parsing.started", filename);
@@ -649,8 +648,7 @@
                 tree = (tree == null) ? make.Ident(names.fromString(s))
                                       : make.Select(tree, names.fromString(s));
             }
-            JCCompilationUnit toplevel =
-                make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
+            JCCompilationUnit toplevel = make.TopLevel(List.<JCTree>nil());
             toplevel.packge = syms.unnamedPackage;
             return attr.attribIdent(tree, toplevel);
         } finally {
@@ -708,11 +706,8 @@
     /** Complete compiling a source file that has been accessed
      *  by the class file reader.
      *  @param c          The class the source file of which needs to be compiled.
-     *  @param filename   The name of the source file.
-     *  @param f          An input stream that reads the source file.
      */
     public void complete(ClassSymbol c) throws CompletionFailure {
-//      System.err.println("completing " + c);//DEBUG
         if (completionFailureName == c.fullname) {
             throw new CompletionFailure(c, "user-selected completion failure by class name");
         }
@@ -724,7 +719,7 @@
             tree = parse(filename, filename.getCharContent(false));
         } catch (IOException e) {
             log.error("error.reading.file", filename, e);
-            tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil());
+            tree = make.TopLevel(List.<JCTree>nil());
         } finally {
             log.useSource(prev);
         }
@@ -742,17 +737,28 @@
         }
 
         if (enter.getEnv(c) == null) {
-            boolean isPkgInfo =
+            boolean isPackageInfo =
                 tree.sourcefile.isNameCompatible("package-info",
                                                  JavaFileObject.Kind.SOURCE);
-            if (isPkgInfo) {
+            boolean isModuleInfo =
+                tree.sourcefile.isNameCompatible("module-info",
+                                                 JavaFileObject.Kind.SOURCE);
+            if (isPackageInfo) {
                 if (enter.getEnv(tree.packge) == null) {
                     JCDiagnostic diag =
                         diagFactory.fragment("file.does.not.contain.package",
                                                  c.location());
                     throw reader.new BadClassFile(c, filename, diag);
                 }
-            } else {
+            } else if (isModuleInfo) {
+                if (enter.getEnv(tree.modle) == null) {
+                    JCDiagnostic diag =
+                        diagFactory.fragment("file.does.not.contain.module",
+                                                 c.location());
+                    throw reader.new BadClassFile(c, filename, diag);
+                }
+            }
+            else {
                 JCDiagnostic diag =
                         diagFactory.fragment("file.doesnt.contain.class",
                                             c.getQualifiedName());
@@ -791,6 +797,7 @@
     {
         if (processors != null && processors.iterator().hasNext())
             explicitAnnotationProcessingRequested = true;
+
         // as a JavaCompiler can only be used once, throw an exception if
         // it has been used before.
         if (hasBeenUsed)
@@ -1128,7 +1135,7 @@
                                   env.enclClass.sym.sourcefile :
                                   env.toplevel.sourcefile);
         try {
-            attr.attribClass(env.tree.pos(), env.enclClass.sym);
+            attr.analyze(env);
             compileStates.put(env, CompileState.ATTR);
         }
         finally {
@@ -1287,7 +1294,7 @@
             make.at(Position.FIRSTPOS);
             TreeMaker localMake = make.forToplevel(env.toplevel);
 
-            if (env.tree instanceof JCCompilationUnit) {
+            if (env.tree.getTag() == JCTree.TOPLEVEL || env.tree.getTag() == JCTree.MODULE) {
                 if (!(stubOutput || sourceOutput || printFlat)) {
                     if (shouldStop(CompileState.LOWER))
                         return;
--- a/src/share/classes/com/sun/tools/javac/main/Main.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/main/Main.java	Fri Nov 06 13:20:18 2009 -0800
@@ -242,6 +242,7 @@
             return null;
 
         String sourceString = options.get("-source");
+
         Source source = (sourceString != null)
             ? Source.lookup(sourceString)
             : Source.DEFAULT;
@@ -511,6 +512,7 @@
     public static void useRawMessages(boolean enable) {
         if (enable) {
             messages = new JavacMessages(javacBundleName) {
+                    @Override
                     public String getLocalizedString(String key, Object... args) {
                         return key;
                     }
--- a/src/share/classes/com/sun/tools/javac/main/OptionName.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/main/OptionName.java	Fri Nov 06 13:20:18 2009 -0800
@@ -51,6 +51,7 @@
     XBOOTCLASSPATH_PREPEND("-Xbootclasspath/p:"),
     XBOOTCLASSPATH_APPEND("-Xbootclasspath/a:"),
     XBOOTCLASSPATH("-Xbootclasspath:"),
+    MODULEPATH("-modulepath"),
     EXTDIRS("-extdirs"),
     DJAVA_EXT_DIRS("-Djava.ext.dirs="),
     ENDORSEDDIRS("-endorseddirs"),
--- a/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java	Fri Nov 06 13:20:18 2009 -0800
@@ -130,6 +130,7 @@
         XBOOTCLASSPATH_PREPEND,
         XBOOTCLASSPATH_APPEND,
         XBOOTCLASSPATH,
+        MODULEPATH,
         EXTDIRS,
         DJAVA_EXT_DIRS,
         ENDORSEDDIRS,
@@ -177,6 +178,7 @@
         XBOOTCLASSPATH_PREPEND,
         XBOOTCLASSPATH_APPEND,
         XBOOTCLASSPATH,
+        MODULEPATH,
         EXTDIRS,
         DJAVA_EXT_DIRS,
         ENDORSEDDIRS,
@@ -314,6 +316,15 @@
                 return super.process(options, "-bootclasspath", arg);
             }
         },
+        new Option(MODULEPATH,             "opt.arg.path",      "opt.modulepath") {
+            // TEMP HACK FOR JIGSAW TO AUTO-DEFAULT -source TO 7 WHEN -modulepath
+            // IS USED. REMOVE WHEN -source 7 IS THE DEFAULT
+            @Override
+            public boolean process(Options options, String option, String arg) {
+                options.put("jigsaw.source", "7");
+                return super.process(options, option, arg);
+            }
+        },
         new Option(EXTDIRS,                "opt.arg.dirs",      "opt.extdirs"),
         new XOption(DJAVA_EXT_DIRS,        "opt.arg.dirs",      "opt.extdirs") {
             @Override
@@ -588,6 +599,10 @@
                         helper.error("err.file.not.file", f);
                         return true;
                     }
+                    // TEMP HACK FOR JIGSAW TO AUTO-DEFAULT -source TO 7 WHEN
+                    // module-info.java USED. REMOVE WHEN -source 7 IS THE DEFAULT
+                    if (f.getName().equals("module-info.java"))
+                        options.put("jigsaw.source", "7");
                     helper.addFile(f);
                 }
                 else
--- a/src/share/classes/com/sun/tools/javac/model/JavacElements.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Nov 06 13:20:18 2009 -0800
@@ -224,8 +224,8 @@
         Symbol sym = cast(Symbol.class, e);
         class Vis extends JCTree.Visitor {
             List<JCAnnotation> result = null;
-            public void visitTopLevel(JCCompilationUnit tree) {
-                result = tree.packageAnnotations;
+            public void visitPackage(JCPackageDecl tree) {
+                result = tree.annots;
             }
             public void visitClassDef(JCClassDecl tree) {
                 result = tree.mods.annotations;
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Nov 06 13:20:18 2009 -0800
@@ -133,6 +133,8 @@
         this.allowAnnotations = source.allowAnnotations();
         this.allowDiamond = source.allowDiamond();
         this.allowTypeAnnotations = source.allowTypeAnnotations();
+        this.allowModules = source.allowModules();
+        this.allowImportsBeforePackage = source.allowImportsBeforePackage();
         this.keepDocComments = keepDocComments;
         if (keepDocComments)
             docComments = new HashMap<JCTree,String>();
@@ -181,6 +183,14 @@
      */
     boolean allowTypeAnnotations;
 
+    /** Switch: should we recognize modules?
+     */
+    boolean allowModules;
+
+    /** Switch: should we recognize import before package?
+     */
+    boolean allowImportsBeforePackage;
+
     /** Switch: should we keep docComments?
      */
     boolean keepDocComments;
@@ -478,7 +488,7 @@
             accept(IDENTIFIER);
             return names.error;
         }
-}
+    }
 
     /**
      * Qualident = Ident { DOT Ident }
@@ -494,6 +504,20 @@
     }
 
     /**
+     * Qualident = Ident { DOT Ident }
+     * (used when we've had to lookahead at the first identifier)
+     */
+    public JCExpression qualident(JCExpression head) {
+        JCExpression t = head;
+        while (S.token() == DOT) {
+            int pos = S.pos();
+            S.nextToken();
+            t = toP(F.at(pos).Select(t, ident()));
+        }
+        return t;
+    }
+
+    /**
      * Literal =
      *     INTLITERAL
      *   | LONGLITERAL
@@ -1642,7 +1666,7 @@
         JCClassDecl body = null;
         if (S.token() == LBRACE) {
             int pos = S.pos();
-            List<JCTree> defs = classOrInterfaceBody(names.empty, false);
+            List<JCTree> defs = classOrInterfaceBody(names.empty, CLASS);
             JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
             body = toP(F.at(pos).AnonymousClassDef(mods, defs));
         }
@@ -1729,7 +1753,7 @@
             case MONKEYS_AT:
             case FINAL: {
                 String dc = S.docComment();
-                JCModifiers mods = modifiersOpt();
+                JCModifiers mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
                 if (S.token() == INTERFACE ||
                     S.token() == CLASS ||
                     allowEnums && S.token() == ENUM) {
@@ -1746,13 +1770,13 @@
             }
             case ABSTRACT: case STRICTFP: {
                 String dc = S.docComment();
-                JCModifiers mods = modifiersOpt();
+                JCModifiers mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
                 stats.append(classOrInterfaceOrEnumDeclaration(mods, dc));
                 break;
             }
             case INTERFACE:
             case CLASS:
-                stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(),
+                stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.DISALLOWED),
                                                                S.docComment()));
                 break;
             case ENUM:
@@ -1760,7 +1784,7 @@
                 if (allowEnums && S.token() == ENUM) {
                     log.error(S.pos(), "local.enum");
                     stats.
-                        append(classOrInterfaceOrEnumDeclaration(modifiersOpt(),
+                        append(classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.DISALLOWED),
                                                                  S.docComment()));
                     break;
                 } else if (allowAsserts && S.token() == ASSERT) {
@@ -2066,7 +2090,7 @@
             JCExpression t = term(EXPR | TYPE);
             if ((lastmode & TYPE) != 0 &&
                 (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM))
-                return variableDeclarators(modifiersOpt(), t, stats).toList();
+                return variableDeclarators(modifiersOpt(ModuleModifierKind.DISALLOWED), t, stats).toList();
             else
                 return moreStatementExpressions(pos, t, stats).toList();
         }
@@ -2108,15 +2132,23 @@
         return List.convert(JCTypeAnnotation.class, annotations);
     }
 
+    enum ModuleModifierKind { DISALLOWED, LOOKAHEAD, ALLOWED };
+
     /** ModifiersOpt = { Modifier }
      *  Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
      *           | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
      *           | "@" Annotation
      */
-    JCModifiers modifiersOpt() {
-        return modifiersOpt(null);
+    JCModifiers modifiersOpt(ModuleModifierKind mmk) {
+        return modifiersOpt(mmk, null, null);
     }
-    JCModifiers modifiersOpt(JCModifiers partial) {
+
+    JCModifiers modifiersOpt(ModuleModifierKind mmk, Name constrName) {
+        return modifiersOpt(mmk, null, constrName);
+    }
+
+    @SuppressWarnings("fallthrough")
+    JCModifiers modifiersOpt(ModuleModifierKind mmk, JCModifiers partial, Name constrName) {
         long flags = (partial == null) ? 0 : partial.flags;
         if (S.deprecatedFlag()) {
             flags |= Flags.DEPRECATED;
@@ -2124,7 +2156,7 @@
         }
         ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
         if (partial != null) annotations.appendList(partial.annotations);
-        int pos = S.pos();
+        int pos = (partial != null ? partial.pos : S.pos());
         int lastPos = Position.NOPOS;
     loop:
         while (true) {
@@ -2142,20 +2174,56 @@
             case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
             case STRICTFP    : flag = Flags.STRICTFP; break;
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
+            case IDENTIFIER:
+                if (S.name() != names.module)
+                    break loop;
+                switch (mmk) {
+                    case DISALLOWED:
+                        break loop;
+                    case LOOKAHEAD: {
+                        if ((flags & (Flags.AccessFlags)) != 0)
+                            break loop;
+                        S.mark();
+                        try {
+                            S.nextToken();
+                            if (S.token() == IDENTIFIER) {
+                                Name ident = S.name();
+                                S.nextToken();
+                                switch (S.token()) {
+                                    case SEMI:
+                                    case EQ:
+                                    case LBRACKET:
+                                        break loop;
+                                    case LPAREN:
+                                        if (ident == constrName)
+                                            break;
+                                        break loop;
+                                }
+                            }
+                        } finally {
+                            S.reset();
+                        }
+                    }
+                    case ALLOWED:
+                        break;
+                }
+                flag = Flags.MODULE;
+                break;
             default: break loop;
             }
-            if ((flags & flag) != 0) log.error(S.pos(), "repeated.modifier");
+            if ((flags & flag) != 0)
+                log.error(S.pos(), "repeated.modifier");
             lastPos = S.pos();
             S.nextToken();
             if (flag == Flags.ANNOTATION) {
                 checkAnnotations();
                 if (S.token() != INTERFACE) {
                 JCAnnotation ann = annotation(lastPos, AnnotationKind.DEFAULT_ANNO);
-                // if first modifier is an annotation, set pos to annotation's.
-                if (flags == 0 && annotations.isEmpty())
-                    pos = ann.pos;
-                annotations.append(ann);
-                lastPos = ann.pos;
+                    // if first modifier is an annotation, set pos to annotation's.
+                    if (flags == 0 && annotations.isEmpty())
+                        pos = ann.pos;
+                    annotations.append(ann);
+                    lastPos = ann.pos;
                     flag = 0;
                 }
             }
@@ -2336,28 +2404,58 @@
         return toP(F.at(pos).VarDef(mods, name, type, null));
     }
 
-    /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
+    /** CompilationUnit =
+     *      {ImportDeclaration} [ModuleDeclaration]
+     *      [ { "@" Annotation } PACKAGE Qualident ";"]
+     *      {ImportDeclaration}
+     *      {TypeDeclaration}
      */
     public JCTree.JCCompilationUnit parseCompilationUnit() {
-        int pos = S.pos();
-        JCExpression pid = null;
+        ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
+        int cu_pos = S.pos();
+        boolean seenImport = false;
+
+        String toplevel_dc = S.docComment();
+
+        while (S.token() == IMPORT) {
+            defs.append(importDeclaration());
+            seenImport = true;
+        }
+
         String dc = S.docComment();
+
         JCModifiers mods = null;
-        List<JCAnnotation> packageAnnotations = List.nil();
-        if (S.token() == MONKEYS_AT)
-            mods = modifiersOpt();
+        if (S.token() == MONKEYS_AT)  {
+            mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
+        }
+
+        if (S.token() == IDENTIFIER && S.name() == names.module) {
+            defs.append(moduleDecl(mods, dc));
+            dc = null;
+        }
+
+        if (mods == null && S.token() == MONKEYS_AT) {
+            dc = S.docComment();
+            mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
+        }
 
         if (S.token() == PACKAGE) {
+            int pos = S.pos();
+            if (seenImport && !allowImportsBeforePackage)
+                log.error(pos, "imports.not.allowed.before.package.in.source", source.name);
+            List<JCAnnotation> annots = List.nil();
             if (mods != null) {
                 checkNoMods(mods.flags);
-                packageAnnotations = mods.annotations;
+                annots = mods.annotations;
                 mods = null;
+                dc = null;
             }
             S.nextToken();
-            pid = qualident();
+            JCExpression pid = qualident();
             accept(SEMI);
+            defs.append(toP(F.at(pos).Package(annots, pid)));
         }
-        ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
+
         boolean checkForImports = true;
         while (S.token() != EOF) {
             if (S.pos() <= errorEndPos) {
@@ -2369,17 +2467,19 @@
             if (checkForImports && mods == null && S.token() == IMPORT) {
                 defs.append(importDeclaration());
             } else {
-                JCTree def = typeDeclaration(mods);
+                JCTree def = typeDeclaration(mods, dc);
                 if (def instanceof JCExpressionStatement)
                     def = ((JCExpressionStatement)def).expr;
                 defs.append(def);
                 if (def instanceof JCClassDecl)
                     checkForImports = false;
                 mods = null;
+                dc = null;
             }
         }
-        JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList());
-        attach(toplevel, dc);
+
+        JCTree.JCCompilationUnit toplevel = F.at(cu_pos).TopLevel(defs.toList());
+        attach(toplevel, toplevel_dc);
         if (defs.elems.isEmpty())
             storeEnd(toplevel, S.prevEndPos());
         if (keepDocComments)
@@ -2389,6 +2489,152 @@
         return toplevel;
     }
 
+    /**
+     * ModuleDecl = { "@" Annotation } MODULE ModuleId [ ModuleProvides ] '{' { ModuleMetadata } '}'
+     * ModuleProvides = PROVIDES ModuleIdList
+     *
+     * called after MODULE has been seen
+     */
+    JCModuleDecl moduleDecl(JCModifiers mods, String dc) {
+        int pos = S.pos();
+        if (!allowModules)
+            log.error(pos, "modules.not.supported.in.source", source.name);
+        List<JCAnnotation> annots = List.nil();
+        if (mods != null) {
+            checkNoMods(mods.flags);
+            annots = mods.annotations;
+            mods = null;
+        }
+        S.nextToken();
+        JCModuleId mid = moduleId();
+        List<JCModuleId> provides = null;
+        List<JCModuleMetadata> metadataList = null;
+
+        if (S.token() == IDENTIFIER && S.name() == names.provides) {
+            S.nextToken();
+            provides = moduleIdList();
+        } else
+            provides = List.nil();
+        accept(LBRACE);
+        metadataList = moduleMetadataList();
+        accept(RBRACE);
+
+        JCModuleDecl result = toP(F.at(pos).Module(annots, mid, provides, metadataList));
+        attach(result, dc);
+        return result;
+    }
+
+    /**
+     * ModuleMetadataList = ModuleMetadata*
+     * ModuleMetadata = ModuleRequires | ModulePermits | ModuleProvides
+     * ModuleRequires = REQUIRES Identifier* ModuleId {',' ModuleId}
+     * ModulePermits  = PERMITS  QualifiedIdentifier {',' QualifiedIdentifier}
+     */
+    List<JCModuleMetadata> moduleMetadataList() {
+        ListBuffer<JCModuleMetadata> defs = new ListBuffer<JCModuleMetadata>();
+
+        while (S.token() == IDENTIFIER || S.token() == CLASS) {
+            int pos = S.pos();
+            if (S.token() == CLASS) {
+                S.nextToken();
+                ListBuffer<Name> flags = new ListBuffer<Name>();
+                JCExpression qualIdHead = null;
+                while (S.token() == IDENTIFIER) {
+                    int id_pos = S.pos();
+                    Name id = S.name();
+                    S.nextToken();
+                    if (S.token() == DOT || S.token() == SEMI) {
+                        qualIdHead = toP(F.at(id_pos).Ident(id));
+                        break;
+                    }
+                    flags.append(id);
+                }
+                if (qualIdHead == null) {
+                    log.error(pos, "class.id.expected");
+                } else {
+                    JCExpression qualId = qualident(qualIdHead);
+                    accept(SEMI);
+                    defs.append(toP(F.at(pos).ModuleClass(flags.toList(), qualId)));
+                }
+            } else if (S.name() == names.requires) {
+                ListBuffer<Name> flags = new ListBuffer<Name>();
+                List<JCModuleId> moduleIds;
+                S.nextToken();
+                JCExpression moduleIdHead = null;
+                while (S.token() == IDENTIFIER ||
+                        S.token().name != null && Character.isLetter(S.token().name.charAt(0))) {
+                    int id_pos = S.pos();
+                    Name id = S.name();
+                    S.nextToken();
+                    if (S.token() == DOT || S.token() == MONKEYS_AT || S.token() == COMMA || S.token() == SEMI) {
+                        moduleIdHead = toP(F.at(id_pos).Ident(id));
+                        break;
+                    }
+                    flags.append(id);
+                }
+                if (moduleIdHead == null) {
+                    log.error(pos, "module.id.expected");
+                } else {
+                    moduleIds = moduleIdList(moduleIdHead);
+                    accept(SEMI);
+                    defs.append(toP(F.at(pos).ModuleRequires(flags.toList(), moduleIds)));
+                }
+            } else if (S.name() == names.permits) {
+                S.nextToken();
+                List<JCExpression> qualIds = qualidentList();
+                accept(SEMI);
+                defs.append(toP(F.at(pos).ModulePermits(qualIds)));
+            } else
+                break;
+        }
+
+        return defs.toList();
+    }
+
+    /** ModuleIdList = ModuleId {"," ModuleId}
+     */
+    List<JCModuleId> moduleIdList() {
+        ListBuffer<JCModuleId> ts = new ListBuffer<JCModuleId>();
+        ts.append(moduleId());
+        while (S.token() == COMMA) {
+            S.nextToken();
+            ts.append(moduleId());
+        }
+        return ts.toList();
+    }
+
+    /** ModuleIdList = ModuleId {"," ModuleId}
+     *  used when we've peeked ahead at the first identifier
+     */
+    List<JCModuleId> moduleIdList(JCExpression head) {
+        ListBuffer<JCModuleId> ts = new ListBuffer<JCModuleId>();
+        ts.append(moduleId(head));
+        while (S.token() == COMMA) {
+            S.nextToken();
+            ts.append(moduleId());
+        }
+        return ts.toList();
+    }
+
+    JCModuleId moduleId() {
+        return moduleId(toP(F.at(S.pos()).Ident(ident())));
+    }
+
+    JCModuleId moduleId(JCExpression head) {
+        int pos = S.pos();
+        JCTree qualId = qualident(head);
+        Name version = null;
+        if (S.token() == MONKEYS_AT) {
+            S.nextToken();
+            if (S.token() == MODULEVERSIONLITERAL || S.token() == STRINGLITERAL) {
+                version = names.fromString(S.stringVal());
+            } else
+               log.error(pos, "modules.version.literal.expected");
+            S.nextToken();
+        }
+        return toP(F.at(pos).ModuleId(qualId, version));
+    }
+
     /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
      */
     JCTree importDeclaration() {
@@ -2419,14 +2665,17 @@
     /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration
      *                  | ";"
      */
-    JCTree typeDeclaration(JCModifiers mods) {
+    JCTree typeDeclaration(JCModifiers mods, String dc) {
         int pos = S.pos();
         if (mods == null && S.token() == SEMI) {
             S.nextToken();
             return toP(F.at(pos).Skip());
         } else {
-            String dc = S.docComment();
-            return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc);
+            if (mods == null) {
+                assert dc == null;
+                dc = S.docComment();
+            }
+            return classOrInterfaceOrEnumDeclaration(modifiersOpt(ModuleModifierKind.ALLOWED, mods, null), dc);
         }
     }
 
@@ -2496,7 +2745,7 @@
             S.nextToken();
             implementing = typeList();
         }
-        List<JCTree> defs = classOrInterfaceBody(name, false);
+        List<JCTree> defs = classOrInterfaceBody(name, CLASS);
         JCClassDecl result = toP(F.at(pos).ClassDef(
             mods, name, typarams, extending, implementing, defs));
         attach(result, dc);
@@ -2520,7 +2769,7 @@
             S.nextToken();
             extending = typeList();
         }
-        List<JCTree> defs = classOrInterfaceBody(name, true);
+        List<JCTree> defs = classOrInterfaceBody(name, INTERFACE);
         JCClassDecl result = toP(F.at(pos).ClassDef(
             mods, name, typarams, null, extending, defs));
         attach(result, dc);
@@ -2577,7 +2826,7 @@
             S.nextToken();
             while (S.token() != RBRACE && S.token() != EOF) {
                 defs.appendList(classOrInterfaceBodyDeclaration(enumName,
-                                                                false));
+                                                                ENUM));
                 if (S.pos() <= errorEndPos) {
                     // error recovery
                    skip(false, true, true, false);
@@ -2609,7 +2858,7 @@
         JCClassDecl body = null;
         if (S.token() == LBRACE) {
             JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC);
-            List<JCTree> defs = classOrInterfaceBody(names.empty, false);
+            List<JCTree> defs = classOrInterfaceBody(names.empty, CLASS);
             body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
         }
         if (args.isEmpty() && body == null)
@@ -2639,7 +2888,7 @@
     /** ClassBody     = "{" {ClassBodyDeclaration} "}"
      *  InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
      */
-    List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) {
+    List<JCTree> classOrInterfaceBody(Name className, Token encl) {
         accept(LBRACE);
         if (S.pos() <= errorEndPos) {
             // error recovery
@@ -2649,7 +2898,7 @@
         }
         ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
         while (S.token() != RBRACE && S.token() != EOF) {
-            defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
+            defs.appendList(classOrInterfaceBodyDeclaration(className, encl));
             if (S.pos() <= errorEndPos) {
                // error recovery
                skip(false, true, true, false);
@@ -2676,14 +2925,15 @@
      *    | ModifiersOpt Type Ident
      *      ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" )
      */
-    List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
+    List<JCTree> classOrInterfaceBodyDeclaration(Name className, Token encl) {
         if (S.token() == SEMI) {
             S.nextToken();
             return List.<JCTree>of(F.at(Position.NOPOS).Block(0, List.<JCStatement>nil()));
         } else {
+            boolean isInterface = (encl == INTERFACE);
             String dc = S.docComment();
             int pos = S.pos();
-            JCModifiers mods = modifiersOpt();
+            JCModifiers mods = modifiersOpt(ModuleModifierKind.LOOKAHEAD, (encl == CLASS ? className : null));
             if (S.token() == CLASS ||
                 S.token() == INTERFACE ||
                 allowEnums && S.token() == ENUM) {
@@ -2923,7 +3173,7 @@
     }
 
     JCModifiers optFinal(long flags) {
-        JCModifiers mods = modifiersOpt();
+        JCModifiers mods = modifiersOpt(ModuleModifierKind.DISALLOWED);
         checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
         mods.flags |= flags;
         return mods;
--- a/src/share/classes/com/sun/tools/javac/parser/Keywords.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/parser/Keywords.java	Fri Nov 06 13:20:18 2009 -0800
@@ -26,7 +26,6 @@
 package com.sun.tools.javac.parser;
 
 import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
 
@@ -51,12 +50,10 @@
         return instance;
     }
 
-    private final Log log;
     private final Names names;
 
     protected Keywords(Context context) {
         context.put(keywordsKey, this);
-        log = Log.instance(context);
         names = Names.instance(context);
 
         for (Token t : Token.values()) {
--- a/src/share/classes/com/sun/tools/javac/parser/Lexer.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/parser/Lexer.java	Fri Nov 06 13:20:18 2009 -0800
@@ -139,4 +139,15 @@
      * Sets the current token.
      */
     void token(Token token);
+
+    /**
+     * Very simple mark/reset support. At most one position may be marked.
+     */
+    void mark();
+
+    /**
+     * Reset the lexer back to the last marked position. No-op if no position
+     * has been set.
+     */
+    void reset();
 }
--- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Fri Nov 06 13:20:18 2009 -0800
@@ -89,6 +89,59 @@
         }
     }
 
+    static class Mark {
+        /** Save the observable state of scanner as updated by nextToken().
+         */
+        Mark(Scanner s) {
+            bp = s.bp;
+            ch = s.ch;
+            deprecatedFlag = s.deprecatedFlag;
+            docComment = s.docComment();
+            endPos = s.endPos;
+            errPos = s.errPos;
+            name = s.name;
+            pos = s.pos;
+            prevEndPos = s.prevEndPos;
+            radix = s.radix;
+            stringVal = s.stringVal();
+            token = s.token;
+        }
+
+        void apply(Scanner s) {
+            s.bp = bp;
+            s.ch = ch;
+            s.deprecatedFlag = deprecatedFlag;
+            // currently, there is no way to reset the docComment, but for the
+            // limited context for mark/reset this is probably not an issue
+            //s.docComment = docComment;
+            s.endPos = endPos;
+            s.errPos = errPos;
+            s.name = name;
+            s.pos = pos;
+            s.prevEndPos = prevEndPos;
+            s.radix = radix;
+            assert stringVal.length() < s.sbuf.length;
+            s.sp = stringVal.length();
+            for (int i = 0; i < s.sp; i++)
+                s.sbuf[i] = stringVal.charAt(i);
+            s.token = token;
+
+        }
+
+        final int bp;
+        final char ch;
+        final boolean deprecatedFlag;
+        final String docComment;
+        final int endPos;
+        final int errPos;
+        final Name name;
+        final int pos;
+        final int prevEndPos;
+        final int radix;
+        final String stringVal;
+        final Token token;
+    }
+
     /* Output variables; set by nextToken():
      */
 
@@ -162,6 +215,10 @@
      */
     private int unicodeConversionBp = -1;
 
+    /** The last marked position.
+     */
+    private Mark mark;
+
     /** The log to be used for error reporting.
      */
     private final Log log;
@@ -802,6 +859,35 @@
         return;
     }
 
+    private void scanModuleVersion() {
+        do {
+            putChar(ch);
+            scanChar();
+            switch (ch) {
+                case ' ': case '\t':
+                case FF: case CR: case LF:
+                case '\"': case '\'': case '\\':
+                case ',': case ';':
+                case EOI:
+                    token = MODULEVERSIONLITERAL;
+                    return;
+            }
+        } while(true);
+    }
+
+    /** Return true if ch can be part of an operator.
+     */
+    private boolean isModuleStart(char ch) {
+        switch (ch) {
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+        case '(': case '[': case '<': case '=': case '>':
+            return true;
+        default:
+            return false;
+        }
+    }
+
     /** The value of a literal token, recorded as a string.
      *  For integers, leading 0x and 'l' suffixes are suppressed.
      */
@@ -858,46 +944,54 @@
                     scanIdent();
                     return;
                 case '0':
-                    scanChar();
-                    if (ch == 'x' || ch == 'X') {
-                        scanChar();
-                        skipIllegalUnderscores();
-                        if (ch == '.') {
-                            scanHexFractionAndSuffix(false);
-                        } else if (digit(16) < 0) {
-                            lexError("invalid.hex.number");
-                        } else {
-                            scanNumber(16);
-                        }
-                    } else if (ch == 'b' || ch == 'B') {
-                        if (!allowBinaryLiterals) {
-                            lexError("unsupported.binary.lit", source.name);
-                            allowBinaryLiterals = true;
-                        }
+                    if (token == MONKEYS_AT) {
+                        scanModuleVersion();
+                    } else {
                         scanChar();
-                        skipIllegalUnderscores();
-                        if (digit(2) < 0) {
-                            lexError("invalid.binary.number");
-                        } else {
-                            scanNumber(2);
-                        }
-                    } else {
-                        putChar('0');
-                        if (ch == '_') {
-                            int savePos = bp;
-                            do {
-                                scanChar();
-                            } while (ch == '_');
-                            if (digit(10) < 0) {
-                                lexError(savePos, "illegal.underscore");
-                            }
-                        }
-                        scanNumber(8);
+			if (ch == 'x' || ch == 'X') {
+			    scanChar();
+			    skipIllegalUnderscores();
+			    if (ch == '.') {
+				scanHexFractionAndSuffix(false);
+			    } else if (digit(16) < 0) {
+				lexError("invalid.hex.number");
+			    } else {
+				scanNumber(16);
+			    }
+			} else if (ch == 'b' || ch == 'B') {
+			    if (!allowBinaryLiterals) {
+				lexError("unsupported.binary.lit", source.name);
+				allowBinaryLiterals = true;
+			    }
+			    scanChar();
+			    skipIllegalUnderscores();
+			    if (digit(2) < 0) {
+				lexError("invalid.binary.number");
+			    } else {
+				scanNumber(2);
+			    }
+			} else {
+			    putChar('0');
+			    if (ch == '_') {
+				int savePos = bp;
+				do {
+				    scanChar();
+				} while (ch == '_');
+				if (digit(10) < 0) {
+				    lexError(savePos, "illegal.underscore");
+				}
+			    }
+			    scanNumber(8);
+			}
                     }
                     return;
                 case '1': case '2': case '3': case '4':
                 case '5': case '6': case '7': case '8': case '9':
-                    scanNumber(10);
+                    if (token == MONKEYS_AT) {
+                        scanModuleVersion();
+                    } else {
+                        scanNumber(10);
+                    }
                     return;
                 case '.':
                     scanChar();
@@ -923,11 +1017,23 @@
                 case ';':
                     scanChar(); token = SEMI; return;
                 case '(':
-                    scanChar(); token = LPAREN; return;
+                    if (token == MONKEYS_AT) {
+                        scanModuleVersion();
+                    } else {
+                        scanChar();
+                        token = LPAREN;
+                    }
+                    return;
                 case ')':
                     scanChar(); token = RPAREN; return;
                 case '[':
-                    scanChar(); token = LBRACKET; return;
+                    if (token == MONKEYS_AT) {
+                        scanModuleVersion();
+                    } else {
+                        scanChar();
+                        token = LBRACKET;
+                    }
+                    return;
                 case ']':
                     scanChar(); token = RBRACKET; return;
                 case '{':
@@ -1028,7 +1134,9 @@
                     }
                     return;
                 default:
-                    if (isSpecial(ch)) {
+                    if (token == MONKEYS_AT && isModuleStart(ch)) {
+                        scanModuleVersion();
+                    } else if (isSpecial(ch)) {
                         scanOperator();
                     } else {
                         boolean isJavaIdentifierStart;
@@ -1227,4 +1335,13 @@
         return Position.makeLineMap(buf, buflen, false);
     }
 
+    public void mark() {
+        mark = new Mark(this);
+    }
+
+    public void reset() {
+        if (mark != null)
+            mark.apply(this);
+    }
+
 }
--- a/src/share/classes/com/sun/tools/javac/parser/Token.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/parser/Token.java	Fri Nov 06 13:20:18 2009 -0800
@@ -149,6 +149,7 @@
     GTGTEQ(">>="),
     GTGTGTEQ(">>>="),
     MONKEYS_AT("@"),
+    MODULEVERSIONLITERAL,
     CUSTOM;
 
     Token() {
@@ -176,6 +177,8 @@
             return "token.float";
         case DOUBLELITERAL:
             return "token.double";
+        case MODULEVERSIONLITERAL:
+            return "token.version";
         case ERROR:
             return "token.bad-symbol";
         case EOF:
--- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Fri Nov 06 13:20:18 2009 -0800
@@ -1213,9 +1213,19 @@
                     node.type = null;
             }
             public void visitTopLevel(JCCompilationUnit node) {
+                node.locn = null;
+                node.modle = null;
                 node.packge = null;
                 super.visitTopLevel(node);
             }
+            public void visitModuleDef(JCModuleDecl node) {
+                node.sym = null;
+                super.visitModuleDef(node);
+            }
+            public void visitPackageDef(JCPackageDecl node) {
+                node.sym = null;
+                super.visitPackageDef(node);
+            }
             public void visitClassDef(JCClassDecl node) {
                 node.sym = null;
                 super.visitClassDef(node);
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Nov 06 13:20:18 2009 -0800
@@ -502,6 +502,17 @@
 compiler.err.var.might.be.assigned.in.loop=\
     variable {0} might be assigned in loop
 
+compiler.err.mdl.no.version.available=\
+    no version available for module {0}
+compiler.err.mdl.no.unique.version.available=\
+    no unique version available for module {0}
+compiler.err.mdl.required.version.not.available=\
+    required version not available for module {0}
+compiler.err.mdl.duplicate.definition=\
+    duplicate definition of module {0}
+compiler.err.mdl.file.in.wrong.directory=\
+    file is not in the expected subdirectory within its package hierarchy
+
 # In the following string, {1} will always be the detail message from
 # java.io.IOException.
 compiler.err.class.cant.write=\
@@ -827,6 +838,8 @@
     <float>
 compiler.misc.token.double=\
     <double>
+compiler.misc.token.version=\
+    <version>
 compiler.misc.token.bad-symbol=\
     <bad symbol>
 compiler.misc.token.end-of-input=\
@@ -874,6 +887,9 @@
 compiler.misc.unnamed.package=\
     unnamed package
 
+compiler.misc.unnamed.module=\
+    unnamed module
+
 #####
 
 compiler.err.cant.access=\
@@ -1110,6 +1126,8 @@
     class
 compiler.misc.kindname.package=\
     package
+compiler.misc.kindname.module=\
+    module
 #####
 
 compiler.misc.no.args=\
@@ -1232,6 +1250,10 @@
     strings in switch are not supported in -source {0}\n\
 (use -source 7 or higher to enable strings in switch)
 
+compiler.err.modules.not.supported.in.source=\
+    modules are not supported in -source {0}\n\
+(use -source 7 or higher to enable modules)
+
 ########################################
 # Diagnostics for where clause implementation
 # used by the RichDiagnosticFormatter.
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Nov 06 13:20:18 2009 -0800
@@ -31,6 +31,7 @@
 import java.io.StringWriter;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.type.TypeKind;
+import javax.tools.JavaFileManager.Location;
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.util.*;
@@ -314,9 +315,17 @@
     public static final int DIV_ASG = MUL_ASG + 1;           // /=
     public static final int MOD_ASG = DIV_ASG + 1;           // %=
 
+    public static final int MODULE = MOD_ASG + 1;
+    public static final int MODULE_CLASS = MODULE + 1;
+    public static final int MODULE_ID = MODULE_CLASS + 1;
+    public static final int MODULE_PERMITS = MODULE_CLASS + 1;
+    public static final int MODULE_REQUIRES = MODULE_PERMITS + 1;
+
+    public static final int PACKAGE = MODULE_PERMITS + 1;
+
     /** A synthetic let expression, of type LetExpr.
      */
-    public static final int LETEXPR = MOD_ASG + 1;           // ala scheme
+    public static final int LETEXPR = PACKAGE + 1;           // ala scheme
 
 
     /** The offset between assignment operators and normal operators.
@@ -336,6 +345,7 @@
     public abstract int getTag();
 
     /** Convert a tree to a pretty-printed string. */
+    @Override
     public String toString() {
         StringWriter s = new StringWriter();
         try {
@@ -371,10 +381,11 @@
 
     /** Return a shallow copy of this tree.
      */
+    @Override
     public Object clone() {
         try {
             return super.clone();
-        } catch(CloneNotSupportedException e) {
+        } catch (CloneNotSupportedException e) {
             throw new RuntimeException(e);
         }
     }
@@ -423,10 +434,10 @@
      *                         Defined only if option -Xjcov is set.
      */
     public static class JCCompilationUnit extends JCTree implements CompilationUnitTree {
-        public List<JCAnnotation> packageAnnotations;
-        public JCExpression pid;
         public List<JCTree> defs;
         public JavaFileObject sourcefile;
+        public ModuleSymbol modle;
+        public Location locn;
         public PackageSymbol packge;
         public Scope namedImportScope;
         public Scope starImportScope;
@@ -434,15 +445,11 @@
         public Position.LineMap lineMap = null;
         public Map<JCTree, String> docComments = null;
         public Map<JCTree, Integer> endPositions = null;
-        protected JCCompilationUnit(List<JCAnnotation> packageAnnotations,
-                        JCExpression pid,
-                        List<JCTree> defs,
+        protected JCCompilationUnit(List<JCTree> defs,
                         JavaFileObject sourcefile,
                         PackageSymbol packge,
                         Scope namedImportScope,
                         Scope starImportScope) {
-            this.packageAnnotations = packageAnnotations;
-            this.pid = pid;
             this.defs = defs;
             this.sourcefile = sourcefile;
             this.packge = packge;
@@ -454,7 +461,8 @@
 
         public Kind getKind() { return Kind.COMPILATION_UNIT; }
         public List<JCAnnotation> getPackageAnnotations() {
-            return packageAnnotations;
+            JCPackageDecl pd = TreeInfo.getPackage(this);
+            return pd == null ? List.<JCAnnotation>nil() : pd.getAnnotations();
         }
         public List<JCImport> getImports() {
             ListBuffer<JCImport> imports = new ListBuffer<JCImport>();
@@ -466,7 +474,10 @@
             }
             return imports.toList();
         }
-        public JCExpression getPackageName() { return pid; }
+        public JCExpression getPackageName() {
+            JCPackageDecl pd = TreeInfo.getPackage(this);
+            return pd == null ? null : pd.getPackageId();
+        }
         public JavaFileObject getSourceFile() {
             return sourcefile;
         }
@@ -2041,6 +2052,225 @@
         }
     }
 
+    public static class JCModuleDecl extends JCTree implements com.sun.source.tree.ModuleTree {
+        public List<JCAnnotation> annots;
+        public JCModuleId id;
+        public List<JCModuleId> provides;
+        public List<JCModuleMetadata> metadata;
+        public ModuleSymbol sym;
+        protected JCModuleDecl(List<JCAnnotation> annots, JCModuleId id,
+                List<JCModuleId> provides, List<JCModuleMetadata> metadata) {
+            this.annots = annots;
+            this.id = id;
+            this.provides = provides;
+            this.metadata = metadata;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitModuleDef(this); }
+
+        public Kind getKind() {
+            return Kind.MODULE;
+        }
+
+        public List<JCAnnotation> getAnnotations() {
+            return annots;
+        }
+
+        public JCModuleId getId() {
+            return id;
+        }
+
+        public List<JCModuleId> getProvides() {
+            return provides;
+        }
+
+        public List<JCModuleMetadata> getMetadataList() {
+            return metadata;
+        }
+
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitModule(this, d);
+        }
+
+        @Override
+        public int getTag() {
+            return MODULE;
+        }
+    }
+
+    public static class JCModuleId extends JCTree implements com.sun.source.tree.ModuleIdTree {
+        public JCTree qualId;
+        public Name version;
+        protected JCModuleId(JCTree qualId, Name version) {
+            this.qualId = qualId;
+            this.version = version;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitModuleId(this); }
+
+        public Kind getKind() {
+            return Kind.MODULE_ID;
+        }
+
+        public JCTree getModuleName() {
+            return qualId;
+        }
+
+        public Name getModuleVersion() {
+            return version;
+        }
+
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitModuleId(this, d);
+        }
+
+        @Override
+        public int getTag() {
+            return MODULE_ID;
+        }
+    }
+
+    public static abstract class JCModuleMetadata extends JCTree {
+
+    }
+
+    public static class JCModuleClass extends JCModuleMetadata implements com.sun.source.tree.ModuleClassTree {
+        public JCTree qualId;
+        public List<Name> flags;
+        protected JCModuleClass(List<Name> flags, JCTree qualId) {
+            this.qualId = qualId;
+            this.flags = flags;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitModuleClass(this); }
+
+        public Kind getKind() {
+            return Kind.MODULE_CLASS;
+        }
+
+        public JCTree getClassName() {
+            return qualId;
+        }
+
+        public List<Name> getFlags() {
+            return flags;
+        }
+
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitModuleClass(this, d);
+        }
+
+        @Override
+        public int getTag() {
+            return MODULE_ID;
+        }
+    }
+
+    public static class JCModulePermits extends JCModuleMetadata
+            implements com.sun.source.tree.ModulePermitsTree {
+        public List<JCExpression> moduleNames;
+
+        protected JCModulePermits(List<JCExpression> moduleNames) {
+            this.moduleNames = moduleNames;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitModulePermits(this); }
+
+        public Kind getKind() {
+            return Kind.MODULE_PERMITS;
+        }
+
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitModulePermits(this, d);
+        }
+
+        public List<JCExpression> getModuleNames() {
+            return moduleNames;
+        }
+
+        @Override
+        public int getTag() {
+            return MODULE_PERMITS;
+        }
+    }
+
+    public static class JCModuleRequires extends JCModuleMetadata
+            implements com.sun.source.tree.ModuleRequiresTree {
+        public List<Name> flags;
+        public List<JCModuleId> moduleIds;
+
+        protected JCModuleRequires(List<Name> flags, List<JCModuleId> moduleIds) {
+            this.flags = flags;
+            this.moduleIds = moduleIds;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitModuleRequires(this); }
+
+        public Kind getKind() {
+            return Kind.MODULE_REQUIRES;
+        }
+
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitModuleRequires(this, d);
+        }
+
+        public List<Name> getFlags() {
+            return flags;
+        }
+
+        public List<JCModuleId> getModuleIds() {
+            return moduleIds;
+        }
+
+        @Override
+        public int getTag() {
+            return MODULE_REQUIRES;
+        }
+    }
+
+    public static class JCPackageDecl extends JCTree implements com.sun.source.tree.PackageTree {
+        public List<JCAnnotation> annots;
+        public JCExpression packageId;
+        public PackageSymbol sym;
+        protected JCPackageDecl(List<JCAnnotation> annots, JCExpression packageId) {
+            this.annots = annots;
+            this.packageId = packageId;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitPackageDef(this); }
+
+        public Kind getKind() {
+            return Kind.PACKAGE;
+        }
+
+        public List<JCAnnotation> getAnnotations() {
+            return annots;
+        }
+
+        public JCExpression getPackageId() {
+            return packageId;
+        }
+
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitPackage(this, d);
+        }
+
+        @Override
+        public int getTag() {
+            return PACKAGE;
+        }
+    }
+
     public static class JCErroneous extends JCExpression
             implements com.sun.source.tree.ErroneousTree {
         public List<? extends JCTree> errs;
@@ -2093,9 +2323,7 @@
     /** An interface for tree factories
      */
     public interface Factory {
-        JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations,
-                                   JCExpression pid,
-                                   List<JCTree> defs);
+        JCCompilationUnit TopLevel(List<JCTree> defs);
         JCImport Import(JCTree qualid, boolean staticImport);
         JCClassDecl ClassDef(JCModifiers mods,
                           Name name,
@@ -2172,6 +2400,10 @@
         JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args);
         JCModifiers Modifiers(long flags, List<JCAnnotation> annotations);
         JCErroneous Erroneous(List<? extends JCTree> errs);
+        JCModuleId ModuleId(JCTree qualId, Name version);
+        JCModuleMetadata ModuleClass(List<Name> flags, JCTree qualId);
+        JCModuleMetadata ModulePermits(List<JCExpression> qualIds);
+        JCModuleMetadata ModuleRequires(List<Name> flags, List<JCModuleId> moduleIds);
         LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr);
     }
 
@@ -2227,6 +2459,12 @@
         public void visitModifiers(JCModifiers that)         { visitTree(that); }
         public void visitAnnotatedType(JCAnnotatedType that) { visitTree(that); }
         public void visitErroneous(JCErroneous that)         { visitTree(that); }
+        public void visitModuleDef(JCModuleDecl that)        { visitTree(that); }
+        public void visitModuleClass(JCModuleClass that)     { visitTree(that); }
+        public void visitModuleId(JCModuleId that)           { visitTree(that); }
+        public void visitModulePermits(JCModulePermits that) { visitTree(that); }
+        public void visitModuleRequires(JCModuleRequires that) { visitTree(that); }
+        public void visitPackageDef(JCPackageDecl that)      { visitTree(that); }
         public void visitLetExpr(LetExpr that)               { visitTree(that); }
 
         public void visitTree(JCTree that)                   { assert false; }
--- a/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Fri Nov 06 13:20:18 2009 -0800
@@ -329,33 +329,40 @@
      *  @param cdef     The class definition, which is assumed to be part of the
      *                  toplevel tree.
      */
+    @SuppressWarnings("fallthrough")
     public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
         docComments = tree.docComments;
         printDocComment(tree);
-        if (tree.pid != null) {
-            print("package ");
-            printExpr(tree.pid);
-            print(";");
-            println();
-        }
-        boolean firstImport = true;
-        for (List<JCTree> l = tree.defs;
-        l.nonEmpty() && (cdef == null || l.head.getTag() == JCTree.IMPORT);
-        l = l.tail) {
-            if (l.head.getTag() == JCTree.IMPORT) {
-                JCImport imp = (JCImport)l.head;
-                Name name = TreeInfo.name(imp.qualid);
-                if (name == name.table.names.asterisk ||
-                        cdef == null ||
-                        isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
-                    if (firstImport) {
-                        firstImport = false;
+        boolean inImports = false;
+        for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
+            switch (l.head.getTag()) {
+                case JCTree.IMPORT:
+                    JCImport imp = (JCImport)l.head;
+                    Name name = TreeInfo.name(imp.qualid);
+                    if (name == name.table.names.asterisk ||
+                            cdef == null ||
+                            isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
+                        if (!inImports) {
+                            inImports = true;
+                            println();
+                        }
+                        printStat(imp);
+                    }
+                    break;
+
+                default:
+                    if (cdef != null)
+                        break;
+                    // fall-through
+
+                case JCTree.MODULE:
+                case JCTree.PACKAGE:
+                    if (inImports) {
+                        inImports = false;
                         println();
                     }
-                    printStat(imp);
-                }
-            } else {
-                printStat(l.head);
+                    printStat(l.head);
+                    break;
             }
         }
         if (cdef != null) {
@@ -391,6 +398,89 @@
         }
     }
 
+    public void visitModuleDef(JCModuleDecl tree) {
+        try {
+            printAnnotations(tree.annots);
+            print("module ");
+            printExpr(tree.id);
+            if (tree.metadata == null) {
+                print(";");
+            } else {
+                if (tree.provides.nonEmpty()) {
+                    print(" provides ");
+                    printExprs(tree.provides);
+                    print(" ");
+                }
+                printBlock(tree.metadata);
+            }
+            println();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitModuleId(JCModuleId tree) {
+        try {
+            printExpr(tree.qualId);
+            if (tree.version != null) {
+                print(" @ ");
+                print(tree.version);  // JIGSAW FIXME -- CHECK IF QUOTES REQUIRED
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitModuleClass(JCModuleClass tree) {
+        try {
+            print("class ");
+            for (List<Name> l = tree.flags; l.nonEmpty(); l = l.tail ) {
+                print(l.head);
+                print(" ");
+            }
+            printExpr(tree.qualId);
+            print(";");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitModulePermits(JCModulePermits tree) {
+        try {
+            print("permits ");
+            printExprs(tree.moduleNames);
+            print(";");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitModuleRequires(JCModuleRequires tree) {
+        try {
+            print("requires ");
+            for (List<Name> l = tree.flags; l.nonEmpty(); l = l.tail ) {
+                print(l.head);
+                print(" ");
+            }
+            printExprs(tree.moduleIds);
+            print(";");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitPackageDef(JCPackageDecl tree) {
+        try {
+            printAnnotations(tree.annots);
+            print("package ");
+            printExpr(tree.packageId);
+            print(";");
+            println();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitImport(JCImport tree) {
         try {
             print("import ");
--- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Nov 06 13:20:18 2009 -0800
@@ -29,6 +29,7 @@
 import com.sun.tools.javac.tree.JCTree.*;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Name;
 
 /**
  * Creates a copy of a tree, using a given TreeMaker.
@@ -324,10 +325,8 @@
 
     public JCTree visitCompilationUnit(CompilationUnitTree node, P p) {
         JCCompilationUnit t = (JCCompilationUnit) node;
-        List<JCAnnotation> packageAnnotations = copy(t.packageAnnotations, p);
-        JCExpression pid = copy(t.pid, p);
         List<JCTree> defs = copy(t.defs, p);
-        return M.at(t.pos).TopLevel(packageAnnotations, pid, defs);
+        return M.at(t.pos).TopLevel(defs);
     }
 
     public JCTree visitTry(TryTree node, P p) {
@@ -405,6 +404,48 @@
         return M.at(t.pos).Wildcard(kind, inner);
     }
 
+    public JCTree visitModule(ModuleTree node, P p) {
+        JCModuleDecl t = (JCModuleDecl) node;
+        List<JCAnnotation> annots = copy(t.annots, p);
+        JCModuleId moduleId = copy(t.id);
+        List<JCModuleId> provides = copy(t.provides);
+        List<JCModuleMetadata> metadataList = copy(t.metadata, p);
+        return M.at(t.pos).Module(annots, moduleId, provides, metadataList);
+    }
+
+    public JCModuleClass visitModuleClass(ModuleClassTree node, P p) {
+        JCModuleClass t = (JCModuleClass) node;
+        JCTree qualId = copy(t.qualId, p);
+        return M.at(t.pos).ModuleClass(t.flags, qualId);
+    }
+
+    public JCTree visitModuleId(ModuleIdTree node, P p) {
+        JCModuleId t = (JCModuleId) node;
+        JCTree qualId = copy(t.qualId, p);
+        Name version = t.version;
+        return M.at(t.pos).ModuleId(qualId, version);
+    }
+
+    public JCModulePermits visitModulePermits(ModulePermitsTree node, P p) {
+        JCModulePermits t = (JCModulePermits) node;
+        List<JCExpression> moduleNames = copy(t.moduleNames, p);
+        return M.at(t.pos).ModulePermits(moduleNames);
+    }
+
+    public JCModuleRequires visitModuleRequires(ModuleRequiresTree node, P p) {
+        JCModuleRequires t = (JCModuleRequires) node;
+        List<Name> flags = t.flags;
+        List<JCModuleId> moduleIds = copy(t.moduleIds, p);
+        return M.at(t.pos).ModuleRequires(flags, moduleIds);
+    }
+
+    public JCTree visitPackage(PackageTree node, P p) {
+        JCPackageDecl t = (JCPackageDecl) node;
+        List<JCAnnotation> annots = copy(t.annots, p);
+        JCExpression packageId = copy(t.packageId);
+        return M.at(t.pos).Package(annots, packageId);
+    }
+
     public JCTree visitOther(Tree node, P p) {
         JCTree tree = (JCTree) node;
         switch (tree.getTag()) {
--- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Nov 06 13:20:18 2009 -0800
@@ -34,6 +34,7 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.tree.JCTree.*;
 
+import javax.tools.JavaFileObject;
 import static com.sun.tools.javac.code.Flags.*;
 
 /** Utility class containing inspector methods for trees.
@@ -891,4 +892,40 @@
             throw new AssertionError("Unexpected type tree: " + tree);
         }
     }
+
+    public static boolean isModuleInfo(JCCompilationUnit tree) {
+        return tree.sourcefile.isNameCompatible("module-info", JavaFileObject.Kind.SOURCE);
+    }
+
+    public static JCModuleDecl getModule(JCCompilationUnit t) {
+        for (JCTree def: t.defs) {
+            switch (def.getTag()) {
+                case JCTree.IMPORT:
+                    continue;
+                case JCTree.MODULE:
+                    return (JCModuleDecl) def;
+                default:
+                    break;
+            }
+        }
+        return null;
+    }
+
+    public static boolean isPackageInfo(JCCompilationUnit tree) {
+        return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
+    }
+
+    public static JCPackageDecl getPackage(JCCompilationUnit t) {
+        for (JCTree def: t.defs) {
+            switch (def.getTag()) {
+                case JCTree.IMPORT:
+                    continue;
+                case JCTree.PACKAGE:
+                    return (JCPackageDecl) def;
+                default:
+                    break;
+            }
+        }
+        return null;
+    }
 }
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Nov 06 13:20:18 2009 -0800
@@ -119,19 +119,19 @@
      * Create given tree node at current position.
      * @param defs a list of ClassDef, Import, and Skip
      */
-    public JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations,
-                                      JCExpression pid,
-                                      List<JCTree> defs) {
-        assert packageAnnotations != null;
+    public JCCompilationUnit TopLevel(List<JCTree> defs) {
         for (JCTree node : defs)
             assert node instanceof JCClassDecl
                 || node instanceof JCImport
+                || node instanceof JCPackageDecl
+                || node instanceof JCModuleDecl
+                || node instanceof JCModuleMetadata
                 || node instanceof JCSkip
                 || node instanceof JCErroneous
                 || (node instanceof JCExpressionStatement
                     && ((JCExpressionStatement)node).expr instanceof JCErroneous)
                  : node.getClass().getSimpleName();
-        JCCompilationUnit tree = new JCCompilationUnit(packageAnnotations, pid, defs,
+        JCCompilationUnit tree = new JCCompilationUnit(defs,
                                      null, null, null, null);
         tree.pos = pos;
         return tree;
@@ -495,6 +495,43 @@
         return tree;
     }
 
+    public JCModuleDecl Module(List<JCAnnotation> annots, JCModuleId moduleId,
+            List<JCModuleId> provides, List<JCModuleMetadata> metadata) {
+        JCModuleDecl tree = new JCModuleDecl(annots, moduleId, provides, metadata);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCModuleClass ModuleClass(List<Name> flags, JCTree qualId) {
+        JCModuleClass tree = new JCModuleClass(flags, qualId);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCModuleId ModuleId(JCTree qualId, Name version) {
+        JCModuleId tree = new JCModuleId(qualId, version);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCModulePermits ModulePermits(List<JCExpression> qualIds) {
+        JCModulePermits tree = new JCModulePermits(qualIds);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCModuleRequires ModuleRequires(List<Name> flags, List<JCModuleId> moduleIds) {
+        JCModuleRequires tree = new JCModuleRequires(flags, moduleIds);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCPackageDecl Package(List<JCAnnotation> annots, JCExpression packageId) {
+        JCPackageDecl tree = new JCPackageDecl(annots, packageId);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCErroneous Erroneous() {
         return Erroneous(List.<JCTree>nil());
     }
@@ -675,10 +712,10 @@
     /** Create a list of trees representing given list of types.
      */
     public List<JCExpression> Types(List<Type> ts) {
-        ListBuffer<JCExpression> types = new ListBuffer<JCExpression>();
+        ListBuffer<JCExpression> t = new ListBuffer<JCExpression>();
         for (List<Type> l = ts; l.nonEmpty(); l = l.tail)
-            types.append(Type(l.head));
-        return types.toList();
+            t.append(Type(l.head));
+        return t.toList();
     }
 
     /** Create a variable definition from a variable symbol and an initializer
--- a/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Nov 06 13:20:18 2009 -0800
@@ -46,7 +46,8 @@
     /** Visitor method: Scan a single node.
      */
     public void scan(JCTree tree) {
-        if(tree!=null) tree.accept(this);
+        if (tree != null)
+            tree.accept(this);
     }
 
     /** Visitor method: scan a list of nodes.
@@ -63,11 +64,35 @@
  ****************************************************************************/
 
     public void visitTopLevel(JCCompilationUnit tree) {
-        scan(tree.packageAnnotations);
-        scan(tree.pid);
         scan(tree.defs);
     }
 
+    public void visitModuleDef(JCModuleDecl tree) {
+        scan(tree.annots);
+        scan(tree.id);
+    }
+
+    public void visitModuleId(JCModuleId tree) {
+        scan(tree.qualId);
+    }
+
+    public void visitModuleClass(JCModuleClass tree) {
+        scan(tree.qualId);
+    }
+
+    public void visitModulePermits(JCModulePermits tree) {
+        scan(tree.moduleNames);
+    }
+
+    public void visitModuleRequires(JCModuleRequires tree) {
+        scan(tree.moduleIds);
+    }
+
+    public void visitPackageDef(JCPackageDecl tree) {
+        scan(tree.annots);
+        scan(tree.packageId);
+    }
+
     public void visitImport(JCImport tree) {
         scan(tree.qualid);
     }
--- a/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Nov 06 13:20:18 2009 -0800
@@ -116,7 +116,6 @@
  ****************************************************************************/
 
     public void visitTopLevel(JCCompilationUnit tree) {
-        tree.pid = translate(tree.pid);
         tree.defs = translate(tree.defs);
         result = tree;
     }
--- a/src/share/classes/com/sun/tools/javac/util/Names.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java	Fri Nov 06 13:20:18 2009 -0800
@@ -75,6 +75,7 @@
     public final Name java_lang_Enum;
     public final Name java_dyn_MethodHandle;
     public final Name java_dyn_InvokeDynamic;
+    public final Name module_info;
     public final Name package_info;
     public final Name ConstantValue;
     public final Name LineNumberTable;
@@ -148,6 +149,16 @@
     public final Name getDeclaringClass;
     public final Name ex;
     public final Name finalize;
+    public final Name module;
+    public final Name Module;
+    public final Name requires;
+    public final Name provides;
+    public final Name permits;
+    public final Name synthetic;
+    public final Name ModuleClass;
+    public final Name ModulePermits;
+    public final Name ModuleProvides;
+    public final Name ModuleRequires;
 
     public final Name.Table table;
 
@@ -184,6 +195,7 @@
         java_lang_Enum = fromString("java.lang.Enum");
         java_dyn_MethodHandle = fromString("java.dyn.MethodHandle");
         java_dyn_InvokeDynamic = fromString("java.dyn.InvokeDynamic");
+        module_info = fromString("module-info");
         package_info = fromString("package-info");
         serialVersionUID = fromString("serialVersionUID");
         ConstantValue = fromString("ConstantValue");
@@ -263,6 +275,16 @@
         getDeclaringClass = fromString("getDeclaringClass");
         ex = fromString("ex");
         finalize = fromString("finalize");
+        module = fromString("module");
+        Module = fromString("Module");
+        requires = fromString("requires");
+        provides = fromString("provides");
+        permits = fromString("permits");
+        synthetic = fromString("synthetic");
+        ModuleClass = fromString("ModuleClass");
+        ModulePermits = fromString("ModulePermits");
+        ModuleProvides = fromString("ModuleProvides");
+        ModuleRequires = fromString("ModuleRequires");
     }
 
     protected Name.Table createTable(Options options) {
--- a/src/share/classes/com/sun/tools/javap/AttributeWriter.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javap/AttributeWriter.java	Fri Nov 06 13:20:18 2009 -0800
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javap;
 
+import java.util.Arrays;
 import java.util.Formatter;
 
 import com.sun.tools.classfile.AccessFlags;
@@ -45,8 +46,10 @@
 import com.sun.tools.classfile.LineNumberTable_attribute;
 import com.sun.tools.classfile.LocalVariableTable_attribute;
 import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
-import com.sun.tools.classfile.ModuleExportTable_attribute;
-import com.sun.tools.classfile.ModuleMemberTable_attribute;
+import com.sun.tools.classfile.ModuleClass_attribute;
+import com.sun.tools.classfile.ModulePermits_attribute;
+import com.sun.tools.classfile.ModuleProvides_attribute;
+import com.sun.tools.classfile.ModuleRequires_attribute;
 import com.sun.tools.classfile.Module_attribute;
 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
@@ -373,9 +376,7 @@
     }
 
     public Void visitModule(Module_attribute attr, Void ignore) {
-        print("Module: #" + attr.module_name);
-        tab();
-        println("// " + getModuleName(attr));
+        println("  Module: " + constantWriter.stringValue(attr.module_id_index));
         return null;
     }
 
@@ -387,46 +388,40 @@
         }
     }
 
-    public Void visitModuleExportTable(ModuleExportTable_attribute attr, Void ignore) {
-        println("ModuleExportTable:");
-        indent(+1);
-        println("Types: (" + attr.export_type_table.length + ")");
-        for (int i = 0; i < attr.export_type_table.length; i++) {
-            print("#" + attr.export_type_table[i]);
-            tab();
-            println("// " + getExportTypeName(attr, i));
+    public Void visitModuleClass(ModuleClass_attribute attr, Void ignore) {
+        println("  ModuleClass: ");
+        println("  #" + attr.class_index + "," + Arrays.toString(attr.attributes)
+                + "\t// " + constantWriter.stringValues(attr.attributes, " ")
+                + " " + constantWriter.stringValue(attr.class_index));
+        return null;
+    }
+
+    public Void visitModulePermits(ModulePermits_attribute attr, Void ignore) {
+        println("  ModulePermits: ");
+        for (int i = 0; i < attr.permits_table.length; i++) {
+            int permits_index = attr.permits_table[i];
+            println("  #" + permits_index + "\t// " + constantWriter.stringValue(permits_index));
         }
-        indent(-1);
         return null;
     }
 
-    String getExportTypeName(ModuleExportTable_attribute attr, int index) {
-        try {
-            return attr.getExportTypeName(index, constant_pool);
-        } catch (ConstantPoolException e) {
-            return report(e);
+    public Void visitModuleProvides(ModuleProvides_attribute attr, Void ignore) {
+        println("  ModuleProvides: ");
+        for (int i = 0; i < attr.provides_table.length; i++) {
+            int provides_index = attr.provides_table[i];
+            println("  #" + provides_index + "\t// " + constantWriter.stringValue(provides_index));
         }
-    }
-
-    public Void visitModuleMemberTable(ModuleMemberTable_attribute attr, Void ignore) {
-        println("ModuleMemberTable:");
-        indent(+1);
-        println("Packages: (" + attr.package_member_table.length + ")");
-        for (int i = 0; i < attr.package_member_table.length; i++) {
-            print("#" + attr.package_member_table[i]);
-            tab();
-            println("// " + getPackageMemberName(attr, i));
-        }
-        indent(-1);
         return null;
     }
 
-    String getPackageMemberName(ModuleMemberTable_attribute attr, int index) {
-        try {
-            return attr.getPackageMemberName(index, constant_pool);
-        } catch (ConstantPoolException e) {
-            return report(e);
+    public Void visitModuleRequires(ModuleRequires_attribute attr, Void ignore) {
+        println("  ModuleRequires: ");
+        for (ModuleRequires_attribute.Entry e: attr.requires_table) {
+            println("  #" + e.requires_index + "," + Arrays.toString(e.attributes)
+                    + "\t// " + constantWriter.stringValues(e.attributes, " ")
+                    + " " + constantWriter.stringValue(e.requires_index));
         }
+        return null;
     }
 
     public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) {
--- a/src/share/classes/com/sun/tools/javap/ConstantWriter.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javap/ConstantWriter.java	Fri Nov 06 13:20:18 2009 -0800
@@ -102,15 +102,22 @@
                 return 2;
             }
 
-            public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
-                print("#" + info.name_index + ":#" + info.type_index);
+            public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) {
+                print("#" + info.class_index + ".#" + info.name_and_type_index);
                 tab();
                 println("//  " + stringValue(info));
                 return 1;
             }
 
-            public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) {
-                print("#" + info.class_index + ".#" + info.name_and_type_index);
+            public Integer visitModuleId(CONSTANT_ModuleId_info info, Void p) {
+                print("#" + info.name_index + ":#" + info.version_index);
+		tab();
+		println("//  " + stringValue(info));
+                return 1;
+            }
+
+            public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
+                print("#" + info.name_index + ":#" + info.type_index);
                 tab();
                 println("//  " + stringValue(info));
                 return 1;
@@ -207,6 +214,8 @@
                 return "InterfaceMethod";
             case CONSTANT_NameAndType:
                 return "NameAndType";
+            case CONSTANT_ModuleId:
+                return "ModuleId";
             default:
                 return "(unknown tag)";
         }
@@ -221,6 +230,16 @@
         }
     }
 
+    String stringValues(int[] constant_pool_indices, String sep) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < constant_pool_indices.length; i++) {
+            if (i > 0)
+                sb.append(sep);
+            sb.append(stringValue(constant_pool_indices[i]));
+        }
+        return sb.toString();
+    }
+
     String stringValue(CPInfo cpInfo) {
         return stringValueVisitor.visit(cpInfo);
     }
@@ -268,6 +287,33 @@
             return info.value + "l";
         }
 
+        public String visitMethodref(CONSTANT_Methodref_info info, Void p) {
+            return visitRef(info, p);
+        }
+
+        public String visitModuleId(CONSTANT_ModuleId_info info, Void p) {
+            if (info.version_index == 0)
+                return getCheckedName(info);
+            else
+                return getCheckedName(info) + "@" + getCheckedVersion(info);
+        }
+
+        String getCheckedName(CONSTANT_ModuleId_info info) {
+            try {
+                return checkName(info.getName());
+            } catch (ConstantPoolException e) {
+                return report(e);
+            }
+        }
+
+        String getCheckedVersion(CONSTANT_ModuleId_info info) {
+            try {
+                return info.getVersion();
+            } catch (ConstantPoolException e) {
+                return report(e);
+            }
+        }
+
         public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
             return getCheckedName(info) + ":" + getType(info);
         }
@@ -288,10 +334,6 @@
             }
         }
 
-        public String visitMethodref(CONSTANT_Methodref_info info, Void p) {
-            return visitRef(info, p);
-        }
-
         public String visitString(CONSTANT_String_info info, Void p) {
             try {
                 ClassFile classFile = classWriter.getClassFile();
--- a/src/share/classes/com/sun/tools/javap/JavapTask.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javap/JavapTask.java	Fri Nov 06 13:20:18 2009 -0800
@@ -236,12 +236,6 @@
             }
         },
 
-        new Option(false, "-XDjsr277") {
-            void process(JavapTask task, String opt, String arg) {
-                task.options.jsr277 = true;
-            }
-        },
-
         new Option(false, "-XDdetails") {
             void process(JavapTask task, String opt, String arg) {
                 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
@@ -586,7 +580,6 @@
         sourceWriter.setFileManager(fileManager);
 
         attributeFactory.setCompat(options.compat);
-        attributeFactory.setJSR277(options.jsr277);
 
         boolean ok = true;
 
--- a/src/share/classes/com/sun/tools/javap/Options.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/com/sun/tools/javap/Options.java	Fri Nov 06 13:20:18 2009 -0800
@@ -90,5 +90,4 @@
     public int tabColumn = 40;    // column number for comments
 
     public boolean compat;             // bug-for-bug compatibility mode with old javap
-    public boolean jsr277;
 }
--- a/src/share/classes/javax/lang/model/element/Element.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/javax/lang/model/element/Element.java	Fri Nov 06 13:20:18 2009 -0800
@@ -32,7 +32,6 @@
 import java.util.List;
 import java.util.Set;
 
-import javax.lang.model.element.Modifier;
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
--- a/src/share/classes/javax/lang/model/element/Modifier.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/javax/lang/model/element/Modifier.java	Fri Nov 06 13:20:18 2009 -0800
@@ -59,7 +59,8 @@
     /** The modifier {@code volatile} */        VOLATILE,
     /** The modifier {@code synchronized} */    SYNCHRONIZED,
     /** The modifier {@code native} */          NATIVE,
-    /** The modifier {@code strictfp} */        STRICTFP;
+    /** The modifier {@code strictfp} */        STRICTFP,
+    /** The modifier {@code module} */          MODULE;
 
 
     private String lowercase = null;    // modifier name in lowercase
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/lang/model/element/ModuleElement.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2006-2008 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 javax.lang.model.element;
+
+import java.util.List;
+
+/** Interim API. */
+public interface ModuleElement extends Element {
+    interface ModuleId {
+        CharSequence getName();
+        CharSequence getVersion();
+    }
+
+    interface ModuleRequires {
+        ModuleId getModuleId();
+        List<? extends CharSequence> getFlags();
+    }
+
+    List<? extends ModuleRequires> getRequires();
+
+}
--- a/src/share/classes/javax/lang/model/type/TypeKind.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/javax/lang/model/type/TypeKind.java	Fri Nov 06 13:20:18 2009 -0800
@@ -134,6 +134,12 @@
     EXECUTABLE,
 
     /**
+     * A pseudo-type corresponding to a module element.
+     * @see NoType
+     */
+    MODULE,
+
+    /**
      * An implementation-reserved type.
      * This is not the type you are looking for.
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/lang/model/util/ModuleResolver.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,67 @@
+/*
+ * 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 javax.lang.model.util;
+// TODO: reconsider this package -- perhaps it belongs in com.sun.tools.javac.api
+
+import javax.lang.model.element.ModuleElement;
+
+/**
+ * Module resolver for modules defined in the Java&trade; Programming Language.
+ *
+ * Given a set of root modules, and an overall set of modules, the resolver determines
+ * which modules are visible from the root modules.
+ */
+public interface ModuleResolver {
+
+    class ResolutionException extends Exception {
+        private static final long serialVersionUID = -5294493995009985322L;
+    }
+
+    /**
+     * Resolve a set of modules. The resolution may take additional modules into
+     * account, such as may be found in a system module library.
+     * @param roots The root modules whose dependencies need to be resolved
+     * @param modules A set of modules in which to find any dependencies.
+     * @throws ResolutionException if the resolution cannot be successfully completed.
+     */
+    Iterable<? extends ModuleElement> resolve(
+        Iterable<? extends ModuleElement> roots,
+        Iterable<? extends ModuleElement> modules)
+        throws ResolutionException;
+
+    /**
+     * Get the set of visible modules for a module. This method may be called
+     * after {@link #resolve} to get more specific information.
+     * @param module
+     * @return the visible modules
+     */
+    Iterable<? extends ModuleElement> getVisibleModules(ModuleElement module)
+        throws IllegalStateException;
+
+    boolean isPlatformName(CharSequence name);
+
+    String getDefaultPlatformModule(); // should use a "platform" enum
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/tools/ModuleFileManager.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,47 @@
+/*
+ * 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 javax.tools;
+
+public interface ModuleFileManager extends JavaFileManager {
+    class InvalidLocationException extends IllegalArgumentException {
+        private static final long serialVersionUID = 2115919242510692026L;
+    }
+
+    class InvalidFileObjectException extends IllegalArgumentException {
+        private static final long serialVersionUID = 1234906668846471087L;
+    }
+
+    enum ModuleMode { SINGLE, MULTIPLE };
+
+    ModuleMode getModuleMode();
+
+    Location getModuleLocation(Location location, JavaFileObject fo, String packageName)
+            throws IllegalArgumentException;
+
+    Iterable<? extends Location> getModuleLocations(Location location);
+
+    Location join(Iterable<? extends Location> locations);
+}
--- a/src/share/classes/javax/tools/StandardLocation.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/src/share/classes/javax/tools/StandardLocation.java	Fri Nov 06 13:20:18 2009 -0800
@@ -66,7 +66,12 @@
      * Location to search for platform classes.  Sometimes called
      * the boot class path.
      */
-    PLATFORM_CLASS_PATH;
+    PLATFORM_CLASS_PATH,
+
+    /**
+     * Location to search for existing module class files.
+     */
+    MODULE_PATH;
 
     /**
      * Gets a location object with the given name.  The following
--- a/test/tools/javac/T6232928.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/test/tools/javac/T6232928.java	Fri Nov 06 13:20:18 2009 -0800
@@ -27,7 +27,7 @@
  * @summary Interface package-info should be marked abstract and synthetic
  * @author Wei Tao
  * @compile T6232928.java
- * @compile T6232928/package-info.java
+ * @compile -doe T6232928/package-info.java
  * @run main T6232928
  */
 
--- a/test/tools/javac/T6341023.java	Mon Nov 02 21:36:59 2009 -0800
+++ b/test/tools/javac/T6341023.java	Fri Nov 06 13:20:18 2009 -0800
@@ -101,6 +101,26 @@
                 ok = ok & verify(k, i, i == WildcardTree.class);
                 break;
 
+            case MODULE:
+                ok = ok & verify(k, i, i == ModuleTree.class);
+                break;
+
+            case MODULE_CLASS:
+                ok = ok & verify(k, i, i == ModuleClassTree.class);
+                break;
+
+            case MODULE_PERMITS:
+                ok = ok & verify(k, i, i == ModulePermitsTree.class);
+                break;
+
+            case MODULE_REQUIRES:
+                ok = ok & verify(k, i, i == ModuleRequiresTree.class);
+                break;
+
+            case PACKAGE:
+                ok = ok & verify(k, i, i == PackageTree.class);
+                break;
+
             case OTHER:
                 ok = ok & verify(k, i, i == null);
                 break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleAccessTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2008-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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of module access modifier
+ */
+
+import java.io.*;
+import java.util.*;
+
+/*
+ * Test access to items in a module for combinations of:
+ * -- referencing module
+ * -- type of item being referenced
+ * As a control, we verify that access to the items fails
+ * when they have package access, but succeeds with module
+ * access.
+ *
+ * Verify that compilation errors are generated or that
+ * compilation is successful.
+ */
+public class ModuleAccessTest01
+{
+    enum AccessKind {
+        PACKAGE(""),
+        MODULE("module");
+        AccessKind(String s) {
+            text = s;
+        }
+        final String text;
+    }
+
+    enum ItemKind {
+        CLASS("p.Ref.C r = null;"),
+        CONSTR("new p.Ref();"),
+        FIELD("int i = ref.field;"),
+        METHOD("int i = ref.method();");
+        ItemKind(String s) {
+            text = s;
+        }
+        final String text;
+    };
+
+    enum ModuleKind {
+        M1("m1", "p1"),
+        M2("m2", "p2"),
+        UNNAMED("", "");
+        ModuleKind(String m, String p) {
+            moduleName = m;
+            packageName = p;
+        }
+        String moduleDir() { return (moduleName.equals("") ? "anon" : moduleName) + "/"; }
+        String moduleDecl() { return "module " + moduleName + " { }"; }
+        String packageDir() { return (packageName.equals("") ? "" : packageName + "/"); }
+        String packageDecl() { return (packageName.equals("") ? "" : "package " + packageName + ";"); }
+        final String moduleName;
+        final String packageName;
+    };
+
+    public static void main(String... args) throws Exception {
+        new ModuleAccessTest01().run();
+    }
+
+    public void run() throws Exception {
+        for (ItemKind ik: ItemKind.values()) {
+            for (ModuleKind mk: ModuleKind.values()) {
+                for (AccessKind ak: AccessKind.values()) {
+                    test(ik, mk, ak);
+                }
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(ItemKind ik, ModuleKind mk, AccessKind ak) throws Exception {
+        System.out.println("Test " + (++count) + ": " + ik + " " + mk + " " + ak);
+
+        File testDir = new File("test" + count);
+        srcDir = new File(testDir, "src");
+        classesDir = new File(testDir, "classes");
+        resetDirs(srcDir, classesDir);
+
+        List<File> files = new ArrayList<File>();
+
+        // create a reference class in module m1, package p
+        String[] refBody = {
+            "package p;",
+            "public class Ref {",
+            "    " + ak.text + " Ref() { }",
+            "    " + ak.text + " int field;",
+            "    " + ak.text + " int method() { return 0; }",
+            "    " + ak.text + " class C { }",
+            "}"
+        };
+        files.add(createFile(srcDir, "m1/p/Ref.java", join(refBody)));
+        files.add(createFile(srcDir, "m1/module-info.java", "module m1 { }"));
+
+        // create a test class in module mk.moduleName, package mk.packageName
+        String[] testBody = {
+            mk.packageDecl(),
+            "class Test {",
+            "    void m(p.Ref ref) {",
+            "        " + ik.text,
+            "    }",
+            "}"
+        };
+        files.add(createFile(srcDir, mk.moduleDir() + mk.packageDir() + "Test.java", join(testBody)));
+        switch (mk) {
+        case UNNAMED:   // no module-info
+        case M1:        // already generated for ref
+            break;
+        default:
+            files.add(createFile(srcDir, mk.moduleDir() + "module-info.java", mk.moduleDecl()));
+        }
+
+        System.out.println("files: " + files);
+
+        boolean expectError = (ak == AccessKind.PACKAGE || mk != ModuleKind.M1);
+
+        compile(files, classesDir, Arrays.asList("-modulepath", classesDir.getPath()), expectError);
+    }
+
+    void compile(List<File> files, File classOutDir, List<String> extraOpts, boolean expectError) {
+        List<String> options = new ArrayList<String>();
+        options.add("-XDrawDiagnostics");
+        options.addAll(Arrays.asList("-source", "7", "-d", classOutDir.getPath()));
+        if (extraOpts != null)
+            options.addAll(extraOpts);
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter out = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, out);
+        out.close();
+
+        if (expectError) {
+            if (rc == 0)
+                error(files, "compilation succeeded unexpectedly");
+            else {
+                //log(files, "compilation failed as expected", sw.toString());
+                //log(files, "OK");
+            }
+        }
+        else {
+            if (rc != 0)
+                error(files, "compilation failed unexpectedly", sw.toString());
+            else {
+                //log(files, "OK");
+            }
+        }
+    }
+
+    /**
+     * Join lines with newline.
+     */
+    String join(String... lines) {
+        StringBuilder sb = new StringBuilder();
+        for (String s: lines) {
+            sb.append(s);
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Create a test file with given content.
+     */
+    File createFile(File dir, String path, String body) throws IOException {
+        File file = new File(dir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(List<File> files, String msg, String... more) {
+        System.out.println("test " + files);
+        System.out.println("error: " + msg);
+        for (String s: more)
+            System.out.println(s);
+        errors++;
+        //throw new Error(msg);
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.out.println("error: " + msg);
+        for (String s: more)
+            System.out.println(s);
+        errors++;
+        throw new Error(msg);
+    }
+
+    /**
+     * Log a message.
+     */
+    void log(List<File> files, String... msgs) {
+        System.out.println("test " + files);
+        for (String s: msgs)
+            System.out.println(s);
+    }
+
+    int count;
+    int errors;
+    File srcDir;
+    File classesDir;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleAttributeTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,219 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of Module attribute
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+public class ModuleAttributeTest01 {
+    /** Simple combinations of compilation units to test. */
+    enum Kind {
+        NONE("package P; class C { }", null),
+        NAME("package P; class C { }", "module M { }"),
+        NAME_AND_VERSION("package P; class C { }", "module M@1.0 { }");
+        Kind(String classBody, String moduleInfoBody) {
+            this.classBody = classBody;
+            this.moduleInfoBody = moduleInfoBody;
+        }
+        final String classBody;
+        final String moduleInfoBody;
+    };
+
+
+    public static void main(String[] args) throws Exception {
+        new ModuleAttributeTest01().run();
+    }
+
+    void run() throws Exception {
+        for (Kind k: Kind.values()) {
+            try {
+                test(k);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                errors++;
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(Kind k) throws Exception {
+        System.out.println("Test " + (++count) + ": " + k);
+
+        File testDir = new File("test" + count);
+        srcDir = new File(testDir, "src");
+        classesDir = new File(testDir, "classes");
+        resetDirs(srcDir, classesDir);
+
+        String classBody = k.classBody;
+        String moduleInfoBody = k.moduleInfoBody;
+
+        List<File> files = new ArrayList<File>();
+        addFile(files, createFile("C.java", classBody));
+        addFile(files, createFile("module-info.java", moduleInfoBody));
+        compile(files);
+        String moduleId = getModuleId(moduleInfoBody);
+        checkModuleAttribute("P/C.class", null); // Module attribute no longer written in class file
+        if (moduleInfoBody != null)
+            checkModuleAttribute("module-info.class", moduleId);
+    }
+
+    String getModuleId(String moduleBody) {
+        if (moduleBody == null)
+            return null;
+        String[] tokens = moduleBody.split(" +");
+        return tokens[1];
+    }
+
+    void checkModuleAttribute(String file, String moduleId) throws IOException {
+        System.err.println("Checking " + file);
+        try {
+            ClassFile cf = ClassFile.read(new File(classesDir, file));
+            Module_attribute attr = (Module_attribute) cf.getAttribute(Attribute.Module);
+            if (attr == null) {
+                if (moduleId != null)
+                    error("Module attribute not found; expected " + moduleId);
+            } else {
+                if (moduleId == null) {
+                    error("Unexpected module attribute found: " + attr);
+                } else {
+                    String name, version;
+                    int sep = moduleId.indexOf("@");
+                    if (sep == -1) {
+                        name = moduleId;
+                        version = null;
+                    } else {
+                        name = moduleId.substring(0, sep);
+                        version = moduleId.substring(sep + 1);
+                    }
+                    ConstantPool cp = cf.constant_pool;
+                    checkEqual("module name", name, attr.getModuleName(cp));
+                    checkEqual("module version", version, attr.getModuleVersion(cp));
+                }
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + file + ": " + e);
+        } catch (IOException e) {
+            error("Error reading " + file + ": " + e);
+        }
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<File> files) {
+        List<String> options = new ArrayList<String>();
+        options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath()));
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    /**
+     * Add a file to a list if the file is not null.
+     */
+    void addFile(List<File> files, File file) {
+        if (file != null)
+            files.add(file);
+    }
+
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents
+    File classesDir = new File("tmp", "classes");
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleClassAttributeTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,227 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of ModuleClass attribute
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+public class ModuleClassAttributeTest01 {
+    String[][] values = {
+        {"C"},
+        {"main", "my.pckge.Main"},
+        {"fx", "applet", "a.b.c.MyClass"}
+    };
+
+    public static void main(String[] args) throws Exception {
+        new ModuleClassAttributeTest01().run();
+    }
+
+    void run() throws Exception {
+        for (String[] v: values) {
+            try {
+                String[] flags = null;
+                String className = null;
+                if (v.length > 0) {
+                    flags = new String[v.length - 1];
+                    System.arraycopy(v, 0, flags, 0, flags.length);
+                    className = v[v.length - 1];
+                }
+                System.err.println("Test " + Arrays.asList(flags) + " " + className);
+                test(flags, className);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                errors++;
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(String[] flags, String className) throws Exception {
+        count++;
+        reset();
+        StringBuilder sb = new StringBuilder();
+        sb.append("module M { ");
+        if (className != null) {
+            sb.append("class ");
+            for (String f: flags)
+                sb.append(f + " ");
+            sb.append(className);
+            sb.append("; ");
+        }
+        sb.append("}");
+        String moduleInfoBody = sb.toString();
+
+        String classPath; // path name of the class
+        String classBody;
+        int dot = className.lastIndexOf('.');
+        if (dot == -1) {
+            classBody = "public class " + className + " { }";
+            classPath = className + ".java";
+        }
+        else {
+            classBody = "package " + className.substring(0, dot) + "; public class " + className.substring(dot + 1) + " { }";
+            classPath = className.substring(dot + 1) + ".java";
+        }
+
+        List<File> files = new ArrayList<File>();
+        addFile(files, createFile(classPath, classBody));
+        addFile(files, createFile("module-info.java", moduleInfoBody));
+        compile(files);
+        checkModuleClassAttribute("module-info.class", flags, className.replace('.', '/'));
+    }
+
+    void checkModuleClassAttribute(String file, String[] flags, String className) throws IOException {
+        System.err.println("Checking " + file);
+        try {
+            ClassFile cf = ClassFile.read(new File(classesDir, file));
+            ModuleClass_attribute attr = (ModuleClass_attribute) cf.getAttribute(Attribute.ModuleClass);
+            if (attr == null) {
+                if (className != null)
+                    error("ModuleClass attribute not found; expected " + Arrays.asList(flags) + " " + className);
+            } else {
+                if (className == null) {
+                    error("Unexpected module attribute found: " + attr);
+                } else {
+                    ConstantPool cp = cf.constant_pool;
+                    checkEqual("class name", className, attr.getClassName(cp));
+                    checkEqual("class flags", flags, attr.getClassAttributes(cp));
+                }
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + file + ": " + e);
+            e.printStackTrace();
+        } catch (IOException e) {
+            error("Error reading " + file + ": " + e);
+        }
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    <T> void checkEqual(String tag, T[] expect, T[] found) {
+        if (expect == null ? found == null : Arrays.equals(expect, found))
+            return;
+        error(tag + " mismatch", "expected " + Arrays.asList(expect), "found: " + Arrays.asList(found));
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<File> files) {
+        List<String> options = new ArrayList<String>();
+        options.addAll(Arrays.asList("-source", "7", "-doe", "-d", classesDir.getPath()));
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    /**
+     * Add a file to a list if the file is not null.
+     */
+    void addFile(List<File> files, File file) {
+        if (file != null)
+            files.add(file);
+    }
+
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty src and classes directories for a test.
+     */
+    void reset() {
+        resetDir(srcDir);
+        resetDir(classesDir);
+    }
+
+    /**
+     * Set up an empty directory.
+     */
+    void resetDir(File dir) {
+        if (dir.exists())
+            deleteAll(dir);
+        dir.mkdirs();
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents
+    File classesDir = new File("tmp", "classes");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleModifierTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2008 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of module access modifier
+ */
+
+import java.io.*;
+import java.util.*;
+
+/*
+ * Test correct handling of module modifiers, including the cases
+ * involving lookahead, using combinations of
+ * -- class, interface or enum container
+ * -- different items to go in the container
+ */
+public class ModuleModifierTest01
+{
+    enum ItemKind {
+        FIELD("module int field", " = 0;", ";"),
+        ARRAY1("module int array[]", " = { };", ";"),
+        ARRAY2("module int[] array", " = { };", ";"),
+        METHOD("module int method()", ";", " { return 0; }"),
+        AMBIG1("module Test()", ";", " { }"),                     // constr for class, err for enum
+        AMBIG2("module Test()", ";", " { return null; }"),        // error for class, method for enum
+        AMBIG3("public module Test()", ";", " { return null; }"); // method for all
+        ItemKind(String decl, String intfTail, String classTail) {
+            this.decl = decl;
+            this.intfTail = intfTail;
+            this.classTail = classTail;
+        }
+        final String decl;
+        final String intfTail;
+        final String classTail;
+    };
+
+    enum ClassKind {
+        CLASS("class Test {"),
+        INTERFACE("interface Test {"),
+        ENUM("enum Test { e1 ;");
+        ClassKind(String s) {
+            text = s;
+        }
+        final String text;
+    };
+
+    public static void main(String... args) throws Exception {
+        new ModuleModifierTest01().run();
+    }
+
+    public void run() throws Exception {
+        for (ClassKind ck: ClassKind.values()) {
+            for (ItemKind ik: ItemKind.values()) {
+                test(ck, ik);
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(ClassKind ck, ItemKind ik) throws Exception {
+        System.out.println("Test " + (++count) + ": " + ck + " " + ik);
+
+        File testDir = new File("test" + count);
+        srcDir = new File(testDir, "src");
+        classesDir = new File(testDir, "classes");
+        resetDirs(srcDir, classesDir);
+
+        boolean needModule;
+        switch (ik) {
+        case AMBIG1: needModule = (ck == ClassKind.INTERFACE); break;
+        case AMBIG2: needModule = (ck != ClassKind.CLASS);     break;
+        case AMBIG3: needModule = true;  break;
+        default:     needModule = false; break;
+        }
+
+        String[] testBody = {
+            "package p;",
+            "    " + ck.text,
+            "    " + ik.decl + (ck == ClassKind.INTERFACE ? ik.intfTail : ik.classTail),
+            "}",
+            (needModule ? "class module { }" : "")
+        };
+
+        String[] moduleInfoBody = {
+            "module m { }"
+        };
+
+        File test = createFile(srcDir, "Test.java", join(testBody));
+        File module_info = createFile(srcDir, "module-info.java", join(moduleInfoBody));
+        boolean expectError =
+            (ck == ClassKind.ENUM && ik == ItemKind.AMBIG1)
+            || (ck == ClassKind.CLASS && ik == ItemKind.AMBIG2);
+
+        compile(Arrays.asList(test, module_info), classesDir, null, expectError);
+    }
+
+    void compile(List<File> files, File classOutDir, List<String> extraOpts, boolean expectError) {
+        List<String> options = new ArrayList<String>();
+        options.add("-XDrawDiagnostics");
+        options.addAll(Arrays.asList("-source", "7", "-d", classOutDir.getPath()));
+        if (extraOpts != null)
+            options.addAll(extraOpts);
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter out = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, out);
+        out.close();
+
+        if (expectError) {
+            if (rc == 0)
+                error(files, "compilation succeeded unexpectedly");
+            else {
+                //log(files, "compilation failed as expected", sw.toString());
+                //log(files, "OK");
+            }
+        }
+        else {
+            if (rc != 0)
+                error(files, "compilation failed unexpectedly", sw.toString());
+            else {
+                //log(files, "OK");
+            }
+        }
+    }
+
+    /**
+     * Join lines with newline.
+     */
+    String join(String... lines) {
+        StringBuilder sb = new StringBuilder();
+        for (String s: lines) {
+            sb.append(s);
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Create a test file with given content.
+     */
+    File createFile(File dir, String path, String body) throws IOException {
+        File file = new File(dir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(List<File> files, String msg, String... more) {
+        System.out.println("test " + files);
+        System.out.println("error: " + msg);
+        for (String s: more)
+            System.out.println(s);
+        errors++;
+        //throw new Error(msg);
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.out.println("error: " + msg);
+        for (String s: more)
+            System.out.println(s);
+        errors++;
+        throw new Error(msg);
+    }
+
+    /**
+     * Log a message.
+     */
+    void log(List<File> files, String... msgs) {
+        System.out.println("test " + files);
+        for (String s: msgs)
+            System.out.println(s);
+    }
+
+    int count;
+    int errors;
+    File srcDir;
+    File classesDir;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModulePathTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,229 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of module resolution
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class ModulePathTest01
+{
+    enum ModuleKind { SINGLE, MULTIPLE };
+
+    enum FileKind {
+        CLASS("p", "A.java", "package p; class A { }"),
+        MODULE_INFO("", "module-info.java", "module M { }");
+        FileKind(String pkgName, String path, String body) {
+            this.pkgName = pkgName;
+            this.path = path;
+            this.body = body;
+        }
+        final String pkgName;
+        final String path;
+        final String body;
+    }
+
+    enum TestKind { GOOD, BAD };
+
+    public static void main(String... args) throws Exception {
+        new ModulePathTest01().run();
+    }
+
+    public void run() throws Exception {
+        for (ModuleKind mk: ModuleKind.values()) {
+            for (FileKind fk: FileKind.values()) {
+                for (TestKind tk: TestKind.values()) {
+                    test(mk, fk, tk);
+                }
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(ModuleKind mk, FileKind fk, TestKind tk) throws IOException {
+        System.err.println("Test " + (++count) + ": moduleKind " + mk + ": fileKind " + fk + ": testKind " + tk);
+
+        File testDir = new File("test" + count);
+        srcDir = new File(testDir, "src");
+        modulesDir = new File(testDir, "modules");
+        resetDirs(srcDir, modulesDir);
+
+        String path = "m/" + (tk == TestKind.GOOD ? fk.pkgName : "BAD") + "/" + fk.path;
+        File srcFile = createFile(srcDir, path, fk.body);
+
+        List<String> args = new ArrayList<String>();
+        if (mk == ModuleKind.MULTIPLE)
+            append(args, "-modulepath", modulesDir.getPath());
+        append(args, "-d", modulesDir.getPath());
+        append(args, "-source", "7");
+        append(args, "-XDrawDiagnostics");
+
+        String expectPath = null; // path name of expected output file
+        String expectDiag = null; //
+        if (mk == ModuleKind.SINGLE)
+            expectPath = (fk.pkgName.equals("") ? "" : fk.pkgName + "/") + replaceExtn(fk.path, ".class");
+        else if (tk == TestKind.GOOD)
+            expectPath = "m/" + (fk.pkgName.equals("") ? "" : fk.pkgName + "/") + replaceExtn(fk.path, ".class");
+        else if (fk == FileKind.MODULE_INFO)
+            expectPath = "BAD/module-info.class"; // cannot tell bad package dir from module tag dir
+        else
+            expectDiag = "file.in.wrong.directory";
+
+        Set<File> expectFiles = (expectPath == null) ?
+                Collections.<File>emptySet() :
+                Collections.singleton(new File(modulesDir, expectPath));
+
+        compile(args, Arrays.asList(srcFile), expectDiag);
+
+        Set<File> files = listClasses(modulesDir);
+
+        checkEqual("output files", expectFiles, files);
+    }
+
+    <T> void append(List<T> list, T... items) {
+        list.addAll(Arrays.asList(items));
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    String replaceExtn(String path, String extn) {
+        int dot = path.lastIndexOf(".");
+        return path.substring(0, dot) + extn;
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    boolean compile(List<String> opts, List<File> files, String diag) {
+        List<String> argList = new ArrayList<String>(opts);
+        for (File f: files)
+            argList.add(f.getPath());
+        System.err.println("Compile: " + argList);
+        String[] args = argList.toArray(new String[argList.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+
+        if (diag == null) {
+            if (rc == 0)
+                return true;
+            else {
+                error("compilation failed unexpectedly: rc=" + rc);
+                return false;
+            }
+        } else {
+            if (rc == 0) {
+                error("compilation succeeded unexpectedly");
+                return false;
+            } else if (!out.contains(diag)) {
+                error("compilation failed unexpectedly: rc=" + rc);
+                return false;
+            } else {
+                System.err.println("compilation failed as expected");
+                return true;
+            }
+        }
+    }
+
+    Set<File> listClasses(File dir) {
+        Set<File> files = new LinkedHashSet<File>();
+        listClasses(dir, files);
+        return files;
+    }
+    // where
+    private void listClasses(File dir, Set<File> files) {
+        for (File f: dir.listFiles()) {
+            if (f.isDirectory())
+                listClasses(f, files);
+            else if (f.getName().endsWith(".class"))
+                files.add(f);
+        }
+    }
+
+    /**
+     * Create a test file with given content.
+     */
+    File createFile(File dir, String path, String body) throws IOException {
+        File file = new File(dir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+        //throw new Error(msg);
+    }
+
+    int count;
+    int errors;
+    File srcDir;
+    File modulesDir;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModulePermitsAttributeTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,237 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of ModulePermits attribute
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+public class ModulePermitsAttributeTest01 {
+    enum Kind { LIST, DISTINCT };
+
+    public static void main(String[] args) throws Exception {
+        new ModulePermitsAttributeTest01().run();
+    }
+
+    void run() throws Exception {
+        for (Kind k: Kind.values()) {
+            try {
+                test(k);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                errors++;
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(Kind kind) throws Exception {
+        System.err.println("Test " + kind);
+        reset();
+        try {
+            String[] modules = { "M1", "M2.N2", "M3.N3.O3@1.0", "M4@4.0" };
+
+            List<String> permitsList = new ArrayList<String>();
+            for (String m: modules) {
+                test(kind, m, permitsList);
+                permitsList.add(getModuleName(m));
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+            errors++;
+        }
+
+    }
+
+    void test(Kind kind, String moduleId, List<String> permitsList) throws Exception {
+        // do not reset on each test case so that we can reuse the previously
+        // generated module classes
+        count++;
+        File f = createFile(kind, moduleId, permitsList);
+        compile(Arrays.asList(f));
+        checkPermitsAttribute(getModuleName(moduleId), permitsList);
+    }
+
+    File createFile(Kind kind, String moduleId, List<String> permitsList) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append("module " + moduleId + " {");
+        if (permitsList.size() > 0) {
+            switch (kind) {
+                case DISTINCT:
+                    for (String p: permitsList) {
+                        sb.append(" permits " + p + ";");
+                    }
+                    break;
+                case LIST:
+                    String sep = " permits ";
+                    for (String p: permitsList) {
+                        sb.append(sep);
+                        sb.append(p);
+                        sep = ", ";
+                    }
+                    sb.append("; ");
+            }
+        }
+        sb.append(" }");
+        return createFile("module-info.java", sb.toString());
+    }
+
+    private static final char FS = File.separatorChar;
+
+    void checkPermitsAttribute(String moduleName, List<String> permitsList) {
+        String file = "module-info.class";
+        System.err.println("Checking " + file);
+        try {
+            ClassFile cf = ClassFile.read(new File(classesDir, file));
+            ModulePermits_attribute attr =
+                    (ModulePermits_attribute) cf.getAttribute(Attribute.ModulePermits);
+            if (attr == null) {
+                if (permitsList.size() > 0)
+                    error("ModulePermits attribute not found; expected " + permitsList);
+            } else {
+                if (permitsList.size() == 0) {
+                    error("Unexpected module attribute found: " + attr);
+                } else {
+                    ConstantPool cp = cf.constant_pool;
+                    List<String> attrList = new ArrayList<String>();
+                    for (int i = 0; i < attr.permits_length; i++) {
+                        attrList.add(cp.getUTF8Value(attr.permits_table[i]));
+                    }
+                    checkEqual("permits", permitsList, attrList);
+                }
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + file + ": " + e);
+        } catch (IOException e) {
+            error("Error reading " + file + ": " + e);
+        }
+    }
+
+    static String getModuleId(String name, String version) {
+        return (version == null ? name : name + "@" + version);
+    }
+
+    static String getModuleName(String moduleId) {
+        int sep = moduleId.indexOf("@");
+        return (sep == -1 ? moduleId : moduleId.substring(0, sep).trim());
+    }
+
+    static String getModuleVersion(String moduleId) {
+        int sep = moduleId.indexOf("@");
+        return (sep == -1 ? moduleId : moduleId.substring(sep+1).trim());
+    }
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<File> files) {
+        List<String> options = new ArrayList<String>();
+        options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath()));
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Set up empty src and classes directories for a test.
+     */
+    void reset() {
+        resetDir(srcDir);
+        resetDir(classesDir);
+    }
+
+    /**
+     * Set up an empty directory.
+     */
+    void resetDir(File dir) {
+        if (dir.exists())
+            deleteAll(dir);
+        dir.mkdirs();
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents
+    File classesDir = new File("tmp", "classes");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleProvidesAttributeTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,219 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of ModuleProvides attribute
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_ModuleId_info;
+
+
+public class ModuleProvidesAttributeTest01 {
+
+    public static void main(String[] args) throws Exception {
+        new ModuleProvidesAttributeTest01().run();
+    }
+
+    void run() throws Exception {
+        reset();
+        try {
+            String[] modules = { "M1", "M2.N2", "M3.N3.O3@1.0", "M4@4.0" };
+
+            List<String> providesList = new ArrayList<String>();
+            for (String m: modules) {
+                test(m, providesList);
+                providesList.add(m);
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+            errors++;
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(String moduleId, List<String> providesList) throws Exception {
+        // do not reset on each test so that we can reuse the previously
+        // generated module classes
+        count++;
+        File f = createFile(moduleId, providesList);
+        compile(Arrays.asList(f));
+        checkProvidesAttribute(getModuleName(moduleId), providesList);
+    }
+
+    File createFile(String moduleId, List<String> providesList) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append("module " + moduleId);
+        if (providesList.size() > 0) {
+            String sep = " provides ";
+            for (String p: providesList) {
+                sb.append(sep);
+                sb.append(p);
+                sep = ", ";
+            }
+        }
+        sb.append(" { }");
+        return createFile("module-info.java", sb.toString());
+    }
+
+    private static final char FS = File.separatorChar;
+
+    void checkProvidesAttribute(String moduleName, List<String> providesList) {
+        String file = "module-info.class";
+        System.err.println("Checking " + file);
+        try {
+            ClassFile cf = ClassFile.read(new File(classesDir, file));
+            ModuleProvides_attribute attr =
+                    (ModuleProvides_attribute) cf.getAttribute(Attribute.ModuleProvides);
+            if (attr == null) {
+                if (providesList.size() > 0)
+                    error("ModuleProvides attribute not found; expected " + providesList);
+            } else {
+                if (providesList.size() == 0) {
+                    error("Unexpected module attribute found: " + attr);
+                } else {
+                    ConstantPool cp = cf.constant_pool;
+                    List<String> attrList = new ArrayList<String>();
+                    for (int i = 0; i < attr.provides_length; i++) {
+                        CONSTANT_ModuleId_info info = cp.getModuleIdInfo(attr.provides_table[i]);
+                        String name = cp.getUTF8Value(info.name_index);
+                        String version = (info.version_index == 0 ? null : cp.getUTF8Value(info.version_index));
+                        attrList.add(getModuleId(name, version));
+                    }
+                    checkEqual("provides", providesList, attrList);
+                }
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + file + ": " + e);
+        } catch (IOException e) {
+            error("Error reading " + file + ": " + e);
+        }
+    }
+
+    static String getModuleId(String name, String version) {
+        return (version == null ? name : name + "@" + version);
+    }
+
+    static String getModuleName(String moduleId) {
+        int sep = moduleId.indexOf("@");
+        return (sep == -1 ? moduleId : moduleId.substring(0, sep).trim());
+    }
+
+    static String getModuleVersion(String moduleId) {
+        int sep = moduleId.indexOf("@");
+        return (sep == -1 ? moduleId : moduleId.substring(sep+1).trim());
+    }
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<File> files) {
+        List<String> options = new ArrayList<String>();
+        options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath()));
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Set up empty src and classes directories for a test.
+     */
+    void reset() {
+        resetDir(srcDir);
+        resetDir(classesDir);
+    }
+
+    /**
+     * Set up an empty directory.
+     */
+    void resetDir(File dir) {
+        if (dir.exists())
+            deleteAll(dir);
+        dir.mkdirs();
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents
+    File classesDir = new File("tmp", "classes");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleRequiresAttributeTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,280 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of ModuleRequires attribute
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+public class ModuleRequiresAttributeTest01 {
+    enum Flag { PRIVATE, OPTIONAL, LOCAL;
+        static Flag of(String s) {
+            for (Flag f: values()) {
+                if (f.toString().toLowerCase().equals(s))
+                    return f;
+            }
+            return null;
+        }};
+    enum MultiKind { LIST, DISTINCT };
+
+    public static void main(String[] args) throws Exception {
+        new ModuleRequiresAttributeTest01().run();
+    }
+
+    void run() throws Exception {
+        for (int i = 0; i < (1 << Flag.values().length); i++) {
+            Set<Flag> flags = new LinkedHashSet<Flag>();
+            if ((i & 4) != 0) flags.add(Flag.PRIVATE);
+            if ((i & 2) != 0) flags.add(Flag.OPTIONAL);
+            if ((i & 1) != 0) flags.add(Flag.LOCAL);
+            for (MultiKind k: MultiKind.values()) {
+                try {
+                    test(flags, k);
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    errors++;
+                }
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(Set<Flag> flags, MultiKind kind) throws Exception {
+        System.err.println("Test group " + (++group) + " " + flags + " " + kind);
+        srcDir = new File("group" + group + "/src");
+        modulesDir = new File("group" + group + "/modules");
+        resetDirs(srcDir, modulesDir);
+        try {
+            String[] modules = { "M1", "M2.N2", "M3.N3.O3@1.0", "M4@4.0" };
+            List<String> requiresList = new ArrayList<String>();
+            for (String m: modules) {
+                test(flags, kind, m, requiresList);
+                requiresList.add(m);
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+            errors++;
+        }
+
+    }
+
+    void test(Set<Flag> flags, MultiKind kind, String moduleId, List<String> requiresList) throws Exception {
+        // do not reset on each test case so that we can reuse the previously
+        // generated module classes
+        System.err.println("Test " + (++count) + " " + moduleId + " " + requiresList);
+        File f = createFile(flags, kind, moduleId, requiresList);
+        compile(Arrays.asList(f));
+        checkRequiresAttribute(getModuleName(moduleId), flags, requiresList);
+    }
+
+    File createFile(Set<Flag> flags, MultiKind kind, String moduleId, List<String> requiresList) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append("module " + moduleId + " {");
+        if (requiresList.size() > 0) {
+            switch (kind) {
+                case DISTINCT:
+                    for (String p: requiresList) {
+                        sb.append(" requires " + flags2String(flags) + p + ";");
+                    }
+                    break;
+                case LIST:
+                    String sep = " requires " + flags2String(flags);
+                    for (String p: requiresList) {
+                        sb.append(sep);
+                        sb.append(p);
+                        sep = ", ";
+                    }
+                    sb.append("; ");
+            }
+        }
+        sb.append(" }");
+        return createFile("test" + count + "/module-info.java", sb.toString());
+    }
+
+    static String flags2String(Set<Flag> flags) {
+        StringBuilder sb = new StringBuilder();
+        for (Flag f: flags) {
+            sb.append(f.toString().toLowerCase() + " ");
+        }
+        return sb.toString();
+    }
+
+    private static final char FS = File.separatorChar;
+
+    void checkRequiresAttribute(String moduleName, Set<Flag> flags, List<String> requiresList) {
+        String file = "test" + count + "/module-info.class";
+        System.err.println("Checking " + file);
+        try {
+            ClassFile cf = ClassFile.read(new File(modulesDir, file));
+            ModuleRequires_attribute attr =
+                    (ModuleRequires_attribute) cf.getAttribute(Attribute.ModuleRequires);
+            if (attr == null) {
+                if (requiresList.size() > 0)
+                    error("ModuleRequires attribute not found; expected " + flags + " " + requiresList);
+            } else {
+                ConstantPool cp = cf.constant_pool;
+                List<String> attrList = new ArrayList<String>();
+                for (int i = 0; i < attr.requires_length; i++) {
+                    ModuleRequires_attribute.Entry e = attr.requires_table[i];
+		    if (isSynthetic(e, cp))
+			continue;
+                    ConstantPool.CONSTANT_ModuleId_info mid = cp.getModuleIdInfo(e.requires_index);
+                    String mn = cp.getUTF8Value(mid.name_index);
+                    String mvq = (mid.version_index == 0 ? null : cp.getUTF8Value(mid.version_index));
+                    attrList.add(getModuleId(mn, mvq));
+                    Set<Flag> attrFlags = new HashSet<Flag>();
+                    for (int f = 0; f < e.attributes_length; f++)
+                        attrFlags.add(Flag.of(cp.getUTF8Value(e.attributes[f])));
+                    checkEqual("flags", flags, attrFlags);
+                }
+                checkEqual("requires", requiresList, attrList);
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + file + ": " + e);
+        } catch (IOException e) {
+            error("Error reading " + file + ": " + e);
+        }
+    }
+
+    static boolean isSynthetic(ModuleRequires_attribute.Entry e, ConstantPool cp) 
+		throws ConstantPoolException {
+        for (int f = 0; f < e.attributes_length; f++) {
+            if (cp.getUTF8Value(e.attributes[f]).equals("synthetic"))
+		return true;
+   	}
+	return false;
+    }
+
+    static String getModuleId(String name, String version) {
+        return (version == null ? name : name + "@" + version);
+    }
+
+    static String getModuleName(String moduleId) {
+        int sep = moduleId.indexOf("@");
+        return (sep == -1 ? moduleId : moduleId.substring(0, sep).trim());
+    }
+
+    static String getModuleVersion(String moduleId) {
+        int sep = moduleId.indexOf("@");
+        return (sep == -1 ? moduleId : moduleId.substring(sep+1).trim());
+    }
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<File> files) {
+        List<String> argList = new ArrayList<String>();
+        argList.addAll(Arrays.asList("-source", "7", "-d", modulesDir.getPath(), "-modulepath", modulesDir.getPath()));
+        for (File f: files)
+            argList.add(f.getPath());
+
+        String[] args = argList.toArray(new String[argList.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Set up an empty directory.
+     */
+    void resetDir(File dir) {
+        if (dir.exists())
+            deleteAll(dir);
+        dir.mkdirs();
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+        throw new Error();
+    }
+
+    int group;
+    int count;
+    int errors;
+    File srcDir;
+    File modulesDir;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleResolverTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,203 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of module resolution
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * Test compilation of module-info.java on the command line
+ * and interaction with path options.
+ */
+public class ModuleResolverTest01
+{
+    public static void main(String... args) throws Exception {
+        new ModuleResolverTest01().run();
+    }
+
+    public void run() throws Exception {
+        boolean[] values = { false, true };
+        for (boolean modulepath : values) {
+            for (boolean classpath : values) {
+                for (boolean sourcepath : values) {
+                    test(modulepath, classpath, sourcepath);
+                }
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(boolean mp, boolean cp, boolean sp) throws IOException {
+        System.err.println("Test " + (++count) + ": modulepath " + mp + "  classpath " + cp + " sourcepath " + sp);
+
+        File srcDir = new File("test" + count, "src");
+        File classesDir = new File("test" + count, "classes");
+        resetDirs(srcDir, classesDir);
+
+        boolean modular = (mp && !cp);
+
+        String moduleId = "M@1.0";
+        File srcFile = createFile(srcDir,
+                    modular ? "m/module-info.java" : "module-info.java",
+                    "module " + moduleId + " { }");
+
+        List<String> args = new ArrayList<String>();
+        if (cp) append(args, "-classpath", ".");
+        if (sp) append(args, "-sourcepath", ".");
+        if (mp) append(args, "-modulepath", ".");
+        append(args, "-d", classesDir.getPath());
+        append(args, "-source", "7");
+        compile(args, srcFile);
+
+        checkModuleAttribute(classesDir,
+                        modular ? "m/module-info.class" : "module-info.class",
+                        moduleId);
+    }
+
+    void checkModuleAttribute(File dir, String path, String moduleId) throws IOException {
+        System.err.println("Checking " + path);
+        try {
+            ClassFile cf = ClassFile.read(new File(dir, path));
+            Module_attribute attr = (Module_attribute) cf.getAttribute(Attribute.Module);
+            if (attr == null) {
+                if (moduleId != null)
+                    error("Module attribute not found; expected " + moduleId);
+            } else {
+                if (moduleId == null) {
+                    error("Unexpected module attribute found: " + attr);
+                } else {
+                    String name, version;
+                    int sep = moduleId.indexOf("@");
+                    if (sep == -1) {
+                        name = moduleId;
+                        version = null;
+                    } else {
+                        name = moduleId.substring(0, sep);
+                        version = moduleId.substring(sep + 1);
+                    }
+                    ConstantPool cp = cf.constant_pool;
+                    checkEqual("module name", name, attr.getModuleName(cp));
+                    checkEqual("module version", version, attr.getModuleVersion(cp));
+                }
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + path + ": " + e);
+        } catch (FileNotFoundException e) {
+            error("File not found: " + path);
+        } catch (IOException e) {
+            error("Error reading " + path + ": " + e);
+        }
+    }
+
+    void append(List<String> list, String... args) {
+        list.addAll(Arrays.asList(args));
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<String> opts, File... files) {
+        List<String> argList = new ArrayList<String>(opts);
+        for (File f: files)
+            argList.add(f.getPath());
+        System.err.println("Compile: " + argList);
+        String[] args = argList.toArray(new String[argList.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.out.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    /**
+     * Create a test file with given content.
+     */
+    File createFile(File dir, String path, String body) throws IOException {
+        File file = new File(dir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+        throw new Error(msg);
+    }
+
+    int count;
+    int errors;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleResolverTest02.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,229 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of module resolution
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * Test compilation of module-info.java on the command line
+ * and interaction with path options.
+ */
+public class ModuleResolverTest02
+{
+    enum Kind {
+        CMD_LINE,
+        SOURCE_PATH,
+        CLASS_PATH,
+        MODULE_PATH
+    };
+
+    static final String moduleId = "M@1.0";
+
+    public static void main(String... args) throws Exception {
+        new ModuleResolverTest02().run();
+    }
+
+    public void run() throws Exception {
+        setup();
+
+        for (Kind mk: Kind.values()) {
+            for (Kind ak: Kind.values()) {
+                if (mk == Kind.CMD_LINE || ak == Kind.CMD_LINE)
+                    test(mk, ak);
+            }
+        }
+    }
+
+    // Initialize copies of src files and class files to be used in individual tests
+    void setup() throws IOException {
+        File srcDir = new File("ref", "src/m");
+        File classesDir = new File("ref", "modules/m");
+        resetDirs(srcDir, classesDir);
+
+        File miFile = createFile(srcDir, "module-info.java", "module " + moduleId + " { }");
+        File aFile  = createFile(srcDir, "p/A.java",         "package p; class A { }");
+
+        List<String> args = new ArrayList<String>();
+        append(args, "-d", classesDir.getPath());
+        append(args, "-source", "7");
+        compile(args, miFile, aFile);
+    }
+
+    void test(Kind mk, Kind ak) throws IOException {
+        System.err.println("Test " + (++count) + ": module_info " + mk + "  class A " + ak);
+        File testDir = new File("test" + count);
+        File testOutDir = new File(testDir, "out");
+        testOutDir.mkdirs();
+
+        List<String> args = new ArrayList<String>();
+        List<File> files = new ArrayList<File>();
+
+        boolean multiModuleMode = (mk == Kind.MODULE_PATH || ak == Kind.MODULE_PATH);
+
+        setup(testDir, mk, "module-info", args, files, multiModuleMode);
+        setup(testDir, ak, "p/A", args, files, multiModuleMode);
+        append(args, "-source", "7");
+        append(args, "-d", testOutDir.getPath());
+
+        compile(args, files.toArray(new File[files.size()]));
+
+        List<File> expect = new ArrayList<File>();
+        if (ak == Kind.CMD_LINE)
+            expect.add(new File(testOutDir, (multiModuleMode ? "m/" : "") + "p/A.class"));
+        if (mk == Kind.CMD_LINE || mk == Kind.SOURCE_PATH)
+            expect.add(new File(testOutDir, (multiModuleMode ? "m/" : "") + "module-info.class"));
+
+        for (File f: expect) {
+            if (!f.exists())
+                error("File not found: " + f);
+        }
+    }
+
+    void setup(File testDir, Kind kind, String base,
+            List<String> compileArgs, List<File> compileFiles,
+            boolean multiModuleMode)
+            throws IOException {
+
+        switch (kind) {
+            case CMD_LINE:
+                compileFiles.add(new File("ref/src/m/" + base + ".java"));
+                break;
+            case SOURCE_PATH:
+                copy("src/m/" + base + ".java", testDir);
+                compileArgs.add("-sourcepath");
+                compileArgs.add(testDir + "/src" + (multiModuleMode ? "" : "/m"));
+                break;
+            case CLASS_PATH:
+                copy("modules/m/" + base + ".class", testDir);
+                compileArgs.add("-classpath");
+                compileArgs.add(testDir + "/modules/m");
+                break;
+            case MODULE_PATH:
+                copy("modules/m/" + base + ".class", testDir);
+                compileArgs.add("-modulepath");
+                compileArgs.add(testDir + "/modules");
+                break;
+        }
+    }
+
+    void copy(String path, File dest) throws IOException {
+        File from = new File("ref", path);
+        byte[] data = new byte[(int) from.length()];
+        DataInputStream in = new DataInputStream(new FileInputStream(from));
+        in.readFully(data);
+        in.close();
+
+        File to = new File(dest, path);
+        to.getParentFile().mkdirs();
+        OutputStream out = new FileOutputStream(to);
+        out.write(data);
+        out.close();
+    }
+
+    void append(List<String> list, String... args) {
+        list.addAll(Arrays.asList(args));
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<String> opts, File... files) {
+        List<String> argList = new ArrayList<String>(opts);
+        for (File f: files)
+            argList.add(f.getPath());
+        System.err.println("Compile: " + argList);
+        String[] args = argList.toArray(new String[argList.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    /**
+     * Create a test file with given content.
+     */
+    File createFile(File dir, String path, String body) throws IOException {
+        File file = new File(dir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.out.println("error: " + msg);
+        for (String s: more)
+            System.out.println(s);
+        errors++;
+        throw new Error(msg);
+    }
+
+    int count;
+    int errors;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleResolverTest03.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,316 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of Module Resolver
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class ModuleResolverTest03 {
+    static class Test {
+        Test(String desc, Unit... units) {
+            this.desc = desc;
+            this.units = units;
+        }
+        final String desc;
+        final Unit[] units;
+    };
+
+    // uugh can't static import these because this class is in unnamed package
+    Unit.Kind CMDLINE = Unit.Kind.CMDLINE;
+    Unit.Kind SRCPATH = Unit.Kind.SRCPATH;
+
+    static class Unit {
+        enum Kind { CMDLINE, SRCPATH };
+        Unit(Kind kind, String path, String text) {
+            this.kind = kind;
+            this.path = path;
+            this.text = text;
+        }
+        final Kind kind;
+        final String path;
+        final String text;
+    }
+
+    Test[] tests = {
+        new Test(
+            "no versions; expect m1, m3, m5",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m5; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4 { }"),
+            new Unit(SRCPATH, "m4/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5 { }"),
+            new Unit(SRCPATH, "m5/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "no versions; provides; expect m1, m3, m5",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module mX provides m3 { requires m5; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4 { }"),
+            new Unit(SRCPATH, "m4/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5 { }"),
+            new Unit(SRCPATH, "m5/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "no version in requires; single versions available; expect m1@1.0, m3@1.0, m5@1.0",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1@1.0 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2@1.0 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module m3@1.0 { requires m5; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4@1.0 { }"),
+            new Unit(SRCPATH, "m4/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5@1.0 { }"),
+            new Unit(SRCPATH, "m5/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "version in requires; multiple versions available; expect m1@1.0, m3@1.0, m5@1.0",
+            new Unit(CMDLINE, "m11/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m11/module-info.java", "module m1@1.0 { requires m3@1.0; }"),
+            new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { requires m4@1.0; }"),
+            new Unit(SRCPATH, "m21/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 { requires m4@2.0; }"),
+            new Unit(SRCPATH, "m22/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m31/module-info.java", "module m3@1.0 { requires m5@1.0; }"),
+            new Unit(SRCPATH, "m32/module-info.java", "module m3@2.0 { requires m5@2.0; }"),
+            new Unit(SRCPATH, "m41/module-info.java", "module m4@1.0 { }"),
+            new Unit(SRCPATH, "m41/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m42/module-info.java", "module m4@2.0 { }"),
+            new Unit(SRCPATH, "m42/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m51/module-info.java", "module m5@1.0 { }"),
+            new Unit(SRCPATH, "m51/q/B.java",         "package q; public class B { }"),
+            new Unit(SRCPATH, "m52/module-info.java", "module m5@2.0 { }"),
+            new Unit(SRCPATH, "m52/q/B.java",         "ERROR")
+        ),
+
+        new Test(
+            "no versions, simple cycle (m3,m5); expect m1, m3, m5",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m5; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4 { }"),
+            new Unit(SRCPATH, "m4/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m3;}"),
+            new Unit(SRCPATH, "m5/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "no versions, bigger cycle (m3,m4,m5); expect m1, m3, m4, m5",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m4; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4 { requires m5; }"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m3;}"),
+            new Unit(SRCPATH, "m5/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "no versions, two cycles (m3,m4),(m5,m6); expect m1, m3, m4, m5,m6",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m4; requires m5; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4 { requires m3; }"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m6;}"),
+            new Unit(SRCPATH, "m6/module-info.java", "module m6 { requires m5;}"),
+            new Unit(SRCPATH, "m6/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "no versions, complex cycle (m3,m4,m5,m6); expect m1, m3, m4, m5,m6",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m3; }"),
+            new Unit(SRCPATH, "m2/module-info.java", "module m2 { requires m4; }"),
+            new Unit(SRCPATH, "m2/q/B.java",         "ERROR"),
+            new Unit(SRCPATH, "m3/module-info.java", "module m3 { requires m4; requires m5; }"),
+            new Unit(SRCPATH, "m4/module-info.java", "module m4 { requires m3; }"),
+            new Unit(SRCPATH, "m5/module-info.java", "module m5 { requires m6;}"),
+            new Unit(SRCPATH, "m6/module-info.java", "module m6 { requires m3; requires m5;}"),
+            new Unit(SRCPATH, "m6/q/B.java",         "package q; public class B { }")
+        ),
+    };
+
+    public static void main(String[] args) throws Exception {
+        new ModuleResolverTest03().run();
+    }
+
+    void run() throws Exception {
+        for (Test test: tests) {
+            try {
+                test(test);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                errors++;
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(Test t) throws IOException {
+        System.err.println("Test " + (++count) + " " + t.desc);
+
+        File testDir = new File("test" + count);
+        srcDir = new File(testDir, "src");
+        modulesDir = new File(testDir, "modules");
+        resetDirs(srcDir, modulesDir);
+
+        List<String> opts = new ArrayList<String>();
+        add(opts, "-source", "7");
+        add(opts, "-modulepath", modulesDir.getPath());
+        add(opts, "-d", modulesDir.getPath());
+
+        boolean srcPath = false;
+        List<File> files = new ArrayList<File>();
+
+        for (Unit u: t.units) {
+            File f = createFile(u.path, u.text);
+            switch (u.kind) {
+                case CMDLINE: files.add(f); break;
+                case SRCPATH: srcPath = true; break;
+            }
+        }
+
+        if (srcPath)
+            add(opts, "-sourcepath", srcDir.getPath());
+
+        compile(opts, files);
+
+        for (Unit u: t.units) {
+            File f = new File(modulesDir, replaceExtension(u.path, ".class"));
+            if (u.text.equals("ERROR")) {
+                if (f.exists())
+                    error("unexpected output found: " + f);
+            } else {
+                if (!f.exists())
+                    error("expected file not found: " + f);
+            }
+        }
+    }
+
+    <T> void add(List<T> list, T... items) {
+        for (T t: items)
+            list.add(t);
+    }
+
+    String replaceExtension(String path, String extn) {
+        int dot = path.lastIndexOf(".");
+        return path.substring(0, dot) + extn;
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<String> opts, List<File> files) {
+        List<String> argList = new ArrayList<String>();
+        argList.addAll(opts);
+        for (File f: files)
+            argList.add(f.getPath());
+
+        System.err.println("compile: " + argList);
+
+        String[] args = argList.toArray(new String[argList.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir;
+    File modulesDir;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleResolverTest04.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,257 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test basic use of Module Resolver
+ */
+
+import java.io.*;
+import java.util.*;
+
+public class ModuleResolverTest04 {
+    static class Test {
+        Test(String desc, String diag, Unit... units) {
+            this.desc = desc;
+            this.diag = diag;
+            this.units = units;
+        }
+        final String desc;
+        final String diag;
+        final Unit[] units;
+    };
+
+    // uugh can't static import these because this class is in unnamed package
+    Unit.Kind CMDLINE = Unit.Kind.CMDLINE;
+    Unit.Kind SRCPATH = Unit.Kind.SRCPATH;
+
+    static class Unit {
+        enum Kind { CMDLINE, SRCPATH };
+        Unit(Kind kind, String path, String text) {
+            this.kind = kind;
+            this.path = path;
+            this.text = text;
+        }
+        final Kind kind;
+        final String path;
+        final String text;
+    }
+
+    Test[] tests = {
+        new Test(
+            "no version available",
+            "compiler.err.mdl.no.version.available",
+            new Unit(CMDLINE, "m1/p/A.java",         "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java", "module m1 { requires m2; }"),
+            new Unit(SRCPATH, "m1/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "no unique version available",
+            "compiler.err.mdl.no.unique.version.available",
+            new Unit(CMDLINE, "m1/p/A.java",          "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java",  "module m1 { requires m2; }"),
+            new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { }"),
+            new Unit(SRCPATH, "m21/q/B.java",         "package q; public class B { }"),
+            new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 { }"),
+            new Unit(SRCPATH, "m22/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "required version not available",
+            "compiler.err.mdl.required.version.not.available",
+            new Unit(CMDLINE, "m1/p/A.java",          "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java",  "module m1 { requires m2@3.0; }"),
+            new Unit(SRCPATH, "m21/module-info.java", "module m2@1.0 { }"),
+            new Unit(SRCPATH, "m22/module-info.java", "module m2@2.0 { }")
+        ),
+
+        new Test(
+            "duplicate versions available",
+            "compiler.err.mdl.duplicate.definition",
+            new Unit(CMDLINE, "m1/p/A.java",           "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java",   "module m1 { requires m2; }"),
+            new Unit(SRCPATH, "m21a/module-info.java", "module m2@1.0 { }"),
+            new Unit(SRCPATH, "m21a/q/B.java",         "package q; public class B { }"),
+            new Unit(SRCPATH, "m21b/module-info.java", "module m2@1.0 { }"),
+            new Unit(SRCPATH, "m22a/q/B.java",         "package q; public class B { }")
+        ),
+
+        new Test(
+            "duplicate versions available (provides)",
+            "compiler.err.mdl.duplicate.definition",
+            new Unit(CMDLINE, "m1/p/A.java",           "package p; class A { q.B b; }"),
+            new Unit(SRCPATH, "m1/module-info.java",   "module m1 { requires m2@1.0; }"),
+            new Unit(SRCPATH, "m21/module-info.java",  "module m2@1.0 { }"),
+            new Unit(SRCPATH, "m21/q/B.java",          "package q; public class B { }"),
+            new Unit(SRCPATH, "m22/module-info.java",  "module m2@2.0 provides m2@1.0 { }"),
+            new Unit(SRCPATH, "m22/q/B.java",          "package q; public class B { }")
+        )
+    };
+
+    public static void main(String[] args) throws Exception {
+        new ModuleResolverTest04().run();
+    }
+
+    void run() throws Exception {
+        for (Test test: tests) {
+            try {
+                test(test);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                errors++;
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(Test t) throws IOException {
+        System.err.println("Test " + (++count) + " " + t.desc);
+
+        File testDir = new File("test" + count);
+        srcDir = new File(testDir, "src");
+        modulesDir = new File(testDir, "modules");
+        resetDirs(srcDir, modulesDir);
+
+        List<String> opts = new ArrayList<String>();
+        add(opts, "-source", "7");
+        add(opts, "-modulepath", modulesDir.getPath());
+        add(opts, "-d", modulesDir.getPath());
+        add(opts, "-XDrawDiagnostics");
+
+        boolean srcPath = false;
+        List<File> files = new ArrayList<File>();
+
+        for (Unit u: t.units) {
+            File f = createFile(u.path, u.text);
+            switch (u.kind) {
+                case CMDLINE: files.add(f); break;
+                case SRCPATH: srcPath = true; break;
+            }
+        }
+
+        if (srcPath)
+            add(opts, "-sourcepath", srcDir.getPath());
+
+        compile(opts, files, t.diag);
+
+        for (File f: modulesDir.listFiles()) {
+            error("unexpected file found: " + f);
+        }
+    }
+
+    <T> void add(List<T> list, T... items) {
+        for (T t: items)
+            list.add(t);
+    }
+
+    String replaceExtension(String path, String extn) {
+        int dot = path.lastIndexOf(".");
+        return path.substring(0, dot) + extn;
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<String> opts, List<File> files, String diag) {
+        List<String> argList = new ArrayList<String>();
+        argList.addAll(opts);
+        for (File f: files)
+            argList.add(f.getPath());
+
+        System.err.println("compile: " + argList);
+
+        String[] args = argList.toArray(new String[argList.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(args, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+
+        if (rc == 0)
+            throw new Error("compilation succeeded unexpectedly");
+        else if (!out.contains(diag))
+            throw new Error("compilation failed unexpectedly: rc=" + rc);
+        else
+            System.err.println("compilation failed as expected");
+    }
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty directories.
+     */
+    void resetDirs(File... dirs) {
+        for (File dir: dirs) {
+            if (dir.exists())
+                deleteAll(dir);
+            dir.mkdirs();
+        }
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir;
+    File modulesDir;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/modules/ModuleVersionTest01.java	Fri Nov 06 13:20:18 2009 -0800
@@ -0,0 +1,215 @@
+/*
+ * 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
+ * @bug 6802521
+ * @summary add support for modules: test version strings
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+public class ModuleVersionTest01 {
+    String[] values = {
+        "0",
+        "1",
+        "2.3",
+        "3.4alpha",
+        "(2:3]",
+        "[3:4]",
+        "<1",
+        "=2",
+        ">3",
+        "\"alpha\"",
+        "\"alpha beta\"",
+        "\"alpha,beta\""
+    };
+
+
+    public static void main(String[] args) throws Exception {
+        new ModuleVersionTest01().run();
+    }
+
+    void run() throws Exception {
+        for (String v: values) {
+            try {
+                System.err.println("Test " + v);
+                test(v);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                errors++;
+            }
+        }
+
+        if (errors == 0)
+            System.out.println(count + " tests passed");
+        else
+            throw new Exception(errors + "/" + count + " tests failed");
+    }
+
+    void test(String version) throws Exception {
+        count++;
+        reset();
+        List<File> files = new ArrayList<File>();
+        addFile(files, createFile("module-info.java", "module M @ " + version + " { }"));
+        compile(files);
+        String moduleId = "M@" + unquote(version);
+        checkModuleAttribute("module-info.class", moduleId);
+    }
+
+    String unquote(String v) {
+        if (v.startsWith("\"") && v.endsWith("\""))
+            return v.substring(1, v.length() - 1);
+        else
+            return v;
+    }
+
+    void checkModuleAttribute(String file, String moduleId) throws IOException {
+        System.err.println("Checking " + file);
+        try {
+            ClassFile cf = ClassFile.read(new File(classesDir, file));
+            Module_attribute attr = (Module_attribute) cf.getAttribute(Attribute.Module);
+            if (attr == null) {
+                if (moduleId != null)
+                    error("Module attribute not found; expected " + moduleId);
+            } else {
+                if (moduleId == null) {
+                    error("Unexpected module attribute found: " + attr);
+                } else {
+                    String name, version;
+                    int sep = moduleId.indexOf("@");
+                    if (sep == -1) {
+                        name = moduleId;
+                        version = null;
+                    } else {
+                        name = moduleId.substring(0, sep);
+                        version = moduleId.substring(sep + 1);
+                    }
+                    ConstantPool cp = cf.constant_pool;
+                    checkEqual("module name", name, attr.getModuleName(cp));
+                    checkEqual("module version", version, attr.getModuleVersion(cp));
+                }
+            }
+        } catch (ConstantPoolException e) {
+            error("Error accessing constant pool " + file + ": " + e);
+        } catch (IOException e) {
+            error("Error reading " + file + ": " + e);
+        }
+    }
+
+    <T> void checkEqual(String tag, T expect, T found) {
+        if (expect == null ? found == null : expect.equals(found))
+            return;
+        error(tag + " mismatch", "expected " + expect, "found: " + found);
+    }
+
+    /**
+     * Compile a list of files.
+     */
+    void compile(List<File> files) {
+        List<String> options = new ArrayList<String>();
+        options.addAll(Arrays.asList("-source", "7", "-d", classesDir.getPath()));
+        for (File f: files)
+            options.add(f.getPath());
+
+        String[] opts = options.toArray(new String[options.size()]);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javac.Main.compile(opts, pw);
+        pw.close();
+
+        String out = sw.toString();
+        if (out.trim().length() > 0)
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("compilation failed: rc=" + rc);
+    }
+
+    /**
+     * Add a file to a list if the file is not null.
+     */
+    void addFile(List<File> files, File file) {
+        if (file != null)
+            files.add(file);
+    }
+
+
+    /**
+     * Create a test file with given content if the content is not null.
+     */
+    File createFile(String path, String body) throws IOException {
+        if (body == null)
+            return null;
+        File file = new File(srcDir, path);
+        file.getAbsoluteFile().getParentFile().mkdirs();
+        FileWriter out = new FileWriter(file);
+        out.write(body);
+        out.close();
+        return file;
+    }
+
+    /**
+     * Set up empty src and classes directories for a test.
+     */
+    void reset() {
+        resetDir(srcDir);
+        resetDir(classesDir);
+    }
+
+    /**
+     * Set up an empty directory.
+     */
+    void resetDir(File dir) {
+        if (dir.exists())
+            deleteAll(dir);
+        dir.mkdirs();
+    }
+
+    /**
+     * Delete a file or a directory (including all its contents).
+     */
+    boolean deleteAll(File file) {
+        if (file.isDirectory()) {
+            for (File f: file.listFiles())
+                deleteAll(f);
+        }
+        return file.delete();
+    }
+
+    /**
+     * Report an error.
+     */
+    void error(String msg, String... more) {
+        System.err.println("error: " + msg);
+        for (String s: more)
+            System.err.println(s);
+        errors++;
+    }
+
+    int count;
+    int errors;
+    File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents
+    File classesDir = new File("tmp", "classes");
+}