changeset 10:23bff1275c4d

Added support for a new kind of Java programing component: the module, contributed by: leonid.kuskov@oracle.com
author afedorch
date Fri, 06 Oct 2017 15:15:23 -0700
parents 00021c8bcd23
children f2cacbad3e0c
files .hgignore README.html build/productinfo.properties src/org/openjdk/asmtools/common/Module.java src/org/openjdk/asmtools/jasm/CFVersion.java src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java src/org/openjdk/asmtools/jasm/ClassData.java src/org/openjdk/asmtools/jasm/CodeAttr.java src/org/openjdk/asmtools/jasm/ConstantPool.java src/org/openjdk/asmtools/jasm/Constants.java src/org/openjdk/asmtools/jasm/JasmTokens.java src/org/openjdk/asmtools/jasm/Main.java src/org/openjdk/asmtools/jasm/Modifiers.java src/org/openjdk/asmtools/jasm/ModuleAttr.java src/org/openjdk/asmtools/jasm/Parser.java src/org/openjdk/asmtools/jasm/ParserAnnotation.java src/org/openjdk/asmtools/jasm/ParserCP.java src/org/openjdk/asmtools/jasm/RuntimeConstants.java src/org/openjdk/asmtools/jasm/Scanner.java src/org/openjdk/asmtools/jasm/Tables.java src/org/openjdk/asmtools/jasm/i18n.properties src/org/openjdk/asmtools/jcdec/Main.java src/org/openjdk/asmtools/jcoder/JcodTokens.java src/org/openjdk/asmtools/jcoder/Jcoder.java src/org/openjdk/asmtools/jcoder/Main.java src/org/openjdk/asmtools/jcoder/Scanner.java src/org/openjdk/asmtools/jcoder/i18n.properties src/org/openjdk/asmtools/jdec/ClassData.java src/org/openjdk/asmtools/jdec/Main.java src/org/openjdk/asmtools/jdis/ClassData.java src/org/openjdk/asmtools/jdis/CodeData.java src/org/openjdk/asmtools/jdis/ConstantPool.java src/org/openjdk/asmtools/jdis/Main.java src/org/openjdk/asmtools/jdis/ModuleData.java src/org/openjdk/asmtools/jdis/StackMapData.java src/org/openjdk/asmtools/jdis/i18n.properties src/org/openjdk/asmtools/jdis/iAtt.java
diffstat 37 files changed, 2817 insertions(+), 2296 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Jun 15 12:47:32 2016 -0600
+++ b/.hgignore	Fri Oct 06 15:15:23 2017 -0700
@@ -5,3 +5,4 @@
 re:.*\.pyc$
 re:.*\.swp$
 re:.*\.DS_Store$
+re:.*\iml$
--- a/README.html	Wed Jun 15 12:47:32 2016 -0600
+++ b/README.html	Fri Oct 06 15:15:23 2017 -0700
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <!--
 
-  Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+  Copyright (c) 2008, 2017, Oracle and/or its affiliates. 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
@@ -106,7 +106,7 @@
       <h1>Release Notes</h1>
       <h2>AsmTools</h2>
       </h2>
-      <h2>November 2014</h2>
+      <h2>October 2017</h2>
       </center>
       </td>
     </tr>
@@ -190,7 +190,7 @@
 <p>
 Using ASM Tools requires a properly configured, certified Java
 Platform, Standard Edition (Java SE&#8482; platform) runtime environment
-version 1.7 or later, or a Java SE platform 7.0 runtime environment.
+version 1.8 or later, or a Java SE platform 8.0 runtime environment.
 </p>
 <p class="nav-link">[<a href="#_top">Top</a>]</p>
 <a name="installation"></a>
@@ -316,9 +316,9 @@
 <p><a name="building" id="building"></a></p>
 <h2>Building the Sources</h2>
 <p>
-Building the sources requires Ant version 1.8 or later (1.8.2 is current at the
+Building the sources requires Ant version 1.8 or later (1.10.1 is current at the
 time of writing), and the built-in build is compatible with using an IDE.
-The sources are designed for Java 7 and if you invoke <code>ant</code> with this
+The sources are designed for Java 8 and if you invoke <code>ant</code> with this
 runtime, your chance of encountering an abnormal conditions due to your runtime
 or compiler (or javadoc) version.
 </p>
@@ -328,7 +328,7 @@
 </p>
 <ul>
 <li>ant, version 1.8 or later
-<li>Java 7 runtime and compiler (minimum and recommended)
+<li>Java 8 runtime and compiler (minimum and recommended)
 <li>10MB free disk space (3MB for source tree, 7MB for build output)
 </ul>
 
@@ -348,7 +348,7 @@
 installation of Java on your machine:
 </p>
 <pre>
-# JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_10.jdk/Contents/Home ANTHOME=/usr/share/ant ant
+# JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home ANTHOME=/usr/share/ant ant
 </pre>
 This example for common *nix shells (<code>zsh, bash, sh</code>), alter it as needed for your
 command environment.  You can test your invocation of <code>ant</code> by running it with
@@ -368,7 +368,7 @@
 <hr>
 
 <hr noshade="noshade">
-<p><a href="legal/copyright.txt">Copyright</a> &copy; 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+<p><a href="legal/copyright.txt">Copyright</a> &copy; 2008, 2017, Oracle and/or its affiliates. All rights reserved.
     Use is subject to license terms.The majority of the Assember Tools project is released under the <A
         HREF="http://openjdk.java.net/legal/gplv2+ce.html">GNU
         General Public License Version 2 (GPLv2)</A></p>
--- a/build/productinfo.properties	Wed Jun 15 12:47:32 2016 -0600
+++ b/build/productinfo.properties	Fri Oct 06 15:15:23 2017 -0700
@@ -1,4 +1,4 @@
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. 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
@@ -26,6 +26,6 @@
 PRODUCT_NAME        = asmtools
 PRODUCT_JAR_NAME    = asmtools.jar
 PRODUCT_VERSION     = 6.0
-PRODUCT_MILESTONE   = beta
+PRODUCT_MILESTONE   = fcs
 PRODUCT_BUILDNUMBER = b01
 PRODUCT_NAME_LONG   = Java Assembler Tools
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openjdk/asmtools/common/Module.java	Fri Oct 06 15:15:23 2017 -0700
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.asmtools.common;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static java.lang.String.format;
+
+/**
+ * Internal presentation of a module
+ */
+public final class Module {
+
+  //* A module name and module_flags
+  public final Header header;
+  //* A service dependence's of this module
+  public final Set<Uses> uses;
+  //* Modules on which the current module has a dependence.
+  public final Set<Dependence> requires;
+  //* A module exports, may be qualified or unqualified.
+  public final Map<Exported, Set<String>> exports;
+  //* Packages, to be opened by the current module
+  public final Map<Opened, Set<String>> opens;
+  //* A service that a module provides one or more implementations of.
+  public final Map<Provided, Set<String>> provides;
+
+  private Module(Builder builder) {
+    this.header = builder.header;
+    this.requires = Collections.unmodifiableSet(builder.requires);
+    this.exports = Collections.unmodifiableMap(builder.exports);
+    this.opens = Collections.unmodifiableMap(builder.opens);
+    this.uses = Collections.unmodifiableSet(builder.uses);
+    this.provides = Collections.unmodifiableMap(builder.provides);
+  }
+
+  public String getModuleFlags () {
+    return Modifier.getModuleModifiers(header.getFlags());
+  }
+  public String getModuleName () { return header.getModuleName();  }
+  public String getModuleVersion()  { return header.getModuleVersion(); };
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    int l = 0;
+    requires.stream()
+        .sorted()
+        .forEach(d -> sb.append(format("  requires %s;%s%n",
+            d.toString(),
+            d.getModuleVersion() == null ? "" : " // @" + d.getModuleVersion())));
+    //
+    l = newLine(sb,l);
+    exports.entrySet().stream()
+        .filter(e -> e.getValue().isEmpty())
+        .sorted(Map.Entry.comparingByKey())
+        .map(e -> format("  exports %s;%n", e.getKey().toString()))
+        .forEach(sb::append);
+    exports.entrySet().stream()
+        .filter(e -> !e.getValue().isEmpty())
+        .sorted(Map.Entry.comparingByKey())
+        .map(e -> format("  exports %s to%n%s;%n", e.getKey().toString(),
+            e.getValue().stream().sorted()
+                .map(mn -> format("          %s", mn))
+                .collect(Collectors.joining(",\n"))))
+        .forEach(sb::append);
+    //
+    l = newLine(sb,l);
+    opens.entrySet().stream()
+        .filter(e -> e.getValue().isEmpty())
+        .sorted(Map.Entry.comparingByKey())
+        .map(e -> format("  opens %s;%n", e.getKey().toString()))
+        .forEach(sb::append);
+    opens.entrySet().stream()
+        .filter(e -> !e.getValue().isEmpty())
+        .sorted(Map.Entry.comparingByKey())
+        .map(e -> format("  opens %s to%n%s;%n", e.getKey().toString(),
+            e.getValue().stream().sorted()
+                .map(mn -> format("          %s", mn))
+                .collect(Collectors.joining(",\n"))))
+        .forEach(sb::append);
+    //
+    l = newLine(sb,l);
+    uses.stream().sorted()
+        .map(s -> format("  uses %s;%n", s))
+        .forEach(sb::append);
+    //
+    l = newLine(sb,l);
+    provides.entrySet().stream()
+        .filter(e -> !e.getValue().isEmpty())
+        .sorted(Map.Entry.comparingByKey())
+        .map(e -> format("  provides %s with%n%s;%n", e.getKey().toString(),
+            e.getValue().stream().sorted()
+                .map(mn -> format("          %s", mn))
+                .collect(Collectors.joining(",\n"))))
+        .forEach(sb::append);
+    //
+    if( Character.isWhitespace(sb.charAt(sb.length()-1)) )
+      sb.deleteCharAt(sb.length()-1);
+    return sb.toString();
+  }
+
+  private int newLine(StringBuilder sb, int length) {
+    if(sb.length() > length) {
+      sb.append("\n");
+      return sb.length() + 1;
+    }
+    return length;
+  }
+
+  /**
+   * Modules flags
+   */
+  public enum Modifier {
+    ACC_NONE(0x0000, "", ""),
+    ACC_OPEN(0x0020, "open", "ACC_OPEN"),
+    ACC_TRANSITIVE(0x0020, "transitive", "ACC_TRANSITIVE"),
+    ACC_STATIC_PHASE(0x0040, "static", "ACC_STATIC_PHASE"),
+    ACC_SYNTHETIC(0x1000, "", "ACC_SYNTHETIC"),
+    ACC_MANDATED(0x8000, "", "ACC_MANDATED");
+    private final int value;
+    private final String keyword;
+    private final String flag;
+    Modifier(int value, String keyword, String flagName) {
+      this.value = value;
+      this.keyword = keyword;
+      this.flag = flagName;
+    }
+
+    public int asInt() { return value; }
+
+    public static String getModuleModifiers(int flag) {
+      return asString(flag, false, ACC_TRANSITIVE);
+    }
+
+    public static String getModuleFlags(int flag) {
+      return asString(flag, true, ACC_TRANSITIVE);
+    }
+
+    public static String getStatementModifiers(int flag) {
+      return asString(flag, false, ACC_OPEN);
+    }
+
+    public static String getStatementFlags(int flag) {
+      return asString(flag, true, ACC_OPEN);
+    }
+
+    private static String asString(int value, boolean flagFormat, Modifier skipped ) {
+      String buf = "";
+      for(Module.Modifier m : values()) {
+        if( m != skipped && (value & m.value) != 0) {
+          buf += ((flagFormat) ? m.flag : m.keyword) + " ";
+          value ^= m.value;
+        }
+      }
+      if( flagFormat && value != 0 )
+        buf += String.format("0x%04X ", value);
+      return buf;
+    }
+  }
+
+  // A module header consists of a module name and module flags
+  public final static class Header extends VersionedFlaggedTargetType{
+    Header(String typeName, int flag) { this(typeName, flag, null); }
+    Header(String typeName, int flag, String moduleVersion) { super(typeName, flag, moduleVersion); }
+    public String getModuleName()    { return getTypeName(); }
+    public int    getModuleFlags()   { return getFlags();    }
+    public String getModuleVersion() { return getVersion();  }
+  }
+
+  //* A module on which the current module has a dependence.
+  public final static class Dependence extends VersionedFlaggedTargetType {
+    public Dependence(String moduleName, int flag) {this(moduleName, flag, null);}
+    public Dependence(String moduleName, int flag, String moduleVersion) {super(moduleName, flag, moduleVersion);}
+    public Dependence(String moduleName, boolean transitive, boolean staticPhase) { this(moduleName,transitive,staticPhase,null);}
+    public Dependence(String moduleName, boolean transitive, boolean staticPhase, String moduleVersion) {
+      this(moduleName,
+          (transitive ? Modifier.ACC_TRANSITIVE.value : Modifier.ACC_NONE.value) |
+          (staticPhase ? Modifier.ACC_STATIC_PHASE.value : Modifier.ACC_NONE.value), moduleVersion);
+    }
+    public String getModuleVersion()          { return getVersion();  }
+  }
+
+  public final static class Uses extends TargetType {
+    public Uses(String typeName) { super(typeName); }
+  }
+
+  //* A provided type of the current module.
+  public final static class Provided extends TargetType {
+    public Provided(String typeName) { super(typeName); }
+  }
+
+  //* An opened package of the current module.
+  public final static class Opened extends FlaggedTargetType {
+    public Opened(String typeName) {
+      super(typeName, 0);
+    }
+    public Opened(String typeName, int opensFlags) {
+      super(typeName, opensFlags);
+    }
+  }
+
+  //* An exported package of the current module.
+  public final static class Exported extends FlaggedTargetType {
+    public Exported(String typeName) {
+      super(typeName, 0);
+    }
+
+    public Exported(String typeName, int exportsFlags) {
+      super(typeName, exportsFlags);
+    }
+  }
+
+  public static class VersionedFlaggedTargetType extends FlaggedTargetType {
+    private String version;
+
+    VersionedFlaggedTargetType(String typeName, int flag) {
+      this(typeName,flag, null);
+    }
+
+    VersionedFlaggedTargetType(String typeName, int flag, String version) {
+      super(typeName, flag);
+      this.version = version != null && !version.isEmpty() ? version : null;
+    }
+    public String getVersion() { return version; }
+
+    @Override
+    public int hashCode() {
+      int code = version == null ? 0 : version.hashCode();
+      return code + super.hashCode();
+    }
+  }
+
+  public static class FlaggedTargetType extends TargetType {
+    private int flag;
+
+    FlaggedTargetType(String typeName, int flag) {
+      super(typeName);
+      this.flag = flag;
+    }
+
+    public boolean isFlagged() {
+      return true;
+    }
+
+    public int getFlags() {
+      return flag;
+    }
+
+    public void setFlag(int value) { flag = value; }
+
+    @Override
+    public int hashCode() {
+      return super.hashCode() + flag;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return super.equals(o) && ((FlaggedTargetType) o).flag == this.flag;
+    }
+
+    @Override
+    public String toString() {
+      return Modifier.getStatementModifiers(this.flag)+ super.toString();
+    }
+  }
+
+  public static class TargetType implements Comparable<TargetType> {
+    private String typeName;
+
+    TargetType(String typeName) { this.typeName = typeName; }
+
+    public String getTypeName() {
+      return typeName;
+    }
+
+    public void setTypeName(String value) { typeName = value; }
+
+    public boolean isFlagged() {
+      return false;
+    }
+
+    @Override
+    public int hashCode() { return typeName.hashCode() * 11; }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o instanceof TargetType) {
+        TargetType t = (TargetType) o;
+        return this.typeName.equals(t.getTypeName());
+      }
+      return false;
+    }
+
+    @Override
+    public int compareTo(TargetType t) {
+      return this.typeName.compareTo(t.getTypeName());
+    }
+
+    @Override
+    public String toString() {
+      return typeName;
+    }
+  }
+
+  /**
+   * The module builder.
+   */
+  public static final class Builder {
+    final Header header;
+    final Set<Dependence> requires = new HashSet<>();
+    final Map<Exported, Set<String>> exports = new HashMap<>();
+    final Map<Opened, Set<String>> opens = new HashMap<>();
+    final Set<Uses> uses = new HashSet<>();
+    final Map<Provided, Set<String>> provides = new HashMap<>();
+
+
+    public Builder() {
+      this("", Modifier.ACC_NONE.asInt(), null);
+    }
+
+    public Builder(String moduleName, int moduleFlags, String moduleVersion) {
+      header = new Header( moduleName,moduleFlags, moduleVersion);
+    }
+
+    public Builder setModuleFlags(int moduleFlags) {
+      header.setFlag(header.getFlags() | moduleFlags);
+      return this;
+    }
+
+    public Builder setModuleFlags(Modifier... moduleFlags) {
+      for (Modifier m : moduleFlags)
+        setModuleFlags(m.value);
+      return this;
+    }
+
+    public Builder setModuleName(String value) {
+      header.setTypeName(value);
+      return this;
+    }
+
+    public Builder require(String d, boolean transitive, boolean staticPhase, String version) {
+      requires.add(new Dependence(d, transitive, staticPhase, version));
+      return this;
+    }
+
+    public Builder require(String d, int requiresFlag, String version) {
+      requires.add(new Dependence(d, requiresFlag, version));
+      return this;
+    }
+
+    public Builder require(String d, int requiresFlag) {
+      requires.add(new Dependence(d, requiresFlag, null));
+      return this;
+    }
+
+    public Builder opens(Opened p, Set<String> ms) {
+      return add(opens, p, ms);
+    }
+
+    public Builder opens(String packageName, int exportFlags, Set<String> ms) {
+      return add(opens, new Opened(packageName, exportFlags), ms);
+    }
+
+    public Builder opens(String packageName, int exportFlags) {
+      return add(opens, new Opened(packageName, exportFlags), new HashSet<>());
+    }
+
+
+    public Builder exports(Exported p, Set<String> ms) {
+      return add(exports, p, ms);
+    }
+
+    public Builder exports(String packageName, int exportFlags, Set<String> ms) {
+      return add(exports, new Exported(packageName, exportFlags), ms);
+    }
+
+    public Builder exports(String packageName, int exportFlags) {
+      return add(exports, new Exported(packageName, exportFlags), new HashSet<>());
+    }
+
+    public Builder uses(String serviceName) {
+      uses.add(new Uses(serviceName));
+      return this;
+    }
+
+
+    public Builder uses(Set<String> serviceNames) {
+      uses.addAll(serviceNames.stream().map(Uses::new).collect(Collectors.toList()));
+      return this;
+    }
+
+    public Builder provides(Provided t, Set<String> implementations) {
+      return add(provides, t, implementations);
+    }
+
+    public Builder provides(String serviceName, Set<String> implementations) {
+      return add(provides, new Provided(serviceName), implementations);
+    }
+
+
+    /**
+     * @return The new module
+     */
+    public Module build() {
+      return new Module(this);
+    }
+
+    private <T extends TargetType> Builder  add( Map<T, Set<String>> collection, T source, Set<String> target) {
+      Objects.requireNonNull(source);
+      Objects.requireNonNull(target);
+      if (!collection.containsKey(source))
+        collection.put(source, new HashSet<>());
+      collection.get(source).addAll(target);
+      return this;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openjdk/asmtools/jasm/CFVersion.java	Fri Oct 06 15:15:23 2017 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.asmtools.jasm;
+
+/*
+ * Class File Version
+ */
+public class CFVersion {
+    /**
+     * Default versions of class file
+     */
+    public static final short DEFAULT_MAJOR_VERSION = 45;
+    public static final short DEFAULT_MINOR_VERSION = 3;
+    public static final short DEFAULT_MODULE_MAJOR_VERSION = 53;
+    public static final short DEFAULT_MODULE_MINOR_VERSION = 0;
+    public static final short UNDEFINED_VERSION = -1;
+
+    private short major_version;
+    private short minor_version;
+
+    public CFVersion() {
+        major_version = UNDEFINED_VERSION;
+        minor_version = UNDEFINED_VERSION;
+    }
+
+    public CFVersion(short major_version, short minor_version) {
+        this.major_version = major_version;
+        this.minor_version = minor_version;
+    }
+
+    public void setMajorVersion(short major_version) {
+        if ( !isSet() )
+            this.major_version = major_version;
+    }
+
+    public void setMinorVersion(short minor_version) {
+        if ( !isSet() )
+            this.minor_version = minor_version;
+    }
+
+    private boolean isSet() {
+        return this.major_version != UNDEFINED_VERSION && this.minor_version != UNDEFINED_VERSION;
+    }
+
+    public String asString() {
+        return (isSet()) ? this.major_version + ":" +this.minor_version : "(undef):(undef)";
+    }
+
+    public void initModuleDefaults() {
+        if( ! isSet()) {
+            major_version = DEFAULT_MODULE_MAJOR_VERSION;
+            minor_version = DEFAULT_MODULE_MINOR_VERSION;
+        }
+    }
+
+    public void initClassDefaults() {
+        if( ! isSet()) {
+            major_version = DEFAULT_MAJOR_VERSION;
+            minor_version = DEFAULT_MINOR_VERSION;
+        }
+    }
+
+    public short minor_version() {
+        return this.minor_version;
+    }
+
+    public short major_version() {
+        return this.major_version;
+    }
+}
--- a/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/CheckedDataOutputStream.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. 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
@@ -61,5 +61,4 @@
 
     public void writeUTF(String s) throws IOException;
 
-//       public int writeUTF(String str, DataOutput out) throws IOException;
 }
--- a/src/org/openjdk/asmtools/jasm/ClassData.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/ClassData.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -25,8 +25,7 @@
 import java.io.*;
 import java.util.ArrayList;
 
-import static org.openjdk.asmtools.jasm.Constants.DEFAULT_MAJOR_VERSION;
-import static org.openjdk.asmtools.jasm.Constants.DEFAULT_MINOR_VERSION;
+import static org.openjdk.asmtools.jasm.Constants.*;
 import static org.openjdk.asmtools.jasm.Tables.*;
 
 /**
@@ -43,8 +42,7 @@
 
     /*-------------------------------------------------------- */
     /* ClassData Fields */
-    short major_version = DEFAULT_MAJOR_VERSION;
-    short minor_version = DEFAULT_MINOR_VERSION;
+    CFVersion cfv = new CFVersion();
     ConstantPool.ConstCell me, father;
     String myClassName;
     AttrData sourceFileNameAttr;
@@ -86,12 +84,18 @@
         }
         this.father = father;
         this.interfaces = interfaces;
+
+        cfv.initClassDefaults();
     }
 
-    public final void initAsModule(ConstantPool.ConstCell me) {
+    public final void initAsModule() {
         this.access = RuntimeConstants.ACC_MODULE;
-        this.me = me;
+        // this_class" module-info
+        this.me = pool.FindCellClassByName("module-info");
+        // super_class: zero
         this.father = new ConstantPool.ConstCell(0);
+
+        cfv.initModuleDefaults();
     }
 
     /**
@@ -114,13 +118,11 @@
      * canonical default constructor
      *
      * @param env The error reporting environment.
-     * @param major_version The major version that this class file supports.
-     * @param minor_version The minor version that this class file supports
+     * @param cfv The class file version that this class file supports.
      */
-    public ClassData(Environment env, short major_version, short minor_version) {
+    public ClassData(Environment env, CFVersion cfv) {
         this(env);
-        this.major_version = major_version;
-        this.minor_version = minor_version;
+        this.cfv = cfv;
     }
 
     public ClassData(Environment env, int acc, ConstantPool.ConstCell me, ConstantPool.ConstCell father, ArrayList<Argument> impls) {
@@ -142,7 +144,6 @@
         return Modifiers.isInterface(access);
     }
 
-
     /*
      * After a constant pool has been explicitly declared,
      * this method links the Constant_InvokeDynamic constants
@@ -348,8 +349,8 @@
 
         // Write the header
         out.writeInt(JAVA_MAGIC);
-        out.writeShort(minor_version);
-        out.writeShort(major_version);
+        out.writeShort(cfv.minor_version());
+        out.writeShort(cfv.major_version());
 
         pool.write(out);
         out.writeShort(access); // & MM_CLASS; // Q
@@ -390,6 +391,10 @@
 
         // Write the attributes
         if( moduleAttribute != null ) {
+            if (annotAttrVis != null)
+                attrs.add(annotAttrVis);
+            if (annotAttrInv != null)
+                attrs.add(annotAttrInv);
             attrs.add(moduleAttribute);
         } else {
             attrs.add(sourceFileNameAttr);
@@ -585,6 +590,5 @@
          * */
 
     }
-
 }// end class ClassData
 
--- a/src/org/openjdk/asmtools/jasm/CodeAttr.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/CodeAttr.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -434,7 +434,7 @@
     public StackMapData getStackMap() {
         if (curMapEntry == null) {
             curMapEntry = new StackMapData(env);
-            if (cls.major_version >= SPLIT_VERIFIER_CFV) {
+            if (cls.cfv.major_version() >= SPLIT_VERIFIER_CFV) {
                 curMapEntry.setIsStackMapTable(true);
             }
         }
@@ -473,7 +473,7 @@
             curMapEntry.pc = cur_pc;
             StackMapData prevStackFrame = null;
             if (stackMap == null) {
-                if (cls.major_version >= SPLIT_VERIFIER_CFV) {
+                if (cls.cfv.major_version() >= SPLIT_VERIFIER_CFV) {
                     stackMap = new DataVectorAttr<>(cls, AttrTag.ATT_StackMapTable.parsekey());
                 } else {
                     stackMap = new DataVectorAttr<>(cls, AttrTag.ATT_StackMap.parsekey());
--- a/src/org/openjdk/asmtools/jasm/ConstantPool.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/ConstantPool.java	Fri Oct 06 15:15:23 2017 -0700
@@ -619,13 +619,21 @@
         public R visitInvokedynamic(ConstType tag) {
             return null;
         }
+        ;
 
+        public R visitModule(ConstType tag) {
+            return null;
+        }
         ;
-//        public R visitInvokedynamicTrans() { return null; };
+
+        public R visitPackage(ConstType tag) {
+            return null;
+        }
+        ;
+
         public void visitDefault(ConstType tag) {
         }
-    ;
-
+        ;
     }
 
     /**
@@ -684,9 +692,12 @@
                 case CONSTANT_INVOKEDYNAMIC:
                     retVal = visitInvokedynamic((ConstValue_IndyPair) val);
                     break;
-//                case CONSTANT_INVOKEDYNAMIC_TRANS:
-//                    retVal = visitInvokedynamicTrans((ConstValue_Pair) val);
-//                    break;
+                case CONSTANT_MODULE:
+                    retVal = visitModule((ConstValue_Cell) val);
+                    break;
+                case CONSTANT_PACKAGE:
+                    retVal = visitPackage((ConstValue_Cell) val);
+                    break;
                 default:
                     visitDefault(tag);
             }
@@ -758,15 +769,17 @@
         }
 
         ;
-        public R visitInvokedynamic(ConstValue_IndyPair p) {
-            return null;
-        }
+        public R visitInvokedynamic(ConstValue_IndyPair p) { return null;}
 
         ;
-//        public R visitInvokedynamicTrans(ConstValue_Pair p) { return null; };
-        public void visitDefault(ConstType tag) {
-        }
-    ;
+        public R visitModule(ConstValue_Cell p) { return null; }
+
+        ;
+        public R visitPackage(ConstValue_Cell p) { return null; }
+        ;
+
+        public void visitDefault(ConstType tag) {}
+        ;
 
     }
 
@@ -970,9 +983,23 @@
         public Void visitInvokedynamic(ConstValue_IndyPair p) {
             return null;
         }
+        ;
 
+        @Override
+        public Void visitModule(ConstValue_Cell p) {
+            handleClassRef(p);
+            return null;
+        }
         ;
 
+        @Override
+        public Void visitPackage(ConstValue_Cell p) {
+            handleClassRef(p);
+            return null;
+        }
+        ;
+
+
         public void handleClassRef(ConstValue_Cell cv) {
             ConstCell clref = cv.cell;
             if (clref.ref == null) {
@@ -1170,9 +1197,11 @@
         return FindCell(ConstType.CONSTANT_UTF8, str);
     }
 
-    public ConstCell FindCellClassByName(String name) {
-        return FindCell(ConstType.CONSTANT_CLASS, FindCellAsciz(name));
-    }
+    public ConstCell FindCellClassByName(String name) { return FindCell(ConstType.CONSTANT_CLASS, FindCellAsciz(name)); }
+
+    public ConstCell FindCellModuleByName(String name) { return FindCell(ConstType.CONSTANT_MODULE, FindCellAsciz(name)); }
+
+    public ConstCell FindCellPackageByName(String name) { return FindCell(ConstType.CONSTANT_PACKAGE, FindCellAsciz(name)); }
 
     public void write(CheckedDataOutputStream out) throws IOException {
         // Write the constant pool
@@ -1186,7 +1215,6 @@
             if (cell.arg != i) {
                 throw new Parser.CompilerError(env.errorStr("comperr.constcell.invarg", Integer.toString(i), cell.arg));
             }
-// System.out.print("         WRITE CONST[" + i + "]:");
             value.write(out);
             i += value.size();
         }
--- a/src/org/openjdk/asmtools/jasm/Constants.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/Constants.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -29,11 +29,6 @@
  */
 public interface Constants extends RuntimeConstants {
 
-    /**
-     * Default version of class file
-     */
-    public static final short DEFAULT_MAJOR_VERSION = 45;
-    public static final short DEFAULT_MINOR_VERSION = 3;
 
     /**
      * End of input
--- a/src/org/openjdk/asmtools/jasm/JasmTokens.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/JasmTokens.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -22,7 +22,11 @@
  */
 package org.openjdk.asmtools.jasm;
 
+import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.Optional;
+
+import static org.openjdk.asmtools.jasm.JasmTokens.Token.ALL_TOKENS;
 
 /**
  *
@@ -61,21 +65,23 @@
     }
 
 
-    /*-------------------------------------------------------- */
-    /* Marker - describes the type of token */
-    /*    this is rather cosmetic, no function currently. */
+    /*--------------------------------------------------------  */
+    /* Marker - describes the type of token                     */
+    /*    this is rather cosmetic, no function currently.       */
     static public enum TokenType {
-        MODIFIER            (0, "Modifier"),
-        OPERATOR            (1, "Operator"),
-        VALUE               (2, "Value"),
-        TYPE                (3, "Type"),
-        EXPRESSION          (4, "Expression"),
-        STATEMENT           (5, "Statement"),
-        DECLARATION         (6, "Declaration"),
-        PUNCTUATION         (7, "Punctuation"),
-        SPECIAL             (8, "Special"),
-        JASM                (9, "Jasm"),
-        MISC                (10, "Misc");
+        MODIFIER            (1, "Modifier"),
+        OPERATOR            (2, "Operator"),
+        VALUE               (3, "Value"),
+        TYPE                (4, "Type"),
+        EXPRESSION          (5, "Expression"),
+        STATEMENT           (6, "Statement"),
+        DECLARATION         (7, "Declaration"),
+        PUNCTUATION         (8, "Punctuation"),
+        SPECIAL             (9, "Special"),
+        JASM                (10, "Jasm"),
+        MISC                (11, "Misc"),
+        JASM_IDENT          (12, "Jasm identifier"),
+        MODULE_NAME         (13, "Module Name");
 
         private final Integer value;
         private final String printval;
@@ -84,7 +90,6 @@
             value = val;
             printval = print;
         }
-
         public String printval() {
             return printval;
         }
@@ -95,257 +100,257 @@
      * Scanner Tokens (Definitive List)
      */
     static public enum Token {
-        EOF                 (-1, "EOF",         "EOF",  TokenType.MISC),
-        COMMA               (0, "COMMA",        ",",    TokenType.OPERATOR),
-        ASSIGN              (1, "ASSIGN",       "=",    TokenType.OPERATOR),
+        EOF                 (-1, "EOF",         "EOF",  EnumSet.of(TokenType.MISC)),
+        COMMA               (0, "COMMA",        ",",    EnumSet.of(TokenType.OPERATOR)),
+        ASSIGN              (1, "ASSIGN",       "=",    EnumSet.of(TokenType.OPERATOR)),
 
-        ASGMUL              (2, "ASGMUL",       "*=",   TokenType.OPERATOR),
-        ASGDIV              (3, "ASGDIV",       "/=",   TokenType.OPERATOR),
-        ASGREM              (4, "ASGREM",       "%=",   TokenType.OPERATOR),
-        ASGADD              (5, "ASGADD",       "+=",   TokenType.OPERATOR),
-        ASGSUB              (6, "ASGSUB",       "-=",   TokenType.OPERATOR),
-        ASGLSHIFT           (7, "ASGLSHIFT",    "<<=",  TokenType.OPERATOR),
-        ASGRSHIFT           (8, "ASGRSHIFT",    ">>=",  TokenType.OPERATOR),
-        ASGURSHIFT          (9, "ASGURSHIFT",   "<<<=", TokenType.OPERATOR),
-        ASGBITAND           (10, "ASGBITAND",   "&=",   TokenType.OPERATOR),
-        ASGBITOR            (11, "ASGBITOR",    "|=",   TokenType.OPERATOR),
-        ASGBITXOR           (12, "ASGBITXOR",   "^=",   TokenType.OPERATOR),
+        ASGMUL              (2, "ASGMUL",       "*=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGDIV              (3, "ASGDIV",       "/=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGREM              (4, "ASGREM",       "%=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGADD              (5, "ASGADD",       "+=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGSUB              (6, "ASGSUB",       "-=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGLSHIFT           (7, "ASGLSHIFT",    "<<=",  EnumSet.of(TokenType.OPERATOR)),
+        ASGRSHIFT           (8, "ASGRSHIFT",    ">>=",  EnumSet.of(TokenType.OPERATOR)),
+        ASGURSHIFT          (9, "ASGURSHIFT",   "<<<=", EnumSet.of(TokenType.OPERATOR)),
+        ASGBITAND           (10, "ASGBITAND",   "&=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGBITOR            (11, "ASGBITOR",    "|=",   EnumSet.of(TokenType.OPERATOR)),
+        ASGBITXOR           (12, "ASGBITXOR",   "^=",   EnumSet.of(TokenType.OPERATOR)),
 
-        COND                (13, "COND",        "?:",   TokenType.OPERATOR),
-        OR                  (14, "OR",          "||",   TokenType.OPERATOR),
-        AND                 (15, "AND",         "&&",   TokenType.OPERATOR),
-        BITOR               (16, "BITOR",       "|",    TokenType.OPERATOR),
-        BITXOR              (17, "BITXOR",      "^",    TokenType.OPERATOR),
-        BITAND              (18, "BITAND",      "&",    TokenType.OPERATOR),
-        NE                  (19, "NE",          "!=",   TokenType.OPERATOR),
-        EQ                  (20, "EQ",          "==",   TokenType.OPERATOR),
-        GE                  (21, "GE",          ">=",   TokenType.OPERATOR),
-        GT                  (22, "GT",          ">",    TokenType.OPERATOR),
-        LE                  (23, "LE",          "<=",   TokenType.OPERATOR),
-        LT                  (24, "LT",          "<",    TokenType.OPERATOR),
-        INSTANCEOF          (25, "INSTANCEOF",  "instanceof",  TokenType.OPERATOR),
-        LSHIFT              (26, "LSHIFT",      "<<",   TokenType.OPERATOR),
-        RSHIFT              (27, "RSHIFT",      ">>",   TokenType.OPERATOR),
-        URSHIFT             (28, "URSHIFT",     "<<<",  TokenType.OPERATOR),
-        ADD                 (29, "ADD",         "+",    TokenType.OPERATOR),
-        SUB                 (30, "SUB",         "-",    TokenType.OPERATOR),
-        DIV                 (31, "DIV",         "/",    TokenType.OPERATOR),
-        REM                 (32, "REM",         "%",    TokenType.OPERATOR),
-        MUL                 (33, "MUL",         "*",    TokenType.OPERATOR),
-        CAST                (34, "CAST",        "cast", TokenType.OPERATOR),
-        POS                 (35, "POS",         "+",    TokenType.OPERATOR),
-        NEG                 (36, "NEG",         "-",    TokenType.OPERATOR),
-        NOT                 (37, "NOT",         "!",    TokenType.OPERATOR),
-        BITNOT              (38, "BITNOT",      "~",    TokenType.OPERATOR),
-        PREINC              (39, "PREINC",      "++",   TokenType.OPERATOR),
-        PREDEC              (40, "PREDEC",      "--",   TokenType.OPERATOR),
-        NEWARRAY            (41, "NEWARRAY",    "new",  TokenType.OPERATOR),
-        NEWINSTANCE         (42, "NEWINSTANCE", "new",  TokenType.OPERATOR),
-        NEWFROMNAME         (43, "NEWFROMNAME", "new",  TokenType.OPERATOR),
-        POSTINC             (44, "POSTINC",     "++",   TokenType.OPERATOR),
-        POSTDEC             (45, "POSTDEC",     "--",   TokenType.OPERATOR),
-        FIELD               (46, "FIELD",       "field", TokenType.OPERATOR),
-        METHOD              (47, "METHOD",      "method",  TokenType.OPERATOR),
-        ARRAYACCESS         (48, "ARRAYACCESS", "[]",   TokenType.OPERATOR),
-        NEW                 (49, "NEW",         "new",  TokenType.OPERATOR),
-        INC                 (50, "INC",         "++",   TokenType.OPERATOR),
-        DEC                 (51, "DEC",         "--",   TokenType.OPERATOR),
+        COND                (13, "COND",        "?:",   EnumSet.of(TokenType.OPERATOR)),
+        OR                  (14, "OR",          "||",   EnumSet.of(TokenType.OPERATOR)),
+        AND                 (15, "AND",         "&&",   EnumSet.of(TokenType.OPERATOR)),
+        BITOR               (16, "BITOR",       "|",    EnumSet.of(TokenType.OPERATOR)),
+        BITXOR              (17, "BITXOR",      "^",    EnumSet.of(TokenType.OPERATOR)),
+        BITAND              (18, "BITAND",      "&",    EnumSet.of(TokenType.OPERATOR)),
+        NE                  (19, "NE",          "!=",   EnumSet.of(TokenType.OPERATOR)),
+        EQ                  (20, "EQ",          "==",   EnumSet.of(TokenType.OPERATOR)),
+        GE                  (21, "GE",          ">=",   EnumSet.of(TokenType.OPERATOR)),
+        GT                  (22, "GT",          ">",    EnumSet.of(TokenType.OPERATOR)),
+        LE                  (23, "LE",          "<=",   EnumSet.of(TokenType.OPERATOR)),
+        LT                  (24, "LT",          "<",    EnumSet.of(TokenType.OPERATOR)),
+        INSTANCEOF          (25, "INSTANCEOF",  "instanceof",  EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        LSHIFT              (26, "LSHIFT",      "<<",   EnumSet.of(TokenType.OPERATOR)),
+        RSHIFT              (27, "RSHIFT",      ">>",   EnumSet.of(TokenType.OPERATOR)),
+        URSHIFT             (28, "URSHIFT",     "<<<",  EnumSet.of(TokenType.OPERATOR)),
+        ADD                 (29, "ADD",         "+",    EnumSet.of(TokenType.OPERATOR)),
+        SUB                 (30, "SUB",         "-",    EnumSet.of(TokenType.OPERATOR)),
+        DIV                 (31, "DIV",         "/",    EnumSet.of(TokenType.OPERATOR)),
+        REM                 (32, "REM",         "%",    EnumSet.of(TokenType.OPERATOR)),
+        MUL                 (33, "MUL",         "*",    EnumSet.of(TokenType.OPERATOR)),
+        CAST                (34, "CAST",        "cast", EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        POS                 (35, "POS",         "+",    EnumSet.of(TokenType.OPERATOR)),
+        NEG                 (36, "NEG",         "-",    EnumSet.of(TokenType.OPERATOR)),
+        NOT                 (37, "NOT",         "!",    EnumSet.of(TokenType.OPERATOR)),
+        BITNOT              (38, "BITNOT",      "~",    EnumSet.of(TokenType.OPERATOR)),
+        PREINC              (39, "PREINC",      "++",   EnumSet.of(TokenType.OPERATOR)),
+        PREDEC              (40, "PREDEC",      "--",   EnumSet.of(TokenType.OPERATOR)),
+        NEWARRAY            (41, "NEWARRAY",    "new",  EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        NEWINSTANCE         (42, "NEWINSTANCE", "new",  EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        NEWFROMNAME         (43, "NEWFROMNAME", "new",  EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        POSTINC             (44, "POSTINC",     "++",   EnumSet.of(TokenType.OPERATOR)),
+        POSTDEC             (45, "POSTDEC",     "--",   EnumSet.of(TokenType.OPERATOR)),
+        FIELD               (46, "FIELD",       "field", EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        METHOD              (47, "METHOD",      "method",  EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        ARRAYACCESS         (48, "ARRAYACCESS", "[]",   EnumSet.of(TokenType.OPERATOR)),
+        NEW                 (49, "NEW",         "new",  EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        INC                 (50, "INC",         "++",   EnumSet.of(TokenType.OPERATOR)),
+        DEC                 (51, "DEC",         "--",   EnumSet.of(TokenType.OPERATOR)),
 
-        CONVERT             (55, "CONVERT",     "convert", TokenType.OPERATOR),
-        EXPR                (56, "EXPR",        "expr", TokenType.OPERATOR),
-        ARRAY               (57, "ARRAY",       "array", TokenType.OPERATOR),
-        GOTO                (58, "GOTO",        "goto", TokenType.OPERATOR),
-
-
+        CONVERT             (55, "CONVERT",     "convert", EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        EXPR                (56, "EXPR",        "expr", EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        ARRAY               (57, "ARRAY",       "array", EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
+        GOTO                (58, "GOTO",        "goto", EnumSet.of(TokenType.OPERATOR, TokenType.MODULE_NAME)),
 
     /*
      * Value tokens
      */
-        IDENT               (60, "IDENT",       "Identifier", TokenType.VALUE, KeywordType.VALUE, true),
-        BOOLEANVAL          (61, "BOOLEANVAL",  "Boolean",  TokenType.VALUE, KeywordType.VALUE),
-        BYTEVAL             (62, "BYTEVAL",     "Byte",     TokenType.VALUE),
-        CHARVAL             (63, "CHARVAL",     "Char",     TokenType.VALUE),
-        SHORTVAL            (64, "SHORTVAL",    "Short",    TokenType.VALUE),
-        INTVAL              (65, "INTVAL",      "Integer",  TokenType.VALUE, KeywordType.VALUE),
-        LONGVAL             (66, "LONGVAL",     "Long",     TokenType.VALUE, KeywordType.VALUE),
-        FLOATVAL            (67, "FLOATVAL",    "Float",    TokenType.VALUE, KeywordType.VALUE),
-        DOUBLEVAL           (68, "DOUBLEVAL",   "Double",   TokenType.VALUE, KeywordType.VALUE),
-        STRINGVAL           (69, "STRINGVAL",   "String",   TokenType.VALUE, KeywordType.VALUE),
+        IDENT               (60, "IDENT",       "Identifier", EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME, TokenType.JASM_IDENT), KeywordType.VALUE),
+        BOOLEANVAL          (61, "BOOLEANVAL",  "Boolean",    EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME),   KeywordType.VALUE),
+        BYTEVAL             (62, "BYTEVAL",     "Byte",       EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME)),
+        CHARVAL             (63, "CHARVAL",     "Char",       EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME)),
+        SHORTVAL            (64, "SHORTVAL",    "Short",      EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME)),
+        INTVAL              (65, "INTVAL",      "Integer",    EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME),   KeywordType.VALUE),
+        LONGVAL             (66, "LONGVAL",     "Long",       EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME),   KeywordType.VALUE),
+        FLOATVAL            (67, "FLOATVAL",    "Float",      EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME),   KeywordType.VALUE),
+        DOUBLEVAL           (68, "DOUBLEVAL",   "Double",     EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME),   KeywordType.VALUE),
+        STRINGVAL           (69, "STRINGVAL",   "String",     EnumSet.of(TokenType.VALUE, TokenType.MODULE_NAME),   KeywordType.VALUE),
 
     /*
      * Type keywords
      */
-        BYTE                (70, "BYTE",        "byte",     TokenType.TYPE),
-        CHAR                (71, "CHAR",        "char",     TokenType.TYPE),
-        SHORT               (72, "SHORT",       "short",    TokenType.TYPE),
-        INT                 (73, "INT",         "int",      TokenType.TYPE),
-        LONG                (74, "LONG",        "long",     TokenType.TYPE),
-        FLOAT               (75, "FLOAT",       "float",    TokenType.TYPE),
-        DOUBLE              (76, "DOUBLE",      "double",   TokenType.TYPE),
-        VOID                (77, "VOID",        "void",     TokenType.TYPE),
-        BOOLEAN             (78, "BOOLEAN",     "boolean",  TokenType.TYPE),
+        BYTE                (70, "BYTE",        "byte",     EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME )),
+        CHAR                (71, "CHAR",        "char",     EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME )),
+        SHORT               (72, "SHORT",       "short",    EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME )),
+        INT                 (73, "INT",         "int",      EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME )),
+        LONG                (74, "LONG",        "long",     EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME )),
+        FLOAT               (75, "FLOAT",       "float",    EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME)),
+        DOUBLE              (76, "DOUBLE",      "double",   EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME)),
+        VOID                (77, "VOID",        "void",     EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME)),
+        BOOLEAN             (78, "BOOLEAN",     "boolean",  EnumSet.of(TokenType.TYPE, TokenType.MODULE_NAME)),
 
     /*
      * Expression keywords
      */
-        TRUE                (80, "TRUE",        "true",     TokenType.EXPRESSION),
-        FALSE               (81, "FALSE",       "false",    TokenType.EXPRESSION),
-        THIS                (82, "THIS",        "this",     TokenType.EXPRESSION),
-        SUPER               (83, "SUPER",       "super",     TokenType.MODIFIER, KeywordType.KEYWORD),
-        NULL                (84, "NULL",        "null",     TokenType.EXPRESSION),
+        TRUE                (80, "TRUE",        "true",     EnumSet.of(TokenType.EXPRESSION, TokenType.MODULE_NAME )),
+        FALSE               (81, "FALSE",       "false",    EnumSet.of(TokenType.EXPRESSION, TokenType.MODULE_NAME )),
+        THIS                (82, "THIS",        "this",     EnumSet.of(TokenType.EXPRESSION, TokenType.MODULE_NAME )),
+        SUPER               (83, "SUPER",       "super",    EnumSet.of(TokenType.MODIFIER,   TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        NULL                (84, "NULL",        "null",     EnumSet.of(TokenType.EXPRESSION, TokenType.MODULE_NAME )),
 
     /*
      * Statement keywords
      */
-        IF                  (90, "IF",          "if",       TokenType.STATEMENT),
-        ELSE                (91, "ELSE",        "else",     TokenType.STATEMENT),
-        FOR                 (92, "FOR",         "for",      TokenType.STATEMENT),
-        WHILE               (93, "WHILE",       "while",    TokenType.STATEMENT),
-        DO                  (94, "DO",          "do",       TokenType.STATEMENT),
-        SWITCH              (95, "SWITCH",      "switch",   TokenType.STATEMENT),
-        CASE                (96, "CASE",        "case",     TokenType.STATEMENT),
-        DEFAULT             (97,  "DEFAULT",    "default",  TokenType.STATEMENT, KeywordType.KEYWORD),
-        BREAK               (98, "BREAK",       "break",    TokenType.STATEMENT),
-        CONTINUE            (99, "CONTINUE",    "continue", TokenType.STATEMENT),
-        RETURN              (100, "RETURN",     "return",   TokenType.STATEMENT),
-        TRY                 (101, "TRY",        "try",      TokenType.STATEMENT),
-        CATCH               (102, "CATCH",      "catch",    TokenType.STATEMENT),
-        FINALLY             (103, "FINALLY",    "finally",  TokenType.STATEMENT),
-        THROW               (104, "THROW",      "throw",    TokenType.STATEMENT),
-        STAT                (105, "STAT",       "stat",     TokenType.STATEMENT),
-        EXPRESSION          (106, "EXPRESSION", "expression",  TokenType.STATEMENT),
-        DECLARATION         (107, "DECLARATION", "declaration",   TokenType.STATEMENT),
-        VARDECLARATION      (108, "VARDECLARATION", "vdeclaration", TokenType.STATEMENT),
+        IF                  (90, "IF",          "if",       EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        ELSE                (91, "ELSE",        "else",     EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        FOR                 (92, "FOR",         "for",      EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        WHILE               (93, "WHILE",       "while",    EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        DO                  (94, "DO",          "do",       EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        SWITCH              (95, "SWITCH",      "switch",   EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        CASE                (96, "CASE",        "case",     EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        DEFAULT             (97,  "DEFAULT",    "default",  EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        BREAK               (98, "BREAK",       "break",    EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        CONTINUE            (99, "CONTINUE",    "continue", EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        RETURN              (100, "RETURN",     "return",   EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        TRY                 (101, "TRY",        "try",      EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+
+        CATCH               (102, "CATCH",      "catch",    EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        FINALLY             (103, "FINALLY",    "finally",  EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        THROW               (104, "THROW",      "throw",            EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        STAT                (105, "STAT",       "stat",             EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        EXPRESSION          (106, "EXPRESSION", "expression",       EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        DECLARATION         (107, "DECLARATION", "declaration",     EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
+        VARDECLARATION      (108, "VARDECLARATION", "vdeclaration", EnumSet.of(TokenType.STATEMENT, TokenType.MODULE_NAME )),
 
     /*
      * Declaration keywords
      */
-        IMPORT              (110, "IMPORT",     "import",   TokenType.DECLARATION),
-        CLASS               (111, "CLASS",      "class",    TokenType.DECLARATION, KeywordType.KEYWORD),
-        EXTENDS             (112, "EXTENDS",    "extends",  TokenType.DECLARATION, KeywordType.KEYWORD),
-        IMPLEMENTS          (113, "IMPLEMENTS", "implements", TokenType.DECLARATION, KeywordType.KEYWORD),
-        INTERFACE           (114, "INTERFACE",  "interface", TokenType.DECLARATION, KeywordType.KEYWORD),
-        PACKAGE             (115, "PACKAGE",    "package",  TokenType.DECLARATION, KeywordType.KEYWORD),
-        ENUM                (116, "ENUM",       "enum",     TokenType.DECLARATION, KeywordType.KEYWORD),
-        MANDATED            (117, "MANDATED",   "mandated", TokenType.DECLARATION, KeywordType.KEYWORD),
-     /*
+        IMPORT              (110, "IMPORT",     "import",   EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME )),
+        CLASS               (111, "CLASS",      "class",    EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        EXTENDS             (112, "EXTENDS",    "extends",  EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        IMPLEMENTS          (113, "IMPLEMENTS", "implements",   EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        INTERFACE           (114, "INTERFACE",  "interface",    EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        PACKAGE             (115, "PACKAGE",    "package",  EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        ENUM                (116, "ENUM",       "enum",     EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        MANDATED            (117, "MANDATED",   "mandated", EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        THROWS              (118, "THROWS",     "throws",   EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+
+    /*
      * Modifier keywords
      */
-        PRIVATE             (120, "PRIVATE",    "private",  TokenType.MODIFIER, KeywordType.KEYWORD),
-        PUBLIC              (121, "PUBLIC",     "public",   TokenType.MODIFIER, KeywordType.KEYWORD),
-        PROTECTED           (122, "PROTECTED",  "protected", TokenType.MODIFIER, KeywordType.KEYWORD),
-        CONST               (123, "CONST",      "const",    TokenType.DECLARATION, KeywordType.KEYWORD),
-        STATIC              (124, "STATIC",     "static",   TokenType.MODIFIER, KeywordType.KEYWORD),
-        TRANSIENT           (125, "TRANSIENT",  "transient", TokenType.MODIFIER, KeywordType.KEYWORD),
-        SYNCHRONIZED        (126, "SYNCHRONIZED", "synchronized", TokenType.MODIFIER, KeywordType.KEYWORD),
-        NATIVE              (127, "NATIVE",     "native",   TokenType.MODIFIER, KeywordType.KEYWORD),
-        FINAL               (128, "FINAL",      "final",    TokenType.MODIFIER, KeywordType.KEYWORD),
-        VOLATILE            (129, "VOLATILE",   "volatile", TokenType.MODIFIER, KeywordType.KEYWORD),
-        ABSTRACT            (130, "ABSTRACT",   "abstract", TokenType.MODIFIER, KeywordType.KEYWORD),
+        ANNOTATION_ACCESS   (119, "ANNOTATION_ACCESS",  "annotation",       EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        PRIVATE             (120, "PRIVATE",            "private",          EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        PUBLIC              (121, "PUBLIC",             "public",           EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        PROTECTED           (122, "PROTECTED",          "protected",        EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        CONST               (123, "CONST",              "const",            EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME), KeywordType.KEYWORD),
+        STATIC              (124, "STATIC",             "static",           EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        TRANSIENT           (125, "TRANSIENT",          "transient",        EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        SYNCHRONIZED        (126, "SYNCHRONIZED",       "synchronized",     EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        NATIVE              (127, "NATIVE",             "native",           EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        FINAL               (128, "FINAL",              "final",            EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        VOLATILE            (129, "VOLATILE",           "volatile",         EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        ABSTRACT            (130, "ABSTRACT",           "abstract",         EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        TRANSITIVE          (131, "TRANSITIVE",         "transitive",       EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        OPEN                (132, "OPEN",               "open",             EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
 
     /*
      * Punctuation
      */
-        SEMICOLON           (135, "SEMICOLON",  ";",    TokenType.PUNCTUATION, KeywordType.VALUE),
-        COLON               (136, "COLON",      ":",    TokenType.PUNCTUATION, KeywordType.VALUE),
-        QUESTIONMARK        (137, "QUESTIONMARK", "?",  TokenType.PUNCTUATION),
-        LBRACE              (138, "LBRACE",     "{",    TokenType.PUNCTUATION, KeywordType.VALUE),
-        RBRACE              (139, "RBRACE",     "}",    TokenType.PUNCTUATION, KeywordType.VALUE),
-        LPAREN              (140, "LPAREN",     "(",    TokenType.PUNCTUATION),
-        RPAREN              (141, "RPAREN",     ")",    TokenType.PUNCTUATION),
-        LSQBRACKET          (142, "LSQBRACKET", "[",    TokenType.PUNCTUATION),
-        RSQBRACKET          (143, "RSQBRACKET", "]",    TokenType.PUNCTUATION),
-        THROWS              (144, "THROWS",     "throws",  TokenType.DECLARATION, KeywordType.KEYWORD),
+        AT_SIGN             (133, "AT",         ";",       EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE),
+        SEMICOLON           (134, "SEMICOLON",  ";",       EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE),
+        COLON               (135, "COLON",      ":",       EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE),
+        QUESTIONMARK        (136, "QUESTIONMARK", "?",     EnumSet.of(TokenType.PUNCTUATION)),
+        LBRACE              (137, "LBRACE",     "{",       EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE),
+        RBRACE              (138, "RBRACE",     "}",       EnumSet.of(TokenType.PUNCTUATION), KeywordType.VALUE),
+        LPAREN              (139, "LPAREN",     "(",       EnumSet.of(TokenType.PUNCTUATION)),
+        RPAREN              (140, "RPAREN",     ")",       EnumSet.of(TokenType.PUNCTUATION)),
+        LSQBRACKET          (141, "LSQBRACKET", "[",       EnumSet.of(TokenType.PUNCTUATION)),
+        RSQBRACKET          (142, "RSQBRACKET", "]",       EnumSet.of(TokenType.PUNCTUATION)),
+
+        ESCAPED_COLON       (201, "ESCCOLON",     "\\:",     EnumSet.of(TokenType.PUNCTUATION, TokenType.MODULE_NAME)),
+        ESCAPED_ATSIGH      (202, "ESCATSIGH",    "\\@",     EnumSet.of(TokenType.PUNCTUATION, TokenType.MODULE_NAME)),
+        ESCAPED_BACKSLASH   (203, "ESCBACKSLASH", "\\\\",    EnumSet.of(TokenType.PUNCTUATION, TokenType.MODULE_NAME)),
     /*
      * Special tokens
      */
-        ERROR               (145, "ERROR",      "error",    TokenType.MODIFIER),
-        COMMENT             (146, "COMMENT",    "comment",   TokenType.MODIFIER),
-        TYPE                (147, "TYPE",       "type",     TokenType.MODIFIER),
-        LENGTH              (148, "LENGTH",     "length",   TokenType.DECLARATION),
-        INLINERETURN        (149, "INLINERETURN", "inline-return", TokenType.MODIFIER),
-        INLINEMETHOD        (150, "INLINEMETHOD", "inline-method", TokenType.MODIFIER),
-        INLINENEWINSTANCE   (151, "INLINENEWINSTANCE", "inline-new", TokenType.MODIFIER),
+        ERROR               (145, "ERROR",      "error",    EnumSet.of(TokenType.MODIFIER,    TokenType.MODULE_NAME)),
+        COMMENT             (146, "COMMENT",    "comment",  EnumSet.of(TokenType.MODIFIER,    TokenType.MODULE_NAME)),
+        TYPE                (147, "TYPE",       "type",     EnumSet.of(TokenType.MODIFIER,    TokenType.MODULE_NAME)),
+        LENGTH              (148, "LENGTH",     "length",   EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME )),
+        INLINERETURN        (149, "INLINERETURN", "inline-return",  EnumSet.of(TokenType.MODIFIER)),
+        INLINEMETHOD        (150, "INLINEMETHOD", "inline-method",  EnumSet.of(TokenType.MODIFIER)),
+        INLINENEWINSTANCE   (151, "INLINENEWINSTANCE", "inline-new",EnumSet.of(TokenType.MODIFIER)),
 
     /*
      * Added for jasm
      */
-        METHODREF           (152, "METHODREF",  "Method",   TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        FIELDREF            (153, "FIELD",      "Field",    TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        STACK               (154, "STACK",      "stack",    TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        LOCAL               (155, "LOCAL",      "locals",   TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        CPINDEX             (156, "CPINDEX",    "CPINDEX",  TokenType.DECLARATION, true),
-        CPNAME              (157, "CPNAME",     "CPName",   TokenType.DECLARATION, true),
-        SIGN                (158, "SIGN",       "SIGN",     TokenType.DECLARATION, true),
-        BITS                (159, "BITS",       "bits",     TokenType.MISC, KeywordType.KEYWORD, true),
-        INF                 (160, "INF",        "Inf", "Infinity", TokenType.MISC, KeywordType.KEYWORD),
-        NAN                 (161, "NAN",        "NaN",      TokenType.MISC, KeywordType.KEYWORD, true),
-        INNERCLASS          (162, "INNERCLASS", "InnerClass", TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        OF                  (163, "OF",         "of",       TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        SYNTHETIC           (164, "SYNTHETIC",  "synthetic", TokenType.MODIFIER, KeywordType.KEYWORD, true),
-        STRICT              (165, "STRICT",     "strict",   TokenType.MODIFIER, KeywordType.KEYWORD, true),
-        DEPRECATED          (166, "DEPRECATED", "deprecated", TokenType.MODIFIER, KeywordType.KEYWORD, true),
-        VERSION             (167, "VERSION",    "version",  TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        MODULE              (168, "MODULE",     "module",   TokenType.DECLARATION, KeywordType.KEYWORD),
-        ANNOTATION          (169, "ANNOTATION", "@",        TokenType.MISC),
-        PARAM_NAME          (173, "PARAM_NAME", "#",        TokenType.MISC),
+        METHODREF           (152, "METHODREF",  "Method",   EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        FIELDREF            (153, "FIELD",      "Field",    EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        STACK               (154, "STACK",      "stack",    EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        LOCAL               (155, "LOCAL",      "locals",   EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        CPINDEX             (156, "CPINDEX",    "CPINDEX",  EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME )),
+        CPNAME              (157, "CPNAME",     "CPName",   EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME )),
+        SIGN                (158, "SIGN",       "SIGN",     EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME )),
+        BITS                (159, "BITS",       "bits",             EnumSet.of(TokenType.MISC, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        INF                 (160, "INF",        "Inf", "Infinity",  EnumSet.of(TokenType.MISC, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        NAN                 (161, "NAN",        "NaN",              EnumSet.of(TokenType.MISC, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        INNERCLASS          (162, "INNERCLASS", "InnerClass",       EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        OF                  (163, "OF",         "of",               EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        SYNTHETIC           (164, "SYNTHETIC",  "synthetic",  EnumSet.of(TokenType.MODIFIER, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        STRICT              (165, "STRICT",     "strict",     EnumSet.of(TokenType.MODIFIER, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        DEPRECATED          (166, "DEPRECATED", "deprecated", EnumSet.of(TokenType.MODIFIER, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        VERSION             (167, "VERSION",    "version",    EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        MODULE              (168, "MODULE",     "module",   EnumSet.of(TokenType.DECLARATION, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        ANNOTATION          (169, "ANNOTATION", "@",        EnumSet.of(TokenType.MISC, TokenType.MODULE_NAME )),
+        PARAM_NAME          (173, "PARAM_NAME", "#",        EnumSet.of(TokenType.MISC, TokenType.MODULE_NAME )),
 
-        VARARGS             (170, "VARARGS",    "varargs",  TokenType.MODIFIER, KeywordType.KEYWORD),
-        BRIDGE              (171, "BRIDGE",     "bridge",   TokenType.MODIFIER, KeywordType.KEYWORD),
+        VARARGS             (170, "VARARGS",    "varargs",  EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        BRIDGE              (171, "BRIDGE",     "bridge",   EnumSet.of(TokenType.MODIFIER, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
 
         // Declaration keywords
-        BOOTSTRAPMETHOD     (172, "BOOTSTRAPMETHOD", "BootstrapMethod", TokenType.DECLARATION, KeywordType.KEYWORD, true),
+        BOOTSTRAPMETHOD     (172, "BOOTSTRAPMETHOD", "BootstrapMethod", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
 
         //Module statements
-        REQUIRES            (180, "REQUIRES", "requires", TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        EXPORTS             (182, "EXPORTS",  "exports",  TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        TO                  (183, "TO",       "to",       TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        USES                (184, "USES",     "uses",     TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        PROVIDES            (185, "PROVIDES", "provides", TokenType.DECLARATION, KeywordType.KEYWORD, true),
-        WITH                (186, "WITH",     "with",     TokenType.DECLARATION, KeywordType.KEYWORD, true);
+        REQUIRES            (180, "REQUIRES", "requires", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        EXPORTS             (182, "EXPORTS",  "exports",  EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        TO                  (183, "TO",       "to",       EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        USES                (184, "USES",     "uses",     EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        PROVIDES            (185, "PROVIDES", "provides", EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        WITH                (186, "WITH",     "with",     EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD),
+        OPENS               (187, "OPENS",    "opens",    EnumSet.of(TokenType.DECLARATION, TokenType.JASM_IDENT, TokenType.MODULE_NAME ), KeywordType.KEYWORD);
 
+        final static EnumSet<Token> ALL_TOKENS = EnumSet.allOf(Token.class);
         // Misc Keywords
-        private Integer value;
-        private String printval;
-        private String alias;
-        private TokenType tok_type;
-        private KeywordType key_type;
-        private String parsekey;
-        private boolean possible_jasm_identifier;
+        final private Integer value;                    // 160
+        final private String  printval;                 // INF
+        final private String  parsekey;                 // inf
+        final private String  alias;                    // Infinity
+        final private EnumSet<TokenType>  tokenType;    // TokenType.MISC, TokenType.MODULE_NAME
+        final private KeywordType key_type;             // KeywordType.KEYWORD
+
+        public static Optional<Token> get(String  parsekey, KeywordType ktype) {
+            return ALL_TOKENS.stream().filter(t->t.key_type == ktype).filter(t->t.parsekey.equals(parsekey)).findFirst();
+        }
 
         // By default, if a KeywordType is not specified, it has the value 'TOKEN'
-        Token(Integer val, String print, String op, TokenType ttype) {
-            init(val, print, op, null, ttype, KeywordType.TOKEN, false);
+        Token(Integer val, String print, String op, EnumSet<TokenType> ttype) {
+            this(val, print, op, null, ttype, KeywordType.TOKEN);
         }
 
-        Token(Integer val, String print, String op, TokenType ttype, boolean ident) {
-            init(val, print, op, null, ttype, KeywordType.TOKEN, ident);
+        Token(Integer val, String print, String op, String als, EnumSet<TokenType> ttype) {
+            this(val, print, op, als, ttype, KeywordType.TOKEN);
         }
 
-        Token(Integer val, String print, String op, String als, TokenType ttype) {
-            init(val, print, op, als, ttype, KeywordType.TOKEN, false);
+        Token(Integer val, String print, String op, EnumSet<TokenType> ttype, KeywordType ktype) {
+            this(val, print, op, null, ttype, ktype);
         }
 
-        Token(Integer val, String print, String op, TokenType ttype, KeywordType ktype) {
-            init(val, print, op, null, ttype, ktype, false);
-        }
-
-        Token(Integer val, String print, String op, TokenType ttype, KeywordType ktype, boolean ident) {
-            init(val, print, op, null, ttype, ktype, ident);
-        }
-
-        Token(Integer val, String print, String op, String als, TokenType ttype, KeywordType ktype) {
-            init(val, print, op, als, ttype, ktype, false);
-        }
-
-        private void init(Integer val, String print, String op, String als, TokenType ttype, KeywordType ktype, boolean ident) {
-            value = val;
-            printval = print;
-            parsekey = op;
-            tok_type = ttype;
-            key_type = ktype;
-            alias = als;
-            possible_jasm_identifier = ident;
+        Token(Integer val, String print, String op, String als, EnumSet<TokenType> ttype, KeywordType ktype) {
+            this.value = val;
+            this.printval = print;
+            this.parsekey = op;
+            this.tokenType = ttype;
+            this.key_type = ktype;
+            this.alias = als;
         }
 
         public String printval() {
@@ -361,153 +366,18 @@
         }
 
         public boolean possibleJasmIdentifier() {
-            return possible_jasm_identifier;
+            return tokenType.contains(TokenType.JASM_IDENT);
         }
 
+        public boolean possibleModuleName() {  return tokenType.contains(TokenType.MODULE_NAME)  && !tokenType.contains(TokenType.PUNCTUATION); }
+
         @Override
         public String toString() {
             return "<" + printval + "> [" + value + "]";
         }
-
-    }
-
-    /**
-     * Initialized keyword and token Hash Maps (and Reverse Tables)
-     */
-    static protected final int MaxTokens = 172;
-    private static HashMap<Integer, Token> TagToTokens = new HashMap<>(MaxTokens);
-    private static HashMap<String, Token> SymbolToTokens = new HashMap<>(MaxTokens);
-    private static HashMap<String, Token> ParsekeyToTokens = new HashMap<>(MaxTokens);
-
-    static protected final int MaxValTokens = 12;
-    private static HashMap<Integer, Token> TagToValTokens = new HashMap<>(MaxValTokens);
-    private static HashMap<String, Token> SymbolToValTokens = new HashMap<>(MaxValTokens);
-    private static HashMap<String, Token> ParsekeyToValTokens = new HashMap<>(MaxValTokens);
-
-    private static HashMap<Integer, Token> PossibleJasmIdentifiers = new HashMap<>(MaxValTokens);
-
-    static protected final int MaxKeywords = 40;
-    private static HashMap<Integer, Token> TagToKeywords = new HashMap<>(MaxKeywords);
-    private static HashMap<String, Token> SymbolToKeywords = new HashMap<>(MaxKeywords);
-    private static HashMap<String, Token> ParsekeyToKeywords = new HashMap<>(MaxKeywords);
-
-    static {
-
-        // register all of the tokens
-        for (Token tk : Token.values()) {
-            registerToken(tk);
-        }
-    }
-
-    private static void registerToken(Token tk) {
-        // Tag is a keyword
-        if (tk.key_type == KeywordType.KEYWORD) {
-            TagToKeywords.put(tk.value, tk);
-            if (tk.alias != null) {
-                ParsekeyToKeywords.put(tk.alias, tk);
-            }
-            SymbolToKeywords.put(tk.printval, tk);
-            if (tk.parsekey != null) {
-                ParsekeyToKeywords.put(tk.parsekey, tk);
-            }
-        }
-
-        // Values (and Keywords) go on the Val tokens list
-        if (tk.key_type == KeywordType.KEYWORD
-                || tk.key_type == KeywordType.VALUE) {
-            TagToValTokens.put(tk.value, tk);
-            SymbolToValTokens.put(tk.printval, tk);
-            if (tk.alias != null) {
-                SymbolToValTokens.put(tk.alias, tk);
-            }
-            if (tk.parsekey != null) {
-                ParsekeyToValTokens.put(tk.parsekey, tk);
-            }
-        }
-
-        // make the list of 'possible jasm identifiers'
-        if (tk.possible_jasm_identifier) {
-            PossibleJasmIdentifiers.put(tk.value(), tk);
-        }
-
-        // Finally, register all tokens
-        TagToTokens.put(tk.value, tk);
-        SymbolToTokens.put(tk.printval, tk);
-        ParsekeyToTokens.put(tk.printval, tk);
-    }
-
-    /* Token accessors */
-    public static Token token(int tk) {
-        return TagToTokens.get(tk);
-    }
-
-    public static Token val_token(int tk) {
-        return TagToValTokens.get(tk);
-    }
-
-    public static Token keyword_token(int tk) {
-        return TagToKeywords.get(tk);
-    }
-
-    public static Token possibleJasmIdentifiers(int token) {
-        return PossibleJasmIdentifiers.get(token);
-    }
-
-    /* Reverse lookup accessors */
-    public static Token token(String parsekey) {
-        return ParsekeyToTokens.get(parsekey);
-    }
-
-    public static Token val_token(String parsekey) {
-        return ParsekeyToValTokens.get(parsekey);
-    }
-
-    public static Token keyword_token(String parsekey) {
-        return ParsekeyToKeywords.get(parsekey);
-    }
-
-    /* Reverse lookup by ID accessors */
-    public static Token token_ID(String ID) {
-        return ParsekeyToTokens.get(ID);
-    }
-
-    public static Token val_token_ID(String ID) {
-        return ParsekeyToValTokens.get(ID);
-    }
-
-    public static Token keyword_token_ID(String ID) {
-        return ParsekeyToKeywords.get(ID);
-    }
-
-    public static String keywordName(int token) {
-        String retval = null;
-        Token tk = keyword_token(token);
-        if (tk != null) {
-            retval = tk.parsekey;
-        }
-        return retval;
-    }
-
-    public static int val_token_int(String idValue) {
-        Token kwd = val_token(idValue);
-        int retval = Token.IDENT.value;
-
-        if (kwd != null) {
-            retval = kwd.value;
-        }
-        return retval;
     }
 
     public static Token keyword_token_ident(String idValue) {
-        Token kwd = keyword_token(idValue);
-
-        if (kwd == null) {
-            kwd = Token.IDENT;
-        }
-        return kwd;
-    }
-
-    public static int keyword_token_int(String idValue) {
-        return keyword_token_ident(idValue).value();
+        return Token.get(idValue,KeywordType.KEYWORD).orElse(Token.IDENT);
     }
 }
--- a/src/org/openjdk/asmtools/jasm/Main.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/Main.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -22,8 +22,8 @@
  */
 package org.openjdk.asmtools.jasm;
 
-import static org.openjdk.asmtools.jasm.Constants.DEFAULT_MAJOR_VERSION;
-import static org.openjdk.asmtools.jasm.Constants.DEFAULT_MINOR_VERSION;
+import static org.openjdk.asmtools.jasm.CFVersion.DEFAULT_MAJOR_VERSION;
+import static org.openjdk.asmtools.jasm.CFVersion.DEFAULT_MINOR_VERSION;
 import org.openjdk.asmtools.util.I18NResourceBundle;
 import org.openjdk.asmtools.util.ProductInfo;
 import java.io.File;
@@ -42,6 +42,7 @@
      * Name of the program.
      */
     String program;
+
     /**
      * The stream where error message are printed.
      */
@@ -61,8 +62,7 @@
     private boolean strict = false;
     private String props = null;
     private int nwarnings = 0;
-    private short major_version = DEFAULT_MAJOR_VERSION;
-    private short minor_version = DEFAULT_MINOR_VERSION;
+    private CFVersion cfv = new CFVersion();
     private int bytelimit = 0;
     private boolean debugScanner = false;
     private boolean debugMembers = false;
@@ -70,6 +70,7 @@
     private boolean debugAnnot = false;
     private boolean debugInstr = false;
 
+
     /**
      * Constructor.
      */
@@ -197,8 +198,7 @@
                         return false;
                     }
                     try {
-                        major_version = Short.parseShort(versions[0]);
-                        minor_version = Short.parseShort(versions[1]);
+                        cfv = new CFVersion(Short.parseShort(versions[0]), Short.parseShort(versions[1]) );
                     } catch (NumberFormatException e) {
                         error(i18n.getString("jasm.error.invalid_major_minor_param"));
                         usage();
@@ -237,8 +237,7 @@
         strict = false;
         props = null;
         nwarnings = 0;
-        major_version = DEFAULT_MAJOR_VERSION;
-        minor_version = DEFAULT_MINOR_VERSION;
+        cfv = new CFVersion();
         bytelimit = 0;
     }
 
@@ -262,7 +261,7 @@
                     sf = new Environment(new File(inpname), out, nowarn);
                     sf.traceFlag = traceFlag;
                     sf.debugInfoFlag = debugInfoFlag;
-                    p = new Parser(sf, major_version, minor_version);
+                    p = new Parser(sf, cfv);
                     p.setDebugFlags(debugScanner, debugMembers, debugCP, debugAnnot, debugInstr);
                     p.parseFile();
                 } catch (FileNotFoundException ex) {
--- a/src/org/openjdk/asmtools/jasm/Modifiers.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/Modifiers.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -22,6 +22,8 @@
  */
 package org.openjdk.asmtools.jasm;
 
+import java.util.stream.Collectors;
+
 import static org.openjdk.asmtools.jasm.RuntimeConstants.*;
 import static org.openjdk.asmtools.jasm.JasmTokens.*;
 import static org.openjdk.asmtools.jasm.Tables.CF_Context;
@@ -38,36 +40,29 @@
      * Modifier masks
      */
     public static final int MM_ATTR        = SYNTHETIC_ATTRIBUTE | DEPRECATED_ATTRIBUTE;
+    public static final int MM_ACCESS      = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED;
 
-    public static final int MM_INTRF       = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | MM_ATTR ; // | ACC_MODULE  ;
-    public static final int MM_CLASS       = ACC_PUBLIC | ACC_FINAL|  ACC_SUPER | ACC_ABSTRACT | ACC_SYNTHETIC  | ACC_ANNOTATION | ACC_ENUM | MM_ATTR |  ACC_MODULE ;
-    public static final int MM_ACCESS      = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED; // | ACC_MODULE;
-    public static final int MM_FIELD       = MM_ACCESS | ACC_STATIC | ACC_FINAL |  ACC_VOLATILE | ACC_TRANSIENT |  ACC_SYNTHETIC | ACC_ENUM | MM_ATTR ; // |  ACC_MODULE ;
+    public static final int MM_INTRF       = MM_ACCESS  | ACC_ABSTRACT  | ACC_INTERFACE | MM_ATTR | ACC_ANNOTATION;
+    public static final int MM_CLASS       = MM_ACCESS  | ACC_FINAL     |  ACC_SUPER    | ACC_ABSTRACT | ACC_ENUM | MM_ATTR |  ACC_MODULE ;
+
+    public static final int MM_FIELD       = MM_ACCESS | ACC_STATIC | ACC_FINAL |  ACC_VOLATILE | ACC_TRANSIENT |  ACC_SYNTHETIC | ACC_ENUM | MM_ATTR ;
     public static final int MM_I_METHOD    = ACC_ABSTRACT | ACC_PUBLIC | ACC_PRIVATE | ACC_STATIC | ACC_VARARGS | ACC_BRIDGE | ACC_SYNTHETIC ; // interface method
     public static final int MM_A_METHOD    = MM_ACCESS | ACC_ABSTRACT | MM_ATTR;
-    public static final int MM_N_METHOD    = MM_ACCESS | ACC_STRICT | ACC_VARARGS | ACC_SYNTHETIC | MM_ATTR;  // <init>
+    public static final int MM_N_METHOD    = MM_ACCESS | ACC_STRICT | ACC_VARARGS | ACC_SYNTHETIC | MM_ATTR;                                   // <init>
     public static final int MM_METHOD      = MM_ACCESS | ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |  ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | ACC_ABSTRACT |  ACC_STRICT | ACC_SYNTHETIC | MM_ATTR ; // |  ACC_MODULE ;
     public static final int MM_INNERCLASS  = MM_ACCESS | ACC_STATIC | ACC_FINAL | ACC_SUPER | ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM | MM_ATTR ; // |  ACC_MODULE ;
-    public static final int MM_REQUIRES    = ACC_REEXPORT | ACC_SYNTHETIC | ACC_MANDATED ;
+    public static final int MM_REQUIRES    = ACC_TRANSITIVE | ACC_STATIC_PHASE  | ACC_SYNTHETIC | ACC_MANDATED ;
+    public static final int MM_EXPORTS     = ACC_SYNTHETIC | ACC_MANDATED ;
 
 
     private Modifiers() {
     }
 
-    public static Modifiers ModifiersObject() {
-        if (ref == null) {
-            ref = new Modifiers();
-        }
-        return ref;
-    }
-
     public static boolean validRequires(int mod) {
         return (mod & ~MM_REQUIRES) == 0;
     }
 
-    public static boolean validClass(int mod) {
-        return (mod & ~MM_CLASS) == 0;
-    }
+    public static boolean validExports(int mod) { return (mod & ~MM_EXPORTS) == 0; }
 
     public static boolean validInnerClass(int mod) {
         return (mod & ~MM_INNERCLASS) == 0;
@@ -85,6 +80,18 @@
         return (mod & ~MM_INTRF) == 0;
     }
 
+    public static int getInvalidModifiers4Interface(int mod) {
+        return  mod & ~MM_INTRF;
+    }
+
+    public static boolean validClass(int mod) {
+        return (mod & ~MM_CLASS) == 0;
+    }
+
+    public static int getInvalidModifiers4Class(int mod) {
+        return (mod & ~MM_CLASS);
+    }
+
     public static boolean validAbstractMethod(int mod) {
         return (mod & ~MM_A_METHOD) == 0;
     }
@@ -95,7 +102,7 @@
 
     public static boolean validInterfaceMethod(int mod, ClassData cd) {
         return ((mod & ~MM_I_METHOD) == 0) &&
-            (cd.major_version >= 52 || isPublic(mod) && isAbstract(mod) && !isStatic(mod));
+            (cd.cfv.major_version() >= 52 || isPublic(mod) && isAbstract(mod) && !isStatic(mod));
     }
 
     public static boolean validInterfaceField(int mod) {
@@ -194,7 +201,10 @@
         return isSyntheticPseudoMod(mod) || isDeprecatedPseudoMod(mod);
     }
 
-    public static boolean isReexport(int mod) { return (mod & ACC_REEXPORT) != 0;  }
+    public static boolean isTransitive(int mod) { return (mod & ACC_TRANSITIVE) != 0;  }
+
+    public static boolean isStaticPhase(int mod) { return (mod & ACC_STATIC_PHASE) != 0;  }
+
     /*
      * Checks that only one (or none) of the Access flags are set.
      */
@@ -202,7 +212,6 @@
         boolean retval = true;
         switch (mod & MM_ACCESS) {
             case 0:
-            //        case ACC_MODULE:
             case ACC_PUBLIC:
             case ACC_PRIVATE:
             case ACC_PROTECTED:
@@ -210,9 +219,7 @@
             default:
                 retval = false;
         }
-
         return retval;
-
     }
 
     /*
@@ -223,27 +230,41 @@
         return (mod & (flagA | flagB)) == (flagA | flagB);
     }
 
+    private static String getNames(int bits) {
+        return RuntimeConstants.ACC_NAMES.entrySet().stream()
+                .filter(e -> (e.getKey() & bits) != 0 && !e.getValue().isEmpty())
+                .map(s->s.getValue())
+                .collect(Collectors.joining(", "));
+    }
+
     /**
      * Check the modifier flags for the class
      *
-     * @param env The error reporting environment.
-     * @param mod The modifier flags being checked
-     * @param pos the position of the parser in the file
+     * @param env       The error reporting environment.
+     * @param mod       The modifier flags being checked
+     * @param scanner   The file parser
      */
-    public static void checkClassModifiers(Environment env, int mod, int pos) {
+    public static void checkClassModifiers(Environment env, int mod, Scanner scanner) {
         if (isInterface(mod)) {
-            if (!validInterface(mod)) {
-                env.error(pos, "warn.invalid.modifier.int");
+            if( isEnum(mod) ) {
+                env.error(scanner.pos, "warn.invalid.modifier.class.intenum");
+            } else if ( !validInterface(mod) ) {
+                String names = getNames(getInvalidModifiers4Interface(mod));
+                env.error(scanner.pos, "warn.invalid.modifier.int", (names.isEmpty() ? "." : " - " + names));
             }
             if (!isAbstract(mod)) {
-                env.error(pos, "warn.invalid.modifier.int.abs");
+                env.error(scanner.pos, "warn.invalid.modifier.int.abs");
             }
         } else {
-            if (!validClass(mod)) {
-                env.error(pos, "warn.invalid.modifier.class");
+            if ( scanner.token != Token.CLASS && !isEnum(mod) && scanner.token != Token.ANNOTATION) {
+                env.error(scanner.pos, "warn.missing.modifier.class");
+            }
+            if (! validClass(mod)) {
+                String names = getNames(getInvalidModifiers4Class(mod));
+                env.error(scanner.pos, "warn.invalid.modifier.class", (names.isEmpty() ? "." : " - " + names));
             }
             if (isAbstract(mod) && Modifiers.isFinal(mod)) {
-                env.error(pos, "warn.invalid.modifier.class.finabs");
+                env.error(scanner.pos, "warn.invalid.modifier.class.finabs");
             }
         }
     }
@@ -386,6 +407,9 @@
             sb.append(Token.FINAL.parsekey() + " ");
         }
         if ((context == CF_Context.CTX_CLASS || context == CF_Context.CTX_INNERCLASS) && isInterface(mod)) {
+            if (isAnnotation(mod)) {
+                sb.append(Token.ANNOTATION_ACCESS.parsekey() + " ");
+            }
             sb.append(Token.INTERFACE.parsekey() + " ");
         }
         if (isStrict(mod)) {
@@ -403,9 +427,6 @@
         if (context == CF_Context.CTX_METHOD && isMandated(mod)) {
             sb.append(Token.MANDATED.parsekey() + " ");
         }
-//      We don't have print identifiers for annotation flags
-//      if (isAnnotation(mod))
-//          sb.append(Tables.keywordName(Tables.ANNOTATION) + " ");
 
         return sb;
     }
@@ -423,9 +444,16 @@
         return sb.toString();
     }
 
+    public static String moduleFlags( int flags ) {
+
+
+        return "";
+    }
+
     public static String accessString(int mod, CF_Context context) {
-        StringBuffer sb = _accessString(mod, context);
-        return sb.toString();
+        return (context == CF_Context.CTX_MODULE) ?
+            moduleFlags(mod) :
+            _accessString(mod, context).toString();
     }
 
 }
--- a/src/org/openjdk/asmtools/jasm/ModuleAttr.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/ModuleAttr.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. 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
@@ -22,34 +22,63 @@
  */
 package org.openjdk.asmtools.jasm;
 
+import org.openjdk.asmtools.common.Module;
+
 import java.io.IOException;
 import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
-import static org.openjdk.asmtools.jasm.RuntimeConstants.ACC_NONE;
-import static org.openjdk.asmtools.jasm.RuntimeConstants.ACC_REEXPORT;
+/**
+ * The module attribute
+ */
+class ModuleAttr extends AttrData {
+  // shared data
+  private Module.Builder builder;
+  private final ClassData clsData;
+  private final Function<String, ConstantPool.ConstCell> findCellAsciz;
+  private final Function<String, ConstantPool.ConstCell> findCellClassByName;
+  private final Function<String, ConstantPool.ConstCell> findCellModuleByName;
+  private final Function<String, ConstantPool.ConstCell> findCellPackageByName;
 
-public class ModuleAttr extends AttrData {
-  // shared data
-  private final Module.Builder builder;
-  private final ClassData clsData;
-  private Module module;
+  // entries to populate tables of the module attribute
+  BiConsumer<String, Integer> requires       = (mn, f) -> this.builder.require(mn, f);
+  BiConsumer<String, Set<String>> exports    = (pn, ms) -> this.builder.exports(new Module.Exported(pn), ms);
+  BiConsumer<String, Set<String>> opens      = (pn, ms) -> this.builder.opens(new Module.Opened(pn), ms);
+  BiConsumer<String, Set<String>> provides   = (tn, ts) -> this.builder.provides(new Module.Provided(tn), ts);
+  Consumer<Set<String>>           uses       = (ts) -> this.builder.uses(ts);
 
   ModuleAttr(ClassData cdata) {
     super(cdata, Tables.AttrTag.ATT_Module.parsekey());
     builder = new Module.Builder();
     clsData = cdata;
+    findCellAsciz = (name) -> clsData.pool.FindCellAsciz(name);
+    findCellClassByName = (name) -> clsData.pool.FindCellClassByName(name);
+    findCellModuleByName = (name) -> clsData.pool.FindCellModuleByName(name);
+    findCellPackageByName = (name) -> clsData.pool.FindCellPackageByName(name);
   }
 
-  public ModuleAttr build() {
-    Content.instance.requiresStruct = new RequiresStruct();
-    Content.instance.exportsStruct = new ExportsStruct();
-    Content.instance.usesStruct = new UsesStruct();
-    Content.instance.providesStruct = new ProvidesStruct();
+  void openModule() {
+    builder.setModuleFlags(Module.Modifier.ACC_OPEN);
+  }
+  void setModuleName(String value) { builder.setModuleName(value);}
+
+  ModuleAttr build() {
+    Module module = builder.build();
+    Content.instance.header = new HeaderStruct(module.header, findCellModuleByName, findCellAsciz);
+    Content.instance.requiresStruct = new SetStruct<>(module.requires, findCellModuleByName, findCellAsciz);
+    Content.instance.exportsMapStruct = new MapStruct<>(module.exports, findCellPackageByName, findCellModuleByName );
+    Content.instance.opensMapStruct = new MapStruct<>(module.opens,findCellPackageByName, findCellModuleByName );
+    Content.instance.usesStruct = new SetStruct<>(module.uses, findCellClassByName, null);
+    Content.instance.providesMapStruct = new MapStruct<>(module.provides, findCellClassByName, findCellClassByName);
     return this;
   }
 
   @Override
-  public int attrLength() { return Content.instance.getLength(); }
+  public int attrLength() {
+    return Content.instance.getLength();
+  }
 
   @Override
   public void write(CheckedDataOutputStream out) throws IOException {
@@ -57,178 +86,205 @@
     Content.instance.write(out);
   }
 
-  /**
-   * Adds a module on which the current module has a dependence.
-   */
-  protected void require(String d, boolean reexports) {
-    builder.require(d, reexports);
-  }
-
-  /**
-   * Adds a qualified/an unqualified  module exports.
-   */
-  protected void exports(String p, Set<String> ms) { builder.exports(p, ms); }
-
-  /**
-   * Adds a service dependence's of this module
-   */
-  protected void use(String cn) {
-    builder.use(cn);
-  }
-
-  /**
-   * Adds a service that a module provides one implementation of.
-   */
-  protected void provide(String s, String impl) {
-    builder.provide(s, impl);
-  }
-
-  /**
-   * Gets the module if it is absent builds one
-   *
-   * @return the Module
-   */
-  private Module buildModuleIfAbsent() {
-    if (module == null) {
-      module = builder.build();
-    }
-    return module;
-  }
-
   private enum Content implements Data {
-
     instance {
       @Override
       public int getLength() {
-        return requiresStruct.getLength() + exportsStruct.getLength() +
-            usesStruct.getLength() + providesStruct.getLength();
+        return header.getLength() +
+            requiresStruct.getLength() +
+            exportsMapStruct.getLength() +
+            opensMapStruct.getLength() +
+            usesStruct.getLength() +
+            providesMapStruct.getLength();
       }
 
       @Override
       public void write(CheckedDataOutputStream out) throws IOException {
         // keep order!
+        header.write(out);
         requiresStruct.write(out);
-        exportsStruct.write(out);
+        exportsMapStruct.write(out);
+        opensMapStruct.write(out);
         usesStruct.write(out);
-        providesStruct.write(out);
+        providesMapStruct.write(out);
       }
     };
-    RequiresStruct requiresStruct;
-    ExportsStruct exportsStruct;
-    UsesStruct usesStruct;
-    ProvidesStruct providesStruct;
+
+    HeaderStruct header ;
+    SetStruct<Module.Dependence>  requiresStruct;
+    MapStruct<Module.Exported>    exportsMapStruct;
+    MapStruct<Module.Opened>      opensMapStruct;
+    SetStruct<Module.Uses>        usesStruct;
+    MapStruct<Module.Provided>    providesMapStruct;
   }
 
-  private final static class Module {
-    //* A service dependence's of this module
-    final Set<String> uses;
-    //* A module on which the current module has a dependence.
-    private final Set<Dependence> requires;
-    //* A module export, may be qualified or unqualified.
-    private final Map<String, Set<String>> exports;
-    //* A service that a module provides one or more implementations of.
-    private final Map<String, Set<String>> provides;
+  /**
+   * u2 {exports|opens}_count;
+   * {  u2 {exports|opens}_index;
+   * u2 {exports|opens}_flags;
+   * u2 {exports|opens}_to_count;
+   * u2 {exports|opens}_to_index[{exports|opens}_to_count];
+   * } {exports|opens}[{exports|opens}_count];
+   * or
+   * u2 provides_count;
+   * {  u2 provides_index;
+   * u2 provides_with_count;
+   * u2 provides_with_index[provides_with_count];
+   * } provides[provides_count];
+   */
+  private class MapStruct<T extends Module.TargetType> implements Data {
+    final List<Triplet<ConstantPool.ConstCell, Integer, List<ConstantPool.ConstCell>>> exportsOpensList = new ArrayList<>();
+    final List<Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>>> providesList = new ArrayList<>();
 
-    private Module(Set<Dependence> requires,
-                   Map<String, Set<String>> exports,
-                   Set<String> uses,
-                   Map<String, Set<String>> provides) {
-      this.requires = Collections.unmodifiableSet(requires);
-      this.exports = Collections.unmodifiableMap(exports);
-      this.uses = Collections.unmodifiableSet(uses);
-      this.provides = Collections.unmodifiableMap(provides);
+    MapStruct(Map<T, Set<String>> source,
+              Function<String,ConstantPool.ConstCell> nameFinder,
+              Function<String,ConstantPool.ConstCell> targetFinder) {
+      Objects.requireNonNull(source);
+      source.entrySet().stream()
+          .sorted(Map.Entry.comparingByKey())
+          .forEach(e -> {
+                ArrayList<ConstantPool.ConstCell> to = new ArrayList<>();
+                e.getValue().forEach(mn -> to.add(targetFinder.apply(mn)));
+                if (e.getKey().isFlagged()) {
+                  exportsOpensList.add(new Triplet<>
+                      ( nameFinder.apply(e.getKey().getTypeName()),
+                        ((Module.FlaggedTargetType) e.getKey()).getFlags(),
+                        to));
+                } else {
+                  providesList.add(new Pair<>(nameFinder.apply(e.getKey().getTypeName()),
+                      to));
+                }
+              }
+          );
     }
 
-    //* A module on which the current module has a dependence.
-    private final static class Dependence implements Comparable<Dependence> {
-      private final String mn;
-      private final boolean reexports;
-
-      public Dependence(String name, boolean reexports) {
-        this.mn = name;
-        this.reexports = reexports;
-      }
-
-      /**
-       * Returns the module name.
-       */
-      public String name() { return mn; }
-
-      /**
-       * Returns the public modifier of the requires.
-       */
-      public boolean isReexports() { return reexports; }
-
-      @Override
-      public int hashCode() {
-        return mn.hashCode() * 11 + Boolean.hashCode(reexports);
-      }
-
-      @Override
-      public boolean equals(Object o) {
-        if (o instanceof Dependence) {
-          Dependence d = (Dependence) o;
-          return this.mn.equals(d.mn) && Boolean.compare(reexports, d.isReexports()) == 0;
+    @Override
+    public void write(CheckedDataOutputStream out) throws IOException {
+      if (providesList.isEmpty()) {
+        out.writeShort(exportsOpensList.size());          // u2 {exports|opens}_count;
+        for (Triplet<ConstantPool.ConstCell, Integer, List<ConstantPool.ConstCell>> triplet : exportsOpensList) {
+          out.writeShort(triplet.first.arg);              // {  u2 {exports|opens}_index;
+          out.writeShort(triplet.second);                 //    u2 {exports|opens}_flags;
+          out.writeShort(triplet.third.size());           //    u2 {exports|opens}_to_count;
+          for (ConstantPool.ConstCell to : triplet.third)
+            out.writeShort(to.arg);                       // u2 {exports|opens}_to_index[{exports|opens}_to_count]; }
         }
-        return false;
-      }
-
-      @Override
-      public int compareTo(Dependence o) {
-        int rc = this.mn.compareTo(o.mn);
-        return rc != 0 ? rc : Boolean.compare(reexports, o.isReexports());
+      } else {
+        out.writeShort(providesList.size());              // u2 provides_count;
+        for (Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>> pair : providesList) {
+          out.writeShort(pair.first.arg);                 // {  u2 provides_index;
+          out.writeShort(pair.second.size());             //    u2 provides_with_count;
+          for (ConstantPool.ConstCell to : pair.second)
+            out.writeShort(to.arg);                       // u2 provides_with_index[provides_with_count]; }
+        }
       }
     }
 
-    /**
-     * The module builder.
-     */
-    private static final class Builder {
-      public final Set<Dependence> requires = new HashSet<>();
-      final Map<String, Set<String>> exports = new HashMap<>();
-      final Set<String> uses = new HashSet<>();
-      final Map<String, Set<String>> provides = new HashMap<>();
-
-      public Builder() {
-      }
-
-      public Builder require(String d, boolean reexports) {
-        requires.add(new Dependence(d, reexports));
-        return this;
-      }
-
-      public Builder exports(String p, Set<String> ms) {
-        Objects.requireNonNull(p);
-        Objects.requireNonNull(ms);
-        if (!exports.containsKey(p))
-          exports.put(p, new HashSet<>());
-        exports.get(p).addAll(ms);
-        return this;
-      }
-
-      public Builder use(String cn) {
-        uses.add(cn);
-        return this;
-      }
-
-      public Builder provide(String s, String impl) {
-        provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
-        return this;
-      }
-
-      /**
-       * @return The new module
-       */
-      public Module build() {
-        return new Module(requires, exports, uses, provides);
+    @Override
+    public int getLength() {
+      if (providesList.isEmpty()) {
+        // (u2:{exports|opens}_count) + (u2:{exports|opens}_index + u2:{exports|opens}_flags u2:{exports|opens}_to_count) * {exports|opens}_count +
+        return 2 + 6 * exportsOpensList.size() +
+        //  (u2:{exports|opens}_to_index) * {exports|opens}_to_count
+            exportsOpensList.stream().mapToInt(p -> p.third.size()).filter(s -> s > 0).sum() * 2;
+      } else {
+        // (u2 : provides_count) + (u2:provides_index + u2:provides_with_count) * provides_count +
+        return 2 + 4 * providesList.size() +
+        // (u2:provides_with_index) * provides_with_count
+            providesList.stream().mapToInt(p -> p.second.size()).filter(s -> s > 0).sum() * 2;
       }
     }
   }
 
-  // Helper class
+  private class HeaderStruct implements Data {
+    final ConstantPool.ConstCell index;
+    final int flags;
+    final ConstantPool.ConstCell versionIndex;
+
+    HeaderStruct(Module.Header source,
+                 Function<String,ConstantPool.ConstCell> nameFinder,
+                 Function<String,ConstantPool.ConstCell> versionFinder) {
+      index = nameFinder.apply(source.getModuleName());
+      versionIndex = (source.getModuleVersion() == null ) ? null : versionFinder.apply(source.getModuleVersion());
+      flags = source.getModuleFlags();
+    }
+
+    @Override
+    public void write(CheckedDataOutputStream out) throws IOException {
+      out.writeShort(index.arg);                                    // u2 module_name_index;
+      out.writeShort(flags);                                        // u2 module_flags;
+      out.writeShort(versionIndex == null ? 0 : versionIndex.arg);  // u2 module_version_index;
+    }
+
+    @Override
+    public int getLength() {
+      // u2:module_name_index) +  u2:module_flags +u2:module_version_index
+      return 6;
+    }
+  }
+
+  /**
+   * u2 uses_count;
+   * u2 uses_index[uses_count];
+   * or
+   * u2 requires_count;
+   * {  u2 requires_index;
+   *    u2 requires_flags;
+   *    u2 requires_version_index;
+   * } requires[requires_count];
+   */
+  private class SetStruct<T extends Module.TargetType> implements Data {
+    final List<ConstantPool.ConstCell> usesList = new ArrayList<>();
+    final List<Triplet<ConstantPool.ConstCell, Integer, ConstantPool.ConstCell>> requiresList = new ArrayList<>();
+
+    SetStruct(Set<T> source,
+              Function<String,ConstantPool.ConstCell> nameFinder,
+              Function<String,ConstantPool.ConstCell> versionFinder) {
+      Objects.requireNonNull(source);
+      source.forEach(e -> {
+        if (e.isFlagged()) {
+          requiresList.add(new Triplet<>(
+              nameFinder.apply(e.getTypeName()),
+              ((Module.FlaggedTargetType) e).getFlags(),
+              (((Module.VersionedFlaggedTargetType) e).getVersion() == null) ?
+                  null :
+                  versionFinder.apply(((Module.VersionedFlaggedTargetType) e).getVersion())));
+        } else {
+          usesList.add(nameFinder.apply((e.getTypeName())));
+        }
+      });
+    }
+
+    @Override
+    public void write(CheckedDataOutputStream out) throws IOException {
+      if (usesList.isEmpty()) {
+        out.writeShort(requiresList.size());                  // u2 requires_count;
+        for (Triplet<ConstantPool.ConstCell, Integer, ConstantPool.ConstCell> r : requiresList) {
+          out.writeShort(r.first.arg);                        // u2 requires_index;
+          out.writeShort(r.second);                           // u2 requires_flags;
+          out.writeShort(r.third == null ? 0 : r.third.arg);  // u2 requires_version_index;
+        }
+      } else {
+        out.writeShort(usesList.size());                      // u2 uses_count;
+        for (ConstantPool.ConstCell u : usesList)
+          out.writeShort(u.arg);                              // u2 uses_index[uses_count];
+      }
+    }
+
+    @Override
+    public int getLength() {
+      return usesList.isEmpty() ?
+          // (u2:requires_count) + (u2:requires_index + u2:requires_flags + u2:requires_version_index) * requires_count
+          2 + 6 * requiresList.size() :
+          // (u2:uses_count) + (u2:uses_index) * uses_count
+          2 + 2 * usesList.size();
+    }
+  }
+
+  // Helper classes
   private class Pair<F, S> {
-    public final F first;
-    public final S second;
+    final F first;
+    final S second;
 
     Pair(F first, S second) {
       this.first = first;
@@ -236,132 +292,12 @@
     }
   }
 
-  /**
-   * u2 requires_count;
-   * { u2 requires_index;
-   * u2 requires_flags;
-   * } requires[requires_count];
-   */
-  class RequiresStruct implements Data {
-    List<Pair<ConstantPool.ConstCell, Integer>> list = new ArrayList<>();
-
-    public RequiresStruct() {
-      buildModuleIfAbsent().requires.forEach(
-          r -> list.add(
-              new Pair<>(clsData.pool.FindCellAsciz(r.name()),
-                  r.isReexports() ? ACC_REEXPORT : ACC_NONE))
-      );
-    }
-
-    @Override
-    public int getLength() { return 2 + list.size() * 4; }
-
-    @Override
-    public void write(CheckedDataOutputStream out) throws IOException {
-      out.writeShort(list.size());    // u2 requires_count;
-      for (Pair<ConstantPool.ConstCell, Integer> p : list) {
-        out.writeShort(p.first.arg);      // u2 requires_index;
-        out.writeShort(p.second);         // u2 requires_flags;
-      }
+  public class Triplet<F, S, T>  extends Pair<F,S> {
+    private final T third;
+    Triplet(F first, S second, T third) {
+      super(first,second);
+      this.third = third;
     }
   }
 
-  /**
-   * u2 exports_count;
-   * { u2 exports_index;
-   * u2 exports_to_count;
-   * u2 exports_to_index[exports_to_count];
-   * } exports[exports_count];
-   */
-  private class ExportsStruct implements Data {
-    final List<Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>>> exports = new ArrayList<>();
-
-    ExportsStruct() {
-      Objects.requireNonNull(module);
-      //(un)qualified module exports
-      buildModuleIfAbsent().exports.entrySet().stream()
-          .sorted(Map.Entry.comparingByKey())
-          .forEach(e -> {
-                ArrayList<ConstantPool.ConstCell> to = new ArrayList<>();
-                e.getValue().forEach(mn -> to.add(clsData.pool.FindCellAsciz(mn)));
-                exports.add(new Pair<>(clsData.pool.FindCellAsciz(e.getKey()), to));
-              }
-          );
-    }
-
-    @Override
-    public int getLength() {
-      return 2 + 4 * exports.size() + exports.stream().mapToInt(p->p.second.size()).filter(s->s>0).sum() * 2;
-    }
-
-    @Override
-    public void write(CheckedDataOutputStream out) throws IOException {
-      out.writeShort(exports.size());         // u2 exports_count;
-      for (Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>> pair : exports) {
-        out.writeShort(pair.first.arg);       // u2 exports_index;
-        out.writeShort(pair.second.size());   // u2 exports_to_count;
-        for( ConstantPool.ConstCell to : pair.second ) {
-            out.writeShort(to.arg);           // u2 exports_to_index[exports_to_count];
-        }
-      }
-    }
-  }
-
-  /**
-   * u2 uses_count;
-   * u2 uses_index[uses_count];
-   */
-  private class UsesStruct implements Data {
-    final List<ConstantPool.ConstCell> uses = new ArrayList<>();
-
-    UsesStruct() {
-      buildModuleIfAbsent().uses.stream().sorted().forEach(u -> uses.add(clsData.pool.FindCellAsciz(u)));
-    }
-
-    @Override
-    public int getLength() {
-      return 2 + 2 * uses.size();
-    }
-
-    @Override
-    public void write(CheckedDataOutputStream out) throws IOException {
-      out.writeShort(uses.size());
-      for (ConstantPool.ConstCell u : uses)
-        out.writeShort(u.arg);
-    }
-  }
-
-  /**
-   * u2 provides_count;
-   * { u2 provides_index;
-   * u2 with_index;
-   * } provides[provides_count];
-   */
-  private class ProvidesStruct implements Data {
-    List<Pair<ConstantPool.ConstCell, ConstantPool.ConstCell>> list = new ArrayList<>();
-
-    protected ProvidesStruct() {
-      buildModuleIfAbsent().provides.entrySet().stream()
-          .sorted(Map.Entry.comparingByKey())
-          .forEach(e -> e.getValue().stream()
-              .sorted()
-              .forEach(impl -> list.add(new Pair<>(
-                  clsData.pool.FindCellAsciz(e.getKey()), clsData.pool.FindCellAsciz(impl))
-              )));
-    }
-
-    @Override
-    public int getLength() {
-      return 2 + list.size() * 4;
-    }
-
-    @Override
-    public void write(CheckedDataOutputStream out) throws IOException {
-      out.writeShort(list.size());        // u2 provides_count;
-      for (Pair<ConstantPool.ConstCell, ConstantPool.ConstCell> p : list) {
-        out.writeShort(p.first.arg);      // u2 requires_index;
-        out.writeShort(p.second.arg);     // u2 requires_flags;
-      }
-    }
-  }
 }
--- a/src/org/openjdk/asmtools/jasm/Parser.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/Parser.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -23,13 +23,16 @@
 
 package org.openjdk.asmtools.jasm;
 
+import org.openjdk.asmtools.common.Module;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 import static org.openjdk.asmtools.jasm.ConstantPool.*;
-import static org.openjdk.asmtools.jasm.Constants.DEFAULT_MAJOR_VERSION;
-import static org.openjdk.asmtools.jasm.Constants.DEFAULT_MINOR_VERSION;
 import static org.openjdk.asmtools.jasm.JasmTokens.Token;
 import static org.openjdk.asmtools.jasm.RuntimeConstants.*;
 import static org.openjdk.asmtools.jasm.Tables.*;
@@ -62,13 +65,23 @@
  * parser for error recovery.
  */
 class Parser extends ParseBase {
+    @FunctionalInterface
+    interface NameSupplier {
+        String get() throws IOException;
+    }
+
+    @FunctionalInterface
+    interface Method {
+        void call() throws IOException;
+    }
+
 
   /*-------------------------------------------------------- */
   /* Annotation Inner Classes */
     /**
      * The main compile error for the parser
      */
-    public static class CompilerError extends Error {
+    static class CompilerError extends Error {
 
         CompilerError(String message) {
             super(message);
@@ -78,21 +91,18 @@
   /* Parser Fields */
 
     private ArrayList                   clsDataList = new ArrayList<>();
-    protected ClassData                 cd = null;
+    ClassData                           cd = null;
+    CodeAttr                            curCode;
     protected ConstantPool              pool = null;
-    private MethodData                  curMethod;
-    protected CodeAttr                  curCode;
     private String                      pkg = null;
     private String                      pkgPrefix = "";
     private ArrayList<AnnotationData>   pkgAnnttns = null;
-    private String                      mdl = null;
-    private ArrayList<AnnotationData>   mdlAnnttns = null;
     private ArrayList<AnnotationData>   clsAnnttns = null;
     private ArrayList<AnnotationData>   memberAnnttns = null;
-    private short                       major_version = DEFAULT_MAJOR_VERSION;
-    private short                       minor_version = DEFAULT_MINOR_VERSION;
     private boolean                     explicitcp = false;
+    private String                      moduleName = null;
     private ModuleAttr                  moduleAttribute;
+    private CFVersion                   cfv;
 
 
     /** other parser components */
@@ -107,24 +117,17 @@
     /**
      * Create a parser
      */
-    /*
-    protected Parser(Environment sf) throws IOException {
-        this.scanner = new Scanner(sf);
-    }
-    * */
-
-    protected Parser(Environment sf, short major_version, short minor_version) throws IOException {
+    protected Parser(Environment sf, CFVersion cfVersion) throws IOException {
         super.init(new Scanner(sf), this, sf);
-        this.major_version = major_version;
-        this.minor_version = minor_version;
+        this.cfv = cfVersion;
         this.annotParser = new ParserAnnotation(scanner, this, env);
         this.cpParser = new ParserCP(scanner, this, env);
         this.instrParser = new ParserInstr(scanner, this, cpParser, env);
     }
 
 
-    protected void setDebugFlags(boolean debugScanner, boolean debugMembers,
-            boolean debugCP, boolean debugAnnot, boolean debugInstr) {
+    void setDebugFlags(boolean debugScanner, boolean debugMembers,
+                       boolean debugCP, boolean debugAnnot, boolean debugInstr) {
 
         enableDebug(debugMembers);
         scanner.enableDebug(debugScanner);
@@ -136,15 +139,16 @@
 
     /*---------------------------------------------*/
 
-    protected String encodeClassString(String classname) {
+    String encodeClassString(String classname) {
         return "L" + classname + ";";
     }
 
+
     /**
      * Parses version in package statements
      */
 
-    protected final void parseVersionPkg() throws IOException  {
+    private void parseVersionPkg() throws IOException  {
         if (scanner.token == Token.SEMICOLON) {
             return;
         }
@@ -156,7 +160,7 @@
             if (scanner.token != Token.INTVAL) {
                 break parse_ver;
             }
-            major_version = (short)scanner.intValue;
+            cfv.setMajorVersion((short)scanner.intValue);
             scanner.scan();
             if (scanner.token != Token.COLON) {
                 break parse_ver;
@@ -165,16 +169,16 @@
             if (scanner.token != Token.INTVAL) {
                 break parse_ver;
             }
-            minor_version = (short)scanner.intValue;
+            cfv.setMinorVersion((short)scanner.intValue);
             scanner.scan();
-            debugScan("     [Parser.parseVersionPkg]: " + major_version + ":" + minor_version);
+            debugScan("     [Parser.parseVersionPkg]: " + cfv.asString());
             return;
         }
         env.error(scanner.pos, "version.expected");
         throw new Scanner.SyntaxError();
     }
 
-    protected final void parseVersion() throws IOException  {
+    private void parseVersion() throws IOException  {
         if (scanner.token == Token.LBRACE) {
             return;
         }
@@ -186,7 +190,7 @@
             if (scanner.token != Token.INTVAL) {
                 break parse_ver;
             }
-            cd.major_version = (short)scanner.intValue;
+            cfv.setMajorVersion((short)scanner.intValue);
             scanner.scan();
             if (scanner.token != Token.COLON) {
                 break parse_ver;
@@ -195,9 +199,9 @@
             if (scanner.token != Token.INTVAL) {
                 break parse_ver;
             }
-            cd.minor_version = (short)scanner.intValue;
+            cfv.setMinorVersion((short)scanner.intValue);
             scanner.scan();
-            debugStr("parseVersion: " + cd.major_version + ":" + cd.minor_version);
+            debugStr( "parseVersion: " + cfv.asString());
             return;
         }
         env.error(scanner.pos, "version.expected");
@@ -207,7 +211,7 @@
     /**
      * Parse an internal name: identifier.
      */
-    protected String parseIdent() throws Scanner.SyntaxError, IOException {
+    String parseIdent() throws Scanner.SyntaxError, IOException {
         String v = scanner.idValue;
         scanner.expect(Token.IDENT);
         return v;
@@ -216,7 +220,7 @@
     /**
      * Parse a local variable
      */
-    protected void parseLocVarDef() throws Scanner.SyntaxError, IOException {
+    void parseLocVarDef() throws Scanner.SyntaxError, IOException {
         if (scanner.token == Token.INTVAL) {
             int v = scanner.intValue;
             scanner.scan();
@@ -234,7 +238,7 @@
         }
     }
 
-    protected Argument parseLocVarRef() throws Scanner.SyntaxError, IOException {
+    Argument parseLocVarRef() throws Scanner.SyntaxError, IOException {
         if (scanner.token == Token.INTVAL) {
             int v = scanner.intValue;
             scanner.scan();
@@ -246,7 +250,7 @@
         }
     }
 
-    protected void parseLocVarEnd() throws Scanner.SyntaxError, IOException {
+    void parseLocVarEnd() throws Scanner.SyntaxError, IOException {
         if (scanner.token == Token.INTVAL) {
             int v = scanner.intValue;
             scanner.scan();
@@ -258,8 +262,8 @@
         }
     }
 
-    protected void parseMapItem(DataVector map) throws Scanner.SyntaxError, IOException {
-        StackMapType itemType = stackMapType(scanner.intValue);
+    void parseMapItem(DataVector map) throws Scanner.SyntaxError, IOException {
+        StackMapType itemType = stackMapType(scanner.intValue, null);
         ConstType tag = null;
         Argument arg = null;
         Token ptoken = scanner.token;
@@ -280,9 +284,7 @@
                     break resolve;
                 case IDENT:
                     itemType = stackMapType(sValue);
-                    ConstType tg = Tables.tag(sValue);
-//                    tag = (tg == null) ? 0 : tg.value;
-                    tag = tg;
+                    tag = Tables.tag(sValue);
                     if (itemType != null) { // itemType OK
                         if ((tag != null) // ambiguity: "int," or "int 77,"?
                                 && (scanner.token != Token.SEMICOLON)
@@ -319,7 +321,7 @@
     /**
      * Parse an external name: CPINDEX, string, or identifier.
      */
-    protected ConstCell parseName() throws Scanner.SyntaxError, IOException {
+    ConstCell parseName() throws Scanner.SyntaxError, IOException {
         debugScan("------- [Parser.parseName]: ");
         String v;
         switch (scanner.token) {
@@ -361,7 +363,7 @@
     /**
      * Parses a field or method reference for method handle.
      */
-    protected ConstCell parseMethodHandle(SubTag subtag) throws Scanner.SyntaxError, IOException {
+    ConstCell parseMethodHandle(SubTag subtag) throws Scanner.SyntaxError, IOException {
         ConstCell refCell;
         switch (subtag) {
             case REF_GETFIELD: case REF_GETSTATIC:
@@ -385,7 +387,7 @@
     /**
      * Parses a sub-tag value in method handle.
      */
-    protected SubTag parseSubtag() throws Scanner.SyntaxError, IOException {
+    SubTag parseSubtag() throws Scanner.SyntaxError, IOException {
         SubTag subtag = null;
         switch (scanner.token) {
             case IDENT:
@@ -403,7 +405,7 @@
         return subtag;
     }
 
-    protected ConstCell parseClassName(boolean uncond) throws Scanner.SyntaxError, IOException {
+    ConstCell parseClassName(boolean uncond) throws Scanner.SyntaxError, IOException {
         String v;
         switch (scanner.token) {
             case CPINDEX: {
@@ -433,9 +435,9 @@
             case IDENT:
                 v = scanner.idValue;
                 scanner.scan();
-                if (uncond || (scanner.token == Token.FIELD)) {  //?????????????????????????????????????
-                    if ((v.indexOf("/") == -1)           // class identifier doesn't contain "/"
-                            && (v.indexOf("[")==-1)){    // class identifier doesn't contain "["
+                if (uncond || (scanner.token == Token.FIELD)) {
+                    if ((!v.contains("/"))             // class identifier doesn't contain "/"
+                            && (!v.contains("["))){    // class identifier doesn't contain "["
                         v = pkgPrefix + v; // add package
                     }
                 }
@@ -443,7 +445,7 @@
             default:
                 ConstType key = Tables.tag(scanner.token.value());
                 env.traceln("%%%%% Unrecognized token [" + scanner.token + "]: '" + (key == null? "null":key.parseKey()) + "'.");
-                env.error(scanner.prevPos, "name.expected");
+                env.error(scanner.prevPos, "name.expected", "\"" + scanner.token.parsekey() + "\"");
                 throw new Scanner.SyntaxError();
         }
     }
@@ -453,7 +455,7 @@
      * Parse a signed integer of size bytes long.
      *  size = 1 or 2
      */
-    protected Argument parseInt(int size) throws Scanner.SyntaxError, IOException {
+    Argument parseInt(int size) throws Scanner.SyntaxError, IOException {
         if (scanner.token == Token.BITS) {
             scanner.scan();
         }
@@ -492,7 +494,7 @@
      * Parse an unsigned integer of size bytes long.
      *  size = 1 or 2
      */
-    protected Argument parseUInt(int size) throws Scanner.SyntaxError, IOException {
+    Argument parseUInt(int size) throws Scanner.SyntaxError, IOException {
         if (scanner.token != Token.INTVAL) {
             env.error(scanner.pos, "int.expected");
             throw new Scanner.SyntaxError();
@@ -525,7 +527,7 @@
     /**
      * Parse constant declaration
      */
-    protected void parseConstDef() throws IOException {
+    private void parseConstDef() throws IOException {
         for (;;) {
             if (scanner.token == Token.CPINDEX) {
                 int cpx = scanner.intValue;
@@ -571,11 +573,12 @@
                 case STRICT:       nextmod = ACC_STRICT;       break;
                 case ENUM:         nextmod = ACC_ENUM;         break;
                 case SYNTHETIC:    nextmod = ACC_SYNTHETIC;    break;
+                case ANNOTATION_ACCESS:
+                                   nextmod = ACC_ANNOTATION;    break;
 
                 case DEPRECATED:   nextmod = DEPRECATED_ATTRIBUTE;   break;
-                case MANDATED:       nextmod = ACC_MANDATED;       break;
+                case MANDATED:     nextmod = ACC_MANDATED;           break;
                 default:
-//                    env.traceln(" is not a mod");
                     return nextmod;
             }
             prevpos = scanner.pos;
@@ -587,7 +590,7 @@
         }
     }
 
-    protected int scanModifiers() throws IOException {
+    int scanModifiers() throws IOException {
         int mod = 0, nextmod;
 
         while (true) {
@@ -602,7 +605,7 @@
     /**
      * Parse a field.
      */
-    protected void parseField(int mod) throws Scanner.SyntaxError, IOException {
+    private void parseField(int mod) throws Scanner.SyntaxError, IOException {
         debugStr("  [Parser.parseField]: <<<Begin>>>");
         // check access modifiers:
         Modifiers.checkFieldModifiers(cd, mod, scanner.pos);
@@ -639,7 +642,7 @@
     /**
      * Scan method's signature to determine size of parameters.
      */
-    protected int countParams(int pos, ConstCell sigCell) throws Scanner.SyntaxError, IOException {
+    private int countParams(ConstCell sigCell) throws Scanner.SyntaxError, IOException {
         String sig;
         try {
             ConstValue_String strConst = (ConstValue_String) sigCell.ref;
@@ -706,15 +709,14 @@
                 }
             }
         }
-        env.error(scanner.pos, "msig.malformed", new Integer(k).toString(),
-                new Integer(errparam).toString());
+        env.error(scanner.pos, "msig.malformed", Integer.toString(k),Integer.toString(errparam));
         return loccnt;
     }
 
     /**
      * Parse a method.
      */
-    protected void parseMethod(int mod) throws Scanner.SyntaxError, IOException {
+    private void parseMethod(int mod) throws Scanner.SyntaxError, IOException {
 
         // The start of the method
         int posa = scanner.pos;
@@ -732,12 +734,12 @@
 
         scanner.expect(Token.COLON);
         ConstCell typeCell = parseName();
-        int paramcnt = countParams(scanner.pos, typeCell);
+        int paramcnt = countParams(typeCell);
         if ((! Modifiers.isStatic(mod)) && ! is_clinit) {
             paramcnt++;
         }
         if (paramcnt > 255) {
-            env.error(scanner.pos, "warn.msig.more255", new Integer(paramcnt).toString());
+            env.error(scanner.pos, "warn.msig.more255", Integer.toString(paramcnt));
         }
         // Parse throws clause
         ArrayList<ConstCell> exc_table = null;
@@ -764,7 +766,7 @@
             defAnnot = annotParser.parseDefaultAnnotation();
         }
 
-        curMethod = cd.StartMethod(mod, nameCell, typeCell, exc_table);
+      MethodData curMethod = cd.StartMethod(mod, nameCell, typeCell, exc_table);
         Argument max_stack = null, max_locals = null;
 
         if (scanner.token == Token.STACK) {
@@ -806,7 +808,7 @@
             curMethod.addAnnotations(memberAnnttns);
         }
         cd.EndMethod();
-        debugStr("  [Parser.parseMethod]: Method: " + curMethod );
+        debugStr("  [Parser.parseMethod]: Method: " + curMethod);
 
     }  // end parseMethod
 
@@ -814,7 +816,7 @@
     /**
      * Parse a (CPX based) BootstrapMethod entry.
      */
-    protected void parseCPXBootstrapMethod(int mod) throws Scanner.SyntaxError, IOException {
+    private void parseCPXBootstrapMethod() throws Scanner.SyntaxError, IOException {
         // Parses in the form:
         // BOOTSTRAPMETHOD CPX_MethodHandle (CPX_Arg)* ;
         if (scanner.token == Token.CPINDEX) {
@@ -849,7 +851,7 @@
     /**
      * Parse an inner class.
      */
-    protected void parseInnerClass(int mod) throws Scanner.SyntaxError, IOException {
+    private void parseInnerClass(int mod) throws Scanner.SyntaxError, IOException {
         // Parses in the form:
         // MODIFIERS (INNERCLASSNAME =)? (INNERCLASS) (OF OUTERCLASS)? ;
         //
@@ -912,13 +914,11 @@
 
     }
 
-
     private void parseInnerClass_s2(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException {
         // scanner.token is either "CLASS IDENT" or "CPX_Class"
         if ((scanner.token == Token.CPINDEX) || (scanner.token == Token.CLASS)) {
             if (scanner.token == Token.CPINDEX) {
-                int cpx = scanner.intValue;
-                innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
+              innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
             }
 
             if (scanner.token == Token.CLASS) {
@@ -956,8 +956,7 @@
                outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
             }
             if (scanner.token == Token.CPINDEX) {
-                int cpx = scanner.intValue;
-                outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
+              outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
             }
 
             if (scanner.token == Token.SEMICOLON) {
@@ -983,7 +982,7 @@
             }
 
             ConstValue_Cell ici_val = (ConstValue_Cell) innerClass.ref;
-            ConstCell ici_ascii = (ConstCell) ici_val.cell;
+            ConstCell ici_ascii = ici_val.cell;
             // Constant pool may not be numberized yet.
             //
             // check values before dereference on a trace.
@@ -1001,7 +1000,7 @@
             if (outerClass != pool.getCell(0)) {
                 if (outerClass.arg != 0) {
                     ConstValue_Cell oci_val = (ConstValue_Cell) outerClass.ref;
-                    ConstCell  oci_ascii = (ConstCell) oci_val.cell;
+                    ConstCell  oci_ascii = oci_val.cell;
                     if (oci_ascii.ref == null) {
                         env.trace(" of <#cpx-unresolved>  ");
                     } else {
@@ -1032,7 +1031,7 @@
      * Scan to a matching '}', ']' or ')'. The current scanner.token must be
      * a '{', '[' or '(';
      */
-    protected void match(Token open, Token close) throws IOException {
+    private void match(Token open, Token close) throws IOException {
         int depth = 1;
 
         while (true) {
@@ -1055,7 +1054,7 @@
      * discarding scanner.tokens until an EOF or a possible legal
      * continuation is encountered.
      */
-    protected void recoverField() throws Scanner.SyntaxError, IOException {
+    private void recoverField() throws Scanner.SyntaxError, IOException {
         while (true) {
             switch (scanner.token) {
                 case EOF:
@@ -1070,6 +1069,7 @@
                 case NATIVE:
 //                case INTERFACE: see below
                 case ABSTRACT:
+                case ANNOTATION_ACCESS:
 
                 // possible begin of a field, continue
                 return;
@@ -1095,7 +1095,7 @@
                 case IMPORT:
                 case PACKAGE:
                     // begin of something outside a class, panic more
-                    endClass(scanner.pos);
+                    endClass();
                     scanner.debugStr("    [Parser.recoverField]: pos: [" + scanner.pos + "]: ");
                     throw new Scanner.SyntaxError();
 
@@ -1110,14 +1110,14 @@
     /**
      * Parse a class or interface declaration.
      */
-    protected void parseClass(int mod) throws IOException {
+    private void parseClass(int mod) throws IOException {
         int posa = scanner.pos;
         debugStr("   [Parser.parseClass]:  Begin ");
         // check access modifiers:
-        Modifiers.checkClassModifiers(env, mod, posa);
+        Modifiers.checkClassModifiers(env, mod, scanner);
 
         if (cd == null) {
-            cd = new ClassData(env, major_version, minor_version);
+            cd = new ClassData(env, cfv);
             pool = cd.pool;
         }
 
@@ -1128,6 +1128,15 @@
         // move the tokenizer to the identifier:
         if (scanner.token == Token.CLASS) {
             scanner.scan();
+        } else if (scanner.token == Token.ANNOTATION) {
+            scanner.scan();
+            if( scanner.token == Token.INTERFACE ) {
+                mod |= ACC_ANNOTATION | ACC_INTERFACE;
+                scanner.scan();
+            } else {
+                env.error(scanner.prevPos, "token.expected", Token.ANNOTATION.parsekey() + Token.INTERFACE.parsekey());
+                throw new Scanner.SyntaxError();
+            }
         }
 
         // Parse the class name
@@ -1149,6 +1158,9 @@
             }
             scanner.scan();
             cd.fileExtension="."+fileExtension;
+        } else if (scanner.token == Token.MODULE) {
+            env.error(scanner.prevPos, "token.expected", Token.OPEN.parsekey() );
+            throw new Scanner.SyntaxError();
         } else if (scanner.token == Token.SEMICOLON) {
             // drop the semi-colon following a name
             scanner.scan();
@@ -1194,39 +1206,36 @@
                     // Empty fields are allowed
                     scanner.scan();
                     break;
-
                 case CONST:
                     scanner.scan();
                     parseConstDef();
                     explicitcp = true;
                     break;
-
-
                 default:   // scanner.token is some member.
                     parseClassMembers();
             }  // end switch
         } // while
-
         scanner.expect(Token.RBRACE);
-
         // End the class
-        endClass(scanner.prevPos);
+        endClass();
     } // end parseClass
 
   /**
-   * Parses a module, package or type name in a module statement(s)
+   * Parses a package or type name in a module statement(s)
    */
     private String parseTypeName() throws IOException {
-        String name = "";
+        String name = "", field = "";
         while (true) {
-            if ( scanner.token == Token.IDENT ) {
-                name += String.format("%s%s", name.isEmpty() ? "" : "/", scanner.idValue);
+            if ( scanner.token.possibleModuleName() ) {
+                name = name + field + scanner.idValue;
                 scanner.scan();
             } else {
-                env.error(scanner.pos, "name.expected");
+                env.error(scanner.pos, "name.expected",  "\"" + scanner.token.parsekey() + "\"");
                 throw new Scanner.SyntaxError();
             }
             if(scanner.token == Token.FIELD) {
+                env.error(scanner.pos, "warn.dot.will.be.converted");
+                field = "/";
                 scanner.scan();
             } else {
                 break;
@@ -1235,56 +1244,101 @@
         return name;
     }
 
+    /**
+     * Parses a module name in a module statement(s)
+     */
+    private String parseModuleName() throws IOException {
+        String name = "", field = "";
+        while (true) {
+            if ( scanner.token.possibleModuleName() ) {
+                name = name + field + scanner.idValue;
+                scanner.scanModuleStatement();
+            } else {
+                env.error(scanner.pos, "module.name.expected",  "\"" + scanner.token.parsekey() + "\"");
+                throw new Scanner.SyntaxError().Fatal();
+            }
+            if(scanner.token == Token.FIELD) {
+                field = Character.toString((char) scanner.token.value());
+                scanner.scanModuleStatement();
+            } else {
+                break;
+            }
+        }
+        System.out.println(name);
+        return name;
+    }
+
   /**
    * Parse a module declaration.
    */
-  protected void parseModule() throws IOException {
+  private void parseModule() throws IOException {
     debugStr("   [Parser.parseModule]:  Begin ");
+    if (cd == null) {
+      cd = new ClassData(env, cfv);
+      pool = cd.pool;
+    }
+    if (clsAnnttns != null) {
+        cd.addAnnotations(clsAnnttns);
+    }
+    moduleAttribute    = new ModuleAttr(cd);
 
-    if (cd == null) {
-      cd = new ClassData(env, major_version, minor_version);
-      pool = cd.pool;
+    if( scanner.token == Token.OPEN ) {
+        moduleAttribute.openModule();
+        scanner.scan();
     }
 
     // move the tokenizer to the identifier:
     if (scanner.token == Token.MODULE) {
-      scanner.scan();
+        scanner.scanModuleStatement();
+        // scanner.scan();
+    } else {
+        env.error(scanner.pos, "token.expected", Token.MODULE.parsekey() );
+        throw new Scanner.SyntaxError().Fatal();
     }
-
     // Parse the module name
-    String name = parseTypeName();
-
-    if (scanner.token == Token.SEMICOLON) {
-      // drop the semi-colon following a name
-      scanner.scan();
+    moduleName = parseModuleName();
+    if (moduleName.isEmpty()) {
+        env.error(scanner.pos, "name.expected");
+        throw new Scanner.SyntaxError().Fatal();
     }
-    if (name.isEmpty()) {
-      env.error(scanner.pos, "name.expected");
-      throw new Scanner.SyntaxError();
-    }
-    ConstCell this_cpx = pool.FindCellClassByName(name + "/module-info");
-    moduleAttribute    = new ModuleAttr(cd);
+    moduleAttribute.setModuleName(moduleName);
 
     parseVersion();
     scanner.expect(Token.LBRACE);
 
     // Begin a new class as module
-    cd.initAsModule(this_cpx);
+    cd.initAsModule();
 
     // Parse module statement(s)
     while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) {
       switch (scanner.token) {
         case REQUIRES:
-          scanRequires(moduleAttribute);
+          scanRequires(moduleAttribute.requires);
           break;
         case EXPORTS:
-          scanExports(moduleAttribute);
+          scanStatement(moduleAttribute.exports,
+              this::parseTypeName,
+              this::parseModuleName,
+              Token.TO,
+              true,
+              "exports.expected");
+          break;
+        case OPENS:
+          scanStatement(moduleAttribute.opens,
+              this::parseTypeName,
+              this::parseModuleName,
+              Token.TO,  true, "opens.expected");
           break;
         case USES:
-          scanUses(moduleAttribute);
+            scanStatement(moduleAttribute.uses, "uses.expected");
           break;
         case PROVIDES:
-          scanProvidesWith(moduleAttribute);
+          scanStatement(moduleAttribute.provides,
+              this::parseTypeName,
+              this::parseTypeName,
+              Token.WITH,
+              false,
+              "provides.expected");
           break;
         case SEMICOLON:
           // Empty fields are allowed
@@ -1292,7 +1346,7 @@
           break;
         default:
           env.error(scanner.pos, "module.statement.expected");
-          throw new Scanner.SyntaxError();
+          throw new Scanner.SyntaxError().Fatal();
       }  // end switch
     } // while
     scanner.expect(Token.RBRACE);
@@ -1300,197 +1354,165 @@
     endModule();
   } // end parseModule
 
+
   /**
-   * Scans  ModuleStatement: provides TypeName with TypeName ;
+   * Scans  ModuleStatement: requires [transitive] [static] ModuleName ;
    */
-  private void scanProvidesWith(ModuleAttr attr) throws IOException {
-    String s = "", impl = "";
-    boolean inWith = false;
+  private void scanRequires(BiConsumer<String, Integer> action) throws IOException {
+    int flags = 0;
+    String mn = "";
+    scanner.scanModuleStatement();
+    while (scanner.token != Token.SEMICOLON) {
+      switch (scanner.token) {
+        case STATIC:
+          if (  ((flags & (1 << Module.Modifier.ACC_STATIC_PHASE.asInt())) != 0) || !mn.isEmpty()) {
+            env.error(scanner.pos, "requires.expected");
+            throw new Scanner.SyntaxError().Fatal();
+          }
+          flags |= Module.Modifier.ACC_STATIC_PHASE.asInt();
+          break;
+        case TRANSITIVE:
+          if (  ((flags & (1 << Module.Modifier.ACC_TRANSITIVE.asInt())) != 0) || !mn.isEmpty()) {
+            env.error(scanner.pos, "requires.expected");
+            throw new Scanner.SyntaxError().Fatal();
+          }
+          flags |= Module.Modifier.ACC_TRANSITIVE.asInt();
+          break;
+        case IDENT:
+          if (!mn.isEmpty()) {
+            env.error(scanner.pos, "requires.expected");
+            throw new Scanner.SyntaxError().Fatal();
+          }
+          mn = parseModuleName();
+          continue;
+        default:
+          if( mn.isEmpty() && scanner.token.possibleModuleName() ) {
+              mn = parseModuleName();
+              continue;
+          } else {
+              env.error(scanner.pos, "requires.expected");
+              throw new Scanner.SyntaxError().Fatal();
+          }
+      }
+      scanner.scanModuleStatement();
+    }
+    // Token.SEMICOLON
+    if (mn.isEmpty()) {
+      env.error(scanner.pos, "requires.expected");
+      throw new Scanner.SyntaxError().Fatal();
+    }
+    action.accept(mn, flags);
+    scanner.scanModuleStatement();
+  }
+
+    /**
+     * Scans  ModuleStatement: uses TypeName;
+     */
+    private void scanStatement(Consumer<Set<String>> action, String err) throws IOException {
+        HashSet<String> names = scanList( ()->scanner.scan(), this::parseTypeName, err, true);
+        // Token.SEMICOLON
+        if (names.size() != 1 ) {
+            env.error(scanner.pos, err);
+            throw new Scanner.SyntaxError().Fatal();
+        }
+        action.accept(names);
+        scanner.scan();
+    }
+
+
+    /**
+   * Scans  Module Statement(s):
+   * exports  packageName [to ModuleName {, ModuleName}] ;
+   * opens    packageName [to ModuleName {, ModuleName}] ;
+   * provides TypeName with TypeName [,typeName] ;
+   */
+  private void scanStatement(BiConsumer<String, Set<String>> action,
+                             NameSupplier source,
+                             NameSupplier target,
+                             Token startList,
+                             boolean emptyListAllowed,
+                             String err) throws IOException {
+    String typeName = "";
+    HashSet<String> names = new HashSet<>();
     scanner.scan();
     while (scanner.token != Token.SEMICOLON) {
+      if( scanner.token == Token.IDENT) {
+        if (typeName.isEmpty()) {
+            typeName = source.get();
+          continue;
+        }
+        env.error(scanner.pos, err);
+        throw new Scanner.SyntaxError().Fatal();
+      } if( scanner.token == startList ) {
+        if (typeName.isEmpty()) {
+          env.error(scanner.pos, err);
+          throw new Scanner.SyntaxError().Fatal();
+        }
+        names = scanList( scanner.token == Token.TO ? ()->scanner.scanModuleStatement() : ()->scanner.scan() , target, err, false);
+        break;
+      } else {
+        env.error(scanner.pos, err);
+        throw new Scanner.SyntaxError().Fatal();
+      }
+    }
+    // Token.SEMICOLON
+    if (typeName.isEmpty() || ( names.isEmpty() && ! emptyListAllowed) ) {
+          env.error(scanner.pos, err);
+          throw new Scanner.SyntaxError().Fatal();
+    }
+    action.accept(typeName, names);
+    scanner.scan();
+  }
+
+  /**
+   * Scans the "to" or "with" part of ModuleStatement: exports PackageName  [to  ModuleName {, ModuleName}] ;,
+   *                                                   opens  packageName   [to  ModuleName {, ModuleName}] ;
+   *                                                   provides TypeName with TypeName [,typeName] ;
+   *                                                   uses TypeName;
+   * : [ModuleName {, ModuleName}]; , [TypeName [,typeName]]; or TypeName;
+   */
+  private HashSet<String> scanList(Method scanMethod, NameSupplier target, String err, boolean onlyOneElement) throws IOException {
+    HashSet<String> names = new HashSet<>();
+    boolean comma = false, first = true;
+    scanMethod.call();
+    while (scanner.token != Token.SEMICOLON) {
       switch (scanner.token) {
+        case COMMA:
+          if (comma || first || onlyOneElement) {
+            env.error(scanner.pos, err);
+            throw new Scanner.SyntaxError().Fatal();
+          }
+          comma = true;
+          break;
         case IDENT:
-          if (s.isEmpty() && !inWith) {
-            s = parseTypeName();
-            continue;
-          } else if (impl.isEmpty() && inWith) {
-            impl = parseTypeName();
-            continue;
+          if (!first && !comma) {
+            env.error(scanner.pos, err);
+            throw new Scanner.SyntaxError().Fatal();
           }
-          env.error(scanner.pos, "provides.expected");
-          throw new Scanner.SyntaxError();
-        case WITH:
-          if (s.isEmpty() || inWith) {
-            env.error(scanner.pos, "provides.expected");
-            throw new Scanner.SyntaxError();
-          }
-          inWith = true;
-          break;
+          names.add(target.get());
+          comma = false;
+          first = false;
+          continue;
         default:
-          env.error(scanner.pos, "provides.expected");
-          throw new Scanner.SyntaxError();
+          env.error(scanner.pos, err);
+          throw new Scanner.SyntaxError().Fatal();
       }
       scanner.scan();
     }
     // Token.SEMICOLON
-    if (s.isEmpty() || impl.isEmpty()) {
-      env.error(scanner.pos, "provides.expected");
-      throw new Scanner.SyntaxError();
-    }
-    attr.provide(s, impl);
-    scanner.scan();
-  }
-
-  /**
-   * Scans  ModuleStatement: uses TypeName ;
-   */
-  private void scanUses(ModuleAttr attr) throws IOException {
-    String tn = "";
-    scanner.scan();
-    while (scanner.token != Token.SEMICOLON) {
-      switch (scanner.token) {
-        case IDENT:
-          if (!tn.isEmpty()) {
-            env.error(scanner.pos, "uses.expected");
-            throw new Scanner.SyntaxError();
-          }
-          tn = parseTypeName();
-          continue;
-        default:
-          env.error(scanner.pos, "uses.expected");
-          throw new Scanner.SyntaxError();
-      }
-    }
-    // Token.SEMICOLON
-    if (tn.isEmpty()) {
-      env.error(scanner.pos, "uses.expected");
-      throw new Scanner.SyntaxError();
-    }
-    attr.use(tn);
-    scanner.scan();
-  }
-
-  /**
-   * Scans  ModuleStatement: exports PackageName [to ModuleName {, ModuleName}] ;
-   */
-  private void scanExports(ModuleAttr attr) throws IOException {
-    String pn = "";
-    HashSet<String> mn = new HashSet<>();
-    scanner.scan();
-    while (scanner.token != Token.SEMICOLON) {
-      switch (scanner.token) {
-        case IDENT:
-          if (!pn.isEmpty()) {
-            env.error(scanner.pos, "exports.expected");
-            throw new Scanner.SyntaxError();
-          }
-          pn = parseTypeName();
-          continue;
-        case TO:
-          if (pn.isEmpty()) {
-            env.error(scanner.pos, "exports.expected");
-            throw new Scanner.SyntaxError();
-          }
-          mn = scanTo();
-          continue;
-        default:
-          env.error(scanner.pos, "exports.expected");
-          throw new Scanner.SyntaxError();
-      }
-    }
-    // Token.SEMICOLON
-    if (pn.isEmpty()) {
-      env.error(scanner.pos, "exports.expected");
-      throw new Scanner.SyntaxError();
-    }
-    attr.exports(pn, mn);
-    scanner.scan();
-  }
-
-  /**
-   * Scans the "to" part of ModuleStatement: exports PackageName [to ModuleName {, ModuleName}] ;
-   * : [to ModuleName {, ModuleName}] ;
-   */
-  private HashSet<String> scanTo() throws IOException {
-    HashSet<String> names = new HashSet<>();
-    boolean nextID = true;
-    scanner.scan();
-    while (scanner.token != Token.SEMICOLON) {
-      switch (scanner.token) {
-        case COMMA:
-          if (nextID) {
-            env.error(scanner.pos, "exports.expected");
-            throw new Scanner.SyntaxError();
-          }
-          nextID = true;
-          break;
-        case IDENT:
-          if (!nextID) {
-            env.error(scanner.pos, "exports.expected");
-            throw new Scanner.SyntaxError();
-          }
-          names.add(parseTypeName());
-          nextID = false;
-          continue;
-        default:
-          env.error(scanner.pos, "exports.expected");
-          throw new Scanner.SyntaxError();
-      }
-      scanner.scan();
-    }
-    // Token.SEMICOLON
-    if (names.isEmpty()) {
-      env.error(scanner.pos, "exports.expected");
-      throw new Scanner.SyntaxError();
+    if (names.isEmpty() || comma) {
+      env.error(scanner.pos, err);
+      throw new Scanner.SyntaxError().Fatal();
     }
     return names;
   }
 
-  /**
-   * Scans  ModuleStatement: requires [public] ModuleName ;
-   */
-  private void scanRequires(ModuleAttr attr) throws IOException {
-    boolean reexports = false;
-    String mn = "";
-    scanner.scan();
-    while (scanner.token != Token.SEMICOLON) {
-      switch (scanner.token) {
-        case IDENT:
-          if (!mn.isEmpty()) {
-            env.error(scanner.pos, "requires.expected");
-            throw new Scanner.SyntaxError();
-          }
-          mn = parseTypeName();
-          continue;
-          case PUBLIC:
-          if (reexports || !mn.isEmpty()) {
-            env.error(scanner.pos, "requires.expected");
-            throw new Scanner.SyntaxError();
-          }
-          reexports = true;
-          break;
-        default:
-          env.error(scanner.pos, "requires.expected");
-          throw new Scanner.SyntaxError();
-      }
-      scanner.scan();
-    }
-    // Token.SEMICOLON
-    if (mn.isEmpty()) {
-      env.error(scanner.pos, "requires.expected");
-      throw new Scanner.SyntaxError();
-    }
-    attr.require(mn, reexports);
-    scanner.scan();
-  }
-
   private void parseClassMembers() throws IOException {
         debugScan("[Parser.parseClassMembers]:  Begin ");
         // Parse annotations
         if (scanner.token == Token.ANNOTATION) {
             memberAnnttns = annotParser.scanAnnotations();
         }
-
         // Parse modifiers
         int mod = scanModifiers();
         try {
@@ -1509,7 +1531,7 @@
                     break;
                 case BOOTSTRAPMETHOD:
                     scanner.scan();
-                    parseCPXBootstrapMethod(mod);
+                    parseCPXBootstrapMethod();
                     break;
                 default:
                     env.error(scanner.pos, "field.expected");
@@ -1526,7 +1548,7 @@
      * This involves discarding scanner.tokens until an EOF
      * or a possible legal continuation is encountered.
      */
-    protected void recoverFile() throws IOException {
+    private void recoverFile() throws IOException {
         while (true) {
             env.traceln("recoverFile: scanner.token=" + scanner.token);
             switch (scanner.token) {
@@ -1564,7 +1586,7 @@
     /**
      * End class
      */
-    protected void endClass(int where) {
+    private void endClass() {
         if (explicitcp) {
             // Fix references in the constant pool (for explicitly coded CPs)
             pool.fixRefsInPool();
@@ -1580,19 +1602,19 @@
     /**
      * End module
      */
-    protected void endModule() {
+    private void endModule() {
         cd.endModule(moduleAttribute);
         clsDataList.add(cd);
         cd = null;
     }
 
-    public final ClassData[] getClassesData() {
+    final ClassData[] getClassesData() {
         return ((ClassData[]) clsDataList.toArray(new ClassData[0]));
     }
 
     /**
      * Determines whether the JASM file is for a package-info class
-     * or a module-info class.
+     * or for a module-info class.
      *
      * creates the correct kind of ClassData accordingly.
      *
@@ -1604,7 +1626,7 @@
             // a package annotation, or a class annotation
             if (scanner.token == Token.ANNOTATION) {
                 if (cd == null) {
-                    cd = new ClassData(env, major_version, minor_version);
+                    cd = new ClassData(env, cfv);
                     pool = cd.pool;
                 }
                 pkgAnnttns = annotParser.scanAnnotations();
@@ -1641,18 +1663,17 @@
 
             // package-info
             if (sourceName.endsWith("package-info.jasm")) {
-                env.traceln("Creating \"package-info.jasm\": package: " + pkg + " " + major_version + ":" + minor_version);
+                env.traceln("Creating \"package-info.jasm\": package: " + pkg + " " + cfv.asString());
 
                 if (cd == null) {
-                    cd = new ClassData(env, major_version, minor_version);
+                    cd = new ClassData(env, cfv);
                     pool = cd.pool;
                 } else {
-                    cd.major_version = major_version;
-                    cd.minor_version = minor_version;
+                    cd.cfv = cfv;
                 }
                 ConstCell me = pool.FindCellClassByName(pkgPrefix + "package-info");
 
-                if (major_version > 49) {
+                if (cfv.major_version() > 49) {
                     mod |= SYNTHETIC_ATTRIBUTE;
                 }
                 cd.init(mod, me, new ConstCell(0), null);
@@ -1661,7 +1682,7 @@
                     cd.addAnnotations(pkgAnnttns);
                 }
 
-                endClass(scanner.prevPos);
+                endClass();
             }
             return;
         }
@@ -1675,7 +1696,7 @@
     /**
      * Parse an Jasm file.
      */
-    public void parseFile() {
+    void parseFile() {
         try{
             // First, parse any package identifiers (and associated package annotations)
             parseJasmPackages();
@@ -1686,7 +1707,7 @@
                     // Parse annotations
                     if (scanner.token == Token.ANNOTATION) {
                         if (cd == null) {
-                            cd = new ClassData(env, major_version, minor_version);
+                            cd = new ClassData(env, cfv);
                             pool = cd.pool;
                         }
                         clsAnnttns = annotParser.scanAnnotations();
@@ -1696,6 +1717,7 @@
                     int mod = scanModifiers();
                     if (mod == 0) {
                         switch (scanner.token) {
+                            case OPEN:
                             case MODULE:
                             case CLASS:
                             case CPINDEX:
@@ -1718,7 +1740,7 @@
                         // interface <ident> == abstract interface class <ident>
                         mod |= ACC_ABSTRACT;
                     }
-                    if( scanner.token == Token.MODULE )
+                    if( scanner.token == Token.MODULE || scanner.token == Token.OPEN)
                         parseModule();
                     else
                         parseClass(mod);
@@ -1729,6 +1751,9 @@
                     env.traceln("^^^^^^^ Syntax Error ^^^^^^^^^^^^");
                     if (scanner.debugFlag)
                         e.printStackTrace();
+                    if (e.isFatal()) {
+                        break;
+                    }
                     recoverFile();
                 }
             }
--- a/src/org/openjdk/asmtools/jasm/ParserAnnotation.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/ParserAnnotation.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -258,6 +258,8 @@
                 annttns.add(parseAnnotation());
             } else if (isTypeAnnotationToken(scanner.stringValue)) {
                 annttns.add(parseTypeAnnotation());
+            } else {
+                return null;
             }
         }
 
@@ -369,7 +371,7 @@
             // First - validate that the parameter number (integer)
             // (eg >= 0, < numParams, and param num is not previously set)
             int paramNum = scanner.intValue;
-            Integer iParamNum = new Integer(paramNum);
+            Integer iParamNum = Integer.valueOf(paramNum);
             if (paramNum < 0 || paramNum >= totalParams) {
                 //invalid Parameter number.  Throw an error.
                 env.error(scanner.pos, "invalid.paramnum", paramNum);
--- a/src/org/openjdk/asmtools/jasm/ParserCP.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/ParserCP.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -450,12 +450,15 @@
                     ConstantPool.ConstCell NapeCell = parser.pool.FindCell(parseConstValue(ConstType.CONSTANT_NAMEANDTYPE));
 
                     ArrayList<ConstantPool.ConstCell> bsm_args = new ArrayList<>(256);
-                    while (scanner.token != Token.SEMICOLON) {
-                        if (scanner.token == Token.COMMA) {
-                            scanner.scan();
-                        }
+
+                    for (boolean sep = false; scanner.token != Token.SEMICOLON; sep = true) {
+                        if (sep) scanner.expect(Token.COMMA);
+                        bsm_args.add(parseConstRef(null));
+                        scanner.idValue = null; // Clear tag
                         bsm_args.add(parseConstRef(null));
                     }
+
+
                     BootstrapMethodData bsmData = new BootstrapMethodData(MHCell, bsm_args);
                     parser.cd.addBootstrapMethod(bsmData);
                     obj = new ConstantPool.ConstValue_IndyPair(bsmData, NapeCell);
--- a/src/org/openjdk/asmtools/jasm/RuntimeConstants.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/RuntimeConstants.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -22,77 +22,69 @@
  */
 package org.openjdk.asmtools.jasm;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  *
  */
 public interface RuntimeConstants {
-
-    /* Signature Characters */
-    public static final char   SIGC_VOID                  = 'V';
-    public static final String SIG_VOID                   = "V";
-    public static final char   SIGC_BOOLEAN               = 'Z';
-    public static final String SIG_BOOLEAN                = "Z";
-    public static final char   SIGC_BYTE                  = 'B';
-    public static final String SIG_BYTE                   = "B";
-    public static final char   SIGC_CHAR                  = 'C';
-    public static final String SIG_CHAR                   = "C";
-    public static final char   SIGC_SHORT                 = 'S';
-    public static final String SIG_SHORT                  = "S";
-    public static final char   SIGC_INT                   = 'I';
-    public static final String SIG_INT                    = "I";
-    public static final char   SIGC_LONG                  = 'J';
-    public static final String SIG_LONG                   = "J";
-    public static final char   SIGC_FLOAT                 = 'F';
-    public static final String SIG_FLOAT                  = "F";
-    public static final char   SIGC_DOUBLE                = 'D';
-    public static final String SIG_DOUBLE                 = "D";
-    public static final char   SIGC_ARRAY                 = '[';
-    public static final String SIG_ARRAY                  = "[";
-    public static final char   SIGC_CLASS                 = 'L';
-    public static final String SIG_CLASS                  = "L";
-    public static final char   SIGC_METHOD                = '(';
-    public static final String SIG_METHOD                 = "(";
-    public static final char   SIGC_ENDCLASS              = ';';
-    public static final String SIG_ENDCLASS               = ";";
-    public static final char   SIGC_ENDMETHOD             = ')';
-    public static final String SIG_ENDMETHOD              = ")";
-    public static final char   SIGC_PACKAGE               = '/';
-    public static final String SIG_PACKAGE                = "/";
-
-    /* Class File Constants */
-//    public static final int JAVA_MAGIC                   = 0xcafebabe;
-    public static final int JAVA_VERSION                 = 45;
-    public static final int JAVA_MINOR_VERSION           = 3;
     /* Access Flags */
 
-    public static final int ACC_NONE          = 0x0000; // <<everywhere>>
-    public static final int ACC_PUBLIC        = 0x0001; // class, inner, field, method
-    public static final int ACC_PRIVATE       = 0x0002; //        inner, field, method
-    public static final int ACC_PROTECTED     = 0x0004; //        inner, field, method
-    public static final int ACC_STATIC        = 0x0008; //        inner, field, method
-    public static final int ACC_FINAL         = 0x0010; // class, inner, field, method
-    public static final int ACC_SUPER         = 0x0020; // class
-    public static final int ACC_REEXPORT      = 0x0020; //                             requires (ACC_PUBLIC)
-    public static final int ACC_SYNCHRONIZED  = 0x0020; //                      method
-    public static final int ACC_VOLATILE      = 0x0040; //               field
-    public static final int ACC_BRIDGE        = 0x0040; //                      method
-    public static final int ACC_TRANSIENT     = 0x0080; //               field
-    public static final int ACC_VARARGS       = 0x0080; //                      method
-    public static final int ACC_NATIVE        = 0x0100; //                      method
-    public static final int ACC_INTERFACE     = 0x0200; // class, inner
-    public static final int ACC_ABSTRACT      = 0x0400; // class, inner,        method
-    public static final int ACC_STRICT        = 0x0800; //                      method
-    public static final int ACC_SYNTHETIC     = 0x1000; // class, inner, field, method requires
-    public static final int ACC_ANNOTATION    = 0x2000; // class, inner
-    public static final int ACC_ENUM          = 0x4000; // class, inner, field
-    public static final int ACC_MODULE        = 0x8000; // class
-    public static final int ACC_MANDATED      = 0x8000; //                      method requires
+    int ACC_NONE          = 0x0000; // <<everywhere>>
+    int ACC_PUBLIC        = 0x0001; // class, inner, field, method
+    int ACC_PRIVATE       = 0x0002; //        inner, field, method
+    int ACC_PROTECTED     = 0x0004; //        inner, field, method
+    int ACC_STATIC        = 0x0008; //        inner, field, method
+    int ACC_FINAL         = 0x0010; // class, inner, field, method
+    int ACC_TRANSITIVE    = 0x0010; //                                      requires(module)
+    int ACC_SUPER         = 0x0020; // class
+    int ACC_STATIC_PHASE  = 0x0020; //                                      requires(module)
+    int ACC_SYNCHRONIZED  = 0x0020; //                      method
+    int ACC_OPEN          = 0x0020; //                              module
+    int ACC_VOLATILE      = 0x0040; //               field
+    int ACC_BRIDGE        = 0x0040; //                      method
+    int ACC_TRANSIENT     = 0x0080; //               field
+    int ACC_VARARGS       = 0x0080; //                      method
+    int ACC_NATIVE        = 0x0100; //                      method
+    int ACC_INTERFACE     = 0x0200; // class, inner
+    int ACC_ABSTRACT      = 0x0400; // class, inner,        method
+    int ACC_STRICT        = 0x0800; //                      method
+    int ACC_SYNTHETIC     = 0x1000; // class, inner, field, method, module  requires(module) exports(module)
+    int ACC_ANNOTATION    = 0x2000; // class, inner
+    int ACC_ENUM          = 0x4000; // class, inner, field
+    int ACC_MODULE        = 0x8000; // class
+    int ACC_MANDATED      = 0x8000; //                      method  module  requires(module) exports(module)
 
-    /* Attribute codes */
-    public static final int SYNTHETIC_ATTRIBUTE          = 0x00010000; // actually, this is an attribute
-    public static final int DEPRECATED_ATTRIBUTE         = 0x00020000; // actually, this is an attribute
-    /* The version of a class file since which the compact format of stack map
-     * is necessary */
-    public final int SPLIT_VERIFIER_CFV = 50;
+   /* Attribute codes */
+   int SYNTHETIC_ATTRIBUTE          = 0x00010000; // actually, this is an attribute
+   int DEPRECATED_ATTRIBUTE         = 0x00020000; // actually, this is an attribute
+
+   Map<Integer,String> ACC_NAMES = new HashMap() {{
+                        put(ACC_PUBLIC       ,"public");
+                        put(ACC_PRIVATE      ,"private");
+                        put(ACC_PROTECTED    ,"protected");
+                        put(ACC_STATIC       ,"static");
+                        put(ACC_FINAL        ,"final");
+                        put(ACC_SUPER        ,"super");
+                        put(ACC_SYNCHRONIZED ,"synchronized");
+                        put(ACC_VOLATILE     ,"volatile");
+                        put(ACC_BRIDGE       ,"bridge");
+                        put(ACC_TRANSIENT    ,"transient");
+                        put(ACC_VARARGS      ,"varargs");
+                        put(ACC_NATIVE       ,"native");
+                        put(ACC_INTERFACE    ,"interface");
+                        put(ACC_ABSTRACT     ,"abstract");
+                        put(ACC_STRICT       ,"strict");
+                        put(ACC_SYNTHETIC    ,"synthetic");
+                        put(ACC_ANNOTATION   ,"annotation");
+                        put(ACC_ENUM         ,"enum");
+                        put(ACC_MODULE       ,"module");
+                        put(ACC_MANDATED     ,"mandated");
+                        put(SYNTHETIC_ATTRIBUTE     ,"synthetic");
+  }};
+
+    /* The version of a class file since which the compact format of stack map is necessary */
+    int SPLIT_VERIFIER_CFV = 50;
 
 }
--- a/src/org/openjdk/asmtools/jasm/Scanner.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/Scanner.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -23,10 +23,10 @@
 package org.openjdk.asmtools.jasm;
 
 import static org.openjdk.asmtools.jasm.JasmTokens.*;
-import static org.openjdk.asmtools.jasm.Tables.*;
 import static org.openjdk.asmtools.jasm.Constants.EOF;
 import static org.openjdk.asmtools.jasm.Constants.OFFSETBITS;
 import java.io.IOException;
+import java.util.function.Predicate;
 
 /**
  * A Scanner for Jasm tokens. Errors are reported to the environment object.<p>
@@ -47,6 +47,9 @@
      * SyntaxError is the generic error thrown for parsing problems.
      */
     protected static class SyntaxError extends Error {
+        boolean fatalError = false;
+        SyntaxError Fatal() { fatalError = true; return this; }
+        boolean isFatal() {return fatalError;}
     }
 
     /**
@@ -62,7 +65,7 @@
     /**
      * Current token
      */
-//    protected int           token;
+//    protected int token;
     protected Token token;
 
     /**
@@ -88,7 +91,8 @@
     /* A growable character buffer. */
     private int count;
     private char buffer[] = new char[32];
-
+    //
+    private Predicate<Integer> escapingAllowed;
     /**
      * The position of the previous token
      */
@@ -103,11 +107,21 @@
      */
     protected Scanner(Environment env) throws IOException {
         super.init(this, null, env);
+        escapingAllowed = noFunc;
         this.in = env;
         ch = env.read();
         xscan();
     }
 
+    protected void scanModuleStatement() throws IOException {
+        try {
+            escapingAllowed = yesAndProcessFunc;
+            scan();
+        } finally {
+            escapingAllowed = noFunc;
+        }
+    }
+
     /**
      * scan
      *
@@ -181,7 +195,7 @@
         scan();
     }
 
-    private void putc(int ch) {
+    private void putCh(int ch) {
         if (count == buffer.length) {
             char newBuffer[] = new char[buffer.length * 2];
             System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
@@ -207,33 +221,33 @@
         }
         switch (ch >> 8) {
             case 0x06:
-                return ((ch >= 0x0660) && (ch <= 0x0669)) || // Arabic-Indic
-                        ((ch >= 0x06f0) && (ch <= 0x06f9));          // Eastern Arabic-Indic
+                return ((ch >= 0x0660) && (ch <= 0x0669)) ||        // Arabic-Indic
+                        ((ch >= 0x06f0) && (ch <= 0x06f9));         // Eastern Arabic-Indic
             case 0x07:
             case 0x08:
             default:
                 return false;
             case 0x09:
-                return ((ch >= 0x0966) && (ch <= 0x096f)) || // Devanagari
-                        ((ch >= 0x09e6) && (ch <= 0x09ef));          // Bengali
+                return ((ch >= 0x0966) && (ch <= 0x096f)) ||        // Devanagari
+                        ((ch >= 0x09e6) && (ch <= 0x09ef));         // Bengali
             case 0x0a:
-                return ((ch >= 0x0a66) && (ch <= 0x0a6f)) || // Gurmukhi
-                        ((ch >= 0x0ae6) && (ch <= 0x0aef));          // Gujarati
+                return ((ch >= 0x0a66) && (ch <= 0x0a6f)) ||        // Gurmukhi
+                        ((ch >= 0x0ae6) && (ch <= 0x0aef));         // Gujarati
             case 0x0b:
-                return ((ch >= 0x0b66) && (ch <= 0x0b6f)) || // Oriya
-                        ((ch >= 0x0be7) && (ch <= 0x0bef));          // Tamil
+                return ((ch >= 0x0b66) && (ch <= 0x0b6f)) ||        // Oriya
+                        ((ch >= 0x0be7) && (ch <= 0x0bef));         // Tamil
             case 0x0c:
-                return ((ch >= 0x0c66) && (ch <= 0x0c6f)) || // Telugu
-                        ((ch >= 0x0ce6) && (ch <= 0x0cef));          // Kannada
+                return ((ch >= 0x0c66) && (ch <= 0x0c6f)) ||        // Telugu
+                        ((ch >= 0x0ce6) && (ch <= 0x0cef));         // Kannada
             case 0x0d:
                 return ((ch >= 0x0d66) && (ch <= 0x0d6f));          // Malayalam
             case 0x0e:
-                return ((ch >= 0x0e50) && (ch <= 0x0e59)) || // Thai
-                        ((ch >= 0x0ed0) && (ch <= 0x0ed9));          // Lao
+                return ((ch >= 0x0e50) && (ch <= 0x0e59)) ||        // Thai
+                        ((ch >= 0x0ed0) && (ch <= 0x0ed9));         // Lao
             case 0x0f:
                 return false;
             case 0x10:
-                return ((ch >= 0x1040) && (ch <= 0x1049));        // Tibetan
+                return ((ch >= 0x1040) && (ch <= 0x1049));         // Tibetan
         }
     }
 
@@ -333,14 +347,14 @@
                     env.error(pos, "eof.in.comment");
                     return bufferString();
                 case '\n':
-                    putc('\n');
+                    putCh('\n');
                     ch = in.read();
                     seenstar = false;
                     c = count;
                     break;
                 case ' ':
                 case '\t':
-                    putc(ch);
+                    putCh(ch);
                     ch = in.read();
                     break;
                 case '*':
@@ -350,7 +364,7 @@
                             count = c;
                             return bufferString();
                         }
-                        putc('*');
+                        putCh('*');
                     } else {
                         seenstar = true;
                         count = c;
@@ -370,7 +384,7 @@
                     if (!seenstar) {
                         seenstar = true;
                     }
-                    putc(ch);
+                    putCh(ch);
                     ch = in.read();
                     c = count;
                     break;
@@ -396,7 +410,7 @@
                 boolean overflow = false;
                 long value = ch - '0';
                 count = 0;
-                putc(ch);                // save character in buffer
+                putCh(ch);                // save character in buffer
 numberLoop:
                 for (;;) {
                     switch (ch = in.read()) {
@@ -410,7 +424,7 @@
                         case '7':
                         case '8':
                         case '9':
-                            putc(ch);
+                            putCh(ch);
                             if (overflow) {
                                 break;
                             }
@@ -448,7 +462,7 @@
         radix = (ch == '0' ? 8 : 10);
         long value = ch - '0';
         count = 0;
-        putc(ch);                // save character in buffer
+        putCh(ch);                // save character in buffer
 numberLoop:
         for (;;) {
             switch (ch = in.read()) {
@@ -472,7 +486,7 @@
                 case '5':
                 case '6':
                 case '7':
-                    putc(ch);
+                    putCh(ch);
                     if (radix == 10) {
                         overflow = overflow || (value * 10) / 10 != value;
                         value = (value * 10) + (ch - '0');
@@ -502,7 +516,7 @@
                 case 'B':
                 case 'c':
                 case 'C':
-                    putc(ch);
+                    putCh(ch);
                     if (radix != 16) {
                         break numberLoop; // an illegal character
                     }
@@ -566,7 +580,7 @@
         boolean isSingleFloat = false;
         char lastChar;
         if (ch == '.') {
-            putc(ch);
+            putCh(ch);
             ch = in.read();
         }
 
@@ -583,14 +597,14 @@
                 case '7':
                 case '8':
                 case '9':
-                    putc(ch);
+                    putCh(ch);
                     break;
                 case 'e':
                 case 'E':
                     if (seenExponent) {
                         break numberLoop; // we'll get a format error
                     }
-                    putc(ch);
+                    putCh(ch);
                     seenExponent = true;
                     break;
                 case '+':
@@ -599,7 +613,7 @@
                     if (lastChar != 'e' && lastChar != 'E') {
                         break numberLoop; // this isn't an error, though!
                     }
-                    putc(ch);
+                    putCh(ch);
                     break;
                 case 'f':
                 case 'F':
@@ -632,12 +646,12 @@
                         || lastChar == '+' || lastChar == '-') {
                     env.error(in.pos - 1, "float.format");
                 } else if (isSingleFloat) {
-                    floatValue = Float.valueOf(bufferString()).floatValue();
+                    floatValue = Float.valueOf(bufferString());
                     if (Float.isInfinite(floatValue)) {
                         env.error(pos, "overflow");
                     }
                 } else {
-                    doubleValue = Double.valueOf(bufferString()).doubleValue();
+                    doubleValue = Double.valueOf(bufferString());
                     if (Double.isInfinite(doubleValue)) {
                         env.error(pos, "overflow");
                         env.error(pos, "overflow");
@@ -753,29 +767,54 @@
                 case '\\': {
                     int c = scanEscapeChar();
                     if (c >= 0) {
-                        putc((char) c);
+                        putCh((char) c);
                     }
                     break;
                 }
                 default:
-                    putc(ch);
+                    putCh(ch);
                     ch = in.read();
                     break;
             }
         }
     }
 
+
     /**
      * Scan an Identifier. The current character should be the first character of the
      * identifier.
      */
-    private void scanIdentifier() throws IOException {
+    private void scanIdentifier(char[] prefix) throws IOException {
+        int firstChar;
         count = 0;
-        int firstChar = ch;
+        if(prefix != null) {
+            for(;;) {
+                for (int i = 0; i < prefix.length; i++)
+                    putCh(prefix[i]);
+                ch = in.read();
+                if (ch == '\\') {
+                    ch = in.read();
+                    if (ch == 'u') {
+                        ch = in.convertUnicode();
+                        if (!isUCLetter(ch) && !isUCDigit(ch)) {
+                            prefix = new char[]{(char)ch};
+                            continue;
+                        }
+                    } else if (escapingAllowed.test(ch)) {
+                        prefix = new char[]{(char)ch};
+                        continue;
+                    }
+                    int p = in.pos;
+                    env.error(p, "invalid.escape.char");
+                }
+                break;
+            }
+        }
+        firstChar = ch;
         boolean firstIteration = true;
 scanloop:
         while (true) {
-            putc(ch);
+            putCh(ch);
             ch = in.read();
 
             // Check to see if the annotation marker is at
@@ -783,7 +822,7 @@
             if (firstIteration && firstChar == '@') {
                 // May be a type annotation
                 if (ch == 'T') {  // type annotation
-                    putc(ch);
+                    putCh(ch);
                     ch = in.read();
                 }
 
@@ -791,7 +830,7 @@
                 if (ch == '+' || ch == '-') {  // regular annotation
                     // possible annotation -
                     // need to eat up the '@+' or '@-'
-                    putc(ch);
+                    putCh(ch);
                     ch = in.read();
                 }
                 idValue = bufferString();
@@ -882,15 +921,17 @@
                     break; // no, continue to parse identifier
                 }
                 case '\\':
-                    if ((ch = in.read()) == 'u') {
+                    ch = in.read();
+                    if ( ch == 'u') {
                         ch = in.convertUnicode();
                         if (isUCLetter(ch) || isUCDigit(ch)) {
                             break;
                         }
-                    } else {
-                        int p = in.pos;
-                        env.error(p, "invalid.escape.char");
+                    } else if( escapingAllowed.test(ch)) {
+                        break;
                     }
+                    int p = in.pos;
+                    env.error(p, "invalid.escape.char");
                 default:
 //                    if ((!isUCDigit(ch)) && (!isUCLetter(ch))) {
                     break scanloop;
@@ -977,7 +1018,7 @@
                         case '8':
                         case '9':
                             count = 0;
-                            putc('.');
+                            putCh('.');
                             scanReal();
                             break;
                         default:
@@ -1073,7 +1114,7 @@
                 case ')':
                 case '<':
                 case '>':
-                    scanIdentifier();
+                    scanIdentifier(null);
                     break loop;
                 case '\u001a':
                     // Our one concession to DOS.
@@ -1097,13 +1138,24 @@
                     scanCPRef();
                     break loop;
                 case '\\':
-                    if ((ch = in.read()) == 'u') {
+                    ch = in.read();
+                    if ( ch == 'u') {
                         ch = in.convertUnicode();
                         if (isUCLetter(ch)) {
-                            scanIdentifier();
+                            scanIdentifier(null);
                             break loop;
                         }
+                    } else if( escapingAllowed.test(ch)) {
+                        scanIdentifier(new char[]{'\\', (char)ch});
+                        break loop;
                     }
+//                    if ((ch = in.read()) == 'u') {
+//                        ch = in.convertUnicode();
+//                        if (isUCLetter(ch)) {
+//                            scanIdentifier();
+//                            break loop;
+//                        }
+//                    }
                 default:
                     env.out.println("funny.char:" + env.lineNumber(pos) + "/" + (pos & ((1 << OFFSETBITS) - 1)));
                     env.error(pos, "funny.char");
@@ -1112,27 +1164,6 @@
         }
     }
 
-    /**
-     * Scan to a matching '}', ']' or ')'. The current token must be a '{', '[' or '(';
-     */
-    protected void match(Token open, Token close) throws IOException {
-        int depth = 1;
-
-        while (true) {
-            xscan();
-            if (token == open) {
-                depth++;
-            } else if (token == close) {
-                if (--depth == 0) {
-                    return;
-                }
-            } else if (token == Token.EOF) {
-                env.error(pos, "unbalanced.paren");
-                return;
-            }
-        }
-    }
-
     @Override
     protected void debugScan(String dbstr) {
         if (token == null) {
@@ -1161,4 +1192,11 @@
         }
     }
 
+    private Predicate<Integer> noFunc = (ch)-> false;
+    private Predicate<Integer> yesAndProcessFunc = (ch) -> {
+        boolean res = ((ch == '\\') || (ch == ':') || (ch == '@'));
+        if (res)
+            putCh('\\');
+        return res;
+    };
 }
--- a/src/org/openjdk/asmtools/jasm/Tables.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/Tables.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -22,6 +22,7 @@
  */
 package org.openjdk.asmtools.jasm;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
@@ -126,10 +127,12 @@
         // Constant 14 reserved
         CONSTANT_METHODHANDLE               (15, "CONSTANT_METHODHANDLE", "MethodHandle"),
         CONSTANT_METHODTYPE                 (16, "CONSTANT_METHODTYPE", "MethodType"),
-        CONSTANT_INVOKEDYNAMIC_TRANS        (17, "CONSTANT_INVOKEDYNAMIC_TRANS", "InvokeDynamicTrans"),
-        CONSTANT_INVOKEDYNAMIC              (18, "CONSTANT_INVOKEDYNAMIC", "InvokeDynamic");
+        // Constant 17 reserved
+        CONSTANT_INVOKEDYNAMIC              (18, "CONSTANT_INVOKEDYNAMIC", "InvokeDynamic"),
+        CONSTANT_MODULE                     (19, "CONSTANT_MODULE",        "Module"),
+        CONSTANT_PACKAGE                    (20, "CONSTANT_PACKAGE",       "Package");
 
-        static final public int maxTag = 18;
+        static final public int maxTag = 20;
 
         private final int value;
         private final String parseKey;
@@ -209,7 +212,13 @@
         ATT_RuntimeVisibleTypeAnnotations           (22, "ATT_RuntimeVisibleTypeAnnotations", "RuntimeVisibleTypeAnnotations"),
         ATT_RuntimeInvisibleTypeAnnotations         (23, "ATT_RuntimeInvisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations"),
         ATT_MethodParameters                        (24, "ATT_MethodParameters", "MethodParameters"),
-        ATT_Module                                  (25, "ATT_Module", "Module");
+        ATT_Module                                  (25, "ATT_Module",  "Module"),
+        ATT_Version                                 (26, "ATT_Version", "Version"),
+        ATT_TargetPlatform                          (27, "ATT_TargetPlatform", "TargetPlatform"),
+        ATT_MainClass                               (28, "ATT_MainClass", "MainClass"),
+        ATT_ModulePackages                          (29, "ATT_ModulePackages", "ModulePackages"),
+        ATT_ModuleMainClass                         (30, "ATT_ModuleMainClass", "ModuleMainClass"),
+        ATT_ModuleTarget                            (31, "ATT_ModuleTarget", "ModuleTarget");
 
         private final Integer value;
         private final String printval;
@@ -390,21 +399,22 @@
      */
     static public enum AnnotElemType {
 
-        AE_BYTE      ('B', "byte"),
-        AE_CHAR      ('C', "char"),
-        AE_SHORT     ('S', "short"),
-        AE_INT       ('I', "int"),
-        AE_LONG      ('J', "long"),
-        AE_FLOAT     ('F', "float"),
-        AE_DOUBLE    ('D', "double"),
-        AE_BOOLEAN   ('Z', "boolean"),
-        AE_STRING    ('s', "string"),
-        AE_ENUM      ('e', "enum"),
-        AE_CLASS     ('c', "class"),
+        AE_BYTE         ('B', "byte"),
+        AE_CHAR         ('C', "char"),
+        AE_SHORT        ('S', "short"),
+        AE_INT          ('I', "int"),
+        AE_LONG         ('J', "long"),
+        AE_FLOAT        ('F', "float"),
+        AE_DOUBLE       ('D', "double"),
+        AE_BOOLEAN      ('Z', "boolean"),
+        AE_STRING       ('s', "string"),
+        AE_ENUM         ('e', "enum"),
+        AE_CLASS        ('c', "class"),
         AE_ANNOTATION   ('@', "annotation"),
-        AE_ARRAY   ('[', "array");
+        AE_ARRAY        ('[', "array"),
+        AE_UNKNOWN      ((char)0, "unknown");
 
-        private final char value;
+        private char value;
         private final String printval;
 
         AnnotElemType(char val, String print) {
@@ -431,7 +441,11 @@
     }
 
     public static AnnotElemType annotElemType(char subtag) {
-        return AnnotElemTypes.get(subtag);
+        AnnotElemType type = AnnotElemTypes.get(subtag);
+        if ( type == null ) {
+            type = AnnotElemType.AE_UNKNOWN;
+        }
+        return type;
     }
 
     public static String annotElemTypeName(char subtag) {
@@ -459,17 +473,18 @@
      */
     static public enum StackMapType {
         /* Type codes for StackMap attribute */
-        ITEM_Bogus      (0, "bogus",    "B"),   // an unknown or uninitialized value
-        ITEM_Integer    (1, "int",      "I"),   // a 32-bit integer
-        ITEM_Float      (2, "float",    "F"),   // not used
-        ITEM_Double     (3, "double",   "D"),   // not used
-        ITEM_Long       (4, "long",     "L"),   // a 64-bit integer
-        ITEM_Null       (5, "null",     "N"),   // the type of null
-        ITEM_InitObject (6, "this",     "IO"),  // "this" in constructor
-        ITEM_Object     (7, "CP",       "O"),   // followed by 2-byte index of class name
-        ITEM_NewObject  (8, "at",       "NO");  // followed by 2-byte ref to "new"
+        ITEM_Bogus      (0,     "bogus",    "B"),           // an unknown or uninitialized value
+        ITEM_Integer    (1,     "int",      "I"),           // a 32-bit integer
+        ITEM_Float      (2,     "float",    "F"),           // not used
+        ITEM_Double     (3,     "double",   "D"),           // not used
+        ITEM_Long       (4,     "long",     "L"),           // a 64-bit integer
+        ITEM_Null       (5,     "null",     "N"),           // the type of null
+        ITEM_InitObject (6,     "this",     "IO"),          // "this" in constructor
+        ITEM_Object     (7,     "CP",       "O"),           // followed by 2-byte index of class name
+        ITEM_NewObject  (8,     "at",       "NO"),          // followed by 2-byte ref to "new"
+        ITEM_UNKNOWN    (null,  "UNKNOWN",  "UNKNOWN");     // placeholder for wrong types
 
-        private final Integer value;
+        private Integer value;
         private final String printval;
         private final String parsekey;
 
@@ -498,8 +513,15 @@
         StackMapTypes.put(typ.value, typ);
     }
 
-    public static StackMapType stackMapType(int subtag) {
-        return StackMapTypes.get(subtag);
+    public static StackMapType stackMapType(int subtag, PrintWriter out) {
+        StackMapType type = StackMapTypes.get(subtag);
+        if (type == null || type == StackMapType.ITEM_UNKNOWN) {
+            if (out != null)
+                out.println("// Unknown StackMap type " + subtag);
+            type = StackMapType.ITEM_UNKNOWN;
+            type.value = subtag;
+        }
+        return type;
     }
 
     public static StackMapType stackMapType(String subtag) {
@@ -619,7 +641,8 @@
         CTX_CLASS       (0, "class"),
         CTX_FIELD       (1, "field"),
         CTX_METHOD      (2, "method"),
-        CTX_INNERCLASS  (3, "inner-class");
+        CTX_INNERCLASS  (3, "inner-class"),
+        CTX_MODULE      (4, "module") ;
 
         private final int value;
         private final String printval;
@@ -640,7 +663,7 @@
 
     private static void registerAnnotElemType(CF_Context ctx) {
         //       NameToAnnotElemType.put(typ.printval, typ);
-//        AnnotElemTypes.put(typ.value, typ);
+        //        AnnotElemTypes.put(typ.value, typ);
     }
     /*
      public static CF_Context annotElemType(String idValue) {
@@ -649,6 +672,5 @@
      public static CF_Context annotElemType(int subtag) {
      return  AnnotElemTypes.get(subtag);
      }
-     * */
-
+    */
 }
--- a/src/org/openjdk/asmtools/jasm/i18n.properties	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jasm/i18n.properties	Fri Oct 06 15:15:23 2017 -0700
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. 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
@@ -67,11 +67,10 @@
 err.unbalanced.paren=Unbalanced parentheses.
 # Parser:
 err.package.repeated=Package statement repeated.
-#err.module.repeated=Module statement repeated.
 warn.intf.repeated=Interface {0} repeated.
 warn.exc.repeated=Exception repeated in throws clause.
 err.multiple.inherit=Multiple inheritance is not supported.
-err.toplevel.expected=Class or interface declaration expected.
+err.toplevel.expected=Class, module or interface declaration expected.
 err.const.def.expected=Constant declaration expected.
 err.const.undecl=Constant #{0} not declared.
 err.const.redecl=Constant {0} redeclared.
@@ -84,6 +83,7 @@
 #err.missing.term=Missing term.
 #err.tag.expected=Tag expected.
 err.name.expected=Name expected, got {0}.
+err.module.name.expected=Module name expected, got {0}.
 err.int.expected=Integer expected.
 err.neg.forbidden=Negative integer is not allowed here.
 err.value.large=Value doesn't fit in {0}.
@@ -126,10 +126,12 @@
 warn.invalid.modifier.abst=invalid modifier for abstract method.
 warn.invalid.modifier.mth=invalid modifier for a method.
 warn.invalid.modifier.acc=at most one of public, protected, and private modifiers can be used.
-warn.invalid.modifier.int=invalid modifier for an interface.
+warn.invalid.modifier.int=invalid modifier(s) for an interface{0}
 warn.invalid.modifier.int.abs=interface class must have abstract modifier.
-warn.invalid.modifier.class=invalid modifier for a class.
+warn.invalid.modifier.class=invalid modifier(s) for a class{0}
+warn.missing.modifier.class=class or enum declaration missing.
 warn.invalid.modifier.class.finabs=class cannot be both abstract and final.
+warn.invalid.modifier.class.intenum=cannot be both interface and enum.
 warn.invalid.modifier.innerclass=invalid modifier for an inner class \"{0}\".
 err.itemtype.expected=StackMap item type expected instead of {0}.
 err.localsmap.repeated=locals_map redeclared.
@@ -159,7 +161,7 @@
 #
 err.incorrect.annot.class=Incorrect Annotation (class), expected class name or CPX), got \"{0}\".
 err.incorrect.annot.enum=Incorrect Annotation (enum), expected type field IDENT, \"{0}\".
-err.incorrect.annot.enum.cpx==Incorrect Annotation (enum), expexted type field CPX.
+err.incorrect.annot.enum.cpx==Incorrect Annotation (enum), expected type field CPX.
 err.incorrect.annot.token=Incorrect Annotation, unrecognized token: \"{0}\".
 err.incorrect.annot.bool=Incorrect Annotation (boolean), expected Integer), got \"{0}\".
 err.incorrect.annot.byte=Incorrect Annotation (byte), expected Integer), got \"{0}\".
@@ -173,12 +175,9 @@
 err.incorrect.typeannot.pathentry.argindex=Incorrect TypeAnnotation  TargetPath PathEntry ArgIndex (expected Integer),  \"{0}\".
 #
 # module Errors
-err.requires.expected=Module statement \"requires [public] ModuleName;\" expected.
-err.exports.expected=Module statement \"exports PackageName [to ModuleName (, ModuleName)];\" expected.
-err.uses.expected=Module statement \"uses TypeName ;\" expected.
-err.provides.expected=Module statement \"provides TypeName with TypeName ;\" expected.
-err.module.statement.expected=One of a module statements - \"requires ...\", \"exports ...\", \"uses ...\" or \"provides ... with ...\"  expected.
-
+err.module.statement.expected= Module statement expected.
+err.requires.expected=Module statement \"requires [transitive] [static] ModuleName;\" expected.
+warn.dot.will.be.converted=Forward slash \"/\" expected instead of dot \".\". The dot is replaced by \"/\".
 #
 # Compiler Errors
 #
--- a/src/org/openjdk/asmtools/jcdec/Main.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jcdec/Main.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. 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
@@ -250,7 +250,7 @@
                     out_println("class #" + in.readUnsignedShort() + "; // #" + i);
                     break;
 
-                case CONSTANT_PACKAGE:
+                case CONSTANT_JAVACARD_PACKAGE:
                     out_begin("package { // #" + i);
                     out_println(toHex(in.readUnsignedByte(), 1) + ";  // flags");
                     out_println("#" + in.readUnsignedShort() + "; // name");
--- a/src/org/openjdk/asmtools/jcoder/JcodTokens.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jcoder/JcodTokens.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -292,7 +292,6 @@
         CONSTANT_FLOAT                      (4, "CONSTANT_FLOAT", "float"),
         CONSTANT_LONG                       (5, "CONSTANT_LONG", "long"),
         CONSTANT_DOUBLE                     (6, "CONSTANT_DOUBLE", "double"),
-
         // Class is removed for JavaCard (???)
         CONSTANT_CLASS                      (7, "CONSTANT_CLASS", "class"),
         CONSTANT_STRING                     (8, "CONSTANT_STRING", "String"),
@@ -300,16 +299,17 @@
         CONSTANT_METHOD                     (10, "CONSTANT_METHOD", "Method"),
         CONSTANT_INTERFACEMETHOD            (11, "CONSTANT_INTERFACEMETHOD", "InterfaceMethod"),
         CONSTANT_NAMEANDTYPE                (12, "CONSTANT_NAMEANDTYPE", "NameAndType"),
-
         // added for JavaCard
-        CONSTANT_PACKAGE                    (13, "CONSTANT_PACKAGE", "package"),  // in javacard export file
+        CONSTANT_JAVACARD_PACKAGE           (13, "CONSTANT_PACKAGE", "package"),  // in javacard export file
         // Constant 14 reserved
         CONSTANT_METHODHANDLE               (15, "CONSTANT_METHODHANDLE", "MethodHandle"),
         CONSTANT_METHODTYPE                 (16, "CONSTANT_METHODTYPE", "MethodType"),
-        CONSTANT_INVOKEDYNAMIC_TRANS        (17, "CONSTANT_INVOKEDYNAMIC_TRANS", "InvokeDynamicTrans"),
-        CONSTANT_INVOKEDYNAMIC              (18, "CONSTANT_INVOKEDYNAMIC", "InvokeDynamic");
+      // Constant 17 reserved
+        CONSTANT_INVOKEDYNAMIC              (18, "CONSTANT_INVOKEDYNAMIC", "InvokeDynamic"),
+        CONSTANT_MODULE                     (19, "CONSTANT_MODULE",  "Module"),
+        CONSTANT_MODULE_PACKAGE             (20, "CONSTANT_PACKAGE", "Package");
 
-        public static final int maxTag = 18;
+        public static final int maxTag = 20;
 
         private final int value;
         private final String parseKey;
@@ -368,7 +368,7 @@
         ConstantTypes.put(tt.value, tt);
     }
 
-    static int constValue(String stringValue) {
+    public static int constValue(String stringValue) {
         ConstType Val = constType(stringValue);
         int val = -1;
 
--- a/src/org/openjdk/asmtools/jcoder/Jcoder.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jcoder/Jcoder.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. 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
@@ -22,15 +22,14 @@
  */
 package org.openjdk.asmtools.jcoder;
 
-import static org.openjdk.asmtools.jcoder.JcodTokens.*;
-import java.io.BufferedOutputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Stack;
-import java.util.ArrayList;
+
+import static org.openjdk.asmtools.jcoder.JcodTokens.ConstType;
+import static org.openjdk.asmtools.jcoder.JcodTokens.Token;
 
 /**
  * Compiles just 1 source file
@@ -39,13 +38,12 @@
 
     /*-------------------------------------------------------- */
     /* Jcoder Fields */
-    ArrayList<ByteBuffer> Classes = new ArrayList<>();
-    ByteBuffer buf;
-    DataOutputStream bufstream;
-    String pkg = null, pkgPrefix = "";
-    int depth = 0;
-    String tabStr = "";
-    Context context = null;
+    private ArrayList<ByteBuffer> Classes = new ArrayList<>();
+    private ByteBuffer buf;
+    private DataOutputStream bufstream;
+    private int depth = 0;
+    private String tabStr = "";
+    private Context context = null;
     protected SourceFile env;
     protected Scanner scanner;
 
@@ -55,46 +53,44 @@
     /*-------------------------------------------------------- */
     /* ContextTag (marker) - describes the type of token */
     /*    this is rather cosmetic, no function currently. */
-    static public enum ContextTag {
-        NULL                (0, ""),
-        CLASS               (1, "Class"),
-        CONSTANTPOOL        (2, "Constant-Pool"),
-        INTERFACES          (3, "Interfaces"),
-        INTERFACE           (4, "Interface"),
-        METHODS             (5, "Methods"),
-        METHOD              (6, "Method"),
-        FIELDS              (7, "Fields"),
-        FIELD               (8, "Field"),
-        ATTRIBUTE           (9, "Attribute");
+    private enum ContextTag {
+        NULL                ( ""),
+        CLASS               ( "Class"),
+        CONSTANTPOOL        ( "Constant-Pool"),
+        INTERFACES          ( "Interfaces"),
+        INTERFACE           ( "Interface"),
+        METHODS             ( "Methods"),
+        METHOD              ( "Method"),
+        FIELDS              ( "Fields"),
+        FIELD               ( "Field"),
+        ATTRIBUTE           ( "Attribute");
 
-        private final Integer value;
-        private final String  printval;
+        private final String  printValue;
 
-        ContextTag(Integer val,  String print) {
-            value = val;
-            printval = print;
+        ContextTag(String value) {
+            printValue = value;
         }
 
         public String printval() {
-            return printval;
+            return printValue;
         }
     }
 
     /*-------------------------------------------------------- */
     /* ContextVal (marker) - Specific value on a context stack */
-    public class ContextVal {
+    private class ContextVal {
 
         public ContextTag tag;
-        public int compCount;
-        public ContextVal owner;
+        int compCount;
+        ContextVal owner;
 
-        public ContextVal(ContextTag tg) {
+        ContextVal(ContextTag tg) {
             tag = tg;
             compCount = 0;
             owner = null;
         }
 
-        public ContextVal(ContextTag tg, ContextVal ownr) {
+        ContextVal(ContextTag tg, ContextVal ownr) {
             tag = tg;
             compCount = 0;
             owner = ownr;
@@ -118,11 +114,8 @@
             init();
         }
 
-        public boolean isConstantPool() {
-            if (stack.empty()) {
-                return false;
-            }
-            return (stack.peek().tag == ContextTag.CONSTANTPOOL);
+        boolean isConstantPool() {
+          return !stack.empty() && (stack.peek().tag == ContextTag.CONSTANTPOOL);
         }
 
         public void init() {
@@ -133,7 +126,7 @@
             hasFields = false;
         }
 
-        public void update() {
+        void update() {
             if (stack.empty()) {
                 stack.push(new ContextVal(ContextTag.CLASS));
                 return;
@@ -164,8 +157,6 @@
                     currentCtx.compCount += 1;
                     stack.push(new ContextVal(ContextTag.INTERFACE, currentCtx));
                     break;
-                //               case INTERFACE:
-//                    break;
                 case FIELDS:
                     currentCtx.compCount += 1;
                     stack.push(new ContextVal(ContextTag.FIELD, currentCtx));
@@ -185,7 +176,7 @@
             }
         }
 
-        public void exit() {
+        void exit() {
             if (!stack.isEmpty()) {
                 stack.pop();
             }
@@ -217,7 +208,7 @@
     /**
      * Create a parser
      */
-    protected Jcoder(SourceFile sf, HashMap<String, String> macros) throws IOException {
+    Jcoder(SourceFile sf, HashMap<String, String> macros) throws IOException {
         scanner = new Scanner(sf, macros);
         env = sf;
         context = new Context();
@@ -228,16 +219,14 @@
     /**
      * Expect a token, return its value, scan the next token or throw an exception.
      */
-    protected final void expect(Token t) throws SyntaxError, IOException {
+    private void expect(Token t) throws SyntaxError, IOException {
         if (scanner.token != t) {
             env.traceln("expect:" + t + " instead of " + scanner.token);
             switch (t) {
                 case IDENT:
-//                  env.error(prevPos, "identifier.expected");
                     env.error(scanner.pos, "identifier.expected");
                     break;
                 default:
-//                  env.error(prevPos, "token.expected", keywordName(t)]);
                     env.error(scanner.pos, "token.expected", t.toString());
                     break;
             }
@@ -246,7 +235,7 @@
         scanner.scan();
     }
 
-    protected void recoverField() throws SyntaxError, IOException {
+    private void recoverField() throws SyntaxError, IOException {
         while (true) {
             switch (scanner.token) {
                 case LBRACE:
@@ -269,7 +258,6 @@
                 case INTERFACE:
                 case CLASS:
                     // begin of something outside a class, panic more
-//                  endClass(pos);
                     throw new SyntaxError();
 
                 default:
@@ -283,7 +271,7 @@
     /**
      * Parse an array of struct.
      */
-    protected void parseArray() throws IOException {
+    private void parseArray() throws IOException {
         scanner.scan();
         int length0 = buf.length, pos0 = scanner.pos;
         int num_expected;
@@ -316,6 +304,7 @@
         if (numSize > 0) {
             buf.append(num_expected, numSize);
         }
+
         int num_present = parseStruct();
         if (num_expected == -1) {
             env.trace(" buf.writeAt(" + length0 + ", " + num_present + ", " + numSize + ");  ");
@@ -323,15 +312,16 @@
             if (numSize > 0) {
                 buf.writeAt(length0, num_present, numSize);
             }
-        } else if (num_expected != num_present) {
-            env.error(pos0, "warn.array.wronglength", new Integer(num_expected), new Integer(num_present));
+        } else if ( num_expected != num_present) {
+            if (context.isConstantPool() && num_expected == num_present +1) return;
+            env.error(pos0, "warn.array.wronglength", num_expected, num_present);
         }
     }
 
     /**
      * Parse a byte array.
      */
-    protected void parseByteArray() throws IOException {
+    private void parseByteArray() throws IOException {
         scanner.scan();
         expect(Token.LSQBRACKET);
         int length0 = buf.length, pos0 = scanner.pos;
@@ -375,14 +365,14 @@
                 buf.writeAt(length0, len_present, lenSize);
             }
         } else if (len_expected != len_present) {
-            env.error(pos0, "warn.array.wronglength", new Integer(len_expected), new Integer(len_present));
+            env.error(pos0, "warn.array.wronglength", len_expected, len_present);
         }
     }
 
     /**
      * Parse an Attribute.
      */
-    protected void parseAttr() throws IOException {
+    private void parseAttr() throws IOException {
         scanner.scan();
         expect(Token.LPAREN);
         int cpx; // index int const. pool
@@ -418,14 +408,14 @@
         if (len_expected == -1) {
             buf.writeAt(length0, len_present, 4);
         } else if (len_expected != len_present) {
-            env.error(pos0, "warn.attr.wronglength", new Integer(len_expected), new Integer(len_present));
+            env.error(pos0, "warn.attr.wronglength", len_expected, len_present);
         }
     } // end parseAttr
 
     /**
      * Parse a Component of JavaCard .cap file.
      */
-    protected void parseComp() throws IOException {
+    private void parseComp() throws IOException {
         scanner.scan();
         expect(Token.LPAREN);
         int tag = scanner.intValue; // index int const. pool
@@ -447,7 +437,7 @@
         if (len_expected == -1) {
             buf.writeAt(length0, len_present, 2);
         } else if (len_expected != len_present) {
-            env.error(pos0, "warn.attr.wronglength", new Integer(len_expected), new Integer(len_present));
+            env.error(pos0, "warn.attr.wronglength", len_expected, len_present);
         }
     } // end parseComp
 
@@ -472,10 +462,10 @@
     /**
      * Parse a structure.
      */
-    protected int parseStruct() throws IOException {
+    private int parseStruct() throws IOException {
         adjustDepth(true);
         env.traceln(" ");
-        env.traceln(tabStr + "Struct { <" + context + "> ");
+        env.traceln(tabStr + "MapStruct { <" + context + "> ");
         expect(Token.LBRACE);
         int num = 0;
         int addElem = 0;
@@ -510,7 +500,7 @@
                         break;
                     case LONGSTRINGVAL:
                         scanner.scan();
-                        env.traceln("LongString [\"" + scanner.longStringValue.data + "\"] ");
+                        env.traceln("LongString [\"" + Arrays.toString(scanner.longStringValue.data) + "\"] ");
                         buf.write(scanner.longStringValue.data, 0, scanner.longStringValue.length);
                         addElem = 1;
                         break;
@@ -540,7 +530,7 @@
                     case RBRACE:
                         scanner.scan();
                         env.traceln(" ");
-                        env.traceln(tabStr + "} // Struct  <" + context + "> [");
+                        env.traceln(tabStr + "} // MapStruct  <" + context + "> [");
                         adjustDepth(false);
                         return num + addElem;
                     default:
@@ -559,7 +549,7 @@
      * Recover after a syntax error in the file. This involves discarding tokens until an
      * EOF or a possible legal continuation is encountered.
      */
-    protected void recoverFile() throws IOException {
+    private void recoverFile() throws IOException {
         while (true) {
             switch (scanner.token) {
                 case CLASS:
@@ -594,19 +584,29 @@
     }
 
     /**
+     * Parse module declaration
+     */
+    private void parseModule() throws IOException {
+        // skip module name as a redundant element
+        scanner.skipTill(Scanner.LBRACE);
+        buf = new ByteBuffer();
+        bufstream = new DataOutputStream(buf);
+        buf.myname = "module-info.class";
+        scanner.scan();
+        env.traceln("starting " + buf.myname);
+        // Parse the clause
+        parseClause();
+        env.traceln("ending " + buf.myname);
+    }
+
+    /**
      * Parse a class or interface declaration.
      */
-    protected void parseClass() throws IOException {
-        // Begin a new class
-        Token prev = scanner.token;
+    private void parseClass(Token prev) throws IOException {
         scanner.scan();
         buf = new ByteBuffer();
         bufstream = new DataOutputStream(buf);
-
-        String doc = scanner.docComment;
-
         // Parse the class name
-        int p = scanner.pos;
         switch (scanner.token) {
             case STRINGVAL:
                 buf.myname = scanner.stringValue;
@@ -621,8 +621,6 @@
             case IDENT:
                 if (prev == Token.FILE) {
                     buf.myname = scanner.stringValue;
-                } else if( prev == Token.MODULE) {
-                    buf.myname = "module-info.class";
                 } else {
                     buf.myname = scanner.stringValue + ".class";
                 }
@@ -632,12 +630,17 @@
                 throw new SyntaxError();
         }
         scanner.scan();
-
         env.traceln("starting class " + buf.myname);
         // Parse the clause
+        parseClause();
+        env.traceln("ending class " + buf.myname);
+
+    } // end parseClass
+
+    private void parseClause() throws IOException {
         switch (scanner.token) {
             case LBRACE:
-                parseStruct(); // ??
+                parseStruct();
                 break;
             case LSQBRACKET:
                 parseArray();
@@ -654,18 +657,12 @@
             default:
                 env.error(scanner.pos, "struct.expected");
         }
-
-        env.traceln("ending class " + buf.myname);
-
-        // End the class
-        env.flushErrors();
-        Classes.add(buf);
-    } // end parseClass
+    }
 
     /**
      * Parse an Jcoder file.
      */
-    public ArrayList<ByteBuffer> parseFile() {
+    ArrayList<ByteBuffer> parseFile() {
         env.traceln("PARSER");
         context.init();
         try {
@@ -676,11 +673,16 @@
                         case MODULE:
                         case INTERFACE:
                         case FILE:
-                            // Start of a class
-//                          scan();
-                            parseClass();
+                            Token t = scanner.token;
+                            if ( t == Token.MODULE) {
+                                parseModule();
+                            } else {
+                                parseClass(t);
+                            }
+                            // End of the class,interface or module
+                            env.flushErrors();
+                            Classes.add(buf);
                             break;
-
                         case SEMICOLON:
                             // Bogus semi colon
                             scanner.scan();
@@ -696,8 +698,11 @@
                             throw new SyntaxError();
                     }
                 } catch (SyntaxError e) {
-                    env.traceln("SyntaxError " + e.getMessage());
-                    e.printStackTrace();
+                    String msg = e.getMessage();
+                    env.traceln("SyntaxError " + (msg == null ? "" : msg));
+                    if( env.debugInfoFlag ) {
+                        e.printStackTrace();
+                    }
                     recoverFile();
                 }
             }
@@ -709,7 +714,7 @@
     } //end parseFile
 
     /*---------------------------------------------*/
-    static char fileSeparator; //=System.getProperty("file.separator");
+    private static char fileSeparator; //=System.getProperty("file.separator");
 
     /**
      * write to the directory passed with -d option
@@ -721,7 +726,7 @@
             return;
         }
 
-        env.traceln("writing class " + myname);
+        env.traceln("writing " + myname);
         File outfile;
         if (destdir == null) {
             int startofname = myname.lastIndexOf('/');
@@ -749,8 +754,7 @@
         out.write(cls.data, 0, cls.length);
         try {
             out.close();
-        } catch (IOException e) {
-        }
+        } catch (IOException ignored) { }
     }
 
     /**
--- a/src/org/openjdk/asmtools/jcoder/Main.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jcoder/Main.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. 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
@@ -75,10 +75,9 @@
     public void usage() {
         out.println(i18n.getString("jcoder.usage"));
         out.println(i18n.getString("jcoder.opt.nowrite"));
+        out.println(i18n.getString("jcoder.opt.ignore"));
         out.println(i18n.getString("jcoder.opt.d"));
         out.println(i18n.getString("jcoder.opt.version"));
-
-//      out.println("     -D<macroDef>=<string>   macro declaration");
     }
 
     /**
@@ -91,7 +90,7 @@
         long tm = System.currentTimeMillis();
         ArrayList<String> v = new ArrayList<>();
         boolean nowrite = false;
-        String props = null;
+        boolean ignore  = false;
         int nwarnings = 0;
         HashMap<String, String> macros = new HashMap<>();
         macros.put("VERSION", "3;45");
@@ -130,10 +129,15 @@
                     macro = arg.substring(index, argLength);
                 }
                 macros.put(macroId, macro);
+            } else if (arg.equals("-vv")) {
+                debugInfoFlag = true;
+                traceFlag = true;
             } else if (arg.equals("-v")) {
                 traceFlag = true;
             } else if (arg.equals("-nowrite")) {
                 nowrite = true;
+            } else if (arg.equals("-ignore")) {
+                ignore = true;
             } else if (arg.equals("-d")) {
                 if ((i + 1) == argv.length) {
                     error(i18n.getString("jcoder.error.d_requires_argument"));
@@ -176,7 +180,7 @@
                 }
                 nerrors += env.nerrors;
                 nwarnings += env.nwarnings;
-                if (nowrite || (nerrors > 0)) {
+                if (nowrite || (nerrors > 0 & !ignore)) {
                     continue;
                 }
                 try {
--- a/src/org/openjdk/asmtools/jcoder/Scanner.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jcoder/Scanner.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -48,6 +48,7 @@
      * End of input
      */
     public static final int EOF = -1;
+    public static final int LBRACE = 123; // "{"
     private boolean debugCP = false;
     private int numCPentrs = 0;
 
@@ -471,7 +472,12 @@
                 }
                 return n;
             }
-
+            case '@':
+                readCh();
+                return '@';
+            case ':':
+                readCh();
+                return ':';
             case 'r':
                 readCh();
                 return '\r';
@@ -530,7 +536,11 @@
                 case '\\': {
                     int c = scanEscapeChar();
                     if (c >= 0) {
-                        putc((char) c);
+                        char ch = (char)c;
+                        if ( ch == '@' || ch == ':' || ch == '\\') {
+                            putc('\\');
+                        }
+                        putc(ch);
                     }
                     break;
                 }
@@ -639,6 +649,19 @@
         }
     } // end scanIdentifier
 
+    // skip till symbol
+    protected void skipTill(int sym) throws IOException {
+        while (true) {
+            if( ch == EOF ) {
+                env.error(pos, "eof.in.comment");
+                return;
+            } else if (ch == sym) {
+                return;
+            }
+            readCh();
+        }
+    }
+
     protected int xscan() throws IOException {
         int retPos = pos;
         prevPos = in.pos;
--- a/src/org/openjdk/asmtools/jcoder/i18n.properties	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jcoder/i18n.properties	Fri Oct 06 15:15:23 2017 -0700
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. 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
@@ -25,10 +25,12 @@
 
 jcoder.opt.nowrite=\
 \     -nowrite     do not write resulting .class files
+jcoder.opt.ignore=\
+      -ignore      ingore non-fatal error(s) that suppress writing .class files
 jcoder.opt.d=\
 \     -d destdir   directory to place resulting .class files
 jcoder.opt.version=\
-\     -version   prints the program version
+\     -version     prints the program version
 
 jcoder.error.D_needs_marco=-D needs macro declaration
 jcoder.error.no_closing_quota=no closing quota in macro definition
@@ -55,8 +57,8 @@
 err.name.expected=Name expected.
 err.io.exception=I/O error in {0}.
 err.cannot.write=Cannot write to {0}.
-warn.array.wronglength=expected array length {0} do not match real length {1}; expected length written
-warn.attr.wronglength=expected attribute length {0} do not match real length {1}; expected length written
+warn.array.wronglength=expected array length %s do not match real length %s; expected length written
+warn.attr.wronglength=expected attribute length %s do not match real length %s; expected length written
 #attrname.notfound=Cannot find "{0}" in constant pool
 err.attrname.expected=Attribute's name or index expected.
 err.element.expected=Primary data item expected.
--- a/src/org/openjdk/asmtools/jdec/ClassData.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdec/ClassData.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. 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
@@ -22,12 +22,18 @@
  */
 package org.openjdk.asmtools.jdec;
 
+import org.openjdk.asmtools.common.Module;
 import org.openjdk.asmtools.jasm.Modifiers;
+import org.openjdk.asmtools.jcoder.JcodTokens;
 import org.openjdk.asmtools.util.I18NResourceBundle;
 
+import java.awt.event.KeyEvent;
 import java.io.*;
 
+import static java.lang.String.format;
 import static org.openjdk.asmtools.jasm.Tables.*;
+import static org.openjdk.asmtools.jasm.Tables.AnnotElemType.AE_UNKNOWN;
+import static org.openjdk.asmtools.jasm.Tables.StackMapType.ITEM_UNKNOWN;
 import static org.openjdk.asmtools.jasm.TypeAnnotationUtils.*;
 
 /**
@@ -36,23 +42,22 @@
  */
 class ClassData {
 
-    byte types[];
-    Object cpool[];
-    int CPlen;
-    NestedByteArrayInputStream countedin;
-    DataInputStream in;
-    PrintWriter out;
-    String inpname;
-    int[] cpe_pos;
-    boolean printDetails;
-    String entityname;
-
+    private byte types[];
+    private Object cpool[];
+    private int CPlen;
+    private NestedByteArrayInputStream countedin;
+    private DataInputStream in;
+    private PrintWriter out;
+    private String inpname;
+    private int[] cpe_pos;
+    private boolean printDetails;
+    private String entityType = "";
+    private String entityName = "";
 
     public static I18NResourceBundle i18n
             = I18NResourceBundle.getBundleForClass(Main.class);
 
     public ClassData(String inpname, int printFlags, PrintWriter out) throws IOException {
-        entityname = (inpname.endsWith("module-info.class")) ? "module" : "class";
         FileInputStream filein = new FileInputStream(inpname);
         byte buf[] = new byte[filein.available()];
         filein.read(buf);
@@ -64,12 +69,12 @@
     }
 
     /*========================================================*/
-    public static final char hexTable[] = {
-        '0', '1', '2', '3', '4', '5', '6', '7',
-        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    private static final char hexTable[] = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
     };
 
-    String toHex(long val, int width) {
+    private String toHex(long val, int width) {
         StringBuilder s = new StringBuilder();
         for (int i = width * 2 - 1; i >= 0; i--) {
             s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
@@ -77,7 +82,7 @@
         return "0x" + s.toString();
     }
 
-    String toHex(long val) {
+    private String toHex(long val) {
         int width;
         for (width = 8; width > 0; width--) {
             if ((val >> (width - 1) * 8) != 0) {
@@ -87,12 +92,12 @@
         return toHex(val, width);
     }
 
-    void printByteHex(PrintWriter out, int b) {
+    private void printByteHex(PrintWriter out, int b) {
         out.print(hexTable[(b >> 4) & 0xF]);
         out.print(hexTable[b & 0xF]);
     }
 
-    void printBytes(PrintWriter out, DataInputStream in, int len)
+    private void printBytes(PrintWriter out, DataInputStream in, int len)
             throws IOException {
         try {
             for (int i = 0; i < len; i++) {
@@ -111,27 +116,28 @@
         }
     }
 
-    void printRestOfBytes() throws IOException {
-        for (int i = 0;; i++) {
+    private void printRestOfBytes() throws IOException {
+        for (int i = 0; ; i++) {
             try {
+                byte b = in.readByte();
                 if (i % 8 == 0) {
                     out_print("0x");
                 }
-                printByteHex(out, in.readByte());
+                printByteHex(out, b);
                 if (i % 8 == 7) {
                     out.print(";\n");
                 }
             } catch (IOException e) {
-                out.println();
+                // out.println();
                 return;
             }
         }
     }
 
     /*========================================================*/
-    int shift = 0;
+    private int shift = 0;
 
-    void out_begin(String s) {
+    private void out_begin(String s) {
         for (int i = 0; i < shift; i++) {
             out.print("  ");
         }
@@ -139,21 +145,21 @@
         shift++;
     }
 
-    void out_print(String s) {
+    private void out_print(String s) {
         for (int i = 0; i < shift; i++) {
             out.print("  ");
         }
         out.print(s);
     }
 
-    void out_println(String s) {
+    private void out_println(String s) {
         for (int i = 0; i < shift; i++) {
             out.print("  ");
         }
         out.println(s);
     }
 
-    void out_end(String s) {
+    private void out_end(String s) {
         shift--;
         for (int i = 0; i < shift; i++) {
             out.print("  ");
@@ -161,20 +167,20 @@
         out.println(s);
     }
 
-    String startArray(int length) {
+    private String startArray(int length) {
         return "[" + (printDetails ? Integer.toString(length) : "") + "]";
     }
 
-    void startArrayCmt(int length, String comment) {
-        out_begin(startArray(length) + " { // " + comment);
+    private void startArrayCmt(int length, String comment) {
+        out_begin(startArray(length) + format(" {%s", comment == null ? "" : " // " + comment));
     }
 
-    void startArrayCmtB(int length, String comment) {
-        out_begin(startArray(length) + "b { // " + comment);
+    private void startArrayCmtB(int length, String comment) {
+        out_begin(startArray(length) + format("b {%s", comment == null ? "" : " // " + comment));
     }
 
     /*========================================================*/
-    void readCP(DataInputStream in) throws IOException {
+    private void readCP(DataInputStream in) throws IOException {
         int length = in.readUnsignedShort();
         CPlen = length;
         traceln(i18n.getString("jdec.trace.CP_len", length));
@@ -183,7 +189,7 @@
         cpe_pos = new int[length];
         for (int i = 1; i < length; i++) {
             byte btag;
-            int v1, v2, n = i;
+            int v1, n = i;
             long lv;
             cpe_pos[i] = countedin.getPos();
             btag = in.readByte();
@@ -196,26 +202,28 @@
                     break;
                 case CONSTANT_INTEGER:
                     v1 = in.readInt();
-                    cpool[i] = new Integer(v1);
+                    cpool[i] = v1;
                     break;
                 case CONSTANT_FLOAT:
                     v1 = Float.floatToIntBits(in.readFloat());
-                    cpool[i] = new Integer(v1);
+                    cpool[i] = v1;
                     break;
                 case CONSTANT_LONG:
                     lv = in.readLong();
-                    cpool[i] = new Long(lv);
+                    cpool[i] = lv;
                     i++;
                     break;
                 case CONSTANT_DOUBLE:
                     lv = Double.doubleToLongBits(in.readDouble());
-                    cpool[i] = new Long(lv);
+                    cpool[i] = lv;
                     i++;
                     break;
                 case CONSTANT_CLASS:
                 case CONSTANT_STRING:
+                case CONSTANT_MODULE:
+                case CONSTANT_PACKAGE:
                     v1 = in.readUnsignedShort();
-                    cpool[i] = new Integer(v1);
+                    cpool[i] = v1;
                     break;
                 case CONSTANT_INTERFACEMETHOD:
                 case CONSTANT_FIELD:
@@ -241,121 +249,123 @@
         }
     }
 
-    void printCP(PrintWriter out) throws IOException {
+    private void printCP(PrintWriter out) throws IOException {
         int length = CPlen;
         startArrayCmt(length, "Constant Pool");
         out_println("; // first element is empty");
-        int size;
-        for (int i = 1; i < length; i = i + size) {
-            size = 1;
-            byte btag = types[i];
-            ConstType tg = tag(btag);
-            int pos = cpe_pos[i];
-            String tagstr = "";
-            String valstr;
-            int v1, v2;
-            long lv;
-            if (tg != null) {
-                tagstr = tg.parseKey();
+        try {
+            int size;
+            for (int i = 1; i < length; i = i + size) {
+                size = 1;
+                byte btag = types[i];
+                ConstType tg = tag(btag);
+                int pos = cpe_pos[i];
+                String tagstr = "";
+                String valstr;
+                int v1;
+                long lv;
+                if (tg != null) {
+                    tagstr = tg.parseKey();
+                }
+                switch (tg) {
+                    case CONSTANT_UTF8: {
+                        tagstr = "Utf8";
+                        StringBuilder sb = new StringBuilder();
+                        String s = (String) cpool[i];
+                        sb.append('\"');
+                        for (int k = 0; k < s.length(); k++) {
+                            char c = s.charAt(k);
+                            switch (c) {
+                                case '\t':
+                                    sb.append('\\').append('t');
+                                    break;
+                                case '\n':
+                                    sb.append('\\').append('n');
+                                    break;
+                                case '\r':
+                                    sb.append('\\').append('r');
+                                    break;
+                                case '\"':
+                                    sb.append('\\').append('\"');
+                                    break;
+                                default:
+                                    sb.append(c);
+                            }
+                        }
+
+                        valstr = sb.append('\"').toString();
+                    }
+                    break;
+                    case CONSTANT_FLOAT:
+                        v1 = (Integer) cpool[i];
+                        valstr = toHex(v1, 4);
+                        break;
+                    case CONSTANT_INTEGER:
+                        v1 = (Integer) cpool[i];
+                        valstr = toHex(v1, 4);
+                        break;
+                    case CONSTANT_DOUBLE:
+                        lv = (Long) cpool[i];
+                        valstr = toHex(lv, 8) + ";";
+                        size = 2;
+                        break;
+                    case CONSTANT_LONG:
+                        lv = (Long) cpool[i];
+                        valstr = toHex(lv, 8) + ";";
+                        size = 2;
+                        break;
+                    case CONSTANT_CLASS:
+                    case CONSTANT_MODULE:
+                    case CONSTANT_PACKAGE:
+                        v1 = (Integer) cpool[i];
+                        valstr = "#" + v1;
+                        break;
+                    case CONSTANT_STRING:
+                        v1 = (Integer) cpool[i];
+                        valstr = "#" + v1;
+                        break;
+                    case CONSTANT_INTERFACEMETHOD:
+                        valstr = (String) cpool[i];
+                        break;
+                    case CONSTANT_FIELD:
+                        valstr = (String) cpool[i];
+                        break;
+                    case CONSTANT_METHOD:
+                        valstr = (String) cpool[i];
+                        break;
+                    case CONSTANT_NAMEANDTYPE:
+                        valstr = (String) cpool[i];
+                        break;
+                    case CONSTANT_METHODHANDLE:
+                        valstr = (String) cpool[i];
+                        break;
+                    case CONSTANT_METHODTYPE:
+                        valstr = (String) cpool[i];
+                        break;
+                    case CONSTANT_INVOKEDYNAMIC:
+                        valstr = (String) cpool[i];
+                        break;
+                    default:
+                        throw new Error("invalid constant type: " + (int) btag);
+                }
+                out_print(tagstr + " " + valstr + "; // #" + i);
+                if (printDetails) {
+                    out_println(" at " + toHex(pos));
+                } else {
+                    out_println("");
+                }
             }
-            switch (tg) {
-                case CONSTANT_UTF8: {
-                    tagstr = "Utf8";
-                    StringBuilder sb = new StringBuilder();
-                    String s = (String) cpool[i];
-                    sb.append('\"');
-                    for (int k = 0; k < s.length(); k++) {
-                        char c = s.charAt(k);
-                        switch (c) {
-                            case '\t':
-                                sb.append('\\').append('t');
-                                break;
-                            case '\n':
-                                sb.append('\\').append('n');
-                                break;
-                            case '\r':
-                                sb.append('\\').append('r');
-                                break;
-                            case '\"':
-                                sb.append('\\').append('\"');
-                                break;
-                            default:
-                                sb.append(c);
-                        }
-                    }
-                    valstr = sb.append('\"').toString();
-                }
-                break;
-                case CONSTANT_FLOAT:
-                    v1 = ((Integer) cpool[i]).intValue();
-                    valstr = toHex(v1, 4);
-                    break;
-                case CONSTANT_INTEGER:
-                    v1 = ((Integer) cpool[i]).intValue();
-                    valstr = toHex(v1, 4);
-                    break;
-                case CONSTANT_DOUBLE:
-                    lv = ((Long) cpool[i]).longValue();
-                    valstr = toHex(lv, 8) + ";";
-                    size = 2;
-                    break;
-                case CONSTANT_LONG:
-                    lv = ((Long) cpool[i]).longValue();
-                    valstr = toHex(lv, 8) + ";";
-                    size = 2;
-                    break;
-                case CONSTANT_CLASS:
-                    v1 = ((Integer) cpool[i]).intValue();
-                    valstr = "#" + v1;
-                    break;
-                case CONSTANT_STRING:
-                    v1 = ((Integer) cpool[i]).intValue();
-                    valstr = "#" + v1;
-                    break;
-                case CONSTANT_INTERFACEMETHOD:
-                    valstr = (String) cpool[i];
-                    break;
-                case CONSTANT_FIELD:
-                    valstr = (String) cpool[i];
-                    break;
-                case CONSTANT_METHOD:
-                    valstr = (String) cpool[i];
-                    break;
-                case CONSTANT_NAMEANDTYPE:
-                    valstr = (String) cpool[i];
-                    break;
-                case CONSTANT_METHODHANDLE:
-                    valstr = (String) cpool[i];
-                    break;
-                case CONSTANT_METHODTYPE:
-                    valstr = (String) cpool[i];
-                    break;
-//                case CONSTANT_INVOKEDYNAMIC_TRANS:
-//                    tagstr = "InvokeDynamicTrans";
-//                    valstr = (String) cpool[i];
-//                    break;
-                case CONSTANT_INVOKEDYNAMIC:
-                    valstr = (String) cpool[i];
-                    break;
-                default:
-                    throw new Error("invalid constant type: " + (int) btag);
-            }
-            out_print(tagstr + " " + valstr + "; // #" + i);
-            if (printDetails) {
-                out_println(" at " + toHex(pos));
-            } else {
-                out_println("");
-            }
+        } finally {
+            out_end("} // Constant Pool");
+            out.println();
         }
-        out_end("} // Constant Pool");
-        out.println();
     }
 
-    String getStringPos() {
+    private String getStringPos() {
         return " at " + toHex(countedin.getPos());
     }
 
-    String getStringPosCond() {
+    private String getStringPosCond() {
         if (printDetails) {
             return getStringPos();
         } else {
@@ -363,7 +373,7 @@
         }
     }
 
-    String getCommentPosCond() {
+    private String getCommentPosCond() {
         if (printDetails) {
             return " // " + getStringPos();
         } else {
@@ -371,26 +381,30 @@
         }
     }
 
-    void decodeCPXAttr(DataInputStream in, int len, String attrname, PrintWriter out) throws IOException {
+    private void decodeCPXAttr(DataInputStream in, int len, String attrname, PrintWriter out) throws IOException {
         decodeCPXAttrM(in, len, attrname, out, 1);
     }
 
-    void decodeCPXAttrM(DataInputStream in, int len, String attrname, PrintWriter out, int expectedIndices) throws IOException {
+    private void decodeCPXAttrM(DataInputStream in, int len, String attrname, PrintWriter out, int expectedIndices) throws IOException {
         if (len != expectedIndices * 2) {
             out_println("// invalid length of " + attrname + " attr: " + len + " (should be " + (expectedIndices * 2) + ") > ");
             printBytes(out, in, len);
         } else {
             String outputString = "";
-            String space = "";
-            for (int k = 0; k < expectedIndices; k++) {
-                outputString += (space + "#" + in.readUnsignedShort());
-                space = " ";
+            for (int k = 1; k <= expectedIndices; k++) {
+                outputString += ("#" + in.readUnsignedShort() + "; ");
+                if (k % 16 == 0) {
+                    out_println(outputString.replaceAll("\\s+$",""));
+                    outputString = "";
+                }
             }
-            out_println(outputString + ";");
+            if (!outputString.isEmpty()) {
+                out_println(outputString.replaceAll("\\s+$",""));
+            }
         }
     }
 
-    void printStackMap(DataInputStream in, int elementsNum) throws IOException {
+    private void printStackMap(DataInputStream in, int elementsNum) throws IOException {
         int num;
         if (elementsNum > 0) {
             num = elementsNum;
@@ -398,40 +412,45 @@
             num = in.readUnsignedShort();
         }
         out.print(startArray(num) + (elementsNum > 0 ? "z" : "") + "{");
-        for (int k = 0; k < num; k++) {
-            int maptype = in.readUnsignedByte();
-            StackMapType mptyp = stackMapType(maptype);
-            String maptypeImg;
-            if (printDetails) {
-                maptypeImg = Integer.toString(maptype) + "b";
-            } else {
-                try {
-                    maptypeImg = mptyp.parsekey();
-                    // maptypeImg = ITEM_Names[maptype];
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    maptypeImg = "/* BAD TYPE: */ " + maptype + "b";
+        try {
+            for (int k = 0; k < num; k++) {
+                int maptype = in.readUnsignedByte();
+                StackMapType mptyp = stackMapType(maptype, out);
+                String maptypeImg;
+                if (printDetails) {
+                    maptypeImg = Integer.toString(maptype) + "b";
+                } else {
+                    try {
+                        maptypeImg = mptyp.parsekey();
+                    } catch (ArrayIndexOutOfBoundsException e) {
+                        maptypeImg = "/* BAD TYPE: */ " + maptype + "b";
+                    }
+                }
+                switch (mptyp) {
+                    case ITEM_Object:
+                    case ITEM_NewObject:
+                        maptypeImg = maptypeImg + "," + in.readUnsignedShort();
+                        break;
+                    case ITEM_UNKNOWN:
+                        maptypeImg = Integer.toString(maptype) + "b";
+                        break;
+                    default:
+                }
+                out.print(maptypeImg);
+                if (k < num - 1) {
+                    out.print("; ");
                 }
             }
-            switch (mptyp) {
-                case ITEM_Object:
-                case ITEM_NewObject:
-                    maptypeImg = maptypeImg + "," + in.readUnsignedShort();
-                    break;
-                default:
-            }
-            out.print(maptypeImg);
-            if (k < num - 1) {
-                out.print("; ");
-            }
+        } finally {
+            out.print("}");
         }
-        out.print("}");
     }
 
     /**
      * Processes 4.7.20 The RuntimeVisibleTypeAnnotations Attribute, 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute
      * <code>type_annotation</code> structure.
      */
-    void decodeTargetTypeAndRefInfo(DataInputStream in, PrintWriter out, boolean isWildcard) throws IOException {
+    private void decodeTargetTypeAndRefInfo(DataInputStream in, boolean isWildcard) throws IOException {
         int tt = in.readUnsignedByte(); // [4.7.20] annotations[], type_annotation { u1 target_type; ...}
         TargetType target_type = targetTypeEnum(tt);
         InfoType info_type = target_type.infoType();
@@ -462,11 +481,14 @@
             {
                 int lv_num = in.readUnsignedShort();
                 startArrayCmt(lv_num, "local_variables");
-                for (int i = 0; i < lv_num; i++) {
-                    out_println(in.readUnsignedShort() + " " + in.readUnsignedShort()
-                            + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                try {
+                    for (int i = 0; i < lv_num; i++) {
+                        out_println(in.readUnsignedShort() + " " + in.readUnsignedShort()
+                                + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                    }
+                } finally {
+                    out_end("}");
                 }
-                out_end("}");
             }
             break;
             case CATCH:             //[3.3.8]  exception_param
@@ -488,116 +510,148 @@
         // [4.7.20.2]
         int path_length = in.readUnsignedByte();  // type_path { u1 path_length; ...}
         startArrayCmt(path_length, "type_paths");
-        for (int i = 0; i < path_length; i++) {
-            // print the type_path elements
-            out_println("{ " + toHex(in.readUnsignedByte(), 1)  // { u1 type_path_kind;
-                    + "; " + toHex(in.readUnsignedByte(), 1)    //   u1 type_argument_index; }
-                    + "; } // type_path[" + i + "]");           // path[i]
+        try {
+            for (int i = 0; i < path_length; i++) {
+                // print the type_path elements
+                out_println("{ " + toHex(in.readUnsignedByte(), 1)  // { u1 type_path_kind;
+                        + "; " + toHex(in.readUnsignedByte(), 1)    //   u1 type_argument_index; }
+                        + "; } // type_path[" + i + "]");           // path[i]
+            }
+        } finally {
+            out_end("}");
         }
-        out_end("}");
-
     }
 
-    void decodeElementValue(DataInputStream in, int len, PrintWriter out) throws IOException {
+    private void decodeElementValue(DataInputStream in, PrintWriter out) throws IOException {
         out_begin("{  //  element_value");
-        char tg = (char) in.readByte();
-        AnnotElemType tag = annotElemType(tg);
-        out_println("'" + tg + "';");
-        switch (tag) {
-            case AE_BYTE:
-            case AE_CHAR:
-            case AE_DOUBLE:
-            case AE_FLOAT:
-            case AE_INT:
-            case AE_LONG:
-            case AE_SHORT:
-            case AE_BOOLEAN:
-            case AE_STRING:
-                decodeCPXAttr(in, 2, "const_value_index", out);
-                break;
-            case AE_ENUM:
-                out_begin("{  //  enum_const_value");
-                decodeCPXAttr(in, 2, "type_name_index", out);
-                decodeCPXAttr(in, 2, "const_name_index", out);
-                out_end("}  //  enum_const_value");
-                break;
-            case AE_CLASS:
-                decodeCPXAttr(in, 2, "class_info_index", out);
-                break;
-            case AE_ANNOTATION:
-                decodeAnnotation(in, out);
-                break;
-            case AE_ARRAY:
-                int ev_num = in.readUnsignedShort();
-                startArrayCmt(ev_num, "array_value");
-                for (int i = 0; i < ev_num; i++) {
-                    decodeElementValue(in, 0, out);
-                    if (i < ev_num - 1) {
+        try {
+            char tg = (char) in.readByte();
+            AnnotElemType tag = annotElemType(tg);
+            if (tag != AE_UNKNOWN) {
+                out_println("'" + tg + "';");
+            }
+            switch (tag) {
+                case AE_BYTE:
+                case AE_CHAR:
+                case AE_DOUBLE:
+                case AE_FLOAT:
+                case AE_INT:
+                case AE_LONG:
+                case AE_SHORT:
+                case AE_BOOLEAN:
+                case AE_STRING:
+                    decodeCPXAttr(in, 2, "const_value_index", out);
+                    break;
+                case AE_ENUM:
+                    out_begin("{  //  enum_const_value");
+                    decodeCPXAttr(in, 2, "type_name_index", out);
+                    decodeCPXAttr(in, 2, "const_name_index", out);
+                    out_end("}  //  enum_const_value");
+                    break;
+                case AE_CLASS:
+                    decodeCPXAttr(in, 2, "class_info_index", out);
+                    break;
+                case AE_ANNOTATION:
+                    decodeAnnotation(in, out);
+                    break;
+                case AE_ARRAY:
+                    int ev_num = in.readUnsignedShort();
+                    startArrayCmt(ev_num, "array_value");
+                    try {
+                        for (int i = 0; i < ev_num; i++) {
+                            decodeElementValue(in, out);
+                            if (i < ev_num - 1) {
+                                out_println(";");
+                            }
+                        }
+                    } finally {
+                        out_end("}  //  array_value");
+                    }
+                    break;
+                case AE_UNKNOWN:
+                default:
+                    String msg = "invalid element_value" + (isPrintableChar(tg) ? " tag type : " + tg : "");
+                    out_println(toHex(tg, 1) + "; // " + msg);
+                    throw new ClassFormatError(msg);
+            }
+        } finally {
+            out_end("}  //  element_value");
+        }
+    }
+
+    public boolean isPrintableChar(char c) {
+        Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
+        return (!Character.isISOControl(c)) &&
+                c != KeyEvent.CHAR_UNDEFINED &&
+                block != null &&
+                block != Character.UnicodeBlock.SPECIALS;
+    }
+
+    private void decodeAnnotation(DataInputStream in, PrintWriter out) throws IOException {
+        out_begin("{  //  annotation");
+        try {
+            decodeCPXAttr(in, 2, "field descriptor", out);
+            int evp_num = in.readUnsignedShort();
+            decodeElementValuePairs(evp_num, in, out);
+        } finally {
+            out_end("}  //  annotation");
+        }
+    }
+
+    private void decodeElementValuePairs(int count, DataInputStream in, PrintWriter out) throws IOException {
+        startArrayCmt(count, "element_value_pairs");
+        try {
+            for (int i = 0; i < count; i++) {
+                out_begin("{  //  element value pair");
+                try {
+                    decodeCPXAttr(in, 2, "name of the annotation type element", out);
+                    decodeElementValue(in, out);
+                } finally {
+                    out_end("}  //  element value pair");
+                    if (i < count - 1) {
                         out_println(";");
                     }
                 }
-                out_end("}  //  array_value");
-                break;
-            default:
-                out_println(toHex(tg, 1) + "; // invalid element_value tag type: " + tg);
-                throw new ClassFormatError();
+            }
+        } finally {
+            out_end("}  //  element_value_pairs");
         }
-        out_end("}  //  element_value");
     }
 
-    void decodeAnnotation(DataInputStream in, PrintWriter out) throws IOException {
-        out_begin("{  //  annotation");
-        decodeCPXAttr(in, 2, "field descriptor", out);
-        int evp_num = in.readUnsignedShort();
-        startArrayCmt(evp_num, "element_value_pairs");
-        for (int i = 0; i < evp_num; i++) {
-            out_begin("{  //  element value pair");
-            decodeCPXAttr(in, 2, "name of the annotation type element", out);
-            decodeElementValue(in, 0, out);
-            out_end("}  //  element value pair");
-            if (i < evp_num - 1) {
-                out_println(";");
-            }
+    private void decodeTypeAnnotation(DataInputStream in, PrintWriter out) throws IOException {
+        out_begin("{  //  type_annotation");
+        try {
+            decodeTargetTypeAndRefInfo(in, false);
+            decodeCPXAttr(in, 2, "field descriptor", out);
+            int evp_num = in.readUnsignedShort();
+            decodeElementValuePairs(evp_num, in, out);
+        } finally {
+            out_end("}  //  type_annotation");
         }
-        out_end("}  //  element_value_pairs");
-        out_end("}  //  annotation");
     }
 
-    void decodeTypeAnnotation(DataInputStream in, PrintWriter out) throws IOException {
-        out_begin("{  //  type_annotation");
-        decodeTargetTypeAndRefInfo(in, out, false);
-        decodeCPXAttr(in, 2, "field descriptor", out);
-        int evp_num = in.readUnsignedShort();
-        startArrayCmt(evp_num, "element_value_pairs");
-        for (int i = 0; i < evp_num; i++) {
-            out_begin("{  //  element value pair");
-            decodeCPXAttr(in, 2, "name of the annotation type element", out);
-            decodeElementValue(in, 0, out);
-            out_end("}  //  element value pair");
-            if (i < evp_num - 1) {
-                out_println(";");
+    private void decodeBootstrapMethod(DataInputStream in) throws IOException {
+        out_begin("{  //  bootstrap_method");
+        try {
+            out_println("#" + in.readUnsignedShort() + "; // bootstrap_method_ref");
+            int bm_args_cnt = in.readUnsignedShort();
+            startArrayCmt(bm_args_cnt, "bootstrap_arguments");
+            try {
+                for (int i = 0; i < bm_args_cnt; i++) {
+                    out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond());
+                }
+            } finally {
+                out_end("}  //  bootstrap_arguments");
             }
+        } finally {
+            out_end("}  //  bootstrap_method");
         }
-        out_end("}  //  element_value_pairs");
-        out_end("}  //  type_annotation");
     }
 
-    void decodeBootstrapMethod(DataInputStream in, PrintWriter out) throws IOException {
-        out_begin("{  //  bootstrap_method");
-        out_println("#" + in.readUnsignedShort() + "; // bootstrap_method_ref");
-        int bm_args_cnt = in.readUnsignedShort();
-        startArrayCmt(bm_args_cnt, "bootstrap_arguments");
-        for (int i = 0; i < bm_args_cnt; i++) {
-            out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond());
-        }
-        out_end("}  //  bootstrap_arguments");
-        out_end("}  //  bootstrap_method");
-    }
-
-    void decodeAttr(DataInputStream in0, PrintWriter out) throws IOException {
+    private void decodeAttr(DataInputStream in, PrintWriter out) throws IOException {
         // Read one attribute
         String posComment = getStringPos();
-        int name_cpx = in0.readUnsignedShort(), btag, len;
+        int name_cpx = in.readUnsignedShort(), btag, len;
 
         String AttrName = "";
         try {
@@ -607,11 +661,11 @@
             if (tag == ConstType.CONSTANT_UTF8) {
                 AttrName = (String) cpool[name_cpx];
             }
-        } catch (ArrayIndexOutOfBoundsException e) {
+        } catch (ArrayIndexOutOfBoundsException ignored) {
         }
         AttrTag tg = attrtag(AttrName);
         String endingComment = AttrName;
-        len = in0.readInt();
+        len = in.readInt();
         countedin.enter(len);
         try {
             if (printDetails) {
@@ -626,15 +680,20 @@
                     out_println(in.readUnsignedShort() + "; // max_locals");
                     int code_len = in.readInt();
                     out_begin("Bytes" + startArray(code_len) + "{");
-                    printBytes(out, in, code_len);
-                    out_end("};");
+                    try {
+                        printBytes(out, in, code_len);
+                    } finally {
+                        out_end("}");
+                    }
                     int trap_num = in.readUnsignedShort();
                     startArrayCmt(trap_num, "Traps");
-                    for (int i = 0; i < trap_num; i++) {
-                        out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                    try {
+                        for (int i = 0; i < trap_num; i++) {
+                            out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                        }
+                    } finally {
+                        out_end("} // end Traps");
                     }
-                    out_end("} // end Traps");
-
                     // Read the attributes
                     decodeAttrs(in, out);
                     break;
@@ -644,42 +703,47 @@
                 case ATT_Exceptions:
                     int exc_num = in.readUnsignedShort();
                     startArrayCmt(exc_num, AttrName);
-                    for (int i = 0; i < exc_num; i++) {
-                        out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond());
+                    try {
+                        for (int i = 0; i < exc_num; i++) {
+                            out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond());
+                        }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_LineNumberTable:
                     int ll_num = in.readUnsignedShort();
                     startArrayCmt(ll_num, AttrName);
-                    for (int i = 0; i < ll_num; i++) {
-                        out_println(in.readUnsignedShort() + "  " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                    try {
+                        for (int i = 0; i < ll_num; i++) {
+                            out_println(in.readUnsignedShort() + "  " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                        }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_LocalVariableTable:
-                    int lv_num = in.readUnsignedShort();
-                    startArrayCmt(lv_num, AttrName);
-                    for (int i = 0; i < lv_num; i++) {
-                        out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
-                    }
-                    out_end("}");
-                    break;
                 case ATT_LocalVariableTypeTable:
                     int lvt_num = in.readUnsignedShort();
                     startArrayCmt(lvt_num, AttrName);
-                    for (int i = 0; i < lvt_num; i++) {
-                        out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                    try {
+                        for (int i = 0; i < lvt_num; i++) {
+                            out_println(in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                        }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_InnerClasses:
                     int ic_num = in.readUnsignedShort();
                     startArrayCmt(ic_num, AttrName);
-                    for (int i = 0; i < ic_num; i++) {
-                        out_println("#" + in.readUnsignedShort() + " #" + in.readUnsignedShort() + " #" + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                    try {
+                        for (int i = 0; i < ic_num; i++) {
+                            out_println("#" + in.readUnsignedShort() + " #" + in.readUnsignedShort() + " #" + in.readUnsignedShort() + " " + in.readUnsignedShort() + ";" + getCommentPosCond());
+                        }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_Signature:
                     decodeCPXAttr(in, len, AttrName, out);
@@ -687,78 +751,83 @@
                 case ATT_StackMap:
                     int e_num = in.readUnsignedShort();
                     startArrayCmt(e_num, "");
-                    for (int k = 0; k < e_num; k++) {
-                        int start_pc = in.readUnsignedShort();
-                        out_print("" + start_pc + ", ");
-                        printStackMap(in, 0);
-                        out.print(", ");
-                        printStackMap(in, 0);
-                        out.println(";");
+                    try {
+                        for (int k = 0; k < e_num; k++) {
+                            int start_pc = in.readUnsignedShort();
+                            out_print("" + start_pc + ", ");
+                            printStackMap(in, 0);
+                            out.print(", ");
+                            printStackMap(in, 0);
+                            out.println(";");
+                        }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_StackMapTable:
                     int et_num = in.readUnsignedShort();
                     startArrayCmt(et_num, "");
-                    for (int k = 0; k < et_num; k++) {
-                        int frame_type = in.readUnsignedByte();
-                        StackMapFrameType ftype = stackMapFrameType(frame_type);
-                        switch (ftype) {
-                            case SAME_FRAME:
-                                // type is same_frame;
-                                out_print("" + frame_type + "b");
-                                out.println("; // same_frame");
-                                break;
-                            case SAME_LOCALS_1_STACK_ITEM_FRAME:
-                                // type is same_locals_1_stack_item_frame
-                                int offset = frame_type - 64;
-                                out_print("" + frame_type + "b, ");
-                                // read additional single stack element
-                                printStackMap(in, 1);
-                                out.println("; // same_locals_1_stack_item_frame");
-                                break;
-                            case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME:
-                                // type is same_locals_1_stack_item_frame_extended
-                                int noffset = in.readUnsignedShort();
-                                out_print("" + frame_type + "b, " + noffset + ", ");
-                                // read additional single stack element
-                                printStackMap(in, 1);
-                                out.println("; // same_locals_1_stack_item_frame_extended");
-                                break;
-                            case CHOP_1_FRAME:
-                            case CHOP_2_FRAME:
-                            case CHOP_3_FRAME:
-                                // type is chop_frame
-                                int coffset = in.readUnsignedShort();
-                                out_print("" + frame_type + "b, " + coffset);
-                                out.println("; // chop_frame " + (251 - frame_type));
-                                break;
-                            case SAME_FRAME_EX:
-                                // type is same_frame_extended;
-                                int xoffset = in.readUnsignedShort();
-                                out_print("" + frame_type + "b, " + xoffset);
-                                out.println("; // same_frame_extended");
-                                break;
-                            case APPEND_FRAME:
-                                // type is append_frame
-                                int aoffset = in.readUnsignedShort();
-                                out_print("" + frame_type + "b, " + aoffset + ", ");
-                                // read additional locals
-                                printStackMap(in, frame_type - 251);
-                                out.println("; // append_frame " + (frame_type - 251));
-                                break;
-                            case FULL_FRAME:
-                                // type is full_frame
-                                int foffset = in.readUnsignedShort();
-                                out_print("" + frame_type + "b, " + foffset + ", ");
-                                printStackMap(in, 0);
-                                out.print(", ");
-                                printStackMap(in, 0);
-                                out.println("; // full_frame");
-                                break;
+                    try {
+                        for (int k = 0; k < et_num; k++) {
+                            int frame_type = in.readUnsignedByte();
+                            StackMapFrameType ftype = stackMapFrameType(frame_type);
+                            switch (ftype) {
+                                case SAME_FRAME:
+                                    // type is same_frame;
+                                    out_print("" + frame_type + "b");
+                                    out.println("; // same_frame");
+                                    break;
+                                case SAME_LOCALS_1_STACK_ITEM_FRAME:
+                                    // type is same_locals_1_stack_item_frame
+                                    out_print("" + frame_type + "b, ");
+                                    // read additional single stack element
+                                    printStackMap(in, 1);
+                                    out.println("; // same_locals_1_stack_item_frame");
+                                    break;
+                                case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME:
+                                    // type is same_locals_1_stack_item_frame_extended
+                                    int noffset = in.readUnsignedShort();
+                                    out_print("" + frame_type + "b, " + noffset + ", ");
+                                    // read additional single stack element
+                                    printStackMap(in, 1);
+                                    out.println("; // same_locals_1_stack_item_frame_extended");
+                                    break;
+                                case CHOP_1_FRAME:
+                                case CHOP_2_FRAME:
+                                case CHOP_3_FRAME:
+                                    // type is chop_frame
+                                    int coffset = in.readUnsignedShort();
+                                    out_print("" + frame_type + "b, " + coffset);
+                                    out.println("; // chop_frame " + (251 - frame_type));
+                                    break;
+                                case SAME_FRAME_EX:
+                                    // type is same_frame_extended;
+                                    int xoffset = in.readUnsignedShort();
+                                    out_print("" + frame_type + "b, " + xoffset);
+                                    out.println("; // same_frame_extended");
+                                    break;
+                                case APPEND_FRAME:
+                                    // type is append_frame
+                                    int aoffset = in.readUnsignedShort();
+                                    out_print("" + frame_type + "b, " + aoffset + ", ");
+                                    // read additional locals
+                                    printStackMap(in, frame_type - 251);
+                                    out.println("; // append_frame " + (frame_type - 251));
+                                    break;
+                                case FULL_FRAME:
+                                    // type is full_frame
+                                    int foffset = in.readUnsignedShort();
+                                    out_print("" + frame_type + "b, " + foffset + ", ");
+                                    printStackMap(in, 0);
+                                    out.print(", ");
+                                    printStackMap(in, 0);
+                                    out.println("; // full_frame");
+                                    break;
+                            }
                         }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_EnclosingMethod:
                     decodeCPXAttrM(in, len, AttrName, out, 2);
@@ -767,19 +836,22 @@
                     decodeCPXAttr(in, len, AttrName, out);
                     break;
                 case ATT_AnnotationDefault:
-                    decodeElementValue(in, len, out);
+                    decodeElementValue(in, out);
                     break;
                 case ATT_RuntimeInvisibleAnnotations:
                 case ATT_RuntimeVisibleAnnotations:
                     int an_num = in.readUnsignedShort();
                     startArrayCmt(an_num, "annotations");
-                    for (int i = 0; i < an_num; i++) {
-                        decodeAnnotation(in, out);
-                        if (i < an_num - 1) {
-                            out_println(";");
+                    try {
+                        for (int i = 0; i < an_num; i++) {
+                            decodeAnnotation(in, out);
+                            if (i < an_num - 1) {
+                                out_println(";");
+                            }
                         }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 // 4.7.20 The RuntimeVisibleTypeAnnotations Attribute
                 // 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute
@@ -787,47 +859,71 @@
                 case ATT_RuntimeVisibleTypeAnnotations:
                     int ant_num = in.readUnsignedShort();
                     startArrayCmt(ant_num, "annotations");
-                    for (int i = 0; i < ant_num; i++) {
-                        decodeTypeAnnotation(in, out);
-                        if (i < ant_num - 1) {
-                            out_println(";");
+                    try {
+                        for (int i = 0; i < ant_num; i++) {
+                            decodeTypeAnnotation(in, out);
+                            if (i < ant_num - 1) {
+                                out_println(";");
+                            }
                         }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_RuntimeInvisibleParameterAnnotations:
                 case ATT_RuntimeVisibleParameterAnnotations:
                     int pm_num = in.readUnsignedByte();
                     startArrayCmtB(pm_num, "parameters");
-                    for (int k = 0; k < pm_num; k++) {
-                        int anp_num = in.readUnsignedShort();
-                        startArrayCmt(anp_num, "annotations");
-                        for (int i = 0; i < anp_num; i++) {
-                            decodeAnnotation(in, out);
-                            if (k < anp_num - 1) {
+                    try {
+                        for (int k = 0; k < pm_num; k++) {
+                            int anp_num = in.readUnsignedShort();
+                            startArrayCmt(anp_num, "annotations");
+                            try {
+                                for (int i = 0; i < anp_num; i++) {
+                                    decodeAnnotation(in, out);
+                                    if (k < anp_num - 1) {
+                                        out_println(";");
+                                    }
+                                }
+                            } finally {
+                                out_end("}");
+                            }
+                            if (k < pm_num - 1) {
                                 out_println(";");
                             }
                         }
+                    } finally {
                         out_end("}");
-                        if (k < pm_num - 1) {
-                            out_println(";");
-                        }
                     }
-                    out_end("}");
                     break;
                 case ATT_BootstrapMethods:
                     int bm_num = in.readUnsignedShort();
                     startArrayCmt(bm_num, "bootstrap_methods");
-                    for (int i = 0; i < bm_num; i++) {
-                        decodeBootstrapMethod(in, out);
-                        if (i < bm_num - 1) {
-                            out_println(";");
+                    try {
+                        for (int i = 0; i < bm_num; i++) {
+                            decodeBootstrapMethod(in);
+                            if (i < bm_num - 1) {
+                                out_println(";");
+                            }
                         }
+                    } finally {
+                        out_end("}");
                     }
-                    out_end("}");
                     break;
                 case ATT_Module:
-                    decodeModule(in, out);
+                    decodeModule(in);
+                    break;
+                case ATT_TargetPlatform:
+                    decodeCPXAttrM(in, len, AttrName, out, 3);
+                    break;
+                case ATT_ModulePackages:
+                    int p_num = in.readUnsignedShort();
+                    startArrayCmt(p_num, null);
+                    try {
+                        decodeCPXAttrM(in, len - 2, AttrName, out, p_num);
+                    } finally {
+                        out_end("}");
+                    }
                     break;
                 default:
                     if (AttrName == null) {
@@ -841,91 +937,153 @@
 
         } catch (EOFException e) {
             out.println("// ======== unexpected end of attribute array");
+        } finally {
+            int rest = countedin.available();
+            if (rest > 0) {
+                out.println("// ======== attribute array started " + posComment + " has " + rest + " bytes more:");
+                printBytes(out, in, rest);
+            }
+            out_end("} // end " + endingComment);
+            countedin.leave();
         }
-        int rest = countedin.available();
-        if (rest > 0) {
-            out.println("// ======== attribute array started " + posComment + " has " + rest + " bytes more:");
-            printBytes(out, in, rest);
-        }
-        out_end("} // end " + endingComment);
-        countedin.leave();
     }
 
-    void decodeModule(DataInputStream in, PrintWriter out) throws IOException {
-        int count = in.readUnsignedShort(); // u2 requires_count
+    private void decodeModuleStatement(String statementName, DataInputStream in) throws IOException {
+        // u2 {exports|opens}_count
+        int count = in.readUnsignedShort();
+        startArrayCmt(count, statementName);
+        try {
+            for (int i = 0; i < count; i++) {
+                // u2 {exports|opens}_index; u2 {exports|opens}_flags
+                int index = in.readUnsignedShort();
+                int nFlags = in.readUnsignedShort();
+                String sFlags = printDetails ? Module.Modifier.getStatementFlags(nFlags) : "";
+                out_println("#" + index + " " + toHex(nFlags, 2) + (sFlags.isEmpty() ? "" : " // [ " + sFlags + " ]"));
+                int exports_to_count = in.readUnsignedShort();
+                startArrayCmt(exports_to_count, null);
+                try {
+                    for (int j = 0; j < exports_to_count; j++) {
+                        out_println("#" + in.readUnsignedShort() + ";");
+                    }
+                } finally {
+                    out_end("};");
+                }
+            }
+        } finally {
+            out_end("} // " + statementName + "\n");
+        }
+    }
+
+    private void decodeModule(DataInputStream in) throws IOException {
+        //u2 module_name_index
+        int index = in.readUnsignedShort();
+        entityName = (String) cpool[(Integer) cpool[index]];
+        out_print("#" + index + "; // name_index");
+        if (printDetails) {
+            out_print(" : " + entityName);
+        }
+        out_println("");
+
+        // u2 module_flags
+        int moduleFlags = in.readUnsignedShort();
+        out_print(toHex(moduleFlags, 2) + "; // flags");
+        if (printDetails) {
+            out_print(" " + Module.Modifier.getModuleFlags(moduleFlags));
+        }
+        out_println("");
+
+        //u2 module_version
+        int versionIndex = in.readUnsignedShort();
+        out_println("#" + versionIndex + "; // version");
+
+        // u2 requires_count
+        int count = in.readUnsignedShort();
         startArrayCmt(count, "requires");
-        for (int i = 0; i < count; i++) {
-            // u2 requires_index; u2 requires_flag
-            out_println("#" + in.readUnsignedShort() + " " + toHex(in.readUnsignedShort(), 2) + ";");
+        try {
+            for (int i = 0; i < count; i++) {
+                // u2 requires_index; u2 requires_flags; u2 requires_version_index
+                index = in.readUnsignedShort();
+                int nFlags = in.readUnsignedShort();
+                versionIndex = in.readUnsignedShort();
+                String sFlags = printDetails ? Module.Modifier.getStatementFlags(nFlags) : "";
+                out_println("#" + index + " " + toHex(nFlags, 2) + " #" + versionIndex + ";" + (sFlags.isEmpty() ? "" : " // " + sFlags));
+            }
+        } finally {
+            out_end("} // requires\n");
         }
-        out_end("} // requires\n");
 
-//        count = in.readUnsignedShort();     // u2 permits_count
-//        startArrayCmt(count, "permits");
-//        for (int i = 0; i < count; i++) {
-//            // u2 permits_index
-//            out_println("#" + in.readUnsignedShort() + ";");
-//        }
-//        out_end("} // permits\n");
+        decodeModuleStatement("exports", in);
 
-        count = in.readUnsignedShort();     // u2 exports_count
-        startArrayCmt(count, "exports");
-        for (int i = 0; i < count; i++) {
-            // u2 exports_index
-            out_println("#" + in.readUnsignedShort());
-            int exports_to_count = in.readUnsignedShort();
-            startArrayCmt(exports_to_count, "to");
-            for (int j = 0; j < exports_to_count; j++) {
+        decodeModuleStatement("opens", in);
+        // u2 uses_count
+        count = in.readUnsignedShort();
+        startArrayCmt(count, "uses");
+        try {
+            for (int i = 0; i < count; i++) {
+                // u2 uses_index
                 out_println("#" + in.readUnsignedShort() + ";");
             }
-            out_end("}; // end to");
+        } finally {
+            out_end("} // uses\n");
         }
-        out_end("} // exports\n");
-        count = in.readUnsignedShort();     // u2 uses_count
-        startArrayCmt(count, "uses");
-        for (int i = 0; i < count; i++) {
-            // u2 uses_index
-            out_println("#" + in.readUnsignedShort() + ";");
-        }
-        out_end("} // uses\n");
         count = in.readUnsignedShort(); // u2 provides_count
         startArrayCmt(count, "provides");
-        for (int i = 0; i < count; i++) {
-            // u2 provides_index; u2 with_index
-            out_println("#" + in.readUnsignedShort() + " #" + in.readUnsignedShort() + ";");
+        try {
+            for (int i = 0; i < count; i++) {
+                // u2 provides_index
+                out_println("#" + in.readUnsignedShort());
+                int provides_with_count = in.readUnsignedShort();
+                // u2 provides_with_count
+                startArrayCmt(provides_with_count, null);
+                try {
+                    for (int j = 0; j < provides_with_count; j++) {
+                        // u2 provides_with_index;
+                        out_println("#" + in.readUnsignedShort() + ";");
+                    }
+                } finally {
+                    out_end("};");
+                }
+            }
+        } finally {
+            out_end("} // provides\n");
         }
-        out_end("} // provides\n");
     }
 
-    void decodeAttrs(DataInputStream in, PrintWriter out) throws IOException {
+    private void decodeAttrs(DataInputStream in, PrintWriter out) throws IOException {
         // Read the attributes
         int attr_num = in.readUnsignedShort();
         startArrayCmt(attr_num, "Attributes");
-        for (int i = 0; i < attr_num; i++) {
-            decodeAttr(in, out);
-            if (i + 1 < attr_num) {
-                out_println(";");
+        try {
+            for (int i = 0; i < attr_num; i++) {
+                decodeAttr(in, out);
+                if (i + 1 < attr_num) {
+                    out_println(";");
+                }
             }
+        } finally {
+            out_end("} // Attributes");
         }
-        out_end("} // Attributes");
     }
 
-    void decodeMembers(DataInputStream in, PrintWriter out, String comment) throws IOException {
+    private void decodeMembers(DataInputStream in, PrintWriter out, String comment) throws IOException {
         int nfields = in.readUnsignedShort();
         traceln(comment + "=" + nfields);
         startArrayCmt(nfields, "" + comment);
         try {
             for (int i = 0; i < nfields; i++) {
                 out_begin("{ // Member" + getStringPosCond());
-                int access = in.readShort();
-                out_println(toHex(access, 2) + "; // access");
-                int name_cpx = in.readUnsignedShort();
-                out_println("#" + name_cpx + "; // name_cpx");
-                int sig_cpx = in.readUnsignedShort();
-                out_println("#" + sig_cpx + "; // sig_cpx");
-                // Read the attributes
-                decodeAttrs(in, out);
-                out_end("} // Member");
+                try {
+                    int access = in.readShort();
+                    out_println(toHex(access, 2) + "; // access");
+                    int name_cpx = in.readUnsignedShort();
+                    out_println("#" + name_cpx + "; // name_cpx");
+                    int sig_cpx = in.readUnsignedShort();
+                    out_println("#" + sig_cpx + "; // sig_cpx");
+                    // Read the attributes
+                    decodeAttrs(in, out);
+                } finally {
+                    out_end("} // Member");
+                }
                 if (i + 1 < nfields) {
                     out_println(";");
                 }
@@ -936,8 +1094,7 @@
         }
     }
 
-    public void decodeClass() throws IOException {
-        String classname  = "N/A";
+    void decodeClass() throws IOException {
         // Read the header
         try {
             int magic = in.readInt();
@@ -950,17 +1107,24 @@
             int this_cpx = in.readUnsignedShort();
 
             try {
-                classname = (String) cpool[((Integer) cpool[this_cpx]).intValue()];
-                int ind = classname.lastIndexOf("module-info");
-                if( ind > -1) {
-                    entityname = "module";
-                    classname = classname.substring(0, --ind < 0 ? 0 : ind ).replace('/', '.');
+                entityName = (String) cpool[(Integer) cpool[this_cpx]];
+                if (entityName.equals("module-info")) {
+                    entityType = "module";
+                    entityName = "";
+                } else {
+                    entityType = "class";
                 }
-                out_begin(String.format("%s %s {", entityname, classname));
+                if (!entityName.isEmpty() && (JcodTokens.keyword_token_ident(entityName) != JcodTokens.Token.IDENT || JcodTokens.constValue(entityName) != -1)) {
+                    // Jcod can't parse a entityName matching a keyword or a constant value,
+                    // then use the filename instead:
+                    out_begin(String.format("file \"%s.class\" {", entityName));
+                } else {
+                    out_begin(format("%s %s {", entityType, entityName));
+                }
             } catch (Exception e) {
-                classname = inpname;
-                out.println("// " + e.getMessage() + " while accessing classname");
-                out_begin(String.format("%s %s { // source file name", entityname, classname));
+                entityName = inpname;
+                out.println("// " + e.getMessage() + " while accessing entityName");
+                out_begin(format("%s %s { // source file name", entityType, entityName));
             }
 
             out_print(toHex(magic, 4) + ";");
@@ -973,8 +1137,8 @@
 
             // Print the constant pool
             printCP(out);
-            out_println(toHex(access, 2) + "; // access"  +
-            ( printDetails ? " [" +  (" " + Modifiers.accessString(access, CF_Context.CTX_CLASS).toUpperCase()).replaceAll(" (\\S)"," ACC_$1") + "]" : "" ));
+            out_println(toHex(access, 2) + "; // access" +
+                    (printDetails ? " [" + (" " + Modifiers.accessString(access, CF_Context.CTX_CLASS).toUpperCase()).replaceAll(" (\\S)", " ACC_$1") + "]" : ""));
             out_println("#" + this_cpx + ";// this_cpx");
             int super_cpx = in.readUnsignedShort();
             out_println("#" + super_cpx + ";// super_cpx");
@@ -985,13 +1149,15 @@
             int numinterfaces = in.readUnsignedShort();
             traceln(i18n.getString("jdec.trace.numinterfaces", numinterfaces));
             startArrayCmt(numinterfaces, "Interfaces");
-            for (int i = 0; i < numinterfaces; i++) {
-                int intrf_cpx = in.readUnsignedShort();
-                traceln(i18n.getString("jdec.trace.intrf", i, intrf_cpx));
-                out_println("#" + intrf_cpx + ";");
+            try {
+                for (int i = 0; i < numinterfaces; i++) {
+                    int intrf_cpx = in.readUnsignedShort();
+                    traceln(i18n.getString("jdec.trace.intrf", i, intrf_cpx));
+                    out_println("#" + intrf_cpx + ";");
+                }
+            } finally {
+                out_end("} // Interfaces\n");
             }
-            out_end("} // Interfaces\n");
-
             // Read the fields
             decodeMembers(in, out, "fields");
 
@@ -1000,16 +1166,19 @@
 
             // Read the attributes
             decodeAttrs(in, out);
-        } catch (EOFException e) {
+        } catch (EOFException ignored) {
         } catch (ClassFormatError err) {
-            out.println("//------- ClassFormatError:" + err.getMessage());
+            String msg = err.getMessage();
+            out.println("//------- ClassFormatError" +
+                    (msg == null || msg.isEmpty() ? "" : ": " + msg));
             printRestOfBytes();
         } finally {
-            out_end(String.format("} // end %s %s", entityname, classname));
+            out_end(format("} // end %s %s", entityType, entityName));
         }
     } // end decodeClass()
+
     /* ====================================================== */
-    public boolean DebugFlag = false;
+    boolean DebugFlag = false;
 
     public void trace(String s) {
         if (!DebugFlag) {
--- a/src/org/openjdk/asmtools/jdec/Main.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdec/Main.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. 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
@@ -78,7 +78,6 @@
      * Run the decoder
      */
     public synchronized boolean decode(String argv[]) {
-//      int flags = F_WARNINGS;
         long tm = System.currentTimeMillis();
         ArrayList<String> vargs = new ArrayList<>();
         ArrayList<String> vj = new ArrayList<>();
@@ -88,10 +87,10 @@
         // Parse arguments
         int i = 0;
         for (String arg : argv) {
+            //
             if (arg.equals("-g")) {
                 printFlags = printFlags | 1;
                 vargs.add(arg);
-//out.println("arg["+i+"]="+argv[i]+"/printFlags");
             } else if (arg.equals("-v")) {
                 DebugFlag = true;
                 vargs.add(arg);
@@ -99,7 +98,6 @@
             } else if (arg.equals("-version")) {
                 out.println(ProductInfo.FULL_VERSION);
             } else if (arg.startsWith("-")) {
-//out.println("arg["+i+"]="+argv[i]+"/invalid flag");
                 error(i18n.getString("jdec.error.invalid_flag", arg));
                 usage();
                 return false;
@@ -117,24 +115,23 @@
 
         String[] names = new String[0];
         names = vj.toArray(names);
-decode:
-        for (String inpname : names) {
-            try {
-                ClassData cc = new ClassData(inpname, printFlags, out);
-                cc.DebugFlag = DebugFlag;
-                cc.decodeClass();
-                continue decode;
-            } catch (FileNotFoundException ee) {
-                error(i18n.getString("jdec.error.cannot_read", inpname));
-            } catch (Error ee) {
-                ee.printStackTrace();
-                error(i18n.getString("jdec.error.fatal_error"));
-            } catch (Exception ee) {
-                ee.printStackTrace();
-                error(i18n.getString("jdec.error.fatal_exception"));
-            }
-            return false;
+      for (String inpname : names) {
+        try {
+          ClassData cc = new ClassData(inpname, printFlags, out);
+          cc.DebugFlag = DebugFlag;
+          cc.decodeClass();
+          continue;
+        } catch (FileNotFoundException ee) {
+          error(i18n.getString("jdec.error.cannot_read", inpname));
+        } catch (Error ee) {
+          ee.printStackTrace();
+          error(i18n.getString("jdec.error.fatal_error"));
+        } catch (Exception ee) {
+          ee.printStackTrace();
+          error(i18n.getString("jdec.error.fatal_exception"));
         }
+        return false;
+      }
         return true;
     }
 
--- a/src/org/openjdk/asmtools/jdis/ClassData.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/ClassData.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -23,10 +23,12 @@
 package org.openjdk.asmtools.jdis;
 
 import org.openjdk.asmtools.asmutils.HexUtils;
+import org.openjdk.asmtools.jasm.JasmTokens;
 import org.openjdk.asmtools.jasm.Modifiers;
 
 import java.io.*;
 import java.util.ArrayList;
+import java.util.List;
 
 import static org.openjdk.asmtools.jasm.RuntimeConstants.*;
 import static org.openjdk.asmtools.jasm.Tables.*;
@@ -37,15 +39,14 @@
 public class ClassData extends MemberData {
 
     /*-------------------------------------------------------- */
-    /* ClassData Fields */
+    /* ClassData Fields                                        */
     // -----------------------------
     // Header Info
     // -----------------------------
     /**
      * Version info
      */
-    protected int minor_version,
-            major_version;
+    protected int minor_version, major_version;
 
     /**
      * Constant Pool index to this class
@@ -251,9 +252,6 @@
         }
         minor_version = in.readShort();
         major_version = in.readShort();
-//        if (major_version != JAVA_VERSION) {
-//            throw new ClassFormatError("wrong version: " + major_version + ", expected " + JAVA_VERSION);
-//        }
 
         // Read the constant pool
         // -----------------------------------------------
@@ -304,93 +302,58 @@
         return line;
     }
 
+    private <T extends AnnotationData> void printAnnotations(List<T> annotations) {
+        if (annotations != null) {
+            for (T ad : annotations) {
+                ad.print(out, initialTab);
+                out.println();
+            }
+        }
+    }
+
     public void print() throws IOException {
         int k, l;
-        String className = pool.getClassName(this_cpx);
-        String moduleName = pool.getModuleName(this_cpx);
-        boolean isModuleUnit = !moduleName.isEmpty();
-        pkgPrefixLen = className.lastIndexOf("/") + 1;
-        // Write the header
-        // package-info compilation unit
-        if (className.endsWith("package-info")) {
+        String className = "";
+        if( isModuleUnit() ) {
             // Print the Annotations
-            if (visibleAnnotations != null) {
-                for (AnnotationData visad : visibleAnnotations) {
-                    visad.print(out, initialTab);
-                    out.println();
+            printAnnotations(visibleAnnotations);
+            printAnnotations(invisibleAnnotations);
+        } else {
+            className = pool.getClassName(this_cpx);
+            pkgPrefixLen = className.lastIndexOf("/") + 1;
+            // Write the header
+            // package-info compilation unit
+            if (className.endsWith("package-info")) {
+                // Print the Annotations
+                printAnnotations(visibleAnnotations);
+                printAnnotations(invisibleAnnotations);
+                printAnnotations(visibleTypeAnnotations);
+                printAnnotations(invisibleTypeAnnotations);
+                if (pkgPrefixLen != 0) {
+                    pkgPrefix = className.substring(0, pkgPrefixLen);
+                    out.print("package  " + pkgPrefix.substring(0, pkgPrefixLen - 1) + " ");
+                    out.print("version " + major_version + ":" + minor_version + ";");
                 }
+                out.println();
+                return;
             }
-            if (invisibleAnnotations != null) {
-                for (AnnotationData invisad : invisibleAnnotations) {
-                    invisad.print(out, initialTab);
-                    out.println();
-                }
-            }
-            if (visibleTypeAnnotations != null) {
-                out.println();
-                for (TypeAnnotationData visad : visibleTypeAnnotations) {
-                    visad.print(out, initialTab);
-                    out.println();
-                }
-            }
-            if (invisibleTypeAnnotations != null) {
-                out.println();
-                for (TypeAnnotationData invisad : invisibleTypeAnnotations) {
-                    invisad.print(out, initialTab);
-                    out.println();
-                }
-            }
-
-            if (pkgPrefixLen != 0) {
-                pkgPrefix = className.substring(0, pkgPrefixLen);
-                out.print("package  " + pkgPrefix.substring(0, pkgPrefixLen - 1) + " ");
-                out.print("version " + major_version + ":" + minor_version + ";");
-            }
-            out.println();
-            return;
-        }
-        if (!isModuleUnit) {
             if (pkgPrefixLen != 0) {
                 pkgPrefix = className.substring(0, pkgPrefixLen);
                 out.println("package  " + pkgPrefix.substring(0, pkgPrefixLen - 1) + ";");
                 className = pool.getShortClassName(this_cpx, pkgPrefix);
             }
             out.println();
-
             // Print the Annotations
-            if (visibleAnnotations != null) {
-                for (AnnotationData visad : visibleAnnotations) {
-                    visad.print(out, initialTab);
-                    out.println();
-                }
-            }
-            if (invisibleAnnotations != null) {
-                for (AnnotationData invisad : invisibleAnnotations) {
-                    invisad.print(out, initialTab);
-                    out.println();
-                }
-            }
-            if (visibleTypeAnnotations != null) {
-                out.println();
-                for (TypeAnnotationData visad : visibleTypeAnnotations) {
-                    visad.print(out, initialTab);
-                    out.println();
-                }
-            }
-            if (invisibleTypeAnnotations != null) {
-                out.println();
-                for (TypeAnnotationData invisad : invisibleTypeAnnotations) {
-                    invisad.print(out, initialTab);
-                    out.println();
-                }
-            }
+            printAnnotations(visibleAnnotations);
+            printAnnotations(invisibleAnnotations);
+            printAnnotations(visibleTypeAnnotations);
+            printAnnotations(invisibleTypeAnnotations);
             if ((access & ACC_SUPER) != 0) {
                 out.print("super ");
                 access = access & ~ACC_SUPER;
             }
         }
-
-        // see if we are going to print: abstract interface class
+// see if we are going to print: abstract interface class
 // then replace it with just: interface
 printHeader:
         {
@@ -427,21 +390,25 @@
                 break printHeader;
             }
 
-            // not all conditions met, print header in ordinary way:
-            out.print(Modifiers.accessString(access, CF_Context.CTX_CLASS));
-            if (isSynthetic) {
-                out.print("synthetic ");
+            if(isModuleUnit()) {
+                out.print(moduleData.getModuleHeader());
+            } else {
+                // not all conditions met, print header in ordinary way:
+                out.print(Modifiers.accessString(access, CF_Context.CTX_CLASS));
+                if (isSynthetic) {
+                    out.print("synthetic ");
+                }
+                if (isDeprecated) {
+                    out.print("deprecated ");
+                }
+                if (options.contains(Options.PR.CPX)) {
+                    out.print("\t#" + this_cpx + "; //");
+                }
+                pool.PrintConstant(out, this_cpx);
             }
-            if (isDeprecated) {
-                out.print("deprecated ");
-            }
-            if (options.contains(Options.PR.CPX)) {
-                out.print("\t#" + this_cpx + "; //");
-            }
-            pool.PrintConstant(out, this_cpx);
         }
         out.println();
-        if(!isModuleUnit ) {
+        if(!isModuleUnit()) {
             if (!pool.getClassName(super_cpx).equals("java/lang/Object")) {
                 out.print("\textends ");
                 pool.printlnClassId(out, super_cpx);
@@ -470,11 +437,10 @@
             out.println("\t// Compiled from " + source_name);
             try {
                 source = new TextLines(source_name);
-            } catch (IOException e) {
-            }
+            } catch (IOException ignored) {}
         }
         // keep this new line for classes to pass huge test suite.
-        if(!isModuleUnit)
+        if(!isModuleUnit())
             out.println();
 
         // Print the constant pool
@@ -482,52 +448,56 @@
             pool.print(out);
             out.println();
         }
+        // Don't print fields, methods, inner classes and bootstrap methods if it is module-info entity
+        if ( !isModuleUnit() ) {
 
-        // Print the fields
-        if (fields != null) {
-            for (FieldData curf : fields) {
-                curf.print();
+            // Print the fields
+            if (fields != null && !fields.isEmpty()) {
+                for (FieldData curf : fields) {
+                    curf.print();
+                }
             }
-        }
 
-        // Print the methods
-        if (methods != null) {
-            for (MethodData curm : methods) {
-                boolean skipBlankLine = false;
-                curm.print(skipBlankLine);
+            // Print the methods
+            if (methods != null && !methods.isEmpty()) {
+                for (MethodData curm : methods) {
+                    boolean skipBlankLine = false;
+                    curm.print(skipBlankLine);
+                }
+                out.println();
             }
+
+            // Print the inner classes
+            if (innerClasses != null && !innerClasses.isEmpty()) {
+                for (InnerClassData icd : innerClasses) {
+                    icd.print();
+                }
+                out.println();
+            }
+            // Print the BootstrapMethods
+            //
+            // Only print these if printing extended constants
+            if ((options.contains(Options.PR.CPX)) && bootstrapMethods != null && !bootstrapMethods.isEmpty()) {
+                for (BootstrapMethodData bsmdd : bootstrapMethods) {
+                    bsmdd.print();
+                }
+                out.println();
+            }
+            out.println("} // end Class " + className);
+        } else {
+            // Print module attributes
+            moduleData.print();
+            out.print("} // end Module ");
+            out.print( moduleData.getModuleName());
+            if(moduleData.getModuleVersion() != null)
+                out.print(" @" + moduleData.getModuleVersion());
             out.println();
         }
-
-        // Print the inner classes
-        if (innerClasses != null) {
-            for (InnerClassData icd : innerClasses) {
-                icd.print();
-            }
-            out.println();
-        }
-
-        // Print the BootstrapMethods
-        //
-        // Only print these if printing extended constants
-        if ((options.contains(Options.PR.CPX)) && bootstrapMethods != null) {
-            for (BootstrapMethodData bsmdd : bootstrapMethods) {
-                bsmdd.print();
-            }
-            out.println();
-        }
-        // Print module attributes
-        if( isModuleUnit  && moduleData != null) {
-            moduleData.print();
-        }
-
-        if( isModuleUnit ) {
-            out.println("} // end Module " + moduleName);
-        } else {
-            out.println("} // end Class " + className);
-        }
-
     } // end ClassData.print()
 
+    // Gets the type of processed binary
+    private boolean isModuleUnit() {
+        return moduleData != null;
+    }
 }// end class ClassData
 
--- a/src/org/openjdk/asmtools/jdis/CodeData.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/CodeData.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -65,8 +65,8 @@
             name_cpx = in.readShort();
             sig_cpx = in.readShort();
             slot = in.readShort();
-    //cls.traceln("   var #"+name_cpx+" start:"+start_pc
-            //+" length:"+length+"sig_cpx:"+sig_cpx+" sig_cpx:"+sig_cpx);
+            // cls.traceln("   var #"+name_cpx+" start:"+start_pc
+            // +" length:"+length+"sig_cpx:"+sig_cpx+" sig_cpx:"+sig_cpx);
         }
     }
 
--- a/src/org/openjdk/asmtools/jdis/ConstantPool.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/ConstantPool.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -42,7 +42,6 @@
     private static final Hashtable<Byte, TAG> taghash = new Hashtable<>();
     private static final Hashtable<Byte, SUBTAG> subtaghash = new Hashtable<>();
 
-
     /*-------------------------------------------------------- */
     /* ConstantPool Inner Classes */
     /**
@@ -66,8 +65,9 @@
         CONSTANT_NAMEANDTYPE        ((byte) 12, "NameAndType", "CONSTANT_NAMEANDTYPE"),
         CONSTANT_METHODHANDLE       ((byte) 15, "MethodHandle", "CONSTANT_METHODHANDLE"),
         CONSTANT_METHODTYPE         ((byte) 16, "MethodType", "CONSTANT_METHODTYPE"),
-//            CONSTANT_INVOKEDYNAMIC_TRANS               ((byte) 17, "InvokeDynamicTrans", "method reciever"),
-        CONSTANT_INVOKEDYNAMIC      ((byte) 18, "InvokeDynamic", "CONSTANT_INVOKEDYNAMIC");
+        CONSTANT_INVOKEDYNAMIC      ((byte) 18, "InvokeDynamic", "CONSTANT_INVOKEDYNAMIC"),
+        CONSTANT_MODULE             ((byte) 19, "Module", "CONSTANT_MODULE"),
+        CONSTANT_PACKAGE            ((byte) 20, "Package", "CONSTANT_PACKAGE");
 
         private final Byte value;
         private final String tagname;
@@ -164,8 +164,9 @@
         taghash.put(new Byte(TAG.CONSTANT_NAMEANDTYPE.value()), TAG.CONSTANT_NAMEANDTYPE);
         taghash.put(new Byte(TAG.CONSTANT_METHODHANDLE.value()), TAG.CONSTANT_METHODHANDLE);
         taghash.put(new Byte(TAG.CONSTANT_METHODTYPE.value()), TAG.CONSTANT_METHODTYPE);
-//        taghash.put(new Byte(TAG.CONSTANT_INVOKEDYNAMIC_TRANS.value()), TAG.CONSTANT_INVOKEDYNAMIC_TRANS);
         taghash.put(new Byte(TAG.CONSTANT_INVOKEDYNAMIC.value()), TAG.CONSTANT_INVOKEDYNAMIC);
+        taghash.put(new Byte(TAG.CONSTANT_MODULE.value()), TAG.CONSTANT_MODULE);
+        taghash.put(new Byte(TAG.CONSTANT_PACKAGE.value()), TAG.CONSTANT_PACKAGE);
 
         subtaghash.put(new Byte(SUBTAG.REF_GETFIELD.value()), SUBTAG.REF_GETFIELD);
         subtaghash.put(new Byte(SUBTAG.REF_GETSTATIC.value()), SUBTAG.REF_GETSTATIC);
@@ -431,7 +432,7 @@
      * CPX
      *
      * Constant entries that contain a single constant-pool index. Usually, this includes:
-     * CONSTANT_CLASS CONSTANT_METHODTYPE CONSTANT_STRING
+     * CONSTANT_CLASS CONSTANT_METHODTYPE CONSTANT_STRING CONSTANT_MODULE CONSTANT_PACKAGE
      *
      */
     class CPX extends Constant {
@@ -445,12 +446,15 @@
 
         @Override
         public String stringVal() {
-
             String str = "UnknownTag";
             switch (tag) {
                 case CONSTANT_CLASS:
                     str = getShortClassName(getClassName(this), cd.pkgPrefix);
                     break;
+                case CONSTANT_PACKAGE:
+                case CONSTANT_MODULE:
+                    str = getString(value);
+                    break;
                 case CONSTANT_METHODTYPE:
                 case CONSTANT_STRING:
                     str = StringValue(value);
@@ -468,6 +472,8 @@
                 case CONSTANT_CLASS:
                 case CONSTANT_STRING:
                 case CONSTANT_METHODTYPE:
+                case CONSTANT_PACKAGE:
+                case CONSTANT_MODULE:
                     out.println("#" + (value) + ";\t//  " + stringVal());
                     break;
             }
@@ -509,10 +515,6 @@
                 case CONSTANT_METHODHANDLE:
                     str = subtagToString(value1) + ":" + StringValue(value2);
                     break;
-                // Removed INVOKEDYNAMIC_TRANS
-//              case: CONSTANT_INVOKEDYNAMIC_TRANS:
-//                  str = StringValue(value1) + ":" + StringValue(value2);
-//                  break;
                 case CONSTANT_INVOKEDYNAMIC:
                     int bsm_attr_idx = value1;
                     int nape_idx = value2;
@@ -562,7 +564,6 @@
                     out.println(value1 + ":#" + value2 + ";\t//  " + stringVal());
                     break;
                 case CONSTANT_NAMEANDTYPE:
-                    //            case CONSTANT_INVOKEDYNAMIC_TRANS:
                     out.println("#" + value1 + ":#" + value2 + ";\t//  " + stringVal());
                     break;
                 case CONSTANT_INVOKEDYNAMIC:
@@ -641,6 +642,8 @@
                 case CONSTANT_CLASS:
                 case CONSTANT_STRING:
                 case CONSTANT_METHODTYPE:
+                case CONSTANT_PACKAGE:
+                case CONSTANT_MODULE:
                     pool.add(i, new CPX(tagobj, in.readUnsignedShort()));
                     break;
                 case CONSTANT_FIELD:
@@ -648,7 +651,6 @@
                 case CONSTANT_INTERFACEMETHOD:
                 case CONSTANT_NAMEANDTYPE:
                 case CONSTANT_INVOKEDYNAMIC:
-//                case CONSTANT_INVOKEDYNAMIC_TRANS:
                     pool.add(i, new CPX2(tagobj, in.readUnsignedShort(), in.readUnsignedShort()));
                     break;
                 case CONSTANT_METHODHANDLE:
@@ -730,7 +732,49 @@
 
     /**
      *
-     * getName
+     * getModule
+     *
+     * Public string val - Safely gets the string-rep of a ConstantModule from the CP at a
+     * given index.
+     *
+     * Returns either null (if invalid), or the string value of the ConstantModule
+     *
+     */
+    public String getModule(int cpx) {
+        String str = null;
+        if (inbounds(cpx)) {
+            Constant cns = pool.get(cpx);
+            if (cns != null && cns.tag == TAG.CONSTANT_MODULE) {
+                str = cns.stringVal();
+            }
+        }
+        return str;
+    }
+
+    /**
+     *
+     * getPackage
+     *
+     * Public string val - Safely gets the string-rep of a ConstantPackage from the CP at a
+     * given index.
+     *
+     * Returns either null (if invalid), or the string value of the ConstantPackage
+     *
+     */
+    public String getPackage(int cpx) {
+        String str = null;
+        if (inbounds(cpx)) {
+            Constant cns = pool.get(cpx);
+            if (cns != null && cns.tag == TAG.CONSTANT_PACKAGE) {
+                str = cns.stringVal();
+            }
+        }
+        return str;
+    }
+
+    /**
+     *
+     * getTypeName
      *
      * Safely gets a Java name from a ConstantUTF8 from the CP at a given index.
      *
@@ -773,38 +817,6 @@
 
     /**
      *
-     * getModuleName
-     *
-     * Gets a Java module name from a ConstantClass from the CP at a given index
-     * where this_class is presented in the form: [Module's name in internal form (JVMS 4.2.1)]/module-info
-     * Traditionally, if this_class indicates P/Q/R, then the ClassFile occupies a file R.class in a directory representing
-     * the package P.Q. Similarly, if this_class indicates P/Q/module-info, then the ClassFile occupies a file module-info.class
-     * in a directory representing the module P.Q.
-     *
-     * Returns the Java module name, or an empty string in any other case.
-     */
-    public String getModuleName(int cpx) {
-        String this_class = getClassName(cpx);
-        if(this_class.equals("#" + cpx)) {
-            return "";
-        }
-        return _getModuleName(this_class);
-    }
-
-  /**
-   * _getModuleName
-   *
-   * Helper for getting Module's name from the this_class string.
-   *
-   * Returns an empty string if this_class is not [Module's name in internal form (JVMS 4.2.1)]/module-info
-   */
-    private String _getModuleName(String this_class) {
-        int i = this_class.lastIndexOf("/module-info");
-        return (i>0) ? this_class.substring(0,i).replace('/', '.') : "";
-    }
-
-    /**
-     *
      * getClassName
      *
      * Safely gets a Java class name from a ConstantClass from a CPX2 constant pool
@@ -942,7 +954,6 @@
     }
 
     /**
-     *
      * ConstantStrValue
      *
      * Safely gets the string value of any Constant at any CP index. This string is either
@@ -962,10 +973,8 @@
             return "#" + cpx;
         }
         switch (cns.tag) {
-
             case CONSTANT_METHODHANDLE:
             case CONSTANT_INVOKEDYNAMIC:
-//            case CONSTANT_INVOKEDYNAMIC_TRANS:
             case CONSTANT_METHOD:
             case CONSTANT_INTERFACEMETHOD:
             case CONSTANT_FIELD: {
@@ -975,21 +984,11 @@
                 }
             }
         }
-        if(cns.tag == TAG.CONSTANT_CLASS) {
-            String moduleName = _getModuleName(StringValue(cpx));
-            if( !moduleName.isEmpty() ) {
-                return " " + moduleName;
-            }
-        }
         return cns.tag.tagname + " " + StringValue(cpx);
     }
 
     /**
-     *
-     * print
-     *
      * prints the entire constant pool.
-     *
      */
     public void print(PrintWriter out) throws IOException {
         int cpx = 0;
--- a/src/org/openjdk/asmtools/jdis/Main.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/Main.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -39,7 +39,7 @@
     /**
      * Name of the program.
      */
-    String program;
+    public static String programName;
     /**
      * The stream where error message are printed.
      */
@@ -58,14 +58,14 @@
      */
     public Main(PrintWriter out, String program) {
         this.out = out;
-        this.program = program;
+        Main.programName = program;
     }
 
     /**
      * Top level error message
      */
     public void error(String msg) {
-        System.err.println(program + ": " + msg);
+        System.err.println(programName + ": " + msg);
     }
 
     /**
@@ -122,7 +122,6 @@
             return false;
         }
 
-disasm:
         for (String inpname : vj) {
             if (inpname == null) {
                 continue;
@@ -131,14 +130,16 @@
                 ClassData cc = new ClassData(out);
                 cc.read(new DataInputStream(new FileInputStream(inpname)));
                 cc.print();
-                continue disasm;
+                continue;
             } catch (FileNotFoundException ee) {
                 error(i18n.getString("jdis.error.cannot_read", inpname));
             } catch (Error ee) {
-                ee.printStackTrace();
+                if (options.contains(Options.PR.DEBUG))
+                    ee.printStackTrace();
                 error(i18n.getString("jdis.error.fatal_error", inpname));
             } catch (Exception ee) {
-                ee.printStackTrace();
+                if (options.contains(Options.PR.DEBUG))
+                    ee.printStackTrace();
                 error(i18n.getString("jdis.error.fatal_exception", inpname));
             }
             return false;
--- a/src/org/openjdk/asmtools/jdis/ModuleData.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/ModuleData.java	Fri Oct 06 15:15:23 2017 -0700
@@ -22,15 +22,15 @@
  */
 package org.openjdk.asmtools.jdis;
 
-import org.openjdk.asmtools.jasm.Modifiers;
-
 import java.io.DataInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.*;
-import java.util.stream.Collectors;
 
-import static java.lang.String.format;
+import org.openjdk.asmtools.common.Module;
+import org.openjdk.asmtools.jasm.JasmTokens;
+
+import static org.openjdk.asmtools.jdis.Main.i18n;
 
 /**
  *  The module attribute data.
@@ -47,79 +47,145 @@
     this.out = clsData.out;
   }
 
+  public String getModuleName() {
+    return module == null ? "N/A" : module.getModuleName();
+  }
+
+  public String getModuleVersion() { return module.getModuleVersion();  }
+
+  public String getModuleHeader() {
+    if ( module == null ) {
+      return "N/A";
+    } else {
+      StringBuilder sb = new StringBuilder(module.getModuleFlags());
+      sb.append(JasmTokens.Token.MODULE.parsekey()).append(" ");
+      sb.append(module.getModuleName());
+      if (module.getModuleVersion() != null)
+        sb.append("// @").append(module.getModuleVersion());
+      return sb.toString();
+    }
+  }
+
   /**
    * Reads and resolve the method's attribute data called from ClassData.
    */
   public void read(DataInputStream in) throws IOException {
-    Module.Builder builder = new Module.Builder();
-    int requires_count = in.readUnsignedShort();
-    for (int i = 0; i < requires_count; i++) {
-      int index = in.readUnsignedShort();
-      int flags = in.readUnsignedShort();
-      String moduleName = pool.getString(index);
-
-      Set<Modifier> mods;
-      if (flags == 0) {
-        mods = Collections.emptySet();
-      } else {
-        mods = new HashSet<>();
-        if (Modifiers.isReexport(flags))
-          mods.add(Modifier.PUBLIC);
-        if (Modifiers.isSynthetic(flags))
-          mods.add(Modifier.SYNTHETIC);
-        if (Modifiers.isMandated(flags))
-          mods.add(Modifier.MANDATED);
-      }
-      builder.require(moduleName, mods);
+    int index, moduleFlags, versionIndex;
+    String moduleName, version;
+    Module.Builder builder;
+    try {
+    // u2 module_name_index;
+    index = in.readUnsignedShort();
+    moduleName = pool.getModule(index);
+    // u2 module_flags;
+    moduleFlags = in.readUnsignedShort();
+    // u2 module_version_index;
+    versionIndex = in.readUnsignedShort();
+    version = pool.getString(versionIndex);
+    builder = new Module.Builder(moduleName, moduleFlags, version);
+    } catch (IOException ioe) {
+      System.err.println(Main.programName + ": " + i18n.getString("jdis.error.invalid_header"));
+      throw ioe;
     }
 
-    int exports_count = in.readUnsignedShort();
-    if (exports_count > 0) {
-      for (int i = 0; i < exports_count; i++) {
-        int index = in.readUnsignedShort();
-        String packageName = pool.getString(index).replace('/', '.');
-        int exports_to_count = in.readUnsignedShort();
-        if (exports_to_count > 0) {
-          Set<String> targets = new HashSet<>(exports_to_count);
-          for (int j = 0; j < exports_to_count; j++) {
-            int exports_to_index = in.readUnsignedShort();
-            targets.add(pool.getString(exports_to_index));
+    try {
+      int requires_count = in.readUnsignedShort();
+      for (int i = 0; i < requires_count; i++) {
+        index = in.readUnsignedShort();
+        int requiresFlags = in.readUnsignedShort();
+        versionIndex = in.readUnsignedShort();
+
+        moduleName = pool.getModule(index);
+        version = pool.getString(versionIndex);
+        builder.require(moduleName, requiresFlags, version);
+      }
+    } catch (IOException ioe) {
+      System.err.println(Main.programName + ": " + i18n.getString("jdis.error.invalid_requires"));
+      throw ioe;
+    }
+
+    try {
+      int exports_count = in.readUnsignedShort();
+      if (exports_count > 0) {
+        for (int i = 0; i < exports_count; i++) {
+          index = in.readUnsignedShort();
+          String packageName = pool.getPackage(index);
+          int exportsFlags = in.readUnsignedShort();
+          int exports_to_count = in.readUnsignedShort();
+          if (exports_to_count > 0) {
+            Set<String> targets = new HashSet<>(exports_to_count);
+            for (int j = 0; j < exports_to_count; j++) {
+              int exports_to_index = in.readUnsignedShort();
+              targets.add(pool.getModule(exports_to_index));
+            }
+            builder.exports(packageName, exportsFlags, targets);
+          } else {
+            builder.exports(packageName, exportsFlags);
           }
-          builder.exports(packageName, targets);
-        } else {
-          builder.export(packageName);
         }
       }
+    } catch (IOException ioe) {
+      System.err.println(Main.programName + ": " + i18n.getString("jdis.error.invalid_exports"));
+      throw ioe;
     }
 
-    int uses_count = in.readUnsignedShort();
-    if (uses_count > 0) {
-      for (int i = 0; i < uses_count; i++) {
-        int index = in.readUnsignedShort();
-        String serviceName = pool.getClassName(index).replace('/', '.');
-        builder.use(serviceName);
+    try {
+      int opens_count = in.readUnsignedShort();
+      if (opens_count > 0) {
+        for (int i = 0; i < opens_count; i++) {
+          index = in.readUnsignedShort();
+          String packageName = pool.getPackage(index);
+          int opensFlags = in.readUnsignedShort();
+          int opens_to_count = in.readUnsignedShort();
+          if (opens_to_count > 0) {
+            Set<String> targets = new HashSet<>(opens_to_count);
+            for (int j = 0; j < opens_to_count; j++) {
+              int opens_to_index = in.readUnsignedShort();
+              targets.add(pool.getModule(opens_to_index));
+            }
+            builder.opens(packageName, opensFlags, targets);
+          } else {
+            builder.opens(packageName, opensFlags);
+          }
+        }
       }
+    } catch (IOException ioe) {
+      System.err.println(Main.programName + ": " + i18n.getString("jdis.error.invalid_opens"));
+      throw ioe;
     }
 
-    int provides_count = in.readUnsignedShort();
-    if (provides_count > 0) {
-      Map<String, Set<String>> pm = new HashMap<>();
-      for (int i = 0; i < provides_count; i++) {
-        int index = in.readUnsignedShort();
-        int with_index = in.readUnsignedShort();
-        String sn = pool.getClassName(index).replace('/', '.');
-        String cn = pool.getClassName(with_index).replace('/', '.');
-        // computeIfAbsent
-        Set<String> providers = pm.get(sn);
-        if (providers == null) {
-          providers = new HashSet<>();
-          pm.put(sn, providers);
+    try {
+      int uses_count = in.readUnsignedShort();
+      if (uses_count > 0) {
+        for (int i = 0; i < uses_count; i++) {
+          index = in.readUnsignedShort();
+          String serviceName = pool.getClassName(index);
+          builder.uses(serviceName);
         }
-        providers.add(cn);
       }
-      for (Map.Entry<String, Set<String>> e : pm.entrySet()) {
-        builder.provide(e.getKey(), e.getValue());
+    } catch (IOException ioe) {
+      System.err.println(Main.programName + ": " + i18n.getString("jdis.error.invalid_uses"));
+      throw ioe;
+    }
+
+    try {
+      int provides_count = in.readUnsignedShort();
+      if (provides_count > 0) {
+        for (int i = 0; i < provides_count; i++) {
+          index = in.readUnsignedShort();
+          String serviceName = pool.getClassName(index);
+          int provides_with_count = in.readUnsignedShort();
+          Set<String> implNames = new HashSet<>(provides_with_count);
+          for (int j = 0; j < provides_with_count; j++) {
+            int provides_with_index = in.readUnsignedShort();
+            implNames.add(pool.getClassName(provides_with_index));
+          }
+          builder.provides(serviceName, implNames);
+        }
       }
+    } catch (IOException ioe) {
+      System.err.println(Main.programName + ": " + i18n.getString("jdis.error.invalid_provides"));
+      throw ioe;
     }
     module = builder.build();
   }
@@ -129,195 +195,4 @@
     if (module != null)
       out.println(module.toString());
   }
-
-
-  private enum Modifier {
-    PUBLIC(0x0020), SYNTHETIC(0x1000), MANDATED(0x8000);
-    private final int value;
-    Modifier(int value) {
-      this.value = value;
-    }
-  }
-
-  private final static class Module {
-    //* A service dependence's of this module
-    final Set<String> uses;
-    //* A module on which the current module has a dependence.
-    private final Set<Dependence> requires;
-    //* A module export, may be qualified or unqualified.
-    private final Map<String, Set<String>> exports;
-    //* A service that a module provides one or more implementations of.
-    private final Map<String, Set<String>> provides;
-
-    private Module(Set<Dependence> requires,
-                   Map<String, Set<String>> exports,
-                   Set<String> uses,
-                   Map<String, Set<String>> provides) {
-      this.requires = Collections.unmodifiableSet(requires);
-      this.exports = Collections.unmodifiableMap(exports);
-      this.uses = Collections.unmodifiableSet(uses);
-      this.provides = Collections.unmodifiableMap(provides);
-    }
-
-    @Override
-    public String toString() {
-      StringBuilder sb = new StringBuilder();
-      requires.stream()
-          .sorted()
-          .forEach(d -> sb.append(format("  %s%n", d.toString())));
-      //
-      exports.entrySet().stream()
-          .filter(e -> e.getValue().isEmpty())
-          .sorted(Map.Entry.comparingByKey())
-          .map(e -> format("  exports %s;%n", e.getKey()))
-          .forEach(sb::append);
-      exports.entrySet().stream()
-          .filter(e -> !e.getValue().isEmpty())
-          .sorted(Map.Entry.comparingByKey())
-          .map(e -> format("  exports %s to%n%s;%n", e.getKey(),
-              e.getValue().stream().sorted()
-                  .map(mn -> format("      %s", mn))
-                  .collect(Collectors.joining(",\n"))))
-          .forEach(sb::append);
-      //
-      uses.stream().sorted()
-          .map(s -> format("  uses %s;%n", s))
-          .forEach(sb::append);
-      //
-      provides.entrySet().stream()
-          .sorted(Map.Entry.comparingByKey())
-          .flatMap(e -> e.getValue().stream().sorted()
-              .map(impl -> format("  provides %s with %s;%n", e.getKey(), impl)))
-          .forEach(sb::append);
-      return sb.toString();
-    }
-
-    //* A module on which the current module has a dependence.
-    private final static class Dependence implements Comparable<Dependence> {
-      private final String name;
-      private final Set<Modifier> flags;
-
-      public Dependence(String name, Set<Modifier> flags) {
-        this.name = name;
-        this.flags = flags;
-      }
-
-      /**
-       * Returns the module name.
-       *
-       * @return The module name
-       */
-      public String name() {
-        return name;
-      }
-
-      /**
-       * Returns the set of modifiers.
-       *
-       * @return A possibly-empty unmodifiable set of modifiers
-       */
-      public Set<Modifier> modifiers() {
-        return flags;
-      }
-
-      @Override
-      public int hashCode() {
-        return name.hashCode() * 11 + flags.hashCode();
-      }
-
-      @Override
-      public boolean equals(Object o) {
-        if (o instanceof Dependence) {
-          Dependence d = (Dependence) o;
-          return this.name.equals(d.name) && flags.equals(d.flags);
-        }
-        return false;
-      }
-
-      @Override
-      public int compareTo(Dependence o) {
-        int rc = this.name.compareTo(o.name);
-        return rc != 0 ? rc : Integer.compare(this.flagsValue(), o.flagsValue());
-      }
-
-      @Override
-      public String toString() {
-        return format("requires %s%s;", flags.contains(Modifier.PUBLIC) ? "public " : "", name);
-      }
-
-      private int flagsValue() {
-        int value = 0;
-        for (Modifier m : flags) {
-          value |= m.value;
-        }
-        return value;
-      }
-    }
-
-    /**
-     * The module builder.
-     */
-    public static final class Builder {
-
-      public final Set<Dependence> requires = new HashSet<>();
-      final Map<String, Set<String>> exports = new HashMap<>();
-      final Set<String> uses = new HashSet<>();
-      final Map<String, Set<String>> provides = new HashMap<>();
-
-      public Builder() {
-      }
-
-      /**
-       * Adds a module on which the current module has a dependence.
-       */
-      public Builder require(String d, Set<Modifier> flags) {
-        requires.add(new Dependence(d, flags));
-        return this;
-      }
-
-      /**
-       * Adds a unqualified module export.
-       */
-      public Builder export(String p) {
-        Objects.requireNonNull(p);
-        if (!exports.containsKey(p)) exports.put(p, new HashSet<>());
-        return this;
-      }
-
-      /**
-       * Adds a qualified module exports.
-       */
-      public Builder exports(String p, Set<String> ms) {
-        Objects.requireNonNull(p);
-        Objects.requireNonNull(ms);
-        if (!exports.containsKey(p)) export(p);
-        exports.get(p).addAll(ms);
-        return this;
-      }
-
-
-      /**
-       * Adds a service dependence's of this module
-       */
-      public Builder use(String cn) {
-        uses.add(cn);
-        return this;
-      }
-
-      /**
-       * Adds a service that a module provides one or more implementations of.
-       */
-      public Builder provide(String s, Set<String> impl) {
-        provides.computeIfAbsent(s, _k -> new HashSet<>()).addAll(impl);
-        return this;
-      }
-
-      /**
-       * @return The new module
-       */
-      public Module build() {
-        return new Module(requires, exports, uses, provides);
-      }
-    }
-  }
 }
--- a/src/org/openjdk/asmtools/jdis/StackMapData.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/StackMapData.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -144,7 +144,7 @@
         int[] map = new int[num];
         for (int k = 0; k < num; k++) {
             int mt_val = in.readUnsignedByte();
-            StackMapType maptype = stackMapType(mt_val);
+            StackMapType maptype = stackMapType(mt_val, null);
             switch (maptype) {
                 case ITEM_Object:
                     mt_val = mt_val | (in.readUnsignedShort() << 8);
@@ -153,6 +153,7 @@
                     int pc = in.readUnsignedShort();
                     code.get_iAtt(pc).referred = true;
                     mt_val = mt_val | (pc << 8);
+                    break;
                 }
             }
             map[k] = mt_val;
--- a/src/org/openjdk/asmtools/jdis/i18n.properties	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/i18n.properties	Fri Oct 06 15:15:23 2017 -0700
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017 Oracle and/or its affiliates. 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
@@ -38,3 +38,10 @@
 jdis.error.cannot_read=cannot read {0}
 jdis.error.fatal_error=fatal error in file: {0}
 jdis.error.fatal_exception=fatal exception in file: {0}
+
+jdis.error.invalid_header=Invalid Module's attributes table
+jdis.error.invalid_requires=Invalid requires table
+jdis.error.invalid_exports=Invalid exports table
+jdis.error.invalid_opens=Invalid opens table
+jdis.error.invalid_uses=Invalid uses table
+jdis.error.invalid_provides=Invalid provides table
--- a/src/org/openjdk/asmtools/jdis/iAtt.java	Wed Jun 15 12:47:32 2016 -0600
+++ b/src/org/openjdk/asmtools/jdis/iAtt.java	Fri Oct 06 15:15:23 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. 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
@@ -168,13 +168,13 @@
         }
     }
 
-    public void printMapList(int[] map) {
+    public void printMapList(int[] map) throws IOException {
         boolean pr_cpx = options.contains(Options.PR.CPX);
 
         for (int k = 0; k < map.length; k++) {
             int fullmaptype = map[k];
             int mt_val = fullmaptype & 0xFF;
-            StackMapType maptype = stackMapType(mt_val);
+            StackMapType maptype = stackMapType(mt_val, out);
             int argument = fullmaptype >> 8;
             switch (maptype) {
                 case ITEM_Object: